Update mspack, add to premake, and fix missing license. Fixes #1252.

This commit is contained in:
gibbed 2018-11-23 15:32:14 -06:00
parent 021af14a6e
commit 7226c9e047
12 changed files with 4093 additions and 595 deletions

View File

@ -228,6 +228,7 @@ solution("xenia")
include("third_party/glslang-spirv.lua") include("third_party/glslang-spirv.lua")
include("third_party/imgui.lua") include("third_party/imgui.lua")
include("third_party/libav.lua") include("third_party/libav.lua")
include("third_party/mspack.lua")
include("third_party/snappy.lua") include("third_party/snappy.lua")
include("third_party/spirv-tools.lua") include("third_party/spirv-tools.lua")
include("third_party/volk.lua") include("third_party/volk.lua")

View File

@ -25,7 +25,6 @@
#include "third_party/crypto/rijndael-alg-fst.c" #include "third_party/crypto/rijndael-alg-fst.c"
#include "third_party/crypto/rijndael-alg-fst.h" #include "third_party/crypto/rijndael-alg-fst.h"
#include "third_party/mspack/lzx.h" #include "third_party/mspack/lzx.h"
#include "third_party/mspack/lzxd.c"
#include "third_party/mspack/mspack.h" #include "third_party/mspack/mspack.h"
#include "third_party/pe/pe_image.h" #include "third_party/pe/pe_image.h"
@ -120,7 +119,7 @@ int lzx_decompress(const void* lzx_data, size_t lzx_len, void* dest,
mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len); mspack_memory_file* lzxdst = mspack_memory_open(sys, dest, dest_len);
lzxd_stream* lzxd = lzxd_stream* lzxd =
lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst, lzxd_init(sys, (struct mspack_file*)lzxsrc, (struct mspack_file*)lzxdst,
window_bits, 0, 0x8000, (off_t)dest_len); window_bits, 0, 0x8000, (off_t)dest_len, 0);
if (lzxd) { if (lzxd) {
if (window_data) { if (window_data) {

33
third_party/mspack.lua vendored Normal file
View File

@ -0,0 +1,33 @@
group("third_party")
project("mspack")
uuid("0881692A-75A1-4E7B-87D8-BB9108CEDEA4")
kind("StaticLib")
language("C")
defines({
"_LIB",
"HAVE_CONFIG_H",
})
removedefines({
"_UNICODE",
"UNICODE",
})
includedirs({
"mspack",
})
files({
"mspack/lzx.h",
"mspack/lzxd.c",
"mspack/mspack.h",
"mspack/readbits.h",
"mspack/readhuff.h",
"mspack/system.c",
"mspack/system.h",
})
filter("platforms:Windows")
defines({
})
filter("platforms:Linux")
defines({
})

504
third_party/mspack/COPYING.LIB vendored Normal file
View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

114
third_party/mspack/config.h vendored Normal file
View File

@ -0,0 +1,114 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Turn debugging mode on? */
#undef DEBUG
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
#undef HAVE_FSEEKO
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkdir' function. */
#undef HAVE_MKDIR
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the `towlower' function. */
#undef HAVE_TOWLOWER
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `_mkdir' function. */
#undef HAVE__MKDIR
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Define if mkdir takes only one argument. */
#undef MKDIR_TAKES_ONE_ARG
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of `off_t', as computed by sizeof. */
#undef SIZEOF_OFF_T
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Version number of package */
#undef VERSION
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
#undef _LARGEFILE_SOURCE
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/* Define to `long int' if <sys/types.h> does not define. */
#undef off_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t

View File

@ -1,5 +1,5 @@
/* This file is part of libmspack. /* This file is part of libmspack.
* (C) 2003-2004 Stuart Caie. * (C) 2003-2013 Stuart Caie.
* *
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft Corporation. * by Microsoft Corporation.
@ -13,6 +13,10 @@
#ifndef MSPACK_LZX_H #ifndef MSPACK_LZX_H
#define MSPACK_LZX_H 1 #define MSPACK_LZX_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* LZX compression / decompression definitions */ /* LZX compression / decompression definitions */
/* some constants defined by the LZX specification */ /* some constants defined by the LZX specification */
@ -31,7 +35,7 @@
/* LZX huffman defines: tweak tablebits as desired */ /* LZX huffman defines: tweak tablebits as desired */
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) #define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
#define LZX_PRETREE_TABLEBITS (6) #define LZX_PRETREE_TABLEBITS (6)
#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) #define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 290*8)
#define LZX_MAINTREE_TABLEBITS (12) #define LZX_MAINTREE_TABLEBITS (12)
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) #define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
#define LZX_LENGTH_TABLEBITS (12) #define LZX_LENGTH_TABLEBITS (12)
@ -51,6 +55,8 @@ struct lzxd_stream {
unsigned char *window; /* decoding window */ unsigned char *window; /* decoding window */
unsigned int window_size; /* window size */ unsigned int window_size; /* window size */
unsigned int ref_data_size; /* LZX DELTA reference data size */
unsigned int num_offsets; /* number of match_offset entries in table */
unsigned int window_posn; /* decompression offset within window */ unsigned int window_posn; /* decompression offset within window */
unsigned int frame_posn; /* current frame offset within in window */ unsigned int frame_posn; /* current frame offset within in window */
unsigned int frame; /* the number of 32kb frames processed */ unsigned int frame; /* the number of 32kb frames processed */
@ -66,8 +72,8 @@ struct lzxd_stream {
unsigned char intel_started; /* has intel E8 decoding started? */ unsigned char intel_started; /* has intel E8 decoding started? */
unsigned char block_type; /* type of the current block */ unsigned char block_type; /* type of the current block */
unsigned char header_read; /* have we started decoding at all yet? */ unsigned char header_read; /* have we started decoding at all yet? */
unsigned char posn_slots; /* how many posn slots in stream? */
unsigned char input_end; /* have we reached the end of input? */ unsigned char input_end; /* have we reached the end of input? */
unsigned char is_delta; /* does stream follow LZX DELTA spec? */
int error; int error;
@ -90,35 +96,53 @@ struct lzxd_stream {
(LZX_LENGTH_MAXSYMBOLS * 2)]; (LZX_LENGTH_MAXSYMBOLS * 2)];
unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) + unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
(LZX_ALIGNED_MAXSYMBOLS * 2)]; (LZX_ALIGNED_MAXSYMBOLS * 2)];
unsigned char LENGTH_empty;
/* this is used purely for doing the intel E8 transform */ /* this is used purely for doing the intel E8 transform */
unsigned char e8_buf[LZX_FRAME_SIZE]; unsigned char e8_buf[LZX_FRAME_SIZE];
}; };
/* allocates LZX decompression state for decoding the given stream. /**
* Allocates and initialises LZX decompression state for decoding an LZX
* stream.
* *
* - returns NULL if window_bits is outwith the range 15 to 21 (inclusive). * This routine uses system->alloc() to allocate memory. If memory
* allocation fails, or the parameters to this function are invalid,
* NULL is returned.
* *
* - uses system->alloc() to allocate memory * @param system an mspack_system structure used to read from
* * the input stream and write to the output
* - returns NULL if not enough memory * stream, also to allocate and free memory.
* * @param input an input stream with the LZX data.
* - window_bits is the size of the LZX window, from 32Kb (15) to 2Mb (21). * @param output an output stream to write the decoded data to.
* * @param window_bits the size of the decoding window, which must be
* - reset_interval is how often the bitstream is reset, measured in * between 15 and 21 inclusive for regular LZX
* multiples of 32Kb bytes output. For CAB LZX streams, this is always 0 * data, or between 17 and 25 inclusive for
* (does not occur). * LZX DELTA data.
* * @param reset_interval the interval at which the LZX bitstream is
* - input_buffer_size is how many bytes to use as an input bitstream buffer * reset, in multiples of LZX frames (32678
* * bytes), e.g. a value of 2 indicates the input
* - output_length is the length in bytes of the entirely decompressed * stream resets after every 65536 output bytes.
* output stream, if known in advance. It is used to correctly perform * A value of 0 indicates that the bitstream never
* the Intel E8 transformation, which must stop 6 bytes before the very * resets, such as in CAB LZX streams.
* end of the decompressed stream. It is not otherwise used or adhered * @param input_buffer_size the number of bytes to use as an input
* to. If the full decompressed length is known in advance, set it here. * bitstream buffer.
* If it is NOT known, use the value 0, and call lzxd_set_output_length() * @param output_length the length in bytes of the entirely
* once it is known. If never set, 4 of the final 6 bytes of the output * decompressed output stream, if known in
* stream may be incorrect. * advance. It is used to correctly perform the
* Intel E8 transformation, which must stop 6
* bytes before the very end of the
* decompressed stream. It is not otherwise used
* or adhered to. If the full decompressed
* length is known in advance, set it here.
* If it is NOT known, use the value 0, and call
* lzxd_set_output_length() once it is
* known. If never set, 4 of the final 6 bytes
* of the output stream may be incorrect.
* @param is_delta should be zero for all regular LZX data,
* non-zero for LZX DELTA encoded data.
* @return a pointer to an initialised lzxd_stream structure, or NULL if
* there was not enough memory or parameters to the function were wrong.
*/ */
extern struct lzxd_stream *lzxd_init(struct mspack_system *system, extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
struct mspack_file *input, struct mspack_file *input,
@ -126,42 +150,72 @@ extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
int window_bits, int window_bits,
int reset_interval, int reset_interval,
int input_buffer_size, int input_buffer_size,
off_t output_length); off_t output_length,
char is_delta);
/* see description of output_length in lzxd_init() */ /* see description of output_length in lzxd_init() */
extern void lzxd_set_output_length(struct lzxd_stream *lzx, extern void lzxd_set_output_length(struct lzxd_stream *lzx,
off_t output_length); off_t output_length);
/* decompresses, or decompresses more of, an LZX stream. /**
* Reads LZX DELTA reference data into the window and allows
* lzxd_decompress() to reference it.
* *
* - out_bytes of data will be decompressed and the function will return * Call this before the first call to lzxd_decompress().
* with an MSPACK_ERR_OK return code.
* @param lzx the LZX stream to apply this reference data to
* @param system an mspack_system implementation to use with the
* input param. Only read() will be called.
* @param input an input file handle to read reference data using
* system->read().
* @param length the length of the reference data. Cannot be longer
* than the LZX window size.
* @return an error code, or MSPACK_ERR_OK if successful
*/
extern int lzxd_set_reference_data(struct lzxd_stream *lzx,
struct mspack_system *system,
struct mspack_file *input,
unsigned int length);
/**
* Decompresses entire or partial LZX streams.
* *
* - decompressing will stop as soon as out_bytes is reached. if the true * The number of bytes of data that should be decompressed is given as the
* amount of bytes decoded spills over that amount, they will be kept for * out_bytes parameter. If more bytes are decoded than are needed, they
* a later invocation of lzxd_decompress(). * will be kept over for a later invocation.
* *
* - the output bytes will be passed to the system->write() function given in * The output bytes will be passed to the system->write() function given in
* lzxd_init(), using the output file handle given in lzxd_init(). More * lzxd_init(), using the output file handle given in lzxd_init(). More than
* than one call may be made to system->write(). * one call may be made to system->write().
* Input bytes will be read in as necessary using the system->read()
* function given in lzxd_init(), using the input file handle given in
* lzxd_init(). This will continue until system->read() returns 0 bytes,
* or an error. Errors will be passed out of the function as
* MSPACK_ERR_READ errors. Input streams should convey an "end of input
* stream" by refusing to supply all the bytes that LZX asks for when they
* reach the end of the stream, rather than return an error code.
* *
* - LZX will read input bytes as necessary using the system->read() function * If any error code other than MSPACK_ERR_OK is returned, the stream
* given in lzxd_init(), using the input file handle given in lzxd_init(). * should be considered unusable and lzxd_decompress() should not be
* This will continue until system->read() returns 0 bytes, or an error. * called again on this stream.
* input streams should convey an "end of input stream" by refusing to
* supply all the bytes that LZX asks for when they reach the end of the
* stream, rather than return an error code.
* *
* - if an error code other than MSPACK_ERR_OK is returned, the stream should * @param lzx LZX decompression state, as allocated by lzxd_init().
* be considered unusable and lzxd_decompress() should not be called again * @param out_bytes the number of bytes of data to decompress.
* on this stream. * @return an error code, or MSPACK_ERR_OK if successful
*/ */
extern int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes); extern int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes);
/* frees all state associated with an LZX data stream /**
* Frees all state associated with an LZX data stream. This will call
* system->free() using the system pointer given in lzxd_init().
* *
* - calls system->free() using the system pointer given in lzxd_init() * @param lzx LZX decompression state to free.
*/ */
void lzxd_free(struct lzxd_stream *lzx); void lzxd_free(struct lzxd_stream *lzx);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,5 +1,5 @@
/* This file is part of libmspack. /* This file is part of libmspack.
* (C) 2003-2004 Stuart Caie. * (C) 2003-2013 Stuart Caie.
* *
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft Corporation. * by Microsoft Corporation.
@ -12,11 +12,11 @@
/* LZX decompression implementation */ /* LZX decompression implementation */
#include "mspack.h" #include <system.h>
#include "lzx.h" #include <lzx.h>
/* Microsoft's LZX document and their implementation of the /* Microsoft's LZX document (in cab-sdk.exe) and their implementation
* com.ms.util.cab Java package do not concur. * of the com.ms.util.cab Java package do not concur.
* *
* In the LZX document, there is a table showing the correlation between * In the LZX document, there is a table showing the correlation between
* window size and the number of position slots. It states that the 1MB * window size and the number of position slots. It states that the 1MB
@ -58,226 +58,71 @@
* least one element. However, many CAB files contain blocks where the * least one element. However, many CAB files contain blocks where the
* length tree is completely empty (because there are no matches), and * length tree is completely empty (because there are no matches), and
* this is expected to succeed. * this is expected to succeed.
*
* The errors in LZX documentation appear have been corrected in the
* new documentation for the LZX DELTA format.
*
* http://msdn.microsoft.com/en-us/library/cc483133.aspx
*
* However, this is a different format, an extension of regular LZX.
* I have noticed the following differences, there may be more:
*
* The maximum window size has increased from 2MB to 32MB. This also
* increases the maximum number of position slots, etc.
*
* If the match length is 257 (the maximum possible), this signals
* a further length decoding step, that allows for matches up to
* 33024 bytes long.
*
* The format now allows for "reference data", supplied by the caller.
* If match offsets go further back than the number of bytes
* decompressed so far, that is them accessing the reference data.
*/ */
/* import bit-reading macros and code */
/* LZX decompressor input macros #define BITS_TYPE struct lzxd_stream
* #define BITS_VAR lzx
* STORE_BITS stores bitstream state in lzxd_stream structure #define BITS_ORDER_MSB
* RESTORE_BITS restores bitstream state from lzxd_stream structure #define READ_BYTES do { \
* READ_BITS(var,n) takes N bits from the buffer and puts them in var unsigned char b0, b1; \
* ENSURE_BITS(n) ensures there are at least N bits in the bit buffer. READ_IF_NEEDED; b0 = *i_ptr++; \
* PEEK_BITS(n) extracts without removing N bits from the bit buffer READ_IF_NEEDED; b1 = *i_ptr++; \
* REMOVE_BITS(n) removes N bits from the bit buffer INJECT_BITS((b1 << 8) | b0, 16); \
*
* These bit access routines work by using the area beyond the MSB and the
* LSB as a free source of zeroes when shifting. This avoids having to
* mask any bits. So we have to know the bit width of the bit buffer
* variable.
*
* The bit buffer datatype should be at least 32 bits wide: it must be
* possible to ENSURE_BITS(16), so it must be possible to add 16 new bits
* to the bit buffer when the bit buffer already has 1 to 15 bits left.
*/
#include <limits.h>
#ifndef CHAR_BIT
# define CHAR_BIT (8)
#endif
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
#ifdef LZXDEBUG
# include <stdio.h>
# define D(x) do { printf("%s:%d (%s) ",__FILE__, __LINE__, __FUNCTION__); \
printf x ; fputc('\n', stdout); fflush(stdout);} while (0);
#else
# define D(x)
#endif
#define STORE_BITS do { \
lzx->i_ptr = i_ptr; \
lzx->i_end = i_end; \
lzx->bit_buffer = bit_buffer; \
lzx->bits_left = bits_left; \
} while (0) } while (0)
#include <readbits.h>
#define RESTORE_BITS do { \ /* import huffman-reading macros and code */
i_ptr = lzx->i_ptr; \ #define TABLEBITS(tbl) LZX_##tbl##_TABLEBITS
i_end = lzx->i_end; \ #define MAXSYMBOLS(tbl) LZX_##tbl##_MAXSYMBOLS
bit_buffer = lzx->bit_buffer; \ #define HUFF_TABLE(tbl,idx) lzx->tbl##_table[idx]
bits_left = lzx->bits_left; \ #define HUFF_LEN(tbl,idx) lzx->tbl##_len[idx]
} while (0) #define HUFF_ERROR return lzx->error = MSPACK_ERR_DECRUNCH
#include <readhuff.h>
#define ENSURE_BITS(nbits) \
while (bits_left < (nbits)) { \
if (i_ptr >= i_end) { \
if (lzxd_read_input(lzx)) return lzx->error; \
i_ptr = lzx->i_ptr; \
i_end = lzx->i_end; \
} \
bit_buffer |= ((i_ptr[1] << 8) | i_ptr[0]) \
<< (BITBUF_WIDTH - 16 - bits_left); \
bits_left += 16; \
i_ptr += 2; \
}
#define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
#define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
#define READ_BITS(val, nbits) do { \
ENSURE_BITS(nbits); \
(val) = PEEK_BITS(nbits); \
REMOVE_BITS(nbits); \
} while (0)
static int lzxd_read_input(struct lzxd_stream *lzx) {
int read = lzx->sys->read(lzx->input, &lzx->inbuf[0], (int)lzx->inbuf_size);
if (read < 0) return lzx->error = MSPACK_ERR_READ;
/* huff decode's ENSURE_BYTES(16) might overrun the input stream, even
* if those bits aren't used, so fake 2 more bytes */
if (read == 0) {
if (lzx->input_end) {
D(("out of input bytes"))
return lzx->error = MSPACK_ERR_READ;
}
else {
read = 2;
lzx->inbuf[0] = lzx->inbuf[1] = 0;
lzx->input_end = 1;
}
}
lzx->i_ptr = &lzx->inbuf[0];
lzx->i_end = &lzx->inbuf[read];
return MSPACK_ERR_OK;
}
/* Huffman decoding macros */
/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
* bitstream using the stated table and puts it in var.
*/
#define READ_HUFFSYM(tbl, var) do { \
/* huffman symbols can be up to 16 bits long */ \
ENSURE_BITS(16); \
/* immediate table lookup of [tablebits] bits of the code */ \
sym = lzx->tbl##_table[PEEK_BITS(LZX_##tbl##_TABLEBITS)]; \
/* is the symbol is longer than [tablebits] bits? (i=node index) */ \
if (sym >= LZX_##tbl##_MAXSYMBOLS) { \
/* decode remaining bits by tree traversal */ \
i = 1 << (BITBUF_WIDTH - LZX_##tbl##_TABLEBITS); \
do { \
/* one less bit. error if we run out of bits before decode */ \
i >>= 1; \
if (i == 0) { \
D(("out of bits in huffman decode")) \
return lzx->error = MSPACK_ERR_DECRUNCH; \
} \
/* double node index and add 0 (left branch) or 1 (right) */ \
sym <<= 1; sym |= (bit_buffer & i) ? 1 : 0; \
/* hop to next node index / decoded symbol */ \
sym = lzx->tbl##_table[sym]; \
/* while we are still in node indicies, not decoded symbols */ \
} while (sym >= LZX_##tbl##_MAXSYMBOLS); \
} \
/* result */ \
(var) = sym; \
/* look up the code length of that symbol and discard those bits */ \
i = lzx->tbl##_len[sym]; \
REMOVE_BITS(i); \
} while (0)
/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */ /* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
#define BUILD_TABLE(tbl) \ #define BUILD_TABLE(tbl) \
if (make_decode_table(LZX_##tbl##_MAXSYMBOLS, LZX_##tbl##_TABLEBITS, \ if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
&lzx->tbl##_len[0], &lzx->tbl##_table[0])) \ &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
{ \ { \
D(("failed to build %s table", #tbl)) \ D(("failed to build %s table", #tbl)) \
return lzx->error = MSPACK_ERR_DECRUNCH; \ return lzx->error = MSPACK_ERR_DECRUNCH; \
} }
/* make_decode_table(nsyms, nbits, length[], table[]) #define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
* lzx->tbl##_empty = 0; \
* This function was coded by David Tritscher. It builds a fast huffman if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
* decoding table from a canonical huffman code lengths table. &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
* { \
* nsyms = total number of symbols in this huffman tree. for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
* nbits = any symbols with a code length of nbits or less can be decoded if (HUFF_LEN(tbl, i) > 0) { \
* in one lookup of the table. D(("failed to build %s table", #tbl)) \
* length = A table to get code lengths from [0 to syms-1] return lzx->error = MSPACK_ERR_DECRUNCH; \
* table = The table to fill up with decoded symbols and pointers. } \
* } \
* Returns 0 for OK or 1 for error /* empty tree - allow it, but don't decode symbols with it */ \
*/ lzx->tbl##_empty = 1; \
} \
static int make_decode_table(unsigned int nsyms, unsigned int nbits, } while (0)
unsigned char *length, unsigned short *table)
{
unsigned short sym;
unsigned int leaf, fill;
unsigned char bit_num;
unsigned int pos = 0; /* the current position in the decode table */
unsigned int table_mask = 1 << nbits;
unsigned int bit_mask = table_mask >> 1; /* don't do 0 length codes */
unsigned int next_symbol = bit_mask; /* base of allocation for long codes */
/* fill entries for codes short enough for a direct mapping */
for (bit_num = 1; bit_num <= nbits; bit_num++) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] != bit_num) continue;
leaf = pos;
if((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
}
bit_mask >>= 1;
}
/* full table already? */
if (pos == table_mask) return 0;
/* clear the remainder of the table */
for (sym = pos; sym < table_mask; sym++) table[sym] = 0xFFFF;
/* allow codes to be up to nbits+16 long, instead of nbits */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
for (bit_num = nbits+1; bit_num <= 16; bit_num++) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] != bit_num) continue;
leaf = pos >> 16;
for (fill = 0; fill < bit_num - nbits; fill++) {
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0xFFFF) {
table[(next_symbol << 1)] = 0xFFFF;
table[(next_symbol << 1) + 1] = 0xFFFF;
table[leaf] = next_symbol++;
}
/* follow the path and select either left or right for next bit */
leaf = table[leaf] << 1;
if ((pos >> (15-fill)) & 1) leaf++;
}
table[leaf] = sym;
if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
}
bit_mask >>= 1;
}
/* full table? */
if (pos == table_mask) return 0;
/* either erroneous table, or all elements are 0 - let's find out. */
for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
return 0;
}
/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols /* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
* first to last in the given table. The code lengths are stored in their * first to last in the given table. The code lengths are stored in their
@ -285,7 +130,7 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
*/ */
#define READ_LENGTHS(tbl, first, last) do { \ #define READ_LENGTHS(tbl, first, last) do { \
STORE_BITS; \ STORE_BITS; \
if (lzxd_read_lens(lzx, &lzx->tbl##_len[0], (first), \ if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
(unsigned int)(last))) return lzx->error; \ (unsigned int)(last))) return lzx->error; \
RESTORE_BITS; \ RESTORE_BITS; \
} while (0) } while (0)
@ -348,27 +193,71 @@ static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
* a small 'position slot' number and a small offset from that slot are * a small 'position slot' number and a small offset from that slot are
* encoded instead of one large offset. * encoded instead of one large offset.
* *
* The number of slots is decided by how many are needed to encode the
* largest offset for a given window size. This is easy when the gap between
* slots is less than 128Kb, it's a linear relationship. But when extra_bits
* reaches its limit of 17 (because LZX can only ensure reading 17 bits of
* data at a time), we can only jump 128Kb at a time and have to start
* using more and more position slots as each window size doubles.
*
* position_base[] is an index to the position slot bases * position_base[] is an index to the position slot bases
* *
* extra_bits[] states how many bits of offset-from-base data is needed. * extra_bits[] states how many bits of offset-from-base data is needed.
*
* They are calculated as follows:
* extra_bits[i] = 0 where i < 4
* extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
* extra_bits[i] = 17 where i >= 36
* position_base[0] = 0
* position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
*/ */
static unsigned int position_base[51]; static const unsigned int position_slots[11] = {
static unsigned char extra_bits[51]; 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
};
static void lzxd_static_init() { static const unsigned char extra_bits[36] = {
int i, j; 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
for (i = 0, j = 0; i < 51; i += 2) { };
extra_bits[i] = j; /* 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7... */ static const unsigned int position_base[290] = {
extra_bits[i+1] = j; 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
} 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
for (i = 0, j = 0; i < 51; i++) { 1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ 3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
} 4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
} 6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
33161216, 33292288, 33423360
};
static void lzxd_reset_state(struct lzxd_stream *lzx) { static void lzxd_reset_state(struct lzxd_stream *lzx) {
int i; int i;
@ -393,21 +282,32 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
int window_bits, int window_bits,
int reset_interval, int reset_interval,
int input_buffer_size, int input_buffer_size,
off_t output_length) off_t output_length,
char is_delta)
{ {
unsigned int window_size = 1 << window_bits; unsigned int window_size = 1 << window_bits;
struct lzxd_stream *lzx; struct lzxd_stream *lzx;
if (!system) return NULL; if (!system) return NULL;
/* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ /* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
* regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB)
*/
if (is_delta) {
if (window_bits < 17 || window_bits > 25) return NULL;
}
else {
if (window_bits < 15 || window_bits > 21) return NULL; if (window_bits < 15 || window_bits > 21) return NULL;
}
if (reset_interval < 0 || output_length < 0) {
D(("reset interval or output length < 0"))
return NULL;
}
/* round up input buffer size to multiple of two */
input_buffer_size = (input_buffer_size + 1) & -2; input_buffer_size = (input_buffer_size + 1) & -2;
if (!input_buffer_size) return NULL; if (input_buffer_size < 2) return NULL;
/* initialise static data */
lzxd_static_init();
/* allocate decompression state */ /* allocate decompression state */
if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) { if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) {
@ -433,43 +333,73 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
lzx->inbuf_size = input_buffer_size; lzx->inbuf_size = input_buffer_size;
lzx->window_size = 1 << window_bits; lzx->window_size = 1 << window_bits;
lzx->ref_data_size = 0;
lzx->window_posn = 0; lzx->window_posn = 0;
lzx->frame_posn = 0; lzx->frame_posn = 0;
lzx->frame = 0; lzx->frame = 0;
lzx->reset_interval = reset_interval; lzx->reset_interval = reset_interval;
lzx->intel_filesize = 0; lzx->intel_filesize = 0;
lzx->intel_curpos = 0; lzx->intel_curpos = 0;
/* window bits: 15 16 17 18 19 20 21
* position slots: 30 32 34 36 38 42 50 */
lzx->posn_slots = ((window_bits == 21) ? 50 :
((window_bits == 20) ? 42 : (window_bits << 1)));
lzx->intel_started = 0; lzx->intel_started = 0;
lzx->input_end = 0;
lzx->error = MSPACK_ERR_OK; lzx->error = MSPACK_ERR_OK;
lzx->num_offsets = position_slots[window_bits - 15] << 3;
lzx->is_delta = is_delta;
lzx->i_ptr = lzx->i_end = &lzx->inbuf[0];
lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0]; lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
lzx->bit_buffer = lzx->bits_left = 0;
lzxd_reset_state(lzx); lzxd_reset_state(lzx);
INIT_BITS;
return lzx; return lzx;
} }
int lzxd_set_reference_data(struct lzxd_stream *lzx,
struct mspack_system *system,
struct mspack_file *input,
unsigned int length)
{
if (!lzx) return MSPACK_ERR_ARGS;
if (!lzx->is_delta) {
D(("only LZX DELTA streams support reference data"))
return MSPACK_ERR_ARGS;
}
if (lzx->offset) {
D(("too late to set reference data after decoding starts"))
return MSPACK_ERR_ARGS;
}
if (length > lzx->window_size) {
D(("reference length (%u) is longer than the window", length))
return MSPACK_ERR_ARGS;
}
if (length > 0 && (!system || !input)) {
D(("length > 0 but no system or input"))
return MSPACK_ERR_ARGS;
}
lzx->ref_data_size = length;
if (length > 0) {
/* copy reference data */
unsigned char *pos = &lzx->window[lzx->window_size - length];
int bytes = system->read(input, pos, length);
/* length can't be more than 2^25, so no signedness problem */
if (bytes < (int)length) return MSPACK_ERR_READ;
}
lzx->ref_data_size = length;
return MSPACK_ERR_OK;
}
void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) { void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
if (lzx) lzx->length = out_bytes; if (lzx && out_bytes > 0) lzx->length = out_bytes;
} }
int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* bitstream reading and huffman variables */ /* bitstream and huffman reading variables */
unsigned int bit_buffer; unsigned int bit_buffer;
int bits_left, i=0; int bits_left, i=0;
unsigned short sym;
unsigned char *i_ptr, *i_end; unsigned char *i_ptr, *i_end;
unsigned short sym;
int match_length, length_footer, extra, verbatim_bits, bytes_todo; int match_length, length_footer, extra, verbatim_bits, bytes_todo;
int this_run, main_element, aligned_bits, j; int this_run, main_element, aligned_bits, j, warned = 0;
unsigned char *window, *runsrc, *rundest, buf[12]; unsigned char *window, *runsrc, *rundest, buf[12];
unsigned int frame_size=0, end_frame, match_offset, window_posn; unsigned int frame_size=0, end_frame, match_offset, window_posn;
unsigned int R0, R1, R2; unsigned int R0, R1, R2;
@ -505,12 +435,25 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* have we reached the reset interval? (if there is one?) */ /* have we reached the reset interval? (if there is one?) */
if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) { if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
if (lzx->block_remaining) { if (lzx->block_remaining) {
/* this is a file format error, we can make a best effort to extract what we can */
D(("%d bytes remaining at reset interval", lzx->block_remaining)) D(("%d bytes remaining at reset interval", lzx->block_remaining))
return lzx->error = MSPACK_ERR_DECRUNCH; if (!warned) {
lzx->sys->message(NULL, "WARNING; invalid reset interval detected during LZX decompression");
warned++;
}
} }
/* re-read the intel header and reset the huffman lengths */ /* re-read the intel header and reset the huffman lengths */
lzxd_reset_state(lzx); lzxd_reset_state(lzx);
R0 = lzx->R0;
R1 = lzx->R1;
R2 = lzx->R2;
}
/* LZX DELTA format has chunk_size, not present in LZX format */
if (lzx->is_delta) {
ENSURE_BITS(16);
REMOVE_BITS(16);
} }
/* read header if necessary */ /* read header if necessary */
@ -527,7 +470,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
* has been filled in. */ * has been filled in. */
frame_size = LZX_FRAME_SIZE; frame_size = LZX_FRAME_SIZE;
if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) { if (lzx->length && (lzx->length - lzx->offset) < (off_t)frame_size) {
frame_size = (unsigned int)(lzx->length - lzx->offset); frame_size = lzx->length - lzx->offset;
} }
/* decode until one more frame is available */ /* decode until one more frame is available */
@ -539,11 +482,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
(lzx->block_length & 1)) (lzx->block_length & 1))
{ {
if (i_ptr == i_end) { READ_IF_NEEDED;
if (lzxd_read_input(lzx)) return lzx->error;
i_ptr = lzx->i_ptr;
i_end = lzx->i_end;
}
i_ptr++; i_ptr++;
} }
@ -559,17 +498,17 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* read lengths of and build aligned huffman decoding tree */ /* read lengths of and build aligned huffman decoding tree */
for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; } for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
BUILD_TABLE(ALIGNED); BUILD_TABLE(ALIGNED);
/* no break -- rest of aligned header is same as verbatim */ /* rest of aligned header is same as verbatim */ /*@fallthrough@*/
case LZX_BLOCKTYPE_VERBATIM: case LZX_BLOCKTYPE_VERBATIM:
/* read lengths of and build main huffman decoding tree */ /* read lengths of and build main huffman decoding tree */
READ_LENGTHS(MAINTREE, 0, 256); READ_LENGTHS(MAINTREE, 0, 256);
READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3)); READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets);
BUILD_TABLE(MAINTREE); BUILD_TABLE(MAINTREE);
/* if the literal 0xE8 is anywhere in the block... */ /* if the literal 0xE8 is anywhere in the block... */
if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1; if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
/* read lengths of and build lengths huffman decoding tree */ /* read lengths of and build lengths huffman decoding tree */
READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
BUILD_TABLE(LENGTH); BUILD_TABLE_MAYBE_EMPTY(LENGTH);
break; break;
case LZX_BLOCKTYPE_UNCOMPRESSED: case LZX_BLOCKTYPE_UNCOMPRESSED:
@ -577,17 +516,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
lzx->intel_started = 1; lzx->intel_started = 1;
/* read 1-16 (not 0-15) bits to align to bytes */ /* read 1-16 (not 0-15) bits to align to bytes */
ENSURE_BITS(16); if (bits_left == 0) ENSURE_BITS(16);
if (bits_left > 16) i_ptr -= 2;
bits_left = 0; bit_buffer = 0; bits_left = 0; bit_buffer = 0;
/* read 12 bytes of stored R0 / R1 / R2 values */ /* read 12 bytes of stored R0 / R1 / R2 values */
for (rundest = &buf[0], i = 0; i < 12; i++) { for (rundest = &buf[0], i = 0; i < 12; i++) {
if (i_ptr == i_end) { READ_IF_NEEDED;
if (lzxd_read_input(lzx)) return lzx->error;
i_ptr = lzx->i_ptr;
i_end = lzx->i_end;
}
*rundest++ = *i_ptr++; *rundest++ = *i_ptr++;
} }
R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
@ -627,6 +561,10 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* get match length */ /* get match length */
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
if (match_length == LZX_NUM_PRIMARY_LENGTHS) { if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
if (lzx->LENGTH_empty) {
D(("LENGTH symbol needed but tree is empty"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
READ_HUFFSYM(LENGTH, length_footer); READ_HUFFSYM(LENGTH, length_footer);
match_length += length_footer; match_length += length_footer;
} }
@ -639,12 +577,37 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
case 2: match_offset = R2; R2=R0; R0 = match_offset; break; case 2: match_offset = R2; R2=R0; R0 = match_offset; break;
case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break; case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break;
default: default:
extra = extra_bits[match_offset]; extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
READ_BITS(verbatim_bits, extra); READ_BITS(verbatim_bits, extra);
match_offset = position_base[match_offset] - 2 + verbatim_bits; match_offset = position_base[match_offset] - 2 + verbatim_bits;
R2 = R1; R1 = R0; R0 = match_offset; R2 = R1; R1 = R0; R0 = match_offset;
} }
/* LZX DELTA uses max match length to signal even longer match */
if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
int extra_len = 0;
ENSURE_BITS(3); /* 4 entry huffman tree */
if (PEEK_BITS(1) == 0) {
REMOVE_BITS(1); /* '0' -> 8 extra length bits */
READ_BITS(extra_len, 8);
}
else if (PEEK_BITS(2) == 2) {
REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
READ_BITS(extra_len, 10);
extra_len += 0x100;
}
else if (PEEK_BITS(3) == 6) {
REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
READ_BITS(extra_len, 12);
extra_len += 0x500;
}
else {
REMOVE_BITS(3); /* '111' -> 15 extra length bits */
READ_BITS(extra_len, 15);
}
match_length += extra_len;
}
if ((window_posn + match_length) > lzx->window_size) { if ((window_posn + match_length) > lzx->window_size) {
D(("match ran over window wrap")) D(("match ran over window wrap"))
return lzx->error = MSPACK_ERR_DECRUNCH; return lzx->error = MSPACK_ERR_DECRUNCH;
@ -655,6 +618,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
i = match_length; i = match_length;
/* does match offset wrap the window? */ /* does match offset wrap the window? */
if (match_offset > window_posn) { if (match_offset > window_posn) {
if ((off_t)match_offset > lzx->offset &&
(match_offset - window_posn) > lzx->ref_data_size)
{
D(("match offset beyond LZX stream"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* j = length from match offset to end of window */ /* j = length from match offset to end of window */
j = match_offset - window_posn; j = match_offset - window_posn;
if (j > (int) lzx->window_size) { if (j > (int) lzx->window_size) {
@ -695,6 +664,10 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* get match length */ /* get match length */
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
if (match_length == LZX_NUM_PRIMARY_LENGTHS) { if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
if (lzx->LENGTH_empty) {
D(("LENGTH symbol needed but tree is empty"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
READ_HUFFSYM(LENGTH, length_footer); READ_HUFFSYM(LENGTH, length_footer);
match_length += length_footer; match_length += length_footer;
} }
@ -706,7 +679,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
case 1: match_offset = R1; R1 = R0; R0 = match_offset; break; case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
case 2: match_offset = R2; R2 = R0; R0 = match_offset; break; case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
default: default:
extra = extra_bits[match_offset]; extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
match_offset = position_base[match_offset] - 2; match_offset = position_base[match_offset] - 2;
if (extra > 3) { if (extra > 3) {
/* verbatim and aligned bits */ /* verbatim and aligned bits */
@ -734,6 +707,31 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
R2 = R1; R1 = R0; R0 = match_offset; R2 = R1; R1 = R0; R0 = match_offset;
} }
/* LZX DELTA uses max match length to signal even longer match */
if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
int extra_len = 0;
ENSURE_BITS(3); /* 4 entry huffman tree */
if (PEEK_BITS(1) == 0) {
REMOVE_BITS(1); /* '0' -> 8 extra length bits */
READ_BITS(extra_len, 8);
}
else if (PEEK_BITS(2) == 2) {
REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
READ_BITS(extra_len, 10);
extra_len += 0x100;
}
else if (PEEK_BITS(3) == 6) {
REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
READ_BITS(extra_len, 12);
extra_len += 0x500;
}
else {
REMOVE_BITS(3); /* '111' -> 15 extra length bits */
READ_BITS(extra_len, 15);
}
match_length += extra_len;
}
if ((window_posn + match_length) > lzx->window_size) { if ((window_posn + match_length) > lzx->window_size) {
D(("match ran over window wrap")) D(("match ran over window wrap"))
return lzx->error = MSPACK_ERR_DECRUNCH; return lzx->error = MSPACK_ERR_DECRUNCH;
@ -744,6 +742,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
i = match_length; i = match_length;
/* does match offset wrap the window? */ /* does match offset wrap the window? */
if (match_offset > window_posn) { if (match_offset > window_posn) {
if ((off_t)match_offset > lzx->offset &&
(match_offset - window_posn) > lzx->ref_data_size)
{
D(("match offset beyond LZX stream"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* j = length from match offset to end of window */ /* j = length from match offset to end of window */
j = match_offset - window_posn; j = match_offset - window_posn;
if (j > (int) lzx->window_size) { if (j > (int) lzx->window_size) {
@ -775,18 +779,16 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
rundest = &window[window_posn]; rundest = &window[window_posn];
window_posn += this_run; window_posn += this_run;
while (this_run > 0) { while (this_run > 0) {
if ((i = (int)(i_end - i_ptr))) { if ((i = (int)(i_end - i_ptr)) == 0) {
READ_IF_NEEDED;
}
else {
if (i > this_run) i = this_run; if (i > this_run) i = this_run;
lzx->sys->copy(i_ptr, rundest, (size_t) i); lzx->sys->copy(i_ptr, rundest, (size_t) i);
rundest += i; rundest += i;
i_ptr += i; i_ptr += i;
this_run -= i; this_run -= i;
} }
else {
if (lzxd_read_input(lzx)) return lzx->error;
i_ptr = lzx->i_ptr;
i_end = lzx->i_end;
}
} }
break; break;
@ -818,7 +820,8 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* check that we've used all of the previous frame first */ /* check that we've used all of the previous frame first */
if (lzx->o_ptr != lzx->o_end) { if (lzx->o_ptr != lzx->o_end) {
D(("%d avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size)) D(("%ld avail bytes, new %d frame",
(long)(lzx->o_end - lzx->o_ptr), frame_size))
return lzx->error = MSPACK_ERR_DECRUNCH; return lzx->error = MSPACK_ERR_DECRUNCH;
} }

File diff suppressed because it is too large Load Diff

207
third_party/mspack/readbits.h vendored Normal file
View File

@ -0,0 +1,207 @@
/* This file is part of libmspack.
* (C) 2003-2010 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
*
* For further details, see the file COPYING.LIB distributed with libmspack
*/
#ifndef MSPACK_READBITS_H
#define MSPACK_READBITS_H 1
/* this header defines macros that read data streams by
* the individual bits
*
* INIT_BITS initialises bitstream state in state structure
* STORE_BITS stores bitstream state in state structure
* RESTORE_BITS restores bitstream state from state structure
* ENSURE_BITS(n) ensure there are at least N bits in the bit buffer
* READ_BITS(var,n) takes N bits from the buffer and puts them in var
* PEEK_BITS(n) extracts without removing N bits from the bit buffer
* REMOVE_BITS(n) removes N bits from the bit buffer
*
* READ_BITS simply calls ENSURE_BITS, PEEK_BITS and REMOVE_BITS,
* which means it's limited to reading the number of bits you can
* ensure at any one time. It also fails if asked to read zero bits.
* If you need to read zero bits, or more bits than can be ensured in
* one go, use READ_MANY_BITS instead.
*
* These macros have variable names baked into them, so to use them
* you have to define some macros:
* - BITS_TYPE: the type name of your state structure
* - BITS_VAR: the variable that points to your state structure
* - define BITS_ORDER_MSB if bits are read from the MSB, or
* define BITS_ORDER_LSB if bits are read from the LSB
* - READ_BYTES: some code that reads more data into the bit buffer,
* it should use READ_IF_NEEDED (calls read_input if the byte buffer
* is empty), then INJECT_BITS(data,n) to put data from the byte
* buffer into the bit buffer.
*
* You also need to define some variables and structure members:
* - unsigned char *i_ptr; // current position in the byte buffer
* - unsigned char *i_end; // end of the byte buffer
* - unsigned int bit_buffer; // the bit buffer itself
* - unsigned int bits_left; // number of bits remaining
*
* If you use read_input() and READ_IF_NEEDED, they also expect these
* structure members:
* - struct mspack_system *sys; // to access sys->read()
* - unsigned int error; // to record/return read errors
* - unsigned char input_end; // to mark reaching the EOF
* - unsigned char *inbuf; // the input byte buffer
* - unsigned int inbuf_size; // the size of the input byte buffer
*
* Your READ_BYTES implementation should read data from *i_ptr and
* put them in the bit buffer. READ_IF_NEEDED will call read_input()
* if i_ptr reaches i_end, and will fill up inbuf and set i_ptr to
* the start of inbuf and i_end to the end of inbuf.
*
* If you're reading in MSB order, the routines work by using the area
* beyond the MSB and the LSB of the bit buffer as a free source of
* zeroes when shifting. This avoids having to mask any bits. So we
* have to know the bit width of the bit buffer variable. We use
* <limits.h> and CHAR_BIT to find the size of the bit buffer in bits.
*
* If you are reading in LSB order, bits need to be masked. Normally
* this is done by computing the mask: N bits are masked by the value
* (1<<N)-1). However, you can define BITS_LSB_TABLE to use a lookup
* table instead of computing this. This adds two new macros,
* PEEK_BITS_T and READ_BITS_T which work the same way as PEEK_BITS
* and READ_BITS, except they use this lookup table. This is useful if
* you need to look up a number of bits that are only known at
* runtime, so the bit mask can't be turned into a constant by the
* compiler.
* The bit buffer datatype should be at least 32 bits wide: it must be
* possible to ENSURE_BITS(17), so it must be possible to add 16 new bits
* to the bit buffer when the bit buffer already has 1 to 15 bits left.
*/
#ifndef BITS_VAR
# error "define BITS_VAR as the state structure poiner variable name"
#endif
#ifndef BITS_TYPE
# error "define BITS_TYPE as the state structure type"
#endif
#if defined(BITS_ORDER_MSB) && defined(BITS_ORDER_LSB)
# error "you must define either BITS_ORDER_MSB or BITS_ORDER_LSB"
#else
# if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
# error "you must define BITS_ORDER_MSB or BITS_ORDER_LSB"
# endif
#endif
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#ifndef CHAR_BIT
# define CHAR_BIT (8)
#endif
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
#define INIT_BITS do { \
BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
BITS_VAR->bit_buffer = 0; \
BITS_VAR->bits_left = 0; \
BITS_VAR->input_end = 0; \
} while (0)
#define STORE_BITS do { \
BITS_VAR->i_ptr = i_ptr; \
BITS_VAR->i_end = i_end; \
BITS_VAR->bit_buffer = bit_buffer; \
BITS_VAR->bits_left = bits_left; \
} while (0)
#define RESTORE_BITS do { \
i_ptr = BITS_VAR->i_ptr; \
i_end = BITS_VAR->i_end; \
bit_buffer = BITS_VAR->bit_buffer; \
bits_left = BITS_VAR->bits_left; \
} while (0)
#define ENSURE_BITS(nbits) do { \
while (bits_left < (nbits)) READ_BYTES; \
} while (0)
#define READ_BITS(val, nbits) do { \
ENSURE_BITS(nbits); \
(val) = PEEK_BITS(nbits); \
REMOVE_BITS(nbits); \
} while (0)
#define READ_MANY_BITS(val, bits) do { \
unsigned char needed = (bits), bitrun; \
(val) = 0; \
while (needed > 0) { \
if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
bitrun = (bits_left < needed) ? bits_left : needed; \
(val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
REMOVE_BITS(bitrun); \
needed -= bitrun; \
} \
} while (0)
#ifdef BITS_ORDER_MSB
# define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
# define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
(bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), (bits_left += (nbits)))
#else /* BITS_ORDER_LSB */
# define PEEK_BITS(nbits) (bit_buffer & ((1 << (nbits))-1))
# define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits)))
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
(bitdata) << bits_left), (bits_left += (nbits)))
#endif
#ifdef BITS_LSB_TABLE
/* lsb_bit_mask[n] = (1 << n) - 1 */
static const unsigned short lsb_bit_mask[17] = {
0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};
# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
# define READ_BITS_T(val, nbits) do { \
ENSURE_BITS(nbits); \
(val) = PEEK_BITS_T(nbits); \
REMOVE_BITS(nbits); \
} while (0)
#endif
#ifndef BITS_NO_READ_INPUT
# define READ_IF_NEEDED do { \
if (i_ptr >= i_end) { \
if (read_input(BITS_VAR)) \
return BITS_VAR->error; \
i_ptr = BITS_VAR->i_ptr; \
i_end = BITS_VAR->i_end; \
} \
} while (0)
static int read_input(BITS_TYPE *p) {
int read = p->sys->read(p->input, &p->inbuf[0], (int)p->inbuf_size);
if (read < 0) return p->error = MSPACK_ERR_READ;
/* we might overrun the input stream by asking for bits we don't use,
* so fake 2 more bytes at the end of input */
if (read == 0) {
if (p->input_end) {
D(("out of input bytes"))
return p->error = MSPACK_ERR_READ;
}
else {
read = 2;
p->inbuf[0] = p->inbuf[1] = 0;
p->input_end = 1;
}
}
/* update i_ptr and i_end */
p->i_ptr = &p->inbuf[0];
p->i_end = &p->inbuf[read];
return MSPACK_ERR_OK;
}
#endif
#endif

172
third_party/mspack/readhuff.h vendored Normal file
View File

@ -0,0 +1,172 @@
/* This file is part of libmspack.
* (C) 2003-2014 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
*
* For further details, see the file COPYING.LIB distributed with libmspack
*/
#ifndef MSPACK_READHUFF_H
#define MSPACK_READHUFF_H 1
/* This implements a fast Huffman tree decoding system. */
#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
# error "readhuff.h is used in conjunction with readbits.h, include that first"
#endif
#if !(defined(TABLEBITS) && defined(MAXSYMBOLS))
# error "define TABLEBITS(tbl) and MAXSYMBOLS(tbl) before using readhuff.h"
#endif
#if !(defined(HUFF_TABLE) && defined(HUFF_LEN))
# error "define HUFF_TABLE(tbl) and HUFF_LEN(tbl) before using readhuff.h"
#endif
#ifndef HUFF_ERROR
# error "define HUFF_ERROR before using readhuff.h"
#endif
#ifndef HUFF_MAXBITS
# define HUFF_MAXBITS 16
#endif
/* Decodes the next huffman symbol from the input bitstream into var.
* Do not use this macro on a table unless build_decode_table() succeeded.
*/
#define READ_HUFFSYM(tbl, var) do { \
ENSURE_BITS(HUFF_MAXBITS); \
sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
(var) = sym; \
i = HUFF_LEN(tbl, sym); \
REMOVE_BITS(i); \
} while (0)
#ifdef BITS_ORDER_LSB
# define HUFF_TRAVERSE(tbl) do { \
i = TABLEBITS(tbl) - 1; \
do { \
if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
sym = HUFF_TABLE(tbl, \
(sym << 1) | ((bit_buffer >> i) & 1)); \
} while (sym >= MAXSYMBOLS(tbl)); \
} while (0)
#else
#define HUFF_TRAVERSE(tbl) do { \
i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
do { \
if ((i >>= 1) == 0) HUFF_ERROR; \
sym = HUFF_TABLE(tbl, \
(sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
} while (sym >= MAXSYMBOLS(tbl)); \
} while (0)
#endif
/* make_decode_table(nsyms, nbits, length[], table[])
*
* This function was originally coded by David Tritscher.
* It builds a fast huffman decoding table from
* a canonical huffman code lengths table.
*
* nsyms = total number of symbols in this huffman tree.
* nbits = any symbols with a code length of nbits or less can be decoded
* in one lookup of the table.
* length = A table to get code lengths from [0 to nsyms-1]
* table = The table to fill up with decoded symbols and pointers.
* Should be ((1<<nbits) + (nsyms*2)) in length.
*
* Returns 0 for OK or 1 for error
*/
static int make_decode_table(unsigned int nsyms, unsigned int nbits,
unsigned char *length, unsigned short *table)
{
register unsigned short sym, next_symbol;
register unsigned int leaf, fill;
#ifdef BITS_ORDER_LSB
register unsigned int reverse;
#endif
register unsigned char bit_num;
unsigned int pos = 0; /* the current position in the decode table */
unsigned int table_mask = 1 << nbits;
unsigned int bit_mask = table_mask >> 1; /* don't do 0 length codes */
/* fill entries for codes short enough for a direct mapping */
for (bit_num = 1; bit_num <= nbits; bit_num++) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] != bit_num) continue;
#ifdef BITS_ORDER_MSB
leaf = pos;
#else
/* reverse the significant bits */
fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
#endif
if((pos += bit_mask) > table_mask) return 1; /* table overrun */
/* fill all possible lookups of this symbol with the symbol itself */
#ifdef BITS_ORDER_MSB
for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
#else
fill = bit_mask; next_symbol = 1 << bit_num;
do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
#endif
}
bit_mask >>= 1;
}
/* exit with success if table is now complete */
if (pos == table_mask) return 0;
/* mark all remaining table entries as unused */
for (sym = pos; sym < table_mask; sym++) {
#ifdef BITS_ORDER_MSB
table[sym] = 0xFFFF;
#else
reverse = sym; leaf = 0; fill = nbits;
do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
table[leaf] = 0xFFFF;
#endif
}
/* next_symbol = base of allocation for long codes */
next_symbol = ((table_mask >> 1) < nsyms) ? nsyms : (table_mask >> 1);
/* give ourselves room for codes to grow by up to 16 more bits.
* codes now start at bit nbits+16 and end at (nbits+16-codelength) */
pos <<= 16;
table_mask <<= 16;
bit_mask = 1 << 15;
for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
for (sym = 0; sym < nsyms; sym++) {
if (length[sym] != bit_num) continue;
if (pos >= table_mask) return 1; /* table overflow */
#ifdef BITS_ORDER_MSB
leaf = pos >> 16;
#else
/* leaf = the first nbits of the code, reversed */
reverse = pos >> 16; leaf = 0; fill = nbits;
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
#endif
for (fill = 0; fill < (bit_num - nbits); fill++) {
/* if this path hasn't been taken yet, 'allocate' two entries */
if (table[leaf] == 0xFFFF) {
table[(next_symbol << 1) ] = 0xFFFF;
table[(next_symbol << 1) + 1 ] = 0xFFFF;
table[leaf] = next_symbol++;
}
/* follow the path and select either left or right for next bit */
leaf = table[leaf] << 1;
if ((pos >> (15-fill)) & 1) leaf++;
}
table[leaf] = sym;
pos += bit_mask;
}
bit_mask >>= 1;
}
/* full table? */
return (pos == table_mask) ? 0 : 1;
}
#endif

242
third_party/mspack/system.c vendored Normal file
View File

@ -0,0 +1,242 @@
/* This file is part of libmspack.
* (C) 2003-2004 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
*
* For further details, see the file COPYING.LIB distributed with libmspack
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <system.h>
#if !LARGEFILE_SUPPORT
const char *largefile_msg = "library not compiled to support large files.";
#endif
int mspack_version(int entity) {
switch (entity) {
/* CHM decoder version 1 -> 2 changes:
* - added mschmd_sec_mscompressed::spaninfo
* - added mschmd_header::first_pmgl
* - added mschmd_header::last_pmgl
* - added mschmd_header::chunk_cache;
*/
case MSPACK_VER_MSCHMD:
/* CAB decoder version 1 -> 2 changes:
* - added MSCABD_PARAM_SALVAGE
*/
case MSPACK_VER_MSCABD:
return 2;
case MSPACK_VER_LIBRARY:
case MSPACK_VER_SYSTEM:
case MSPACK_VER_MSSZDDD:
case MSPACK_VER_MSKWAJD:
case MSPACK_VER_MSOABD:
return 1;
case MSPACK_VER_MSCABC:
case MSPACK_VER_MSCHMC:
case MSPACK_VER_MSLITD:
case MSPACK_VER_MSLITC:
case MSPACK_VER_MSHLPD:
case MSPACK_VER_MSHLPC:
case MSPACK_VER_MSSZDDC:
case MSPACK_VER_MSKWAJC:
case MSPACK_VER_MSOABC:
return 0;
}
return -1;
}
int mspack_sys_selftest_internal(int offt_size) {
return (sizeof(off_t) == offt_size) ? MSPACK_ERR_OK : MSPACK_ERR_SEEK;
}
/* validates a system structure */
int mspack_valid_system(struct mspack_system *sys) {
return (sys != NULL) && (sys->open != NULL) && (sys->close != NULL) &&
(sys->read != NULL) && (sys->write != NULL) && (sys->seek != NULL) &&
(sys->tell != NULL) && (sys->message != NULL) && (sys->alloc != NULL) &&
(sys->free != NULL) && (sys->copy != NULL) && (sys->null_ptr == NULL);
}
/* returns the length of a file opened for reading */
int mspack_sys_filelen(struct mspack_system *system,
struct mspack_file *file, off_t *length)
{
off_t current;
if (!system || !file || !length) return MSPACK_ERR_OPEN;
/* get current offset */
current = system->tell(file);
/* seek to end of file */
if (system->seek(file, (off_t) 0, MSPACK_SYS_SEEK_END)) {
return MSPACK_ERR_SEEK;
}
/* get offset of end of file */
*length = system->tell(file);
/* seek back to original offset */
if (system->seek(file, current, MSPACK_SYS_SEEK_START)) {
return MSPACK_ERR_SEEK;
}
return MSPACK_ERR_OK;
}
/* definition of mspack_default_system -- if the library is compiled with
* MSPACK_NO_DEFAULT_SYSTEM, no default system will be provided. Otherwise,
* an appropriate default system (e.g. the standard C library, or some native
* API calls)
*/
#ifdef MSPACK_NO_DEFAULT_SYSTEM
struct mspack_system *mspack_default_system = NULL;
#else
/* implementation of mspack_default_system for standard C library */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
struct mspack_file_p {
FILE *fh;
const char *name;
};
static struct mspack_file *msp_open(struct mspack_system *self,
const char *filename, int mode)
{
struct mspack_file_p *fh;
const char *fmode;
switch (mode) {
case MSPACK_SYS_OPEN_READ: fmode = "rb"; break;
case MSPACK_SYS_OPEN_WRITE: fmode = "wb"; break;
case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
case MSPACK_SYS_OPEN_APPEND: fmode = "ab"; break;
default: return NULL;
}
if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
fh->name = filename;
if ((fh->fh = fopen(filename, fmode))) return (struct mspack_file *) fh;
free(fh);
}
return NULL;
}
static void msp_close(struct mspack_file *file) {
struct mspack_file_p *self = (struct mspack_file_p *) file;
if (self) {
fclose(self->fh);
free(self);
}
}
static int msp_read(struct mspack_file *file, void *buffer, int bytes) {
struct mspack_file_p *self = (struct mspack_file_p *) file;
if (self && buffer && bytes >= 0) {
size_t count = fread(buffer, 1, (size_t) bytes, self->fh);
if (!ferror(self->fh)) return (int) count;
}
return -1;
}
static int msp_write(struct mspack_file *file, void *buffer, int bytes) {
struct mspack_file_p *self = (struct mspack_file_p *) file;
if (self && buffer && bytes >= 0) {
size_t count = fwrite(buffer, 1, (size_t) bytes, self->fh);
if (!ferror(self->fh)) return (int) count;
}
return -1;
}
static int msp_seek(struct mspack_file *file, off_t offset, int mode) {
struct mspack_file_p *self = (struct mspack_file_p *) file;
if (self) {
switch (mode) {
case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
case MSPACK_SYS_SEEK_CUR: mode = SEEK_CUR; break;
case MSPACK_SYS_SEEK_END: mode = SEEK_END; break;
default: return -1;
}
#if HAVE_FSEEKO
return fseeko(self->fh, offset, mode);
#else
return fseek(self->fh, offset, mode);
#endif
}
return -1;
}
static off_t msp_tell(struct mspack_file *file) {
struct mspack_file_p *self = (struct mspack_file_p *) file;
#if HAVE_FSEEKO
return (self) ? (off_t) ftello(self->fh) : 0;
#else
return (self) ? (off_t) ftell(self->fh) : 0;
#endif
}
static void msp_msg(struct mspack_file *file, const char *format, ...) {
va_list ap;
if (file) fprintf(stderr, "%s: ", ((struct mspack_file_p *) file)->name);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fputc((int) '\n', stderr);
fflush(stderr);
}
static void *msp_alloc(struct mspack_system *self, size_t bytes) {
#if DEBUG
/* make uninitialised data obvious */
char *buf = malloc(bytes + 8);
if (buf) memset(buf, 0xDC, bytes);
*((size_t *)buf) = bytes;
return &buf[8];
#else
return malloc(bytes);
#endif
}
static void msp_free(void *buffer) {
#if DEBUG
char *buf = buffer;
size_t bytes;
if (buf) {
buf -= 8;
bytes = *((size_t *)buf);
/* make freed data obvious */
memset(buf, 0xED, bytes);
free(buf);
}
#else
free(buffer);
#endif
}
static void msp_copy(void *src, void *dest, size_t bytes) {
memcpy(dest, src, bytes);
}
static struct mspack_system msp_system = {
&msp_open, &msp_close, &msp_read, &msp_write, &msp_seek,
&msp_tell, &msp_msg, &msp_alloc, &msp_free, &msp_copy, NULL
};
struct mspack_system *mspack_default_system = &msp_system;
#endif

