Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
8
Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml
vendored
Normal file
8
Src/external_dependencies/openmpt-trunk/include/lhasa/.travis.yml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
language: c
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
script: ./autogen.sh && make && make check
|
||||
|
1
Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS
vendored
Normal file
1
Src/external_dependencies/openmpt-trunk/include/lhasa/AUTHORS
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Simon Howard <fraggle@gmail.com>
|
17
Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING
vendored
Normal file
17
Src/external_dependencies/openmpt-trunk/include/lhasa/COPYING
vendored
Normal file
|
@ -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.
|
||||
|
13
Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog
vendored
Normal file
13
Src/external_dependencies/openmpt-trunk/include/lhasa/ChangeLog
vendored
Normal file
|
@ -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
|
||||
|
11
Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am
vendored
Normal file
11
Src/external_dependencies/openmpt-trunk/include/lhasa/Makefile.am
vendored
Normal file
|
@ -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
|
||||
|
158
Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS
vendored
Normal file
158
Src/external_dependencies/openmpt-trunk/include/lhasa/NEWS
vendored
Normal file
|
@ -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
|
10
Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt
vendored
Normal file
10
Src/external_dependencies/openmpt-trunk/include/lhasa/OpenMPT.txt
vendored
Normal file
|
@ -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.
|
17
Src/external_dependencies/openmpt-trunk/include/lhasa/README
vendored
Normal file
17
Src/external_dependencies/openmpt-trunk/include/lhasa/README
vendored
Normal file
|
@ -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.
|
||||
|
23
Src/external_dependencies/openmpt-trunk/include/lhasa/TODO
vendored
Normal file
23
Src/external_dependencies/openmpt-trunk/include/lhasa/TODO
vendored
Normal file
|
@ -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.
|
||||
|
13
Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh
vendored
Normal file
13
Src/external_dependencies/openmpt-trunk/include/lhasa/autogen.sh
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
|
||||
mkdir -p autotools
|
||||
|
||||
aclocal
|
||||
libtoolize || glibtoolize
|
||||
autoheader
|
||||
automake -a
|
||||
autoconf
|
||||
automake -a
|
||||
|
||||
./configure $@
|
||||
|
88
Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac
vendored
Normal file
88
Src/external_dependencies/openmpt-trunk/include/lhasa/configure.ac
vendored
Normal file
|
@ -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
|
||||
])
|
||||
|
1360
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile
vendored
Normal file
1360
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Doxyfile
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am
vendored
Normal file
7
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/Makefile.am
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
man_MANS=lha.1
|
||||
EXTRA_DIST=$(man_MANS) html Doxyfile intro.h
|
||||
|
||||
html:
|
||||
doxygen
|
||||
|
54
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h
vendored
Normal file
54
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/intro.h
vendored
Normal file
|
@ -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.
|
||||
*/
|
||||
|
116
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1
vendored
Normal file
116
Src/external_dependencies/openmpt-trunk/include/lhasa/doc/lha.1
vendored
Normal file
|
@ -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.
|
||||
|
||||
|
115
Src/external_dependencies/openmpt-trunk/include/lhasa/gencov
vendored
Normal file
115
Src/external_dependencies/openmpt-trunk/include/lhasa/gencov
vendored
Normal file
|
@ -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
|
||||
|
43
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am
vendored
Normal file
43
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/Makefile.am
vendored
Normal file
|
@ -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
|
||||
|
128
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c
vendored
Normal file
128
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/bit_stream_reader.c
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
|
73
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c
vendored
Normal file
73
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
30
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h
vendored
Normal file
30
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/crc16.h
vendored
Normal file
|
@ -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 */
|
||||
|
437
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c
vendored
Normal file
437
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.c
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
|
44
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h
vendored
Normal file
44
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/ext_header.h
vendored
Normal file
|
@ -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 */
|
||||
|
724
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c
vendored
Normal file
724
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh1_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
||||
|
49
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c
vendored
Normal file
49
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh5_decoder.c
vendored
Normal file
|
@ -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"
|
||||
|
43
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c
vendored
Normal file
43
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh6_decoder.c
vendored
Normal file
|
@ -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"
|
||||
|
44
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c
vendored
Normal file
44
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh7_decoder.c
vendored
Normal file
|
@ -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"
|
||||
|
569
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c
vendored
Normal file
569
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lh_new_decoder.c
vendored
Normal file
|
@ -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
|
||||
|
160
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h
vendored
Normal file
160
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch.h
vendored
Normal file
|
@ -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 */
|
||||
|
173
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c
vendored
Normal file
173
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_unix.c
vendored
Normal file
|
@ -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, ×) == 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 */
|
||||
|
204
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c
vendored
Normal file
204
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_arch_win32.c
vendored
Normal file
|
@ -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 */
|
||||
|
159
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c
vendored
Normal file
159
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.c
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
|
99
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h
vendored
Normal file
99
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_basic_reader.h
vendored
Normal file
|
@ -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 */
|
||||
|
256
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c
vendored
Normal file
256
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
114
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h
vendored
Normal file
114
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_decoder.h
vendored
Normal file
|
@ -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 */
|
||||
|
60
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c
vendored
Normal file
60
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.c
vendored
Normal file
|
@ -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]);
|
||||
}
|
||||
|
72
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h
vendored
Normal file
72
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_endian.h
vendored
Normal file
|
@ -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 */
|
||||
|
1081
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c
vendored
Normal file
1081
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
68
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h
vendored
Normal file
68
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_file_header.h
vendored
Normal file
|
@ -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 */
|
||||
|
403
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c
vendored
Normal file
403
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.c
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
|
51
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h
vendored
Normal file
51
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_input_stream.h
vendored
Normal file
|
@ -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 */
|
||||
|
886
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c
vendored
Normal file
886
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lha_reader.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
45
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c
vendored
Normal file
45
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lhx_decoder.c
vendored
Normal file
|
@ -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"
|
||||
|
198
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c
vendored
Normal file
198
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lz5_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
156
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c
vendored
Normal file
156
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/lzs_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
451
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c
vendored
Normal file
451
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
49
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h
vendored
Normal file
49
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/macbinary.h
vendored
Normal file
|
@ -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 */
|
||||
|
61
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c
vendored
Normal file
61
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/null_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
714
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c
vendored
Normal file
714
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm1_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
549
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c
vendored
Normal file
549
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pm2_decoder.c
vendored
Normal file
|
@ -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
|
||||
};
|
||||
|
162
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c
vendored
Normal file
162
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/pma_common.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
9
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am
vendored
Normal file
9
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/Makefile.am
vendored
Normal file
|
@ -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
|
||||
|
183
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h
vendored
Normal file
183
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_decoder.h
vendored
Normal file
|
@ -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 */
|
||||
|
248
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h
vendored
Normal file
248
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_file_header.h
vendored
Normal file
|
@ -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 */
|
||||
|
134
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h
vendored
Normal file
134
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_input_stream.h
vendored
Normal file
|
@ -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 */
|
||||
|
217
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h
vendored
Normal file
217
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lha_reader.h
vendored
Normal file
|
@ -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 */
|
||||
|
30
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h
vendored
Normal file
30
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/public/lhasa.h
vendored
Normal file
|
@ -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 */
|
||||
|
252
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c
vendored
Normal file
252
Src/external_dependencies/openmpt-trunk/include/lhasa/lib/tree_decode.c
vendored
Normal file
|
@ -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);
|
||||
}
|
||||
|
10
Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in
vendored
Normal file
10
Src/external_dependencies/openmpt-trunk/include/lhasa/liblhasa.pc.in
vendored
Normal file
|
@ -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
|
5
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am
vendored
Normal file
5
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/Makefile.am
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
EXTRA_DIST = \
|
||||
win32/GNUmakefile \
|
||||
win32/README
|
||||
|
18
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in
vendored
Normal file
18
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/config.make.in
vendored
Normal file
|
@ -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
|
||||
|
26
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile
vendored
Normal file
26
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/GNUmakefile
vendored
Normal file
|
@ -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
|
9
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README
vendored
Normal file
9
Src/external_dependencies/openmpt-trunk/include/lhasa/pkg/win32/README
vendored
Normal file
|
@ -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
|
||||
|
53
Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in
vendored
Normal file
53
Src/external_dependencies/openmpt-trunk/include/lhasa/rpm.spec.in
vendored
Normal file
|
@ -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/*/*
|
||||
|
23
Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am
vendored
Normal file
23
Src/external_dependencies/openmpt-trunk/include/lhasa/src/Makefile.am
vendored
Normal file
|
@ -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
|
||||
|
76
Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt
vendored
Normal file
76
Src/external_dependencies/openmpt-trunk/include/lhasa/src/args.txt
vendored
Normal file
|
@ -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.
|
||||
|
676
Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c
vendored
Normal file
676
Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
32
Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h
vendored
Normal file
32
Src/external_dependencies/openmpt-trunk/include/lhasa/src/extract.h
vendored
Normal file
|
@ -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 */
|
||||
|
137
Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c
vendored
Normal file
137
Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
61
Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h
vendored
Normal file
61
Src/external_dependencies/openmpt-trunk/include/lhasa/src/filter.h
vendored
Normal file
|
@ -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 */
|
||||
|
682
Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c
vendored
Normal file
682
Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.c
vendored
Normal file
|
@ -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,
|
||||
×tamp_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,
|
||||
×tamp_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,
|
||||
×tamp_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,
|
||||
×tamp_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);
|
||||
}
|
||||
|
31
Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h
vendored
Normal file
31
Src/external_dependencies/openmpt-trunk/include/lhasa/src/list.h
vendored
Normal file
|
@ -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 */
|
||||
|
275
Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c
vendored
Normal file
275
Src/external_dependencies/openmpt-trunk/include/lhasa/src/main.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
64
Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h
vendored
Normal file
64
Src/external_dependencies/openmpt-trunk/include/lhasa/src/options.h
vendored
Normal file
|
@ -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 */
|
||||
|
107
Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c
vendored
Normal file
107
Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.c
vendored
Normal file
|
@ -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;
|
||||
}
|
||||
|
28
Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h
vendored
Normal file
28
Src/external_dependencies/openmpt-trunk/include/lhasa/src/safe.h
vendored
Normal file
|
@ -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 */
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue