aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/include/lhasa
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/include/lhasa
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/include/lhasa')
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml8
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS1
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING17
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog13
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am11
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS158
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt10
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/README17
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/TODO23
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh13
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac88
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile1360
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am7
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h54
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1116
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/gencov115
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am43
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c128
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c73
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h30
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c437
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h44
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c724
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c49
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c43
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c44
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c569
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h160
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c173
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c204
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c159
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h99
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c256
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h114
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c60
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h72
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c1081
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h68
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c403
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h51
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c886
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c45
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c198
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c156
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c451
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h49
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c61
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c714
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c549
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c162
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am9
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h183
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h248
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h134
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h217
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h30
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c252
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in10
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am5
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in18
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile26
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README9
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in53
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am23
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt76
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c676
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h32
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c137
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h61
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c682
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h31
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c275
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h64
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c107
-rw-r--r--Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h28
75 files changed, 13752 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml b/Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml
new file mode 100644
index 00000000..fff82e6d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml
@@ -0,0 +1,8 @@
+language: c
+
+compiler:
+ - clang
+ - gcc
+
+script: ./autogen.sh && make && make check
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS b/Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS
new file mode 100644
index 00000000..ed0ab083
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS
@@ -0,0 +1 @@
+Simon Howard <fraggle@gmail.com>
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING b/Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING
new file mode 100644
index 00000000..b682a08e
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING
@@ -0,0 +1,17 @@
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog b/Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog
new file mode 100644
index 00000000..c2576d37
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog
@@ -0,0 +1,13 @@
+
+The full change history is maintained in git. Rather than reproduce
+the change history history here, it's easier if you clone a copy of
+the git repository and view it:
+
+ git clone git://github.com/fragglet/lhasa.git lhasa
+ cd lhasa
+ git log
+
+Alternatively, the commit history can be viewed on github:
+
+ https://github.com/fragglet/lhasa/commits/master
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am
new file mode 100644
index 00000000..575548c2
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am
@@ -0,0 +1,11 @@
+
+AUX_DIST_GEN = $(ac_aux_dir)
+
+EXTRA_DIST = $(AUX_DIST_GEN) gencov rpm.spec
+MAINTAINERCLEANFILES = $(AUX_DIST_GEN)
+
+pkgconfigdir = ${libdir}/pkgconfig
+pkgconfig_DATA = liblhasa.pc
+
+SUBDIRS=doc lib pkg src test
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS b/Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS
new file mode 100644
index 00000000..d7294ed9
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS
@@ -0,0 +1,158 @@
+v0.3.1 (2016-03-29):
+
+ * This release fixes an integer underflow vulnerability in the
+ code for doing LZH level 3 header decodes (TALOS-CAN-0095).
+ Thanks go to Marcin Noga and Regina Wilson of Cisco TALOS for
+ reporting this vulnerability.
+
+v0.3.0 (2015-04-20):
+
+ * PMarc -pm1- archives that contain truncated compressed data (the
+ decompressed length is longer than what can be read from the
+ compressed data) now decompress as intended. Certain archives
+ in the wild make the assumption that this can be done.
+ * LArc -lz5- archives that make use of the initial history buffer
+ now decompress correctly.
+ * The tests no longer use predictable temporary paths (thanks Jon
+ Dowland).
+ * Tests were fixed under OS X.
+
+v0.2.0 (2013-08-04):
+
+ * Decompression of archives using the -lhx- file format supported by
+ unlha32.dll is now supported (thanks Multi for the patch).
+ * The -p (print to stdout) command line option is now supported.
+ * The test suite should now run correctly on Windows.
+
+ Bugs fixed:
+ * Bug where archives read from pipes (eg. stdin) were not extracted
+ beyond the first file in the archive.
+ * Output when using the -w (extract directory) option now correctly
+ matches the output of Unix lha.
+
+v0.1.0 (2013-03-16):
+
+ * There are now test archives for OS-9 and OS-9/68k (OSK) and a
+ workaround for a bug in the OSK lha tool on this platform. OSK level
+ 0 extended areas are also supported.
+ * Extracted files are now written using O_EXCL, which prevents
+ malicious symbolic links being used to redirect output.
+ * Directory paths containing '..' as a directory name are now
+ sanitized, to prevent malicious archives being able to overwrite
+ arbitrary files on the filesystem.
+ * Symbolic links are now extracted in a safer way, being created as
+ dummy files that are overwritten with proper symbolic links at the
+ end of extraction. This is the same behavior used by GNU tar to
+ prevent malicious use of symbolic links.
+ * Automake 1.13 is now properly supported (thanks Jan Engelhardt).
+ Processing of archives read from IPC pipes (including stdin) has
+ been fixed.
+
+v0.0.7 (2012-06-02):
+
+ * Extraction and listing of Unix symbolic links is now supported.
+ * Decompression code for the "old" PMarc archive algorithm (-pm1-) has
+ been added.
+ * Support has been added for Unix LHA level 0 header extended areas
+ (so level 0 archives with Unix metadata are now listed and extracted
+ correctly).
+ * The Unix permissions field in the list output for directory entries
+ has been fixed.
+ * The library header files have been fixed so that they can be included
+ in C++ code.
+ * The LHADecoder interface, for extracting raw compressed data, has been
+ added to the public header files.
+ * The Unix LHA test archives have been regenerated and improved.
+ * A "ghost testing" tool has been added for testing ghost compression
+ algorithms such as -pm1-.
+ * The list output tests have been fixed to be repeatable regardless of
+ the current date.
+ * Build of the fuzzer tool has been fixed.
+
+v0.0.6 (2012-05-17):
+
+ * When the -w option is used during extraction, the path specified
+ is now first created if it does not already exist.
+ * The command line tool now exits with a failure return code if an
+ error occurs during extraction.
+ * A "catch-all" header file (lhasa.h) has been added.
+ * The public header files installed with the library can now be
+ included and used externally.
+ * A pkgconfig file is now installed as part of the library
+ (thanks Jan Engelhardt).
+ * Make targets have been added for building Doxygen documentation
+ and including them as part of the distribution.
+
+v0.0.5 (2012-05-08):
+
+ * Architecture-specific functions for running on Windows have now been
+ fully implemented, and the command line tool passes all tests in the
+ test suite on Windows (thanks roytam1 for bug reports).
+ * Bug fixed where the command line tool would enter an infinite loop
+ when extracting a truncated archive (thanks Jon Dowland).
+ * Support added for archives with level 0 headers and Unix path
+ separators (thanks roytam1).
+ * The test suite now runs correctly outside of the Europe/London time
+ zone (thanks Thomas Klausner).
+ * A .spec file is now included for building rpm packages.
+
+v0.0.4 (2012-05-01):
+
+ * Special handling is now included for MacBinary headers generated
+ by MacLHA.
+ * The -w command line option was broken; it has been fixed.
+ * A bug has been fixed where the timestamp and other metadata was
+ not set properly for extracted directories.
+ * Failures to set the UID/GID of extracted files are now ignored,
+ rather than being treated as a fatal error.
+ * Self-extracting archive files with long headers (up to 64KiB)
+ are now supported. This fixes the handling with some Windows
+ archives.
+ * A Unix manpage has been added.
+ * It is now possible to extract an archive from stdin, by using '-'
+ as the filename.
+ * The shorthand command line syntax "lha foo.lzh" to list an archive
+ is now supported.
+ * A bug with the wildcard pattern matching code has been fixed.
+ * Proper regression tests have now been added for command line
+ archive extraction.
+ * A set of archives generated by LHmelt (Windows) have been added to
+ the test suite.
+ * The regression tests for testing file header parsing and CRC checks
+ have been rewritten.
+
+v0.0.3 (2012-04-22):
+
+ Third beta release.
+
+ * A fix has been added for a bug where missing parent directories
+ were not being created properly.
+ * Regression testing archives have been added from MacLHA v2.24.
+ * In order to support MacLHA archives, code has been added that
+ heuristically detects the MacBinary headers added by MacLHA
+ and strips them off.
+
+v0.0.2 (2012-04-17):
+
+ Second beta release.
+
+ * This version adds support for level 2 and 3 file headers. Lhasa
+ should now be capable of decompressing most, if not all archives
+ found in the wild.
+ * A fuzz testing framework has been added for testing the
+ decompression code. A couple of bugs have been fixed as a result
+ of this.
+
+v0.0.1 (2012-04-06):
+
+ Initial version. This should be considered beta code, although this
+ first version should already be capable of extracting the majority of
+ archive files found in the wild. The main missing features are:
+
+ * Lack of support for level 2 and 3 file headers.
+ * Inability to create archives (only extract them).
+
+ These are features that I aim to add in future releases. Other future
+ features can be found in the TODO file.
+
+# vim: tw=75
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt b/Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt
new file mode 100644
index 00000000..65374a14
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt
@@ -0,0 +1,10 @@
+lhasa LHA decompression library from https://github.com/fragglet/lhasa tag
+v0.3.1 (commit c6d6ca6df218a54c94443f8d15afe2869461506f).
+The following changes have been made:
+ * commit
+ https://github.com/fragglet/lhasa/commit/59c43fc841bfdba970a810e21d97f5e074cd286e
+ has been applied.
+ * Obviously, unnecessary folders and files have been removed.
+ * The test directory is not included in the OpenMPT repository.
+For building, premake is used to generate Visual Studio project files.
+See ../build/premake/ for details.
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/README b/Src/external_dependencies/openmpt-trunk/include/lhasa/README
new file mode 100644
index 00000000..caeaa6bc
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/README
@@ -0,0 +1,17 @@
+Lhasa is a library for parsing LHA (.lzh) archives and a free
+replacement for the Unix LHA tool.
+
+Currently it is only possible to read from (ie. decompress) archives;
+generating (compressing) LHA archives may be an enhancement for future
+versions. The aim is to be compatible with as many different variants
+of the LHA file format as possible, including LArc (.lzs) and PMarc
+(.pma). A suite of archives generated from different tools is
+included for regression testing. Type 'make check' to run the tests.
+
+The command line tool aims to be interface-compatible with the
+non-free Unix LHA tool (command line syntax and output), for backwards
+compatibility with tools that expect particular output.
+
+Lhasa is licensed under the ISC license, which is a simplified version
+of the MIT/X11 license that is functionally identical.
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/TODO b/Src/external_dependencies/openmpt-trunk/include/lhasa/TODO
new file mode 100644
index 00000000..7a8e74f7
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/TODO
@@ -0,0 +1,23 @@
+Library:
+ * Better error handling.
+ * Extract:
+ * Add options API to control whether permissions, timestamp are set.
+ * Creation of parent directories on extract (+optional)
+ * Add LHAFile convenience class.
+ * Compression and LHA file generation.
+ * Correctly handle LHmelt backwards directory ordering.
+ * Add test archives generated by:
+ * Microsoft LZH folder add-in for Windows (if possible?)
+ * UNLHA32
+ * Decompressors for obscure algorithms:
+ * -lh2-, -lh3- (experimental LHA?)
+ * LHark -lh7- (modified -lh5-)
+ * -lx1- (unlha32 obscure/experimental?)
+
+Command line tool:
+ * Create/update/modify archives.
+
+Testing:
+ * Valgrind.
+ * Improve coverage.
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh b/Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh
new file mode 100644
index 00000000..fb71080a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+mkdir -p autotools
+
+aclocal
+libtoolize || glibtoolize
+autoheader
+automake -a
+autoconf
+automake -a
+
+./configure $@
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac b/Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac
new file mode 100644
index 00000000..5bf4c002
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac
@@ -0,0 +1,88 @@
+AC_INIT(Lhasa, 0.3.1, fraggle@gmail.com, lhasa)
+AC_CONFIG_AUX_DIR(autotools)
+
+AM_INIT_AUTOMAKE([no-define])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AM_PROG_CC_C_O
+
+AC_PROG_CXX
+AC_PROG_RANLIB
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+if [[ "$GCC" = "yes" ]]; then
+ is_gcc=true
+else
+ is_gcc=false
+fi
+
+TEST_CFLAGS="-DTEST_BUILD"
+
+# Turn on all warnings for gcc. Turn off optimisation for the test build.
+
+if $is_gcc; then
+ WARNINGS="-Wall -Wsign-compare"
+ CFLAGS="$CFLAGS $WARNINGS"
+ TEST_CFLAGS="$TEST_CFLAGS $WARNINGS -O0"
+fi
+
+# Support for coverage analysis via gcov:
+
+coverage=false
+AC_ARG_ENABLE(coverage,
+[ --enable-coverage Enable coverage testing. ],
+[ coverage=true ])
+
+if $coverage; then
+ if $is_gcc; then
+ TEST_CFLAGS="$TEST_CFLAGS -fprofile-arcs -ftest-coverage"
+ else
+ AC_MSG_ERROR([Can only enable coverage when using gcc.])
+ fi
+fi
+
+AM_CONDITIONAL(BUILD_COVERAGE, $coverage)
+
+# Support for running test cases using valgrind:
+
+use_valgrind=false
+AC_ARG_ENABLE(valgrind,
+[ --enable-valgrind Use valgrind when running unit tests. ],
+[ use_valgrind=true ])
+
+if [[ "$use_valgrind" = "true" ]]; then
+ AC_CHECK_PROG(HAVE_VALGRIND, valgrind, yes, no)
+
+ if [[ "$HAVE_VALGRIND" = "no" ]]; then
+ AC_MSG_ERROR([Valgrind not found in PATH. ])
+ fi
+fi
+
+AM_CONDITIONAL(USE_VALGRIND, $use_valgrind)
+
+# Save the default CFLAGS and clear them, so that the test build
+# of the library doesn't get the optimisation flags.
+
+MAIN_CFLAGS="$CFLAGS"
+CFLAGS=""
+
+AC_SUBST(MAIN_CFLAGS)
+AC_SUBST(TEST_CFLAGS)
+AC_SUBST(ac_aux_dir)
+
+AC_CONFIG_HEADERS([config.h:config.hin])
+
+AC_OUTPUT([
+ liblhasa.pc
+ rpm.spec
+ Makefile
+ doc/Makefile
+ lib/Makefile
+ lib/public/Makefile
+ pkg/Makefile
+ pkg/config.make
+ src/Makefile
+ test/Makefile
+])
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile
new file mode 100644
index 00000000..2eea4876
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile
@@ -0,0 +1,1360 @@
+# Doxyfile 1.5.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "Lhasa"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = lib/public/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = intro.h \
+ ../lib/public
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 1000
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am
new file mode 100644
index 00000000..7a9bdc9b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am
@@ -0,0 +1,7 @@
+
+man_MANS=lha.1
+EXTRA_DIST=$(man_MANS) html Doxyfile intro.h
+
+html:
+ doxygen
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h
new file mode 100644
index 00000000..2c201345
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h
@@ -0,0 +1,54 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+/* This file is a dummy header used to generate the Doxygen intro. */
+
+/**
+ * @mainpage Lhasa LZH file library
+ *
+ * @section Introduction
+ *
+ * Lhasa is a library for parsing LHA (.lzh) archive files. Included
+ * with the library is a Unix command line tool that is an interface
+ * compatible replacement for the non-free Unix LHA tool.
+ *
+ * The source code is licensed under the ISC license, a simplified
+ * version of the MIT/X11 license which is functionally identical,
+ * and compatible with the GNU GPL.
+ * As such, it may be reused in any project, either proprietary or
+ * open source.
+ *
+ * @section Main_interfaces Main interfaces
+ *
+ * @li @link lha_input_stream.h @endlink - abstracts
+ * the process of reading data from an LZH file; convenience
+ * functions are provided for reading data from a normal file or
+ * a Standard C FILE pointer.
+ * @li @link lha_reader.h @endlink - routines to decode ands
+ * extract the contents of an LZH file from a stream.
+ * @li @link lha_file_header.h @endlink - structure
+ * representing the decoded contents of an LZH file header.
+ *
+ * @section Additional_interfaces Additional interfaces
+ *
+ * @li @link lha_decoder.h @endlink - routines to decode raw LZH
+ * compressed data.
+ */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1 b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1
new file mode 100644
index 00000000..3f63c0ef
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1
@@ -0,0 +1,116 @@
+.TH lha 1
+.SH NAME
+lha \- compression tool for .lzh archive files.
+.SH SYNOPSIS
+.B lha [-]{lvtxe[q{num}][finv]}[w=<dir>] archive_file [file...]
+.SH DESCRIPTION
+.PP
+.B lha
+is a tool for extracting .lzh archive files. It also supports variants
+of the .lzh archive, such as .lzs and .pma.
+.PP
+This version of the lha tool is part of Lhasa, a free implementation
+of the .lzh format.
+.PP
+.SH COMMAND SYNTAX
+The lha tool has an unusual command syntax, compared to most other
+Unix commands. The first parameter to the program specifies the command
+to perform and all additional options. The second parameter specifies
+the path to the archive file to operate on. Following this is a list
+of wildcard patterns to match against the filenames of the archived
+files.
+.PP
+The first character of the command parameter specifies the command to
+perform, which is one of the following:
+.TP
+\fB-l\fR
+List contents of the specified archive.
+.TP
+\fB-v\fR
+Verbosely list contents of the specified archive.
+.TP
+\fB-t\fR
+Test the integrity of the specified archive: decompress its contents and
+check the CRC.
+.TP
+\fB-e\fR or \fB-x\fR
+Extract archive. Files are extracted to the current working directory
+unless the 'w' option is specified.
+.PP
+.SH OPTIONS
+The remainder of the command parameter is used to specify additional
+options:
+.TP
+\fBq[012]\fR
+Quiet mode. Higher numbers suppress more output. Level 0 is normal
+operation. If no number is specified, full suppression (level 2)
+is used. The quiet option also turns on the force overwrite option
+('f').
+.TP
+\fBf\fR
+Force overwrite of existing files: do not prompt.
+.TP
+\fBi\fR
+Ignore paths of archived files: extract all archived files to the
+same directory, ignoring subdirectories.
+.TP
+\fBn\fR
+Do not perform any actual operations: instead, perform a dry run of
+the requested operation and describe what would have been done on
+standard output.
+.TP
+\fBv\fR
+Verbose mode: causes extra information to be written to standard
+output.
+.TP
+\fBw=dir\fR
+Specify destination directory for extracting files. This must be
+the last option of the first parameter.
+.SH SEE ALSO
+\fBunzip\fR(1),
+\fBtar\fR(1),
+\fBgzip\fR(1),
+\fBbzip2\fR(1)
+.SH HISTORY
+The .lzh format originated with Kazuhiko Miki's MS\-DOS archive tool,
+LArc, using the LZSS algorithm developed by Haruhiko Okumura, and
+the .lzs filename extension. The container format was reused for
+LHarc, by Haruyasu Yoshizaki (Yoshi), which used a new algorithm
+named LZHUF and the .lzh extension. In later versions, LHarc was
+renamed to LHA and extended with more effective compression algorithms.
+.PP
+Versions of the LHA tool were later ported to various different
+operating systems, including the Amiga, Atari, MacOS, OS/2 and Unix.
+A tool for MSX\-DOS named PMarc reused the container format with a new
+compression algorithm (.pma extension).
+.PP
+The Unix version of the tool was developed by Masaru Oki, Nobutaka
+Watazaki and Tsugio Okamoto, but was released under a software
+license that does not conform to the Free Software or Open Source
+Definitions. Lhasa was developed as a drop\-in replacement that is
+Free Software and Open Source.
+.SH BUGS
+The current version does not allow the creation of new archive files.
+.PP
+Some obscure compression algorithms are not currently supported
+(\-lh2\-, \-lh3\-, \-lx1\-, \-lhx\-).
+.SH AUTHOR
+Lhasa was written and is maintained by Simon Howard.
+.SH COPYRIGHT
+Copyright \(co 2011, 2012 Simon Howard.
+.PP
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+.PP
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/gencov b/Src/external_dependencies/openmpt-trunk/include/lhasa/gencov
new file mode 100644
index 00000000..f6219b29
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/gencov
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011, 2012, Simon Howard
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+from re import match
+from os import rename, popen, getcwd, chdir
+from os.path import exists, dirname, basename
+from os.path import join as path_join
+from glob import glob
+import sys
+
+def parse_stats(text):
+ m = match(r"(.*)% of (.*)", text)
+
+ pct = m.group(1)
+ lines = int(m.group(2))
+ cov_lines = int(float(pct) * lines / 100 + 0.5)
+ uncov_lines = lines - cov_lines
+
+ return (pct + "%", uncov_lines, cov_lines, lines)
+
+
+def gcov(filename):
+
+ # gcov must be run from within the same directory as the source
+ # file that we are analysing.
+
+ old_wd = getcwd()
+ src_dir = dirname(filename)
+ chdir(src_dir)
+ s = popen("gcov %s" % basename(filename))
+ chdir(old_wd)
+
+ # Process output from gcov.
+ # This may cover multiple files when one .c file includes another.
+
+ results = {}
+ filename = None
+
+ # File 'lha_file_header.c'
+ # Lines executed:88.97% of 136
+
+ for line in s:
+ m = match(r"File '(.*)'", line)
+ if m:
+ filename = m.group(1)
+
+ m = match(r"Lines executed:(.*)", line)
+ if m:
+ full_path = path_join(src_dir, filename)
+ results[full_path] = parse_stats(m.group(1))
+
+ s.close()
+
+ return results
+
+def format_output(filename, stats):
+ print " %-35s%7s%7s%7s%7s" % ((filename, ) + stats)
+
+print
+format_output("Filename", ("Percent", "Uncov", "Cov", "Total"))
+print " " + ("-" * 65)
+
+for filename in sorted(sys.argv[1:]):
+ gcno = filename.replace(".c", ".gcno")
+ gcda = filename.replace(".c", ".gcda")
+
+ xgcno = glob(path_join(dirname(gcno), "*-" + basename(gcno)))
+ xgcda = glob(path_join(dirname(gcda), "*-" + basename(gcda)))
+
+ # Must rename eg. liblhasatest_a-foo.gcno to foo.gcno:
+
+ if len(xgcno) > 0:
+ rename(xgcno[0], gcno)
+
+ if len(xgcda) > 0:
+ rename(xgcda[0], gcda)
+
+ if not exists(gcno) or not exists(gcda):
+ continue
+
+ # Run gcov and parse output:
+
+ results = gcov(filename)
+
+ if len(results) > 0:
+ if filename in results:
+ format_output(filename, results[filename])
+ else:
+ format_output(filename, ("", "", "", ""))
+
+ for subfile in sorted(results.keys()):
+ if subfile.endswith(".h"):
+ continue
+
+ if subfile != filename:
+ format_output(" -> " + subfile, results[subfile])
+
+print
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am
new file mode 100644
index 00000000..e70de16b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am
@@ -0,0 +1,43 @@
+SUBDIRS = public
+
+lib_LTLIBRARIES=liblhasa.la
+check_LIBRARIES=liblhasatest.a
+
+EXTRA_DIST = \
+ bit_stream_reader.c \
+ lh_new_decoder.c \
+ pma_common.c \
+ tree_decode.c
+
+SRC = \
+ crc16.c crc16.h \
+ ext_header.c ext_header.h \
+ lha_arch_unix.c lha_arch.h \
+ lha_arch_win32.c \
+ lha_decoder.c lha_decoder.h \
+ lha_endian.c lha_endian.h \
+ lha_file_header.c lha_file_header.h \
+ lha_input_stream.c lha_input_stream.h \
+ lha_basic_reader.c lha_basic_reader.h \
+ lha_reader.c \
+ macbinary.c macbinary.h \
+ null_decoder.c \
+ lh1_decoder.c \
+ lh5_decoder.c \
+ lh6_decoder.c \
+ lh7_decoder.c \
+ lhx_decoder.c \
+ lz5_decoder.c \
+ lzs_decoder.c \
+ pm1_decoder.c \
+ pm2_decoder.c
+
+liblhasatest_a_CFLAGS=$(TEST_CFLAGS) -DALLOC_TESTING -I../test -g
+liblhasatest_a_SOURCES=$(SRC) $(HEADER_FILES)
+
+liblhasa_la_CFLAGS=$(MAIN_CFLAGS)
+liblhasa_la_SOURCES=$(SRC) $(HEADER_FILES)
+
+clean-local:
+ rm -f *.gcno *.gcda *.c.gcov
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c
new file mode 100644
index 00000000..6f9edd41
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c
@@ -0,0 +1,128 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Data structure used to read bits from an input source as a stream.
+//
+// This file is designed to be #included by other source files to
+// make a complete decoder.
+//
+
+typedef struct {
+
+ // Callback function to invoke to read more data from the
+ // input stream.
+
+ LHADecoderCallback callback;
+ void *callback_data;
+
+ // Bits from the input stream that are waiting to be read.
+
+ uint32_t bit_buffer;
+ unsigned int bits;
+
+} BitStreamReader;
+
+// Initialize bit stream reader structure.
+
+static void bit_stream_reader_init(BitStreamReader *reader,
+ LHADecoderCallback callback,
+ void *callback_data)
+{
+ reader->callback = callback;
+ reader->callback_data = callback_data;
+
+ reader->bits = 0;
+ reader->bit_buffer = 0;
+}
+
+// Return the next n bits waiting to be read from the input stream,
+// without removing any. Returns -1 for failure.
+
+static int peek_bits(BitStreamReader *reader,
+ unsigned int n)
+{
+ uint8_t buf[4];
+ unsigned int fill_bytes;
+ size_t bytes;
+
+ if (n == 0) {
+ return 0;
+ }
+
+ // If there are not enough bits in the buffer to satisfy this
+ // request, we need to fill up the buffer with more bits.
+
+ while (reader->bits < n) {
+
+ // Maximum number of bytes we can fill?
+
+ fill_bytes = (32 - reader->bits) / 8;
+
+ // Read from input and fill bit_buffer.
+
+ memset(buf, 0, sizeof(buf));
+ bytes = reader->callback(buf, fill_bytes,
+ reader->callback_data);
+
+ // End of file?
+
+ if (bytes == 0) {
+ return -1;
+ }
+
+ reader->bit_buffer |= (uint32_t) buf[0] << (24 - reader->bits);
+ reader->bit_buffer |= (uint32_t) buf[1] << (16 - reader->bits);
+ reader->bit_buffer |= (uint32_t) buf[2] << (8 - reader->bits);
+ reader->bit_buffer |= (uint32_t) buf[3];
+
+ reader->bits += bytes * 8;
+ }
+
+ return (signed int) (reader->bit_buffer >> (32 - n));
+}
+
+// Read a bit from the input stream.
+// Returns -1 for failure.
+
+static int read_bits(BitStreamReader *reader,
+ unsigned int n)
+{
+ int result;
+
+ result = peek_bits(reader, n);
+
+ if (result >= 0) {
+ reader->bit_buffer <<= n;
+ reader->bits -= n;
+ }
+
+ return result;
+}
+
+
+// Read a bit from the input stream.
+// Returns -1 for failure.
+
+static int read_bit(BitStreamReader *reader)
+{
+ return read_bits(reader, 1);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c
new file mode 100644
index 00000000..0a385e90
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c
@@ -0,0 +1,73 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include "crc16.h"
+
+static unsigned int crc16_table[] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+ 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+ 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+ 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+ 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+ 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+ 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+ 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+ 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+ 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+ 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+ 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+ 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+ 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+ 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+ 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+ 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+ 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+ 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+ 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+ 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+ 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+ 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+ 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+ 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+ 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+ 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+ 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
+};
+
+void lha_crc16_buf(uint16_t *crc, uint8_t *buf, size_t buf_len)
+{
+ uint16_t tmp;
+ unsigned int index;
+ unsigned int i;
+
+ tmp = *crc;
+
+ for (i = 0; i < buf_len; ++i) {
+ index = (tmp ^ buf[i]) & 0xff;
+ tmp = ((tmp >> 8) ^ crc16_table[index]) & 0xffff;
+ }
+
+ *crc = tmp;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h
new file mode 100644
index 00000000..723decd1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h
@@ -0,0 +1,30 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_CRC16_H
+#define LHASA_LHA_CRC16_H
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+void lha_crc16_buf(uint16_t *crc, uint8_t *buf, size_t buf_len);
+
+#endif /* #ifndef LHASA_LHA_CRC16_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c
new file mode 100644
index 00000000..e7e92bd5
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c
@@ -0,0 +1,437 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ext_header.h"
+#include "lha_endian.h"
+
+//
+// Extended header parsing.
+//
+// Extended headers were introduced with LHA v2 - various different
+// tools support different extended headers. Some are operating system
+// specific.
+//
+
+// Extended header types:
+
+#define LHA_EXT_HEADER_COMMON 0x00
+#define LHA_EXT_HEADER_FILENAME 0x01
+#define LHA_EXT_HEADER_PATH 0x02
+#define LHA_EXT_HEADER_MULTI_DISC 0x39
+#define LHA_EXT_HEADER_COMMENT 0x3f
+
+#define LHA_EXT_HEADER_WINDOWS_TIMESTAMPS 0x41
+
+#define LHA_EXT_HEADER_UNIX_PERMISSION 0x50
+#define LHA_EXT_HEADER_UNIX_UID_GID 0x51
+#define LHA_EXT_HEADER_UNIX_GROUP 0x52
+#define LHA_EXT_HEADER_UNIX_USER 0x53
+#define LHA_EXT_HEADER_UNIX_TIMESTAMP 0x54
+
+#define LHA_EXT_HEADER_OS9 0xcc
+
+/**
+ * Structure representing an extended header type.
+ */
+typedef struct {
+
+ /**
+ * Header number.
+ *
+ * Each extended header type has a unique byte value that represents
+ * it.
+ */
+ uint8_t num;
+
+ /**
+ * Callback function for parsing an extended header block.
+ *
+ * @param header The file header structure in which to store
+ * decoded data.
+ * @param data Pointer to the header data to decode.
+ * @param data_len Size of the header data, in bytes.
+ * @return Non-zero if successful, or zero for failure.
+ */
+ int (*decoder)(LHAFileHeader *header, uint8_t *data, size_t data_len);
+
+ /** Minimum length for a header of this type. */
+ size_t min_len;
+
+} LHAExtHeaderType;
+
+// Common header (0x00).
+//
+// This contains a 16-bit CRC of the entire LHA header.
+
+static int ext_header_common_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ header->extra_flags |= LHA_FILE_COMMON_CRC;
+ header->common_crc = lha_decode_uint16(data);
+
+ // There is a catch-22 in calculating the CRC, because the field
+ // containing the CRC is part of the data being CRC'd. The solution
+ // is that the CRC is calculated with the CRC field set to zero.
+ // Therefore, now that the CRC has been read, set the field to
+ // zero in the raw_data array so that the CRC can be calculated
+ // correctly.
+
+ data[0] = 0x00;
+ data[1] = 0x00;
+
+ // TODO: Some platforms (OS/2, Unix) put extra data in the common
+ // header which might also be decoded.
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_common = {
+ LHA_EXT_HEADER_COMMON,
+ ext_header_common_decoder,
+ 2
+};
+
+// Filename header (0x01).
+//
+// This stores the filename for the file. This is essential on level 2/3
+// headers, as the filename field is no longer part of the standard
+// header.
+
+static int ext_header_filename_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ char *new_filename;
+ unsigned int i;
+
+ new_filename = malloc(data_len + 1);
+
+ if (new_filename == NULL) {
+ return 0;
+ }
+
+ memcpy(new_filename, data, data_len);
+ new_filename[data_len] = '\0';
+
+ // Sanitize the filename that was read. It is not allowed to
+ // contain a path separator, which could potentially be used
+ // to do something malicious.
+
+ for (i = 0; new_filename[i] != '\0'; ++i) {
+ if (new_filename[i] == '/') {
+ new_filename[i] = '_';
+ }
+ }
+
+ free(header->filename);
+ header->filename = new_filename;
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_filename = {
+ LHA_EXT_HEADER_FILENAME,
+ ext_header_filename_decoder,
+ 1
+};
+
+// Path header (0x02).
+//
+// This stores the directory path of the file. A value of 0xff is used
+// as the path separator. It is supposed to include a terminating path
+// separator as the last character.
+
+static int ext_header_path_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ unsigned int i;
+ uint8_t *new_path;
+
+ new_path = malloc(data_len + 2);
+
+ if (new_path == NULL) {
+ return 0;
+ }
+
+ memcpy(new_path, data, data_len);
+ new_path[data_len] = '\0';
+
+ // Amiga LHA v1.22 generates path headers without a path
+ // separator at the end of the string. This is broken (and
+ // was fixed in a later version), but handle it correctly.
+
+ if (new_path[data_len - 1] != 0xff) {
+ new_path[data_len] = 0xff;
+ new_path[data_len + 1] = '\0';
+ ++data_len;
+ }
+
+ free(header->path);
+ header->path = (char *) new_path;
+
+ for (i = 0; i < data_len; ++i) {
+ if (new_path[i] == 0xff) {
+ new_path[i] = '/';
+ }
+ }
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_path = {
+ LHA_EXT_HEADER_PATH,
+ ext_header_path_decoder,
+ 1
+};
+
+// Windows timestamp header (0x41).
+//
+// This is a Windows-specific header that stores 64-bit timestamps in
+// Windows FILETIME format. The timestamps have 100ns accuracy, which is
+// much more accurate than the normal Unix time_t format.
+
+static int ext_header_windows_timestamps(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ header->extra_flags |= LHA_FILE_WINDOWS_TIMESTAMPS;
+ header->win_creation_time = lha_decode_uint64(data);
+ header->win_modification_time = lha_decode_uint64(data + 8);
+ header->win_access_time = lha_decode_uint64(data + 16);
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_windows_timestamps = {
+ LHA_EXT_HEADER_WINDOWS_TIMESTAMPS,
+ ext_header_windows_timestamps,
+ 24
+};
+
+
+// Unix permissions header (0x50).
+
+static int ext_header_unix_perms_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ header->extra_flags |= LHA_FILE_UNIX_PERMS;
+ header->unix_perms = lha_decode_uint16(data);
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_unix_perms = {
+ LHA_EXT_HEADER_UNIX_PERMISSION,
+ ext_header_unix_perms_decoder,
+ 2
+};
+
+// Unix UID/GID header (0x51).
+
+static int ext_header_unix_uid_gid_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ header->extra_flags |= LHA_FILE_UNIX_UID_GID;
+ header->unix_gid = lha_decode_uint16(data);
+ header->unix_uid = lha_decode_uint16(data + 2);
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_unix_uid_gid = {
+ LHA_EXT_HEADER_UNIX_UID_GID,
+ ext_header_unix_uid_gid_decoder,
+ 4
+};
+
+// Unix username header (0x53).
+//
+// This stores a string containing the username. There don't seem to be
+// any tools that actually generate archives containing this header.
+
+static int ext_header_unix_username_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ char *username;
+
+ username = malloc(data_len + 1);
+
+ if (username == NULL) {
+ return 0;
+ }
+
+ memcpy(username, data, data_len);
+ username[data_len] = '\0';
+
+ free(header->unix_username);
+ header->unix_username = username;
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_unix_username = {
+ LHA_EXT_HEADER_UNIX_USER,
+ ext_header_unix_username_decoder,
+ 1
+};
+
+// Unix group header (0x52).
+//
+// This stores a string containing the Unix group name. As with the
+// username header, there don't seem to be any tools that actually
+// generate archives containing this header.
+
+static int ext_header_unix_group_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ char *group;
+
+ group = malloc(data_len + 1);
+
+ if (group == NULL) {
+ return 0;
+ }
+
+ memcpy(group, data, data_len);
+ group[data_len] = '\0';
+
+ free(header->unix_group);
+ header->unix_group = group;
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_unix_group = {
+ LHA_EXT_HEADER_UNIX_GROUP,
+ ext_header_unix_group_decoder,
+ 1
+};
+
+// Unix timestamp header (0x54).
+//
+// This stores a 32-bit Unix time_t timestamp representing the
+// modification time of the file.
+
+static int ext_header_unix_timestamp_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ header->timestamp = lha_decode_uint32(data);
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_unix_timestamp = {
+ LHA_EXT_HEADER_UNIX_TIMESTAMP,
+ ext_header_unix_timestamp_decoder,
+ 4
+};
+
+// OS-9 (6809) header (0xcc)
+//
+// This stores OS-9 filesystem metadata.
+
+static int ext_header_os9_decoder(LHAFileHeader *header,
+ uint8_t *data,
+ size_t data_len)
+{
+ // TODO: The OS-9 extended header contains various data, but
+ // it's not clear what it's all for. Just extract the
+ // permissions for now.
+
+ header->os9_perms = lha_decode_uint16(data + 7);
+ header->extra_flags |= LHA_FILE_OS9_PERMS;
+
+ return 1;
+}
+
+static LHAExtHeaderType lha_ext_header_os9 = {
+ LHA_EXT_HEADER_OS9,
+ ext_header_os9_decoder,
+ 12
+};
+
+// Table of extended headers.
+
+static const LHAExtHeaderType *ext_header_types[] = {
+ &lha_ext_header_common,
+ &lha_ext_header_filename,
+ &lha_ext_header_path,
+ &lha_ext_header_unix_perms,
+ &lha_ext_header_unix_uid_gid,
+ &lha_ext_header_unix_username,
+ &lha_ext_header_unix_group,
+ &lha_ext_header_unix_timestamp,
+ &lha_ext_header_windows_timestamps,
+ &lha_ext_header_os9,
+};
+
+#define NUM_HEADER_TYPES (sizeof(ext_header_types) / sizeof(*ext_header_types))
+
+/**
+ * Look up the extended header parser for the specified header code.
+ *
+ * @param num Extended header type.
+ * @return Matching @ref LHAExtHeaderType structure, or NULL if
+ * not found for this header type.
+ */
+
+static const LHAExtHeaderType *ext_header_for_num(uint8_t num)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_HEADER_TYPES; ++i) {
+ if (ext_header_types[i]->num == num) {
+ return ext_header_types[i];
+ }
+ }
+
+ return NULL;
+}
+
+int lha_ext_header_decode(LHAFileHeader *header,
+ uint8_t num,
+ uint8_t *data,
+ size_t data_len)
+{
+ const LHAExtHeaderType *htype;
+
+ htype = ext_header_for_num(num);
+
+ if (htype == NULL) {
+ return 0;
+ }
+
+ if (data_len < htype->min_len) {
+ return 0;
+ }
+
+ return htype->decoder(header, data, data_len);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h
new file mode 100644
index 00000000..5484f260
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_EXT_HEADER_H
+#define LHASA_EXT_HEADER_H
+
+#include <stdlib.h>
+
+#include "lha_file_header.h"
+
+/**
+ * Decode the specified extended header.
+ *
+ * @param header The file header in which to store decoded data.
+ * @param num Extended header type.
+ * @param data Pointer to the data to decode.
+ * @param data_len Size of the data to decode, in bytes.
+ * @return Non-zero for success, or zero if not decoded.
+ */
+
+int lha_ext_header_decode(LHAFileHeader *header,
+ uint8_t num,
+ uint8_t *data,
+ size_t data_len);
+
+#endif /* #ifndef LHASA_EXT_HEADER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c
new file mode 100644
index 00000000..2188f122
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c
@@ -0,0 +1,724 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+#include "bit_stream_reader.c"
+
+// Size of the ring buffer used to hold history:
+
+#define RING_BUFFER_SIZE 4096 /* bytes */
+
+// When this limit is reached, the code tree is reordered.
+
+#define TREE_REORDER_LIMIT 32 * 1024 /* 32 kB */
+
+// Number of codes ('byte' codes + 'copy' codes):
+
+#define NUM_CODES 314
+
+// Number of nodes in the code tree.
+
+#define NUM_TREE_NODES (NUM_CODES * 2 - 1)
+
+// Number of possible offsets:
+
+#define NUM_OFFSETS 64
+
+// Minimum length of the offset top bits:
+
+#define MIN_OFFSET_LENGTH 3 /* bits */
+
+// Threshold for copying. The first copy code starts from here.
+
+#define COPY_THRESHOLD 3 /* bytes */
+
+// Required size of the output buffer. At most, a single call to read()
+// might result in a copy of the entire ring buffer.
+
+#define OUTPUT_BUFFER_SIZE RING_BUFFER_SIZE
+
+typedef struct {
+
+ // If true, this node is a leaf node.
+
+ unsigned int leaf :1;
+
+ // If this is a leaf node, child_index is the code represented by
+ // this node. Otherwise, nodes[child_index] and nodes[child_index-1]
+ // are the children of this node.
+
+ unsigned int child_index :15;
+
+ // Index of the parent node of this node.
+
+ uint16_t parent;
+
+ // Frequency count for this node - number of times that it has
+ // received a hit.
+
+ uint16_t freq;
+
+ // Group that this node belongs to.
+
+ uint16_t group;
+} Node;
+
+typedef struct {
+
+ // Input bit stream.
+
+ BitStreamReader bit_stream_reader;
+
+ // Ring buffer of past data. Used for position-based copies.
+
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+
+ // Array of tree nodes. nodes[0] is the root node. The array
+ // is maintained in order by frequency.
+
+ Node nodes[NUM_TREE_NODES];
+
+ // Indices of leaf nodes of the tree (map from code to leaf
+ // node index)
+
+ uint16_t leaf_nodes[NUM_CODES];
+
+ // Groups list. Every node belongs to a group. All nodes within
+ // a group have the same frequency. There can be at most
+ // NUM_TREE_NODES groups (one for each node). num_groups is used
+ // to allocate and deallocate groups as needed.
+
+ uint16_t groups[NUM_TREE_NODES];
+ unsigned int num_groups;
+
+ // Index of the "leader" of a group within the nodes[] array.
+ // The leader is the left-most node within a span of nodes with
+ // the same frequency.
+
+ uint16_t group_leader[NUM_TREE_NODES];
+
+ // Offset lookup table. Maps from a byte value (sequence of next
+ // 8 bits from input stream) to an offset value.
+
+ uint8_t offset_lookup[256];
+
+ // Length of offsets, in bits.
+
+ uint8_t offset_lengths[NUM_OFFSETS];
+} LHALH1Decoder;
+
+// Frequency distribution used to calculate the offset codes.
+
+static const unsigned int offset_fdist[] = {
+ 1, // 3 bits
+ 3, // 4 bits
+ 8, // 5 bits
+ 12, // 6 bits
+ 24, // 7 bits
+ 16, // 8 bits
+};
+
+// Allocate a group from the free groups array.
+
+static uint16_t alloc_group(LHALH1Decoder *decoder)
+{
+ uint16_t result;
+
+ result = decoder->groups[decoder->num_groups];
+ ++decoder->num_groups;
+
+ return result;
+}
+
+// Free a group that is no longer in use.
+
+static void free_group(LHALH1Decoder *decoder, uint16_t group)
+{
+ --decoder->num_groups;
+ decoder->groups[decoder->num_groups] = group;
+}
+
+// Initialize groups array.
+
+static void init_groups(LHALH1Decoder *decoder)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_TREE_NODES; ++i) {
+ decoder->groups[i] = (uint16_t) i;
+ }
+
+ decoder->num_groups = 0;
+}
+
+// Initialize the tree with its basic initial configuration.
+
+static void init_tree(LHALH1Decoder *decoder)
+{
+ unsigned int i, child;
+ int node_index;
+ uint16_t leaf_group;
+ Node *node;
+
+ // Leaf nodes are placed at the end of the table. Start by
+ // initializing these, and working backwards.
+
+ node_index = NUM_TREE_NODES - 1;
+ leaf_group = alloc_group(decoder);
+
+ for (i = 0; i < NUM_CODES; ++i) {
+ node = &decoder->nodes[node_index];
+ node->leaf = 1;
+ node->child_index = (unsigned short) i;
+ node->freq = 1;
+ node->group = leaf_group;
+
+ decoder->group_leader[leaf_group] = (uint16_t) node_index;
+ decoder->leaf_nodes[i] = (uint16_t) node_index;
+
+ --node_index;
+ }
+
+ // Now build up the intermediate nodes, up to the root. Each
+ // node gets two nodes as children.
+
+ child = NUM_TREE_NODES - 1;
+
+ while (node_index >= 0) {
+ node = &decoder->nodes[node_index];
+ node->leaf = 0;
+
+ // Set child pointer and update the parent pointers of the
+ // children.
+
+ node->child_index = child;
+ decoder->nodes[child].parent = (uint16_t) node_index;
+ decoder->nodes[child - 1].parent = (uint16_t) node_index;
+
+ // The node's frequency is equal to the sum of the frequencies
+ // of its children.
+
+ node->freq = (uint16_t) (decoder->nodes[child].freq
+ + decoder->nodes[child - 1].freq);
+
+ // Is the frequency the same as the last node we processed?
+ // if so, we are in the same group. If not, we must
+ // allocate a new group. Either way, this node is now the
+ // leader of its group.
+
+ if (node->freq == decoder->nodes[node_index + 1].freq) {
+ node->group = decoder->nodes[node_index + 1].group;
+ } else {
+ node->group = alloc_group(decoder);
+ }
+
+ decoder->group_leader[node->group] = (uint16_t) node_index;
+
+ // Process next node.
+
+ --node_index;
+ child -= 2;
+ }
+}
+
+// Fill in a range of values in the offset_lookup table, which have
+// the bits from 'code' as the high bits, and the low bits can be
+// any values in the range from 'mask'. Set these values to point
+// to 'offset'.
+
+static void fill_offset_range(LHALH1Decoder *decoder, uint8_t code,
+ unsigned int mask, unsigned int offset)
+{
+ unsigned int i;
+
+ // Set offset lookup table to map from all possible input values
+ // that fit within the mask to the target offset.
+
+ for (i = 0; (i & ~mask) == 0; ++i) {
+ decoder->offset_lookup[code | i] = (uint8_t) offset;
+ }
+}
+
+// Calculate the values for the offset_lookup and offset_lengths
+// tables.
+
+static void init_offset_table(LHALH1Decoder *decoder)
+{
+ unsigned int i, j, len;
+ uint8_t code, iterbit, offset;
+
+ code = 0;
+ offset = 0;
+
+ // Iterate through each entry in the frequency distribution table,
+ // filling in codes in the lookup table as we go.
+
+ for (i = 0; i < sizeof(offset_fdist) / sizeof(*offset_fdist); ++i) {
+
+ // offset_fdist[0] is the number of codes of length
+ // MIN_OFFSET_LENGTH bits, increasing as we go. As the
+ // code increases in length, we must iterate progressively
+ // lower bits in the code (moving right - extending the
+ // code to be 1 bit longer).
+
+ len = i + MIN_OFFSET_LENGTH;
+ iterbit = (uint8_t) (1 << (8 - len));
+
+ for (j = 0; j < offset_fdist[i]; ++j) {
+
+ // Store lookup values for this offset in the
+ // lookup table, and save the code length.
+ // (iterbit - 1) turns into a mask for the lower
+ // bits that are not part of the code.
+
+ fill_offset_range(decoder, code,
+ (uint8_t) (iterbit - 1), offset);
+ decoder->offset_lengths[offset] = (uint8_t) len;
+
+ // Iterate to next code.
+
+ code = (uint8_t) (code + iterbit);
+ ++offset;
+ }
+ }
+}
+
+// Initialize the history ring buffer.
+
+static void init_ring_buffer(LHALH1Decoder *decoder)
+{
+ memset(decoder->ringbuf, ' ', RING_BUFFER_SIZE);
+ decoder->ringbuf_pos = 0;
+}
+
+static int lha_lh1_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHALH1Decoder *decoder = data;
+
+ // Initialize input stream reader.
+
+ bit_stream_reader_init(&decoder->bit_stream_reader,
+ callback, callback_data);
+
+ // Initialize data structures.
+
+ init_groups(decoder);
+ init_tree(decoder);
+ init_offset_table(decoder);
+ init_ring_buffer(decoder);
+
+ return 1;
+}
+
+// Make the given node the leader of its group: swap it with the current
+// leader so that it is in the left-most position. Returns the new index
+// of the node.
+
+static uint16_t make_group_leader(LHALH1Decoder *decoder,
+ uint16_t node_index)
+{
+ Node *node, *leader;
+ uint16_t group;
+ uint16_t leader_index;
+ unsigned int tmp;
+
+ group = decoder->nodes[node_index].group;
+ leader_index = decoder->group_leader[group];
+
+ // Already the leader? If so, there is nothing to do.
+
+ if (leader_index == node_index) {
+ return node_index;
+ }
+
+ node = &decoder->nodes[node_index];
+ leader = &decoder->nodes[leader_index];
+
+ // Swap leaf and child indices in the two nodes:
+
+ tmp = leader->leaf;
+ leader->leaf = node->leaf;
+ node->leaf = tmp;
+
+ tmp = leader->child_index;
+ leader->child_index = node->child_index;
+ node->child_index = tmp;
+
+ if (node->leaf) {
+ decoder->leaf_nodes[node->child_index] = node_index;
+ } else {
+ decoder->nodes[node->child_index].parent = node_index;
+ decoder->nodes[node->child_index - 1].parent = node_index;
+ }
+
+ if (leader->leaf) {
+ decoder->leaf_nodes[leader->child_index] = leader_index;
+ } else {
+ decoder->nodes[leader->child_index].parent = leader_index;
+ decoder->nodes[leader->child_index - 1].parent = leader_index;
+ }
+
+ return leader_index;
+}
+
+// Increase the frequency count for a node, rearranging groups as
+// appropriate.
+
+static void increment_node_freq(LHALH1Decoder *decoder, uint16_t node_index)
+{
+ Node *node, *other;
+
+ node = &decoder->nodes[node_index];
+ other = &decoder->nodes[node_index - 1];
+
+ ++node->freq;
+
+ // If the node is part of a group containing other nodes, it
+ // must leave the group.
+
+ if (node_index < NUM_TREE_NODES - 1
+ && node->group == decoder->nodes[node_index + 1].group) {
+
+ // Next node in the group now becomes the leader.
+
+ ++decoder->group_leader[node->group];
+
+ // The node must now either join the group to its
+ // left, or start a new group.
+
+ if (node->freq == other->freq) {
+ node->group = other->group;
+ } else {
+ node->group = alloc_group(decoder);
+ decoder->group_leader[node->group] = node_index;
+ }
+
+ } else {
+ // The node is in a group of its own (single-node
+ // group). It might need to join the group of the
+ // node on its left if it has the same frequency.
+
+ if (node->freq == other->freq) {
+ free_group(decoder, node->group);
+ node->group = other->group;
+ }
+ }
+}
+
+// Reconstruct the code huffman tree to be more evenly distributed.
+// Invoked periodically as data is processed.
+
+static void reconstruct_tree(LHALH1Decoder *decoder)
+{
+ Node *leaf;
+ unsigned int child;
+ unsigned int freq;
+ unsigned int group;
+ int i;
+
+ // Gather all leaf nodes at the start of the table.
+
+ leaf = decoder->nodes;
+
+ for (i = 0; i < NUM_TREE_NODES; ++i) {
+ if (decoder->nodes[i].leaf) {
+ leaf->leaf = 1;
+ leaf->child_index = decoder->nodes[i].child_index;
+
+ // Frequency of the nodes in the new tree is halved,
+ // this acts as a running average each time the
+ // tree is reconstructed.
+
+ leaf->freq = (uint16_t) (decoder->nodes[i].freq + 1) / 2;
+
+ ++leaf;
+ }
+ }
+
+ // The leaf nodes are now all at the start of the table. Now
+ // reconstruct the tree, starting from the end of the table and
+ // working backwards, inserting branch nodes between the leaf
+ // nodes. Each branch node inherits the sum of the frequencies
+ // of its children, and must be placed to maintain the ordering
+ // within the table by decreasing frequency.
+
+ leaf = &decoder->nodes[NUM_CODES - 1];
+ child = NUM_TREE_NODES - 1;
+ i = NUM_TREE_NODES - 1;
+
+ while (i >= 0) {
+
+ // Before we can add a new branch node, we need at least
+ // two nodes to use as children. If we don't have this
+ // then we need to copy some from the leaves.
+
+ while ((int) child - i < 2) {
+ decoder->nodes[i] = *leaf;
+ decoder->leaf_nodes[leaf->child_index] = (uint16_t) i;
+
+ --i;
+ --leaf;
+ }
+
+ // Now that we have at least two nodes to take as children
+ // of the new branch node, we can calculate the branch
+ // node's frequency.
+
+ freq = (unsigned int) (decoder->nodes[child].freq
+ + decoder->nodes[child - 1].freq);
+
+ // Now copy more leaf nodes until the correct place to
+ // insert the new branch node presents itself.
+
+ while (leaf >= decoder->nodes && freq >= leaf->freq) {
+ decoder->nodes[i] = *leaf;
+ decoder->leaf_nodes[leaf->child_index] = (uint16_t) i;
+
+ --i;
+ --leaf;
+ }
+
+ // The new branch node can now be inserted.
+
+ decoder->nodes[i].leaf = 0;
+ decoder->nodes[i].freq = (uint16_t) freq;
+ decoder->nodes[i].child_index = (uint16_t) child;
+
+ decoder->nodes[child].parent = (uint16_t) i;
+ decoder->nodes[child - 1].parent = (uint16_t) i;
+
+ --i;
+
+ // Process the next pair of children.
+
+ child -= 2;
+ }
+
+ // Reconstruct the group data. Start by resetting group data.
+
+ init_groups(decoder);
+
+ // Assign a group to the first node.
+
+ group = alloc_group(decoder);
+ decoder->nodes[0].group = (uint16_t) group;
+ decoder->group_leader[group] = 0;
+
+ // Assign a group number to each node, nodes having the same
+ // group if the have the same frequency, and allocating new
+ // groups when a new frequency is found.
+
+ for (i = 1; i < NUM_TREE_NODES; ++i) {
+ if (decoder->nodes[i].freq == decoder->nodes[i - 1].freq) {
+ decoder->nodes[i].group = decoder->nodes[i - 1].group;
+ } else {
+ group = alloc_group(decoder);
+ decoder->nodes[i].group = (uint16_t) group;
+
+ // First node with a particular frequency is leader.
+ decoder->group_leader[group] = (uint16_t) i;
+ }
+ }
+}
+
+// Increment the counter for the specific code, reordering the tree as
+// necessary.
+
+static void increment_for_code(LHALH1Decoder *decoder, uint16_t code)
+{
+ uint16_t node_index;
+
+ // When the limit is reached, we must reorder the code tree
+ // to better match the code frequencies:
+
+ if (decoder->nodes[0].freq >= TREE_REORDER_LIMIT) {
+ reconstruct_tree(decoder);
+ }
+
+ ++decoder->nodes[0].freq;
+
+ // Dynamically adjust the tree. Start from the leaf node of
+ // the tree and walk back up, rearranging nodes to the root.
+
+ node_index = decoder->leaf_nodes[code];
+
+ while (node_index != 0) {
+
+ // Shift the node to the left side of its group,
+ // and bump the frequency count.
+
+ node_index = make_group_leader(decoder, node_index);
+
+ increment_node_freq(decoder, node_index);
+
+ // Iterate up to the parent node.
+
+ node_index = decoder->nodes[node_index].parent;
+ }
+}
+
+// Read a code from the input stream.
+
+static int read_code(LHALH1Decoder *decoder, uint16_t *result)
+{
+ unsigned int node_index;
+ int bit;
+
+ // Start from the root node, and traverse down until a leaf is
+ // reached.
+
+ node_index = 0;
+
+ //printf("<root ");
+ while (!decoder->nodes[node_index].leaf) {
+ bit = read_bit(&decoder->bit_stream_reader);
+
+ if (bit < 0) {
+ return 0;
+ }
+
+ //printf("<%i>", bit);
+
+ // Choose one of the two children depending on the
+ // bit that was read.
+
+ node_index = decoder->nodes[node_index].child_index
+ - (unsigned int) bit;
+ }
+
+ *result = decoder->nodes[node_index].child_index;
+ //printf(" -> %i!>\n", *result);
+
+ increment_for_code(decoder, *result);
+
+ return 1;
+}
+
+// Read an offset code from the input stream.
+
+static int read_offset(LHALH1Decoder *decoder, unsigned int *result)
+{
+ unsigned int offset;
+ int future, offset2;
+
+ // The offset can be up to 8 bits long, but is likely not
+ // that long. Use the lookup table to find the offset
+ // and its length.
+
+ future = peek_bits(&decoder->bit_stream_reader, 8);
+
+ if (future < 0) {
+ return 0;
+ }
+
+ offset = decoder->offset_lookup[future];
+
+ // Skip past the offset bits and also read the following
+ // lower-order bits.
+
+ read_bits(&decoder->bit_stream_reader,
+ decoder->offset_lengths[offset]);
+
+ offset2 = read_bits(&decoder->bit_stream_reader, 6);
+
+ if (offset2 < 0) {
+ return 0;
+ }
+
+ *result = (offset << 6) | (unsigned int) offset2;
+
+ return 1;
+}
+
+static void output_byte(LHALH1Decoder *decoder, uint8_t *buf,
+ size_t *buf_len, uint8_t b)
+{
+ buf[*buf_len] = b;
+ ++*buf_len;
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+}
+
+static size_t lha_lh1_read(void *data, uint8_t *buf)
+{
+ LHALH1Decoder *decoder = data;
+ size_t result;
+ uint16_t code;
+
+ result = 0;
+
+ // Read the next code from the input stream.
+
+ if (!read_code(decoder, &code)) {
+ return 0;
+ }
+
+ // The code either indicates a single byte to be output, or
+ // it indicates that a block should be copied from the ring
+ // buffer as it is a repeat of a sequence earlier in the
+ // stream.
+
+ if (code < 0x100) {
+ output_byte(decoder, buf, &result, (uint8_t) code);
+ } else {
+ unsigned int count, start, i, pos, offset;
+
+ // Read the offset into the history at which to start
+ // copying.
+
+ if (!read_offset(decoder, &offset)) {
+ return 0;
+ }
+
+ count = code - 0x100U + COPY_THRESHOLD;
+ start = decoder->ringbuf_pos - offset + RING_BUFFER_SIZE - 1;
+
+ // Copy from history into output buffer:
+
+ for (i = 0; i < count; ++i) {
+ pos = (start + i) % RING_BUFFER_SIZE;
+
+ output_byte(decoder, buf, &result,
+ decoder->ringbuf[pos]);
+ }
+ }
+
+ return result;
+}
+
+LHADecoderType lha_lh1_decoder = {
+ lha_lh1_init,
+ NULL,
+ lha_lh1_read,
+ sizeof(LHALH1Decoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE
+};
+
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c
new file mode 100644
index 00000000..e48b1ccf
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Decoder for the -lh5- algorithm.
+//
+// This is the "new" algorithm that appeared in LHA v2, replacing
+// the older -lh1-. -lh4- seems to be identical to -lh5-.
+//
+
+// 16 KiB history ring buffer:
+
+#define HISTORY_BITS 14 /* 2^14 = 16384 */
+
+// Number of bits to encode HISTORY_BITS:
+
+#define OFFSET_BITS 4
+
+// Name of the variable for the encoder:
+
+#define DECODER_NAME lha_lh5_decoder
+
+// Generate a second decoder for lh4 that just has a different
+// block size.
+
+#define DECODER2_NAME lha_lh4_decoder
+
+// The actual algorithm code is contained in lh_new_decoder.c, which
+// acts as a template for -lh4-, -lh5-, -lh6- and -lh7-.
+
+#include "lh_new_decoder.c"
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c
new file mode 100644
index 00000000..e392f4a8
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c
@@ -0,0 +1,43 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Decoder for the -lh6- algorithm.
+//
+// -lh6- is an "extended" version of -lh5- introduced in LHA v2.66.
+//
+
+// 64 KiB history ring buffer:
+
+#define HISTORY_BITS 16 /* 2^16 = 65536 */
+
+// Number of bits to encode HISTORY_BITS:
+
+#define OFFSET_BITS 5
+
+// Name of the variable for the encoder:
+
+#define DECODER_NAME lha_lh6_decoder
+
+// The actual algorithm code is contained in lh_new_decoder.c, which
+// acts as a template for -lh4-, -lh5-, -lh6- and -lh7-.
+
+#include "lh_new_decoder.c"
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c
new file mode 100644
index 00000000..9867cd1e
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c
@@ -0,0 +1,44 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Decoder for the -lh7- algorithm.
+//
+// -lh7- is an extension of the -lh5- algorithm introduced in
+// LHA 2.67 beta.
+//
+
+// 128 KiB history ring buffer:
+
+#define HISTORY_BITS 17 /* 2^17 = 131072 */
+
+// Number of bits to encode HISTORY_BITS:
+
+#define OFFSET_BITS 5
+
+// Name of the variable for the encoder:
+
+#define DECODER_NAME lha_lh7_decoder
+
+// The actual algorithm code is contained in lh_new_decoder.c, which
+// acts as a template for -lh4-, -lh5-, -lh6- and -lh7-.
+
+#include "lh_new_decoder.c"
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c
new file mode 100644
index 00000000..56310c56
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c
@@ -0,0 +1,569 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+// Decoder for "new-style" LHA algorithms, used with LHA v2 and onwards
+// (-lh4-, -lh5-, -lh6-, -lh7-).
+//
+// This file is designed to be a template. It is #included by other
+// files to generate an optimized decoder.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+#include "bit_stream_reader.c"
+
+// Include tree decoder.
+
+typedef uint16_t TreeElement;
+#include "tree_decode.c"
+
+// Threshold for copying. The first copy code starts from here.
+
+#define COPY_THRESHOLD 3 /* bytes */
+
+// Ring buffer containing history has a size that is a power of two.
+// The number of bits is specified.
+
+#define RING_BUFFER_SIZE (1 << HISTORY_BITS)
+
+// Required size of the output buffer. At most, a single call to read()
+// might result in a copy of the entire ring buffer.
+
+#define OUTPUT_BUFFER_SIZE RING_BUFFER_SIZE
+
+// Number of different command codes. 0-255 range are literal byte
+// values, while higher values indicate copy from history.
+
+#define NUM_CODES 510
+
+// Number of possible codes in the "temporary table" used to encode the
+// codes table.
+
+#define MAX_TEMP_CODES 20
+
+typedef struct {
+ // Input bit stream.
+
+ BitStreamReader bit_stream_reader;
+
+ // Ring buffer of past data. Used for position-based copies.
+
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+
+ // Number of commands remaining before we start a new block.
+
+ unsigned int block_remaining;
+
+ // Table used for the code tree.
+
+ TreeElement code_tree[NUM_CODES * 2];
+
+ // Table used to encode the offset tree, used to read offsets
+ // into the history buffer. This same table is also used to
+ // encode the temp-table, which is bigger; hence the size.
+
+ TreeElement offset_tree[MAX_TEMP_CODES * 2];
+} LHANewDecoder;
+
+// Initialize the history ring buffer.
+
+static void init_ring_buffer(LHANewDecoder *decoder)
+{
+ memset(decoder->ringbuf, ' ', RING_BUFFER_SIZE);
+ decoder->ringbuf_pos = 0;
+}
+
+static int lha_lh_new_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHANewDecoder *decoder = data;
+
+ // Initialize input stream reader.
+
+ bit_stream_reader_init(&decoder->bit_stream_reader,
+ callback, callback_data);
+
+ // Initialize data structures.
+
+ init_ring_buffer(decoder);
+
+ // First read starts the first block.
+
+ decoder->block_remaining = 0;
+
+ // Initialize tree tables to a known state.
+
+ init_tree(decoder->code_tree, NUM_CODES * 2);
+ init_tree(decoder->offset_tree, MAX_TEMP_CODES * 2);
+
+ return 1;
+}
+
+// Read a length value - this is normally a value in the 0-7 range, but
+// sometimes can be longer.
+
+static int read_length_value(LHANewDecoder *decoder)
+{
+ int i, len;
+
+ len = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (len < 0) {
+ return -1;
+ }
+
+ if (len == 7) {
+ // Read more bits to extend the length until we reach a '0'.
+
+ for (;;) {
+ i = read_bit(&decoder->bit_stream_reader);
+
+ if (i < 0) {
+ return -1;
+ } else if (i == 0) {
+ break;
+ }
+
+ ++len;
+ }
+ }
+
+ return len;
+}
+
+// Read the values from the input stream that define the temporary table
+// used for encoding the code table.
+
+static int read_temp_table(LHANewDecoder *decoder)
+{
+ int i, j, n, len, code;
+ uint8_t code_lengths[MAX_TEMP_CODES];
+
+ // How many codes?
+
+ n = read_bits(&decoder->bit_stream_reader, 5);
+
+ if (n < 0) {
+ return 0;
+ }
+
+ // n=0 is a special case, meaning only a single code that
+ // is of zero length.
+
+ if (n == 0) {
+ code = read_bits(&decoder->bit_stream_reader, 5);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ set_tree_single(decoder->offset_tree, code);
+ return 1;
+ }
+
+ // Enforce a hard limit on the number of codes.
+
+ if (n > MAX_TEMP_CODES) {
+ n = MAX_TEMP_CODES;
+ }
+
+ // Read the length of each code.
+
+ for (i = 0; i < n; ++i) {
+ len = read_length_value(decoder);
+
+ if (len < 0) {
+ return 0;
+ }
+
+ code_lengths[i] = len;
+
+ // After the first three lengths, there is a 2-bit
+ // field to allow skipping over up to a further three
+ // lengths. Not sure of the reason for this ...
+
+ if (i == 2) {
+ len = read_bits(&decoder->bit_stream_reader, 2);
+
+ if (len < 0) {
+ return 0;
+ }
+
+ for (j = 0; j < len; ++j) {
+ ++i;
+ code_lengths[i] = 0;
+ }
+ }
+ }
+
+ build_tree(decoder->offset_tree, MAX_TEMP_CODES * 2, code_lengths, n);
+
+ return 1;
+}
+
+// Code table codes can indicate that a sequence of codes should be
+// skipped over. The number to skip is Huffman-encoded. Given a skip
+// range (0-2), this reads the number of codes to skip over.
+
+static int read_skip_count(LHANewDecoder *decoder, int skiprange)
+{
+ int result;
+
+ // skiprange=0 => 1 code.
+
+ if (skiprange == 0) {
+ result = 1;
+ }
+
+ // skiprange=1 => 3-18 codes.
+
+ else if (skiprange == 1) {
+ result = read_bits(&decoder->bit_stream_reader, 4);
+
+ if (result < 0) {
+ return -1;
+ }
+
+ result += 3;
+ }
+
+ // skiprange=2 => 20+ codes.
+
+ else {
+ result = read_bits(&decoder->bit_stream_reader, 9);
+
+ if (result < 0) {
+ return -1;
+ }
+
+ result += 20;
+ }
+
+ return result;
+}
+
+static int read_code_table(LHANewDecoder *decoder)
+{
+ int i, j, n, skip_count, code;
+ uint8_t code_lengths[NUM_CODES];
+
+ // How many codes?
+
+ n = read_bits(&decoder->bit_stream_reader, 9);
+
+ if (n < 0) {
+ return 0;
+ }
+
+ // n=0 implies a single code of zero length; all inputs
+ // decode to the same code.
+
+ if (n == 0) {
+ code = read_bits(&decoder->bit_stream_reader, 9);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ set_tree_single(decoder->code_tree, code);
+
+ return 1;
+ }
+
+ if (n > NUM_CODES) {
+ n = NUM_CODES;
+ }
+
+ // Read the length of each code.
+ // The lengths are encoded using the temp-table previously read;
+ // offset_tree is reused temporarily to hold it.
+
+ i = 0;
+
+ while (i < n) {
+ code = read_from_tree(&decoder->bit_stream_reader,
+ decoder->offset_tree);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ // The code that was read can have different meanings.
+ // If in the range 0-2, it indicates that a number of
+ // codes are unused and should be skipped over.
+ // Values greater than two represent a frequency count.
+
+ if (code <= 2) {
+ skip_count = read_skip_count(decoder, code);
+
+ if (skip_count < 0) {
+ return 0;
+ }
+
+ for (j = 0; j < skip_count && i < n; ++j) {
+ code_lengths[i] = 0;
+ ++i;
+ }
+ } else {
+ code_lengths[i] = code - 2;
+ ++i;
+ }
+ }
+
+ build_tree(decoder->code_tree, NUM_CODES * 2, code_lengths, n);
+
+ return 1;
+}
+
+static int read_offset_table(LHANewDecoder *decoder)
+{
+ int i, n, len, code;
+ uint8_t code_lengths[HISTORY_BITS];
+
+ // How many codes?
+
+ n = read_bits(&decoder->bit_stream_reader, OFFSET_BITS);
+
+ if (n < 0) {
+ return 0;
+ }
+
+ // n=0 is a special case, meaning only a single code that
+ // is of zero length.
+
+ if (n == 0) {
+ code = read_bits(&decoder->bit_stream_reader, OFFSET_BITS);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ set_tree_single(decoder->offset_tree, code);
+ return 1;
+ }
+
+ // Enforce a hard limit on the number of codes.
+
+ if (n > HISTORY_BITS) {
+ n = HISTORY_BITS;
+ }
+
+ // Read the length of each code.
+
+ for (i = 0; i < n; ++i) {
+ len = read_length_value(decoder);
+
+ if (len < 0) {
+ return 0;
+ }
+
+ code_lengths[i] = len;
+ }
+
+ build_tree(decoder->offset_tree, MAX_TEMP_CODES * 2, code_lengths, n);
+
+ return 1;
+}
+
+// Start reading a new block from the input stream.
+
+static int start_new_block(LHANewDecoder *decoder)
+{
+ int len;
+
+ // Read length of new block (in commands).
+
+ len = read_bits(&decoder->bit_stream_reader, 16);
+
+ if (len < 0) {
+ return 0;
+ }
+
+ decoder->block_remaining = (size_t) len;
+
+ // Read the temporary decode table, used to encode the codes table.
+ // The position table data structure is reused for this.
+
+ if (!read_temp_table(decoder)) {
+ return 0;
+ }
+
+ // Read the code table; this is encoded *using* the temp table.
+
+ if (!read_code_table(decoder)) {
+ return 0;
+ }
+
+ // Read the offset table.
+
+ if (!read_offset_table(decoder)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+// Read the next code from the input stream. Returns the code, or -1 if
+// an error occurred.
+
+static int read_code(LHANewDecoder *decoder)
+{
+ return read_from_tree(&decoder->bit_stream_reader, decoder->code_tree);
+}
+
+// Read an offset distance from the input stream.
+// Returns the code, or -1 if an error occurred.
+
+static int read_offset_code(LHANewDecoder *decoder)
+{
+ int bits, result;
+
+ bits = read_from_tree(&decoder->bit_stream_reader,
+ decoder->offset_tree);
+
+ if (bits < 0) {
+ return -1;
+ }
+
+ // The code read indicates the length of the offset in bits.
+ //
+ // The returned value looks like this:
+ // bits = 0 -> 0
+ // bits = 1 -> 1
+ // bits = 2 -> 1x
+ // bits = 3 -> 1xx
+ // bits = 4 -> 1xxx
+ // etc.
+
+ if (bits == 0) {
+ return 0;
+ } else if (bits == 1) {
+ return 1;
+ } else {
+ result = read_bits(&decoder->bit_stream_reader, bits - 1);
+
+ if (result < 0) {
+ return -1;
+ }
+
+ return result + (1 << (bits - 1));
+ }
+}
+
+// Add a byte value to the output stream.
+
+static void output_byte(LHANewDecoder *decoder, uint8_t *buf,
+ size_t *buf_len, uint8_t b)
+{
+ buf[*buf_len] = b;
+ ++*buf_len;
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+}
+
+// Copy a block from the history buffer.
+
+static void copy_from_history(LHANewDecoder *decoder, uint8_t *buf,
+ size_t *buf_len, size_t count)
+{
+ int offset;
+ unsigned int i, start;
+
+ offset = read_offset_code(decoder);
+
+ if (offset < 0) {
+ return;
+ }
+
+ start = decoder->ringbuf_pos + RING_BUFFER_SIZE
+ - (unsigned int) offset - 1;
+
+ for (i = 0; i < count; ++i) {
+ output_byte(decoder, buf, buf_len,
+ decoder->ringbuf[(start + i) % RING_BUFFER_SIZE]);
+ }
+}
+
+static size_t lha_lh_new_read(void *data, uint8_t *buf)
+{
+ LHANewDecoder *decoder = data;
+ size_t result;
+ int code;
+
+ // Start of new block?
+
+ while (decoder->block_remaining == 0) {
+ if (!start_new_block(decoder)) {
+ return 0;
+ }
+ }
+
+ --decoder->block_remaining;
+
+ // Read next command from input stream.
+
+ result = 0;
+
+ code = read_code(decoder);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ // The code may be either a literal byte value or a copy command.
+
+ if (code < 256) {
+ output_byte(decoder, buf, &result, (uint8_t) code);
+ } else {
+ copy_from_history(decoder, buf, &result,
+ code - 256 + COPY_THRESHOLD);
+ }
+
+ return result;
+}
+
+LHADecoderType DECODER_NAME = {
+ lha_lh_new_init,
+ NULL,
+ lha_lh_new_read,
+ sizeof(LHANewDecoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE / 2
+};
+
+// This is a hack for -lh4-:
+
+#ifdef DECODER2_NAME
+LHADecoderType DECODER2_NAME = {
+ lha_lh_new_init,
+ NULL,
+ lha_lh_new_read,
+ sizeof(LHANewDecoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE / 4
+};
+#endif
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h
new file mode 100644
index 00000000..41b4e37c
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h
@@ -0,0 +1,160 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_ARCH_H
+#define LHASA_LHA_ARCH_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#define LHA_ARCH_UNIX 1
+#define LHA_ARCH_WINDOWS 2
+
+#ifdef _WIN32
+#define LHA_ARCH LHA_ARCH_WINDOWS
+#else
+#define LHA_ARCH LHA_ARCH_UNIX
+#endif
+
+typedef enum {
+ LHA_FILE_NONE,
+ LHA_FILE_FILE,
+ LHA_FILE_DIRECTORY,
+ LHA_FILE_ERROR,
+} LHAFileType;
+
+/**
+ * Cross-platform version of vasprintf().
+ *
+ * @param result Pointer to a variable to store the resulting string.
+ * @param fmt Format string.
+ * @param args Additional arguments for printf().
+ * @return Number of characters in resulting string, or -1 if
+ * an error occurred in generating the string.
+ */
+
+int lha_arch_vasprintf(char **result, char *fmt, va_list args);
+
+/**
+ * Change the mode of the specified FILE handle to be binary mode.
+ *
+ * @param handle The FILE handle.
+ */
+
+void lha_arch_set_binary(FILE *handle);
+
+/**
+ * Create a directory.
+ *
+ * @param path Path to the directory to create.
+ * @param unix_perms Unix permissions for the directory to create.
+ * @return Non-zero if the directory was created successfully.
+ */
+
+int lha_arch_mkdir(char *path, unsigned int unix_perms);
+
+/**
+ * Change the Unix ownership of the specified file or directory.
+ * If this is not a Unix system, do nothing.
+ *
+ * @param filename Path to the file or directory.
+ * @param unix_uid The UID to set.
+ * @param unix_gid The GID to set.
+ * @return Non-zero if set successfully.
+ */
+
+int lha_arch_chown(char *filename, int unix_uid, int unix_gid);
+
+/**
+ * Change the Unix permissions on the specified file or directory.
+ *
+ * @param filename Path to the file or directory.
+ * @param unix_perms The permissions to set.
+ * @return Non-zero if set successfully.
+ */
+
+int lha_arch_chmod(char *filename, int unix_perms);
+
+/**
+ * Set the file creation / modification time on the specified file or
+ * directory.
+ *
+ * @param filename Path to the file or directory.
+ * @param timestamp The Unix timestamp to set.
+ * @return Non-zero if set successfully.
+ */
+
+int lha_arch_utime(char *filename, unsigned int timestamp);
+
+/**
+ * Set the file creation, modification and access times for the
+ * specified file or directory, using 64-bit Windows timestamps.
+ *
+ * @param filename Path to the file or directory.
+ * @param creation_time 64-bit Windows FILETIME value for the
+ * creation time of the file.
+ * @param modification_time Modification time of the file.
+ * @param access_time Last access time of the file.
+ * @return Non-zero if set successfully.
+ */
+
+int lha_arch_set_windows_timestamps(char *filename,
+ uint64_t creation_time,
+ uint64_t modification_time,
+ uint64_t access_time);
+/**
+ * Open a new file for writing.
+ *
+ * @param filename Path to the file or directory.
+ * @param unix_uid Unix UID to set for the new file, or -1 to not set.
+ * @param unix_gid Unix GID to set for the new file, or -1 to not set.
+ * @param unix_perms Unix permissions to set for the new file, or -1 to not
+ * set.
+ * @return Standard C file handle.
+ */
+
+FILE *lha_arch_fopen(char *filename, int unix_uid,
+ int unix_gid, int unix_perms);
+
+/**
+ * Query whether the specified file exists.
+ *
+ * @param filename Path to the file.
+ * @return The type of file.
+ */
+
+LHAFileType lha_arch_exists(char *filename);
+
+/**
+ * Create a symbolic link.
+ *
+ * If a file already exists at the location of the link to be created, it is
+ * overwritten.
+ *
+ * @param path Path to the symbolic link to create.
+ * @param target Target for the symbolic link.
+ * @return Non-zero for success.
+ */
+
+int lha_arch_symlink(char *path, char *target);
+
+#endif /* ifndef LHASA_LHA_ARCH_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c
new file mode 100644
index 00000000..c8896374
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c
@@ -0,0 +1,173 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Architecture-specific files for compilation on Unix.
+//
+
+#define _GNU_SOURCE
+#include "lha_arch.h"
+
+#if LHA_ARCH == LHA_ARCH_UNIX
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// TODO: This file depends on vasprintf(), which is a non-standard
+// function (_GNU_SOURCE above). Most modern Unix systems have an
+// implementation of it, but develop a compatible workaround for
+// operating systems that don't have it.
+
+int lha_arch_vasprintf(char **result, char *fmt, va_list args)
+{
+ return vasprintf(result, fmt, args);
+}
+
+void lha_arch_set_binary(FILE *handle)
+{
+ // No-op on Unix systems: there is no difference between
+ // "text" and "binary" files.
+}
+
+int lha_arch_mkdir(char *path, unsigned int unix_perms)
+{
+ return mkdir(path, unix_perms) == 0;
+}
+
+int lha_arch_chown(char *filename, int unix_uid, int unix_gid)
+{
+ return chown(filename, unix_uid, unix_gid) == 0;
+}
+
+int lha_arch_chmod(char *filename, int unix_perms)
+{
+ return chmod(filename, unix_perms) == 0;
+}
+
+int lha_arch_utime(char *filename, unsigned int timestamp)
+{
+ struct utimbuf times;
+
+ times.actime = (time_t) timestamp;
+ times.modtime = (time_t) timestamp;
+
+ return utime(filename, &times) == 0;
+}
+
+FILE *lha_arch_fopen(char *filename, int unix_uid, int unix_gid, int unix_perms)
+{
+ FILE *fstream;
+ int fileno;
+
+ // The O_EXCL flag will cause the open() below to fail if the
+ // file already exists. Remove it first.
+
+ unlink(filename);
+
+ // If we have file permissions, they must be set after the
+ // file is created and UID/GID have been set. When open()ing
+ // the file, create it with minimal permissions granted only
+ // to the current user.
+ // Use O_EXCL so that symlinks are not followed; this prevents
+ // a malicious symlink from overwriting arbitrary filesystem
+ // locations.
+
+ fileno = open(filename, O_CREAT|O_WRONLY|O_EXCL, 0600);
+
+ if (fileno < 0) {
+ return NULL;
+ }
+
+ // Set owner and group.
+
+ if (unix_uid >= 0) {
+ if (fchown(fileno, unix_uid, unix_gid) != 0) {
+ // On most Unix systems, only root can change
+ // ownership. But if we can't change ownership,
+ // it isn't a fatal error. So ignore the failure
+ // and continue.
+
+ // TODO: Implement some kind of alternate handling
+ // here?
+
+ /* close(fileno);
+ remove(filename);
+ return NULL; */
+ }
+ }
+
+ // Set file permissions.
+ // File permissions must be set *after* owner and group have
+ // been set; otherwise, we might briefly be granting permissions
+ // to the wrong group.
+
+ if (unix_perms >= 0) {
+ if (fchmod(fileno, unix_perms) != 0) {
+ close(fileno);
+ remove(filename);
+ return NULL;
+ }
+ }
+
+ // Create stdc FILE handle.
+
+ fstream = fdopen(fileno, "wb");
+
+ if (fstream == NULL) {
+ close(fileno);
+ remove(filename);
+ return NULL;
+ }
+
+ return fstream;
+}
+
+LHAFileType lha_arch_exists(char *filename)
+{
+ struct stat statbuf;
+
+ if (stat(filename, &statbuf) != 0) {
+ if (errno == ENOENT) {
+ return LHA_FILE_NONE;
+ } else {
+ return LHA_FILE_ERROR;
+ }
+ }
+
+ if (S_ISDIR(statbuf.st_mode)) {
+ return LHA_FILE_DIRECTORY;
+ } else {
+ return LHA_FILE_FILE;
+ }
+}
+
+int lha_arch_symlink(char *path, char *target)
+{
+ unlink(path);
+ return symlink(target, path) == 0;
+}
+
+#endif /* LHA_ARCH_UNIX */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c
new file mode 100644
index 00000000..ac8ee331
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c
@@ -0,0 +1,204 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Architecture-specific files for compilation on Windows.
+// A work in progress.
+//
+
+#include "lha_arch.h"
+
+#if LHA_ARCH == LHA_ARCH_WINDOWS
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+
+static uint64_t unix_epoch_offset = 0;
+
+int lha_arch_vasprintf(char **result, char *fmt, va_list args)
+{
+ int len;
+
+ len = vsnprintf(NULL, 0, fmt, args);
+ if (len >= 0) {
+ *result = malloc(len + 1);
+ if (*result != NULL) {
+ return vsprintf(*result, fmt, args);
+ }
+ }
+
+ *result = NULL;
+ return -1;
+}
+
+void lha_arch_set_binary(FILE *handle)
+{
+ _setmode(_fileno(handle), _O_BINARY);
+}
+
+int lha_arch_mkdir(char *path, unsigned int unix_mode)
+{
+ return CreateDirectoryA(path, NULL) != 0;
+}
+
+int lha_arch_chown(char *filename, int unix_uid, int unix_gid)
+{
+ return 1;
+}
+
+int lha_arch_chmod(char *filename, int unix_perms)
+{
+ return 1;
+}
+
+static int set_timestamps(char *filename,
+ FILETIME *creation_time,
+ FILETIME *modification_time,
+ FILETIME *access_time)
+{
+ HANDLE file;
+ int result;
+
+ // Open file handle to the file to change.
+ // The FILE_FLAG_BACKUP_SEMANTICS flag is needed so that we
+ // can obtain handles to directories as well as files.
+
+ file = CreateFileA(filename,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (file == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ // Set the timestamp and close the file handle.
+
+ result = SetFileTime(file, creation_time,
+ access_time, modification_time);
+ CloseHandle(file);
+
+ return result != 0;
+}
+
+int lha_arch_set_windows_timestamps(char *filename,
+ uint64_t creation_time,
+ uint64_t modification_time,
+ uint64_t access_time)
+{
+ FILETIME _creation_time;
+ FILETIME _modification_time;
+ FILETIME _access_time;
+
+ _creation_time.dwHighDateTime
+ = (uint32_t) ((creation_time >> 32) & 0xffffffff);
+ _creation_time.dwLowDateTime
+ = (uint32_t) (creation_time & 0xffffffff);
+
+ _modification_time.dwHighDateTime
+ = (uint32_t) ((modification_time >> 32) & 0xffffffff);
+ _modification_time.dwLowDateTime
+ = (uint32_t) (modification_time & 0xffffffff);
+
+ _access_time.dwHighDateTime
+ = (uint32_t) ((access_time >> 32) & 0xffffffff);
+ _access_time.dwLowDateTime
+ = (uint32_t) (access_time & 0xffffffff);
+
+ return set_timestamps(filename, &_creation_time,
+ &_modification_time, &_access_time);
+}
+
+int lha_arch_utime(char *filename, unsigned int timestamp)
+{
+ SYSTEMTIME unix_epoch;
+ FILETIME filetime;
+ uint64_t ts_scaled;
+
+ // Calculate offset between Windows FILETIME Jan 1, 1601 epoch
+ // and Unix Jan 1, 1970 offset.
+
+ if (unix_epoch_offset == 0) {
+ unix_epoch.wYear = 1970;
+ unix_epoch.wMonth = 1;
+ unix_epoch.wDayOfWeek = 4; // Thursday
+ unix_epoch.wDay = 1;
+ unix_epoch.wHour = 0; // 00:00:00.0
+ unix_epoch.wMinute = 0;
+ unix_epoch.wSecond = 0;
+ unix_epoch.wMilliseconds = 0;
+
+ SystemTimeToFileTime(&unix_epoch, &filetime);
+ unix_epoch_offset = ((uint64_t) filetime.dwHighDateTime << 32)
+ + filetime.dwLowDateTime;
+ }
+
+ // Convert to Unix FILETIME.
+
+ ts_scaled = (uint64_t) timestamp * 10000000 + unix_epoch_offset;
+ filetime.dwHighDateTime = (uint32_t) ((ts_scaled >> 32) & 0xffffffff);
+ filetime.dwLowDateTime = (uint32_t) (ts_scaled & 0xffffffff);
+
+ // Set all timestamps to the same value:
+
+ return set_timestamps(filename, &filetime, &filetime, &filetime);
+}
+
+FILE *lha_arch_fopen(char *filename, int unix_uid, int unix_gid, int unix_perms)
+{
+ return fopen(filename, "wb");
+}
+
+LHAFileType lha_arch_exists(char *filename)
+{
+ WIN32_FILE_ATTRIBUTE_DATA file_attr;
+
+ // Read file attributes to determine the type of the file.
+ // If this fails, assume the file does not exist.
+
+ if (GetFileAttributesExA(filename, GetFileExInfoStandard,
+ &file_attr)) {
+ if ((file_attr.dwFileAttributes
+ & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ return LHA_FILE_DIRECTORY;
+ } else {
+ return LHA_FILE_FILE;
+ }
+ }
+
+ return LHA_FILE_NONE;
+}
+
+int lha_arch_symlink(char *path, char *target)
+{
+ // No-op.
+ return 1;
+}
+
+#endif /* LHA_ARCH_WINDOWS */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c
new file mode 100644
index 00000000..65c4c648
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c
@@ -0,0 +1,159 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crc16.h"
+
+#include "lha_decoder.h"
+#include "lha_basic_reader.h"
+
+struct _LHABasicReader {
+ LHAInputStream *stream;
+ LHAFileHeader *curr_file;
+ size_t curr_file_remaining;
+ int eof;
+};
+
+LHABasicReader *lha_basic_reader_new(LHAInputStream *stream)
+{
+ LHABasicReader *reader;
+
+ reader = calloc(1, sizeof(LHABasicReader));
+
+ if (reader == NULL) {
+ return NULL;
+ }
+
+ reader->stream = stream;
+ reader->curr_file = NULL;
+ reader->curr_file_remaining = 0;
+ reader->eof = 0;
+
+ return reader;
+}
+
+void lha_basic_reader_free(LHABasicReader *reader)
+{
+ if (reader->curr_file != NULL) {
+ lha_file_header_free(reader->curr_file);
+ }
+
+ free(reader);
+}
+
+LHAFileHeader *lha_basic_reader_curr_file(LHABasicReader *reader)
+{
+ return reader->curr_file;
+}
+
+LHAFileHeader *lha_basic_reader_next_file(LHABasicReader *reader)
+{
+ // Free the current file header and skip over any remaining
+ // compressed data that hasn't been read yet.
+
+ if (reader->curr_file != NULL) {
+ lha_file_header_free(reader->curr_file);
+ reader->curr_file = NULL;
+
+ if (!lha_input_stream_skip(reader->stream,
+ reader->curr_file_remaining)) {
+ reader->eof = 1;
+ }
+ }
+
+ if (reader->eof) {
+ return NULL;
+ }
+
+ // Read the header for the next file.
+
+ reader->curr_file = lha_file_header_read(reader->stream);
+
+ if (reader->curr_file == NULL) {
+ reader->eof = 1;
+ return NULL;
+ }
+
+ reader->curr_file_remaining = reader->curr_file->compressed_length;
+
+ return reader->curr_file;
+}
+
+size_t lha_basic_reader_read_compressed(LHABasicReader *reader, void *buf,
+ size_t buf_len)
+{
+ size_t bytes;
+
+ if (reader->eof || reader->curr_file_remaining == 0) {
+ return 0;
+ }
+
+ // Read up to the number of bytes of compressed data remaining.
+
+ if (buf_len > reader->curr_file_remaining) {
+ bytes = reader->curr_file_remaining;
+ } else {
+ bytes = buf_len;
+ }
+
+ if (!lha_input_stream_read(reader->stream, buf, bytes)) {
+ reader->eof = 1;
+ return 0;
+ }
+
+ // Update counter and return success.
+
+ reader->curr_file_remaining -= bytes;
+
+ return bytes;
+}
+
+static size_t decoder_callback(void *buf, size_t buf_len, void *user_data)
+{
+ return lha_basic_reader_read_compressed(user_data, buf, buf_len);
+}
+
+// Create the decoder structure to decode the current file.
+
+LHADecoder *lha_basic_reader_decode(LHABasicReader *reader)
+{
+ LHADecoderType *dtype;
+
+ if (reader->curr_file == NULL) {
+ return NULL;
+ }
+
+ // Look up the decoder to use for this compression method.
+
+ dtype = lha_decoder_for_name(reader->curr_file->compress_method);
+
+ if (dtype == NULL) {
+ return NULL;
+ }
+
+ // Create decoder.
+
+ return lha_decoder_new(dtype, decoder_callback, reader,
+ reader->curr_file->length);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h
new file mode 100644
index 00000000..90cfb88d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h
@@ -0,0 +1,99 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_BASIC_READER_H
+#define LHASA_LHA_BASIC_READER_H
+
+#include "lha_input_stream.h"
+#include "lha_file_header.h"
+#include "lha_decoder.h"
+
+/**
+ * Basic LHA stream reader.
+ *
+ * The basic reader structure just reads @ref LHAFileHeader structures
+ * from an input stream and decompresses files. The more elaborate
+ * @ref LHAReader builds upon this to offer more complicated functionality.
+ */
+
+typedef struct _LHABasicReader LHABasicReader;
+
+/**
+ * Create a new LHA reader to read data from an input stream.
+ *
+ * @param stream The input stream to read from.
+ * @return Pointer to an LHABasicReader structure, or NULL for error.
+ */
+
+LHABasicReader *lha_basic_reader_new(LHAInputStream *stream);
+
+/**
+ * Free an LHA reader.
+ *
+ * @param reader The LHABasicReader structure.
+ */
+
+void lha_basic_reader_free(LHABasicReader *reader);
+
+/**
+ * Return the last file read by @ref lha_basic_reader_next_file.
+ *
+ * @param reader The LHABasicReader structure.
+ * @return Last file returned by @ref lha_basic_reader_next_file,
+ * or NULL if no file has been read yet.
+ */
+
+LHAFileHeader *lha_basic_reader_curr_file(LHABasicReader *reader);
+
+/**
+ * Read the header of the next archived file from the input stream.
+ *
+ * @param reader The LHABasicReader structure.
+ * @return Pointer to an LHAFileHeader structure, or NULL if
+ * an error occurred. This pointer is only valid until
+ * the next time that lha_basic_reader_next_file is called.
+ */
+
+LHAFileHeader *lha_basic_reader_next_file(LHABasicReader *reader);
+
+/**
+ * Read some of the compressed data for the current archived file.
+ *
+ * @param reader The LHABasicReader structure.
+ * @param buf Pointer to the buffer in which to store the data.
+ * @param buf_len Size of the buffer, in bytes.
+ */
+
+size_t lha_basic_reader_read_compressed(LHABasicReader *reader, void *buf,
+ size_t buf_len);
+
+/**
+ * Create a decoder object to decompress the compressed data in the
+ * current file.
+ *
+ * @param reader The LHABasicReader structure.
+ * @return Pointer to a @ref LHADecoder structure to decompress
+ * the current file, or NULL for failure.
+ */
+
+LHADecoder *lha_basic_reader_decode(LHABasicReader *reader);
+
+#endif /* #ifndef LHASA_LHA_BASIC_READER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c
new file mode 100644
index 00000000..9216f002
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c
@@ -0,0 +1,256 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "crc16.h"
+#include "lha_decoder.h"
+
+// Null decoder, used for -lz4-, -lh0-, -pm0-:
+extern LHADecoderType lha_null_decoder;
+
+// LArc compression algorithms:
+extern LHADecoderType lha_lz5_decoder;
+extern LHADecoderType lha_lzs_decoder;
+
+// LHarc compression algorithms:
+extern LHADecoderType lha_lh1_decoder;
+extern LHADecoderType lha_lh4_decoder;
+extern LHADecoderType lha_lh5_decoder;
+extern LHADecoderType lha_lh6_decoder;
+extern LHADecoderType lha_lh7_decoder;
+extern LHADecoderType lha_lhx_decoder;
+
+// PMarc compression algorithms:
+extern LHADecoderType lha_pm1_decoder;
+extern LHADecoderType lha_pm2_decoder;
+
+static struct {
+ char *name;
+ LHADecoderType *dtype;
+} decoders[] = {
+ { "-lz4-", &lha_null_decoder },
+ { "-lz5-", &lha_lz5_decoder },
+ { "-lzs-", &lha_lzs_decoder },
+ { "-lh0-", &lha_null_decoder },
+ { "-lh1-", &lha_lh1_decoder },
+ { "-lh4-", &lha_lh4_decoder },
+ { "-lh5-", &lha_lh5_decoder },
+ { "-lh6-", &lha_lh6_decoder },
+ { "-lh7-", &lha_lh7_decoder },
+ { "-lhx-", &lha_lhx_decoder },
+ { "-pm0-", &lha_null_decoder },
+ { "-pm1-", &lha_pm1_decoder },
+ { "-pm2-", &lha_pm2_decoder },
+};
+
+LHADecoder *lha_decoder_new(LHADecoderType *dtype,
+ LHADecoderCallback callback,
+ void *callback_data,
+ size_t stream_length)
+{
+ LHADecoder *decoder;
+ void *extra_data;
+
+ // Space is allocated together: the LHADecoder structure,
+ // then the private data area used by the algorithm,
+ // followed by the output buffer,
+
+ decoder = calloc(1, sizeof(LHADecoder) + dtype->extra_size
+ + dtype->max_read);
+
+ if (decoder == NULL) {
+ return NULL;
+ }
+
+ decoder->dtype = dtype;
+ decoder->progress_callback = NULL;
+ decoder->last_block = UINT_MAX;
+ decoder->outbuf_pos = 0;
+ decoder->outbuf_len = 0;
+ decoder->stream_pos = 0;
+ decoder->stream_length = stream_length;
+ decoder->decoder_failed = 0;
+ decoder->crc = 0;
+
+ // Private data area follows the structure.
+
+ extra_data = decoder + 1;
+ decoder->outbuf = ((uint8_t *) extra_data) + dtype->extra_size;
+
+ if (dtype->init != NULL
+ && !dtype->init(extra_data, callback, callback_data)) {
+ free(decoder);
+ return NULL;
+ }
+
+ return decoder;
+}
+
+LHADecoderType *lha_decoder_for_name(char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(decoders) / sizeof(*decoders); ++i) {
+ if (!strcmp(name, decoders[i].name)) {
+ return decoders[i].dtype;
+ }
+ }
+
+ // Unknown?
+
+ return NULL;
+}
+
+void lha_decoder_free(LHADecoder *decoder)
+{
+ if (decoder->dtype->free != NULL) {
+ decoder->dtype->free(decoder + 1);
+ }
+
+ free(decoder);
+}
+
+// Check if the stream has progressed far enough that the progress callback
+// should be invoked again.
+
+static void check_progress_callback(LHADecoder *decoder)
+{
+ unsigned int block;
+
+ block = (decoder->stream_pos + decoder->dtype->block_size - 1)
+ / decoder->dtype->block_size;
+
+ // If the stream has advanced by another block, invoke the callback
+ // function. Invoke it multiple times if it has advanced by
+ // more than one block.
+
+ while (decoder->last_block != block) {
+ ++decoder->last_block;
+ decoder->progress_callback(decoder->last_block,
+ decoder->total_blocks,
+ decoder->progress_callback_data);
+ }
+}
+
+void lha_decoder_monitor(LHADecoder *decoder,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ decoder->progress_callback = callback;
+ decoder->progress_callback_data = callback_data;
+
+ decoder->total_blocks
+ = (decoder->stream_length + decoder->dtype->block_size - 1)
+ / decoder->dtype->block_size;
+
+ check_progress_callback(decoder);
+}
+
+size_t lha_decoder_read(LHADecoder *decoder, uint8_t *buf, size_t buf_len)
+{
+ size_t filled, bytes;
+
+ // When we reach the end of the stream, we must truncate the
+ // decompressed data at exactly the right point (stream_length),
+ // or we may read a few extra false byte(s) by mistake.
+ // Reduce buf_len when we get to the end to limit it to the
+ // real number of remaining characters.
+
+ if (decoder->stream_pos + buf_len > decoder->stream_length) {
+ buf_len = decoder->stream_length - decoder->stream_pos;
+ }
+
+ // Try to fill up the buffer that has been passed with as much
+ // data as possible. Each call to read() will fill up outbuf
+ // with some data; this is then copied into buf, with some
+ // data left at the end for the next call.
+
+ filled = 0;
+
+ while (filled < buf_len) {
+
+ // Try to empty out some of the output buffer first.
+
+ bytes = decoder->outbuf_len - decoder->outbuf_pos;
+
+ if (buf_len - filled < bytes) {
+ bytes = buf_len - filled;
+ }
+
+ memcpy(buf + filled, decoder->outbuf + decoder->outbuf_pos,
+ bytes);
+ decoder->outbuf_pos += bytes;
+ filled += bytes;
+
+ // If we previously encountered a failure reading from
+ // the decoder, don't try to call the read function again.
+
+ if (decoder->decoder_failed) {
+ break;
+ }
+
+ // If outbuf is now empty, we can process another run to
+ // re-fill it.
+
+ if (decoder->outbuf_pos >= decoder->outbuf_len) {
+ decoder->outbuf_len
+ = decoder->dtype->read(decoder + 1,
+ decoder->outbuf);
+ decoder->outbuf_pos = 0;
+ }
+
+ // No more data to be read?
+
+ if (decoder->outbuf_len == 0) {
+ decoder->decoder_failed = 1;
+ break;
+ }
+ }
+
+ // Update CRC.
+
+ lha_crc16_buf(&decoder->crc, buf, filled);
+
+ // Track stream position.
+
+ decoder->stream_pos += filled;
+
+ // Check progress callback, if one is set:
+
+ if (decoder->progress_callback != NULL) {
+ check_progress_callback(decoder);
+ }
+
+ return filled;
+}
+
+uint16_t lha_decoder_get_crc(LHADecoder *decoder)
+{
+ return decoder->crc;
+}
+
+size_t lha_decoder_get_length(LHADecoder *decoder)
+{
+ return decoder->stream_pos;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h
new file mode 100644
index 00000000..41bbca1a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h
@@ -0,0 +1,114 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_DECODER_H
+#define LHASA_LHA_DECODER_H
+
+#include "public/lha_decoder.h"
+
+struct _LHADecoderType {
+
+ /**
+ * Callback function to initialize the decoder.
+ *
+ * @param extra_data Pointer to the extra data area allocated for
+ * the decoder.
+ * @param callback Callback function to invoke to read more
+ * compressed data.
+ * @param callback_data Extra pointer to pass to the callback.
+ * @return Non-zero for success.
+ */
+
+ int (*init)(void *extra_data,
+ LHADecoderCallback callback,
+ void *callback_data);
+
+ /**
+ * Callback function to free the decoder.
+ *
+ * @param extra_data Pointer to the extra data area allocated for
+ * the decoder.
+ */
+
+ void (*free)(void *extra_data);
+
+ /**
+ * Callback function to read (ie. decompress) data from the
+ * decoder.
+ *
+ * @param extra_data Pointer to the decoder's custom data.
+ * @param buf Pointer to the buffer in which to store
+ * the decompressed data. The buffer is
+ * at least 'max_read' bytes in size.
+ * @return Number of bytes decompressed.
+ */
+
+ size_t (*read)(void *extra_data, uint8_t *buf);
+
+ /** Number of bytes of extra data to allocate for the decoder. */
+
+ size_t extra_size;
+
+ /** Maximum number of bytes that might be put into the buffer by
+ a single call to read() */
+
+ size_t max_read;
+
+ /** Block size. Used for calculating number of blocks for
+ progress bar. */
+
+ size_t block_size;
+};
+
+struct _LHADecoder {
+
+ /** Type of decoder (algorithm) */
+
+ LHADecoderType *dtype;
+
+ /** Callback function to monitor decoder progress. */
+
+ LHADecoderProgressCallback progress_callback;
+ void *progress_callback_data;
+
+ /** Last announced block position, for progress callback. */
+
+ unsigned int last_block, total_blocks;
+
+ /** Current position in the decode stream, and total length. */
+
+ size_t stream_pos, stream_length;
+
+ /** Output buffer, containing decoded data not yet returned. */
+
+ unsigned int outbuf_pos, outbuf_len;
+ uint8_t *outbuf;
+
+ /** If true, the decoder read() function returned zero. */
+
+ unsigned int decoder_failed;
+
+ /** Current CRC of the output stream. */
+
+ uint16_t crc;
+};
+
+#endif /* #ifndef LHASA_LHA_DECODER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c
new file mode 100644
index 00000000..b9a7d81b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c
@@ -0,0 +1,60 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include "lha_endian.h"
+
+uint16_t lha_decode_uint16(uint8_t *buf)
+{
+ return (uint16_t) (buf[0] | (buf[1] << 8));
+}
+
+uint32_t lha_decode_uint32(uint8_t *buf)
+{
+ return ((uint32_t) buf[0])
+ | ((uint32_t) buf[1] << 8)
+ | ((uint32_t) buf[2] << 16)
+ | ((uint32_t) buf[3] << 24);
+}
+
+uint64_t lha_decode_uint64(uint8_t *buf)
+{
+ return ((uint64_t) buf[0])
+ | ((uint64_t) buf[1] << 8)
+ | ((uint64_t) buf[2] << 16)
+ | ((uint64_t) buf[3] << 24)
+ | ((uint64_t) buf[4] << 32)
+ | ((uint64_t) buf[5] << 40)
+ | ((uint64_t) buf[6] << 48)
+ | ((uint64_t) buf[7] << 56);
+}
+
+uint16_t lha_decode_be_uint16(uint8_t *buf)
+{
+ return (uint16_t) ((buf[0] << 8) | buf[1]);
+}
+
+uint32_t lha_decode_be_uint32(uint8_t *buf)
+{
+ return ((uint32_t) buf[0] << 24)
+ | ((uint32_t) buf[1] << 16)
+ | ((uint32_t) buf[2] << 8)
+ | ((uint32_t) buf[3]);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h
new file mode 100644
index 00000000..c421edb4
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h
@@ -0,0 +1,72 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_ENDIAN_H
+#define LHASA_LHA_ENDIAN_H
+
+#include <inttypes.h>
+
+/**
+ * Decode a 16-bit little-endian unsigned integer.
+ *
+ * @param buf Pointer to buffer containing value to decode.
+ * @return Decoded value.
+ */
+
+uint16_t lha_decode_uint16(uint8_t *buf);
+
+/**
+ * Decode a 32-bit little-endian unsigned integer.
+ *
+ * @param buf Pointer to buffer containing value to decode.
+ * @return Decoded value.
+ */
+
+uint32_t lha_decode_uint32(uint8_t *buf);
+
+/**
+ * Decode a 64-bit little-endian unsigned integer.
+ *
+ * @param buf Pointer to buffer containing value to decode.
+ * @return Decoded value.
+ */
+
+uint64_t lha_decode_uint64(uint8_t *buf);
+
+/**
+ * Decode a 16-bit big-endian unsigned integer.
+ *
+ * @param buf Pointer to buffer containing value to decode.
+ * @return Decoded value.
+ */
+
+uint16_t lha_decode_be_uint16(uint8_t *buf);
+
+/**
+ * Decode a 32-bit big-endian unsigned integer.
+ *
+ * @param buf Pointer to buffer containing value to decode.
+ * @return Decoded value.
+ */
+
+uint32_t lha_decode_be_uint32(uint8_t *buf);
+
+#endif /* #ifndef LHASA_LHA_ENDIAN_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c
new file mode 100644
index 00000000..b06be91a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c
@@ -0,0 +1,1081 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "lha_endian.h"
+#include "lha_file_header.h"
+#include "ext_header.h"
+#include "crc16.h"
+
+#define COMMON_HEADER_LEN 22 /* bytes */
+
+// Minimum length of a level 0 header (with zero-length filename).
+#define LEVEL_0_MIN_HEADER_LEN 22 /* bytes */
+
+// Minimum length of a level 1 base header (with zero-length filename).
+#define LEVEL_1_MIN_HEADER_LEN 25 /* bytes */
+
+// Length of a level 2 base header.
+#define LEVEL_2_HEADER_LEN 26 /* bytes */
+
+// Length of a level 3 base header.
+#define LEVEL_3_HEADER_LEN 32 /* bytes */
+
+// Maximum length of a level 3 header (including extended headers).
+#define LEVEL_3_MAX_HEADER_LEN (1024 * 1024) /* 1 MB */
+
+// Length of a level 0 Unix extended area.
+#define LEVEL_0_UNIX_EXTENDED_LEN 12 /* bytes */
+
+// Length of a level 0 OS-9 extended area.
+#define LEVEL_0_OS9_EXTENDED_LEN 22 /* bytes */
+
+#define RAW_DATA(hdr_ptr, off) ((*hdr_ptr)->raw_data[off])
+#define RAW_DATA_LEN(hdr_ptr) ((*hdr_ptr)->raw_data_len)
+
+char *lha_file_header_full_path(LHAFileHeader *header)
+{
+ char *path;
+ char *filename;
+ char *result;
+
+ if (header->path != NULL) {
+ path = header->path;
+ } else {
+ path = "";
+ }
+
+ if (header->filename != NULL) {
+ filename = header->filename;
+ } else {
+ filename = "";
+ }
+
+ result = malloc(strlen(path) + strlen(filename) + 1);
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ sprintf(result, "%s%s", path, filename);
+
+ return result;
+}
+
+/**
+ * Given a file header with the filename set, split it into separate
+ * path and filename components, if necessary.
+ *
+ * @param header Point to the file header structure.
+ * @return Non-zero for success, or zero for failure.
+ */
+
+static int split_header_filename(LHAFileHeader *header)
+{
+ char *sep;
+ char *new_filename;
+
+ // Is there a directory separator in the path? If so, we need to
+ // split into directory name and filename.
+
+ sep = strrchr(header->filename, '/');
+
+ if (sep != NULL) {
+ new_filename = strdup(sep + 1);
+
+ if (new_filename == NULL) {
+ return 0;
+ }
+
+ *(sep + 1) = '\0';
+ header->path = header->filename;
+ header->filename = new_filename;
+ }
+
+ return 1;
+}
+
+// Perform checksum of header contents.
+
+static int check_l0_checksum(uint8_t *header, size_t header_len, size_t csum)
+{
+ unsigned int result;
+ unsigned int i;
+
+ result = 0;
+
+ for (i = 0; i < header_len; ++i) {
+ result += header[i];
+ }
+
+ return (result & 0xff) == csum;
+}
+
+// Perform full-header CRC check, based on CRC from "common" extended header.
+
+static int check_common_crc(LHAFileHeader *header)
+{
+ uint16_t crc;
+
+ crc = 0;
+ lha_crc16_buf(&crc, header->raw_data, header->raw_data_len);
+
+ return crc == header->common_crc;
+}
+
+// Decode MS-DOS timestamp.
+
+static unsigned int decode_ftime(uint8_t *buf)
+{
+ int raw;
+ struct tm datetime;
+
+ raw = (int) lha_decode_uint32(buf);
+
+ if (raw == 0) {
+ return 0;
+ }
+
+ // Deconstruct the contents of the MS-DOS time value and populate the
+ // 'datetime' structure. Note that 'mktime' generates a timestamp for
+ // the local time zone: this is unfortunate, but probably the best
+ // that can be done, due to the limited data stored in MS-DOS time
+ // values.
+
+ memset(&datetime, 0, sizeof(struct tm));
+
+ datetime.tm_sec = (raw << 1) & 0x3e;
+ datetime.tm_min = (raw >> 5) & 0x3f;
+ datetime.tm_hour = (raw >> 11) & 0x1f;
+ datetime.tm_mday = (raw >> 16) & 0x1f;
+ datetime.tm_mon = ((raw >> 21) & 0xf) - 1;
+ datetime.tm_year = 80 + ((raw >> 25) & 0x7f);
+ datetime.tm_wday = 0;
+ datetime.tm_yday = 0;
+ datetime.tm_isdst = -1;
+
+ return (unsigned int) mktime(&datetime);
+}
+
+// MS-DOS archives (and archives from similar systems) may have paths and
+// filenames that are in all-caps. Detect these and convert them to
+// lower-case.
+
+static void fix_msdos_allcaps(LHAFileHeader *header)
+{
+ unsigned int i;
+ int is_allcaps;
+
+ // Check both path and filename to see if there are any lower-case
+ // characters.
+
+ is_allcaps = 1;
+
+ if (header->path != NULL) {
+ for (i = 0; header->path[i] != '\0'; ++i) {
+ if (islower((unsigned) header->path[i])) {
+ is_allcaps = 0;
+ break;
+ }
+ }
+ }
+
+ if (is_allcaps && header->filename != NULL) {
+ for (i = 0; header->filename[i] != '\0'; ++i) {
+ if (islower((unsigned) header->filename[i])) {
+ is_allcaps = 0;
+ break;
+ }
+ }
+ }
+
+ // If both are all-caps, convert them all to lower-case.
+
+ if (is_allcaps) {
+ if (header->path != NULL) {
+ for (i = 0; header->path[i] != '\0'; ++i) {
+ header->path[i]
+ = tolower((unsigned) header->path[i]);
+ }
+ }
+ if (header->filename != NULL) {
+ for (i = 0; header->filename[i] != '\0'; ++i) {
+ header->filename[i]
+ = tolower((unsigned) header->filename[i]);
+ }
+ }
+ }
+}
+
+// Process the OS-9 permissions field and translate into the equivalent
+// Unix permissions.
+
+static void os9_to_unix_permissions(LHAFileHeader *header)
+{
+ unsigned int or, ow, oe, pr, pw, pe, d;
+
+ // Translate into equivalent Unix permissions. OS-9 just has
+ // owner and public, so double up public for the owner field.
+
+ or = (header->os9_perms & 0x01) != 0;
+ ow = (header->os9_perms & 0x02) != 0;
+ oe = (header->os9_perms & 0x04) != 0;
+ pr = (header->os9_perms & 0x08) != 0;
+ pw = (header->os9_perms & 0x10) != 0;
+ pe = (header->os9_perms & 0x20) != 0;
+ d = (header->os9_perms & 0x80) != 0;
+
+ header->extra_flags |= LHA_FILE_UNIX_PERMS;
+ header->unix_perms = (d << 14)
+ | (or << 8) | (ow << 7) | (oe << 6) // owner
+ | (pr << 5) | (pw << 4) | (pe << 3) // group
+ | (pr << 2) | (pw << 1) | (pe << 0); // everyone
+}
+
+// Parse a Unix symbolic link. These are stored in the format:
+// filename = symlink|target
+
+static int parse_symlink(LHAFileHeader *header)
+{
+ char *fullpath;
+ char *p;
+
+ // Although the format is always the same, some files have
+ // symlink headers where the path is split between the path
+ // and filename headers. For example:
+ // path = etc|../../
+ // filename = etc
+
+ fullpath = lha_file_header_full_path(header);
+
+ if (fullpath == NULL) {
+ return 0;
+ }
+
+ p = strchr(fullpath, '|');
+
+ if (p == NULL) {
+ free(fullpath);
+ return 0;
+ }
+
+ header->symlink_target = strdup(p + 1);
+
+ if (header->symlink_target == NULL) {
+ free(fullpath);
+ return 0;
+ }
+
+ // Cut the string in half at the separator. Keep the left side
+ // as the value for filename.
+
+ *p = '\0';
+
+ free(header->path);
+ free(header->filename);
+ header->path = NULL;
+ header->filename = fullpath;
+
+ // Having joined path and filename together during processing,
+ // we now have the opposite problem: header->filename might
+ // contain a full path rather than just a filename. Split back
+ // into two again.
+
+ return split_header_filename(header);
+}
+
+// Decode the path field in the header.
+
+static int process_level0_path(LHAFileHeader *header, uint8_t *data,
+ size_t data_len)
+{
+ unsigned int i;
+
+ // Zero-length filename probably means that this is a directory
+ // entry. Leave the filename field as NULL - this makes us
+ // consistent with level 2/3 headers.
+
+ if (data_len == 0) {
+ return 1;
+ }
+
+ header->filename = malloc(data_len + 1);
+
+ if (header->filename == NULL) {
+ return 0;
+ }
+
+ memcpy(header->filename, data, data_len);
+ header->filename[data_len] = '\0';
+
+ // Convert MS-DOS path separators to Unix path separators.
+
+ for (i = 0; i < data_len; ++i) {
+ if (header->filename[i] == '\\') {
+ header->filename[i] = '/';
+ }
+ }
+
+ return split_header_filename(header);
+}
+
+// Read some more data from the input stream, extending the raw_data
+// array (and the size of the header).
+
+static uint8_t *extend_raw_data(LHAFileHeader **header,
+ LHAInputStream *stream,
+ size_t nbytes)
+{
+ LHAFileHeader *new_header;
+ size_t new_raw_len;
+ uint8_t *result;
+
+ if (nbytes > LEVEL_3_MAX_HEADER_LEN) {
+ return NULL;
+ }
+
+ // Reallocate the header and raw_data area to be larger.
+
+ new_raw_len = RAW_DATA_LEN(header) + nbytes;
+ new_header = realloc(*header, sizeof(LHAFileHeader) + new_raw_len);
+
+ if (new_header == NULL) {
+ return NULL;
+ }
+
+ // Update the header pointer to point to the new area.
+
+ *header = new_header;
+ new_header->raw_data = (uint8_t *) (new_header + 1);
+ result = new_header->raw_data + new_header->raw_data_len;
+
+ // Read data from stream into new area.
+
+ if (!lha_input_stream_read(stream, result, nbytes)) {
+ return NULL;
+ }
+
+ new_header->raw_data_len = new_raw_len;
+
+ return result;
+}
+
+// Starting at the specified offset in the raw_data array, walk
+// through the list of extended headers and parse them.
+
+static int decode_extended_headers(LHAFileHeader **header,
+ unsigned int offset)
+{
+ unsigned int field_size;
+ uint8_t *ext_header;
+ size_t ext_header_len;
+ size_t available_length;
+
+ // Level 3 headers use 32-bit length fields; all others use
+ // 16-bit fields.
+
+ if ((*header)->header_level == 3) {
+ field_size = 4;
+ } else {
+ field_size = 2;
+ }
+
+ available_length = RAW_DATA_LEN(header) - offset - field_size;
+
+ while (offset <= RAW_DATA_LEN(header) - field_size) {
+ ext_header = &RAW_DATA(header, offset + field_size);
+
+ if (field_size == 4) {
+ ext_header_len
+ = lha_decode_uint32(&RAW_DATA(header, offset));
+ } else {
+ ext_header_len
+ = lha_decode_uint16(&RAW_DATA(header, offset));
+ }
+
+ // Header length zero indicates end of chain. Otherwise, sanity
+ // check the header length is valid.
+
+ if (ext_header_len == 0) {
+ break;
+ } else if (ext_header_len < field_size + 1
+ || ext_header_len > available_length) {
+ return 0;
+ }
+
+ // Process header:
+
+ lha_ext_header_decode(*header, ext_header[0], ext_header + 1,
+ ext_header_len - field_size - 1);
+
+ // Advance to next header.
+
+ offset += ext_header_len;
+ available_length -= ext_header_len;
+ }
+
+ return 1;
+}
+
+static int read_next_ext_header(LHAFileHeader **header,
+ LHAInputStream *stream,
+ uint8_t **ext_header,
+ size_t *ext_header_len)
+{
+ // Last two bytes of the header raw data contain the size
+ // of the next header.
+
+ *ext_header_len
+ = lha_decode_uint16(&RAW_DATA(header, RAW_DATA_LEN(header) - 2));
+
+ // No more headers?
+
+ if (*ext_header_len == 0) {
+ *ext_header = NULL;
+ return 1;
+ }
+
+ *ext_header = extend_raw_data(header, stream, *ext_header_len);
+
+ return *ext_header != NULL;
+}
+
+// Read extended headers for a level 1 header, extending the
+// raw_data block to include them.
+
+static int read_l1_extended_headers(LHAFileHeader **header,
+ LHAInputStream *stream)
+{
+ uint8_t *ext_header;
+ size_t ext_header_len;
+
+ for (;;) {
+ // Try to read the next header.
+
+ if (!read_next_ext_header(header, stream,
+ &ext_header, &ext_header_len)) {
+ return 0;
+ }
+
+ // Last header?
+
+ if (ext_header_len == 0) {
+ break;
+ }
+
+ // For backwards compatibility with level 0 headers,
+ // the compressed length field is actually "compressed
+ // length + length of all extended headers":
+
+ if ((*header)->compressed_length < ext_header_len) {
+ return 0;
+ }
+
+ (*header)->compressed_length -= ext_header_len;
+
+ // Must be at least 3 bytes - 1 byte header type
+ // + 2 bytes for next header length
+
+ if (ext_header_len < 3) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// Process a level 0 Unix extended area.
+
+static void process_level0_unix_area(LHAFileHeader *header,
+ uint8_t *data, size_t data_len)
+{
+ // A typical Unix extended area:
+ //
+ // 00000000 55 00 00 3b 3d 4b 80 81 e8 03 e8 03
+
+ // Sanity check.
+
+ if (data_len < LEVEL_0_UNIX_EXTENDED_LEN || data[1] != 0x00) {
+ return;
+ }
+
+ // OS-9/68k generates an extended area that is broadly compatible
+ // with the Unix one.
+
+ // Fill in the header fields from the data from the extended area.
+ // There's one minor point to note here: OS-9/68k LHA includes the
+ // timestamp twice - I have no idea why. In order to support both
+ // variants, read the end fields from the end of the extended area.
+
+ header->os_type = data[0];
+ header->timestamp = lha_decode_uint32(data + 2);
+
+ header->unix_perms = lha_decode_uint16(data + data_len - 6);
+ header->unix_uid = lha_decode_uint16(data + data_len - 4);
+ header->unix_gid = lha_decode_uint16(data + data_len - 2);
+
+ header->extra_flags |= LHA_FILE_UNIX_PERMS | LHA_FILE_UNIX_UID_GID;
+}
+
+// Process a level 0 OS-9 extended area.
+
+static void process_level0_os9_area(LHAFileHeader *header,
+ uint8_t *data, size_t data_len)
+{
+ // A typical OS-9 extended area:
+ //
+ // 00000000 39 13 00 00 c3 16 00 0f 00 cc 18 07 09 03 01 16
+ // 00000010 00 13 00 00 00 00
+
+ // Sanity checks:
+
+ if (data_len < LEVEL_0_OS9_EXTENDED_LEN
+ || data[9] != 0xcc || data[1] != data[17] || data[2] != data[18]) {
+ return;
+ }
+
+ // The contents resemble the contents of the OS-9 extended header.
+ // We just want the permissions field.
+
+ header->os_type = LHA_OS_TYPE_OS9;
+ header->os9_perms = lha_decode_uint16(data + 1);
+ header->extra_flags |= LHA_FILE_OS9_PERMS;
+}
+
+// Handling for level 0 extended areas.
+
+static void process_level0_extended_area(LHAFileHeader *header,
+ uint8_t *data, size_t data_len)
+{
+ // PMarc archives can include comments that are stored in the
+ // extended area. It is possible that this could conflict with
+ // the logic below, so specifically exclude them.
+
+ if (!strncmp(header->compress_method, "-pm", 3)) {
+ return;
+ }
+
+ // Different tools include different extended areas. Try to
+ // identify which tool generated this one, based on the first
+ // byte.
+
+ switch (data[0]) {
+ case LHA_OS_TYPE_UNIX:
+ case LHA_OS_TYPE_OS9_68K:
+ process_level0_unix_area(header, data, data_len);
+ break;
+
+ case LHA_OS_TYPE_OS9:
+ process_level0_os9_area(header, data, data_len);
+ break;
+
+ default:
+ break;
+ }
+}
+
+// Decode a level 0 or 1 header.
+
+static int decode_level0_header(LHAFileHeader **header, LHAInputStream *stream)
+{
+ uint8_t header_len;
+ uint8_t header_csum;
+ size_t path_len;
+ size_t min_len;
+
+ header_len = RAW_DATA(header, 0);
+ header_csum = RAW_DATA(header, 1);
+
+ // Sanity check header length. This is the minimum header length
+ // for a header that has a zero-length path.
+
+ switch ((*header)->header_level) {
+ case 0:
+ min_len = LEVEL_0_MIN_HEADER_LEN;
+ break;
+ case 1:
+ min_len = LEVEL_1_MIN_HEADER_LEN;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (header_len < min_len) {
+ return 0;
+ }
+
+ // We only have a partial header so far. Read the full header.
+
+ if (!extend_raw_data(header, stream,
+ header_len + 2 - RAW_DATA_LEN(header))) {
+ return 0;
+ }
+
+ // Checksum the header.
+
+ if (!check_l0_checksum(&RAW_DATA(header, 2),
+ RAW_DATA_LEN(header) - 2,
+ header_csum)) {
+ return 0;
+ }
+
+ // Compression method:
+
+ memcpy((*header)->compress_method, &RAW_DATA(header, 2), 5);
+ (*header)->compress_method[5] = '\0';
+
+ // File lengths:
+
+ (*header)->compressed_length = lha_decode_uint32(&RAW_DATA(header, 7));
+ (*header)->length = lha_decode_uint32(&RAW_DATA(header, 11));
+
+ // Timestamp:
+
+ (*header)->timestamp = decode_ftime(&RAW_DATA(header, 15));
+
+ // Read path. Check path length field - is the header long enough
+ // to hold this full path?
+
+ path_len = RAW_DATA(header, 21);
+
+ if (min_len + path_len > header_len) {
+ return 0;
+ }
+
+ // OS type?
+
+ if ((*header)->header_level == 0) {
+ (*header)->os_type = LHA_OS_TYPE_UNKNOWN;
+ } else {
+ (*header)->os_type = RAW_DATA(header, 24 + path_len);
+ }
+
+ // Read filename field:
+
+ if (!process_level0_path(*header, &RAW_DATA(header, 22), path_len)) {
+ return 0;
+ }
+
+ // CRC field.
+
+ (*header)->crc = lha_decode_uint16(&RAW_DATA(header, 22 + path_len));
+
+ // Level 0 headers can contain extended data through different schemes
+ // to the extended header system used in level 1+.
+
+ if ((*header)->header_level == 0
+ && header_len > LEVEL_0_MIN_HEADER_LEN + path_len) {
+ process_level0_extended_area(*header,
+ &RAW_DATA(header, LEVEL_0_MIN_HEADER_LEN + 2 + path_len),
+ header_len - LEVEL_0_MIN_HEADER_LEN - path_len);
+ }
+
+ return 1;
+}
+
+static int decode_level1_header(LHAFileHeader **header, LHAInputStream *stream)
+{
+ unsigned int ext_header_start;
+
+ if (!decode_level0_header(header, stream)) {
+ return 0;
+ }
+
+ // Level 1 headers can have extended headers, so parse them.
+
+ ext_header_start = RAW_DATA_LEN(header) - 2;
+
+ if (!read_l1_extended_headers(header, stream)
+ || !decode_extended_headers(header, ext_header_start)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int decode_level2_header(LHAFileHeader **header, LHAInputStream *stream)
+{
+ unsigned int header_len;
+
+ header_len = lha_decode_uint16(&RAW_DATA(header, 0));
+
+ if (header_len < LEVEL_2_HEADER_LEN) {
+ return 0;
+ }
+
+ // Read the full header.
+
+ if (!extend_raw_data(header, stream,
+ header_len - RAW_DATA_LEN(header))) {
+ return 0;
+ }
+
+ // Compression method:
+
+ memcpy((*header)->compress_method, &RAW_DATA(header, 2), 5);
+ (*header)->compress_method[5] = '\0';
+
+ // File lengths:
+
+ (*header)->compressed_length = lha_decode_uint32(&RAW_DATA(header, 7));
+ (*header)->length = lha_decode_uint32(&RAW_DATA(header, 11));
+
+ // Timestamp. Unlike level 0/1, this is a Unix-style timestamp.
+
+ (*header)->timestamp = lha_decode_uint32(&RAW_DATA(header, 15));
+
+ // CRC.
+
+ (*header)->crc = lha_decode_uint16(&RAW_DATA(header, 21));
+
+ // OS type:
+
+ (*header)->os_type = RAW_DATA(header, 23);
+
+ // LHA for OS-9/68k generates broken level 2 archives: the header
+ // length field is the length of the remainder of the header, not
+ // the complete header length. As a result it's two bytes too
+ // short. We can use the OS type field to detect these archives
+ // and compensate.
+
+ if ((*header)->os_type == LHA_OS_TYPE_OS9_68K) {
+ if (!extend_raw_data(header, stream, 2)) {
+ return 0;
+ }
+ }
+
+ if (!decode_extended_headers(header, 24)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int decode_level3_header(LHAFileHeader **header, LHAInputStream *stream)
+{
+ unsigned int header_len;
+
+ // The first field at the start of a level 3 header is supposed to
+ // indicate word size, with the idea being that the header format
+ // can be extended beyond 32-bit words in the future. In practise,
+ // nothing supports anything other than 32-bit (4 bytes), and neither
+ // do we.
+
+ if (lha_decode_uint16(&RAW_DATA(header, 0)) != 4) {
+ return 0;
+ }
+
+ // Read the full header.
+
+ if (!extend_raw_data(header, stream,
+ LEVEL_3_HEADER_LEN - RAW_DATA_LEN(header))) {
+ return 0;
+ }
+
+ // Read the header length field (including extended headers), and
+ // extend to this full length. Because this is a 32-bit value,
+ // we must place a sensible limit on the amount of data that will
+ // be read, to avoid possibly allocating gigabytes of memory.
+
+ header_len = lha_decode_uint32(&RAW_DATA(header, 24));
+
+ if (header_len > LEVEL_3_MAX_HEADER_LEN
+ || header_len < RAW_DATA_LEN(header)) {
+ return 0;
+ }
+
+ if (!extend_raw_data(header, stream,
+ header_len - RAW_DATA_LEN(header))) {
+ return 0;
+ }
+
+ // Compression method:
+
+ memcpy((*header)->compress_method, &RAW_DATA(header, 2), 5);
+ (*header)->compress_method[5] = '\0';
+
+ // File lengths:
+
+ (*header)->compressed_length = lha_decode_uint32(&RAW_DATA(header, 7));
+ (*header)->length = lha_decode_uint32(&RAW_DATA(header, 11));
+
+ // Unix-style timestamp.
+
+ (*header)->timestamp = lha_decode_uint32(&RAW_DATA(header, 15));
+
+ // CRC.
+
+ (*header)->crc = lha_decode_uint16(&RAW_DATA(header, 21));
+
+ // OS type:
+
+ (*header)->os_type = RAW_DATA(header, 23);
+
+ if (!decode_extended_headers(header, 28)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+// "Collapse" a path down, by removing all instances of "." and ".."
+// paths. This is to protect against malicious archives that might include
+// ".." in a path to break out of the extract directory.
+
+static void collapse_path(char *filename)
+{
+ unsigned int currpath_len;
+ char *currpath;
+ char *r, *w;
+
+ // If the path starts with a /, it is an absolute path; skip over
+ // that first character and don't remove it.
+
+ if (filename[0] == '/') {
+ ++filename;
+ }
+
+ // Step through each character, copying it from 'r' to 'w'. It
+ // is always the case that w <= r, and the final string will
+ // be equal in length or shorter than the original.
+
+ currpath = filename;
+ w = filename;
+
+ for (r = filename; *r != '\0'; ++r) {
+ *w++ = *r;
+
+ // Each time a new path separator is found, examine the
+ // path that was just written.
+
+ if (*r == '/') {
+
+ currpath_len = w - currpath - 1;
+
+ // Empty path (//) or current directory (.)?
+
+ if (currpath_len == 0
+ || (currpath_len == 1 && currpath[0] == '.')) {
+ w = currpath;
+
+ // Parent directory (..)?
+
+ } else if (currpath_len == 2
+ && currpath[0] == '.' && currpath[1] == '.') {
+
+ // Walk back up by one directory. Don't go
+ // past the start of the string.
+
+ if (currpath == filename) {
+ w = filename;
+ } else {
+ w = currpath - 1;
+
+ while (w > filename) {
+ if (*(w - 1) == '/') {
+ break;
+ }
+ --w;
+ }
+
+ currpath = w;
+ }
+
+ // Save for next time we start a new path.
+
+ } else {
+ currpath = w;
+ }
+ }
+ }
+
+ *w = '\0';
+}
+
+LHAFileHeader *lha_file_header_read(LHAInputStream *stream)
+{
+ LHAFileHeader *header;
+ int success;
+
+ // We cannot decode the file header until we identify the
+ // header level (as different header level formats are
+ // decoded in different ways. The header level field is
+ // located at byte offset 20 within the header, so we
+ // must read the first 21 bytes to read it (actually this
+ // reads one byte more, so that we get the filename length
+ // byte for level 1 headers as well).
+
+ // Allocate result structure.
+
+ header = calloc(1, sizeof(LHAFileHeader) + COMMON_HEADER_LEN);
+
+ if (header == NULL) {
+ return NULL;
+ }
+
+ memset(header, 0, sizeof(LHAFileHeader));
+
+ header->_refcount = 1;
+
+ // Read first chunk of header.
+
+ header->raw_data = (uint8_t *) (header + 1);
+ header->raw_data_len = COMMON_HEADER_LEN;
+
+ if (!lha_input_stream_read(stream, header->raw_data,
+ header->raw_data_len)) {
+ goto fail;
+ }
+
+ // Identify header level, and decode header depending on
+ // the value encountered.
+
+ header->header_level = header->raw_data[20];
+
+ switch (header->header_level) {
+ case 0:
+ success = decode_level0_header(&header, stream);
+ break;
+
+ case 1:
+ success = decode_level1_header(&header, stream);
+ break;
+
+ case 2:
+ success = decode_level2_header(&header, stream);
+ break;
+
+ case 3:
+ success = decode_level3_header(&header, stream);
+ break;
+
+ default:
+ success = 0;
+ break;
+ }
+
+ if (!success) {
+ goto fail;
+ }
+
+ // Sanity check that we got some headers, at least.
+ // Directory entries must have a path, and files must have a
+ // filename. Symlinks are stored using the same compression method
+ // field string (-lhd-) as directories.
+
+ if (strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR) != 0) {
+ if (header->filename == NULL) {
+ goto fail;
+ }
+ } else if (!strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR)
+ && LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)
+ && (header->path != NULL || header->filename != NULL)
+ && (header->unix_perms & 0170000) == 0120000) {
+
+ if (!parse_symlink(header)) {
+ goto fail;
+ }
+
+ } else {
+ if (header->path == NULL) {
+ goto fail;
+ }
+ }
+
+ // Is the path an all-caps filename? If so, it is a DOS path that
+ // should be translated to lower case.
+
+ if (header->os_type == LHA_OS_TYPE_UNKNOWN
+ || header->os_type == LHA_OS_TYPE_MSDOS
+ || header->os_type == LHA_OS_TYPE_ATARI
+ || header->os_type == LHA_OS_TYPE_OS2) {
+ fix_msdos_allcaps(header);
+ }
+
+ // Collapse special directory paths to ensure the path is clean.
+
+ if (header->path != NULL) {
+ collapse_path(header->path);
+ }
+
+ // Is this header generated by OS-9/68k LHA? If so, any Unix
+ // permissions are actually OS-9 permissions.
+
+ if (header->os_type == LHA_OS_TYPE_OS9_68K
+ && LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
+ header->os9_perms = header->unix_perms;
+ header->extra_flags |= LHA_FILE_OS9_PERMS;
+ }
+
+ // If OS-9 permissions were read, translate into Unix permissions.
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_OS9_PERMS)) {
+ os9_to_unix_permissions(header);
+ }
+
+ // Was the "common" extended header read, which contains a CRC of
+ // the full header? If so, perform a CRC check now.
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_COMMON_CRC)
+ && !check_common_crc(header)) {
+ goto fail;
+ }
+
+ return header;
+fail:
+ lha_file_header_free(header);
+ return NULL;
+}
+
+void lha_file_header_free(LHAFileHeader *header)
+{
+ // Sanity check:
+
+ if (header->_refcount == 0) {
+ return;
+ }
+
+ // Count down references and only free when all have been removed.
+
+ --header->_refcount;
+
+ if (header->_refcount > 0) {
+ return;
+ }
+
+ free(header->filename);
+ free(header->path);
+ free(header->symlink_target);
+ free(header->unix_username);
+ free(header->unix_group);
+ free(header);
+}
+
+void lha_file_header_add_ref(LHAFileHeader *header)
+{
+ ++header->_refcount;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h
new file mode 100644
index 00000000..2111f9e7
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h
@@ -0,0 +1,68 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+
+#ifndef LHASA_LHA_FILE_HEADER_H
+#define LHASA_LHA_FILE_HEADER_H
+
+#include "public/lha_file_header.h"
+#include "lha_input_stream.h"
+
+/**
+ * Read a file header from the input stream.
+ *
+ * @param stream The input stream to read from.
+ * @return Pointer to a new LHAFileHeader structure, or NULL
+ * if an error occurred or a valid header could not
+ * be read.
+ */
+
+LHAFileHeader *lha_file_header_read(LHAInputStream *stream);
+
+/**
+ * Free a file header structure.
+ *
+ * @param header The file header to free.
+ */
+
+void lha_file_header_free(LHAFileHeader *header);
+
+/**
+ * Add a reference to the specified file header, to stop it from being
+ * freed.
+ *
+ * @param header The file header to add a reference to.
+ */
+
+void lha_file_header_add_ref(LHAFileHeader *header);
+
+/**
+ * Get the full path for the given file header.
+ *
+ * @param header Pointer to the file header structure.
+ * @return Pointer to an allocated string containing the full
+ * file or directory path, or NULL for failure. The
+ * string must be freed by the caller.
+ */
+
+char *lha_file_header_full_path(LHAFileHeader *header);
+
+#endif /* #ifndef LHASA_LHA_FILE_HEADER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c
new file mode 100644
index 00000000..2fe8d96c
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c
@@ -0,0 +1,403 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "lha_arch.h"
+#include "lha_input_stream.h"
+
+// Maximum length of the self-extractor header.
+// If we don't find an LHA file header after this many bytes, give up.
+
+#define MAX_SFX_HEADER_LEN 65536
+
+// Size of the lead-in buffer used to skip the self-extractor.
+
+#define LEADIN_BUFFER_LEN 24
+
+// Magic string to detect an Amiga LhASFX self-extracting file.
+// This type of self-extractor is special because the program itself
+// contains a mini-LHA file that must be skipped over to get to
+// the real one.
+
+#define AMIGA_LHASFX_ID "LhASFX V1.2,"
+
+typedef enum {
+ LHA_INPUT_STREAM_INIT,
+ LHA_INPUT_STREAM_READING,
+ LHA_INPUT_STREAM_FAIL
+} LHAInputStreamState;
+
+struct _LHAInputStream {
+ const LHAInputStreamType *type;
+ void *handle;
+ LHAInputStreamState state;
+ uint8_t leadin[LEADIN_BUFFER_LEN];
+ size_t leadin_len;
+};
+
+LHAInputStream *lha_input_stream_new(const LHAInputStreamType *type,
+ void *handle)
+{
+ LHAInputStream *result;
+
+ result = calloc(1, sizeof(LHAInputStream));
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ result->type = type;
+ result->handle = handle;
+ result->leadin_len = 0;
+ result->state = LHA_INPUT_STREAM_INIT;
+
+ return result;
+}
+
+void lha_input_stream_free(LHAInputStream *stream)
+{
+ // Close the input stream.
+
+ if (stream->type->close != NULL) {
+ stream->type->close(stream->handle);
+ }
+
+ free(stream);
+}
+
+// Check if the specified buffer is the start of a file header.
+
+static int file_header_match(uint8_t *buf)
+{
+ if (buf[2] != '-' || buf[6] != '-') {
+ return 0;
+ }
+
+ // LHA algorithm?
+
+ if (buf[3] == 'l' && buf[4] == 'h') {
+ return 1;
+ }
+
+ // LArc algorithm (lz4, lz5, lzs)?
+
+ if (buf[3] == 'l' && buf[4] == 'z'
+ && (buf[5] == '4' || buf[5] == '5' || buf[5] == 's')) {
+ return 1;
+ }
+
+ // PMarc algorithm? (pm0, pm2)
+ // Note: PMarc SFX archives have a -pms- string in them that must
+ // be ignored.
+
+ if (buf[3] == 'p' && buf[4] == 'm' && buf[5] != 's') {
+ return 1;
+ }
+
+ return 0;
+}
+
+// Empty some of the bytes from the start of the lead-in buffer.
+
+static void empty_leadin(LHAInputStream *stream, size_t bytes)
+{
+ memmove(stream->leadin, stream->leadin + bytes,
+ stream->leadin_len - bytes);
+ stream->leadin_len -= bytes;
+}
+
+// Read bytes from the input stream into the specified buffer.
+
+static int do_read(LHAInputStream *stream, void *buf, size_t buf_len)
+{
+ return stream->type->read(stream->handle, buf, buf_len);
+}
+
+// Skip the self-extractor header at the start of the file.
+// Returns non-zero if a header was found.
+
+static int skip_sfx(LHAInputStream *stream)
+{
+ size_t filepos;
+ unsigned int i;
+ int skip_files;
+ int read;
+
+ filepos = 0;
+ skip_files = 0;
+
+ while (filepos < MAX_SFX_HEADER_LEN) {
+
+ // Add some more bytes to the lead-in buffer:
+
+ read = do_read(stream, stream->leadin + stream->leadin_len,
+ LEADIN_BUFFER_LEN - stream->leadin_len);
+
+ if (read <= 0) {
+ break;
+ }
+
+ stream->leadin_len += (unsigned int) read;
+
+ // Check the lead-in buffer for a file header.
+
+ for (i = 0; i + 12 < stream->leadin_len; ++i) {
+ if (file_header_match(stream->leadin + i)) {
+ if (skip_files == 0) {
+ empty_leadin(stream, i);
+ return 1;
+ } else {
+ --skip_files;
+ }
+ }
+
+ // Detect Amiga self-extractor.
+
+ if (!memcmp(stream->leadin + i, AMIGA_LHASFX_ID,
+ strlen(AMIGA_LHASFX_ID))) {
+ skip_files = 1;
+ }
+ }
+
+ empty_leadin(stream, i);
+ filepos += i;
+ }
+
+ return 0;
+}
+
+int lha_input_stream_read(LHAInputStream *stream, void *buf, size_t buf_len)
+{
+ size_t total_bytes, n;
+ int result;
+
+ // Start of the stream? Skip self-extract header, if there is one.
+
+ if (stream->state == LHA_INPUT_STREAM_INIT) {
+ if (skip_sfx(stream)) {
+ stream->state = LHA_INPUT_STREAM_READING;
+ } else {
+ stream->state = LHA_INPUT_STREAM_FAIL;
+ }
+ }
+
+ if (stream->state == LHA_INPUT_STREAM_FAIL) {
+ return 0;
+ }
+
+ // Now fill the result buffer. Start by emptying the lead-in buffer.
+
+ total_bytes = 0;
+
+ if (stream->leadin_len > 0) {
+ if (buf_len < stream->leadin_len) {
+ n = buf_len;
+ } else {
+ n = stream->leadin_len;
+ }
+
+ memcpy(buf, stream->leadin, n);
+ empty_leadin(stream, n);
+ total_bytes += n;
+ }
+
+ // Read from the input stream.
+
+ if (total_bytes < buf_len) {
+ result = do_read(stream, (uint8_t *) buf + total_bytes,
+ buf_len - total_bytes);
+
+ if (result > 0) {
+ total_bytes += (unsigned int) result;
+ }
+ }
+
+ // Only successful if the complete buffer is filled.
+
+ return total_bytes == buf_len;
+}
+
+int lha_input_stream_skip(LHAInputStream *stream, size_t bytes)
+{
+ // If we have a dedicated skip function, use it; otherwise,
+ // the read function can be used to perform a skip.
+
+ if (stream->type->skip != NULL) {
+ return stream->type->skip(stream->handle, bytes);
+ } else {
+ uint8_t data[32];
+ unsigned int len;
+ int result;
+
+ while (bytes > 0) {
+
+ // Read as many bytes left as possible to fit in
+ // the buffer:
+
+ if (bytes > sizeof(data)) {
+ len = sizeof(data);
+ } else {
+ len = bytes;
+ }
+
+ result = do_read(stream, data, len);
+
+ if (result < 0) {
+ return 0;
+ }
+
+ bytes -= (unsigned int) result;
+ }
+
+ return 1;
+ }
+}
+
+// Read data from a FILE * source.
+
+static int file_source_read(void *handle, void *buf, size_t buf_len)
+{
+ size_t bytes_read;
+ FILE *fh = handle;
+
+ bytes_read = fread(buf, 1, buf_len, fh);
+
+ // If an error occurs, zero is returned; however, it may also
+ // indicate end of file.
+
+ if (bytes_read == 0 && !feof(fh)) {
+ return -1;
+ }
+
+ return (int) bytes_read;
+}
+
+// "Fallback" skip for file source that uses fread(), for unseekable
+// streams.
+
+static int file_source_skip_fallback(FILE *handle, size_t bytes)
+{
+ uint8_t data[32];
+ unsigned int len;
+ int result;
+
+ while (bytes > 0) {
+ if (bytes > sizeof(data)) {
+ len = sizeof(data);
+ } else {
+ len = bytes;
+ }
+
+ result = fread(data, 1, len, handle);
+
+ if (result != (int) len) {
+ return 0;
+ }
+
+ bytes -= len;
+ }
+
+ return 1;
+}
+
+// Seek forward in a FILE * input stream.
+
+static int file_source_skip(void *handle, size_t bytes)
+{
+ int result;
+
+ // If this is an unseekable stream of some kind, always use the
+ // fallback behavior, as at least this is guaranteed to work.
+ // This is to work around problems on Windows, where fseek() can
+ // seek half-way on a stream and *then* fail, leaving us in an
+ // unworkable situation.
+
+ if (ftell(handle) < 0) {
+ return file_source_skip_fallback(handle, bytes);
+ }
+
+ result = fseek(handle, (long) bytes, SEEK_CUR);
+
+ if (result < 0) {
+ if (errno == EBADF || errno == ESPIPE) {
+ return file_source_skip_fallback(handle, bytes);
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// Close a FILE * input stream.
+
+static void file_source_close(void *handle)
+{
+ fclose(handle);
+}
+
+// "Owned" file source - the stream will be closed when the input
+// stream is freed.
+
+static const LHAInputStreamType file_source_owned = {
+ file_source_read,
+ file_source_skip,
+ file_source_close
+};
+
+// "Unowned" file source - the stream is owned by the calling code.
+
+static const LHAInputStreamType file_source_unowned = {
+ file_source_read,
+ file_source_skip,
+ NULL
+};
+
+LHAInputStream *lha_input_stream_from(char *filename)
+{
+ LHAInputStream *result;
+ FILE *fstream;
+
+ fstream = fopen(filename, "rb");
+
+ if (fstream == NULL) {
+ return NULL;
+ }
+
+ result = lha_input_stream_new(&file_source_owned, fstream);
+
+ if (result == NULL) {
+ fclose(fstream);
+ }
+
+ return result;
+}
+
+LHAInputStream *lha_input_stream_from_FILE(FILE *stream)
+{
+ lha_arch_set_binary(stream);
+ return lha_input_stream_new(&file_source_unowned, stream);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h
new file mode 100644
index 00000000..645825c1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h
@@ -0,0 +1,51 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LHA_INPUT_STREAM_H
+#define LHASA_LHA_INPUT_STREAM_H
+
+#include <inttypes.h>
+#include "public/lha_input_stream.h"
+
+/**
+ * Read a block of data from the LHA stream, of the specified number
+ * of bytes.
+ *
+ * @param stream The input stream.
+ * @param buf Pointer to buffer in which to store read data.
+ * @param buf_len Size of buffer, in bytes.
+ * @return Non-zero if buffer was filled, or zero if an
+ * error occurred, or end of file was reached.
+ */
+
+int lha_input_stream_read(LHAInputStream *stream, void *buf, size_t buf_len);
+
+/**
+ * Skip over the specified number of bytes.
+ *
+ * @param stream The input stream.
+ * @param bytes Number of bytes to skip.
+ * @return Non-zero for success, zero for failure.
+ */
+
+int lha_input_stream_skip(LHAInputStream *stream, size_t bytes);
+
+#endif /* #ifndef LHASA_LHA_INPUT_STREAM_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c
new file mode 100644
index 00000000..267b68f5
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c
@@ -0,0 +1,886 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lha_arch.h"
+#include "lha_decoder.h"
+#include "lha_basic_reader.h"
+#include "public/lha_reader.h"
+#include "macbinary.h"
+
+typedef enum {
+
+ // Initial state at start of stream:
+
+ CURR_FILE_START,
+
+ // Current file is a "normal" file (or directory) read from
+ // the input stream.
+
+ CURR_FILE_NORMAL,
+
+ // Current file is a directory that has been popped from the
+ // directory stack.
+
+ CURR_FILE_FAKE_DIR,
+
+ // Current file is a deferred symbolic link that has been left
+ // to the end of the input stream to be created.
+
+ CURR_FILE_DEFERRED_SYMLINK,
+
+ // End of input stream has been reached.
+
+ CURR_FILE_EOF,
+} CurrFileType;
+
+struct _LHAReader {
+ LHABasicReader *reader;
+
+ // The current file that we are processing (last file returned
+ // by lha_reader_next_file).
+
+ LHAFileHeader *curr_file;
+ CurrFileType curr_file_type;
+
+ // Pointer to decoder being used to decompress the current file,
+ // or NULL if we have not yet started decompression.
+
+ LHADecoder *decoder;
+
+ // Pointer to "inner" decoder. Most of the time,
+ // decoder == inner_decoder, but when decoding an archive
+ // generated by MacLHA, inner_decoder points to the actual
+ // decompressor.
+
+ LHADecoder *inner_decoder;
+
+ // Policy used to extract directories.
+
+ LHAReaderDirPolicy dir_policy;
+
+ // Directories that have been created by lha_reader_extract but
+ // have not yet had their metadata set. This is a linked list
+ // using the _next field in LHAFileHeader.
+ // In the case of LHA_READER_DIR_END_OF_DIR this is a stack;
+ // in the case of LHA_READER_DIR_END_OF_FILE it is a list.
+
+ LHAFileHeader *dir_stack;
+
+ // Symbolic links containing absolute paths or '..' are not
+ // created immediately - instead, "placeholder" files are created
+ // in their place, and the symbolic links created at the end
+ // of extraction.
+
+ LHAFileHeader *deferred_symlinks;
+};
+
+/**
+ * Free the current decoder structure.
+ *
+ * If the reader has an allocated decoder being used to decompress the
+ * current file, the decoder is freed and the decoder pointer reset
+ * to NULL.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ */
+
+static void close_decoder(LHAReader *reader)
+{
+ if (reader->decoder != NULL) {
+ if (reader->inner_decoder == reader->decoder) {
+ reader->inner_decoder = NULL;
+ }
+
+ lha_decoder_free(reader->decoder);
+ reader->decoder = NULL;
+ }
+
+ if (reader->inner_decoder != NULL) {
+ lha_decoder_free(reader->inner_decoder);
+ reader->inner_decoder = NULL;
+ }
+}
+
+/**
+ * Create the decoder structure to decompress the data from the
+ * current file.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param callback Callback function to invoke to track progress.
+ * @param callback_data Extra pointer to pass to the callback function.
+ * @return Non-zero for success, zero for failure.
+ */
+
+static int open_decoder(LHAReader *reader,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ // Can only read from a normal file.
+
+ if (reader->curr_file_type != CURR_FILE_NORMAL) {
+ return 0;
+ }
+
+ reader->inner_decoder = lha_basic_reader_decode(reader->reader);
+
+ if (reader->inner_decoder == NULL) {
+ return 0;
+ }
+
+ // Set progress callback for decoder.
+
+ if (callback != NULL) {
+ lha_decoder_monitor(reader->inner_decoder,
+ callback, callback_data);
+ }
+
+ // Some archives generated by MacLHA have a MacBinary header
+ // attached to the start, which contains MacOS-specific
+ // metadata about the compressed file. These are identified
+ // and stripped off, using a "passthrough" decoder.
+
+ if (reader->curr_file->os_type == LHA_OS_TYPE_MACOS) {
+ reader->decoder = lha_macbinary_passthrough(
+ reader->inner_decoder, reader->curr_file);
+
+ if (reader->decoder == NULL) {
+ return 0;
+ }
+ } else {
+ reader->decoder = reader->inner_decoder;
+ }
+
+ return 1;
+}
+
+LHAReader *lha_reader_new(LHAInputStream *stream)
+{
+ LHABasicReader *basic_reader;
+ LHAReader *reader;
+
+ reader = calloc(1, sizeof(LHAReader));
+
+ if (reader == NULL) {
+ return NULL;
+ }
+
+ basic_reader = lha_basic_reader_new(stream);
+
+ if (basic_reader == NULL) {
+ free(reader);
+ return NULL;
+ }
+
+ reader->reader = basic_reader;
+ reader->curr_file = NULL;
+ reader->curr_file_type = CURR_FILE_START;
+ reader->decoder = NULL;
+ reader->inner_decoder = NULL;
+ reader->dir_stack = NULL;
+ reader->dir_policy = LHA_READER_DIR_END_OF_DIR;
+ reader->deferred_symlinks = NULL;
+
+ return reader;
+}
+
+void lha_reader_free(LHAReader *reader)
+{
+ LHAFileHeader *header;
+
+ // Shut down the current decoder, if there is one.
+
+ close_decoder(reader);
+
+ // Free any file headers in the stack.
+
+ while (reader->dir_stack != NULL) {
+ header = reader->dir_stack;
+ reader->dir_stack = header->_next;
+ lha_file_header_free(header);
+ }
+
+ lha_basic_reader_free(reader->reader);
+ free(reader);
+}
+
+void lha_reader_set_dir_policy(LHAReader *reader,
+ LHAReaderDirPolicy policy)
+{
+ reader->dir_policy = policy;
+}
+
+/**
+ * Check if the directory at the top of the stack should be popped.
+ *
+ * Extracting a directory is a two stage process; after the directory
+ * is created, it is pushed onto the directory stack. Later the
+ * directory must be popped off the stack and its metadata applied.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @return Non-zero if there is a directory at the top of
+ * the stack that should be popped.
+ */
+
+static int end_of_top_dir(LHAReader *reader)
+{
+ LHAFileHeader *input;
+
+ // No directories to pop?
+
+ if (reader->dir_stack == NULL) {
+ return 0;
+ }
+
+ // Once the end of the input stream is reached, all that is
+ // left to do is pop off the remaining directories.
+
+ input = lha_basic_reader_curr_file(reader->reader);
+
+ if (input == NULL) {
+ return 1;
+ }
+
+ switch (reader->dir_policy) {
+
+ // Shouldn't happen?
+
+ case LHA_READER_DIR_PLAIN:
+ default:
+ return 1;
+
+ // Don't process directories until we reach the end of
+ // the input stream.
+
+ case LHA_READER_DIR_END_OF_FILE:
+ return 0;
+
+ // Once we reach a file from the input that is not within
+ // the directory at the top of the stack, we have reached
+ // the end of that directory, so we can pop it off.
+
+ case LHA_READER_DIR_END_OF_DIR:
+ return input->path == NULL
+ || strncmp(input->path,
+ reader->dir_stack->path,
+ strlen(reader->dir_stack->path)) != 0;
+ }
+}
+
+// Read the next file from the input stream.
+
+LHAFileHeader *lha_reader_next_file(LHAReader *reader)
+{
+ // Free the current decoder if there is one.
+
+ close_decoder(reader);
+
+ // No point continuing once the end of the input stream has
+ // been reached.
+
+ if (reader->curr_file_type == CURR_FILE_EOF) {
+ return NULL;
+ }
+
+ // Advance to the next file from the input stream?
+ // Don't advance until we've done the fake directories first.
+
+ if (reader->curr_file_type == CURR_FILE_START
+ || reader->curr_file_type == CURR_FILE_NORMAL) {
+ lha_basic_reader_next_file(reader->reader);
+ }
+
+ // If the last file we returned was a 'fake' directory, we must
+ // now unreference it.
+
+ if (reader->curr_file_type == CURR_FILE_FAKE_DIR) {
+ lha_file_header_free(reader->curr_file);
+ }
+
+ // Pop off all appropriate directories from the stack first.
+
+ if (end_of_top_dir(reader)) {
+ reader->curr_file = reader->dir_stack;
+ reader->dir_stack = reader->dir_stack->_next;
+ reader->curr_file_type = CURR_FILE_FAKE_DIR;
+ } else {
+ reader->curr_file = lha_basic_reader_curr_file(reader->reader);
+ reader->curr_file_type = CURR_FILE_NORMAL;
+ }
+
+ // Once we reach the end of the file, there may be deferred
+ // symbolic links still to extract, so process those before
+ // giving up and declaring end of file.
+
+ if (reader->curr_file == NULL) {
+ if (reader->deferred_symlinks != NULL) {
+ reader->curr_file = reader->deferred_symlinks;
+ reader->curr_file_type = CURR_FILE_DEFERRED_SYMLINK;
+
+ reader->deferred_symlinks =
+ reader->deferred_symlinks->_next;
+ reader->curr_file->_next = NULL;
+ } else {
+ reader->curr_file_type = CURR_FILE_EOF;
+ }
+ }
+
+ return reader->curr_file;
+}
+
+size_t lha_reader_read(LHAReader *reader, void *buf, size_t buf_len)
+{
+ // The first time that we try to read the current file, we
+ // must create the decoder to decompress it.
+
+ if (reader->decoder == NULL) {
+ if (!open_decoder(reader, NULL, NULL)) {
+ return 0;
+ }
+ }
+
+ // Read from decoder and return the result.
+
+ return lha_decoder_read(reader->decoder, buf, buf_len);
+}
+
+/**
+ * Decompress the current file.
+ *
+ * Assumes that @param open_decoder has already been called to
+ * start the decode process.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param output FILE handle to write decompressed data, or NULL
+ * if the decompressed data should be discarded.
+ * @return Non-zero if the file decompressed successfully.
+ */
+
+static int do_decode(LHAReader *reader, FILE *output)
+{
+ uint8_t buf[64];
+ unsigned int bytes;
+
+ // Decompress the current file.
+
+ do {
+ bytes = lha_reader_read(reader, buf, sizeof(buf));
+
+ if (output != NULL) {
+ if (fwrite(buf, 1, bytes, output) < bytes) {
+ return 0;
+ }
+ }
+
+ } while (bytes > 0);
+
+ // Decoder stores output position and performs running CRC.
+ // At the end of the stream these should match the header values.
+
+ return lha_decoder_get_length(reader->inner_decoder)
+ == reader->curr_file->length
+ && lha_decoder_get_crc(reader->inner_decoder)
+ == reader->curr_file->crc;
+}
+
+int lha_reader_check(LHAReader *reader,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ if (reader->curr_file_type != CURR_FILE_NORMAL) {
+ return 0;
+ }
+
+ // CRC checking of directories is not necessary.
+
+ if (!strcmp(reader->curr_file->compress_method,
+ LHA_COMPRESS_TYPE_DIR)) {
+ return 1;
+ }
+
+ // Decode file.
+
+ return open_decoder(reader, callback, callback_data)
+ && do_decode(reader, NULL);
+}
+
+/**
+ * Open an output stream into which to decompress the current file.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param filename Name of the file to open.
+ * @return FILE handle of the opened file, or NULL in
+ * case of failure.
+ */
+
+static FILE *open_output_file(LHAReader *reader, char *filename)
+{
+ int unix_uid = -1, unix_gid = -1, unix_perms = -1;
+
+ if (LHA_FILE_HAVE_EXTRA(reader->curr_file, LHA_FILE_UNIX_UID_GID)) {
+ unix_uid = reader->curr_file->unix_uid;
+ unix_gid = reader->curr_file->unix_gid;
+ }
+
+ if (LHA_FILE_HAVE_EXTRA(reader->curr_file, LHA_FILE_UNIX_PERMS)) {
+ unix_perms = reader->curr_file->unix_perms;
+ }
+
+ return lha_arch_fopen(filename, unix_uid, unix_gid, unix_perms);
+}
+
+/**
+ * Set file timestamps for the specified file.
+ *
+ * If possible, the more accurate Windows timestamp values are used;
+ * otherwise normal Unix timestamps are used.
+ *
+ * @param path Path to the file or directory to set.
+ * @param header Pointer to file header structure containing the
+ * timestamps to set.
+ * @return Non-zero if the timestamps were set successfully,
+ * or zero for failure.
+ */
+
+static int set_timestamps_from_header(char *path, LHAFileHeader *header)
+{
+#if LHA_ARCH == LHA_ARCH_WINDOWS
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_WINDOWS_TIMESTAMPS)) {
+ return lha_arch_set_windows_timestamps(
+ path,
+ header->win_creation_time,
+ header->win_modification_time,
+ header->win_access_time
+ );
+ } else // ....
+#endif
+ if (header->timestamp != 0) {
+ return lha_arch_utime(path, header->timestamp);
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * Set directory metadata.
+ *
+ * This is the second stage of directory extraction. Metadata (timestamps
+ * and permissions) should be set on a dictory after the contents of
+ * the directory has been extracted.
+ *
+ * @param header Pointer to file header structure containing the
+ * metadata to set.
+ * @param path Path to the directory on which to set the metadata.
+ * @return Non-zero for success, or zero for failure.
+ */
+
+static int set_directory_metadata(LHAFileHeader *header, char *path)
+{
+ // Set timestamp:
+
+ set_timestamps_from_header(path, header);
+
+ // Set owner and group:
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_UID_GID)) {
+ if (!lha_arch_chown(path, header->unix_uid,
+ header->unix_gid)) {
+ // On most Unix systems, only root can change
+ // ownership. But if we can't change ownership,
+ // it isn't a fatal error. Ignore the failure
+ // and continue.
+
+ // TODO: Implement some kind of alternate handling
+ // here?
+ /* return 0; */
+ }
+ }
+
+ // Set permissions on directory:
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
+ if (!lha_arch_chmod(path, header->unix_perms)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * "Extract" (create) a directory.
+ *
+ * The current file is assumed to be a directory. This is the first
+ * stage in extracting a directory; after the directory is created,
+ * it is added to the directory stack so that the metadata apply stage
+ * runs later. (If the LHA_READER_DIR_PLAIN policy is used, metadata
+ * is just applied now).
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param path Path to the directory, or NULL to use the path from
+ * the file header.
+ * @return Non-zero for success, or zero for failure.
+ */
+
+static int extract_directory(LHAReader *reader, char *path)
+{
+ LHAFileHeader *header;
+ unsigned int mode;
+
+ header = reader->curr_file;
+
+ // If path is not specified, use the path from the file header.
+
+ if (path == NULL) {
+ path = header->path;
+ }
+
+ // Create directory. If there are permissions to be set, create
+ // the directory with minimal permissions limited to the running
+ // user. Otherwise use the default umask.
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
+ mode = 0700;
+ } else {
+ mode = 0777;
+ }
+
+ if (!lha_arch_mkdir(path, mode)) {
+
+ // If the attempt to create the directory failed, it may
+ // be because the directory already exists. Return success
+ // if this is the case; it isn't really an error.
+
+ return lha_arch_exists(path) == LHA_FILE_DIRECTORY;
+ }
+
+ // The directory has been created, but the metadata has not yet
+ // been applied. It depends on the directory policy how this
+ // is handled. If we are using LHA_READER_DIR_PLAIN, set
+ // metadata now. Otherwise, save the directory for later.
+
+ if (reader->dir_policy == LHA_READER_DIR_PLAIN) {
+ set_directory_metadata(header, path);
+ } else {
+ lha_file_header_add_ref(header);
+ header->_next = reader->dir_stack;
+ reader->dir_stack = header;
+ }
+
+ return 1;
+}
+
+/**
+ * Extract the current file.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param filename Filename into which to extract the file, or NULL
+ * to use the filename from the file header.
+ * @param callback Callback function to invoke to track progress.
+ * @param callback_data Extra pointer to pass to the callback function.
+ * @return Non-zero if the file was successfully extracted,
+ * or zero for failure.
+ */
+
+static int extract_file(LHAReader *reader, char *filename,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ FILE *fstream;
+ char *tmp_filename = NULL;
+ int result;
+
+ // Construct filename?
+
+ if (filename == NULL) {
+ tmp_filename = lha_file_header_full_path(reader->curr_file);
+
+ if (tmp_filename == NULL) {
+ return 0;
+ }
+
+ filename = tmp_filename;
+ }
+
+ // Create decoder. If the file cannot be created, there is no
+ // need to even create an output file. If successful, open the
+ // output file and decode.
+
+ result = 0;
+
+ if (open_decoder(reader, callback, callback_data)) {
+
+ fstream = open_output_file(reader, filename);
+
+ if (fstream != NULL) {
+ result = do_decode(reader, fstream);
+ fclose(fstream);
+ }
+ }
+
+ // Set timestamp on file:
+
+ if (result) {
+ set_timestamps_from_header(filename, reader->curr_file);
+ }
+
+ free(tmp_filename);
+
+ return result;
+}
+
+/**
+ * Determine whether a header contains a "dangerous" symbolic link.
+ *
+ * Symbolic links that begin with '/' or contain '..' as a path are
+ * Potentially dangerous and could potentially be used to overwrite
+ * arbitrary files on the filesystem. They therefore need to be
+ * treated specially.
+ *
+ * @param header Pointer to a header structure defining a symbolic
+ * link.
+ * @return Non-zero if the symbolic link is potentially
+ * dangerous.
+ */
+
+static int is_dangerous_symlink(LHAFileHeader *header)
+{
+ char *path_start;
+ char *p;
+
+ if (header->symlink_target == NULL) {
+ return 0;
+ }
+
+ // Absolute path symlinks could be used to point to arbitrary
+ // filesystem locations.
+
+ if (header->symlink_target[0] == '/') {
+ return 1;
+ }
+
+ // Check for paths containing '..'.
+
+ path_start = header->symlink_target;
+
+ for (p = header->symlink_target; *p != '\0'; ++p) {
+ if (*p == '/') {
+ if ((p - path_start) == 2
+ && path_start[0] == '.' && path_start[1] == '.') {
+ return 1;
+ }
+
+ path_start = p + 1;
+ }
+ }
+
+ // The path might also end with '..' (no terminating /)
+
+ if ((p - path_start) == 2
+ && path_start[0] == '.' && path_start[1] == '.') {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Get the length of a path defined by a file header.
+ *
+ * @param header The file header structure.
+ * @return Length of the header in bytes.
+ */
+
+static size_t file_header_path_len(LHAFileHeader *header)
+{
+ size_t result;
+
+ result = 0;
+
+ if (header->path != NULL) {
+ result += strlen(header->path);
+ }
+ if (header->filename != NULL) {
+ result += strlen(header->filename);
+ }
+
+ return result;
+}
+
+/**
+ * Create a "placeholder" symbolic link.
+ *
+ * When a "dangerous" symbolic link is extracted, instead of creating it
+ * immediately, create a "placeholder" empty file to go in its place, and
+ * place it into the deferred_symlinks list to be created later.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param filename Filename into which to extract the symlink.
+ * @return Non-zero if the symlink was extracted successfully,
+ * or zero for failure.
+ */
+
+static int extract_placeholder_symlink(LHAReader *reader, char *filename)
+{
+ LHAFileHeader **rover;
+ FILE *f;
+
+ f = lha_arch_fopen(filename, -1, -1, 0600);
+
+ if (f == NULL) {
+ return 0;
+ }
+
+ fclose(f);
+
+ // Insert this header into the list of deferred symbolic links.
+ // The list must be maintained in order of decreasing path length,
+ // so that one symbolic link cannot depend on another. For example:
+ //
+ // etc -> /etc
+ // etc/passwd -> /malicious_path/passwd
+
+ rover = &reader->deferred_symlinks;
+
+ while (*rover != NULL
+ && file_header_path_len(*rover)
+ > file_header_path_len(reader->curr_file)) {
+ rover = &(*rover)->_next;
+ }
+
+ reader->curr_file->_next = *rover;
+ *rover = reader->curr_file;
+
+ // Save reference to the header so it won't be freed.
+
+ lha_file_header_add_ref(reader->curr_file);
+
+ return 1;
+}
+
+/**
+ * Extract a Unix symbolic link.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param filename Filename into which to extract the symlink, or NULL
+ * to use the filename from the file header.
+ * @return Non-zero if the symlink was extracted successfully,
+ * or zero for failure.
+ */
+
+static int extract_symlink(LHAReader *reader, char *filename)
+{
+ char *tmp_filename = NULL;
+ int result;
+
+ // Construct filename?
+
+ if (filename == NULL) {
+ tmp_filename = lha_file_header_full_path(reader->curr_file);
+
+ if (tmp_filename == NULL) {
+ return 0;
+ }
+
+ filename = tmp_filename;
+ }
+
+ if (reader->curr_file_type == CURR_FILE_NORMAL
+ && is_dangerous_symlink(reader->curr_file)) {
+ return extract_placeholder_symlink(reader, filename);
+ }
+
+ result = lha_arch_symlink(filename, reader->curr_file->symlink_target);
+
+ // TODO: Set symlink timestamp.
+
+ free(tmp_filename);
+
+ return result;
+}
+
+/**
+ * Extract a "normal" file.
+ *
+ * This just extracts the file header most recently read by the
+ * BasicReader.
+ *
+ * @param reader Pointer to the LHA reader structure.
+ * @param filename Filename into which to extract the file, or NULL
+ * to use the filename from the file header.
+ * @param callback Callback function to invoke to track progress.
+ * @param callback_data Extra pointer to pass to the callback function.
+ * @return Non-zero if the file was successfully extracted,
+ * or zero for failure.
+ */
+
+static int extract_normal(LHAReader *reader,
+ char *filename,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ if (strcmp(reader->curr_file->compress_method,
+ LHA_COMPRESS_TYPE_DIR) != 0) {
+ return extract_file(reader, filename, callback, callback_data);
+ } else if (reader->curr_file->symlink_target != NULL) {
+ return extract_symlink(reader, filename);
+ } else {
+ return extract_directory(reader, filename);
+ }
+}
+
+int lha_reader_extract(LHAReader *reader,
+ char *filename,
+ LHADecoderProgressCallback callback,
+ void *callback_data)
+{
+ switch (reader->curr_file_type) {
+
+ case CURR_FILE_NORMAL:
+ return extract_normal(reader, filename, callback,
+ callback_data);
+
+ case CURR_FILE_FAKE_DIR:
+ if (filename == NULL) {
+ filename = reader->curr_file->path;
+ }
+ set_directory_metadata(reader->curr_file, filename);
+ return 1;
+
+ case CURR_FILE_DEFERRED_SYMLINK:
+ return extract_symlink(reader, filename);
+
+ case CURR_FILE_START:
+ case CURR_FILE_EOF:
+ break;
+ }
+
+ return 0;
+}
+
+int lha_reader_current_is_fake(LHAReader *reader)
+{
+ return reader->curr_file_type == CURR_FILE_FAKE_DIR
+ || reader->curr_file_type == CURR_FILE_DEFERRED_SYMLINK;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c
new file mode 100644
index 00000000..1bbf6c54
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c
@@ -0,0 +1,45 @@
+/*
+
+Copyright (c) 2011, 2012, 2013, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Decoder for the -lhx- algorithm. Provided by Multi.
+//
+// -lhx- is Unlha32.dll's original extension. Some unique archivers
+// support it.
+//
+
+// 128 KiB history ring buffer:
+// -lhx-'s maximum dictionary size is 2^19. 2x ring buffer is required.
+
+#define HISTORY_BITS 20 /* 2^20 = 1048576. */
+
+// Number of bits to encode HISTORY_BITS:
+
+#define OFFSET_BITS 5
+
+// Name of the variable for the encoder:
+
+#define DECODER_NAME lha_lhx_decoder
+
+// The actual algorithm code is contained in lh_new_decoder.c, which
+// acts as a template for -lh4-, -lh5-, -lh6-, -lh7- and -lhx-.
+
+#include "lh_new_decoder.c"
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c
new file mode 100644
index 00000000..bddcdc1b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c
@@ -0,0 +1,198 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+// Parameters for ring buffer, used for storing history. This acts
+// as the dictionary for copy operations.
+
+#define RING_BUFFER_SIZE 4096
+#define START_OFFSET 18
+
+// Threshold offset. In the copy operation, the copy length is a 4-bit
+// value, giving a range 0..15. The threshold offsets this so that it
+// is interpreted as 3..18 - a more useful range.
+
+#define THRESHOLD 3
+
+// Size of output buffer. Must be large enough to hold the results of
+// a complete "run" (see below).
+
+#define OUTPUT_BUFFER_SIZE (15 + THRESHOLD) * 8
+
+// Decoder for the -lz5- compression method used by LArc.
+//
+// This processes "runs" of eight commands, each of which is either
+// "output a character" or "copy block". The result of that run
+// is written into the output buffer.
+
+typedef struct {
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+ LHADecoderCallback callback;
+ void *callback_data;
+} LHALZ5Decoder;
+
+static void fill_initial(LHALZ5Decoder *decoder)
+{
+ unsigned int i, j;
+ uint8_t *p;
+
+ p = decoder->ringbuf;
+
+ // For each byte value, the history buffer includes a run of 13
+ // bytes all with that value. This is useful eg. for text files
+ // that include a long run like this (eg. ===========).
+ for (i = 0; i < 256; ++i) {
+ for (j = 0; j < 13; ++j) {
+ *p++ = (uint8_t) i;
+ }
+ }
+
+ // Next we include all byte values ascending and descending.
+ for (i = 0; i < 256; ++i) {
+ *p++ = (uint8_t) i;
+ }
+ for (i = 0; i < 256; ++i) {
+ *p++ = (uint8_t) (255 - i);
+ }
+
+ // Block of zeros, and then ASCII space characters. I think these are
+ // towards the end of the range because they're most likely to be
+ // useful and therefore last to get overwritten?
+ for (i = 0; i < 128; ++i) {
+ *p++ = 0;
+ }
+ for (i = 0; i < 110; ++i) {
+ *p++ = ' ';
+ }
+
+ // Final 18 characters are all zeros, probably because of START_OFFSET.
+ for (i = 0; i < 18; ++i) {
+ *p++ = 0;
+ }
+}
+
+static int lha_lz5_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHALZ5Decoder *decoder = data;
+
+ fill_initial(decoder);
+ decoder->ringbuf_pos = RING_BUFFER_SIZE - START_OFFSET;
+ decoder->callback = callback;
+ decoder->callback_data = callback_data;
+
+ return 1;
+}
+
+// Add a single byte to the output buffer.
+
+static void output_byte(LHALZ5Decoder *decoder, uint8_t *buf,
+ size_t *buf_len, uint8_t b)
+{
+ buf[*buf_len] = b;
+ ++*buf_len;
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+}
+
+// Output a "block" of data from the specified range in the ring buffer.
+
+static void output_block(LHALZ5Decoder *decoder,
+ uint8_t *buf,
+ size_t *buf_len,
+ unsigned int start,
+ unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ output_byte(decoder, buf, buf_len,
+ decoder->ringbuf[(start + i) % RING_BUFFER_SIZE]);
+ }
+}
+
+// Process a "run" of LZ5-compressed data (a control byte followed by
+// eight "commands").
+
+static size_t lha_lz5_read(void *data, uint8_t *buf)
+{
+ LHALZ5Decoder *decoder = data;
+ uint8_t bitmap;
+ unsigned int bit;
+ size_t result;
+
+ // Start from an empty buffer.
+
+ result = 0;
+
+ // Read the bitmap byte first.
+
+ if (!decoder->callback(&bitmap, 1, decoder->callback_data)) {
+ return 0;
+ }
+
+ // Each bit in the bitmap is a command.
+ // If the bit is set, it is an "output byte" command.
+ // If it is not set, it is a "copy block" command.
+
+ for (bit = 0; bit < 8; ++bit) {
+ if ((bitmap & (1 << bit)) != 0) {
+ uint8_t b;
+
+ if (!decoder->callback(&b, 1, decoder->callback_data)) {
+ break;
+ }
+
+ output_byte(decoder, buf, &result, b);
+ } else {
+ uint8_t cmd[2];
+ unsigned int seqstart, seqlen;
+
+ if (!decoder->callback(cmd, 2, decoder->callback_data)) {
+ break;
+ }
+
+ seqstart = (((unsigned int) cmd[1] & 0xf0) << 4)
+ | cmd[0];
+ seqlen = ((unsigned int) cmd[1] & 0x0f) + THRESHOLD;
+
+ output_block(decoder, buf, &result, seqstart, seqlen);
+ }
+ }
+
+ return result;
+}
+
+LHADecoderType lha_lz5_decoder = {
+ lha_lz5_init,
+ NULL,
+ lha_lz5_read,
+ sizeof(LHALZ5Decoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE
+};
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c
new file mode 100644
index 00000000..87efc929
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c
@@ -0,0 +1,156 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+#include "bit_stream_reader.c"
+
+// Parameters for ring buffer, used for storing history. This acts
+// as the dictionary for copy operations.
+
+#define RING_BUFFER_SIZE 2048
+#define START_OFFSET 17
+
+// Threshold offset. In the copy operation, the copy length is a 4-bit
+// value, giving a range 0..15. The threshold offsets this so that it
+// is interpreted as 2..17 - a more useful range.
+
+#define THRESHOLD 2
+
+// Size of output buffer. Must be large enough to hold the results of
+// the maximum copy operation.
+
+#define OUTPUT_BUFFER_SIZE (15 + THRESHOLD)
+
+// Decoder for the -lzs- compression method used by old versions of LArc.
+//
+// The input stream consists of commands, each of which is either "output
+// a literal byte value" or "copy block". A bit at the start of each
+// command signals which command it is.
+
+typedef struct {
+ BitStreamReader bit_stream_reader;
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+} LHALZSDecoder;
+
+static int lha_lzs_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHALZSDecoder *decoder = data;
+
+ memset(decoder->ringbuf, ' ', RING_BUFFER_SIZE);
+ decoder->ringbuf_pos = RING_BUFFER_SIZE - START_OFFSET;
+ bit_stream_reader_init(&decoder->bit_stream_reader, callback,
+ callback_data);
+
+ return 1;
+}
+
+// Add a single byte to the output buffer.
+
+static void output_byte(LHALZSDecoder *decoder, uint8_t *buf,
+ size_t *buf_len, uint8_t b)
+{
+ buf[*buf_len] = b;
+ ++*buf_len;
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+}
+
+// Output a "block" of data from the specified range in the ring buffer.
+
+static void output_block(LHALZSDecoder *decoder,
+ uint8_t *buf,
+ size_t *buf_len,
+ unsigned int start,
+ unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; ++i) {
+ output_byte(decoder, buf, buf_len,
+ decoder->ringbuf[(start + i) % RING_BUFFER_SIZE]);
+ }
+}
+
+// Process a single command from the LZS input stream.
+
+static size_t lha_lzs_read(void *data, uint8_t *buf)
+{
+ LHALZSDecoder *decoder = data;
+ int bit;
+ size_t result;
+
+ // Start from an empty buffer.
+
+ result = 0;
+
+ // Each command starts with a bit that signals the type:
+
+ bit = read_bit(&decoder->bit_stream_reader);
+
+ if (bit < 0) {
+ return 0;
+ }
+
+ // What type of command is this?
+
+ if (bit) {
+ int b;
+
+ b = read_bits(&decoder->bit_stream_reader, 8);
+
+ if (b < 0) {
+ return 0;
+ }
+
+ output_byte(decoder, buf, &result, (uint8_t) b);
+ } else {
+ int pos, len;
+
+ pos = read_bits(&decoder->bit_stream_reader, 11);
+ len = read_bits(&decoder->bit_stream_reader, 4);
+
+ if (pos < 0 || len < 0) {
+ return 0;
+ }
+
+ output_block(decoder, buf, &result, (unsigned int) pos,
+ (unsigned int) len + THRESHOLD);
+ }
+
+ return result;
+}
+
+LHADecoderType lha_lzs_decoder = {
+ lha_lzs_init,
+ NULL,
+ lha_lzs_read,
+ sizeof(LHALZSDecoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE
+};
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c
new file mode 100644
index 00000000..be2ba532
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c
@@ -0,0 +1,451 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+// Code for handling MacBinary headers.
+//
+// Classic Mac OS attaches more metadata to files than other operating
+// systems. For example, each file has a file type that is used to
+// determine the application to open it with. Files can also have both
+// a data fork and a resource fork. Because of this design, when
+// transferring a file between computers (eg. over a network), all of
+// the data associated with the file must be bundled up together to
+// preserve the file.
+//
+// MacLHA uses the MacBinary container format to do this. Within the
+// compressed data, the file contents are preceded by a 128 byte
+// header that contains the metadata. The data from the data fork can
+// also be followed by the data from the resource fork.
+//
+// Because this is incompatible with .lzh archives from other operating
+// systems, MacLHA has two menu items to create new archives - one
+// creates a "Mac" archive, while the other creates a "non-Mac"
+// (standard) archive that contains just the file contents. This quote
+// from the documentation (MacLHAE.doc) describes what is stored when
+// the latter option is used:
+//
+// > If a file has only either Data Fork or Resource Fork, it's stored
+// > into archives. In case a file has both Data Fork and Resource Fork,
+// > only the Data Fork is stored.
+//
+// --
+//
+// Mac OS X has essentially abandoned this practise of using filesystem
+// metadata and other systems do not use it, either. It is therefore
+// sensible and desirable to strip off the MacBinary header (if present)
+// and extract just the normal file contents. It makes sense to use the
+// same strategy quoted above.
+//
+// The possible presence of a MacBinary header can be inferred using the
+// OS type field from the LHA header - a value of 'm' indicates that it
+// was generated by MacLHA. However, there are some issues with this:
+//
+// 1. This type is set regardless of whether a MacBinary header is
+// attached or not. There is no other field to indicate the
+// difference, and MacBinary headers do not have a magic number, so
+// the presence of one must be determined heuristically.
+// Realistically, though, this can be done without too much
+// difficulty, by strictly checking all the fields in the MacBinary
+// header. If an invalid header is seen, it can be rejected and
+// assumed to be a normal file.
+//
+// 2. MacBinary is a standard container format for transferring files
+// between Macs and not used just by MacLHA. Therefore, it is
+// plausible that a .lzh archive might "deliberately" contain a
+// MacBinary file, in which case it would be a mistake to strip
+// off the header.
+//
+// This is an unlikely but still a plausible scenario. It can be
+// mitigated by comparing the MacBinary header values against the
+// values from the .lzh header. A header added by MacLHA will have
+// a filename that matches the .lzh header's filename (MacBinary
+// files usually have a .bin extension appended, so the filenames
+// would not match. Also, the modification timestamp should match
+// the timestamp from the .lzh header.
+//
+// 3. Comparing the MacBinary header modification timestamp with the
+// .lzh header modification timestamp is complicated by the fact
+// that the former is stored as a Macintosh 1904-based timestamp
+// in the local timezone, while the latter is stored as a Unix
+// timestamp in UTC time. Although converting timestamp formats
+// is trivial, the two do not compare exactly due to the timezone
+// offset.
+//
+// --
+//
+// Summary of MacBinary header fields and policy for each
+// (Z = check zero, C = check value, I = ignore):
+//
+// 0x00 - Z - "Old version number", must be zero for compatibility
+// 0x01 - C - Filename length, must match .lzh header filename.
+// 0x02-0x40 - C - Filename, must match .lzh header filename.
+// Z - Remainder following filename contents must be zero
+// 0x41-0x44 - I - File type
+// 0x45-0x48 - I - File creator
+// 0x49 - I - Finder flags
+// 0x4a - Z - "Must be zero for compatibility"
+// 0x4b-0x4c - I - Icon vertical position
+// 0x4d-0x4e - I - Icon horizonal position
+// 0x4f-0x50 - I - Window ID
+// 0x51 - I - "Protected" flag
+// 0x52 - Z - "Must be zero for compatibility"
+// 0x53-0x56 - C - Data fork length }- added together, equal uncompressed
+// 0x57-0x5a - C - Resource fork length }- data length rounded up to 256
+// 0x5b-0x5e - I - File creation date
+// 0x5f-0x62 - C - File modification date - should match .lzh header
+// 0x63-0x64 - Z - Finder "Get Info" comment length - unused by MacLHA
+// 0x65-0x7f - Z - MacBinary II data - unused by MacLHA
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lha_decoder.h"
+#include "lha_endian.h"
+#include "lha_file_header.h"
+
+#define OUTPUT_BUFFER_SIZE 4096 /* bytes */
+
+// Classic Mac OS represents time in seconds since 1904, instead of
+// Unix time's 1970 epoch. This is the difference between the two.
+
+#define MAC_TIME_OFFSET 2082844800 /* seconds */
+
+// Size of the MacBinary header.
+
+#define MBHDR_SIZE 128 /* bytes */
+
+// Offsets of fields in MacBinary header (and their sizes):
+
+#define MBHDR_OFF_VERSION 0x00
+#define MBHDR_OFF_FILENAME_LEN 0x01
+#define MBHDR_OFF_FILENAME 0x02
+#define MBHDR_LEN_FILENAME 63
+#define MBHDR_OFF_ZERO_COMPAT1 0x4a
+#define MBHDR_OFF_ZERO_COMPAT2 0x52
+#define MBHDR_OFF_DATA_FORK_LEN 0x53
+#define MBHDR_OFF_RES_FORK_LEN 0x57
+#define MBHDR_OFF_FILE_MOD_DATE 0x5f
+#define MBHDR_OFF_COMMENT_LEN 0x63
+#define MBHDR_OFF_MACBINARY2_DATA 0x65
+#define MBHDR_LEN_MACBINARY2_DATA (MBHDR_SIZE - MBHDR_OFF_MACBINARY2_DATA)
+
+// Check that the given block of data contains only zero bytes.
+
+static int block_is_zero(uint8_t *data, size_t data_len)
+{
+ unsigned int i;
+
+ for (i = 0; i < data_len; ++i) {
+ if (data[i] != 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// Check that the specified modification time matches the modification
+// time from the file header.
+
+static int check_modification_time(unsigned int mod_time,
+ LHAFileHeader *header)
+{
+ unsigned int time_diff;
+
+ // In an ideal world, mod_time should match header->timestamp
+ // exactly. However, there's an additional complication
+ // because mod_time is local time, not UTC time, so there is
+ // a timezone difference.
+
+ if (header->timestamp > mod_time) {
+ time_diff = header->timestamp - mod_time;
+ } else {
+ time_diff = mod_time - header->timestamp;
+ }
+
+ // The maximum UTC timezone difference is UTC+14, used in
+ // New Zealand and some other islands in the Pacific.
+
+ if (time_diff > 14 * 60 * 60) {
+ return 0;
+ }
+
+ // If the world was simpler, all time zones would be exact
+ // hour offsets, but in fact, some regions use half or
+ // quarter hour offsets. So the difference should be a
+ // multiple of 15 minutes. Actually, the control panel in
+ // Mac OS allows any minute offset to be configured, but if
+ // people are crazy enough to do that, they deserve the
+ // brokenness they get as a result. It's preferable to use
+ // a 15 minute check rather than a 1 minute check, because
+ // this allows MacLHA-added MacBinary headers to be
+ // distinguished from archived MacBinary files more reliably.
+
+ //return (time_diff % (15 * 60)) == 0;
+
+ // It turns out the assumption above doesn't hold, and MacLHA
+ // does generate archives where the timestamps don't always
+ // exactly match. Oh well.
+
+ return 1;
+}
+
+// Given the specified data buffer, check whether it has a MacBinary
+// header with contents that match the specified .lzh header.
+
+static int is_macbinary_header(uint8_t *data, LHAFileHeader *header)
+{
+ unsigned int filename_len;
+ unsigned int data_fork_len, res_fork_len, expected_len;
+ unsigned int mod_time;
+
+ // Check fields in the header that should be zero.
+
+ if (data[MBHDR_OFF_VERSION] != 0
+ || data[MBHDR_OFF_ZERO_COMPAT1] != 0
+ || data[MBHDR_OFF_ZERO_COMPAT2] != 0
+ || !block_is_zero(&data[MBHDR_OFF_COMMENT_LEN], 2)
+ || !block_is_zero(&data[MBHDR_OFF_MACBINARY2_DATA],
+ MBHDR_LEN_MACBINARY2_DATA)) {
+ return 0;
+ }
+
+ // Check that the filename matches the filename from the
+ // lzh header.
+
+ filename_len = data[MBHDR_OFF_FILENAME_LEN];
+
+ if (filename_len > MBHDR_LEN_FILENAME
+ || filename_len != strlen(header->filename)
+ || memcmp(&data[MBHDR_OFF_FILENAME],
+ header->filename, filename_len) != 0) {
+ return 0;
+ }
+
+ // Data following the filename must be zero as well.
+
+ if (!block_is_zero(data + MBHDR_OFF_FILENAME + filename_len,
+ MBHDR_LEN_FILENAME - filename_len)) {
+ return 0;
+ }
+
+ // Decode data fork / resource fork lengths. Their combined
+ // lengths, plus the MacBinary header, should match the
+ // compressed data length (rounded up to the nearest 128).
+
+ data_fork_len = lha_decode_be_uint32(&data[MBHDR_OFF_DATA_FORK_LEN]);
+ res_fork_len = lha_decode_be_uint32(&data[MBHDR_OFF_RES_FORK_LEN]);
+
+ expected_len = (data_fork_len + res_fork_len + MBHDR_SIZE);
+
+ if (header->length != ((expected_len + 0x7f) & ~0x7f)) {
+ return 0;
+ }
+
+ // Check modification time.
+
+ mod_time = lha_decode_be_uint32(&data[MBHDR_OFF_FILE_MOD_DATE]);
+
+ if (mod_time < MAC_TIME_OFFSET
+ || !check_modification_time(mod_time - MAC_TIME_OFFSET, header)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+//
+// MacBinary "decoder". This reuses the LHADecoder framework to provide
+// a "pass-through" decoder that detects and strips the MacBinary header.
+//
+
+typedef struct {
+
+ // When the decoder is initialized, the first 128 bytes of
+ // data are read into this buffer and analysed. If it is
+ // not a MacBinary header, the data must be kept so that it
+ // can be returned in the first call to .read().
+ // mb_header_bytes contains the number of bytes still to read.
+
+ uint8_t mb_header[MBHDR_SIZE];
+ size_t mb_header_bytes;
+
+ // The "inner" decoder used to read the compressed data.
+
+ LHADecoder *decoder;
+
+ // Number of bytes still to read before decode should be
+ // terminated.
+
+ size_t stream_remaining;
+} MacBinaryDecoder;
+
+// Structure used when initializing a MacBinaryDecoder.
+
+typedef struct {
+ LHADecoder *decoder;
+ LHAFileHeader *header;
+} MacBinaryDecoderClosure;
+
+static int read_macbinary_header(MacBinaryDecoder *decoder,
+ LHAFileHeader *header)
+{
+ unsigned int data_fork_len, res_fork_len;
+ size_t n, bytes;
+
+ bytes = 0;
+
+ while (bytes < MBHDR_SIZE) {
+ n = lha_decoder_read(decoder->decoder,
+ decoder->mb_header + bytes,
+ MBHDR_SIZE - bytes);
+
+ // Unexpected EOF?
+
+ if (n == 0) {
+ return 0;
+ }
+
+ bytes += n;
+ }
+
+ // Check if the data that was read corresponds to a MacBinary
+ // header that matches the .lzh header. If not, just decode it
+ // as a normal stream.
+
+ if (!is_macbinary_header(decoder->mb_header, header)) {
+ decoder->mb_header_bytes = bytes;
+ return 1;
+ }
+
+ // We have a MacBinary header, so skip over it. Decide how
+ // long the data stream is (see policy in comment at start
+ // of file).
+
+ decoder->mb_header_bytes = 0;
+
+ data_fork_len = lha_decode_be_uint32(
+ &decoder->mb_header[MBHDR_OFF_DATA_FORK_LEN]);
+ res_fork_len = lha_decode_be_uint32(
+ &decoder->mb_header[MBHDR_OFF_RES_FORK_LEN]);
+
+ if (data_fork_len > 0) {
+ decoder->stream_remaining = data_fork_len;
+ } else {
+ decoder->stream_remaining = res_fork_len;
+ }
+
+ return 1;
+}
+
+static int macbinary_decoder_init(void *_decoder,
+ LHADecoderCallback callback,
+ void *_closure)
+{
+ MacBinaryDecoder *decoder = _decoder;
+ MacBinaryDecoderClosure *closure = _closure;
+
+ decoder->decoder = closure->decoder;
+ decoder->mb_header_bytes = 0;
+ decoder->stream_remaining = closure->header->length;
+
+ if (closure->header->length >= MBHDR_SIZE
+ && !read_macbinary_header(decoder, closure->header)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+static void decode_to_end(LHADecoder *decoder)
+{
+ uint8_t buf[128];
+ size_t n;
+
+ do {
+ n = lha_decoder_read(decoder, buf, sizeof(buf));
+ } while (n > 0);
+}
+
+static size_t macbinary_decoder_read(void *_decoder, uint8_t *buf)
+{
+ MacBinaryDecoder *decoder = _decoder;
+ size_t result;
+ size_t to_read;
+ size_t n;
+
+ result = 0;
+
+ // If there is data from the mb_header buffer waiting to be
+ // read, add it first.
+
+ if (decoder->mb_header_bytes > 0) {
+ memcpy(buf, decoder->mb_header, decoder->mb_header_bytes);
+ result = decoder->mb_header_bytes;
+ decoder->mb_header_bytes = 0;
+ }
+
+ // Read further data, if there is some in the stream still to read.
+
+ to_read = OUTPUT_BUFFER_SIZE - result;
+
+ if (to_read > decoder->stream_remaining) {
+ to_read = decoder->stream_remaining;
+ }
+
+ n = lha_decoder_read(decoder->decoder, buf + result, to_read);
+
+ decoder->stream_remaining -= n;
+ result += n;
+
+ // Once the end of the stream is reached, there may still be
+ // data from the inner decoder to decompress. When this happens,
+ // run the decoder until the end.
+
+ if (decoder->stream_remaining == 0) {
+ decode_to_end(decoder->decoder);
+ }
+
+ return result;
+}
+
+static LHADecoderType macbinary_decoder_type = {
+ macbinary_decoder_init,
+ NULL,
+ macbinary_decoder_read,
+ sizeof(MacBinaryDecoder),
+ OUTPUT_BUFFER_SIZE,
+ 0,
+};
+
+LHADecoder *lha_macbinary_passthrough(LHADecoder *decoder,
+ LHAFileHeader *header)
+{
+ MacBinaryDecoderClosure closure;
+ LHADecoder *result;
+
+ closure.decoder = decoder;
+ closure.header = header;
+
+ result = lha_decoder_new(&macbinary_decoder_type, NULL,
+ &closure, header->length);
+
+ return result;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h
new file mode 100644
index 00000000..09fd11a2
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h
@@ -0,0 +1,49 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_MACBINARY_H
+#define LHASA_MACBINARY_H
+
+#include "lha_decoder.h"
+#include "lha_file_header.h"
+
+/**
+ * Create a passthrough decoder to handle MacBinary headers added
+ * by MacLHA.
+ *
+ * The new decoder reads from the specified decoder and filters
+ * out the header. The contents of the MacBinary header must match
+ * the details from the specified file header.
+ *
+ * @param decoder The "inner" decoder from which to read data.
+ * @param header The file header, that the contents of the
+ * MacBinary header must match.
+ * @return A new decoder, which passes through the
+ * contents of the inner decoder, stripping
+ * off the MacBinary header and truncating
+ * as appropriate. Both decoders must be freed
+ * by the caller.
+ */
+
+LHADecoder *lha_macbinary_passthrough(LHADecoder *decoder,
+ LHAFileHeader *header);
+
+#endif /* #ifndef LHASA_MACBINARY_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c
new file mode 100644
index 00000000..170a2206
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c
@@ -0,0 +1,61 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+// Null decoder, for uncompressed files.
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+#define BLOCK_READ_SIZE 1024
+
+typedef struct {
+ LHADecoderCallback callback;
+ void *callback_data;
+} LHANullDecoder;
+
+static int lha_null_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHANullDecoder *decoder = data;
+
+ decoder->callback = callback;
+ decoder->callback_data = callback_data;
+
+ return 1;
+}
+
+static size_t lha_null_read(void *data, uint8_t *buf)
+{
+ LHANullDecoder *decoder = data;
+
+ return decoder->callback(buf, BLOCK_READ_SIZE, decoder->callback_data);
+}
+
+LHADecoderType lha_null_decoder = {
+ lha_null_init,
+ NULL,
+ lha_null_read,
+ sizeof(LHANullDecoder),
+ BLOCK_READ_SIZE,
+ 2048
+};
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c
new file mode 100644
index 00000000..9fc16037
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c
@@ -0,0 +1,714 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+// Decoder for -pm1- compressed files.
+//
+// This was difficult to put together. I can't find any versions of
+// PMarc that will generate -pm1- encoded files (only -pm2-); however,
+// the extraction tool, PMext, will extract them. I have therefore been
+// able to reverse engineer the format and write a decoder. I am
+// indebted to Alwin Henseler for publishing the Z80 assembly source to
+// his UNPMA10 tool, which was apparently decompiled from the original
+// PMarc and includes the -pm1- decoding code.
+
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+#include "bit_stream_reader.c"
+#include "pma_common.c"
+
+// Size of the ring buffer used to hold the history.
+
+#define RING_BUFFER_SIZE 16384
+
+// Maximum length of a command representing a block of bytes:
+
+#define MAX_BYTE_BLOCK_LEN 216
+
+// Maximum number of bytes that can be copied by a single copy command.
+
+#define MAX_COPY_BLOCK_LEN 244
+
+// Output buffer length. A single call to lha_pm1_read can perform one
+// byte block output followed by a copy command.
+
+#define OUTPUT_BUFFER_SIZE (MAX_BYTE_BLOCK_LEN + MAX_COPY_BLOCK_LEN)
+
+typedef struct {
+ BitStreamReader bit_stream_reader;
+
+ // Position in output stream, in bytes.
+
+ unsigned int output_stream_pos;
+
+ // Pointer to the entry in byte_decode_table used to decode
+ // byte value indices.
+
+ const uint8_t *byte_decode_tree;
+
+ // History ring buffer.
+
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+
+ // History linked list, for adaptively encoding byte values.
+
+ HistoryLinkedList history_list;
+
+ // Callback to read more compressed data from the input (see
+ // read_callback_wrapper below).
+
+ LHADecoderCallback callback;
+ void *callback_data;
+} LHAPM1Decoder;
+
+// Table used to decode distance into history buffer to copy data.
+
+static const VariableLengthTable copy_ranges[] = {
+ { 0, 6 }, // 0 + (1 << 6) = 64
+ { 64, 8 }, // 64 + (1 << 8) = 320
+ { 0, 6 }, // 0 + (1 << 6) = 64
+ { 64, 9 }, // 64 + (1 << 9) = 576
+ { 576, 11 }, // 576 + (1 << 11) = 2624
+ { 2624, 13 }, // 2624 + (1 << 13) = 10816
+
+ // The above table entries are used after a certain number of
+ // bytes have been decoded.
+ // Early in the stream, some of the copy ranges are more limited
+ // in their range, so that fewer bits are needed. The above
+ // table entries are redirected to these entries instead.
+
+ // Table entry #3 (64):
+ { 64, 8 }, // < 320 bytes
+
+ // Table entry #4 (576):
+ { 576, 8 }, // < 832 bytes
+ { 576, 9 }, // < 1088 bytes
+ { 576, 10 }, // < 1600 bytes
+
+ // Table entry #5 (2624):
+ { 2624, 8 }, // < 2880 bytes
+ { 2624, 9 }, // < 3136 bytes
+ { 2624, 10 }, // < 3648 bytes
+ { 2624, 11 }, // < 4672 bytes
+ { 2624, 12 }, // < 6720 bytes
+};
+
+// Table used to decode byte values.
+
+static const VariableLengthTable byte_ranges[] = {
+ { 0, 4 }, // 0 + (1 << 4) = 16
+ { 16, 4 }, // 16 + (1 << 4) = 32
+ { 32, 5 }, // 32 + (1 << 5) = 64
+ { 64, 6 }, // 64 + (1 << 6) = 128
+ { 128, 6 }, // 128 + (1 << 6) = 191
+ { 192, 6 }, // 192 + (1 << 6) = 255
+};
+
+// This table is a list of trees to decode indices into byte_ranges.
+// Each line is actually a mini binary tree, starting with the first
+// byte as the root node. Each nybble of the byte is one of the two
+// branches: either a leaf value (a-f) or an offset to the child node.
+// Expanded representation is shown in comments below.
+
+static const uint8_t byte_decode_trees[][5] = {
+ { 0x12, 0x2d, 0xef, 0x1c, 0xab }, // ((((a b) c) d) (e f))
+ { 0x12, 0x23, 0xde, 0xab, 0xcf }, // (((a b) (c f)) (d e))
+ { 0x12, 0x2c, 0xd2, 0xab, 0xef }, // (((a b) c) (d (e f)))
+ { 0x12, 0xa2, 0xd2, 0xbc, 0xef }, // ((a (b c)) (d (e f)))
+
+ { 0x12, 0xa2, 0xc2, 0xbd, 0xef }, // ((a (b d)) (c (e f)))
+ { 0x12, 0xa2, 0xcd, 0xb1, 0xef }, // ((a (b (e f))) (c d))
+ { 0x12, 0xab, 0x12, 0xcd, 0xef }, // ((a b) ((c d) (e f)))
+ { 0x12, 0xab, 0x1d, 0xc1, 0xef }, // ((a b) ((c (e f)) d))
+
+ { 0x12, 0xab, 0xc1, 0xd1, 0xef }, // ((a b) (c (d (e f))))
+ { 0xa1, 0x12, 0x2c, 0xde, 0xbf }, // (a (((b f) c) (d e)))
+ { 0xa1, 0x1d, 0x1c, 0xb1, 0xef }, // (a (((b (e f)) c) d))
+ { 0xa1, 0x12, 0x2d, 0xef, 0xbc }, // (a (((b c) d) (e f)))
+
+ { 0xa1, 0x12, 0xb2, 0xde, 0xcf }, // (a ((b (c f)) (d e)))
+ { 0xa1, 0x12, 0xbc, 0xd1, 0xef }, // (a ((b c) (d (e f))))
+ { 0xa1, 0x1c, 0xb1, 0xd1, 0xef }, // (a ((b (d (e f))) c))
+ { 0xa1, 0xb1, 0x12, 0xcd, 0xef }, // (a (b ((c d) (e f))))
+
+ { 0xa1, 0xb1, 0xc1, 0xd1, 0xef }, // (a (b (c (d (e f)))))
+ { 0x12, 0x1c, 0xde, 0xab }, // (((d e) c) (d e)) <- BROKEN!
+ { 0x12, 0xa2, 0xcd, 0xbe }, // ((a (b e)) (c d))
+ { 0x12, 0xab, 0xc1, 0xde }, // ((a b) (c (d e)))
+
+ { 0xa1, 0x1d, 0x1c, 0xbe }, // (a (((b e) c) d))
+ { 0xa1, 0x12, 0xbc, 0xde }, // (a ((b c) (d e)))
+ { 0xa1, 0x1c, 0xb1, 0xde }, // (a ((b (d e)) c))
+ { 0xa1, 0xb1, 0xc1, 0xde }, // (a (b (c (d e))))
+
+ { 0x1d, 0x1c, 0xab }, // (((a b) c) d)
+ { 0x1c, 0xa1, 0xbd }, // ((a (b d)) c)
+ { 0x12, 0xab, 0xcd }, // ((a b) (c d))
+ { 0xa1, 0x1c, 0xbd }, // (a ((b d) c))
+
+ { 0xa1, 0xb1, 0xcd }, // (a (b (c d)))
+ { 0xa1, 0xbc }, // (a (b c))
+ { 0xab }, // (a b)
+ { 0x00 }, // -- special entry: 0, no tree
+};
+
+// Wrapper function invoked to read more data from the input. This mostly just
+// calls the real function that does the read. However, when the end of file
+// is reached, instead of returning zero, the buffer is filled with zero bytes
+// instead. There seem to be archive files that actually depend on this
+// ability to read "beyond" the length of the compressed data.
+
+static size_t read_callback_wrapper(void *buf, size_t buf_len, void *user_data)
+{
+ LHAPM1Decoder *decoder = user_data;
+ size_t result;
+
+ result = decoder->callback(buf, buf_len, decoder->callback_data);
+
+ if (result == 0) {
+ memset(buf, 0, buf_len);
+ result = buf_len;
+ }
+
+ return result;
+}
+
+static int lha_pm1_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHAPM1Decoder *decoder = data;
+
+ memset(decoder, 0, sizeof(LHAPM1Decoder));
+
+ // Unlike other decoders, the bitstream code must call the wrapper
+ // function above to read data.
+
+ decoder->callback = callback;
+ decoder->callback_data = callback_data;
+
+ bit_stream_reader_init(&decoder->bit_stream_reader,
+ read_callback_wrapper, decoder);
+
+ decoder->output_stream_pos = 0;
+ decoder->byte_decode_tree = NULL;
+ decoder->ringbuf_pos = 0;
+
+ init_history_list(&decoder->history_list);
+
+ return 1;
+}
+
+// Read the 5-bit header from the start of the input stream. This
+// specifies the table entry to use for byte decodes.
+
+static int read_start_header(LHAPM1Decoder *decoder)
+{
+ int index;
+
+ index = read_bits(&decoder->bit_stream_reader, 5);
+
+ if (index < 0) {
+ return 0;
+ }
+
+ decoder->byte_decode_tree = byte_decode_trees[index];
+
+ return 1;
+}
+
+// Function called when a new byte is outputted, to update the
+// appropriate data structures.
+
+static void outputted_byte(LHAPM1Decoder *decoder, uint8_t b)
+{
+ // Add to history ring buffer.
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos
+ = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+
+ // Other updates: history linked list, output stream position:
+
+ update_history_list(&decoder->history_list, b);
+ ++decoder->output_stream_pos;
+}
+
+// Decode a count of the number of bytes to copy in a copy command.
+// Returns -1 for failure.
+
+static int read_copy_byte_count(LHAPM1Decoder *decoder)
+{
+ int x;
+
+ // This is a form of static huffman encoding that uses less bits
+ // to encode short copy amounts (again).
+
+ // Value in the range 3..5?
+ // Length values start at 3: if it was 2, a different copy
+ // range would have been used and this function would not
+ // have been called.
+
+ x = read_bits(&decoder->bit_stream_reader, 2);
+
+ if (x < 0) {
+ return -1;
+ } else if (x < 3) {
+ return x + 3;
+ }
+
+ // Value in range 6..10?
+
+ x = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (x < 0) {
+ return -1;
+ } else if (x < 5) {
+ return x + 6;
+ }
+
+ // Value in range 11..14?
+
+ else if (x == 5) {
+ x = read_bits(&decoder->bit_stream_reader, 2);
+
+ if (x < 0) {
+ return -1;
+ } else {
+ return x + 11;
+ }
+ }
+
+ // Value in range 15..22?
+
+ else if (x == 6) {
+ x = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (x < 0) {
+ return -1;
+ } else {
+ return x + 15;
+ }
+ }
+
+ // else x == 7...
+
+ x = read_bits(&decoder->bit_stream_reader, 6);
+
+ if (x < 0) {
+ return -1;
+ } else if (x < 62) {
+ return x + 23;
+ }
+
+ // Value in range 85..116?
+
+ else if (x == 62) {
+ x = read_bits(&decoder->bit_stream_reader, 5);
+
+ if (x < 0) {
+ return -1;
+ } else {
+ return x + 85;
+ }
+ }
+
+ // Value in range 117..244?
+
+ else { // a = 63
+ x = read_bits(&decoder->bit_stream_reader, 7);
+
+ if (x < 0) {
+ return -1;
+ } else {
+ return x + 117;
+ }
+ }
+}
+
+// Read a single bit from the input stream, but only once the specified
+// point is reached in the output stream. Before that point is reached,
+// return the value of 'def' instead. Returns -1 for error.
+
+static int read_bit_after_threshold(LHAPM1Decoder *decoder,
+ unsigned int threshold,
+ int def)
+{
+ if (decoder->output_stream_pos >= threshold) {
+ return read_bit(&decoder->bit_stream_reader);
+ } else {
+ return def;
+ }
+}
+
+// Read the range index for the copy type used when performing a copy command.
+
+static int read_copy_type_range(LHAPM1Decoder *decoder)
+{
+ int x;
+
+ // This is another static huffman tree, but the path grows as
+ // more data is decoded. The progression is as follows:
+ // 1. Initially, only '0' and '2' can be returned.
+ // 2. After 64 bytes, '1' and '3' can be returned as well.
+ // 3. After 576 bytes, '4' can be returned.
+ // 4. After 2624 bytes, '5' can be returned.
+
+ x = read_bit(&decoder->bit_stream_reader);
+
+ if (x < 0) {
+ return -1;
+ } else if (x == 0) {
+ x = read_bit_after_threshold(decoder, 576, 0);
+
+ if (x < 0) {
+ return -1;
+ } else if (x != 0) {
+ return 4;
+ } else {
+ // Return either 0 or 1.
+ return read_bit_after_threshold(decoder, 64, 0);
+ }
+ } else {
+ x = read_bit_after_threshold(decoder, 64, 1);
+
+ if (x < 0) {
+ return -1;
+ } else if (x == 0) {
+ return 3;
+ }
+
+ x = read_bit_after_threshold(decoder, 2624, 1);
+
+ if (x < 0) {
+ return -1;
+ } else if (x != 0) {
+ return 2;
+ } else {
+ return 5;
+ }
+ }
+
+}
+
+// Read a copy command from the input stream and copy from history.
+// Returns 0 for failure.
+
+static size_t read_copy_command(LHAPM1Decoder *decoder, uint8_t *buf)
+{
+ int range_index;
+ int history_distance;
+ int copy_index, i;
+ int count;
+
+ range_index = read_copy_type_range(decoder);
+
+ if (range_index < 0) {
+ return 0;
+ }
+
+ // The first two entries in the copy_ranges table are used as
+ // a shorthand to copy two bytes. Otherwise, decode the number
+ // of bytes to copy.
+
+ if (range_index < 2) {
+ count = 2;
+ } else {
+ count = read_copy_byte_count(decoder);
+
+ if (count < 0) {
+ return 0;
+ }
+ }
+
+ // The 'range_index' variable is an index into the copy_ranges
+ // array. As a special-case hack, early in the output stream
+ // some history ranges are inaccessible, so fewer bits can be
+ // used. Redirect range_index to special entries to do this.
+
+ if (range_index == 3) {
+ if (decoder->output_stream_pos < 320) {
+ range_index = 6;
+ }
+ } else if (range_index == 4) {
+ if (decoder->output_stream_pos < 832) {
+ range_index = 7;
+ } else if (decoder->output_stream_pos < 1088) {
+ range_index = 8;
+ } else if (decoder->output_stream_pos < 1600) {
+ range_index = 9;
+ }
+ } else if (range_index == 5) {
+ if (decoder->output_stream_pos < 2880) {
+ range_index = 10;
+ } else if (decoder->output_stream_pos < 3136) {
+ range_index = 11;
+ } else if (decoder->output_stream_pos < 3648) {
+ range_index = 12;
+ } else if (decoder->output_stream_pos < 4672) {
+ range_index = 13;
+ } else if (decoder->output_stream_pos < 6720) {
+ range_index = 14;
+ }
+ }
+
+ // Calculate the number of bytes back into the history buffer
+ // to read.
+
+ history_distance = decode_variable_length(&decoder->bit_stream_reader,
+ copy_ranges, range_index);
+
+ if (history_distance < 0
+ || (unsigned) history_distance >= decoder->output_stream_pos) {
+ return 0;
+ }
+
+ // Copy from the ring buffer.
+
+ copy_index = (decoder->ringbuf_pos + RING_BUFFER_SIZE
+ - history_distance - 1) % RING_BUFFER_SIZE;
+
+ for (i = 0; i < count; ++i) {
+ buf[i] = decoder->ringbuf[copy_index];
+ outputted_byte(decoder, decoder->ringbuf[copy_index]);
+ copy_index = (copy_index + 1) % RING_BUFFER_SIZE;
+ }
+
+ return count;
+}
+
+// Read the index into the byte decode table, using the byte_decode_tree
+// set at the start of the stream. Returns -1 for failure.
+
+static int read_byte_decode_index(LHAPM1Decoder *decoder)
+{
+ const uint8_t *ptr;
+ unsigned int child;
+ int bit;
+
+ ptr = decoder->byte_decode_tree;
+
+ if (ptr[0] == 0) {
+ return 0;
+ }
+
+ // Walk down the tree, reading a bit at each node to determine
+ // which path to take.
+
+ for (;;) {
+ bit = read_bit(&decoder->bit_stream_reader);
+
+ if (bit < 0) {
+ return -1;
+ } else if (bit == 0) {
+ child = (*ptr >> 4) & 0x0f;
+ } else {
+ child = *ptr & 0x0f;
+ }
+
+ // Reached a leaf node?
+
+ if (child >= 10) {
+ return child - 10;
+ }
+
+ ptr += child;
+ }
+}
+
+// Read a single byte value from the input stream.
+// Returns -1 for failure.
+
+static int read_byte(LHAPM1Decoder *decoder)
+{
+ int index;
+ int count;
+
+ // Read the index into the byte_ranges table to use.
+
+ index = read_byte_decode_index(decoder);
+
+ if (index < 0) {
+ return -1;
+ }
+
+ // Decode value using byte_ranges table. This is actually
+ // a distance to walk along the history linked list - it
+ // is static huffman encoding, so that recently used byte
+ // values use fewer bits.
+
+ count = decode_variable_length(&decoder->bit_stream_reader,
+ byte_ranges, index);
+
+ if (count < 0) {
+ return -1;
+ }
+
+ // Walk through the history linked list to get the actual
+ // value.
+
+ return find_in_history_list(&decoder->history_list, count);
+}
+
+// Read the length of a block of bytes.
+
+static int read_byte_block_count(BitStreamReader *reader)
+{
+ int x;
+
+ // This is a form of static huffman coding, where smaller
+ // lengths are encoded using shorter bit sequences.
+
+ // Value in the range 1..3?
+
+ x = read_bits(reader, 2);
+
+ if (x < 0) {
+ return 0;
+ } else if (x < 3) {
+ return x + 1;
+ }
+
+ // Value in the range 4..10?
+
+ x = read_bits(reader, 3);
+
+ if (x < 0) {
+ return 0;
+ } else if (x < 7) {
+ return x + 4;
+ }
+
+ // Value in the range 11..25?
+
+ x = read_bits(reader, 4);
+
+ if (x < 0) {
+ return 0;
+ } else if (x < 14) {
+ return x + 11;
+ } else if (x == 14) {
+ // Value in the range 25-88:
+
+ x = read_bits(reader, 6);
+
+ if (x < 0) {
+ return 0;
+ } else {
+ return x + 25;
+ }
+ } else { // x = 15
+ // Value in the range 89-216:
+
+ x = read_bits(reader, 7);
+
+ if (x < 0) {
+ return 0;
+ } else {
+ return x + 89;
+ }
+ }
+}
+
+// Read a block of bytes from the input stream.
+// Returns 0 for failure.
+
+static size_t read_byte_block(LHAPM1Decoder *decoder, uint8_t *buf)
+{
+ size_t result, result2;
+ int byteval;
+ int block_len;
+ int i;
+
+ // How many bytes to decode?
+
+ block_len = read_byte_block_count(&decoder->bit_stream_reader);
+
+ if (block_len == 0) {
+ return 0;
+ }
+
+ // Decode the byte values and add them to the output buffer.
+
+ for (i = 0; i < block_len; ++i) {
+ byteval = read_byte(decoder);
+
+ if (byteval < 0) {
+ return 0;
+ }
+
+ buf[i] = byteval;
+ outputted_byte(decoder, byteval);
+ }
+
+ result = (size_t) block_len;
+
+ // Because this is a block of bytes, it can be assumed that the
+ // block ended for a copy command. The one exception is that if
+ // the maximum block length was reached, the block may have
+ // ended just because it could not be any larger.
+
+ if (result == MAX_BYTE_BLOCK_LEN) {
+ return result;
+ }
+
+ result2 = read_copy_command(decoder, buf + result);
+
+ if (result2 == 0) {
+ return 0;
+ }
+
+ return result + result2;
+}
+
+static size_t lha_pm1_read(void *data, uint8_t *buf)
+{
+ LHAPM1Decoder *decoder = data;
+ int command_type;
+
+ // Start of input stream? Read the header.
+
+ if (decoder->byte_decode_tree == NULL
+ && !read_start_header(decoder)) {
+ return 0;
+ }
+
+ // Read what type of commmand this is.
+
+ command_type = read_bit(&decoder->bit_stream_reader);
+
+ if (command_type == 0) {
+ return read_copy_command(decoder, buf);
+ } else {
+ return read_byte_block(decoder, buf);
+ }
+}
+
+LHADecoderType lha_pm1_decoder = {
+ lha_pm1_init,
+ NULL,
+ lha_pm1_read,
+ sizeof(LHAPM1Decoder),
+ OUTPUT_BUFFER_SIZE,
+ 2048
+};
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c
new file mode 100644
index 00000000..a423e610
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c
@@ -0,0 +1,549 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Decoder for PMarc -pm2- compression format. PMarc is a variant
+// of LHA commonly used on the MSX computer architecture.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "lha_decoder.h"
+
+#include "bit_stream_reader.c"
+#include "pma_common.c"
+
+// Include tree decoder.
+
+typedef uint8_t TreeElement;
+#include "tree_decode.c"
+
+// Size of the ring buffer (in bytes) used to store past history
+// for copies.
+
+#define RING_BUFFER_SIZE 8192
+
+// Maximum number of bytes that might be placed in the output buffer
+// from a single call to lha_pm2_decoder_read (largest copy size).
+
+#define OUTPUT_BUFFER_SIZE 256
+
+// Number of tree elements in the code tree.
+
+#define CODE_TREE_ELEMENTS 65
+
+// Number of tree elements in the offset tree.
+
+#define OFFSET_TREE_ELEMENTS 17
+
+typedef enum {
+ PM2_REBUILD_UNBUILT, // At start of stream
+ PM2_REBUILD_BUILD1, // After 1KiB
+ PM2_REBUILD_BUILD2, // After 2KiB
+ PM2_REBUILD_BUILD3, // After 4KiB
+ PM2_REBUILD_CONTINUING, // 8KiB onwards...
+} PM2RebuildState;
+
+typedef struct {
+ BitStreamReader bit_stream_reader;
+
+ // State of decode tree.
+
+ PM2RebuildState tree_state;
+
+ // Number of bytes until we initiate a tree rebuild.
+
+ size_t tree_rebuild_remaining;
+
+ // History ring buffer, for copies:
+
+ uint8_t ringbuf[RING_BUFFER_SIZE];
+ unsigned int ringbuf_pos;
+
+ // History linked list, for adaptively encoding byte values.
+
+ HistoryLinkedList history_list;
+
+ // Array representing the huffman tree used for representing
+ // code values. A given node of the tree has children
+ // code_tree[n] and code_tree[n + 1]. code_tree[0] is the
+ // root node.
+
+ TreeElement code_tree[CODE_TREE_ELEMENTS];
+
+ // If zero, we don't need an offset tree:
+
+ int need_offset_tree;
+
+ // Array representing huffman tree used to look up offsets.
+ // Same format as code_tree[].
+
+ TreeElement offset_tree[OFFSET_TREE_ELEMENTS];
+
+} LHAPM2Decoder;
+
+// Decode table for history value. Characters that appeared recently in
+// the history are more likely than ones that appeared a long time ago,
+// so the history value is huffman coded so that small values require
+// fewer bits. The history value is then used to search within the
+// history linked list to get the actual character.
+
+static const VariableLengthTable history_decode[] = {
+ { 0, 3 }, // 0 + (1 << 3) = 8
+ { 8, 3 }, // 8 + (1 << 3) = 16
+ { 16, 4 }, // 16 + (1 << 4) = 32
+ { 32, 5 }, // 32 + (1 << 5) = 64
+ { 64, 5 }, // 64 + (1 << 5) = 96
+ { 96, 5 }, // 96 + (1 << 5) = 128
+ { 128, 6 }, // 128 + (1 << 6) = 192
+ { 192, 6 }, // 192 + (1 << 6) = 256
+};
+
+// Decode table for copies. As with history_decode[], small copies
+// are more common, and require fewer bits.
+
+static const VariableLengthTable copy_decode[] = {
+ { 17, 3 }, // 17 + (1 << 3) = 25
+ { 25, 3 }, // 25 + (1 << 3) = 33
+ { 33, 5 }, // 33 + (1 << 5) = 65
+ { 65, 6 }, // 65 + (1 << 6) = 129
+ { 129, 7 }, // 129 + (1 << 7) = 256
+ { 256, 0 }, // 256 (unique value)
+};
+
+// Initialize PMA decoder.
+
+static int lha_pm2_decoder_init(void *data, LHADecoderCallback callback,
+ void *callback_data)
+{
+ LHAPM2Decoder *decoder = data;
+
+ bit_stream_reader_init(&decoder->bit_stream_reader,
+ callback, callback_data);
+
+ // Tree has not been built yet. It needs to be built on
+ // the first call to read().
+
+ decoder->tree_state = PM2_REBUILD_UNBUILT;
+ decoder->tree_rebuild_remaining = 0;
+
+ // Initialize ring buffer contents.
+
+ memset(&decoder->ringbuf, ' ', RING_BUFFER_SIZE);
+ decoder->ringbuf_pos = 0;
+
+ // Init history lookup list.
+
+ init_history_list(&decoder->history_list);
+
+ // Initialize the lookup trees to a known state.
+
+ init_tree(decoder->code_tree, CODE_TREE_ELEMENTS);
+ init_tree(decoder->offset_tree, OFFSET_TREE_ELEMENTS);
+
+ return 1;
+}
+
+// Read the list of code lengths to use for the code tree and construct
+// the code_tree structure.
+
+static int read_code_tree(LHAPM2Decoder *decoder)
+{
+ uint8_t code_lengths[31];
+ int num_codes, min_code_length, length_bits, val;
+ unsigned int i;
+
+ // Read the number of codes in the tree.
+
+ num_codes = read_bits(&decoder->bit_stream_reader, 5);
+
+ // Read min_code_length, which is used as an offset.
+
+ min_code_length = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (min_code_length < 0 || num_codes < 0) {
+ return 0;
+ }
+
+ // Store flag variable indicating whether we want to read
+ // the offset tree as well.
+
+ decoder->need_offset_tree
+ = num_codes >= 10
+ && !(num_codes == 29 && min_code_length == 0);
+
+ // Minimum length of zero means a tree containing a single code.
+
+ if (min_code_length == 0) {
+ set_tree_single(decoder->code_tree, num_codes - 1);
+ return 1;
+ }
+
+ // How many bits are used to represent each table entry?
+
+ length_bits = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (length_bits < 0) {
+ return 0;
+ }
+
+ // Read table of code lengths:
+
+ for (i = 0; i < (unsigned int) num_codes; ++i) {
+
+ // Read a table entry. A value of zero represents an
+ // unused code. Otherwise the value represents
+ // an offset from the minimum length (previously read).
+
+ val = read_bits(&decoder->bit_stream_reader,
+ (unsigned int) length_bits);
+
+ if (val < 0) {
+ return 0;
+ } else if (val == 0) {
+ code_lengths[i] = 0;
+ } else {
+ code_lengths[i] = (uint8_t) (min_code_length + val - 1);
+ }
+ }
+
+ // Build the tree.
+
+ build_tree(decoder->code_tree, sizeof(decoder->code_tree),
+ code_lengths, (unsigned int) num_codes);
+
+ return 1;
+}
+
+// Read the code lengths for the offset tree and construct the offset
+// tree lookup table.
+
+static int read_offset_tree(LHAPM2Decoder *decoder,
+ unsigned int num_offsets)
+{
+ uint8_t offset_lengths[8];
+ unsigned int off;
+ unsigned int single_offset, num_codes;
+ int len;
+
+ if (!decoder->need_offset_tree) {
+ return 1;
+ }
+
+ // Read 'num_offsets' 3-bit length values. For each offset
+ // value 'off', offset_lengths[off] is the length of the
+ // code that will represent 'off', or 0 if it will not
+ // appear within the tree.
+
+ num_codes = 0;
+ single_offset = 0;
+
+ for (off = 0; off < num_offsets; ++off) {
+ len = read_bits(&decoder->bit_stream_reader, 3);
+
+ if (len < 0) {
+ return 0;
+ }
+
+ offset_lengths[off] = (uint8_t) len;
+
+ // Track how many actual codes were in the tree.
+
+ if (len != 0) {
+ single_offset = off;
+ ++num_codes;
+ }
+ }
+
+ // If there was a single code, this is a single node tree.
+
+ if (num_codes == 1) {
+ set_tree_single(decoder->offset_tree, single_offset);
+ return 1;
+ }
+
+ // Build the tree.
+
+ build_tree(decoder->offset_tree, sizeof(decoder->offset_tree),
+ offset_lengths, num_offsets);
+
+ return 1;
+}
+
+// Rebuild the decode trees used to compress data. This is called when
+// decoder->tree_rebuild_remaining reaches zero.
+
+static void rebuild_tree(LHAPM2Decoder *decoder)
+{
+ switch (decoder->tree_state) {
+
+ // Initial tree build, from start of stream:
+
+ case PM2_REBUILD_UNBUILT:
+ read_code_tree(decoder);
+ read_offset_tree(decoder, 5);
+ decoder->tree_state = PM2_REBUILD_BUILD1;
+ decoder->tree_rebuild_remaining = 1024;
+ break;
+
+ // Tree rebuild after 1KiB of data has been read:
+
+ case PM2_REBUILD_BUILD1:
+ read_offset_tree(decoder, 6);
+ decoder->tree_state = PM2_REBUILD_BUILD2;
+ decoder->tree_rebuild_remaining = 1024;
+ break;
+
+ // Tree rebuild after 2KiB of data has been read:
+
+ case PM2_REBUILD_BUILD2:
+ read_offset_tree(decoder, 7);
+ decoder->tree_state = PM2_REBUILD_BUILD3;
+ decoder->tree_rebuild_remaining = 2048;
+ break;
+
+ // Tree rebuild after 4KiB of data has been read:
+
+ case PM2_REBUILD_BUILD3:
+ if (read_bit(&decoder->bit_stream_reader) == 1) {
+ read_code_tree(decoder);
+ }
+ read_offset_tree(decoder, 8);
+ decoder->tree_state = PM2_REBUILD_CONTINUING;
+ decoder->tree_rebuild_remaining = 4096;
+ break;
+
+ // Tree rebuild after 8KiB of data has been read,
+ // and every 4KiB after that:
+
+ case PM2_REBUILD_CONTINUING:
+ if (read_bit(&decoder->bit_stream_reader) == 1) {
+ read_code_tree(decoder);
+ read_offset_tree(decoder, 8);
+ }
+ decoder->tree_rebuild_remaining = 4096;
+ break;
+ }
+}
+
+static void output_byte(LHAPM2Decoder *decoder, uint8_t *buf,
+ size_t *buf_len, uint8_t b)
+{
+ // Add to history ring buffer.
+
+ decoder->ringbuf[decoder->ringbuf_pos] = b;
+ decoder->ringbuf_pos = (decoder->ringbuf_pos + 1) % RING_BUFFER_SIZE;
+
+ // Add to output buffer.
+
+ buf[*buf_len] = b;
+ ++*buf_len;
+
+ // Update history chain.
+
+ update_history_list(&decoder->history_list, b);
+
+ // Count down until it is time to perform a rebuild of the
+ // lookup trees.
+
+ --decoder->tree_rebuild_remaining;
+
+ if (decoder->tree_rebuild_remaining == 0) {
+ rebuild_tree(decoder);
+ }
+}
+
+// Read a single byte from the input stream and add it to the output
+// buffer.
+
+static void read_single_byte(LHAPM2Decoder *decoder, unsigned int code,
+ uint8_t *buf, size_t *buf_len)
+{
+ int offset;
+ uint8_t b;
+
+ offset = decode_variable_length(&decoder->bit_stream_reader,
+ history_decode, code);
+
+ if (offset < 0) {
+ return;
+ }
+
+ b = find_in_history_list(&decoder->history_list, (uint8_t) offset);
+ output_byte(decoder, buf, buf_len, b);
+}
+
+// Calculate how many bytes from history to copy:
+
+static int history_get_count(LHAPM2Decoder *decoder, unsigned int code)
+{
+ // How many bytes to copy? A small value represents the
+ // literal number of bytes to copy; larger values are a header
+ // for a variable length value to be decoded.
+
+ if (code < 15) {
+ return (int) code + 2;
+ } else {
+ return decode_variable_length(&decoder->bit_stream_reader,
+ copy_decode, code - 15);
+ }
+}
+
+// Calculate the offset within history at which to start copying:
+
+static int history_get_offset(LHAPM2Decoder *decoder, unsigned int code)
+{
+ unsigned int bits;
+ int result, val;
+
+ result = 0;
+
+ // Calculate number of bits to read.
+
+ // Code of zero indicates a simple 6-bit value giving the offset.
+
+ if (code == 0) {
+ bits = 6;
+ }
+
+ // Mid-range encoded offset value.
+ // Read a code using the offset tree, indicating the length
+ // of the offset value to follow. The code indicates the
+ // number of bits (values 0-7 = 6-13 bits).
+
+ else if (code < 20) {
+
+ val = read_from_tree(&decoder->bit_stream_reader,
+ decoder->offset_tree);
+
+ if (val < 0) {
+ return -1;
+ } else if (val == 0) {
+ bits = 6;
+ } else {
+ bits = (unsigned int) val + 5;
+ result = 1 << bits;
+ }
+ }
+
+ // Large copy values start from offset zero.
+
+ else {
+ return 0;
+ }
+
+ // Read a number of bits representing the offset value. The
+ // number of length of this value is variable, and is calculated
+ // above.
+
+ val = read_bits(&decoder->bit_stream_reader, bits);
+
+ if (val < 0) {
+ return -1;
+ }
+
+ result += val;
+
+ return result;
+}
+
+static void copy_from_history(LHAPM2Decoder *decoder, unsigned int code,
+ uint8_t *buf, size_t *buf_len)
+{
+ int to_copy, offset;
+ unsigned int i, pos, start;
+
+ // Read number of bytes to copy and offset within history to copy
+ // from.
+
+ to_copy = history_get_count(decoder, code);
+ offset = history_get_offset(decoder, code);
+
+ if (to_copy < 0 || offset < 0) {
+ return;
+ }
+
+ // Sanity check to prevent the potential for buffer overflow.
+
+ if (to_copy > OUTPUT_BUFFER_SIZE) {
+ return;
+ }
+
+ // Perform copy.
+
+ start = decoder->ringbuf_pos + RING_BUFFER_SIZE - 1
+ - (unsigned int) offset;
+
+ for (i = 0; i < (unsigned int) to_copy; ++i) {
+ pos = (start + i) % RING_BUFFER_SIZE;
+
+ output_byte(decoder, buf, buf_len, decoder->ringbuf[pos]);
+ }
+}
+
+// Decode data and store it into buf[], returning the number of
+// bytes decoded.
+
+static size_t lha_pm2_decoder_read(void *data, uint8_t *buf)
+{
+ LHAPM2Decoder *decoder = data;
+ size_t result;
+ int code;
+
+ // On first pass through, build initial lookup trees.
+
+ if (decoder->tree_state == PM2_REBUILD_UNBUILT) {
+
+ // First bit in stream is discarded?
+
+ read_bit(&decoder->bit_stream_reader);
+ rebuild_tree(decoder);
+ }
+
+ result = 0;
+
+ code = read_from_tree(&decoder->bit_stream_reader, decoder->code_tree);
+
+ if (code < 0) {
+ return 0;
+ }
+
+ if (code < 8) {
+ read_single_byte(decoder, (unsigned int) code, buf, &result);
+ } else {
+ copy_from_history(decoder, (unsigned int) code - 8,
+ buf, &result);
+ }
+
+ return result;
+}
+
+LHADecoderType lha_pm2_decoder = {
+ lha_pm2_decoder_init,
+ NULL,
+ lha_pm2_decoder_read,
+ sizeof(LHAPM2Decoder),
+ OUTPUT_BUFFER_SIZE,
+ RING_BUFFER_SIZE
+};
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c
new file mode 100644
index 00000000..00af915f
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c
@@ -0,0 +1,162 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+//
+// Common functions used by PMarc decoders.
+//
+
+typedef struct {
+ unsigned int offset;
+ unsigned int bits;
+} VariableLengthTable;
+
+// Read a variable length code, given the header bits already read.
+// Returns the decoded value, or -1 for error.
+
+static int decode_variable_length(BitStreamReader *reader,
+ const VariableLengthTable *table,
+ unsigned int header)
+{
+ int value;
+
+ value = read_bits(reader, table[header].bits);
+
+ if (value < 0) {
+ return -1;
+ }
+
+ return (int) table[header].offset + value;
+}
+
+typedef struct {
+ uint8_t prev;
+ uint8_t next;
+} HistoryNode;
+
+// History linked list. In the decode stream, codes representing
+// characters are not the character itself, but the number of
+// nodes to count back in time in the linked list. Every time
+// a character is output, it is moved to the front of the linked
+// list. The entry point index into the list is the last output
+// character, given by history_head;
+
+typedef struct {
+ HistoryNode history[256];
+ uint8_t history_head;
+} HistoryLinkedList;
+
+// Initialize the history buffer.
+
+static void init_history_list(HistoryLinkedList *list)
+{
+ unsigned int i;
+
+ // History buffer is initialized to a linear chain to
+ // start off with:
+
+ for (i = 0; i < 256; ++i) {
+ list->history[i].prev = (uint8_t) (i + 1);
+ list->history[i].next = (uint8_t) (i - 1);
+ }
+
+ // The chain is cut into groups and initially arranged so
+ // that the ASCII characters are closest to the start of
+ // the chain. This is followed by ASCII control characters,
+ // then various other groups.
+
+ list->history_head = 0x20;
+
+ list->history[0x7f].prev = 0x00; // 0x20 ... 0x7f -> 0x00
+ list->history[0x00].next = 0x7f;
+
+ list->history[0x1f].prev = 0xa0; // 0x00 ... 0x1f -> 0xa0
+ list->history[0xa0].next = 0x1f;
+
+ list->history[0xdf].prev = 0x80; // 0xa0 ... 0xdf -> 0x80
+ list->history[0x80].next = 0xdf;
+
+ list->history[0x9f].prev = 0xe0; // 0x80 ... 0x9f -> 0xe0
+ list->history[0xe0].next = 0x9f;
+
+ list->history[0xff].prev = 0x20; // 0xe0 ... 0xff -> 0x20
+ list->history[0x20].next = 0xff;
+}
+
+// Look up an entry in the history list, returning the code found.
+
+static uint8_t find_in_history_list(HistoryLinkedList *list, uint8_t count)
+{
+ unsigned int i;
+ uint8_t code;
+
+ // Start from the last outputted byte.
+
+ code = list->history_head;
+
+ // Walk along the history chain until we reach the desired
+ // node. If we will have to walk more than half the chain,
+ // go the other way around.
+
+ if (count < 128) {
+ for (i = 0; i < count; ++i) {
+ code = list->history[code].prev;
+ }
+ } else {
+ for (i = 0; i < 256U - count; ++i) {
+ code = list->history[code].next;
+ }
+ }
+
+ return code;
+}
+
+// Update history list, by moving the specified byte to the head
+// of the queue.
+
+static void update_history_list(HistoryLinkedList *list, uint8_t b)
+{
+ HistoryNode *node, *old_head;
+
+ // No update necessary?
+
+ if (list->history_head == b) {
+ return;
+ }
+
+ // Unhook the entry from its current position:
+
+ node = &list->history[b];
+ list->history[node->next].prev = node->prev;
+ list->history[node->prev].next = node->next;
+
+ // Hook in between the old head and old_head->next:
+
+ old_head = &list->history[list->history_head];
+ node->prev = list->history_head;
+ node->next = old_head->next;
+
+ list->history[old_head->next].prev = b;
+ old_head->next = b;
+
+ // 'b' is now the head of the queue:
+
+ list->history_head = b;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am
new file mode 100644
index 00000000..9e810ac9
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am
@@ -0,0 +1,9 @@
+
+headerfilesdir=$(includedir)/liblhasa-1.0
+headerfiles_HEADERS= \
+ lhasa.h \
+ lha_decoder.h \
+ lha_file_header.h \
+ lha_input_stream.h \
+ lha_reader.h
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h
new file mode 100644
index 00000000..149e0c3e
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h
@@ -0,0 +1,183 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_PUBLIC_LHA_DECODER_H
+#define LHASA_PUBLIC_LHA_DECODER_H
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file lha_decoder.h
+ *
+ * @brief Raw LHA data decoder.
+ *
+ * This file defines the interface to the decompression code, which can
+ * be used to decompress the raw compressed data from an LZH file.
+ *
+ * Implementations of the various compression algorithms used in LZH
+ * archives are provided - these are represented by the
+ * @ref LHADecoderType structure, and can be retrieved using the
+ * @ref lha_decoder_for_name function. One of these can then be passed to
+ * the @ref lha_decoder_new function to create a @ref LHADecoder structure
+ * and decompress the data.
+ */
+
+/**
+ * Opaque type representing a type of decoder.
+ *
+ * This is an implementation of the decompression code for one of the
+ * algorithms used in LZH archive files. Pointers to these structures are
+ * retrieved by using the @ref lha_decoder_for_name function.
+ */
+
+typedef struct _LHADecoderType LHADecoderType;
+
+/**
+ * Opaque type representing an instance of a decoder.
+ *
+ * This is a decoder structure being used to decompress a stream of
+ * compressed data. Instantiated using the @ref lha_decoder_new
+ * function and freed using the @ref lha_decoder_free function.
+ */
+
+typedef struct _LHADecoder LHADecoder;
+
+/**
+ * Callback function invoked when a decoder wants to read more compressed
+ * data.
+ *
+ * @param buf Pointer to the buffer in which to store the data.
+ * @param buf_len Size of the buffer, in bytes.
+ * @param user_data Extra pointer to pass to the decoder.
+ * @return Number of bytes read.
+ */
+
+typedef size_t (*LHADecoderCallback)(void *buf, size_t buf_len,
+ void *user_data);
+
+/**
+ * Callback function used for monitoring decode progress.
+ * The callback is invoked for every block processed (block size depends on
+ * decode algorithm).
+ *
+ * @param num_blocks Number of blocks processed so far.
+ * @param total_blocks Total number of blocks to process.
+ * @paaram callback_data Extra user-specified data passed to the callback.
+ */
+
+typedef void (*LHADecoderProgressCallback)(unsigned int num_blocks,
+ unsigned int total_blocks,
+ void *callback_data);
+
+/**
+ * Get the decoder type for the specified name.
+ *
+ * @param name String identifying the decoder type, for
+ * example, "-lh1-".
+ * @return Pointer to the decoder type, or NULL if there
+ * is no decoder type for the specified name.
+ */
+
+LHADecoderType *lha_decoder_for_name(char *name);
+
+/**
+ * Allocate a new decoder for the specified type.
+ *
+ * @param dtype The decoder type.
+ * @param callback Callback function for the decoder to call to read
+ * more compressed data.
+ * @param callback_data Extra data to pass to the callback function.
+ * @param stream_length Length of the uncompressed data, in bytes. When
+ * this point is reached, decompression will stop.
+ * @return Pointer to the new decoder, or NULL for failure.
+ */
+
+LHADecoder *lha_decoder_new(LHADecoderType *dtype,
+ LHADecoderCallback callback,
+ void *callback_data,
+ size_t stream_length);
+
+/**
+ * Free a decoder.
+ *
+ * @param decoder The decoder to free.
+ */
+
+void lha_decoder_free(LHADecoder *decoder);
+
+/**
+ * Set a callback function to monitor decode progress.
+ *
+ * @param decoder The decoder.
+ * @param callback Callback function to monitor decode progress.
+ * @param callback_data Extra data to pass to the decoder.
+ */
+
+void lha_decoder_monitor(LHADecoder *decoder,
+ LHADecoderProgressCallback callback,
+ void *callback_data);
+
+/**
+ * Decode (decompress) more data.
+ *
+ * @param decoder The decoder.
+ * @param buf Pointer to buffer to store decompressed data.
+ * @param buf_len Size of the buffer, in bytes.
+ * @return Number of bytes decompressed.
+ */
+
+size_t lha_decoder_read(LHADecoder *decoder, uint8_t *buf, size_t buf_len);
+
+/**
+ * Get the current 16-bit CRC of the decompressed data.
+ *
+ * This should be called at the end of decompression to check that the
+ * data was extracted correctly, and the value compared against the CRC
+ * from the file header.
+ *
+ * @param decoder The decoder.
+ * @return 16-bit CRC of the data decoded so far.
+ */
+
+uint16_t lha_decoder_get_crc(LHADecoder *decoder);
+
+/**
+ * Get the count of the number of bytes decoded.
+ *
+ * This should be called at the end of decompression, and the value
+ * compared against the file length from the file header.
+ *
+ * @param decoder The decoder.
+ * @return The number of decoded bytes.
+ */
+
+size_t lha_decoder_get_length(LHADecoder *decoder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef LHASA_LHA_DECODER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h
new file mode 100644
index 00000000..410ff38d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h
@@ -0,0 +1,248 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_PUBLIC_LHA_FILE_HEADER_H
+#define LHASA_PUBLIC_LHA_FILE_HEADER_H
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file lha_file_header.h
+ *
+ * @brief LHA file header structure.
+ *
+ * This file contains the definition of the @ref LHAFileHeader structure,
+ * representing a decoded file header from an LZH file.
+ */
+
+/** OS type value for an unknown OS. */
+#define LHA_OS_TYPE_UNKNOWN 0x00
+/** OS type value for Microsoft MS/DOS. */
+#define LHA_OS_TYPE_MSDOS 'M'
+/** OS type value for Microsoft Windows 95. */
+#define LHA_OS_TYPE_WIN95 'w'
+/** OS type value for Microsoft Windows NT. */
+#define LHA_OS_TYPE_WINNT 'W'
+/** OS type value for Unix. */
+#define LHA_OS_TYPE_UNIX 'U'
+/** OS type value for IBM OS/2. */
+#define LHA_OS_TYPE_OS2 '2'
+/** OS type for Apple Mac OS (Classic). */
+#define LHA_OS_TYPE_MACOS 'm'
+/** OS type for Amiga OS. */
+#define LHA_OS_TYPE_AMIGA 'A'
+/** OS type for Atari TOS. */
+#define LHA_OS_TYPE_ATARI 'a'
+
+// Obscure:
+
+/** OS type for Sun (Oracle) Java. */
+#define LHA_OS_TYPE_JAVA 'J'
+/** OS type for Digital Research CP/M. */
+#define LHA_OS_TYPE_CPM 'C'
+/** OS type for Digital Research FlexOS. */
+#define LHA_OS_TYPE_FLEX 'F'
+/** OS type for Runser (?). */
+#define LHA_OS_TYPE_RUNSER 'R'
+/** OS type for Fujitsu FM Towns OS. */
+#define LHA_OS_TYPE_TOWNSOS 'T'
+/** OS type for Microware OS-9. */
+#define LHA_OS_TYPE_OS9 '9'
+/** OS type for Microware OS-9/68k. */
+#define LHA_OS_TYPE_OS9_68K 'K'
+/** OS type for OS/386 (?). */
+#define LHA_OS_TYPE_OS386 '3'
+/** OS type for Sharp X68000 Human68K OS. */
+#define LHA_OS_TYPE_HUMAN68K 'H'
+
+/**
+ * Compression type for a stored directory. The same value is also
+ * used for Unix symbolic links.
+ */
+#define LHA_COMPRESS_TYPE_DIR "-lhd-"
+
+/**
+ * Bit field value set in extra_flags to indicate that the
+ * Unix file permission header (0x50) was parsed.
+ */
+#define LHA_FILE_UNIX_PERMS 0x01
+
+/**
+ * Bit field value set in extra_flags to indicate that the
+ * Unix UID/GID header (0x51) was parsed.
+ */
+#define LHA_FILE_UNIX_UID_GID 0x02
+
+/**
+ * Bit field value set in extra_flags to indicate that the 'common
+ * header' extended header (0x00) was parsed, and the common_crc
+ * field has been set.
+ */
+#define LHA_FILE_COMMON_CRC 0x04
+
+/**
+ * Bit field value set in extra_flags to indicate that the
+ * Windows time stamp header (0x41) was parsed, and the Windows
+ * FILETIME timestamp fields have been set.
+ */
+#define LHA_FILE_WINDOWS_TIMESTAMPS 0x08
+
+/**
+ * Bit field value set in extra_flags to indicate that the OS-9
+ * permissions field is set.
+ */
+#define LHA_FILE_OS9_PERMS 0x10
+
+typedef struct _LHAFileHeader LHAFileHeader;
+
+#define LHA_FILE_HAVE_EXTRA(header, flag) \
+ (((header)->extra_flags & (flag)) != 0)
+/**
+ * Structure containing a decoded LZH file header.
+ *
+ * A file header precedes the compressed data of each file stored
+ * within an LZH archive. It contains the name of the file, and
+ * various additional metadata, some of which is optional, and
+ * can depend on the header format, the tool used to create the
+ * archive, and the operating system on which it was created.
+ */
+
+struct _LHAFileHeader {
+
+ // Internal fields, do not touch!
+
+ unsigned int _refcount;
+ LHAFileHeader *_next;
+
+ /**
+ * Stored path, with Unix-style ('/') path separators.
+ *
+ * This may be NULL, although if this is a directory
+ * (@ref LHA_COMPRESS_TYPE_DIR), it is never NULL.
+ */
+ char *path;
+
+ /**
+ * File name.
+ *
+ * This is never NULL, except if this is a directory
+ * (@ref LHA_COMPRESS_TYPE_DIR), where it is always NULL.
+ */
+ char *filename;
+
+ /**
+ * Target for symbolic link.
+ *
+ * This is NULL unless this header represents a symbolic link
+ * (@ref LHA_COMPRESS_TYPE_DIR).
+ */
+ char *symlink_target;
+
+ /**
+ * Compression method.
+ *
+ * If the header represents a directory or a symbolic link, the
+ * compression method is equal to @ref LHA_COMPRESS_TYPE_DIR.
+ */
+ char compress_method[6];
+
+ /** Length of the compressed data. */
+ size_t compressed_length;
+
+ /** Length of the uncompressed data. */
+ size_t length;
+
+ /** LZH header format used to store this header. */
+ uint8_t header_level;
+
+ /**
+ * OS type indicator, identifying the OS on which
+ * the archive was created.
+ */
+ uint8_t os_type;
+
+ /** 16-bit CRC of the compressed data. */
+ uint16_t crc;
+
+ /** Unix timestamp of the modification time of the file. */
+ unsigned int timestamp;
+
+ /** Pointer to a buffer containing the raw header data. */
+ uint8_t *raw_data;
+
+ /** Length of the raw header data. */
+ size_t raw_data_len;
+
+ /**
+ * Flags bitfield identifying extra data decoded from extended
+ * headers.
+ */
+ unsigned int extra_flags;
+
+ /** Unix permissions, set if @ref LHA_FILE_UNIX_PERMS is set. */
+ unsigned int unix_perms;
+
+ /** Unix user ID, set if @ref LHA_FILE_UNIX_UID_GID is set. */
+ unsigned int unix_uid;
+
+ /** Unix group ID, set if @ref LHA_FILE_UNIX_UID_GID is set. */
+ unsigned int unix_gid;
+
+ /** OS-9 permissions, set if @ref LHA_FILE_OS9_PERMS is set. */
+ unsigned int os9_perms;
+
+ /** Unix username. */
+ char *unix_username;
+
+ /** Unix group name. */
+ char *unix_group;
+
+ /** 16-bit CRC of header contents. */
+ uint16_t common_crc;
+
+ /**
+ * Windows FILETIME file creation time, set if
+ * @ref LHA_FILE_WINDOWS_TIMESTAMPS is set.
+ */
+ uint64_t win_creation_time;
+
+ /**
+ * Windows FILETIME file modification time, set if
+ * @ref LHA_FILE_WINDOWS_TIMESTAMPS is set.
+ */
+ uint64_t win_modification_time;
+
+ /**
+ * Windows FILETIME file access time, set if
+ * @ref LHA_FILE_WINDOWS_TIMESTAMPS is set.
+ */
+ uint64_t win_access_time;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef LHASA_PUBLIC_LHA_FILE_HEADER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h
new file mode 100644
index 00000000..7dfe0371
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h
@@ -0,0 +1,134 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+
+#ifndef LHASA_PUBLIC_LHA_INPUT_STREAM_H
+#define LHASA_PUBLIC_LHA_INPUT_STREAM_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file lha_input_stream.h
+ *
+ * @brief LHA input stream structure.
+ *
+ * This file defines the functions relating to the @ref LHAInputStream
+ * structure, used to read data from an LZH file.
+ */
+
+/**
+ * Opaque structure, representing an input stream used to read data from
+ * an LZH file.
+ */
+
+typedef struct _LHAInputStream LHAInputStream;
+
+/**
+ * Structure containing pointers to callback functions to read data from
+ * the input stream.
+ */
+
+typedef struct {
+
+ /**
+ * Read a block of data into the specified buffer.
+ *
+ * @param handle Handle pointer.
+ * @param buf Pointer to buffer in which to store read data.
+ * @param buf_len Size of buffer, in bytes.
+ * @return Number of bytes read, or -1 for error.
+ */
+
+ int (*read)(void *handle, void *buf, size_t buf_len);
+
+
+ /**
+ * Skip the specified number of bytes from the input stream.
+ * This is an optional function.
+ *
+ * @param handle Handle pointer.
+ * @param bytes Number of bytes to skip.
+ * @return Non-zero for success, or zero for failure.
+ */
+
+ int (*skip)(void *handle, size_t bytes);
+
+ /**
+ * Close the input stream.
+ *
+ * @param handle Handle pointer.
+ */
+
+ void (*close)(void *handle);
+
+} LHAInputStreamType;
+
+/**
+ * Create new @ref LHAInputStream structure, using a set of generic functions
+ * to provide LHA data.
+ *
+ * @param type Pointer to a @ref LHAInputStreamType structure
+ * containing callback functions to read data.
+ * @param handle Handle pointer to be passed to callback functions.
+ * @return Pointer to a new @ref LHAInputStream or NULL for error.
+ */
+
+LHAInputStream *lha_input_stream_new(const LHAInputStreamType *type,
+ void *handle);
+
+/**
+ * Create new @ref LHAInputStream, reading from the specified filename.
+ * The file is automatically closed when the input stream is freed.
+ *
+ * @param filename Name of the file to read from.
+ * @return Pointer to a new @ref LHAInputStream or NULL for error.
+ */
+
+LHAInputStream *lha_input_stream_from(char *filename);
+
+/**
+ * Create new @ref LHAInputStream, to read from an already-open FILE pointer.
+ * The FILE is not closed when the input stream is freed; the calling code
+ * must close it.
+ *
+ * @param stream The open FILE structure from which to read data.
+ * @return Pointer to a new @ref LHAInputStream or NULL for error.
+ */
+
+LHAInputStream *lha_input_stream_from_FILE(FILE *stream);
+
+/**
+ * Free an @ref LHAInputStream structure.
+ *
+ * @param stream The input stream.
+ */
+
+void lha_input_stream_free(LHAInputStream *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef LHASA_PUBLIC_LHA_INPUT_STREAM_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h
new file mode 100644
index 00000000..bd722bca
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h
@@ -0,0 +1,217 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_PUBLIC_LHA_READER_H
+#define LHASA_PUBLIC_LHA_READER_H
+
+#include "lha_decoder.h"
+#include "lha_input_stream.h"
+#include "lha_file_header.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file lha_reader.h
+ *
+ * @brief LHA file reader.
+ *
+ * This file contains the interface functions for the @ref LHAReader
+ * structure, used to decode data from a compressed LZH file and
+ * extract compressed files.
+ */
+
+/**
+ * Opaque structure used to decode the contents of an LZH file.
+ */
+
+typedef struct _LHAReader LHAReader;
+
+/**
+ * Policy for extracting directories.
+ *
+ * When extracting a directory, some of the metadata associated with
+ * it needs to be set after the contents of the directory have been
+ * extracted. This includes the modification time (which would
+ * otherwise be reset to the current time) and the permissions (which
+ * can affect the ability to extract files into the directory).
+ * To work around this problem there are several ways of handling
+ * directory extraction.
+ */
+
+typedef enum {
+
+ /**
+ * "Plain" policy. In this mode, the metadata is set at the
+ * same time that the directory is created. This is the
+ * simplest to comprehend, and the files returned from
+ * @ref lha_reader_next_file will match the files in the
+ * archive, but it is not recommended.
+ */
+
+ LHA_READER_DIR_PLAIN,
+
+ /**
+ * "End of directory" policy. In this mode, if a directory
+ * is extracted, the directory name will be saved. Once the
+ * contents of the directory appear to have been extracted
+ * (ie. a file is found that is not within the directory),
+ * the directory will be returned again by
+ * @ref lha_reader_next_file. This time, when the directory
+ * is "extracted" (via @ref lha_reader_extract), the metadata
+ * will be set.
+ *
+ * This method uses less memory than
+ * @ref LHA_READER_DIR_END_OF_FILE, but there is the risk
+ * that a file will appear within the archive after the
+ * metadata has been set for the directory. However, this is
+ * not normally the case, as files and directories typically
+ * appear within an archive in order. GNU tar uses the same
+ * method to address this problem with tar files.
+ *
+ * This is the default policy.
+ */
+
+ LHA_READER_DIR_END_OF_DIR,
+
+ /**
+ * "End of file" policy. In this mode, each directory that
+ * is extracted is recorded in a list. When the end of the
+ * archive is reached, these directories are returned again by
+ * @ref lha_reader_next_file. When the directories are
+ * "extracted" again (via @ref lha_reader_extract), the
+ * metadata is set.
+ *
+ * This avoids the problems that can potentially occur with
+ * @ref LHA_READER_DIR_END_OF_DIR, but uses more memory.
+ */
+
+ LHA_READER_DIR_END_OF_FILE
+
+} LHAReaderDirPolicy;
+
+/**
+ * Create a new @ref LHAReader to read data from an @ref LHAInputStream.
+ *
+ * @param stream The input stream to read data from.
+ * @return Pointer to a new @ref LHAReader structure,
+ * or NULL for error.
+ */
+
+LHAReader *lha_reader_new(LHAInputStream *stream);
+
+/**
+ * Free a @ref LHAReader structure.
+ *
+ * @param reader The @ref LHAReader structure.
+ */
+
+void lha_reader_free(LHAReader *reader);
+
+/**
+ * Set the @ref LHAReaderDirPolicy used to extract directories.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @param policy The policy to use for directories.
+ */
+
+void lha_reader_set_dir_policy(LHAReader *reader,
+ LHAReaderDirPolicy policy);
+
+/**
+ * Read the header of the next archived file from the input stream.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @return Pointer to an @ref LHAFileHeader structure, or NULL if
+ * an error occurred. This pointer is only valid until
+ * the next time that lha_reader_next_file is called.
+ */
+
+LHAFileHeader *lha_reader_next_file(LHAReader *reader);
+
+/**
+ * Read some of the (decompresed) data for the current archived file,
+ * decompressing as appropriate.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @param buf Pointer to a buffer in which to store the data.
+ * @param buf_len Size of the buffer, in bytes.
+ * @return Number of bytes stored in the buffer, or zero if
+ * there is no more data to decompress.
+ */
+
+size_t lha_reader_read(LHAReader *reader, void *buf, size_t buf_len);
+
+/**
+ * Decompress the contents of the current archived file, and check
+ * that the checksum matches correctly.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @param callback Callback function to invoke to monitor progress (or
+ * NULL if progress does not need to be monitored).
+ * @param callback_data Extra data to pass to the callback function.
+ * @return Non-zero if the checksum matches.
+ */
+
+int lha_reader_check(LHAReader *reader,
+ LHADecoderProgressCallback callback,
+ void *callback_data);
+
+/**
+ * Extract the contents of the current archived file.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @param filename Filename to extract the archived file to, or NULL
+ * to use the path and filename from the header.
+ * @param callback Callback function to invoke to monitor progress (or
+ * NULL if progress does not need to be monitored).
+ * @param callback_data Extra data to pass to the callback function.
+ * @return Non-zero for success, or zero for failure (including
+ * CRC error).
+ */
+
+int lha_reader_extract(LHAReader *reader,
+ char *filename,
+ LHADecoderProgressCallback callback,
+ void *callback_data);
+
+/**
+ * Check if the current file (last returned by @ref lha_reader_next_file)
+ * was generated internally by the extract process. This occurs when a
+ * directory or symbolic link must be created as a two-stage process, with
+ * some of the extraction process deferred to later in the stream.
+ *
+ * These "fake" duplicates should usually be hidden in the user interface
+ * when a summary of extraction is presented.
+ *
+ * @param reader The @ref LHAReader structure.
+ * @return Non-zero if the current file is a "fake", or zero
+ * for a normal file.
+ */
+
+int lha_reader_current_is_fake(LHAReader *reader);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef LHASA_PUBLIC_LHA_READER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h
new file mode 100644
index 00000000..7a1b63cd
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h
@@ -0,0 +1,30 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_PUBLIC_LHASA_H
+#define LHASA_PUBLIC_LHASA_H
+
+#include "lha_decoder.h"
+#include "lha_file_header.h"
+#include "lha_input_stream.h"
+#include "lha_reader.h"
+
+#endif /* #ifndef LHASA_PUBLIC_LHASA_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c
new file mode 100644
index 00000000..a52a91ab
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c
@@ -0,0 +1,252 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+// Common tree decoding code.
+//
+// A recurring feature used by the different LHA algorithms is to
+// encode a set of codes, which have varying bit lengths. This is
+// implemented using a binary tree, stored inside an array of
+// elements.
+//
+// This file is implemented as a "template" file to be #include-d by
+// other files. The typedef for TreeElement must be defined before
+// include.
+
+
+// Upper bit is set in a node value to indicate a leaf.
+
+#define TREE_NODE_LEAF (TreeElement) (1 << (sizeof(TreeElement) * 8 - 1))
+
+// Structure used to hold data needed to build the tree.
+
+typedef struct {
+ // The tree data and its size (must not be exceeded)
+
+ TreeElement *tree;
+ unsigned int tree_len;
+
+ // Counter used to allocate entries from the tree.
+ // Every time a new node is allocated, this increase by 2.
+
+ unsigned int tree_allocated;
+
+ // The next tree entry.
+ // As entries are allocated sequentially, the range from
+ // next_entry..tree_allocated-1 constitutes the indices into
+ // the tree that are available to be filled in. By the
+ // end of the tree build, next_entry should = tree_allocated.
+
+ unsigned int next_entry;
+} TreeBuildData;
+
+// Initialize all elements of the given tree to a good initial state.
+
+static void init_tree(TreeElement *tree, size_t tree_len)
+{
+ unsigned int i;
+
+ for (i = 0; i < tree_len; ++i) {
+ tree[i] = TREE_NODE_LEAF;
+ }
+}
+
+// Set tree to always decode to a single code.
+
+static void set_tree_single(TreeElement *tree, TreeElement code)
+{
+ tree[0] = (TreeElement) code | TREE_NODE_LEAF;
+}
+
+// "Expand" the list of queue entries. This generates a new child
+// node at each of the entries currently in the queue, adding the
+// children of those nodes into the queue to replace them.
+// The effect of this is to add an extra level to the tree, and
+// to increase the tree depth of the indices in the queue.
+
+static void expand_queue(TreeBuildData *build)
+{
+ unsigned int end_offset;
+ unsigned int new_nodes;
+
+ // Sanity check that there is enough space in the tree for
+ // all the new nodes.
+
+ new_nodes = (build->tree_allocated - build->next_entry) * 2;
+
+ if (build->tree_allocated + new_nodes > build->tree_len) {
+ return;
+ }
+
+ // Go through all entries currently in the allocated range, and
+ // allocate a subnode for each.
+
+ end_offset = build->tree_allocated;
+
+ while (build->next_entry < end_offset) {
+ build->tree[build->next_entry] = build->tree_allocated;
+ build->tree_allocated += 2;
+ ++build->next_entry;
+ }
+}
+
+// Read the next entry from the queue of entries waiting to be used.
+
+static unsigned int read_next_entry(TreeBuildData *build)
+{
+ unsigned int result;
+
+ // Sanity check.
+
+ if (build->next_entry >= build->tree_allocated) {
+ return 0;
+ }
+
+ result = build->next_entry;
+ ++build->next_entry;
+
+ return result;
+}
+
+// Add all codes to the tree that have the specified length.
+// Returns non-zero if there are any entries in code_lengths[] still
+// waiting to be added to the tree.
+
+static int add_codes_with_length(TreeBuildData *build,
+ uint8_t *code_lengths,
+ unsigned int num_code_lengths,
+ unsigned int code_len)
+{
+ unsigned int i;
+ unsigned int node;
+ int codes_remaining;
+
+ codes_remaining = 0;
+
+ for (i = 0; i < num_code_lengths; ++i) {
+
+ // Does this code belong at this depth in the tree?
+
+ if (code_lengths[i] == code_len) {
+ node = read_next_entry(build);
+
+ build->tree[node] = (TreeElement) i | TREE_NODE_LEAF;
+ }
+
+ // More work to be done after this pass?
+
+ else if (code_lengths[i] > code_len) {
+ codes_remaining = 1;
+ }
+ }
+
+ return codes_remaining;
+}
+
+// Build a tree, given the specified array of codes indicating the
+// required depth within the tree at which each code should be
+// located.
+
+static void build_tree(TreeElement *tree, size_t tree_len,
+ uint8_t *code_lengths, unsigned int num_code_lengths)
+{
+ TreeBuildData build;
+ unsigned int code_len;
+
+ build.tree = tree;
+ build.tree_len = tree_len;
+
+ // Start with a single entry in the queue - the root node
+ // pointer.
+
+ build.next_entry = 0;
+
+ // We always have the root ...
+
+ build.tree_allocated = 1;
+
+ // Iterate over each possible code length.
+ // Note: code_len == 0 is deliberately skipped over, as 0
+ // indicates "not used".
+
+ code_len = 0;
+
+ do {
+ // Advance to the next code length by allocating extra
+ // nodes to the tree - the slots waiting in the queue
+ // will now be one level deeper in the tree (and the
+ // codes 1 bit longer).
+
+ expand_queue(&build);
+ ++code_len;
+
+ // Add all codes that have this length.
+
+ } while (add_codes_with_length(&build, code_lengths,
+ num_code_lengths, code_len));
+}
+
+/*
+static void display_tree(TreeElement *tree, unsigned int node, int offset)
+{
+ unsigned int i;
+
+ if (node & TREE_NODE_LEAF) {
+ for (i = 0; i < offset; ++i) putchar(' ');
+ printf("leaf %i\n", node & ~TREE_NODE_LEAF);
+ } else {
+ for (i = 0; i < offset; ++i) putchar(' ');
+ printf("0 ->\n");
+ display_tree(tree, tree[node], offset + 4);
+ for (i = 0; i < offset; ++i) putchar(' ');
+ printf("1 ->\n");
+ display_tree(tree, tree[node + 1], offset + 4);
+ }
+}
+*/
+
+// Read bits from the input stream, traversing the specified tree
+// from the root node until we reach a leaf. The leaf value is
+// returned.
+
+static int read_from_tree(BitStreamReader *reader, TreeElement *tree)
+{
+ TreeElement code;
+ int bit;
+
+ // Start from root.
+
+ code = tree[0];
+
+ while ((code & TREE_NODE_LEAF) == 0) {
+
+ bit = read_bit(reader);
+
+ if (bit < 0) {
+ return -1;
+ }
+
+ code = tree[code + (unsigned int) bit];
+ }
+
+ // Mask off leaf bit to get the plain code.
+
+ return (int) (code & ~TREE_NODE_LEAF);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in b/Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in
new file mode 100644
index 00000000..e0400716
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: liblhasa
+Description: LHA (de)compression library
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -llhasa
+Cflags: -I${includedir}/liblhasa-1.0
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am
new file mode 100644
index 00000000..4f6b5884
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am
@@ -0,0 +1,5 @@
+
+EXTRA_DIST = \
+win32/GNUmakefile \
+win32/README
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in
new file mode 100644
index 00000000..398203c9
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in
@@ -0,0 +1,18 @@
+# This file is included by package makefiles, it is autogenerated
+# by configure.
+
+CC = @CC@
+STRIP = @STRIP@
+
+PACKAGE = @PACKAGE@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+
+# Documentation files to distribute with packages.
+
+DOC_FILES = README \
+ COPYING \
+ NEWS
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile
new file mode 100644
index 00000000..a40ab6b1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile
@@ -0,0 +1,26 @@
+
+include ../config.make
+
+TOPLEVEL=../..
+
+EXE_FILES=$(TOPLEVEL)/src/lha.exe
+
+ZIP=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-win32.zip
+
+$(ZIP): staging
+ zip -j -r $@ staging/
+
+staging: $(EXE_FILES) $(patsubst %,$(TOPLEVEL)/%,$(DOC_FILES))
+ rm -rf staging
+ mkdir staging
+ cp $(EXE_FILES) staging/
+ $(STRIP) staging/*.exe
+ for f in $(DOC_FILES); do \
+ cp $(TOPLEVEL)/$$f staging/$$f.txt; \
+ unix2dos staging/$$f.txt; \
+ done
+ groff -Thtml -mandoc $(TOPLEVEL)/doc/lha.1 > staging/lha.html
+
+clean:
+ rm -rf $(ZIP)
+ rm -rf staging
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README
new file mode 100644
index 00000000..da303624
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README
@@ -0,0 +1,9 @@
+
+Makefile to build Windows packages. Requires zip and unix2dos cygwin
+packages to be installed.
+
+The configure script should be run with the right options to disable
+shared libraries:
+
+ ./configure --disable-shared --enable-static
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in b/Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in
new file mode 100644
index 00000000..63f8b0da
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in
@@ -0,0 +1,53 @@
+
+Name: @PACKAGE@
+Summary: Free LZH archive tool
+Version: @VERSION@
+Release: 1
+Source: https://github.com/downloads/fragglet/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz
+URL: http://fragglet.github.com/lhasa/
+Group: Applications/Archiving
+BuildRoot: /var/tmp/@PACKAGE@-buildroot
+License: ISC license
+Packager: Simon Howard <@PACKAGE_BUGREPORT@>
+Prefix: %{_prefix}
+Autoreq: 0
+
+%description
+%(cat README)
+
+See @PACKAGE_URL@ for more information.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -q
+
+%build
+./configure \
+ --prefix=/usr \
+ --exec-prefix=/usr \
+ --bindir=/usr/bin \
+ --sbindir=/usr/sbin \
+ --sysconfdir=/etc \
+ --datadir=/usr/share \
+ --includedir=/usr/include \
+ --libdir=/usr/lib \
+ --libexecdir=/usr/lib \
+ --localstatedir=/var/lib \
+ --sharedstatedir=/usr/com \
+ --mandir=/usr/share/man \
+ --infodir=/usr/share/info
+make
+
+%install
+%makeinstall
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%doc %{_mandir}/man1/*
+/usr/bin/*
+/usr/lib*/*
+/usr/include/*/*
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am
new file mode 100644
index 00000000..5d3af87b
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am
@@ -0,0 +1,23 @@
+
+bin_PROGRAMS=lha
+check_PROGRAMS=test-lha
+
+SOURCE_FILES= \
+ main.c \
+ options.h \
+ filter.c filter.h \
+ list.c list.h \
+ extract.c extract.h \
+ safe.c safe.h
+
+lha_SOURCES=$(SOURCE_FILES)
+lha_CFLAGS=$(MAIN_CFLAGS) -I$(top_builddir)/lib/public -I$(top_builddir)
+lha_LDADD=$(top_builddir)/lib/liblhasa.la
+
+test_lha_SOURCES=$(SOURCE_FILES)
+test_lha_CFLAGS=$(TEST_CFLAGS) -I$(top_builddir)/lib/public -I$(top_builddir)
+test_lha_LDADD=$(top_builddir)/lib/liblhasatest.a
+
+clean-local:
+ rm -f *.gcno *.gcda *.c.gcov
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt
new file mode 100644
index 00000000..e66baf04
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt
@@ -0,0 +1,76 @@
+
+Notes on command line arguments:
+
+Mode - must be the first character of the first argument. Leading '-'
+is ignored:
+
+ e/x - Extract
+ l/v - List (normal / verbose mode)
+ t - Test CRC
+ p - Print files to STDOUT
+
+Options - flags following the mode character. Options are accepted
+even if they are inappropriate for the mode, eg. "lha lf".
+
+ q[level] - Quiet mode. Normal running is quiet level 0.
+
+ in list mode, quiet level 2 strips header/footer from
+ listing.
+
+ in extract mode, overwrite is always performed, and:
+ - at quiet level 1, the 'progress bar' is not shown.
+ - at quiet level 2, no messages are printed at all.
+
+ in test mode, behavior is similar to extract mode, but
+ level 2 behavior is similar to level 0.
+
+ in print mode, at quiet level 2 the filename is not
+ printed before the file contents.
+
+ all quiet modes imply 'f', disabling overwrite without
+ confirmation.
+
+ f - Force overwrite. When extracting, existing files are
+ overwritten with no confirmation.
+
+ n - Don't execute commands, just do a dry run of what would
+ be done.
+
+ eg. for lha en:
+
+ EXTRACT lhasa/src/ (directory)
+ EXTRACT lhasa/src/extract.c
+ EXTRACT lhasa/src/extract.c but file is exist.
+
+ eg. for lha tn:
+
+ VERIFY lhasa/src/main.c
+
+ i - Ignore directory path. When extracting, the directory
+ of each file is ignored - they are all extracted into
+ the same directory.
+
+ Also applies to test mode - the output filename of the
+ tested file does not include the directory.
+
+ In print mode, the path is not printed in the header
+ before each file.
+
+ v - Verbose mode, prints extra information.
+
+ in list mode, verbose mode splits the filename onto a
+ separate preceding line and the header level is shown
+ in its normal place.
+
+ in extract mode, verbose mode prints a message when
+ creating a directory. If creating missing parent directories,
+ they are printed in reverse order, eg.
+
+ Making directory "lhasa/src".
+ Making directory "lhasa".
+ lhasa/src/main.c - Melted : o
+
+ w=dir - Specify destination directory to extract files. Must be
+ the last option specified. '=' can be omitted. If combined
+ with 'i', all files get placed in that one directory.
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c
new file mode 100644
index 00000000..1e7f5c92
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c
@@ -0,0 +1,676 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "lib/lha_arch.h"
+
+#include "extract.h"
+#include "safe.h"
+
+// Maximum number of dots in progress output:
+
+#define MAX_PROGRESS_LEN 58
+
+typedef struct {
+ int invoked;
+ LHAFileHeader *header;
+ LHAOptions *options;
+ char *filename;
+ char *operation;
+} ProgressCallbackData;
+
+// Given a file header structure, get the path to extract to.
+// Returns a newly allocated string that must be free()d.
+
+static char *file_full_path(LHAFileHeader *header, LHAOptions *options)
+{
+ size_t len;
+ char *result;
+ char *p;
+
+ // Full path, or filename only?
+
+ len = 0;
+
+ if (options->extract_path != NULL) {
+ len += strlen(options->extract_path) + 1;
+ }
+
+ if (options->use_path && header->path != NULL) {
+ len += strlen(header->path);
+ }
+
+ if (header->filename != NULL) {
+ len += strlen(header->filename);
+ }
+
+ result = malloc(len + 1);
+
+ if (result == NULL) {
+ // TODO?
+ exit(-1);
+ }
+
+ result[0] = '\0';
+
+ if (options->extract_path != NULL) {
+ strcat(result, options->extract_path);
+ strcat(result, "/");
+ }
+
+ // Add path. If it is an absolute path (contains a leading '/')
+ // then skip over the leading '/' to make it a relative path.
+ // This prevents the possibility of a security threat with a
+ // malicious archive that might try to write to arbitrary
+ // filesystem locations.
+ // It also removes the double '/' when using the -w option.
+
+ if (options->use_path && header->path != NULL) {
+ p = header->path;
+ while (*p == '/') {
+ ++p;
+ }
+ strcat(result, p);
+ }
+
+ // The filename header field might conceivably try to include
+ // a path separator as well, so skip over any leading '/'
+ // here too.
+
+ if (header->filename != NULL) {
+ p = header->filename;
+ while (*p == '/') {
+ ++p;
+ }
+ strcat(result, p);
+ }
+
+ return result;
+}
+
+static void print_filename(char *filename, char *status)
+{
+ printf("\r");
+ safe_printf("%s", filename);
+ printf("\t- %s ", status);
+}
+
+static void print_filename_brief(char *filename)
+{
+ printf("\r");
+ safe_printf("%s :", filename);
+}
+
+// Callback function invoked during decompression progress.
+
+static void progress_callback(unsigned int block,
+ unsigned int num_blocks,
+ void *data)
+{
+ ProgressCallbackData *progress = data;
+ unsigned int factor;
+ unsigned int i;
+
+ progress->invoked = 1;
+
+ // If the quiet mode options are specified, print a limited amount
+ // of information without a progress bar (level 1) or no message
+ // at all (level 2).
+
+ if (progress->options->quiet >= 2) {
+ return;
+ } else if (progress->options->quiet == 1) {
+ if (block == 0) {
+ print_filename_brief(progress->filename);
+ fflush(stdout);
+ }
+
+ return;
+ }
+
+ // Scale factor for blocks, so that the line is never too long. When
+ // MAX_PROGRESS_LEN is exceeded, the length is halved (factor=2), then
+ // progressively larger scale factors are applied.
+
+ factor = 1 + (num_blocks / MAX_PROGRESS_LEN);
+ num_blocks = (num_blocks + factor - 1) / factor;
+
+ // First call to specify number of blocks?
+
+ if (block == 0) {
+ print_filename(progress->filename, progress->operation);
+
+ for (i = 0; i < num_blocks; ++i) {
+ printf(".");
+ }
+
+ print_filename(progress->filename, progress->operation);
+ } else if (((block + factor - 1) % factor) == 0) {
+ // Otherwise, signal progress:
+
+ printf("o");
+ }
+
+ fflush(stdout);
+}
+
+// Print a line to stdout describing a symlink.
+
+static void print_symlink_line(char *src, char *dest)
+{
+ safe_printf("Symbolic Link %s -> %s", src, dest);
+ printf("\n");
+}
+
+// Perform CRC check of an archived file.
+
+static int test_archived_file_crc(LHAReader *reader,
+ LHAFileHeader *header,
+ LHAOptions *options)
+{
+ ProgressCallbackData progress;
+ char *filename;
+ int success;
+
+ filename = file_full_path(header, options);
+
+ if (options->dry_run) {
+ if (strcmp(header->compress_method,
+ LHA_COMPRESS_TYPE_DIR) != 0) {
+ safe_printf("VERIFY %s", filename);
+ printf("\n");
+ }
+
+ free(filename);
+ return 1;
+ }
+
+ progress.invoked = 0;
+ progress.operation = "Testing :";
+ progress.options = options;
+ progress.filename = filename;
+ progress.header = header;
+
+ success = lha_reader_check(reader, progress_callback, &progress);
+
+ if (progress.invoked && options->quiet < 2) {
+ if (success) {
+ print_filename(filename, "Tested");
+ printf("\n");
+ } else {
+ print_filename(filename, "CRC error");
+ printf("\n");
+ }
+
+ fflush(stdout);
+ }
+
+ if (!success) {
+ // TODO: Exit with error
+ }
+
+ free(filename);
+
+ return success;
+}
+
+// Check that the specified directory exists, and create it if it
+// does not.
+
+static int check_parent_directory(char *path)
+{
+ LHAFileType file_type;
+
+ file_type = lha_arch_exists(path);
+
+ switch (file_type) {
+
+ case LHA_FILE_DIRECTORY:
+ // Already exists.
+ break;
+
+ case LHA_FILE_NONE:
+ // Create the missing directory:
+
+ if (!lha_arch_mkdir(path, 0755)) {
+ fprintf(stderr,
+ "Failed to create parent directory %s\n",
+ path);
+ return 0;
+ }
+ break;
+
+ case LHA_FILE_FILE:
+ fprintf(stderr, "Parent path %s is not a directory!\n",
+ path);
+ return 0;
+
+ case LHA_FILE_ERROR:
+ fprintf(stderr, "Failed to stat %s\n", path);
+ return 0;
+ }
+
+ return 1;
+}
+
+// Given a filename, create its parent directories as necessary.
+
+static int make_parent_directories(char *orig_path)
+{
+ int result;
+ char *p;
+ char *path;
+
+ result = 1;
+
+ // Duplicate the path and strip off any trailing '/'s:
+
+ path = strdup(orig_path);
+
+ if (path == NULL) {
+ exit(-1);
+ }
+
+ p = path + strlen(path) - 1;
+
+ while (p >= path && *p == '/') {
+ *p = '\0';
+ --p;
+ }
+
+ // Iterate through the string, finding each path separator. At
+ // each place, temporarily chop off the end of the path to get
+ // each parent directory in turn.
+
+ for (p = path; *p == '/'; ++p);
+
+ for (;;) {
+ p = strchr(p, '/');
+
+ if (p == NULL) {
+ break;
+ }
+
+ *p = '\0';
+
+ // Check if this parent directory exists and create it:
+
+ if (!check_parent_directory(path)) {
+ result = 0;
+ break;
+ }
+
+ // Restore path separator and advance to the next path.
+
+ *p = '/';
+ ++p;
+ }
+
+ free(path);
+
+ return result;
+}
+
+// Prompt the user with a message, and return the first character of
+// the typed response.
+
+static char prompt_user(char *message)
+{
+ char result;
+ int c;
+
+ fprintf(stderr, "%s", message);
+ fflush(stderr);
+
+ // Read characters until a newline is found, saving the first
+ // character entered.
+
+ result = 0;
+
+ do {
+ c = getchar();
+
+ if (c < 0) {
+ exit(-1);
+ }
+
+ if (result == 0) {
+ result = c;
+ }
+ } while (c != '\n');
+
+ return result;
+}
+
+// A file to be extracted already exists. Apply the overwrite policy
+// to decide whether to overwrite the existing file, prompting the
+// user if necessary.
+
+static int confirm_file_overwrite(char *filename, LHAOptions *options)
+{
+ char response;
+
+ switch (options->overwrite_policy) {
+ case LHA_OVERWRITE_PROMPT:
+ break;
+ case LHA_OVERWRITE_SKIP:
+ return 0;
+ case LHA_OVERWRITE_ALL:
+ return 1;
+ }
+
+ for (;;) {
+ safe_fprintf(stderr, "%s ", filename);
+
+ response = prompt_user("OverWrite ?(Yes/[No]/All/Skip) ");
+
+ switch (tolower((unsigned int) response)) {
+ case 'y':
+ return 1;
+ case 'n':
+ case '\n':
+ return 0;
+ case 'a':
+ options->overwrite_policy = LHA_OVERWRITE_ALL;
+ return 1;
+ case 's':
+ options->overwrite_policy = LHA_OVERWRITE_SKIP;
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+// Check if the file pointed to by the specified header exists.
+
+static int file_exists(char *filename)
+{
+ LHAFileType file_type;
+
+ file_type = lha_arch_exists(filename);
+
+ if (file_type == LHA_FILE_ERROR) {
+ fprintf(stderr, "Failed to read file type of '%s'\n", filename);
+ exit(-1);
+ }
+
+ return file_type != LHA_FILE_NONE;
+}
+
+// Extract an archived file.
+
+static int extract_archived_file(LHAReader *reader,
+ LHAFileHeader *header,
+ LHAOptions *options)
+{
+ ProgressCallbackData progress;
+ char *filename;
+ int success;
+ int is_dir, is_symlink;
+
+ filename = file_full_path(header, options);
+ is_symlink = header->symlink_target != NULL;
+ is_dir = !strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR)
+ && !is_symlink;
+
+ // If a file already exists with this name, confirm overwrite.
+
+ if (!is_dir && !is_symlink && file_exists(filename)
+ && !confirm_file_overwrite(filename, options)) {
+ if (options->overwrite_policy == LHA_OVERWRITE_SKIP) {
+ safe_printf("%s : Skipped...", filename);
+ printf("\n");
+ }
+ free(filename);
+ return 1;
+ }
+
+ // No need to extract directories if use_path is disabled.
+
+ if (!options->use_path && is_dir) {
+ return 1;
+ }
+
+ // Create parent directories for file:
+
+ if (!make_parent_directories(filename)) {
+ free(filename);
+ return 0;
+ }
+
+ progress.invoked = 0;
+ progress.operation = "Melting :";
+ progress.options = options;
+ progress.header = header;
+ progress.filename = filename;
+
+ success = lha_reader_extract(reader, filename,
+ progress_callback, &progress);
+
+ if (!lha_reader_current_is_fake(reader) && options->quiet < 2) {
+ if (progress.invoked) {
+ if (success) {
+ print_filename(filename, "Melted");
+ printf("\n");
+ } else {
+ print_filename(filename, "Failure");
+ printf("\n");
+ }
+ } else if (is_symlink) {
+ print_symlink_line(filename, header->symlink_target);
+ }
+
+ fflush(stdout);
+ }
+
+ if (!success) {
+ // TODO: Exit with error
+ }
+
+ free(filename);
+
+ return success;
+}
+
+// lha -t command.
+
+int test_file_crc(LHAFilter *filter, LHAOptions *options)
+{
+ int result;
+
+ result = 1;
+
+ for (;;) {
+ LHAFileHeader *header;
+
+ header = lha_filter_next_file(filter);
+
+ if (header == NULL) {
+ break;
+ }
+
+ if (!test_archived_file_crc(filter->reader, header, options)) {
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+// lha -en / -xn / -pn:
+// Simulate extracting an archive file, but just print the operations
+// that would have been performed to stdout.
+
+static int extract_archive_dry_run(LHAFilter *filter, LHAOptions *options)
+{
+ char *filename;
+ int result;
+
+ result = 1;
+
+ for (;;) {
+ LHAFileHeader *header;
+
+ header = lha_filter_next_file(filter);
+
+ if (header == NULL) {
+ break;
+ }
+
+ filename = file_full_path(header, options);
+
+ // Every line begins the same - "EXTRACT filename..."
+
+ safe_printf("EXTRACT %s", filename);
+
+ // After the filename we might print something extra.
+ // The message if we have an existing file is weird, but this
+ // is just accurately duplicating what the Unix LHA tool says.
+ // The symlink handling is particularly odd - they are treated
+ // as directories (a bleed-through of the way in which
+ // symlinks are stored).
+
+ if (header->symlink_target != NULL) {
+ safe_printf("|%s (directory)", header->symlink_target);
+ } else if (!strcmp(header->compress_method,
+ LHA_COMPRESS_TYPE_DIR)) {
+ safe_printf(" (directory)");
+ } else if (file_exists(filename)) {
+ safe_printf(" but file is exist.");
+ }
+ printf("\n");
+
+ free(filename);
+ }
+
+ return result;
+}
+
+// lha -e / -x
+
+int extract_archive(LHAFilter *filter, LHAOptions *options)
+{
+ int result;
+
+ if (options->dry_run) {
+ return extract_archive_dry_run(filter, options);
+ }
+
+ result = 1;
+
+ for (;;) {
+ LHAFileHeader *header;
+
+ header = lha_filter_next_file(filter);
+
+ if (header == NULL) {
+ break;
+ }
+
+ if (!extract_archived_file(filter->reader, header, options)) {
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+// Dump contents of the current file from the specified reader to stdout.
+
+static int print_archived_file(LHAReader *reader)
+{
+ char buf[512];
+ size_t bytes;
+
+ for (;;) {
+ bytes = lha_reader_read(reader, buf, sizeof(buf));
+ if (bytes <= 0) {
+ break;
+ }
+
+ if (fwrite(buf, 1, bytes, stdout) < bytes) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+// lha -p
+
+int print_archive(LHAFilter *filter, LHAOptions *options)
+{
+ LHAFileHeader *header;
+ int is_normal_file;
+ char *full_path;
+
+ // As a weird quirk of Unix LHA, lha -pn is equivalent to lha -en:
+
+ if (options->dry_run) {
+ return extract_archive_dry_run(filter, options);
+ }
+
+ for (;;) {
+ header = lha_filter_next_file(filter);
+
+ if (header == NULL) {
+ break;
+ }
+
+ is_normal_file = strcmp(header->compress_method,
+ LHA_COMPRESS_TYPE_DIR) != 0;
+
+ // Print "header" before the file containing the filename.
+ // For normal files this is a three line separator.
+ // Symlinks get shown in the same way as during extract.
+ // Directories are ignored.
+
+ if (options->quiet < 2) {
+ full_path = file_full_path(header, options);
+
+ if (header->symlink_target != NULL) {
+ print_symlink_line(full_path,
+ header->symlink_target);
+ } else if (is_normal_file) {
+ printf("::::::::\n");
+ safe_printf("%s", full_path);
+ printf("\n::::::::\n");
+ }
+
+ free(full_path);
+ }
+
+ // If this is a normal file, dump the contents to stdout.
+
+ if (is_normal_file && !print_archived_file(filter->reader)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h
new file mode 100644
index 00000000..c6a4c1a6
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h
@@ -0,0 +1,32 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_EXTRACT_H
+#define LHASA_EXTRACT_H
+
+#include "filter.h"
+#include "options.h"
+
+int test_file_crc(LHAFilter *filter, LHAOptions *options);
+int extract_archive(LHAFilter *filter, LHAOptions *options);
+int print_archive(LHAFilter *filter, LHAOptions *options);
+
+#endif /* #ifndef LHASA_EXTRACT_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c
new file mode 100644
index 00000000..c4534699
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c
@@ -0,0 +1,137 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "filter.h"
+
+void lha_filter_init(LHAFilter *filter, LHAReader *reader,
+ char **filters, unsigned int num_filters)
+{
+ filter->reader = reader;
+ filter->filters = filters;
+ filter->num_filters = num_filters;
+}
+
+static int match_glob(char *glob, char *str)
+{
+ // Iterate through the string, matching each character against the
+ // equivalent character from the glob.
+
+ while (*str != '\0') {
+
+ // When we reach a '*', cut off the remainder of the glob
+ // and shift forward through the string trying to find
+ // a point that matches it.
+
+ if (*glob == '*') {
+ if (match_glob(glob + 1, str)) {
+ return 1;
+ }
+ } else if (*glob == '?' || *glob == *str) {
+ ++glob;
+ } else {
+ return 0;
+ }
+
+ ++str;
+ }
+
+ // We have reached the end of the string to match against.
+ // Any '*'s left at the end of the string are superfluous and
+ // can be ignored.
+
+ while (*glob == '*') {
+ ++glob;
+ }
+
+ // We now have a successful match only if we have simultaneously
+ // matched the end of the glob.
+
+ return *glob == '\0';
+}
+
+static int matches_filter(LHAFilter *filter, LHAFileHeader *header)
+{
+ size_t path_len;
+ char *path;
+ unsigned int i;
+
+ // Special case: no filters means match all.
+
+ if (filter->num_filters == 0) {
+ return 1;
+ }
+
+ path_len = 0;
+
+ if (header->path != NULL) {
+ path_len += strlen(header->path);
+ }
+
+ if (header->filename != NULL) {
+ path_len += strlen(header->filename);
+ }
+
+ path = malloc(path_len + 1);
+
+ if (path == NULL) {
+ // TODO?
+ return 0;
+ }
+
+ path[0] = '\0';
+
+ if (header->path != NULL) {
+ strcat(path, header->path);
+ }
+
+ if (header->filename != NULL) {
+ strcat(path, header->filename);
+ }
+
+ // Check this path with the list of filters. If one matches,
+ // we must return true.
+
+ for (i = 0; i < filter->num_filters; ++i) {
+ if (match_glob(filter->filters[i], path)) {
+ break;
+ }
+ }
+
+ free(path);
+
+ return i < filter->num_filters;
+}
+
+LHAFileHeader *lha_filter_next_file(LHAFilter *filter)
+{
+ LHAFileHeader *header;
+
+ // Read through headers until we find one that matches.
+
+ do {
+ header = lha_reader_next_file(filter->reader);
+ } while (header != NULL && !matches_filter(filter, header));
+
+ return header;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h
new file mode 100644
index 00000000..01c4a48d
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h
@@ -0,0 +1,61 @@
+/*
+
+Copyright (c) 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_FILTER_H
+#define LHASA_FILTER_H
+
+#include "lha_reader.h"
+
+typedef struct _LHAFilter LHAFilter;
+
+struct _LHAFilter {
+ LHAReader *reader;
+ char **filters;
+ unsigned int num_filters;
+};
+
+/**
+ * Initialize a @ref LHAFilter structure to read files from
+ * the specified @ref LHAReader, applying the specified list of
+ * filters.
+ *
+ * @param filter The filter structure to initialize.
+ * @param reader The reader object to read files from.
+ * @param filters List of strings containing glob-style filters
+ * to apply to the filenames to read.
+ * @param num_filters Number of filters in the 'filters' array.
+ */
+
+void lha_filter_init(LHAFilter *filter, LHAReader *reader,
+ char **filters, unsigned int num_filters);
+
+/**
+ * Read the next file from the input stream.
+ *
+ * @param filter The filter structure.
+ * @return File header structure for the next file that
+ * matches the filters, or NULL for end of file
+ * or error.
+ */
+
+LHAFileHeader *lha_filter_next_file(LHAFilter *filter);
+
+#endif /* #ifndef LHASA_FILTER_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c
new file mode 100644
index 00000000..79b10d2c
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c
@@ -0,0 +1,682 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include <sys/stat.h>
+
+#include "lha_reader.h"
+#include "list.h"
+#include "safe.h"
+
+typedef struct {
+ unsigned int num_files;
+ unsigned int compressed_length;
+ unsigned int length;
+ unsigned int timestamp;
+} FileStatistics;
+
+typedef struct {
+ char *name;
+ unsigned int width;
+ void (*handler)(LHAFileHeader *header);
+ void (*footer)(FileStatistics *stats);
+} ListColumn;
+
+// Display OS type:
+
+static char *os_type_to_string(uint8_t os_type)
+{
+ switch (os_type) {
+ case LHA_OS_TYPE_MSDOS:
+ return "[MS-DOS]";
+ case LHA_OS_TYPE_WIN95:
+ return "[Win9x]";
+ case LHA_OS_TYPE_WINNT:
+ return "[WinNT]";
+ case LHA_OS_TYPE_UNIX:
+ return "[Unix]";
+ case LHA_OS_TYPE_OS2:
+ return "[OS/2]";
+ case LHA_OS_TYPE_CPM:
+ return "[CP/M]";
+ case LHA_OS_TYPE_MACOS:
+ return "[Mac OS]";
+ case LHA_OS_TYPE_JAVA:
+ return "[Java]";
+ case LHA_OS_TYPE_FLEX:
+ return "[FLEX]";
+ case LHA_OS_TYPE_RUNSER:
+ return "[Runser]";
+ case LHA_OS_TYPE_TOWNSOS:
+ return "[TownsOS]";
+ case LHA_OS_TYPE_OS9:
+ return "[OS-9]";
+ case LHA_OS_TYPE_OS9_68K:
+ return "[OS-9/68K]";
+ case LHA_OS_TYPE_OS386:
+ return "[OS-386]";
+ case LHA_OS_TYPE_HUMAN68K:
+ return "[Human68K]";
+ case LHA_OS_TYPE_ATARI:
+ return "[Atari]";
+ case LHA_OS_TYPE_AMIGA:
+ return "[Amiga]";
+ case LHA_OS_TYPE_UNKNOWN:
+ return "[generic]";
+ default:
+ return "[unknown]";
+ }
+}
+
+// Print Unix file permissions.
+
+static void unix_permissions_print(LHAFileHeader *header)
+{
+ const char *perms = "rwxrwxrwx";
+ unsigned int i;
+
+ if (strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR) != 0) {
+ printf("-");
+ } else if (header->symlink_target != NULL) {
+ printf("l");
+ } else {
+ printf("d");
+ }
+
+ for (i = 0; i < 9; ++i) {
+ if (header->unix_perms & (1U << (8 - i))) {
+ printf("%c", perms[i]);
+ } else {
+ printf("-");
+ }
+ }
+}
+
+// Print OS-9 file permissions.
+
+static void os9_permissions_print(LHAFileHeader *header)
+{
+ const char *perms = "sewrewr";
+ unsigned int i;
+
+ if (strcmp(header->compress_method, LHA_COMPRESS_TYPE_DIR) != 0) {
+ printf("-");
+ } else {
+ printf("d");
+ }
+
+ for (i = 0; i < 7; ++i) {
+ if (header->os9_perms & (1U << (6 - i))) {
+ printf("%c", perms[i]);
+ } else {
+ printf("-");
+ }
+ }
+
+ printf(" ");
+}
+
+// File permissions
+
+static void permission_column_print(LHAFileHeader *header)
+{
+ // Print permissions. If we do not have any permissions to
+ // print, fall back to printing the OS type.
+
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_OS9_PERMS)) {
+ os9_permissions_print(header);
+ } else if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
+ unix_permissions_print(header);
+ } else {
+ printf("%-10s", os_type_to_string(header->os_type));
+ }
+}
+
+static void permission_column_footer(FileStatistics *stats)
+{
+ printf(" Total ");
+}
+
+static ListColumn permission_column = {
+ " PERMSSN", 10,
+ permission_column_print,
+ permission_column_footer
+};
+
+// Unix UID/GID
+
+static void unix_uid_gid_column_print(LHAFileHeader *header)
+{
+ if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_UID_GID)) {
+ printf("%5i/%-5i", header->unix_uid, header->unix_gid);
+ } else {
+ printf(" ");
+ }
+}
+
+static void unix_uid_gid_column_footer(FileStatistics *stats)
+{
+ // The UID/GID column has the total number of files
+ // listed below it.
+
+ if (stats->num_files == 1) {
+ printf("%5i file ", stats->num_files);
+ } else {
+ printf("%5i files", stats->num_files);
+ }
+}
+
+static ListColumn unix_uid_gid_column = {
+ " UID GID", 11,
+ unix_uid_gid_column_print,
+ unix_uid_gid_column_footer
+};
+
+// Compressed file size
+
+static void packed_column_print(LHAFileHeader *header)
+{
+ printf("%7lu", (unsigned long) header->compressed_length);
+}
+
+static void packed_column_footer(FileStatistics *stats)
+{
+ printf("%7lu", (unsigned long) stats->compressed_length);
+}
+
+static ListColumn packed_column = {
+ " PACKED", 7,
+ packed_column_print,
+ packed_column_footer
+};
+
+// Uncompressed file size
+
+static void size_column_print(LHAFileHeader *header)
+{
+ printf("%7lu", (unsigned long) header->length);
+}
+
+static void size_column_footer(FileStatistics *stats)
+{
+ printf("%7lu", (unsigned long) stats->length);
+}
+
+static ListColumn size_column = {
+ " SIZE", 7,
+ size_column_print,
+ size_column_footer
+};
+
+// Compression ratio
+
+static float compression_percent(size_t compressed, size_t uncompressed)
+{
+ if (uncompressed > 0) {
+ return ((float) compressed * 100.0f) / (float) uncompressed;
+ } else {
+ return 100.0f;
+ }
+}
+
+static void ratio_column_print(LHAFileHeader *header)
+{
+ if (!strcmp(header->compress_method, "-lhd-")) {
+ printf("******");
+ } else {
+ printf("%5.1f%%", compression_percent(header->compressed_length,
+ header->length));
+ }
+}
+
+static void ratio_column_footer(FileStatistics *stats)
+{
+ if (stats->length == 0) {
+ printf("******");
+ } else {
+ printf("%5.1f%%", compression_percent(stats->compressed_length,
+ stats->length));
+ }
+}
+
+static ListColumn ratio_column = {
+ " RATIO", 6,
+ ratio_column_print,
+ ratio_column_footer
+};
+
+// Compression method and CRC checksum
+
+static void method_crc_column_print(LHAFileHeader *header)
+{
+ printf("%-5s %04x", header->compress_method, header->crc);
+}
+
+static ListColumn method_crc_column = {
+ "METHOD CRC", 10,
+ method_crc_column_print
+};
+
+// Get the current time.
+
+static time_t get_now_time(void)
+{
+ // For test builds, allow the current time to be overridden using
+ // an environment variable. This is because the list output can
+ // change depending on the current date.
+
+#ifdef TEST_BUILD
+ char *env_val;
+ unsigned int result;
+
+ env_val = getenv("TEST_NOW_TIME");
+
+ if (env_val != NULL
+ && sscanf(env_val, "%u", &result) == 1) {
+ return (time_t) result;
+ }
+#endif
+
+ return time(NULL);
+}
+
+// File timestamp
+
+static void output_timestamp(unsigned int timestamp)
+{
+ const char *months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ struct tm *ts;
+ time_t tmp;
+
+ if (timestamp == 0) {
+ printf(" ");
+ return;
+ }
+
+ tmp = (time_t) timestamp;
+ ts = localtime(&tmp);
+
+ // Print date:
+
+ printf("%s %2d ", months[ts->tm_mon], ts->tm_mday);
+
+ // If this is an old time (more than 6 months), print the year.
+ // For recent timestamps, print the time.
+
+ tmp = get_now_time();
+
+ if ((time_t) timestamp > tmp - 6 * 30 * 24 * 60 * 60) {
+ printf("%02i:%02i", ts->tm_hour, ts->tm_min);
+ } else {
+ printf(" %04i", ts->tm_year + 1900);
+ }
+}
+
+static void timestamp_column_print(LHAFileHeader *header)
+{
+ output_timestamp(header->timestamp);
+};
+
+static void timestamp_column_footer(FileStatistics *stats)
+{
+ output_timestamp(stats->timestamp);
+};
+
+static ListColumn timestamp_column = {
+ " STAMP", 12,
+ timestamp_column_print,
+ timestamp_column_footer
+};
+
+// Filename
+
+static void name_column_print(LHAFileHeader *header)
+{
+ if (header->path != NULL) {
+ safe_printf("%s", header->path);
+ }
+ if (header->filename != NULL) {
+ safe_printf("%s", header->filename);
+ }
+ if (header->symlink_target != NULL) {
+ safe_printf(" -> %s", header->symlink_target);
+ }
+}
+
+static ListColumn name_column = {
+ " NAME", 20,
+ name_column_print
+};
+
+static ListColumn short_name_column = {
+ " NAME", 13,
+ name_column_print
+};
+
+// "Separate line" filename display. Used when the 'v' option
+// is added.
+
+static void whole_line_name_column_print(LHAFileHeader *header)
+{
+ if (header->path != NULL) {
+ safe_printf("%s", header->path);
+ }
+ if (header->filename != NULL) {
+ safe_printf("%s", header->filename);
+ }
+
+ // For wide filename mode (-v), | is used as the symlink separator,
+ // instead of ->. The reason is that this is how symlinks are
+ // represented within the file headers - the Unix LHA tool only
+ // does the parsing in normal list mode.
+
+ if (header->symlink_target != NULL) {
+ safe_printf("|%s", header->symlink_target);
+ }
+
+ printf("\n");
+}
+
+static ListColumn whole_line_name_column = {
+ "", 0,
+ whole_line_name_column_print
+};
+
+// Header level column. Used when the 'v' option is added.
+
+static void header_level_column_print(LHAFileHeader *header)
+{
+ printf(" [%i]", header->header_level);
+}
+
+static ListColumn header_level_column = {
+ "", 0,
+ header_level_column_print
+};
+
+// Get the last "real" column in a list of columns. This is the last
+// column with a width > 0. Beyond this last column it isn't necessary
+// to print any more whitespace.
+
+static ListColumn *last_column(ListColumn **columns)
+{
+ ListColumn *last;
+ unsigned int i;
+
+ last = NULL;
+
+ for (i = 0; columns[i] != NULL; ++i) {
+ if (columns[i]->width != 0) {
+ last = columns[i];
+ }
+ }
+
+ return last;
+}
+
+// Print the names of the column headings at the top of the file list.
+
+static void print_list_headings(ListColumn **columns)
+{
+ ListColumn *last;
+ unsigned int i, j;
+
+ last = last_column(columns);
+
+ for (i = 0; columns[i] != NULL; ++i) {
+ j = (unsigned) printf("%s", columns[i]->name);
+
+ if (columns[i]->width > 0 && columns[i] != last) {
+ for (; j < columns[i]->width + 1; ++j) {
+ printf(" ");
+ }
+ }
+ }
+
+ printf("\n");
+}
+
+// Print separator lines shown at top and bottom of file list.
+
+static void print_list_separators(ListColumn **columns)
+{
+ ListColumn *last;
+ unsigned int i, j;
+
+ last = last_column(columns);
+
+ for (i = 0; columns[i] != NULL; ++i) {
+ for (j = 0; j < columns[i]->width; ++j) {
+ printf("-");
+ }
+
+ if (columns[i]->width != 0 && columns[i] != last) {
+ printf(" ");
+ }
+ }
+
+ printf("\n");
+}
+
+// Print a row in the list corresponding to a file.
+
+static void print_columns(ListColumn **columns, LHAFileHeader *header)
+{
+ ListColumn *last;
+ unsigned int i;
+
+ last = last_column(columns);
+
+ for (i = 0; columns[i] != NULL; ++i) {
+ columns[i]->handler(header);
+
+ if (columns[i]->width != 0 && columns[i] != last) {
+ printf(" ");
+ }
+ }
+
+ printf("\n");
+}
+
+// Print footer information shown at end of list (overall file stats)
+
+static void print_footers(ListColumn **columns, FileStatistics *stats)
+{
+ unsigned int i, j, len;
+ unsigned int num_columns;
+
+ // Work out how many columns there are to print, ignoring trailing
+ // columns that have no footer:
+
+ num_columns = 0;
+
+ for (i = 0; columns[i] != NULL; ++i) {
+ ++num_columns;
+ }
+
+ while (num_columns > 0 && columns[num_columns-1]->footer == NULL) {
+ --num_columns;
+ }
+
+ // Print footers for each column.
+ // Some columns do not have footers: fill in with spaces instead.
+
+ for (i = 0; i < num_columns; ++i) {
+ if (columns[i]->footer != NULL) {
+ columns[i]->footer(stats);
+ } else if (i + 1 < num_columns) {
+ len = strlen(columns[i]->name);
+
+ for (j = 0; j < len; ++j) {
+ printf(" ");
+ }
+ }
+
+ if (columns[i]->width != 0 && i + 1 < num_columns) {
+ printf(" ");
+ }
+ }
+
+ printf("\n");
+}
+
+static unsigned int read_file_timestamp(FILE *fstream)
+{
+ struct stat data;
+
+ if (fstat(fileno(fstream), &data) != 0) {
+ return (unsigned int) -1;
+ }
+
+ return (unsigned int) data.st_mtime;
+}
+
+// List contents of file, using the specified columns.
+// Different columns are provided for basic and verbose modes.
+
+static void list_file_contents(LHAFilter *filter, FILE *fstream,
+ LHAOptions *options, ListColumn **columns)
+{
+ FileStatistics stats;
+
+ if (options->quiet < 2) {
+ print_list_headings(columns);
+ print_list_separators(columns);
+ }
+
+ stats.num_files = 0;
+ stats.length = 0;
+ stats.compressed_length = 0;
+ stats.timestamp = read_file_timestamp(fstream);
+
+ for (;;) {
+ LHAFileHeader *header;
+
+ header = lha_filter_next_file(filter);
+
+ if (header == NULL) {
+ break;
+ }
+
+ print_columns(columns, header);
+
+ ++stats.num_files;
+ stats.length += header->length;
+ stats.compressed_length += header->compressed_length;
+ }
+
+ if (options->quiet < 2) {
+ print_list_separators(columns);
+ print_footers(columns, &stats);
+ }
+}
+
+// Used for lha -l:
+
+static ListColumn *normal_column_headers[] = {
+ &permission_column,
+ &unix_uid_gid_column,
+ &size_column,
+ &ratio_column,
+ &timestamp_column,
+ &name_column,
+ NULL
+};
+
+// Used for lha -lv:
+
+static ListColumn *normal_column_headers_verbose[] = {
+ &whole_line_name_column,
+ &permission_column,
+ &unix_uid_gid_column,
+ &size_column,
+ &ratio_column,
+ &timestamp_column,
+ &header_level_column,
+ NULL
+};
+
+// lha -l command.
+
+void list_file_basic(LHAFilter *filter, LHAOptions *options, FILE *fstream)
+{
+ ListColumn **headers;
+
+ if (options->verbose) {
+ headers = normal_column_headers_verbose;
+ } else {
+ headers = normal_column_headers;
+ }
+
+ list_file_contents(filter, fstream, options, headers);
+}
+
+// Used for lha -v:
+
+static ListColumn *verbose_column_headers[] = {
+ &permission_column,
+ &unix_uid_gid_column,
+ &packed_column,
+ &size_column,
+ &ratio_column,
+ &method_crc_column,
+ &timestamp_column,
+ &short_name_column,
+ NULL
+};
+
+// Used for lha -vv:
+
+static ListColumn *verbose_column_headers_verbose[] = {
+ &whole_line_name_column,
+ &permission_column,
+ &unix_uid_gid_column,
+ &packed_column,
+ &size_column,
+ &ratio_column,
+ &method_crc_column,
+ &timestamp_column,
+ &header_level_column,
+ NULL
+};
+
+// lha -v command.
+
+void list_file_verbose(LHAFilter *filter, LHAOptions *options, FILE *fstream)
+{
+ ListColumn **headers;
+
+ if (options->verbose) {
+ headers = verbose_column_headers_verbose;
+ } else {
+ headers = verbose_column_headers;
+ }
+
+ list_file_contents(filter, fstream, options, headers);
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h
new file mode 100644
index 00000000..3830c9bd
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h
@@ -0,0 +1,31 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_LIST_H
+#define LHASA_LIST_H
+
+#include "filter.h"
+#include "options.h"
+
+void list_file_basic(LHAFilter *filter, LHAOptions *options, FILE *fstream);
+void list_file_verbose(LHAFilter *filter, LHAOptions *options, FILE *fstream);
+
+#endif /* #ifndef LHASA_LIST_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c
new file mode 100644
index 00000000..4c3e77f4
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c
@@ -0,0 +1,275 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "lib/lha_arch.h"
+#include "lha_reader.h"
+
+#include "config.h"
+#include "extract.h"
+#include "list.h"
+
+typedef enum {
+ MODE_UNKNOWN,
+ MODE_LIST,
+ MODE_LIST_VERBOSE,
+ MODE_CRC_CHECK,
+ MODE_EXTRACT,
+ MODE_PRINT
+} ProgramMode;
+
+static void help_page(char *progname)
+{
+ printf(
+ PACKAGE_NAME " v" PACKAGE_VERSION " command line LHA tool "
+ "- Copyright (C) 2011,2012 Simon Howard\n"
+ "usage: %s [-]{lvtxe[q{num}][finv]}[w=<dir>] archive_file [file...]\n"
+ "commands: options:\n"
+ " l,v List / Verbose List f Force overwrite (no prompt)\n"
+ " t Test file CRC in archive i Ignore directory path\n"
+ " x,e Extract from archive n Perform dry run\n"
+ " p Print to stdout from archive q{num} Quiet mode\n"
+ " v Verbose\n"
+ " w=<dir> Specify extract directory\n"
+ , progname);
+
+ exit(-1);
+}
+
+static int do_command(ProgramMode mode, char *filename,
+ LHAOptions *options,
+ char **filters, unsigned int num_filters)
+{
+ FILE *fstream;
+ LHAInputStream *stream;
+ LHAReader *reader;
+ LHAFilter filter;
+ int result;
+
+ if (!strcmp(filename, "-")) {
+ fstream = stdin;
+ } else {
+ fstream = fopen(filename, "rb");
+
+ if (fstream == NULL) {
+ fprintf(stderr, "LHa: Error: %s %s\n",
+ filename, strerror(errno));
+ exit(-1);
+ }
+ }
+
+ stream = lha_input_stream_from_FILE(fstream);
+ reader = lha_reader_new(stream);
+ lha_filter_init(&filter, reader, filters, num_filters);
+
+ result = 1;
+
+ switch (mode) {
+ case MODE_LIST:
+ list_file_basic(&filter, options, fstream);
+ break;
+
+ case MODE_LIST_VERBOSE:
+ list_file_verbose(&filter, options, fstream);
+ break;
+
+ case MODE_CRC_CHECK:
+ result = test_file_crc(&filter, options);
+ break;
+
+ case MODE_EXTRACT:
+ result = extract_archive(&filter, options);
+ break;
+
+ case MODE_PRINT:
+ result = print_archive(&filter, options);
+ break;
+
+ case MODE_UNKNOWN:
+ break;
+ }
+
+ lha_reader_free(reader);
+ lha_input_stream_free(stream);
+
+ fclose(fstream);
+
+ return result;
+}
+
+static void init_options(LHAOptions *options)
+{
+ options->overwrite_policy = LHA_OVERWRITE_PROMPT;
+ options->quiet = 0;
+ options->verbose = 0;
+ options->dry_run = 0;
+ options->extract_path = NULL;
+ options->use_path = 1;
+}
+
+// Determine the program mode from the first character of the command
+// argument.
+
+static ProgramMode mode_for_char(char c)
+{
+ switch (c) {
+ case 'l':
+ return MODE_LIST;
+ case 'v':
+ return MODE_LIST_VERBOSE;
+ case 't':
+ return MODE_CRC_CHECK;
+ case 'e':
+ case 'x':
+ return MODE_EXTRACT;
+ case 'p':
+ return MODE_PRINT;
+ default:
+ return MODE_UNKNOWN;
+ }
+}
+
+// Parse the option flags from the command argument.
+
+static int parse_options(char *arg, LHAOptions *options)
+{
+ for (; *arg != '\0'; ++arg) {
+ switch (*arg) {
+ // Force overwrite of existing files.
+ case 'f':
+ options->overwrite_policy = LHA_OVERWRITE_ALL;
+ break;
+
+ // -i option turns off paths for extract.
+ case 'i':
+ options->use_path = 0;
+ break;
+
+ // Dry run?
+ case 'n':
+ options->dry_run = 1;
+ break;
+
+ // Quiet mode parsing. The quiet 'level' can be
+ // specified - if the level is omitted, level 2
+ // is implied. All quiet mode options imply
+ // -f (overwrite without confirmation).
+ case 'q':
+ if (arg[1] >= '0' && arg[1] <= '9') {
+ ++arg;
+ options->quiet = *arg - '0';
+ } else {
+ options->quiet = 2;
+ }
+ options->overwrite_policy = LHA_OVERWRITE_ALL;
+ break;
+
+ // Verbose mode.
+ case 'v':
+ options->verbose = 1;
+ break;
+
+ // Specify extract directory: must be last option
+ // specified. Optional '=' separator.
+ case 'w':
+ ++arg;
+ if (*arg == '=') {
+ ++arg;
+ }
+ options->extract_path = arg;
+ arg += strlen(arg) - 1;
+ break;
+
+ default:
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * Parse the command line options, initializing the options structure
+ * used by the main program code.
+ *
+ * @param cmd The 'command' argument (first command line option).
+ * @param mode Pointer to variable to store program mode.
+ * @param options Pointer to options structure to initialize.
+ * @return Non-zero if successful.
+ */
+
+static int parse_command_line(char *cmd, ProgramMode *mode,
+ LHAOptions *options)
+{
+ // Parse program mode argument. Initial '-' is ignored.
+
+ if (*cmd == '-') {
+ ++cmd;
+ }
+
+ *mode = mode_for_char(*cmd);
+
+ if (*mode == MODE_UNKNOWN) {
+ return 0;
+ }
+
+ // Parse remaining options.
+
+ if (!parse_options(cmd + 1, options)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ ProgramMode mode;
+ LHAOptions options;
+
+#ifdef TEST_BUILD
+ // When running tests, give output to stdout in binary mode;
+ // on Windows, this gives the expected output (which was
+ // constructed for Unix):
+
+ lha_arch_set_binary(stdout);
+#endif
+
+ // Parse the command line options and run command.
+ // As a shortcut, a single argument can be provided to list the
+ // contents of an archive ("lha foo.lzh" == "lha l foo.lzh").
+
+ init_options(&options);
+
+ if (argc >= 3 && parse_command_line(argv[1], &mode, &options)) {
+ return !do_command(mode, argv[2], &options,
+ argv + 3, argc - 3);
+ } else if (argc == 2) {
+ return !do_command(MODE_LIST, argv[1], &options, NULL, 0);
+ } else {
+ help_page(argv[0]);
+ return 0;
+ }
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h
new file mode 100644
index 00000000..28d5825a
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h
@@ -0,0 +1,64 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_OPTIONS_H
+#define LHASA_OPTIONS_H
+
+typedef enum {
+ LHA_OVERWRITE_PROMPT,
+ LHA_OVERWRITE_SKIP,
+ LHA_OVERWRITE_ALL
+} LHAOverwritePolicy;
+
+// Options structure. Populated from command line arguments.
+
+typedef struct {
+
+ // Policy to take when extracting files and a file
+ // already exists.
+
+ LHAOverwritePolicy overwrite_policy;
+
+ // "Quiet" level. Normal operation is level 0.
+
+ int quiet;
+
+ // "Verbose" mode.
+
+ int verbose;
+
+ // If true, just perform a dry run of the operations that
+ // would normally be performed, printing messages.
+
+ int dry_run;
+
+ // If not NULL, specifies a path into which to extract files.
+
+ char *extract_path;
+
+ // If true, use the directory path for files - otherwise,
+ // the directory path is ignored.
+
+ int use_path;
+
+} LHAOptions;
+
+#endif /* #ifndef LHASA_OPTIONS_H */
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c
new file mode 100644
index 00000000..083093ff
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c
@@ -0,0 +1,107 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "lib/lha_arch.h"
+
+// Routines for safe terminal output.
+//
+// Data in LHA files (eg. filenames) may contain malicious string
+// data. If printed carelessly, this can include terminal emulator
+// commands that cause very unpleasant things to occur. For more
+// information, see:
+//
+// http://marc.info/?l=bugtraq&m=104612710031920&w=2
+//
+// Quote:
+// > Many of the features supported by popular terminal emulator
+// > software can be abused when un-trusted data is displayed on the
+// > screen. The impact of this abuse can range from annoying screen
+// > garbage to a complete system compromise.
+
+// TODO: This may not be ideal behavior for handling files with
+// names that contain Unicode characters.
+
+static void safe_output(FILE *stream, unsigned char *str)
+{
+ unsigned char *p;
+
+ for (p = str; *p != '\0'; ++p) {
+
+ // Accept only plain ASCII characters.
+ // Control characters (0x00-0x1f) are rejected,
+ // as is 0x7f and all characters in the upper range.
+
+ if (*p < 0x20 || *p >= 0x7f) {
+ *p = '?';
+ }
+ }
+
+ fprintf(stream, "%s", str);
+}
+
+// Version of printf() that strips out any potentially malicious
+// characters from the outputted string.
+// Note: all escape characters are considered potentially malicious,
+// including newline characters.
+
+int safe_fprintf(FILE *stream, char *format, ...)
+{
+ va_list args;
+ int result;
+ unsigned char *str;
+
+ va_start(args, format);
+
+ result = lha_arch_vasprintf((char **) &str, format, args);
+ if (str == NULL) {
+ exit(-1);
+ }
+ safe_output(stream, str);
+ free(str);
+
+ va_end(args);
+
+ return result;
+}
+
+int safe_printf(char *format, ...)
+{
+ va_list args;
+ int result;
+ unsigned char *str;
+
+ va_start(args, format);
+
+ result = lha_arch_vasprintf((char **) &str, format, args);
+ if (str == NULL) {
+ exit(-1);
+ }
+ safe_output(stdout, str);
+ free(str);
+
+ va_end(args);
+
+ return result;
+}
+
diff --git a/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h
new file mode 100644
index 00000000..fc32334c
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h
@@ -0,0 +1,28 @@
+/*
+
+Copyright (c) 2011, 2012, Simon Howard
+
+Permission to use, copy, modify, and/or distribute this software
+for any purpose with or without fee is hereby granted, provided
+that the above copyright notice and this permission notice appear
+in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ */
+
+#ifndef LHASA_SAFE_H
+#define LHASA_SAFE_H
+
+int safe_fprintf(FILE *stream, char *format, ...);
+int safe_printf(char *format, ...);
+
+#endif /* #ifndef LHASA_SAFE_H */
+