113
third_party/mspack/system.h vendored Normal file
View File

@ -0,0 +1,113 @@
/* This file is part of libmspack.
* (C) 2003-2018 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
*
* For further details, see the file COPYING.LIB distributed with libmspack
*/
#ifndef MSPACK_SYSTEM_H
#define MSPACK_SYSTEM_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* ensure config.h is read before mspack.h */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <mspack.h>
/* assume <string.h> exists */
#include <string.h>
/* fix for problem with GCC 4 and glibc (thanks to Ville Skytta)
* http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=150429
*/
#ifdef read
# undef read
#endif
/* Old GCCs don't have __func__, but __FUNCTION__:
* http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
*/
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
# define __func__ __FUNCTION__
# else
# define __func__ "<unknown>"
# endif
#endif
#if DEBUG
# include <stdio.h>
# define D(x) do { printf("%s:%d (%s) ",__FILE__, __LINE__, __func__); \
printf x ; fputc('\n', stdout); fflush(stdout);} while (0);
#else
# define D(x)
#endif
/* CAB supports searching through files over 4GB in size, and the CHM file
* format actively uses 64-bit offsets. These can only be fully supported
* if the system the code runs on supports large files. If not, the library
* will work as normal using only 32-bit arithmetic, but if an offset
* greater than 2GB is detected, an error message indicating the library
* can't support the file should be printed.
*/
#if HAVE_INTTYPES_H
# include <inttypes.h>
#else
# define PRId64 "lld"
# define PRIu64 "llu"
# define PRId32 "ld"
# define PRIu32 "lu"
#endif
#include <limits.h>
#if ((defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS >= 64) || \
(defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE) || \
SIZEOF_OFF_T >= 8)
# define LARGEFILE_SUPPORT 1
# define LD PRId64
# define LU PRIu64
#else
extern const char *largefile_msg;
# define LD PRId32
# define LU PRIu32
#endif
/* endian-neutral reading of little-endian data */
#define __egi32(a,n) ( ((((unsigned char *) a)[n+3]) << 24) | \
((((unsigned char *) a)[n+2]) << 16) | \
((((unsigned char *) a)[n+1]) << 8) | \
((((unsigned char *) a)[n+0])))
#define EndGetI64(a) ((((unsigned long long int) __egi32(a,4)) << 32) | \
((unsigned int) __egi32(a,0)))
#define EndGetI32(a) __egi32(a,0)
#define EndGetI16(a) ((((a)[1])<<8)|((a)[0]))
/* endian-neutral reading of big-endian data */
#define EndGetM32(a) (((((unsigned char *) a)[0]) << 24) | \
((((unsigned char *) a)[1]) << 16) | \
((((unsigned char *) a)[2]) << 8) | \
((((unsigned char *) a)[3])))
#define EndGetM16(a) ((((a)[0])<<8)|((a)[1]))
extern struct mspack_system *mspack_default_system;
/* returns the length of a file opened for reading */
extern int mspack_sys_filelen(struct mspack_system *system,
struct mspack_file *file, off_t *length);
/* validates a system structure */
extern int mspack_valid_system(struct mspack_system *sys);
#ifdef __cplusplus
}
#endif
#endif