diff options
author | GoliathLabs | 2020-07-09 13:12:10 +0200 |
---|---|---|
committer | GoliathLabs | 2020-07-09 13:12:10 +0200 |
commit | 266380232b46490ce91aea56495eda523b43ccab (patch) | |
tree | 808dad69189a41dc2afa48feb8d679462d0ec993 | |
parent | 68adf40f2390352cd1403c17ec166d3449530a0a (diff) | |
download | aur-266380232b46490ce91aea56495eda523b43ccab.tar.gz |
Initial commit
-rw-r--r-- | .SRCINFO | 17 | ||||
-rw-r--r-- | PKGBUILD | 29 | ||||
-rw-r--r-- | arx-fatalis-data.install | 10 | ||||
-rwxr-xr-x | arx-install-data | 3278 |
4 files changed, 23 insertions, 3311 deletions
@@ -1,20 +1,21 @@ pkgbase = arx-fatalis-data-gog - pkgdesc = Arx Fatalis game data from GOG.com installer + pkgdesc = Arx Fatalis game data from GOG.com installer (for use with arx-libertatis) pkgver = 1.21 pkgrel = 1 - url = http://www.gog.com/en/gamecard/arx_fatalis - install = arx-fatalis-data.install - arch = i686 - arch = x86_64 + url = https://www.gog.com/game/arx_fatalis + arch = any license = custom:commercial makedepends = innoextract - provides = arx-fatalis-data + optdepends = arxlibertatis: native Linux game executable + provides = arxfatalis-data + conflicts = arxfatalis-data-copy + conflicts = arxfatalis-data-demo conflicts = arx-fatalis-data-copy conflicts = arx-fatalis-data-demo source = gog://setup_arx_fatalis_2.0.0.7.exe - source = arx-install-data + source = https://raw.githubusercontent.com/arx/ArxLibertatis/master/scripts/arx-install-data md5sums = 5be0898e71632e46ca430d7a32d0179a - md5sums = fc5456e4c213af243b65862db8d5db0a + md5sums = 2efe17e19aafb303f71d051d46ae2b3e pkgname = arx-fatalis-data-gog @@ -1,29 +1,28 @@ -# Maintainer: Sam S. <smls75@gmail.com> +# Maintainer: Felix Golatofski <contact@xdfr.de> +# Contributor: Sam S. <smls75@gmail.com> pkgname=arx-fatalis-data-gog pkgver=1.21 pkgrel=1 -pkgdesc='Arx Fatalis game data from GOG.com installer' -url='http://www.gog.com/en/gamecard/arx_fatalis' -arch=('i686' 'x86_64') +pkgdesc='Arx Fatalis game data from GOG.com installer (for use with arx-libertatis)' +url='https://www.gog.com/game/arx_fatalis' +arch=('any') license=('custom:commercial') +provides=('arxfatalis-data') +conflicts=('arxfatalis-data-copy' 'arxfatalis-data-demo' + 'arx-fatalis-data-copy' 'arx-fatalis-data-demo') makedepends=('innoextract') -provides=('arx-fatalis-data') -conflicts=('arx-fatalis-data-copy' 'arx-fatalis-data-demo') -install='arx-fatalis-data.install' -PKGEXT='.pkg.tar' -DLAGENTS+=('hib::/usr/bin/echo "Could not find %u. Manually download it to \"$(pwd)\", or set up a gog:// DLAGENT in /etc/makepkg.conf."; exit 1') +optdepends=('arxlibertatis: native Linux game executable') +DLAGENTS+=('gog::/usr/bin/echo "Could not find %u. Manually download it to \"$(pwd)\", or set up a gog:// DLAGENT in /etc/makepkg.conf."; exit 1') _gamepkg="setup_arx_fatalis_2.0.0.7.exe" source=("gog://$_gamepkg" - "arx-install-data") # from http://arx.vg/arx-install-data + "https://raw.githubusercontent.com/arx/ArxLibertatis/master/scripts/arx-install-data") # from http://arx.vg/arx-install-data md5sums=('5be0898e71632e46ca430d7a32d0179a' - 'fc5456e4c213af243b65862db8d5db0a') + '2efe17e19aafb303f71d051d46ae2b3e') package() { - cd $srcdir - - chmod +x arx-install-data - ./arx-install-data --batch "$_gamepkg" "$pkgdir/usr/share/arx" + chmod +x arx-install-data + ./arx-install-data --batch "$_gamepkg" "$pkgdir/usr/share/arx" } diff --git a/arx-fatalis-data.install b/arx-fatalis-data.install deleted file mode 100644 index 3db61fb887ac..000000000000 --- a/arx-fatalis-data.install +++ /dev/null @@ -1,10 +0,0 @@ - -post_install() { - echo "This package only installs the (proprietary) game data, no" - echo "game binaries." - echo "To actually play the game, compile and install Arx Libertatis," - echo "the community-driven open-source port of Arx Fatalis for Linux" - echo "based on the publically released Arx Fatalis 1.21 source code." - echo " -> http://arx-libertatis.org" - echo " -> AUR package: arx-libertatis" -} diff --git a/arx-install-data b/arx-install-data deleted file mode 100755 index 04e4dfce1e22..000000000000 --- a/arx-install-data +++ /dev/null @@ -1,3278 +0,0 @@ -#!/bin/sh - -# Copyright 2013 Arx Libertatis Team (see the AUTHORS file) -# -# This file is part of Arx Libertatis. -# -# Arx Libertatis is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Arx Libertatis is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>. - -########################################################################################## -# Install script for Arx Fatalis data files to be used with Arx Libertatis -# Usage: just run the damned script, maybe check --help - -# This scripts targets Linux and FreeBSD, but may also work on other UNIX-like systems. - -# Is this a multi-thousand-line bas^H^H^HPOSIX shell script? -# Sure looks like it. -# Am I mad? -# Most likely. - -# If you want to edit the required files and checksums, scroll to the end. - - -########################################################################################## -# Colors - -disable_color() { - red='' ; green='' ; yellow='' ; blue='' ; pink='' ; cyan='' ; white='' - dim_red='' ; dim_green='' ; dim_yellow='' ; dim_blue='' ; dim_pink='' - dim_cyan='' ; dim_white='' ; reset='' -} -disable_color -if [ -t 1 ] && [ "$(tput colors 2> /dev/null)" != -1 ] ; then - - red="$(printf '\033[1;31m')" - green="$(printf '\033[1;32m')" - yellow="$(printf '\033[1;33m')" - blue="$(printf '\033[1;34m')" - pink="$(printf '\033[1;35m')" - cyan="$(printf '\033[1;36m')" - white="$(printf '\033[1;37m')" - - dim_red="$(printf '\033[0;31m')" - dim_green="$(printf '\033[0;32m')" - dim_yellow="$(printf '\033[0;33m')" - dim_blue="$(printf '\033[0;34m')" - dim_pink="$(printf '\033[0;35m')" - dim_cyan="$(printf '\033[0;36m')" - dim_white="$(printf '\033[0;37m')" - - reset="$(printf '\033[m')" -fi - - -########################################################################################## -# Constants - -# Name and download locations for the 1.21 patch -patch_ver='1.21' -patch_name="ArxFatalis_${patch_ver}_MULTILANG.exe" -patch_name_localized="ArxFatalis_${patch_ver}_%s.exe" -patch_url_path="arxfatalis/patches/${patch_ver}/${patch_name}" -patch_url_master="http://cdn.bethsoft.com/${patch_url_path}" -patch_urls="http://arx.vg/${patch_name} ${patch_url_master}" -patch_urls="$patch_urls http://download.zenimax.com/${patch_url_path}" -patch_urls="$patch_urls http://web.archive.org/web/${patch_url_master}" - -# Name and download locations for the Japanese 1.02j patch -patch_jp_ver='1.02j' -patch_jp_name="arx_jpn_patch_${patch_jp_ver}.exe" -patch_jp_url_master="http://www.capcom.co.jp/pc/arx/patch/${patch_jp_name}" -patch_jp_urls="http://arx.vg/${patch_jp_name}" # master URL is no longer available -patch_jp_urls="$patch_jp_urls http://web.archive.org/web/${patch_jp_url_master}" - -# Name and store page for the GOG.com download -gog_names='setup_arx_fatalis.exe setup_arx_fatalis_2.0.0.7.exe' -gog_url='http://www.gog.com/gamecard/arx_fatalis' - -# Store page for the Steam download -steam_appid='1700' -steam_url="http://store.steampowered.com/app/$steam_appid/" -steam_install_dir="Arx Fatalis" - -# Name and wiki page for the demo download -demo_names="arx_demo_english.zip arxdemoenglish.zip arx_demo_english.exe" -demo_names="$demo_names arx_fatalis_demo_fr.zip arx_demo_german.exe arx_jpn_demo.exe" -demo_url='http://arx.vg/Getting_the_game_data#Demo' - -bug_tracker_url='http://bugs.arx-libertatis.org/' - -cabextract_url='http://www.cabextract.org.uk/' -innoextract_url='http://constexpr.org/innoextract/' - - -########################################################################################## -# Standard directories - -user_pwd="$PWD" -user_pwd="${user_pwd%/}" -platform="$(uname)" -command="$(basename "$0")" -scommand="$(printf '%s' "$command" | tr - _)" -if [ "$platform" = 'Darwin' ] ; then - # Mac OS X - data_dirs='/Applications' - data_home="$HOME/Library/Application Support" - config_home="$HOME/Library/Application Support" - data_dir_suffixes='ArxLibertatis' - user_dir_suffixes='ArxLibertatis' - config_dir_suffixes='ArxLibertatis' - downloads_dir="$HOME/Downloads" -else - # Linux, FreeBSD, ... - data_dirs="${XDG_DATA_DIRS:-"/usr/local/share/:/usr/share/"}:/opt" - data_home="${XDG_DATA_HOME:-"$HOME/.local/share"}" - config_home="${XDG_CONFIG_HOME:-"$HOME/.config"}" - data_dir_suffixes='games/arx:arx' - user_dir_suffixes='arx' - config_dir_suffixes='arx' - [ -f "${config_home}/user-dirs.dirs" ] && . "${config_home}/user-dirs.dirs" - downloads_dir="${XDG_DOWNLOAD_DIR:-"$HOME/Downloads"}" -fi -downloads_dir="${downloads_dir%/}" -tempdir="${TMPDIR:-"/tmp"}" -tempdir="${tempdir%/}" -[ -d "$tempdir" ] || tempdir="$PWD" -eval "data_path=\"\$${scommand}_PATH\"" -[ -z "$data_path" ] && data_path="$arx_PATH" - - -########################################################################################## -# Helper functions - -exec 4>&2 # fd to the original stderr (we redirect output to a log file in some cases) -logfile='' # log file receiving sdout and stderr - -true=0 # Return value / exit status that evaluates to true -false=1 # Return value / exit status that evaluates to false - -# 1 if the script is being run as root, false otherwise -if [ "$(id -u)" = 0 ] ; then is_root=1 ; else is_root=0 ; fi - -# Print one line of text, without escape codes or other shell-specific shenanigans. -# Seriously, shells, you can't even agree on a consistent implementation of echo? -# Usage: print <text> -print() { - printf '%s\n' "$1" -} - -puts() { - printf '%s' "$1" -} - -disabled_commands=' ' # List of commands that should not be used, even if they exist - -# Make `have` return false for a comand -# Usage: disable_command <command> -disable_command() { - disabled_commands="$disabled_commands$1 " -} - -# Check if a command is available. -# Usage: have <command> -# Return: $true if the command is available, $false otherwise -have() { - case "$disabled_commands" in *" $1 "*) return $false ; esac - command -v "$1" > /dev/null 2>&1 -} - -# Make a path absolute no matter if it is relative or not -# Usage: abspath <path> -# Too bad we can't just use readlink -m -abspath() { - case "$1" in - /*) print "$1" ;; - *) print "$PWD/$1" ;; - esac -} - -# Get the canonical representation of an existing path -# Usage: canonicalize <path> -# Too bad we can't just use readlink -f -if have realpath ; then - canonicalize() { realpath "$1" ; } -elif have grealpath ; then - canonicalize() { grealpath "$1" ; } -elif have greadlink ; then - canonicalize() { greadlink -f "$1" ; } -else - canonicalize() { - _canonicalize_old_pwd="$PWD" - _canonicalize_file="$1" - while true ; do - cd "$(dirname "$_canonicalize_file")" - _canonicalize_file="$(basename "$_canonicalize_file")" - [ -L "$_canonicalize_file" ] || break; - _canonicalize_file="$(readlink "$_canonicalize_file")" - done - echo "$(pwd -P)/$_canonicalize_file" - cd "$_canonicalize_old_pwd" - } -fi - -cleanup_functions='' # List of functions to be run on exit - -# Add a function to ron on exit. -# Functions are un in the order they are added. -# Usage: on_exit <code> -# Cleanup functions will receive one argument: the exit message if any or an empty string. -on_exit() { - [ -z "$cleanup_functions" ] || cleanup_functions=" $cleanup_functions" - cleanup_functions="$1$cleanup_functions" -} - -# Run exit runctions. -cleanup() { - _cleanup_functions="$cleanup_functions" ; cleanup_functions='' - [ -z "$_cleanup_functions" ] && return - eval "for _cleanup_func in $_cleanup_functions ; do \"\$_cleanup_func\" \"\$@\" ; done" -} - -# Register our cleanup handler. -trap "cleanup" EXIT -# Some shells don't have their own (non-libc) SIGINT handler, but the EXIT trap -# won't trigger if there is none! -trap 'print >&4 ; quit 1' INT - -# Run cleanup functions with a possible message and then exit. -# Usage: quit <status> [<message>] -quit() { - cleanup "$2" - exit $1 -} - -# Exit with a non-zero status and optionally print a message. -# Usage: die [<message>...] -die() { - _die_message='' - if [ $# -gt 0 ] ; then - _die_message="$1" ; shift - for _die_arg ; do _die_message="$_die_message $_die_arg" ; done - _die_message="$_die_message - -If you think this is a bug in the install script -please report the complete output at - $bug_tracker_url" - if [ ! -z "$logfile" ] && [ -f "$logfile" ] ; then - _die_message="$_die_message - -Also attach the contents of - $logfile" - logfile='' # so that we don't remove it on exit - printf "${red}%s${reset}\\n" "$_die_message" >&4 # also print to priginal stdout - printf '\n%s\n' 'Preserving log file.' >&4 - fi - - printf "${red}%s${reset}\\n" "$_die_message" - fi - quit 1 "$_die_message" -} - -# Escape a string from stdin for use in a whitespace-seperated list. -# Usage: print <string> | escape_pipe -escape_pipe() { - sed "s:[^a-zA-Z0-9/_.$1]:\\\\&:g" -} - -# Escape a string for use in a whitespace-seperated list. -# Usage: escape <string> -escape() { - print "$1" | escape_pipe "$2" -} - -# Convert a colon-seperated list into an escaped whitespace-seperated list. -# Usage: to_list <colon-list> -to_list() { - escape "$1" | sed 's/\\:/ /g' -} - -# Line-based output into a list -# Usage: ls | lines_to_list -lines_to_list() { - escape_pipe | tr '\n' ' ' -} - -# Check if a whitespace separated list contains a string. -# Usage: list_contains <list-var> <needle> -list_contains() { - eval "_list_contents=\"\$$1\"" - [ -z "$_list_contents" ] && return $false - eval "for _list_contains_entry in $_list_contents ; do" \ - " [ \"\$_list_contains_entry\" = \"\$2\" ] && return \$true ; done" - return $false -} - -# Append a string to a whitespace separated list. -# Usage: list_append <list-var> <string> [comment] -# Whitespace seperated lists can be loaded into the argument list using: -# eval "set -- $var" -list_append() { - _list_entry="$(escape "$2")" - eval "_list_contents=\"\$$1\"" - if [ -z "$_list_contents" ] - then eval "$1=\"\$_list_entry\"" - else eval "$1=\"\$_list_contents \$_list_entry\"" - fi - eval "[ -z \"\$$1__list_count\" ] && $1__list_count=0" - eval "_list_count=\$$1__list_count" - eval "$1__list_comment_$_list_count=\"\$3\"" - eval "$1__list_count=\$(($1__list_count + 1))" -} - -# Append one list to another, preserving comments. -# Usage: list_merge <list-var> <append-list-var> -list_merge() { - eval "_list_append=\"\$$2\"" - [ -z "$_list_append" ] && return - eval " - _list_merge_i=0 - for _list_merge_entry in $_list_append ; do - list_append $1 \"\$_list_merge_entry\" \"\$(list_comment $2 \$_list_merge_i)\" - _list_merge_i=\$((_list_merge_i + 1)) - done - " -} - -# Get a comment associated with alist entry -# Usage: list_comment <list-var> <index> -list_comment() { - eval "print \"\$$1__list_comment_$2\"" -} - -# Set a comment associated with alist entry -# Usage: list_comment <list-var> <index> <comment> -set_list_comment() { - eval "$1__list_comment_$2=\"\$3\"" -} - -# Append a string to a whitespace separated list if it isn't already in the list. -# Usage: set_append <list-var> <string> [comment] -set_append() { - if ! list_contains "$1" "$2" ; then - list_append "$1" "$2" "$3" - fi -} - -# Check if a directory contains a file while ignoring case differences. -# Usage: icontains <dir> <filename> -icontains() { - [ ! -z "$(find "$1" -mindepth 1 -maxdepth 1 -iname "$2")" ] -} - -# Check if a directory or file is writable or can be created. -# Usage: is_writable <path> -is_writable() { - [ -w "$1" ] && return $true - [ ! -e "$1" ] && is_writable "$(dirname "$1")" -} - -# Create a directory and die with a message on error. -# Usage: create_dir <path> <type> -create_dir() { - mkdir -p "$1" || die "Could not create $2 directory: $1" -} - -probe_file_dirs='' -set_append probe_file_dirs "$user_pwd" -set_append probe_file_dirs "$downloads_dir" -set_append probe_file_dirs "$HOME" -set_append probe_file_dirs "$tempdir" - -# Find a file in standard directories. -# Usage: probe_file <command> <filename> [comment] -# Will call `command <file>` for each file found. -probe_file() { - eval "for _probe_file_d in $probe_file_dirs ; do [ -f \"\$_probe_file_d/\$2\" ] && \$1 \"\$_probe_file_d/\$2\" \"\$3\" && return \$true ; done" -} - -# Find files in standard directories. -# Usage: probe_file <command> <list> [comment] -# Will call `command <file>` for each file found. -probe_files() { - [ -z "$2" ] && return $false - eval "for _probe_files_file in $2 ; do probe_file \"\$1\" \"\$_probe_files_file\" \"\$3\" && return \$true ; done" - return $false -} - - -########################################################################################## -# Parse command-line arguments - -extract_zip_reqs='' -list_append extract_zip_reqs 'bsdtar' 'libarchive' -list_append extract_zip_reqs 'unzip' -list_append extract_zip_reqs '7za' -list_append extract_zip_reqs '7z' 'p7zip' -extract_ms_cab_reqs='' -list_append extract_ms_cab_reqs 'bsdtar' 'with libarchive 3.1+' -list_append extract_ms_cab_reqs 'cabextract' "$cabextract_url" -list_append extract_ms_cab_reqs '7za' -list_append extract_ms_cab_reqs '7z' 'p7zip' -extract_installshield_reqs='' -list_append extract_installshield_reqs 'unshield' -extract_rar_reqs='' -list_append extract_rar_reqs 'unrar' -extract_ace_reqs='' -list_append extract_ace_reqs 'unace' -extract_innosetup_reqs='' -list_append extract_innosetup_reqs 'innoextract' "$innoextract_url" -mount_cdrom_reqs='' -list_append mount_cdrom_reqs 'fuseiso' -extract_iso_reqs='' -list_append extract_iso_reqs 'isoinfo' -list_append extract_iso_reqs 'bsdtar' 'libarchive' -list_append extract_iso_reqs '7z' 'p7zip' -extract_cdrom_reqs='' -list_merge extract_cdrom_reqs mount_cdrom_reqs -list_merge extract_cdrom_reqs extract_iso_reqs -download_reqs='' -list_append download_reqs 'wget' -list_append download_reqs 'curl' -list_append download_reqs 'fetch' 'FreeBSD' - -printf '%s %s\n' "${white}Welome to the ${green}Arx Fatalis${white} ${patch_ver} data" \ - "install script for UNIX-like systems!${reset}" - -patchfile='' # Main patch file -patchfile_jp='' # Japanese patch file -sourcefile='' # Source file or directory -datadir='' # Output data directory -batch=0 # Never wait for user input -gui=0 # Display a graphical user interface (command-line interface otherwise) -install=1 # Install new non-patch files -selected_stuff=0 # Has the user made a selection -installed_stuff=0 # Have we already installed anything? -patch=1 # Install patch files if needed -probe_patch=1 # Look for patch files in standard locations and download if needed -redirect_log=1 # Redirect standard output/error output to a log file in GUI mode - -# Enable compatiblity with old install-* scripts. -# Usage: enable_compat_mode <help-flag> <sourcefile> <patchfile> <datadir> -enable_compat_mode() { - print \ - "${yellow}Enabling compatibility mode for ${pink}$command${yellow}.${reset} - -${dim_yellow}The individual ${dim_pink}install-*${dim_yellow} scripts have been merged. -Rename this script to something else (like ${dim_pink}arx-install-data${dim_yellow}) to unlock its full power!${reset} -" >&2 - batch=1 - probe_patch=0 - if [ -z "$1" ] || [ "$1" = '--help' ] || [ "$1" = '-h' ] ; then - printf '%s\n\n%s\n' "$5" \ - "${yellow}More options are available in the non-compatiblity mode.${reset}" - exit $false - fi - if [ -z "$2" ] ; then install=0 ; else sourcefile="$2" ; fi - if [ -z "$3" ] ; then patch=0 ; else patchfile="$3" ; fi - if [ -z "$4" ] ; then datadir="$user_pwd" ; else datadir="$4" ; fi -} - -case "$command" in - -install-cd) -[ "$1" = "--no-progress" ] && shift # ignore - not supported -enable_compat_mode "$1" "$1" "$2" "$3" "\ -Usage: $command path/to/mount/point/ path/to/ArxFatalis_1.21_MULTILANG.exe [output_dir] -or $command path/to/cd.iso path/to/ArxFatalis_1.21_MULTILANG.exe [output_dir]" ;; - -install-copy) -enable_compat_mode "$1" "$1" '' "$2" "\ -Usage: $command path/to/ArxFatalis/ [output_dir]" ;; - -install-demo) -enable_compat_mode "$1" "$1" '' "$2" "\ -Usage: $command path/to/arx_demo_english.zip [output_dir]" ;; - -install-gog) -[ "$1" = "--no-progress" ] && shift # ignore - not supported -enable_compat_mode "$1" "$1" '' "$2" "\ -Usage: $command path/to/setup_arx_fatalis.exe [output_dir]" ;; - -install-verify) -enable_compat_mode "$1" '' '' "$1" "\ -Usage: $command [directory]" ;; - -*) # non-compatibility mode - -# Print elements in a list, joined by ' or ' -# Usage: print_help_or <list-var> [color] -print_help_or() { - _print_help_or_var=$1 - eval "_print_help_or_list=\"\$$1\"" - _print_help_or_color="$2" - [ -z "$1" ] && return - eval " - _print_help_or_i=0 - for _print_help_or_entry in $_print_help_or_list ; do - [ \$_print_help_or_i = 0 ] || puts ' or ' - printf '%s%s' \"\$_print_help_or_color\" \"\$_print_help_or_entry\" - [ -z \"\$_print_help_or_color\" ] || puts \"\$reset\" - _print_help_or_comment=\"\$(list_comment \$_print_help_or_var \$_print_help_or_i)\" - [ -z \"\$_print_help_or_comment\" ] || printf ' (%s)' \"\$_print_help_or_comment\" - _print_help_or_i=\$((_print_help_or_i + 1)) - done - " -} - -# Print elements in a list, one per line. -# Usage: print_help_list <prefix-format> <list-var> -# prefi-format will receive one argument: the list index starting at 1 -print_help_list() { - _print_help_list_prefix="$1" - _print_help_list_var=$2 - eval "_print_help_list_list=\"\$$2\"" - [ -z "$1" ] && return - eval " - _print_help_list_i=0 - for _print_help_list_entry in $_print_help_list_list ; do - case \"\$_print_help_list_prefix\" in - *%*) printf \"\$_print_help_list_prefix\" \$((_print_help_list_i + 1)) ;; - *) puts \"\$_print_help_list_prefix\" - esac - printf \"%s\${reset}\" \"\$_print_help_list_entry\" - _print_help_list_comment=\"\$(list_comment \$_print_help_list_var \$_print_help_list_i)\" - [ -z \"\$_print_help_list_comment\" ] || printf ' (%s)' \"\$_print_help_list_comment\" - printf '\n' - _print_help_list_i=\$((_print_help_list_i + 1)) - done - " -} - -# Print help output. -# Usage: print_help [<error-message>] -print_help() { - [ -z "${1-}" ] || ( printf '%s\n\n' "${red}$1${reset}" ) - print " -${white}Start the script without any arguments to select paths interactively: - \$ $command${reset} - -Usage: $command [--source] source [--patch patchfile] [[--data-dir] datadir] - $command [--patch patchfile] [--data-dir datadir] - $command --verify [[--data-dir] datadir] - - ${green}-s, --source PATH${reset} Path to the source file or directory - ${cyan}-d, --data-dir DIR${reset} Where to install the data - ${blue}-p, --patch FILE${reset} Path to the ${patch_ver} patch file - --patch-jp FILE Path to the ${patch_jp_ver} Japanese patch file - -v, --verify Only verify the files in the data-dir, don't install new ones, - except for patch files. - -n, --no-patch Don't use a patch file unless explicitly specified. - -h, --help Print this message and maybe more - -b, --batch Never ask the user questions - -g, --gui Show a GUI asking the user what to do - Requires ${dim_pink}KDialog${reset}, ${dim_pink}Zenity${reset}, or ${dim_pink}Xdialog${reset}. - If none of them are available the script is re-launched - in a terminal emulator. - -c, --cli Interactively ask the user to select files/directories (no GUI) - --no-redirect-log Don't redirect output to a log file when in GUI mode - --disable-COMMAND Don't use the given tool, even if it exists. - Valid values are 7z, 7za, aterm, bsdtar, cabextract, curl, - dcop, fetch, fuseiso, fusermount, gnome-terminal, greadlink, - grealpath, gtkterm, gxmessage, innoextract, isoinfo, kdialog, - konsole, md5, md5sum, mount, qdbus, realpath, rxvt, umount, - unace, unrar, unshield, unzip, urxvt, wget, Xdialog, - xmessage, xterm, x-terminal-emulator, zenity. - ---gui is enabled by default if there are no arguments *and* stdin, stdout or stderr is not a terminal -" - [ ! -z "${1-}" ] && exit $false - help_innosetup="$(print_help_or extract_innosetup_reqs "$dim_pink")" - help_cdrom="$(print_help_or extract_cdrom_reqs "$dim_pink") or root access" - help_cab="$(print_help_or extract_ms_cab_reqs "$dim_pink")" - help_zip="$(print_help_or extract_zip_reqs "$dim_pink")" - help_unshield="$(print_help_or extract_installshield_reqs "$dim_pink")" - help_rar="$(print_help_or extract_rar_reqs "$dim_pink")" - help_ace="$(print_help_or extract_ace_reqs "$dim_pink")" - help_download="$(print_help_or download_reqs "$dim_pink")" - help_optpatch="may use the 1.21 patch file and require ${help_innosetup} if not already patched" - help_probe_file_dirs=" - a) the current working directory (\$PWD): $user_pwd - b) the user's downloads directory (\$XDG_DOWNLOAD_DIR): $downloads_dir - c) the user's home directory (\$HOME): $HOME - d) the temp directory (\$TMPDIR): $tempdir" - help_probe_file_dirs_patch="${help_probe_file_dirs} - e) the directory containing the source file" - help_probed_files="$gog_names $demo_names" - print " -The ${pink}dependencies${reset} required by the ${command} script depend on the source files. -However, you always need either ${dim_pink}md5sum${reset} or ${dim_pink}md5${reset}. - - -The ${green}source${reset} can be one of many things: - - * ${white}Mounted Arx Fatalis ${green}cdrom${reset} - requires: - - ${help_cab} - - ${help_innosetup} - needs the 1.21 patch file - - * ${white}Arx Fatalis cdrom ${green}ISO${white} image / device file${reset} - requires: - - ${help_cdrom} - - ${help_cab} - - ${help_innosetup} - needs the 1.21 patch file - - * ${white}Arx Fatalis installer from ${green}GOG.com${white}${reset} ($(print_help_or gog_names)) - requires: - - ${help_innosetup} - never uses the 1.21 patch file - get it from ${dim_green}${gog_url}${reset} - - * ${green}Installed${white} copy of Arx Fatalis${reset} (for example from ${green}Steam${reset}) - ${help_optpatch} - get it from ${dim_green}${steam_url}${reset} - - * ${white}Arx Fatalis ${green}demo${reset} (one of the following) -$(print_help_list " - " demo_names) - requires: - - ${help_zip} [english/french .zip] - - ${help_cab} - - ${help_rar} [english .exe] - - ${help_ace} [german .exe] - - ${help_unshield} [japanese .exe] - never uses the 1.21 patch file - get it from ${dim_green}${demo_url}${reset} - - * ${white}Extracted Arx Fatalis demo installer${reset} - requires: - - ${help_cab} - never uses the 1.21 patch file - - * ${white}Installed copy of the Arx Fatalis demo${reset} - never uses the 1.21 patch file - -If no source is specified, these files will be probed: -1. The following files in${help_probe_file_dirs} -$(print_help_list " 1.%d ${green}" help_probed_files) -2. The user's ${green}Steam${reset} library, if available -3. If \$WINEPREFIX is set, any installation in there -4. Any installation in the default WINEPREFIX (${green}~/.wine${reset}) -5. Any mounted ${green}cdrom${reset} or ISO file - - -If no ${blue}patch${reset} file is specified, but is needed and -the --no-patch option wasn't specified: -1. Try to find the following files in${help_probe_file_dirs_patch} - 1.1. ${blue}${patch_name}${reset} - 1.2. $(printf "$patch_name_localized" '<LANG>') - Where <LANG> is one of EN, ES, FR, GE, IT, RU, - depending on the language of the data files. -2. Downloaded from: -$(print_help_list " - ${dim_blue}" patch_urls) -Downloading the patch file requires ${help_download}. -Extracting the ${patch_ver} patch file requires ${help_innosetup}. - -For the Japanese version, if no ${blue}patch-jp${reset} file is specified, -but is needed and the --no-patch option wasn't specified specified: -1. Try to find ${blue}${patch_jp_name}${reset} in${help_probe_file_dirs_patch} -2. Downloaded from: -$(print_help_list " - ${dim_blue}" patch_jp_urls) -Downloading the patch file requires ${help_download}. -Extracting the Japanese patch file requires: - - ${help_unshield} - - ${help_cab}. - - -If no ${cyan}data-dir${reset} to install into is specified, -one is automatically selected similarly to how Arx Libertatis would: -If --verify and --no-patch are give, use the first existing directory -of the following, otherwise, use the first existing writable directory -or, if none exists, the first directory that can be created: -1. Any path in \$${scommand}_PATH or \$arx_PATH (for use in wrapper scripts) -2. \"\${XDG_DATA_DIRS:-\"/usr/local/share/:/usr/share/\"}:/opt\" / \"$data_dir_suffixes\":" - i=1 - eval "set -- $(to_list "$data_dirs")" - for prefix in "$@" ; do - eval "set -- $(to_list "$data_dir_suffixes")" - for suffix ; do - printf " 2.%d. ${dim_cyan}%s${reset}\\n" $i "$prefix/$suffix" - i=$((i + 1)) - done - done -print "3. \"\${XDG_DATA_HOME:-\"\$HOME/.local/share\"}\" / \"$user_dir_suffixes\"" - i=1 - eval "set -- $(to_list "$user_dir_suffixes")" - for suffix ; do - printf " 3.%d. ${dim_cyan}%s${reset}\\n" $i "$data_home/$suffix" - i=$((i + 1)) - done - print - exit $true -} - -user_is_sane=1 -if [ ! -t 0 ] || [ ! -t 1 ] || [ ! -t 2 ] ; then - [ $# = 0 ] && gui=1 -fi -while [ $# -gt 0 ] ; do - case "$1" in - --source=*) sourcefile="${1#--source=}" ; install=1 ;; - -s|--source) shift ; sourcefile="$1" ; install=1 ;; - --data-dir=*) datadir="${1#--data-dir=}" ;; - -d|--data-dir) shift ; datadir="$1" ;; - --patch=*) patchfile="${1#--patch=}" ; patch=1 ;; - -p|--patch) shift ; patchfile="$1" ; patch=1 ;; - --patch-jp=*) patchfile_jp="${1#--patch-jp=}" ; patch=1 ;; - --patch-jp) shift ; patchfile_jp="$1" ; patch=1 ;; - -v|--verify) install=0 patch=0 ;; - -n|--no-patch) [ -z "$patchfile" ] && [ -z "$patchfile_jp" ] && patch=0 - probe_patch=0 ;; - -b|--batch) batch=1 ;; - -g|--gui) gui=1 ;; - -c|--cui|--cli) batch=0 ; gui=0 ;; - --no-redirect-log) redirect_log=0 ;; - --i-am-insane) user_is_sane=0 ;; - --disable-*) disable_command "${1#--disable-}" ;; - --disable) shift ; disable_command "${1#--disable-}" ;; - -h|--help) print_help ;; - -*) print_help "Uknown option: $1" ;; - *) - if [ -z "${sourcefile-}" ] && [ $install = 1 ] ; then sourcefile="$1" - elif [ -z "${datadir-}" ] ; then datadir="$1" - else print_help "Too many options: $1" ; fi - esac - [ -z "${1-}" ] && print_help "Expected more options" - shift; -done - -print "See \`${dim_pink}$command --help${reset}\` for available options." - -esac - -# Make user-provided paths absolute -[ ! -z "$sourcefile" ] && sourcefile="$(abspath "$sourcefile")" -[ ! -z "$datadir" ] && datadir="$(abspath "$datadir")" -[ ! -z "$patchfile" ] && patchfile="$(abspath "$patchfile")" - -# Sanity check -[ $install = 1 ] && [ $batch = 1 ] && [ -z "$sourcefile" ] && [ $user_is_sane = 1 ] \ - && die "You have used --batch without providing a source file! -This would just pick the first source file found, which is a bad idea™. -If you really want this, add the --i-am-insane option." - - -########################################################################################## -# User interface abstraction - -_dialog_title="Arx Fatalis ${patch_ver} data installer" - -# Handle magic environment variable to tell the script that it has been launched -# in its own terminal and should not try to create a GUI. -if [ $batch = 0 ] && [ "$_arx_install_data_force_cli" = 1 ] ; then - trap '_arx_install_data_force_cli=0 ; quit 1' INT - printf "\n${yellow}%s${reset}\n\n" \ - 'Note: Install KDialog, Zenity or Xdialog for a better GUI' - wait_exit() { - [ "$_arx_install_data_force_cli" = 1 ] && print 'Press enter to exit...' && read f - exit $false - } - on_exit wait_exit - gui=0 - for var in batch install patch probe_patch sourcefile datadir \ - patchfile patchfile_jp disabled_commands; do - eval "$var=\"\$_arx_install_data_force_$var\"" - done -fi - -# Select the dialog backend to use -if [ $gui = 1 ] ; then - - # Detect if we are running in a KDE session - is_kde=0 - case "$DESKTOP_SESSION" in *kde*|*KDE*) is_kde=1 ; esac - [ -z "$KDE_FULL_SESSION" ] || is_kde=1 - [ -z "$KDE_SESSION_UID" ] || is_kde=1 - [ -z "$KDE_SESSION_VERSION" ] || is_kde=1 - - # Select the GUI backend, prefer kdialog for KDE sessions, zenity otherwise - if [ $is_kde = 1 ] ; then preferred=kdialog ; else preferred=zenity ; fi - for backend in $preferred zenity kdialog Xdialog ; do - have $backend && gui=$backend && break - done - - if [ $gui = 1 ] ; then - - # No dialog backend available - # Try opening a graphical terminal and launching the script in there. - print 'No GUI dialog backend is available - trying to launch a terminal emulator' - term_cmd="$(abspath "$(command -v "$0" 2> /dev/null)")" - # Not all terminals accept command arguments in the same way. - # Instead of hacking terminal-specific code, use a magic environment - # variable to tell the sub-process how to behave. - _arx_install_data_force_cli=1 - export _arx_install_data_force_cli - for var in batch install patch probe_patch sourcefile datadir \ - patchfile patchfile_jp disabled_commands ; do - eval "_arx_install_data_force_$var=\"\$$var\"" - eval "export _arx_install_data_force_$var" - done - if [ $is_kde = 1 ] ; then preferred=konsole ; else preferred=x-terminal-emulator ; fi - for backend in x-terminal-emulator $preferred \ - aterm urxvt rxvt konsole xterm gnome-terminal - do - if have $backend ; then - $backend -e "$term_cmd" || continue - exit $true - fi - done - - # Hm, that didn't work either - bail - message="No GUI dialog backend is available" - message="$message - install KDialog, Zenity or Xdialog, or use the --cli option." - # Final attempt to let the user know what happened - for backend in gxmessage xmessage ; do - if have $backend ; then - $backend -center -buttons OK "$_dialog_title - -$message" - break - fi - done - die "$message" - - fi - - # We don't need colors for the UI, but they may cause problems - get rid of them - disable_color - - if [ $redirect_log = 1 ] ; then - # Redirect all further output into a log file - logfile="$(abspath "$(mktemp "$tempdir/arx-install-data.log.XXXXX")")" - clean_logfile() { - [ -z "$logfile" ] || rm -f "$logfile" - } - on_exit clean_logfile - print "Enabling GUI mode, standard output/error saved to $logfile" - print "Use the --cli option for an interactive command-line interface." - exec > "$logfile" 2>&1 - else - print "Enabling GUI mode..." - print "Use the --cli option for an interactive command-line interface." - fi - -elif [ ! "$_arx_install_data_force_cli" = 1 ] ; then - - print "Enabling CLI mode, use the --gui option for a graphical interface." - -fi - -#----------------------------------------------------------------------------------------# -# Functions for controlling an asynchronous process via stdin - -pipe_file='' -pipe_pid=0 - -# Run a command in the background and open a pipe to pass commmands to it -# Usage: pipe_create <command> [<args>...] -pipe_create() { - - pipe_destroy - - # Pipe commands via a FIFO or, if that fails, via a regular file - pipe_file="$(mktemp -u "$tempdir/arx-install-data.pipe.XXXXX")" - if mkfifo -m 600 "$pipe_file" 2> /dev/null ; then - # Fast communication via a FIFO - "$@" < "$pipe_file" & - pipe_pid="$!" - else - # Fallback via regular file, may use polling - pipe_file="$(mktemp "$tempdir/arx-install-data.pipe.XXXXX")" - [ -z "$pipe_file" ] && return $false - tail -f "$pipe_file" | "$@" & - pipe_pid="$!" - fi - - # Open fd 3 for writing into the pipe - exec 3> "$pipe_file" - - return $true -} - -# Kill the program created via pipe_create and cleanup files -# Usage: pipe_destroy -pipe_destroy() { - - # Close fd pointing to the pipe - exec 3<&- - - # Remove the FIFO or temp file - [ -z "$pipe_file" ] || rm -f "$pipe_file" > /dev/null 2>&1 - pipe_file='' - - # Terminate the remote process - [ "$pipe_pid" = 0 ] || kill "$pipe_pid" > /dev/null 2>&1 - pipe_pid=0 - - return $true -} - -# Check if the remote process is running -# Usage: pipe_exists || print 'oh noes' -pipe_exists() { - [ -z "$pipe_file" ] && return $false - [ "$pipe_pid" = 0 ] && return $false - kill -s 0 "$pipe_pid" > /dev/null 2>&1 -} - -# Send a message to the remote process -# Usage: pipe_write <command> -pipe_write() { - [ -z "$pipe_file" ] || print "$1" >&3 -} - -#----------------------------------------------------------------------------------------# -# Code for the different GUI/CLI implementations -# Each implementation exposes dialog_* primitives that are used by generic functions. - -case $gui in - -#----------------------------------------------------------------------------------------# -zenity) - -# Helper functions - -# Run Zenity -# Usage: zenity_run <title-prefix> <dialog-type> [<args>...] -zenity_run() { - _zenity_run_t="$1" ; shift - [ -z "$_zenity_run_t" ] || _zenity_run_t="$_zenity_run_t - " - zenity --title "$_zenity_run_t$_dialog_title" "$@" -} - -# Dialog abstraction - -# Create the main progress window. -# Usage: dialog_create -dialog_create() { - pipe_create zenity --title "$_dialog_title" --width 450 --progress -} - -# Destroy the main progress window. -# Usage: dialog_destroy -dialog_destroy() { - pipe_destroy -} - -# Show an error dialog. -# Usage: dialog_error <message> -dialog_error() { - zenity_run 'Error' --error --no-wrap --text="$1" -} - -# Show a message box. -# Usage: dialog_message <message> -dialog_message() { - zenity_run 'Status' --info --no-wrap --text="$1" -} - -# Ask a yes/no question. -# Usage: dialog_ask <question> -dialog_ask() { - zenity_run 'Confirm' --question --no-wrap --ok-label=Yes --cancel-label=No --text="$1" -} - -# Has the user quested to cancel the operation? -# Usage: dialog_cancelled && print "cancelled" -dialog_cancelled() { - ! pipe_exists -} - -# Set the status text. -# Usage: dialog_set_text <text> -dialog_set_text() { - pipe_write "#$1" -} - -# Set if the progress bar should continously animate instead of showing the value. -# Usage: dialog_set_pulsate <enable> -dialog_set_pulsate() { - if [ $1 = 1 ] - then pipe_write "pulsate:true" - else pipe_write "pulsate:false" - fi -} - -# Set the current progress value. -# Usage: dialog_set_value <percentage> -dialog_set_value() { - pipe_write "$1" -} - -# Select an entry in a list. -# Usage dialog_select_entry <var> <label> <tag1> <item1> [ <tag2> < item2> ... ] -dialog_select_entry() { - _zenity_select_entry_v="$1" ; shift - _zenity_select_entry_t="$1" ; shift - _zenity_select_entry_r="$( - zenity_run 'Select path' --width 550 --height 300 \ - --list --text="$_zenity_select_entry_t" \ - --column '#' --column 'Path' --hide-column=1 "$@" --hide-header - )" - [ -z "$_zenity_select_entry_r" ] && return $false - eval "$_zenity_select_entry_v=\"\$_zenity_select_entry_r\"" - return $true -} - -# dialog_select_path does not support the --any flag -dialog_select_path_any=0 - -# Let the user select a path. -# Usage: dialog_select_path (--file|--dir|--any) <result-var> <label> -# Any is only supported if $dialog_select_path_any is 1. -dialog_select_path() { - case "$1" in - --any) die 'not implemented' ;; - --file) _zenity_select_path_f='--file-selection' ;; - --dir) _zenity_select_path_f='--file-selection --directory' ;; - esac - _zenity_select_path="$( - eval "zenity_run \"\$3\" $_zenity_select_path_f" 2> /dev/null - )" - [ -z "$_zenity_select_path" ] && return $false - eval "$2=\"\$_zenity_select_path\"" - return $true -} - -dialog_retry() { - zenity_run 'Error' --question --no-wrap --text="$1" \ - --ok-label='Retry' --cancel-label='Ignore' - case $? in - 0) dialog_retry_choice='retry' ;; - 1) dialog_retry_choice='ignore' ;; - *) dialog_retry_choice='abort' ;; - esac -} - -;; - -#----------------------------------------------------------------------------------------# -kdialog) - -# Helper functions - -kdialog_handle='' # dbus/dcop handle for the main progress window - -# Send a message to the main KDialog instance non-_q variants hide all output -kdialog_qdbus_q() { have qdbus && eval "qdbus $kdialog_handle \"\$@\"" 2> /dev/null ; } -kdialog_qdbus() { kdialog_qdbus_q "$@" > /dev/null ; } -kdialog_dcop_q() { have dcop && eval "dcop $kdialog_handle \"\$@\"" 2> /dev/null ; } -kdialog_dcop() { kdialog_dcop_q "$@" > /dev/null ; } -kdialog_cmd_q() { kdialog_qdbus_q "$@" || kdialog_dcop_q "$@" ; } -kdialog_cmd() { kdialog_cmd_q "$@" > /dev/null ; } - -# Run KDialog -# Usage: kdialog_run <title-prefix> <dialog-type> [<args>...] -kdialog_run() { - _kdialog_run_t="$1" ; shift - [ -z "$_kdialog_run_t" ] || _kdialog_run_t="$_kdialog_run_t - " - kdialog --icon arx-libertatis --title "$_kdialog_run_t$_dialog_title" "$@" -} - -# Dialog abstraction - -# Create the main progress window. -# Usage: dialog_create -dialog_create() { - dialog_destroy - _kdialog_force_width='WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW' - kdialog_handle="$(kdialog_run '' --progressbar "$_kdialog_force_width" 0)" - [ -z "$kdialog_handle" ] && return $false - kdialog_cmd showCancelButton true - return $true -} - -# Destroy the main progress window. -# Usage: dialog_destroy -dialog_destroy() { - [ -z "$kdialog_handle" ] && return $true - kdialog_cmd close - kdialog_handle='' -} - -# Show an error dialog. -# Usage: dialog_error <message> -dialog_error() { - kdialog_run 'Error' --error "$1" > /dev/null 2> /dev/null -} - -# Show a message box. -# Usage: dialog_message <message> -dialog_message() { - kdialog_run 'Status' --msgbox "$1" > /dev/null 2> /dev/null -} - -# Ask a yes/no question. -# Usage: dialog_ask <question> -dialog_ask() { - kdialog_run 'Confirm' --warningyesno "$1" > /dev/null 2> /dev/null -} - -# Has the user quested to cancel the operation? -# Usage: dialog_cancelled && print "cancelled" -dialog_cancelled() { - [ "$(kdialog_cmd_q wasCancelled || print true)" = true ] -} - -# Set the status text. -# Usage: dialog_set_text <text> -dialog_set_text() { - kdialog_qdbus setLabelText "$1" || kdialog_dcop setLabel "$1" -} - -# Set if the progress bar should continously animate instead of showing the value. -# Usage: dialog_set_pulsate <enable> -dialog_set_pulsate() { - _kdialog_max=100 - [ $1 = 1 ] && _kdialog_max=0 - kdialog_qdbus Set "" maximum $_kdialog_max || kdialog_dcop setMaximum $_kdialog_max -} - -# Set the current progress value. -# Usage: dialog_set_value <percentage> -dialog_set_value() { - kdialog_qdbus Set "" value "$1" || kdialog_dcop setProgress "$1" - [ $1 = 100 ] && kdialog_cmd showCancelButton true -} - -# Select an entry in a list. -# Usage dialog_select_entry <var> <label> <tag1> <item1> [ <tag2> < item2> ... ] -dialog_select_entry() { - _kdialog_select_entry_v="$1" ; shift - _kdialog_select_entry_t="$1" ; shift - _kdialog_select_entry_w=" " - _kdialog_select_entry_w="$_kdialog_select_entry_w$_kdialog_select_entry_w" - _kdialog_select_entry_r="$( - kdialog_run 'Select path' \ - --menu "$_kdialog_select_entry_t$_kdialog_select_entry_w" "$@" 2> /dev/null - )" - [ -z "$_kdialog_select_entry_r" ] && return $false - eval "$_kdialog_select_entry_v=\"\$_kdialog_select_entry_r\"" - return $true -} - -# dialog_select_path does not support the --any flag -dialog_select_path_any=0 - -# Let the user select a path. -# Usage: dialog_select_path (--file|--dir|--any) <result-var> <label> -# Any is only supported if $dialog_select_path_any is 1. -dialog_select_path() { - case "$1" in - --any) die 'not implemented' ;; - --file) _kdialog_select_path_f=--getopenfilename ;; - --dir) _kdialog_select_path_f=--getexistingdirectory ;; - esac - _kdialog_select_path="$( - kdialog_run "$3" $_kdialog_select_path_f "$HOME" 2> /dev/null - )" - [ -z "$_kdialog_select_path" ] && return $false - eval "$2=\"\$_kdialog_select_path\"" - return $true -} - -dialog_retry() { - kdialog_run 'Error' \ - --yes-label 'Retry' --no-label 'Ignore' --cancel-label 'Abort' \ - --warningyesnocancel "$1" 2>&1 - case $? in - 0) dialog_retry_choice='retry' ;; - 1) dialog_retry_choice='ignore' ;; - *) dialog_retry_choice='abort' ;; - esac -} - -;; - -#----------------------------------------------------------------------------------------# -Xdialog) - -# Helper functions - -# Run Xdialog -# Usage: Xdialog_run <title-prefix> <dialog-type> [<args>...] -Xdialog_run() { - _Xdialog_run_t="$1" ; shift - [ -z "$_Xdialog_run_t" ] || _Xdialog_run_t="$_Xdialog_run_t - " - Xdialog --left --title "$_Xdialog_run_t$_dialog_title" "$@" -} - -# Dialog abstraction - -# Create the main progress window. -# Usage: dialog_create -dialog_create() { - _Xdialog_width='WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW' - pipe_create Xdialog --left --title "$_dialog_title" --gauge "$_Xdialog_width" 0 0 -} - -# Destroy the main progress window. -# Usage: dialog_destroy -dialog_destroy() { - pipe_destroy -} - -# Show an error dialog. -# Usage: dialog_error <message> -dialog_error() { - dialog_message "$1" # no dedicated error box for Xdialog -} - -# Show a message box. -# Usage: dialog_message <message> -dialog_message() { - Xdialog_run 'Status' --msgbox "$1" 0 0 -} - -# Ask a yes/no question. -# Usage: dialog_ask <question> -dialog_ask() { - Xdialog_run 'Confirm' --yesno "$1" 0 0 -} - -# Has the user quested to cancel the operation? -# Usage: dialog_cancelled && print "cancelled" -dialog_cancelled() { - ! pipe_exists -} - -# Set the status text. -# Usage: dialog_set_text <text> -dialog_set_text() { - pipe_write 'XXX' - pipe_write "$1" - pipe_write 'XXX' -} - -# Set if the progress bar should continously animate instead of showing the value. -# Usage: dialog_set_pulsate <enable> -dialog_set_pulsate() { - true # Pulsate is not supported by Xdialog -} - -# Set the current progress value. -# Usage: dialog_set_value <percentage> -dialog_set_value() { - pipe_write "$1" -} - -# Select an entry in a list. -# Usage dialog_select_entry <var> <label> <tag1> <item1> [ <tag2> < item2> ... ] -dialog_select_entry() { - _Xdialog_select_entry_v="$1" ; shift - _Xdialog_select_entry_t="$1" ; shift - _Xdialog_select_entry_r="$( - Xdialog_run 'Select path' \ - --menubox "$_Xdialog_select_entry_t" 20 80 10 "$@" 2>&1 - )" - [ -z "$_Xdialog_select_entry_r" ] && return $false - eval "$_Xdialog_select_entry_v=\"\$_Xdialog_select_entry_r\"" - return $true -} - -# dialog_select_path does not support the --any flag -dialog_select_path_any=0 - -# Let the user select a path. -# Usage: dialog_select_path (--file|--dir|--any) <result-var> <label> -# Any is only supported if $dialog_select_path_any is 1. -dialog_select_path() { - case "$1" in - --any) die 'not implemented' ;; - --file) _Xdialog_select_path_f=--fselect ;; - --dir) _Xdialog_select_path_f=--dselect ;; - esac - _Xdialog_select_path="$( - Xdialog_run "$3" $_Xdialog_select_path_f "$HOME" 0 0 2>&1 - )" - [ -z "$_Xdialog_select_path" ] && return $false - eval "$2=\"\$_Xdialog_select_path\"" - return $true -} - -dialog_retry() { - Xdialog_run 'Error' --ok-label='Retry' --cancel-label='Ignore' --yesno "$1" 0 0 - case $? in - 0) dialog_retry_choice='retry' ;; - 1) dialog_retry_choice='ignore' ;; - *) dialog_retry_choice='abort' ;; - esac -} - -;; - -#----------------------------------------------------------------------------------------# -0) # command-line - -# Dialog abstraction - -# Create the main progress window. -# Usage: dialog_create -dialog_create() { - true -} - -# Destroy the main progress window. -# Usage: dialog_destroy -dialog_destroy() { - true -} - -# Show an error dialog. -# Usage: dialog_error <message> -dialog_error() { - true # error messages are always printed to stdout -} - -# Show a message box. -# Usage: dialog_message <message> -dialog_message() { - true -} - -# Ask a yes/no question. -# Usage: dialog_ask <question> -dialog_ask() { - die 'unimplemented' -} - -# Has the user quested to cancel the operation? -# Usage: dialog_cancelled && print "cancelled" -dialog_cancelled() { - false # never cancelled SIGINT is not trapped -} - -# Set the status text. -# Usage: dialog_set_text <text> -dialog_set_text() { - true -} - -# Set if the progress bar should continously animate instead of showing the value. -# Usage: dialog_set_pulsate <enable> -dialog_set_pulsate() { - true -} - -# Set the current progress value. -# Usage: dialog_set_value <percentage> -dialog_set_value() { - true -} - -# Select an entry in a list. -# Usage dialog_select_entry <var> <label> <tag1> <item1> [ <tag2> < item2> ... ] -dialog_select_entry() { - _cli_select_entry_var="$1" ; shift - - # Print a list for the user to select from - print "$1:" ; shift - _cli_select_entry_min=$1 - _cli_select_entry_max=$1 - _cli_select_entry_f=' [default]' - while [ $# -gt 0 ] ; do - _cli_select_entry_i=$1 ; shift - _cli_select_entry_t="$1" ; shift - if [ $_cli_select_entry_i -lt $_cli_select_entry_min ] ; then - _cli_select_entry_min=$_cli_select_entry_i - fi - if [ $_cli_select_entry_i -gt $_cli_select_entry_max ] ; then - _cli_select_entry_max=$_cli_select_entry_i - fi - printf ' %d) %s%s\n' $_cli_select_entry_i \ - "$_cli_select_entry_t" "$_cli_select_entry_f" - _cli_select_entry_f='' - done - - # Read a number (or empty string for the first entry) - while true ; do - - puts '> #' - read -r _cli_select_entry_r - - [ -z "$_cli_select_entry_r" ] && _cli_select_entry_r=1 - - case "$_cli_select_entry_r" in - 'quit') ;; 'q') ;; 'exit') ;; 'abort') ;; - *) - if [ ! "$_cli_select_entry_r" -lt $_cli_select_entry_min ] 2> /dev/null \ - && [ ! "$_cli_select_entry_r" -gt $_cli_select_entry_max ] 2> /dev/null - then - eval "$_cli_select_entry_var=\"\$_cli_select_entry_r\"" - return $true - else - printf "Please enter a number between %d and %d.\n" \ - $_cli_select_entry_min $_cli_select_entry_max - continue - fi - esac - die - - done - - return $true -} - -# dialog_select_path supports the --any flag -dialog_select_path_any=1 - -# Let the user select a path. -# Usage: dialog_select_path (--file|--dir|--any) <result-var> <label> -# Any is only supported if $dialog_select_path_any is 1. -dialog_select_path() { - _cli_select_path_var="$2" - print "$3:" ; shift - puts '> ' - read -r _cli_select_path_r - [ -z "$_cli_select_path_r" ] && return $false - eval "$_cli_select_path_var=\"\$_cli_select_path_r\"" - return $true -} - -dialog_retry() { - printf '\n%s\n' "${red}Error:${reset} $1" - while true ; do - print "Abort / [Retry] / Ignore" - puts '> ' - read -r _cli_dialog_retry_r - case "$_cli_dialog_retry_r" in - a|A|abort|Abort|ABORT) dialog_retry_choice='abort' ; return ;; - ''|r|R|retry|Retry|RETRY) dialog_retry_choice='retry' ; return ;; - i|I|ignore|Ignore|IGNORE) dialog_retry_choice='ignore' ; return ;; - esac - done -} - -esac - - -########################################################################################## -# Common user interface implementation - -# Ask the user if the setup should really be cancelled. -handle_cancel() { - _handle_cancel_message="Are you sure you want to exit the Arx Fatalis data installer?" - if [ $installed_stuff = 1 ] ; then - _handle_cancel_message="$_handle_cancel_message - -Already installed files will not be removed!" - fi - if [ $installed_stuff = 1 ] || [ $selected_stuff = 1 ] ; then - dialog_ask "$_handle_cancel_message" || return $true - fi - print 'Aborted by user' && die -} - -# Update the status. -# Usage: status (<percent>|--temp) [<message>] -_status_text="Initializing..." -_status_cur='' -_status_pulsate=default -status() { - - if [ "$1" = '--temp' ] ; then - _status_value=0 - _status_temp=1 - else - _status_value=$1 - _status_temp=0 - fi - _status_new="${2:-$_status_text}" - - # Handle the cancel and close buttons - if dialog_cancelled ; then - handle_cancel - dialog_create || die "Could not re-create progress window." - _status_cur='' - _status_pulsate=default - fi - - # Update the progress text if one was provided - if [ ! "$_status_cur" = "$_status_new" ] ; then - _status_cur="$_status_new" - print "$_status_new" - dialog_set_text "$_status_new" - fi - [ $_status_temp = 0 ] && _status_text="$_status_new" - - # Set the maximum progress value - if [ $_status_value = 0 ] ; then _new_status_pulsate=1 ; else _new_status_pulsate=0 ; fi - if [ ! "$_status_pulsate" = $_new_status_pulsate ] ; then - _status_pulsate="$_new_status_pulsate" - dialog_set_pulsate $_status_pulsate - fi - - # Update the progress value - [ $_status_pulsate = 0 ] && dialog_set_value $_status_value - -} - -# Print an error message and show an error dialog if we have a GUI/ -# Usage: error <message> -error() { - print "${dim_red}$1${reset}" - dialog_error "$1" -} - -# Let the user select an item from a list or enter a custom one. -# In batch mode, select the first one if --first is given, die otherwise. -# Usage: user_select_entry (--existing|--writable) (--any|--file|--dir) \ -# <list> <result-var> <desc> <desc-color> <list-color> <verb> -user_select_entry() { - - _user_select_entry_access="$1" - _user_select_entry_t="$2" - _user_select_entry_lname="$3" - eval "_user_select_entry_list=\"\$$_user_select_entry_lname\"" - _user_select_entry_var="$4" - _user_select_entry_desc="$5" - _user_select_entry_color1="$6" - _user_select_entry_color2="$7" - _user_select_entry_verb="$8" - - # Select the first element if in batch mode - eval "_user_select_entry_current=\"\$$_user_select_entry_var\"" - if [ $batch = 1 ] || [ ! -z "$_user_select_entry_current" ] ; then - _user_select_entry_='' - eval "set -- $_user_select_entry_list" - for _user_select_entry ; do - _user_select_entry_="$_user_select_entry" - break - done - [ -z "$_user_select_entry_" ] && die "Missing $_user_select_entry_desc!" - eval "$_user_select_entry_var=\"\$_user_select_entry_\"" - return $true - fi - - if [ $gui = 0 ] - then print - else status --temp "Select a ${_user_select_entry_desc}" - fi - - _user_select_entry_i=1 - _user_select_entry_nolist=0 - if [ -z "$_user_select_entry_list" ] \ - && [ ! $_user_select_entry_t = --any ] \ - && [ ! $dialog_select_path_any = 1 ] ; then - - # No entries detected - direclty promt the user - _user_select_entry_num=1 - _user_select_entry_nolist=1 - - else - - _user_select_entry_tlist='' - - # Format the list entries in a user friendly way - eval "set -- $_user_select_entry_list" - for _user_select_entry ; do - - # Use 'command (file)' if comment available or 'file' otherwise - _user_select_entry_comment="$( - list_comment "$_user_select_entry_lname" "$((_user_select_entry_i - 1))" - )" - if [ -z "$_user_select_entry_comment" ] ; then - _user_select_entry_label="$_user_select_entry_color2$_user_select_entry$reset" - else - _user_select_entry_label="$_user_select_entry_color2$_user_select_entry_comment$reset" - _user_select_entry_label="$_user_select_entry_label: $_user_select_entry" - fi - - # Add the tag and label to the arguments - list_append _user_select_entry_tlist $_user_select_entry_i - list_append _user_select_entry_tlist "$_user_select_entry_label" - - # Remeber the file for the tag - eval "_user_select_entry_$_user_select_entry_i=\"\$_user_select_entry\"" - - _user_select_entry_i=$((_user_select_entry_i + 1)) - done - - # Add entries for custom files/diectories - if [ $_user_select_entry_t = --any ] && [ $dialog_select_path_any = 1 ] ; then - list_append _user_select_entry_tlist $_user_select_entry_i - list_append _user_select_entry_tlist "Select file or directory to $_user_select_entry_verb.." - else - _user_select_entry_ii=$_user_select_entry_i - if [ $_user_select_entry_t = --any ] || [ $_user_select_entry_t = --file ] ; then - list_append _user_select_entry_tlist $_user_select_entry_ii - list_append _user_select_entry_tlist "Select file to $_user_select_entry_verb..." - _user_select_entry_ii=$((_user_select_entry_ii + 1)) - fi - if [ $_user_select_entry_t = --any ] || [ $_user_select_entry_t = --dir ] ; then - list_append _user_select_entry_tlist $_user_select_entry_ii - list_append _user_select_entry_tlist "Select directory to $_user_select_entry_verb..." - _user_select_entry_ii=$((_user_select_entry_ii + 1)) - fi - fi - - fi - - # Loop until we have selected a value - while true ; do - - if [ $_user_select_entry_nolist = 0 ] ; then - - # Ask the user to select an entry - eval "set -- $_user_select_entry_tlist" - while true ; do - if dialog_select_entry _user_select_entry_num \ - "${_user_select_entry_color1}Select a ${_user_select_entry_desc}${reset}" "$@" - then - break - else - handle_cancel - fi - done - - fi - - if [ $_user_select_entry_num -lt $_user_select_entry_i ] ; then - - # User selected an entry -- return that - eval "$_user_select_entry_var=\"\$_user_select_entry_$_user_select_entry_num\"" - selected_stuff=1 - return $true - - fi - - # Loop until we have selected a path of the correct type - while true ; do - - # Adjust type based on user selection - if [ $_user_select_entry_t = --any ] && [ ! $dialog_select_path_any = 1 ] ; then - if [ $_user_select_entry_num = $_user_select_entry_i ] - then _user_select_entry_type=--file - else _user_select_entry_type=--dir - fi - else - _user_select_entry_type=$_user_select_entry_t - fi - - _user_select_entry_c="Select a custom source " - - if ! dialog_select_path "$_user_select_entry_type" _user_select_entry_path \ - "${_user_select_entry_color1}Choose a custom ${_user_select_entry_desc}${reset}" \ - "$@" ; then - - # User cancelled the dialog - return to the main selection, unless there is none - if [ $_user_select_entry_nolist = 1 ] ; then - handle_cancel - continue # let the user try again - fi - break # return to list selection - - fi - - _user_select_entry_path="$(abspath "$_user_select_entry_path")" - - # The user selected a path, now check if it meets our criteria. - case "$_user_select_entry_access" in - --existing) - if [ ! -e "$_user_select_entry_path" ] ; then - error "$_user_select_entry_path does not exist!" - continue # let the user try again - fi ;; - --writable) - if ! is_writable "$_user_select_entry_path" ; then - error "$_user_select_entry_path is not writable!" - continue # let the user try again - fi ;; - esac - case "$_user_select_entry_t" in - --any) ;; # anything goes - --file) - if [ -e "$_user_select_entry_path" ] && [ -d "$_user_select_entry_path" ] ; then - error "$_user_select_entry_path is is a directory, but we need a file!" - continue - fi ;; - --dir) - if [ -e "$_user_select_entry_path" ] && [ ! -d "$_user_select_entry_path" ] ; then - error "$_user_select_entry_path is is a file, but we need a directory!" - continue - fi ;; - esac - - # Everything went better than expected - save the result - eval "$_user_select_entry_var=\"\$_user_select_entry_path\"" - selected_stuff=1 - return $true - - done - - done - -} - -# Show error message and close windows on exit -ui_cleanup() { - [ -z "$1" ] || dialog_error "$1" - dialog_destroy -} -on_exit ui_cleanup - -# Initilize the UI -dialog_create || die " -Could not create main window. - -You could try the --cli option. -" -[ $gui = 0 ] || status --temp "$_status_text" - - -########################################################################################## -# Autodetect source file/dir - -sourcefiles='' # List of source file/directory candidates - -# Add a source file or directory to the list of candidates. -# Usage: found_source_file <file> [comment] -# Return: $true if more source files should be probed, $false otherwise. -found_source_file() { - set_append sourcefiles "$(canonicalize "$1")" "$2" - if [ $batch = 1 ] ; then return $true ; else return $false ; fi -} - -# Get a subsection in a .vdf file -# Usage: cat config | steam_get_section <section> -steam_get_section() { - # Abuse indentation to find the section end - grep -Pzoi "\\n(\\s*)\"$1\"\\n\\s+\\{(\\n.*)*?\\n\\1}" -} - -# Get a subsection in a .vdf file - and everything after it -# Usage: cat config | steam_get_section_tail <section> -steam_get_section_tail() { - # Abuse indentation to find the section end - grep -Pzoi "\\n\\s*\"$1\"\\n\\s+\\{(\\n.*)*" -} - -# Remove backtick escapes -# Usage: echo <escaped_string> | unescape -steam_unescape() { - sed 's/\\\(.\)/\1/g' -} - -# Get an entry in a .vdf file, or the first one if there are multiple -# Usage: cat config | steam_get_entry <key> -steam_get_entry() { - grep -Pi "^\\s*\"$1\"\s*\".*\"\\s*$" \ - | head -1 \ - | sed 's/^[^"]*"[^"]*"[^"]*"\(.*\)"[^"]*$/\1/' \ - | steam_unescape -} - -# Get the app information section for an appid -# Usage: steam_get_appinfo <config_file> <appid> -steam_get_appinfo() { - _steam_config="$1" - _steam_appid="$2" - - _steam_appinfo="$( - steam_get_section 'Software' < "$_steam_config" \ - | steam_get_section 'Valve' \ - | steam_get_section 'Steam' \ - | steam_get_section 'apps' \ - | steam_get_section "$_steam_appid" - )" - - # Fallback if the tree structure changed - [ -z "$_steam_appinfo" ] && _steam_appinfo="$( - steam_get_section "$_steam_appid" < "$_steam_config" - )" - - # Fallback if the indentation changed - [ -z "$_steam_appinfo" ] && _steam_appinfo="$( - steam_get_section_tail "$_steam_appid" < "$_steam_config" - )" - - print "$_steam_appinfo" -} - -# Get a config entry for an appid -# Usage: steam_get_app_config <config_file> <appid> -steam_get_installdir() { - steam_get_appinfo "$1" "$2" | steam_get_entry 'installdir' -} - -# Find possible source directories from a Steam library -# Usage: probe_steam_library <steamlibrary> -# Return: $true if more source files should be probed, $false otherwise. -probe_steam_library() { - _steam_library="$1" - for _steam_appdir in "$_steam_library/SteamApps" "$_steam_library/steamapps" ; do - _steam_installdir="$_steam_appdir/common/$steam_install_dir" - if [ -d "$_steam_installdir" ] ; then - found_source_file "$_steam_installdir" "Steam" && return $true - fi - done - return $false -} - -# Find possible source directories from a Steam installation -# Usage: probe_steam_root <steamroot> -# Return: $true if more source files should be probed, $false otherwise. -probe_steam_root() { - _steam_root="$1" - - _steam_config="$_steam_root/config/config.vdf" - - if [ -f "$_steam_config" ] ; then - - # Strategy 1: Read install directory from Steam config file - _steam_installdir="$(steam_get_installdir "$_steam_config" "$steam_appid")" - if [ -d "$_steam_installdir" ] ; then - found_source_file "$_steam_installdir" "Steam" && return $true - fi - - # Strategy 2: Look for known install directory in steam libraries - _steam_libraries="$( - sed -n '/BaseInstallFolder/s/^[^\"]*\"[^\"]*\"[^\"]*\"\([^\"]*\)\".*/\1/p' \ - < "$_steam_config" \ - | sed 's:[^a-zA-Z0-9/_.\n]:\\&:g' - )" - _steam_library_call='probe_steam_library "$_steam_library" && return $true' - eval "for _steam_library in $_steam_libraries ; do $_steam_library_call ; done" - - fi - - # Strategy 3: Look for known install directory in the default library - probe_steam_library "$_steam_root" && return $true - - return $false -} - -# Find possible source directories from Steam -# Usage: probe_steam -# Return: $true if more source files should be probed, $false otherwise. -probe_steam() { - _steam_roots='' - for _steam_root in "$HOME/.steam/root" "$HOME/.steam/steam" "$data_home/Steam" ; do - [ -d "$_steam_root" ] || continue - set_append _steam_roots "$(canonicalize "$_steam_root")" - done - _steam_root_call='probe_steam_root "$_steam_root" && return $true' - [ -z "$_steam_roots" ] && return $false - eval "for _steam_root in $_steam_roots ; do $_steam_root_call ; done" - return $false -} - -# Find a match for a case insensitive path containing arx.exe -# Usage: probe_wine_path <baseprefix> <ipath> -probe_wine_path() { - [ -d "$1" ] || return $false - if [ -z "$2" ] ; then - if icontains "$1" 'arx.exe' ; then - found_source_file "$1" "Wine" - fi - return $false - fi - _wine_path_dir="${2%%\\*}" - if [ "$_wine_path_dir" = "$2" ] - then _wine_path='' - else _wine_path="${2#*\\}" - fi - _wine_paths="$( - find "$1/" -mindepth 1 -maxdepth 1 -iname "$(escape "$_wine_path_dir")" -print \ - | lines_to_list - )" - [ -z "$_wine_paths" ] && return $false - _wine_path_call='probe_wine_path "$_wine_path_prefix" "$_wine_path" && return $true' - eval "for _wine_path_prefix in $_wine_paths ; do $_wine_path_call ; done" - return $false -} - -# Find possible source directories from a registry key. -# Usage: probe_wine_registry <key> <variable> -# Return: $true if more source files should be probed, $false otherwise. -probe_wine_registry() { - - # This is intentionally implemented without calling wine as we don't want to - # modify the source. - - # Get candidate paths from the registry file - _wine_pattern='Software\\\\(Wow6432Node\\\\)?' - _wine_pattern="$_wine_pattern$(print "$1" | sed 's/\\/\\\\/g' | escape_pipe '()|')" - _wine_paths="$( - # The --after is just an arbitrary limit - # We verify the paths by checking for arx.exe, but for effiency we still want - # to avoid false positives. - cat "$_wine_prefix"/*.reg \ - | grep -iPA 20 "^\\[$_wine_pattern\\]" 2> /dev/null \ - | grep -iP "^\"?$2\"?=" 2> /dev/null \ - | sed 's/^[^=]*="\([^"]*\)".*$/\1/;s/\\\(.\)/\1/g' \ - | lines_to_list - )" - - # For each candidate, find a case-insensitive match and check if it contains arx.exe - eval "set -- $_wine_paths" - for _wine_path ; do - probe_wine_path "$_wine_prefix/dosdevices" "$_wine_path" && return $true - done - - return $false -} - -# Find possible source directories from uninstall registry entries. -# Usage: probe_wine_uninstall_info <id> -# Return: $true if more source files should be probed, $false otherwise. -probe_wine_uninstall_info() { - probe_wine_registry "Microsoft\\Windows\\CurrentVersion\\Uninstall\\$1" \ - 'InstallLocation' -} - -# Find possible source directories in a WINEPREFIX. -# Usage: probe_wineprefix <wineprefix> -# Return: $true if more source files should be probed, $false otherwise. -probe_wineprefix() { - - [ -d "$1" ] || return $false - [ -e "$1/system.reg" ] || [ -e "$1/user.reg" ] || return $false - _wine_prefix="$1" - - # Normal install - probe_wine_registry 'Arkane Studios\Installed Apps\Arx Fatalis' 'Folder' && return $true - - # GOG version - probe_wine_registry 'GOG.com\GOGARXFATALIS' 'PATH' && return $true - - # Probe uninstall entries - combined for effiency - _wine_uninstall='Microsoft\Windows\CurrentVersion\Uninstall\' - # Steam - _wine_steam="Steam App $steam_appid" - # Original game - _wine_orig='{96443F45-13E2-11D6-AC87-00D0B7A9E540}' - # 1.21 patch - _wine_patch='{171251E0-4EED-4EA1-A46D-3213A226F2B3}_is1' - probe_wine_registry "$_wine_uninstall($_wine_steam|$_wine_orig|$_wine_patch)" \ - 'InstallLocation' && return $true - -} - -# Check a mounte point if it's an Arx Fatalis cd -# Usage: probe_cd <mountpoint> <fstype> -# Return: $true if more source files should be probed, $false otherwise -probe_cd() { - node="$1" - mountpoint="$2" - fstype="$3" - - case "$fstype" in - cd9660) ;; iso9660) ;; udf) ;; *fuseiso) ;; - *) return $true - esac - - if [ -d "$mountpoint/bin" ] && icontains "$mountpoint/bin" 'arx.ttf' 2> /dev/null ; then - found_source_file "$mountpoint" "CDROM at $node" && return $true - fi - -} - -# Find mounted Arx Fatalis CDs -# Usage: probe_cdrom -# Return: $true if more source files should be probed, $false otherwise -probe_cdrom() { - - _probe_cdrom_mountpoints="$( - [ -f /proc/mounts ] && lines_to_list < /proc/mounts # Linux - use /proc/mounts - mount -p 2> /dev/null | lines_to_list # Hope that mount has a -p option - )" - - eval "set -- $_probe_cdrom_mountpoints" - for _probe_cdrom_line ; do - eval "probe_cd $(escape "$_probe_cdrom_line" ' ' | sed 's/\\\\\040/\\ /g')" # space-separated - eval "probe_cd $(print "$_probe_cdrom_line" | tr '\t' '\n' | lines_to_list)" # tab-separated - done - -} - -# Find possible source files/directories -# Usage: probe_source_files -# If sourcefile is already set, uses that. -probe_source_files() { - - if [ ! -z "$sourcefile" ] ; then - - # Trust the user - found_source_file "$sourcefile" && return $true - - # But also allow to refile the dir in non-batch mode if it is a wineprefix - [ -d "$sourcefile" ] && probe_wineprefix "$sourcefile" - - [ "$sourcefiles" = "$sourcefile" ] || sourcefile='' - - return $true - fi - - status 5 "Searching for source files..." - - # Find by filename - probe_files found_source_file "$gog_names" 'GOG.com setup' - probe_files found_source_file "$demo_names" 'Demo' - - probe_steam && return $true - - # Find an Arx Fatalis installation in $WINEPREFIX - [ ! -z "${WINEPREFIX-}" ] && probe_wineprefix "$WINEPREFIX" && return $true - - # Find an Arx Fatalis installation in ~/.wine - [ ! "${WINEPREFIX-}" = "$HOME/.wine" ] && probe_wineprefix "$HOME/.wine" && return $true - - # Find an Arx Fatalis cdrom - probe_cdrom && return $true - - # Just in case it will ever be installable under non-Windows systems - steam_source_path="$HOME/.steam/root/SteamApps/common/Arx Fatalis" - [ -d "$steam_source_path" ] && found_source_file "$steam_source_path" 'Steam' - -} - - -########################################################################################## -# Autodetect destination dir - -datadirs='' # List of destination data directory candidate - -# Add a destination data directory to the list of candidates. -# Usage: found_data_dir <dir> [comment] -# Return: $true if more data directories should be probed, $false otherwise. -found_data_dir() { - set_append datadirs "$(abspath "$1")" "$2" - if [ $batch = 1 ] ; then return $true ; else return $false ; fi -} - -# Add a destination data directory to the list of candidates if it is writable. -# In verify mode, also existing read-only directories are added. -# Usage: probe_data_dir <must-exists> <dir> [comment] -# Return: $true if more data directories should be probed, $false otherwise. -probe_data_dir() { - [ "$1" = 1 ] && [ ! -e "$2" ] && return $false - [ $install = 0 ] && [ ! -e "$2" ] && return $false - if [ $install = 1 ] || [ $patch = 1 ] ; then is_writable "$2" || return $false ; fi - found_data_dir "$2" "$3" -} - -# Find possible destination data directories -# Usage: probe_data_dirs -# If datadir is already set, uses that. -probe_data_dirs() { - - if [ ! -z "$datadir" ] ; then - found_data_dir "$datadir" - return $true - fi - - status 10 "Searching for destination directories..." - - for _probe_data_dirs_existing in 1 0 ; do - - # Try paths supplied by wrapper scripts - if [ ! -z "$data_path" ] ; then - eval "set -- $(to_list "$data_path")" - for _probe_data_dirs_path ; do - if [ -f "$_probe_data_dirs_path/data" ] ; then - eval "set -- $(lines_to_list < "$_probe_data_dirs_path/data")" - for _probe_data_dirs_line ; do - case "$_probe_data_dirs_line" in - /*) ;; *) _probe_data_dirs_line="$( - canonicalize "$_probe_data_dirs_path/$_probe_data_dirs_line" - )" - esac - probe_data_dir $_probe_data_dirs_existing "$_probe_data_dirs_line" \ - "portable" && return $true - done - elif [ -d "$_probe_data_dirs_path/data" ] ; then - probe_data_dir $_probe_data_dirs_existing "$_probe_data_dirs_path/data" \ - "portable" && return $true - else - probe_data_dir $_probe_data_dirs_existing "$_probe_data_dirs_path" "portable" \ - && return $true - fi - done - fi - - # Try system paths - eval "set -- $(to_list "$data_dirs")" - for _probe_data_dirs_prefix in "$@" ; do - eval "set -- $(to_list "$data_dir_suffixes")" - for _probe_data_dirs_suffix ; do - _probe_data_dirs_force=$_probe_data_dirs_existing - [ -e "$_probe_data_dirs_prefix/$_probe_data_dirs_suffix" ] && \ - _probe_data_dirs_force=0 - probe_data_dir $_probe_data_dirs_force \ - "$_probe_data_dirs_prefix/$_probe_data_dirs_suffix/data" "system" \ - && return $true - probe_data_dir $_probe_data_dirs_existing \ - "$_probe_data_dirs_prefix/$_probe_data_dirs_suffix" "system" \ - && return $true - done - done - - # Try user paths - if [ $is_root = 0 ] ; then - eval "set -- $(to_list "$user_dir_suffixes")" - for _probe_data_dirs_suffix ; do - _probe_data_dirs_force=$_probe_data_dirs_existing - [ -e "$data_home/$_probe_data_dirs_suffix" ] && \ - _probe_data_dirs_force=0 - probe_data_dir $_probe_data_dirs_force \ - "$data_home/$_probe_data_dirs_suffix/data" "user" \ - && return $true - [ $install = 0 ] && probe_data_dir $_probe_data_dirs_existing \ - "$data_home/$_probe_data_dirs_suffix" "user" \ - && return $true - done - fi - - done - -} - - -########################################################################################## -# Extract helpers and other utility abstractions - -# Calculate the MD5 checksum of a file. -# Usage: checksum <result-var> <file> -checksum() { - - if have md5sum ; then - _checksum_result="$(md5sum -b "$2" | sed 's/ .*//g')" - eval "$1=\"\$_checksum_result\"" - return $true - fi - - if have md5 ; then - _checksum_result="$(md5 -q "$2")" - eval "$1=\"\$_checksum_result\"" - return $true - fi - - die "You need either md5sum or md5." -} - -have_run() { - eval "_have_run_p=\"\$${1}_reqs\"" - eval "for _have_run_program in $_have_run_p ; do have \$_have_run_program && return $true ; done" - return $false -} - -# Extract an archive file to the current directory. -# Usage: extract <file> <types>... -have_extract() { - have_run "extract_$1" -} -extract() { - _extract_file="$1" ; shift - - while true ; do - - _extract_missing='' - for _extract_type ; do - - if "have_extract_${_extract_type}" ; then - "extract_${_extract_type}" "$_extract_file" && return "$true" - else - list_merge _extract_missing extract_${_extract_type}_reqs - fi - - done - - _extract_msg="${white}Could not extract $(basename "$_extract_file")${reset}" - [ -z "$_extract_missing" ] \ - || _extract_msg="$_extract_msg - -Please install one or more of the following: -$(print_help_list " - $dim_pink" _extract_missing)" - - [ $batch = 1 ] && die "Error: $_extract_msg" - - dialog_retry "$_extract_msg" - case $dialog_retry_choice in - abort) die "Error extracting files" ;; - retry) continue ;; - ignore) return $true ;; - esac - - done - -} - -# Extract a .zip file to the current directory. -# Usage: extract_zip <zipfile> -have_extract_zip() { have_extract zip ; } -extract_zip() { - - if have bsdtar ; then - printf 'Extracting %s using bsdtar\n' "$1" - bsdtar xvf "$1" - return $? - fi - - if have unzip ; then - puts 'unzip: ' - unzip "$1" - return $? - fi - - for _extract_zip_sz in 7za 7z ; do - if have $_extract_zip_sz ; then - $_extract_zip_sz x "$1" - return $? - fi - done - - die "no program to extract $1" -} - -# Mount a .iso file or CDROM using fuseiso if available or normal mount if root. -# Usage: mount_cdrom <cdromfile> <mountpoint> -have_mount_cdrom() { - have fuseiso && have fusermount && return $true - have mount && have umount && [ $is_root = 1 ] && return $true - return $false -} -mount_cdrom() { - - if have fuseiso && have fusermount && fuseiso "$1" "$2" ; then - printf 'Mounted %s at %s using fuseiso\n' "$1" "$2" - return $true - fi - - if have mount && have umount && [ $is_root = 1 ] && mount -o loop,ro "$1" "$2" ; then - printf 'Mounted %s at %s\n' "$1" "$2" - return $true - fi - - die "no program to extract $1" -} - -# Unmount a CDROM that was mounted using mount_cdrom. -# Usage: unmount_cdrom <mountpoint> -unmount_cdrom() { - have fusermount && fusermount -u "$1" > /dev/null 2>&1 - have umount && [ $is_root = 1 ] && umount "$1" > /dev/null 2>&1 -} - -# isoinfo wrapper to extract all files to the current directory -extract_isoinfo() { - _extract_isoinfo_file="$1" - - # Get a list of all files in the ISO image - _extract_isoinfo_files="$( - isoinfo -i "$_extract_isoinfo_file" -J -f | grep ';1$' | lines_to_list - )" - [ -z "$_extract_isoinfo_files" ] && return $false - - eval "set -- $_extract_isoinfo_files" - for _extract_isoinfo_e ; do - - # Remove leading / and trailing ;1 from filenames - _extract_isoinfo_f="$(print "$_extract_isoinfo_e" | sed 's:^/*::;s:;1$::')" - [ -z "$_extract_isoinfo_f" ] && continue - printf ' - %s\n' "$_extract_isoinfo_f" - - # Create subdirectories as needed - _extract_isoinfo_d="$(dirname "$_extract_isoinfo_f")" - [ -z "$_extract_isoinfo_d" ] || mkdir -p "$_extract_isoinfo_d" || return $false - - # Extract the file - isoinfo -i "$_extract_isoinfo_file" -J -x "$_extract_isoinfo_e" \ - > "$_extract_isoinfo_f" || return $false - - # Don't rely on isoinfo setting a non-zero return code, check that we got something - [ -s "$_extract_isoinfo_f" ] || return $false - - done - - return $true -} - -# Extract a .iso file or CDROM to the current directory. -# Usage: extract_iso <cdromfile> -have_extract_iso() { have_extract iso ; } -extract_iso() { - - if have isoinfo ; then - printf 'Extracting %s using isoinfo\n' "$1" - extract_isoinfo "$1" - return $? - fi - - ret=$false - - if have bsdtar ; then - printf 'Extracting %s using bsdtar\n' "$1" - bsdtar xvf "$1" - ret="$?" - - # Older versions of bsdtar don't always get the names right - fix them - _extrac_cdrom_f="$(find "$PWD" -depth -iname '*;1' | lines_to_list)" - if [ ! -z "$_extrac_cdrom_f" ] ; then - eval "for _extract_iso_f in $_extrac_cdrom_f ; do mv -f \"\$_extract_iso_f\" \"\$(print \"\$_extract_iso_f\" | sed 's:;1$::')\" ; done" - fi - - elif have 7z ; then - 7z x -tiso "$1" - ret="$?" - fi - - # For some iso files bsdtar just does nothing - at least let the user know - if [ ! -d "$PWD/bin" ] || ! icontains "$PWD/bin" 'arx.ttf' ; then - _extract_iso_err="${yellow}It looks like bsdtar/p7zip didn't do what it was supposed to - this will likely fail!${reset} - -You might have better luck with ${dim_pink}isoinfo${reset} or ${dim_pink}fuseiso${reset}, or by manually mounting the CD/ISO." - printf '%s\n' "$_extract_iso_err" - [ $batch = 0 ] && dialog_message "$_extract_iso_err" - fi - - return $ret -} - -# Extract a microsoft .cab or .exe file to the current directory. -# Usage: extract_ms_cab <cabfile> -extract_cab_check_bsdtar() { - if have bsdtar ; then - case "$(bsdtar --version)" in - # These versions have bugs that cause corrupted files - '') ;; - *'libarchive 1.'*) ;; - *'libarchive 2.'*) ;; - *'libarchive 3.0') ;; - *'libarchive 3.0.'*) ;; - # Newer versions should work fine - *) - return $true - esac - fi - return $false -} -have_extract_ms_cab() { - extract_cab_check_bsdtar && return $true - have cabextract || have 7za || have 7z -} -extract_ms_cab() { - - if extract_cab_check_bsdtar ; then - printf 'Extracting %s using bsdtar\n' "$1" - bsdtar xvf "$1" - return $? - fi - - if have cabextract ; then - puts 'cabextract: ' - cabextract "$1" - return $? - fi - - for _extract_ms_cab_sz in 7za 7z ; do - if have $_extract_ms_cab_sz ; then - $_extract_ms_cab_sz x "$1" - return $? - fi - done - - die "no program to extract $1" -} - -# Extract an InstallShield .cab or .exe file to the current directory. -# Usage: extract_installshield <cabfile> -have_extract_installshield() { have_extract installshield ; } -extract_installshield() { - - if have unshield ; then - puts 'unshield: ' - unshield x "$1" - return $? - fi - - die "no program to extract $1" -} - -# Extract a RAR .rar or .exe file to the current directory. -# Usage: extract_rar <rarfile> -have_extract_rar() { have_extract rar ; } -extract_rar() { - - if have unrar ; then - puts 'unrar: ' - unrar x -y -o "$1" - return $? - fi - - die "no program to extract $1" -} - -# Extract an ACE .ace or .exe file to the current directory. -# Usage: extract_ace <acefile> -have_extract_ace() { have_extract ace ; } -extract_ace() { - - if have unace ; then - puts 'unace ' - unace x -y -o "$1" - return $? - fi - - die "no program to extract $1" -} - -# Extract an Inno Setup .exe file to the current directory. -# Usage: extract_innosetup <exefile> -have_extract_innosetup() { have innoextract ; } -innosetup_language='' -extract_innosetup() { - - if have innoextract ; then - puts 'innoextract: ' - if [ -z "$innosetup_language" ] - then innoextract --color=off "$1" ; return $? - else innoextract --color=off --language="$innosetup_language" "$1" ; return $? - fi - fi - - die "no program to extract $1" -} - -# Extract all .cab files in a directory. -# Usage: extract_cab_files <sourcedir> <destdir> -extract_cab_files() { - - _extract_cab_files_i=0 - _extract_cab_files_files="$( - find "$1/" -mindepth 1 -type f -iname '*.cab' -print \ - | lines_to_list - )" - eval "set -- $_extract_cab_files_files" - for _extract_cab_files_cabfile ; do - [ -z "$_extract_cab_files_cabfile" ] && continue - - while true ; do - _extract_cab_files_cabdir="$sourcedir/cab.$_extract_cab_files_i" - if [ -e "$_extract_cab_files_cabdir" ] ; then - _extract_cab_files_i=$((_extract_cab_files_i + 1)) - continue - fi - create_dir "$_extract_cab_files_cabdir" "cab #$i work" - break - done - - cd "$_extract_cab_files_cabdir" - case "$(basename "$_extract_cab_files_cabfile")" in - data*) extract "$_extract_cab_files_cabfile" installshield ms_cab ;; - *) extract "$_extract_cab_files_cabfile" ms_cab installshield ;; - esac - - _extract_cab_files_i=$((_extract_cab_files_i + 1)) - done - -} - -# Download a file. -# Usage: download_file <url> <destination> -have_download() { have_run download ; } -download_impl() { - - if have wget ; then - wget -O "$2" "$1" - return $? - fi - - if have curl ; then - curl --location --fail -o "$2" "$1" - return $? - fi - - if have fetch ; then - fetch -o "$2" "$1" - return $? - fi - - die "no program to download $1" -} -download_file() { - - download_impl "$1" "$2" || return $false - - # Check that we got something useful - case "$(file --dereference --brief --mime-type "$2" 2> /dev/null)" in - */html*) ;; - */xml*) ;; - *) return $true - esac - - rm -f "$2" - return $false; -} - -# Download a file from a list of mirrors. -# Usage: download <callback> <name> <names> <urls> <destdir> -download() { - _download_callback="$1" - _download_name="$2" - _download_names="$3" - _download_urls="$4" - _download_dest="$5" - - while true ; do - - probe_files "$_download_callback" "$_download_names" && return $true - - _download_missing='' - if have_download ; then - eval "for _download_url in $_download_urls ; do download_file \"\$_download_url\" \"\$_download_dest\" && \$_download_callback \"\$_download_dest\" && return $true ; done" - else - list_merge _download_missing download_reqs - fi - - _download_msg="${white}Could not download ${_download_name}${reset}" - [ -z "$_download_missing" ] \ - || _download_msg="$_download_msg - -Please install one of the following: -$(print_help_list " - $dim_pink" _download_missing)" - - _download_msg="$_download_msg - -You can download the file manually from -$(print_help_list " - $dim_blue" _download_urls) - -and put it in one of these locations: -$(print_help_list " - $dim_white" probe_file_dirs)" - - [ $batch = 1 ] && die "Error: $_download_msg" - - dialog_retry "$_download_msg" - case $dialog_retry_choice in - abort) die "Error downloading files" ;; - retry) continue ;; - ignore) return $true ;; - esac - - done - -} - - -########################################################################################## -# Unpack source - -workdir='' -cleanup_workdir() { - [ ! -z "$workdir" ] && [ -e "$workdir" ] && rm -rf "$workdir" -} -# Create the work directory if it doesn't exist. -# Also regiter a cleanup function to remove the work directory on exit. -# Usage: create_workdir -create_workdir() { - [ -z "$workdir" ] || return $true - selected_stuff=1 - workdir="$datadir/$command-temp" - cleanup_workdir - on_exit cleanup_workdir - create_dir "$workdir" 'work' -} - -# Extract setup*.cab files from a source directory into $sourcedir/cab.*. -# Usage: extract_source_dir <sourcedir> -extract_source_dir() { - extract_cab_files "$1" "$sourcedir" -} - -# Extract a source executable into $sourcedir/exe. -# Usage: extract_source_exe <sourcefile> -extract_source_exe() { - - sourcedir_exe="$sourcedir/exe" - create_dir "$sourcedir_exe" 'exe work' - - cd "$sourcedir_exe" || die - case "$(basename "$1")" in - arx_demo_english.exe) - extract "$1" rar ace ms_cab installshield innosetup ;; # English demo - arx_demo_german.exe) - extract "$1" ace rar ms_cab installshield innosetup ;; # German demo - arx_jpn_*.exe) - extract "$1" ms_cab installshield innosetup rar ace ;; # Japanese demo - *) - extract "$1" innosetup ms_cab installshield rar ace ;; # GOG.com setup - esac - - extract_source_dir "$sourcedir_exe" - -} - -# Wrap mount_cdrom et al so we can use them with extract() -extract_mount_cdrom_reqs='' -list_merge extract_mount_cdrom_reqs mount_cdrom_reqs -have_extract_mount_cdrom() { have_mount_cdrom ; } -extract_mount_cdrom() { - # Ignore the current working directory, always mount to $cdromdir - if mount_cdrom "$1" "$cdromdir" ; then - # Pretent the mountpoint is the original source - sourcefile="$cdromdir" - sourcedir_cdrom="$cdromdir" - return $true - else - return $false - fi -} - -cdromdir='' -cleanup_cdrom() { - [ ! -z "$cdromdir" ] && [ -e "$cdromdir" ] && unmount_cdrom "$cdromdir" -} -# Mount a source CDROM/ISO and adjust $sourcefile or extract it into $sourcedir/cdrom. -# Usage: extract_source_cdrom <sourcefile> -extract_source_cdrom() { - - # Try to mount the cdrom to avoid unneeded copies - # Keep the mount point out of $sourcedir so we don't try to mv files from it - cdromdir="$workdir/cdrom" - cleanup_cdrom - on_exit cleanup_cdrom - create_dir "$cdromdir" 'mount work' - - # Otherwise, extract the files from the CDROM if we have the required tools - sourcedir_cdrom="$sourcedir/cdrom" - create_dir "$sourcedir_cdrom" 'cdrom work' - cd "$sourcedir_cdrom" || die - - extract "$1" mount_cdrom iso - - # Extract any cab files on the CDROM - extract_source_dir "$sourcedir_cdrom" -} - -# Extract a source executable into $sourcedir/zip. -# Also extracts contained setup*.cab files into $sourcedir/cab.*. -# Usage: extract_source_zip <sourcefile> -extract_source_zip() { - - sourcedir_zip="$sourcedir/zip" - create_dir "$sourcedir_zip" 'zip work' - - cd "$sourcedir_zip" || die - extract "$1" zip - - extract_source_dir "$sourcedir_zip" -} - -sourcedir='' -# Extract the source file or directory if it hansn't been extracted already. -# Usage: extract_source -extract_source() { - [ -z "$sourcedir" ] || return $true - - status --temp "${white}Extracting source...${reset}" - - create_workdir - sourcedir="$workdir/source" - create_dir "$sourcedir" 'source work' - - if [ -d "$sourcefile" ] ; then - extract_source_dir "$sourcefile" - elif [ -f "$sourcefile" ] ; then - case "$sourcefile" in - *.zip) extract_source_zip "$sourcefile" ;; - *.exe) extract_source_exe "$sourcefile" ;; - *.iso) extract_source_cdrom "$sourcefile" ;; - *) - case "$(file --dereference --brief --mime-type "$sourcefile" 2> /dev/null)" in - application/zip) extract_source_zip "$sourcefile" ;; - application/x-dosexec) extract_source_exe "$sourcefile" ;; - application/x-iso9660-image) extract_source_cdrom "$sourcefile" ;; - *) die "Unknown source file type: $sourcefile" - esac - esac - else - extract_source_cdrom "$sourcefile" - fi - - print -} - - -########################################################################################## -# Detect data language - -find_file_impl() { - _patchable="$1" - - # Search for both file.ext and file_default.ext - _file="$(escape "$(basename "$2")")" - _file_d="$(print "$_file" | sed 's/^\(.*\)\(\.[^.]*\)$/\1_default\2/')" - - # Prefer files from the patch - if availbale, they are most likely the correct ones - set -- -iname "$_file" -print -o -iname "$_file_d" -print - [ "$_patchable" = 1 ] && [ ! -z "$patchdir" ] && find "$patchdir" "$@" - - # Find the file in the source - [ ! -z "$sourcedir" ] && find "$sourcedir" "$@" - [ -d "$sourcefile" ] && find "$sourcefile" "$@" - - # Also find the file if it is already in the data directory, but don't ignore case - find "$datadir" -path '*-temp' -prune -o \ - -name "$_file" -print -o -name "$_file_d" -print - -} -# Find a file in patch, source and data directories. -# Usage: find_file <is-patchable> <return-list-var> <filename/path> -find_file() { - eval "$2=\"\$(find_file_impl \"\$1\" \"\$3\" | lines_to_list)\"" -} - -# Copy/move a file to the data diectory. -# Usage: use_file <file> <data-path> -# Action taken depends on the source directory. -use_file() { - _in="$1" - _out="$datadir/$2" - - # Don't change anything on verify-only mode - [ $install = 0 ] && [ $patch = 0 ] && return $true - - # Don't try to copy/move a file onto itself - [ "$_in" = "$_out" ] && return $true - - # Create directories as needed - _outdir="$(dirname "$_out")" - create_dir "$_outdir" 'output' - - # Copy or move the file - if [ "${_in#"$sourcefile"}" = "$_in" ] - then mv -f "$_in" "$_out" || die "Could not move $_in to $_out!" - else cp -f "$_in" "$_out" || die "Could not copy $_in to $_out!" - fi - installed_stuff=1 - - # Fix permissions - chmod --reference="$_outdir" "$_out" > /dev/null 2>&1 - chmod -x "$_out" > /dev/null 2>&1 -} - -data_lang='' # Data language/tipe ID -data_lang_desc='' # Friendly data language/type label - -# Detect the data language and type -# Usage: detect_data_langauge <callback> -# <callback> receives a speech.pak checksum and sets data_lang and data_lang_desc -detect_data_langauge() { - callback="$1" - - if [ $install = 1 ] - then _detect_data_langauge_status=40 - else _detect_data_langauge_status=10 - fi - [ $gui = 0 ] || status $_detect_data_langauge_status 'Detecting data language...' - puts "${white}Detecting data language..." - - _speech_checksums='' - - find_file 0 _speech_files 'speech.pak' - eval "set -- $_speech_files" - for _speech_file ; do - - checksum _speech_checksum "$_speech_file" - - data_lang='' - "$callback" "$_speech_checksum" - - if [ -z "$data_lang" ] ; then - list_append _speech_checksums "$_speech_checksum" - else - use_file "$_speech_file" 'speech.pak' - break - fi - - done - - if [ -z "$data_lang" ] ; then - printf '\n' - case "$_speech_checksums" in - '') die "speech*.pak not found" ;; - *) die "Unsupported data language - speech*.pak checksum: $_speech_checksums" ;; - esac - fi - - printf " ${green}%s${reset}\n\n" "${data_lang_desc}" - -} - - -########################################################################################## -# Get the patch file - -# Warn if the user-supplied patch file has a suspicious name. -# Usage: patch_check_file_name <file> <expected-name-list> -patch_check_file_name() { - _user_patch_name="$(basename "$1")" - _patch_check_file_names="$2" - if ! list_contains _patch_check_file_names "$_user_patch_name" ; then - printf "${yellow}Warning: unexpected patch file name: %s\n" "$_user_patch_name" >&2 - printf "Expected %s${reset}\n" "$(print_help_or _patch_check_file_names)" >&2 - fi -} - -# Find or download a patch file. -# Usage: probe_patch_file_impl <callback> <name> <user-supplied-file> \ -# <expected-name-list> <url-list> \ -# <callback> will be called with the patch file -probe_patch_file_impl() { - - _patch_found="$1" - _patch_name="$2" - _patch_file="$3" - _patch_names="$4" - _patch_urls="$5" - - if [ ! -z "$_patch_file" ] ; then - - # Check the filename of user-supplied patchse - patch_check_file_name "$_patch_file" "$_patch_names" - - "$_patch_found" "$_patch_file" - return $true - fi - - [ $probe_patch = 0 ] && return $true - - # Probe local files now so we don't lie abut downloading it - probe_files "$_patch_found" "$_patch_names" && return $true - - status --temp "${white}Downloading patch ${blue}${_patch_name}${reset}..." - - create_workdir - download "$_patch_found" "$_patch_name" \ - "$_patch_names" "$_patch_urls" "${workdir}/${_patch_name}" \ - && return $true - -} - -# Callback for the japanese patch. -patch_jp_found() { - patchfile_jp="$(abspath "$1")" - printf "Using Japanese %s patch: ${blue}%s${reset}\n" \ - "$patch_jp_ver" "$patchfile_jp" - return $true -} - -# Callback for the main patch. -patch_found() { - patchfile="$(abspath "$1")" - printf "Using %s patch: ${blue}%s${reset}\n" "$patch_ver" "$patchfile" - return $true -} - -# Find the patch file(s) for a specific language. -# Usage: probe_patch_file <language> -# If patchfile is already set, uses that. -probe_patch_file() { - - _patch_file_lang='' - case "$1" in - 'german') _patch_file_lang='GE' ;; - 'english') _patch_file_lang='EN' ;; - 'spanish') _patch_file_lang='ES' ;; - 'french') _patch_file_lang='FR' ;; - 'italian') _patch_file_lang='IT' ;; - 'russian') _patch_file_lang='RU' ;; - 'japanese') - _patch_jp_names='' - list_append _patch_jp_names "$patch_jp_name" - probe_patch_file_impl patch_jp_found "$patch_jp_name" "$patchfile_jp" \ - "$_patch_jp_names" "$patch_jp_urls" - ;; - esac - _patch_names='' - list_append _patch_names "$patch_name" - if [ ! -z "$_patch_file_lang" ] ; then - list_append _patch_names "$(printf "$patch_name_localized" "$_patch_file_lang")" - fi - - probe_patch_file_impl patch_found "$patch_name" "$patchfile" \ - "$_patch_names" "$patch_urls" - -} - -patchdir='' # Directory where the patch file(s) are extracted - -# Extract all patch files for a specific language. -# Usage: extract_patch <language> -# Does nothing if the patch files are already extracted. -extract_patch() { - [ -z "$patchdir" ] || return $true - _extract_patch_lang="$1" - - print - - # Search for and download the patch files if needed - probe_patch_file "$_extract_patch_lang" - - status --temp "${white}Extracting patch...${reset}" - - create_workdir - patchdir="$workdir/patch" - create_dir "$patchdir" 'patch work' - - # Extract the main patch file - if [ ! -z "$patchfile" ] ; then - _patchdir_main="$patchdir/main" - create_dir "$_patchdir_main" 'main patch work' - cd "$_patchdir_main" - innosetup_language="$_extract_patch_lang" - extract "$patchfile" innosetup - innosetup_language='' - fi - - if [ ! -z "$patchfile_jp" ] ; then - - # Extract the Japanese patch file - _patchdir_jp="$patchdir/main" - create_dir "$_patchdir_jp" 'jp patch work' - cd "$_patchdir_jp" - extract "$patchfile_jp" ms_cab - - # Also extract contained files - extract_cab_files "$_patchdir_jp" "$patchdir" - - fi - - print - status --temp -} - - -########################################################################################## -# Copy and verify files - -checksum_failed=0 # Was there any mismatched checksum or missing file so far? - -# Handle a required file: find, compare checksum and copy/move if needed. -# Usage: required_file <is-patchable> <filepath> <checksums> -required_file() { - - _patchable="$1" - _name="$2" - _valid="$3" - - find_file 1 _files "$_name" - eval "set -- $_files" - _checksums='' - for _file ; do - checksum _checksum "$_file" - - if list_contains _valid "$_checksum" ; then - # We found a match - use it - printf ' - %s\n' "$_name" - use_file "$_file" "$_name" - return $true - fi - - # Remember mismatched checksums so we can output debug info if none matched - list_append _checksums "$_checksum" - continue - - done - - # No matching file found! - - # If we didn't use the patch yet, fetch it and try again! - if [ $patch = 1 ] && [ $_patchable = 1 ] && [ -z "$patchdir" ] ; then - extract_patch "$data_lang" - if [ ! -z "$patchdir" ] ; then - required_file "$_patchable" "$_name" "$_valid" - return $? - fi - fi - - # Let the user know that something is wrong! - if [ -z "$_checksums" ] ; then - printf "${red}Missing ${dim_red}%s${red}!${reset}\n" "$_name" >&2 - else - printf "${red}Checksum failed for ${dim_red}%s${reset}:\n" "$_name" >&2 - printf " expected: ${dim_red}%s${reset}\n" "$(print_help_or _valid)" >&2 - printf " actual: ${dim_red}%s${reset}\n" "$(print_help_or _checksums)" >&2 - fi - - # Be optimistic, copy the first result even if the checksum doesn't match! - # We will display an error at the end (end exit with $false), but it may still work. - eval "set -- $_files" - for _file ; do - use_file "$_file" "$_name" - break - done - - checksum_failed=1 - return $false -} - -# Handle an optional file: find and copy/move if it exists. -# Usage: optional_file <filepath> -optional_file() { - _name="$1" - find_file 1 _files "$_name" - eval "set -- $_files" - for _file ; do - # There is no checksum, just copy the first file - printf ' - %s\n' "$_name" - use_file "$_file" "$_name" - break - done -} - - -########################################################################################## -# Setup - -# Select source file / directory -if [ $install = 1 ] ; then - probe_source_files - if [ $batch = 0 ] ; then - list_append sourcefiles 'Patch existing install' '' - list_append sourcefiles 'Verify existing install only' '' - fi - user_select_entry --existing --any sourcefiles sourcefile \ - "source file or directory to install from" "$green" "$dim_green" 'install from' - case "$sourcefile" in - 'Patch existing install') install=0 ; patch=1 ;; - 'Verify existing install only') install=0 ; patch=0 ;; - *) [ -e "$sourcefile" ] || die "Missing source file: $sourcefile" - esac - set_append probe_file_dirs "$(dirname "$sourcefile")" -fi - -# Select destination data directory -probe_data_dirs -if [ $install = 1 ] ; then - verb='install to' ; access=--writable -elif [ $patch = 1 ] ; then - verb='patch' ; access=--existing -else - verb='verify' ; access=--existing -fi -user_select_entry $access --dir datadirs datadir \ - "data directory to $verb" "$cyan" "$dim_cyan" "$verb" -[ -z "$datadir" ] && die "Missing data dir." -if [ $install = 1 ] ; then - create_dir "$datadir" 'data' -else - [ -d "$datadir" ] || die "Missing data dir: $datadir" -fi - -# Extract source files -if [ $install = 1 ] ; then - printf "\nInstalling Arx Fatalis data files \nfrom %s\nto %s\n\n" \ - "${green}$sourcefile${reset}" "${cyan}$datadir${reset}" - extract_source -else - printf "\nVerifying Arx Fatalis data files \nin %s\n\n" "${cyan}$datadir${reset}" -fi - - -########################################################################################## -# Required files - -# Detect language -determine_language() { - speech_checksum="$1" # speech.pak - - case "$speech_checksum" in - '4e8f962d8204bcfd79ce6f3226d6d6de') data_lang='english' ;; - '4c3fdb1f702700255924afde49081b6e') data_lang='german' ;; - 'ab8a93161688d793a7c78fbefd7d133e') data_lang='german' ;; - '2f88c67ae1537919e69386d27583125b') data_lang='spanish' ;; - '4edf9f8c799190590b4cd52cfa5f91b1') data_lang='french' ;; - '81f05dea47c52d43f01c9b44dd8fe962') data_lang='italian' ;; - '677163bc319cd1e9aa1b53b5fb3e9402') data_lang='russian' ;; - '235b86700fc80b3eb86731d748013a38') data_lang='japanese' ;; - '62ca7b1751c0615ee131a94f0856b389') data_lang='english-demo' ;; - '09038e43508232c44537c162f9e3ecde') data_lang='french-demo' ;; - 'a424fcfc46dd4f11b04030efac15a668') data_lang='german-demo' ;; - 'eeacbd9a845ecc00054934e82e9d7dd3') data_lang='japanese-demo' ;; - esac - - case "$data_lang" in - 'english') data_lang_desc='English' ;; - 'german') data_lang_desc='German' ;; - 'spanish') data_lang_desc='Spanish' ;; - 'french') data_lang_desc='French' ;; - 'italian') data_lang_desc='Italian' ;; - 'russian') data_lang_desc='Russian' ;; - 'japanese') data_lang_desc='Japanese' ;; - 'english-demo') data_lang_desc='English (demo)' ;; - 'french-demo') data_lang_desc='French (demo)' ;; - 'german-demo') data_lang_desc='German (demo)' ;; - 'japanese-demo') data_lang_desc='Japanese (demo)' ;; - esac - -} -detect_data_langauge determine_language - -if [ $install = 1 ] ; then - progress=50 - status $progress "${white}Copying and verifying files...${reset}" - case "$data_lang" in *-demo) increment=8 ;; *) increment=1 ;; esac -else - progress=15 - status $progress "${white}Verifying files...${reset}" - case "$data_lang" in *-demo) increment=14 ;; *) increment=2 ;; esac -fi -print " - speech.pak" - -# Usage: f <is-patchable> <file> <checksums>... -f() { - - # Update progress bar - progress=$((progress + increment)) - status $progress - - # Verify & copy file - required_file "$@" -} - -# speech.pak - already copied in detect_data_langauge - -# loc.pak contains the localized text, so it's different for each language! -case "$data_lang" in - german) loc_checksum='31bc35bca48e430e108db1b8bcc2621d' ;; - english) loc_checksum='a47b192493afb5794e2161a62d35b69f' ;; - spanish) loc_checksum='121f99608814a2c9c5857cfadb665553' ;; - french) loc_checksum='f8fc448fea12469ed94f417c313fe5ea' ;; - italian) loc_checksum='a9e162f2916f5737a95bd8c5bd8a979e' ;; - russian) loc_checksum='a131bf2398ee70a9c22a2bbffd9d0d99' ;; - japanese) loc_checksum='9dcb0f5d7a517be4f1d9190419900892' ;; - english-demo) loc_checksum='2ae16d3925c597dca70f960f175def3a' ;; - french-demo) loc_checksum='4a8ac68341d4758a32d9cd04955b115e' ;; - german-demo) loc_checksum='87accec0658aa109a3efa8b41aab61df' ;; - japanese-demo) loc_checksum='9d84cede805b13fdf7fce856ecc15b19' ;; - *) loc_checksum='' -esac -if [ ! -z "$loc_checksum" ] ; then - f 1 'loc.pak' "$loc_checksum" -fi - -# misc/arx.ttf is the same for everything except japanese -# there are also separate misc/arx_russian.ttf and misc/arx_taiwanese.ttf handled later -case "$data_lang" in - japanese*) font_checksum='58eab00842d8adea8d553ae1f66b0c9b' ;; - *) font_checksum='9a95ff96795c034524ba1c2e94ea12c7' ;; -esac -if [ ! -z "$font_checksum" ] ; then - f 1 'misc/arx.ttf' "$font_checksum" -fi - -case "$data_lang" in - - english-demo) - f 0 'data2.pak' 958b78f8f370b06d769843137138c461 - f 0 'data.pak' 5d7ba6e6c79ebf7fbb232eaced9e8ad9 - f 0 'misc/logo.bmp' aa3dfbd4bc9c863d10a0c5345ae5a4c9 - f 0 'sfx.pak' ea1b3e6d6f4906905d4a34f07e9a59ac - ;; - - french-demo) - f 0 'data2.pak' 8dc1d1b3e85d4a41ae320aa3fa9c649a - f 0 'data.pak' 5d7ba6e6c79ebf7fbb232eaced9e8ad9 - f 0 'misc/logo.bmp' aa3dfbd4bc9c863d10a0c5345ae5a4c9 - f 0 'sfx.pak' ea1b3e6d6f4906905d4a34f07e9a59ac - ;; - - german-demo) - f 0 'data2.pak' 143ba491a357263a2dfad9936a66eeb6 - f 0 'data.pak' 5d7ba6e6c79ebf7fbb232eaced9e8ad9 - f 0 'misc/logo.bmp' aa3dfbd4bc9c863d10a0c5345ae5a4c9 - f 0 'sfx.pak' ea1b3e6d6f4906905d4a34f07e9a59ac - ;; - - japanese-demo) - f 0 'data2.pak' 958b78f8f370b06d769843137138c461 - f 0 'data.pak' 903dfe1878a0cedff3b941fd3aa22ba9 - f 0 'misc/logo.bmp' aa3dfbd4bc9c863d10a0c5345ae5a4c9 - f 0 'sfx.pak' ea1b3e6d6f4906905d4a34f07e9a59ac - ;; - - *) # full game - - f 1 'graph/interface/misc/arkane.bmp' afff1099c01ffeb03b9a351f7b5966b6 - f 1 'graph/interface/misc/quit1.bmp' 41445d3792a1f8818d950aca47254488 - f 1 'graph/obj3d/textures/fixinter_barrel.jpg' 8419274acbff7346c3661b18d6aad6dc - f 1 'graph/obj3d/textures/fixinter_bell.bmp' 5743b9047c9ad65540c318dfcc98123a - f 1 'graph/obj3d/textures/fixinter_metal_door.jpg' f246eff6b19c9c710313b4a4dce96a69 - f 1 'graph/obj3d/textures/fixinter_public_notice.bmp' f81394abbb9006ce0950843b7909db33 - f 1 'graph/obj3d/textures/item_bread.bmp' 544448f8eedc912aa231a6a04fffb7c5 - f 1 'graph/obj3d/textures/item_club.jpg' 7e26c4199ddaca494c8b369294306b0b - f 1 'graph/obj3d/textures/item_long_sword.jpg' 3a6196fe9b7666c7d80d82be06f6de86 - f 1 'graph/obj3d/textures/item_mauld_sabre.jpg' 18492c25ebac02f83e2f0ebda61ecb00 - f 1 'graph/obj3d/textures/item_mauldsword.jpg' 503a5c2f23668040c675aefdde6dbbe5 - f 1 'graph/obj3d/textures/item_mirror.jpg' c0a22b4f7a7a6461da68206e94928637 - f 1 'graph/obj3d/textures/item_ring_casting.bmp' 348f9add709bacee08556d1f8cf10f3f - f 1 'graph/obj3d/textures/item_rope.bmp' ff05de281c8b380ee98f6e123d3d51cb - f 1 'graph/obj3d/textures/item_spell_sheet.jpg' 024ccbb520020f92fba5a5a4f0270cea - f 1 'graph/obj3d/textures/item_torch2.jpg' 027951899b4829599ca611010ea3484f - f 1 'graph/obj3d/textures/item_torch.jpg' 9ada166f23ddcb775ac20836e752187e - f 1 'graph/obj3d/textures/item_zohark.bmp' cd206a4027f86c6e57b7710c94049efa - f 1 'graph/obj3d/textures/l7_dwarf_[wood]_board08.jpg' 79ccc81adb7c37b98f40b478ef1fccd4 - f 1 'graph/obj3d/textures/l7_dwarf_[wood]_board80.jpg' 691611087b13d38ef02bb9dfd6a2518e - f 1 'graph/obj3d/textures/npc_dog.bmp' 116bd374c14ae8c387a4da1899e1dca7 - f 1 'graph/obj3d/textures/npc_pig.bmp' b7a4d0d3d230b2d1470176909004e38b - f 1 'graph/obj3d/textures/npc_pig_dirty.bmp' 76034d8d74056c8a982479d36321c228 - f 1 'graph/obj3d/textures/npc_rat_base.bmp' 00c585ec9ebe8006d7ca72993de7b51b - f 1 'graph/obj3d/textures/npc_rat_base_cm.bmp' cae38facbf77db742180b9e58d0eb42f - f 1 'graph/obj3d/textures/npc_worm_body_part1.jpg' 0b220bffaedc89fa663f08d12630c342 - f 1 'graph/obj3d/textures/npc_worm_body_part2.bmp' 20797cb78f6393a0fb5405969ba9f805 - f 1 'graph/obj3d/textures/[wood]_light_door.jpg' 00d0b018e995e7d013d6e52e92126901 - f 1 'misc/arx_russian.ttf' 921561e83786efcd25f92147b60a13db - f 1 'misc/arx_taiwanese.ttf' da59198061cef0761c6b2fca113f76f6 - f 1 'misc/logo.avi' 63ed31a4eb3d226c23e58cfaa974d484 - f 1 'misc/logo.bmp' afff1099c01ffeb03b9a351f7b5966b6 - f 1 'data2.pak' f7e0ce700bf963429ac535ca86f8a7b4 - - f 0 'sfx.pak' 2efc9a74c517fd1ee9919900cf4091d2 - - # data.pak is censored in some versions (presumably has less gore) - # At least the original german and italian CDs have the censored version. - # The censored version has different level files and a different - # human_female_villager model. - # There are also minor differences in the scripts, but those are - # overwritten by data2.pak from the 1.21 patch. - # A third data.pak variant can be found on the original French Arx Fatalis CD: - # It is almost identical to the preceding censored version, but has different level - # files for level 1 (.llf only) and 3 (.llf and .fts). - data_checksum_original='a91a0b39a046233debbb10b4850e13eb' - data_checksum_censored='a88d239dc7919ab113ff45483cb4ad46' - data_checksum_frenchcd='7ae3632eef92700cd6c5e143aa0fe67b' - f 0 'data.pak' "$data_checksum_original $data_checksum_censored $data_checksum_frenchcd" - -esac - -# Optional files - we don't need them, but copy them anyway if available -optional_file 'manual.pdf' -optional_file 'map.pdf' -optional_file 'arx_handbuch.pdf' - -print - - -########################################################################################## -# Print a summary - -if [ $install = 1 ] ; then verb='Installed' ; else verb='Verified' ; fi -printf "${white}%s Arx Fatalis %s data: ${green}%s${reset}\n" "$verb" \ - "$patch_ver" "$data_lang_desc" - -if [ $checksum_failed = 1 ] ; then - [ $gui = 0 ] || status 100 "Error!" - die "There are wrong or missing files!${reset} - -The game may run fine, or it may fail - good luck!" >&2 -fi - -status 100 "${dim_green}All good!${reset}" -if [ $install = 1 ] ; then verb='Installation' ; else verb='Verification' ; fi -dialog_message "$verb complete: $data_lang_desc - -Have fun playing Arx Fatalis!" - -quit $true |