add lzma.js in thirdparty
This commit is contained in:
Родитель
19520c66ee
Коммит
ee1fc9904b
|
@ -0,0 +1,37 @@
|
|||
|
||||
lzma.js
|
||||
=======
|
||||
|
||||
An LZMA implementation in JavaScript, compiled from lzip using Emscripten
|
||||
with the goal of having a small and fast implementation as much as
|
||||
possible.
|
||||
|
||||
lzip is GPL, additional code is MIT
|
||||
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Run doit.sh. It will build both a native build, lzma-native, and lzma.js.
|
||||
Both are useful because you can use the native build to compress locally,
|
||||
and the JS build to decompress on the client browser. But, you can use
|
||||
whichever you want in either location.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
LZMA.compress(data) receives an array of 8-bit data and returns an
|
||||
array of compressed data.
|
||||
|
||||
LZMA.decompress(data) receives an array of compressed 8-bit data and
|
||||
returns an array of decompressed data.
|
||||
|
||||
|
||||
Use lzma-decoder.js if you just need to decode. It's 66K, or 23K
|
||||
if your webserver does gzip. If you need compression too, use
|
||||
lzma-full.js which is a little larger.
|
||||
|
||||
See test-decoder.js, test-full.js and test-full.html for example
|
||||
uses.
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
cd lzip
|
||||
|
||||
echo "native"
|
||||
make clean
|
||||
DECODER_ONLY=0 make lzip -j 4 # native build
|
||||
mv lzip ../lzma-native
|
||||
|
||||
echo "bitcode full (encoder+decoder)"
|
||||
make clean
|
||||
DECODER_ONLY=0 ~/Dev/emscripten/emmake make lzip -j 4
|
||||
mv lzip lzip-full.bc
|
||||
|
||||
echo "bitcode decoder only"
|
||||
make clean
|
||||
DECODER_ONLY=1 ~/Dev/emscripten/emmake make lzip -j 4
|
||||
mv lzip lzip-decoder.bc
|
||||
|
||||
cd ..
|
||||
|
||||
echo "javascript full"
|
||||
~/Dev/emscripten/emcc -O2 lzip/lzip-full.bc -o lzma-full.raw.js
|
||||
# -s INLINING_LIMIT=0
|
||||
cat pre.js > lzma-full.js
|
||||
cat lzma-full.raw.js >> lzma-full.js
|
||||
cat post.js >> lzma-full.js
|
||||
|
||||
echo "javascript decoder"
|
||||
~/Dev/emscripten/emcc -O2 lzip/lzip-decoder.bc -o lzma-decoder.raw.js
|
||||
# -s INLINING_LIMIT=0
|
||||
cat pre.js > lzma-decoder.js
|
||||
cat lzma-decoder.raw.js >> lzma-decoder.js
|
||||
cat post.js >> lzma-decoder.js
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Lzip was written by Antonio Diaz Diaz.
|
||||
|
||||
The ideas embodied in lzip are due to (at least) the following people:
|
||||
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
|
||||
the definition of Markov chains), G.N.N. Martin (for the definition of
|
||||
range encoding), Igor Pavlov (for putting all the above together in
|
||||
LZMA), and Julian Seward (for bzip2's CLI and the idea of unzcrash).
|
|
@ -0,0 +1,676 @@
|
|||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, 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
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state 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 program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
2011-04-30 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.12 released.
|
||||
* main.cc: Added new option `-F, --recompress'.
|
||||
* encoder.h (update_prices): Update high length symbol prices
|
||||
independently of the value of `pos_state'. This gives better
|
||||
compression for large values of `--match-length' without being
|
||||
slower.
|
||||
* encoder.h encoder.cc: Optimize pair price calculations. This
|
||||
reduces compression time for large values of `--match-length'
|
||||
by up to 6%.
|
||||
* Compression time of option `-0' has been reduced by 2%.
|
||||
* main.cc (decompress): Print only one status line for each
|
||||
multimember file when only one `-v' is specified.
|
||||
* main.cc (decompress): Print up to 6 bytes of trailing garbage
|
||||
when `-vvvv' is specified.
|
||||
* main.cc (open_instream): Do not show the message
|
||||
" and `--stdout' was not specified" for directories, etc.
|
||||
* lziprecover.cc: If `-v' is not specified show errors only.
|
||||
* testsuite/unzcrash.cc: Use Arg_parser.
|
||||
* testsuite/unzcrash.cc: Added new options `-b', `-p' and `-s'.
|
||||
|
||||
2010-09-16 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.11 released.
|
||||
* Added new option `-0' which produces a compression speed and
|
||||
ratio comparable to those of `gzip -9'.
|
||||
* fast_encoder.h fast_encoder.cc: New files.
|
||||
* main.cc: Match length limit set by options -1 to -8 has been
|
||||
reduced to extend range of use towards gzip. Lower numbers now
|
||||
compress less but faster. (-1 now takes 43% less time for only
|
||||
20% larger compressed size).
|
||||
* encoder.cc: Compression of option -9 has been slightly increased.
|
||||
* lziprecover.cc: Added new option `--merge' which tries to
|
||||
produce a correct file merging the good parts of two or more
|
||||
damaged copies.
|
||||
* lziprecover.cc: Added new option `--repair' for repairing a
|
||||
1-byte error in single-member files.
|
||||
* decoder.cc (decode_member): Detect file errors earlier to
|
||||
improve efficiency of lziprecover's new repair capability.
|
||||
This change also prevents (harmless) access to uninitialized
|
||||
memory when decompressing a corrupt file.
|
||||
* lziprecover.cc: Added new option `--force'.
|
||||
* lziprecover.cc: Added new option `--output'.
|
||||
* lziprecover.cc: Added new option `--split' to select the until
|
||||
now only operation of splitting multimember files.
|
||||
* lziprecover.cc: If no operation is specified, warn the user
|
||||
and do nothing.
|
||||
* main.cc: Fixed warning about fchown's return value being ignored.
|
||||
* decoder.cc: `-tvvvv' now also shows compression ratio.
|
||||
* main.cc: Set stdin/stdout in binary mode on MSVC and OS2.
|
||||
* New examples have been added to the manual.
|
||||
* testsuite: `test1' renamed to `test.txt'. Added new tests.
|
||||
* Matchfinder types HC4 (4 bytes hash-chain) and HT4 (4 bytes
|
||||
hash-table) have been tested and found no better than the
|
||||
current BT4.
|
||||
|
||||
2010-04-05 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.10 released.
|
||||
* decoder.h: Input_buffer integrated in Range_decoder.
|
||||
* main.cc: File specified with option `-o' is now created with
|
||||
mode 0666 if umask allows it, deleted if interrupted by user.
|
||||
* main.cc: New constant `o_binary'.
|
||||
* main.cc: Dictionary size for options -2, -3, -4 and -8 has
|
||||
been changed to improve linearity of compressed sizes.
|
||||
* lzip.h: Fixed warnings produced by over-optimization (-O3).
|
||||
* Makefile.in: Added quotes to directory names.
|
||||
|
||||
2010-01-17 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.9 released.
|
||||
* main.cc (main): Return at least 1 if closing stdout fails.
|
||||
* Makefile.in: Added `--name' option to help2man invocation.
|
||||
* testsuite/check.sh: Use `test1' instead of `COPYING' for testing.
|
||||
|
||||
2009-09-02 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.8 released.
|
||||
* Compression time has been reduced by 4%.
|
||||
* Lzdiff and lzgrep have been moved to the new package zutils.
|
||||
* Fixed warnings on sistems where uint32_t != unsigned int.
|
||||
|
||||
2009-06-25 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.7 released.
|
||||
* decoder.h (copy_block): Fixed memcpy overlap introduced in 1.6.
|
||||
|
||||
2009-06-22 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.6 released.
|
||||
* Decompression time has been reduced by 17%.
|
||||
* Added decompression support for Sync Flush marker.
|
||||
* Added support for .tbz extension to lzdiff and lzgrep.
|
||||
* Added man pages for lzdiff, lzgrep and lziprecover.
|
||||
* encoder.cc (Matchfinder): Reduce memory use to 9x if input file
|
||||
is smaller than dictionary size limit.
|
||||
* decoder.cc: Added extra flush calls to improve partial
|
||||
decompression of corrupt files.
|
||||
* `--test' no more needs `/dev/null'.
|
||||
* Removed some `bashisms' from lzdiff and lzgrep.
|
||||
* Dictionary size for options `-1' to `-4' has been changed.
|
||||
* main.cc (signal_handler): Declared as `extern "C"'.
|
||||
* Makefile.in: Extra files are now installed by default.
|
||||
* testsuite/check.sh: Test lziprecover.
|
||||
* Added `export LC_ALL=C' to all scripts.
|
||||
|
||||
2009-04-12 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.5 released.
|
||||
* lzip.h: Coded dictionary size implemented in File_header.
|
||||
* Fixed some includes that prevented compilation with GCC 4.4.
|
||||
* `member_size' and `volume_size' are now accurate limits.
|
||||
* Compression speed has been improved.
|
||||
* Implemented bt4 type matchfinder.
|
||||
* Added chapter `Algorithm' to the manual.
|
||||
* Lzdiff and lzgrep now accept `-h' for `--help' and
|
||||
`-V' for `--version'.
|
||||
* Makefile.in: Man page is now installed by default.
|
||||
* testsuite/check.sh: Verify that files are open in binary mode.
|
||||
|
||||
2009-01-24 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.4 released.
|
||||
* Implemented compression of version 1 files.
|
||||
* Added new option `--member-size'.
|
||||
* Added new option `--volume-size'.
|
||||
* Added new option `--output'.
|
||||
* main.cc: Read from non regular files if `--stdout' is specified.
|
||||
* Added `lziprecover', a member recoverer program.
|
||||
* testsuite/unzcrash.cc: Test all 1-byte errors.
|
||||
|
||||
2008-12-21 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.3 released.
|
||||
* This version automatically chooses the smallest possible
|
||||
dictionary size for each file during compression, saving
|
||||
memory during decompression.
|
||||
* Implemented decompression of version 1 files.
|
||||
* testsuite/check.sh: Replaced `diff -q' with `cmp'.
|
||||
|
||||
2008-12-10 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.2 released.
|
||||
* encoder.cc: A 1-byte read outside allocated memory has been fixed.
|
||||
* lzip.h: Dictionary size limit has been reduced to 512MiB because
|
||||
setting it to 1GiB causes overflow of a 32 bit integer.
|
||||
* Added `lzdiff', a diff/cmp wrapper for gzip, bzip2, lzip and
|
||||
non-compressed files.
|
||||
* Added `lzgrep', a grep wrapper for gzip, bzip2, lzip and
|
||||
non-compressed files.
|
||||
* `make install-info' should now work on Debian and OS X.
|
||||
|
||||
2008-11-17 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.1 released.
|
||||
* Changed short name of option `--dictionary-size' to `-s'.
|
||||
* Changed short name of option `--match-length' to `-m'.
|
||||
* Changed LONG_LONG_MAX to LLONG_MAX.
|
||||
|
||||
2008-10-14 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.0 released.
|
||||
* `-tvv' shows file version and dictionary size.
|
||||
|
||||
2008-09-30 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.5 released.
|
||||
* Decompression is now 1% faster.
|
||||
|
||||
2008-09-23 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.4 released.
|
||||
* Code cleanup for global variable `verbosity'.
|
||||
* Regained the compression ratio of 0.2 with 5% faster speed.
|
||||
* Fixed compilation on sistems where size_t != unsigned int.
|
||||
|
||||
2008-09-15 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.3 released.
|
||||
* encoder.cc: Compression is now 15% faster, 1% worse.
|
||||
* main.cc (main): Make `-t' option override `-c'.
|
||||
* main.cc (decompress): Show `done' instead of `ok' when not testing.
|
||||
* encoder.h: Use trials[] to return the list of pairs.
|
||||
|
||||
2008-09-09 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.2 released.
|
||||
* encoder.cc: Small improvements in compression speed.
|
||||
* Small documentation changes.
|
||||
|
||||
2008-08-20 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.1 released.
|
||||
|
||||
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This file is a collection of facts, and thus it is not copyrightable,
|
||||
but just in case, you have unlimited permission to copy, distribute and
|
||||
modify it.
|
|
@ -0,0 +1,56 @@
|
|||
Requirements
|
||||
------------
|
||||
You will need a C++ compiler.
|
||||
I use gcc 4.3.5 and 3.3.6, but the code should compile with any
|
||||
standards compliant compiler.
|
||||
Gcc is available at http://gcc.gnu.org.
|
||||
|
||||
|
||||
Procedure
|
||||
---------
|
||||
1. Unpack the archive if you have not done so already:
|
||||
|
||||
lzip -cd lzip[version].tar.lz | tar -xf -
|
||||
or
|
||||
gzip -cd lzip[version].tar.gz | tar -xf -
|
||||
|
||||
This creates the directory ./lzip[version] containing the source from
|
||||
the main archive.
|
||||
|
||||
2. Change to lzip directory and run configure.
|
||||
(Try `configure --help' for usage instructions).
|
||||
|
||||
cd lzip[version]
|
||||
./configure
|
||||
|
||||
3. Run make.
|
||||
|
||||
make
|
||||
|
||||
4. Optionally, type `make check' to run the tests that come with lzip.
|
||||
|
||||
5. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
|
||||
Another way
|
||||
-----------
|
||||
You can also compile lzip into a separate directory. To do this, you
|
||||
must use a version of `make' that supports the `VPATH' variable, such
|
||||
as GNU `make'. `cd' to the directory where you want the object files
|
||||
and executables to go and run the `configure' script. `configure'
|
||||
automatically checks for the source code in `.', in `..' and in the
|
||||
directory that `configure' is in.
|
||||
|
||||
`configure' recognizes the option `--srcdir=DIR' to control where to
|
||||
look for the sources. Usually `configure' can determine that directory
|
||||
automatically.
|
||||
|
||||
After running `configure', you can run `make' and `make install' as
|
||||
explained above.
|
||||
|
||||
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
|
@ -0,0 +1,158 @@
|
|||
# Makefile for Lzip - Data compressor based on the LZMA algorithm
|
||||
# Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
#
|
||||
# This Makefile is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
pkgname = lzip
|
||||
pkgversion = 1.12
|
||||
progname = lzip
|
||||
VPATH = .
|
||||
prefix = /usr/local
|
||||
exec_prefix = $(prefix)
|
||||
bindir = $(exec_prefix)/bin
|
||||
datadir = $(prefix)/share
|
||||
infodir = $(datadir)/info
|
||||
mandir = $(datadir)/man
|
||||
sysconfdir = $(prefix)/etc
|
||||
CPPFLAGS = -DDECODER_ONLY=$(DECODER_ONLY)
|
||||
CXXFLAGS = -Wall -W -O2
|
||||
LDFLAGS =
|
||||
|
||||
DISTNAME = $(pkgname)-$(pkgversion)
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL) -p -m 755
|
||||
INSTALL_DATA = $(INSTALL) -p -m 644
|
||||
INSTALL_DIR = $(INSTALL) -d -m 755
|
||||
SHELL = /bin/sh
|
||||
|
||||
objs = decoder.o encoder.o fast_encoder.o main.o
|
||||
recobjs = decoder.o lziprecover.o
|
||||
unzobjs = unzcrash.o
|
||||
|
||||
|
||||
.PHONY : all install install-info install-man install-strip \
|
||||
uninstall uninstall-info uninstall-man \
|
||||
doc info man check dist clean distclean
|
||||
|
||||
all : $(progname)
|
||||
|
||||
$(progname) : $(objs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(objs)
|
||||
|
||||
$(progname)_profiled : $(objs)
|
||||
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
|
||||
|
||||
lziprecover : $(recobjs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(recobjs)
|
||||
|
||||
unzcrash : $(unzobjs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(unzobjs)
|
||||
|
||||
main.o : main.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
lziprecover.o : lziprecover.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
unzcrash.o : testsuite/unzcrash.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
%.o : %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(objs) : Makefile
|
||||
decoder.o : lzip.h decoder.h
|
||||
encoder.o : lzip.h encoder.h
|
||||
fast_encoder.o : lzip.h encoder.h fast_encoder.h
|
||||
main.o : lzip.h decoder.h encoder.h fast_encoder.h
|
||||
lziprecover.o : lzip.h decoder.h Makefile
|
||||
unzcrash.o : Makefile
|
||||
|
||||
|
||||
doc : info man
|
||||
|
||||
info : $(VPATH)/doc/$(pkgname).info
|
||||
|
||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
|
||||
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
|
||||
|
||||
man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/lziprecover.1
|
||||
|
||||
$(VPATH)/doc/$(progname).1 : $(progname)
|
||||
help2man -n 'reduces the size of files' \
|
||||
-o $@ ./$(progname)
|
||||
|
||||
$(VPATH)/doc/lziprecover.1 : lziprecover
|
||||
help2man -n 'recovers data from damaged lzip files' \
|
||||
-o $@ --no-info ./lziprecover
|
||||
|
||||
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
||||
./config.status
|
||||
|
||||
check : all
|
||||
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
||||
|
||||
install : all install-info install-man
|
||||
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
||||
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
||||
$(INSTALL_PROGRAM) ./lziprecover "$(DESTDIR)$(bindir)/lziprecover"
|
||||
|
||||
install-info :
|
||||
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" $(DESTDIR)$(infodir)/$(pkgname).info
|
||||
|
||||
install-man :
|
||||
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
$(INSTALL_DATA) $(VPATH)/doc/lziprecover.1 "$(DESTDIR)$(mandir)/man1/lziprecover.1"
|
||||
|
||||
install-strip : all
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
||||
|
||||
uninstall : uninstall-info uninstall-man
|
||||
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
||||
-rm -f "$(DESTDIR)$(bindir)/lziprecover"
|
||||
|
||||
uninstall-info :
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
|
||||
uninstall-man :
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/lziprecover.1"
|
||||
|
||||
dist : doc
|
||||
ln -sf $(VPATH) $(DISTNAME)
|
||||
tar -cvf $(DISTNAME).tar \
|
||||
$(DISTNAME)/AUTHORS \
|
||||
$(DISTNAME)/COPYING \
|
||||
$(DISTNAME)/ChangeLog \
|
||||
$(DISTNAME)/INSTALL \
|
||||
$(DISTNAME)/Makefile.in \
|
||||
$(DISTNAME)/NEWS \
|
||||
$(DISTNAME)/README \
|
||||
$(DISTNAME)/configure \
|
||||
$(DISTNAME)/doc/$(progname).1 \
|
||||
$(DISTNAME)/doc/lziprecover.1 \
|
||||
$(DISTNAME)/doc/$(pkgname).info \
|
||||
$(DISTNAME)/doc/$(pkgname).texinfo \
|
||||
$(DISTNAME)/testsuite/check.sh \
|
||||
$(DISTNAME)/testsuite/test.txt \
|
||||
$(DISTNAME)/testsuite/test_bad[1-5].lz \
|
||||
$(DISTNAME)/testsuite/test_sync.lz \
|
||||
$(DISTNAME)/testsuite/test_v[01].lz \
|
||||
$(DISTNAME)/testsuite/unzcrash.cc \
|
||||
$(DISTNAME)/*.h \
|
||||
$(DISTNAME)/*.cc
|
||||
rm -f $(DISTNAME)
|
||||
lzip -v -9 $(DISTNAME).tar
|
||||
|
||||
clean :
|
||||
-rm -f $(progname) $(progname)_profiled $(objs)
|
||||
-rm -f lziprecover lziprecover.o unzcrash unzcrash.o
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile config.status *.tar *.tar.lz
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
DISTNAME = $(pkgname)-$(pkgversion)
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL) -p -m 755
|
||||
INSTALL_DATA = $(INSTALL) -p -m 644
|
||||
INSTALL_DIR = $(INSTALL) -d -m 755
|
||||
SHELL = /bin/sh
|
||||
|
||||
objs = arg_parser.o decoder.o encoder.o fast_encoder.o main.o
|
||||
recobjs = arg_parser.o decoder.o lziprecover.o
|
||||
unzobjs = arg_parser.o unzcrash.o
|
||||
|
||||
|
||||
.PHONY : all install install-info install-man install-strip \
|
||||
uninstall uninstall-info uninstall-man \
|
||||
doc info man check dist clean distclean
|
||||
|
||||
all : $(progname) lziprecover
|
||||
|
||||
$(progname) : $(objs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(objs)
|
||||
|
||||
$(progname)_profiled : $(objs)
|
||||
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
|
||||
|
||||
lziprecover : $(recobjs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(recobjs)
|
||||
|
||||
unzcrash : $(unzobjs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(unzobjs)
|
||||
|
||||
main.o : main.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
lziprecover.o : lziprecover.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
unzcrash.o : testsuite/unzcrash.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
%.o : %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
$(objs) : Makefile
|
||||
arg_parser.o : arg_parser.h
|
||||
decoder.o : lzip.h decoder.h
|
||||
encoder.o : lzip.h encoder.h
|
||||
fast_encoder.o : lzip.h encoder.h fast_encoder.h
|
||||
main.o : arg_parser.h lzip.h decoder.h encoder.h fast_encoder.h
|
||||
lziprecover.o : arg_parser.h lzip.h decoder.h Makefile
|
||||
unzcrash.o : arg_parser.h Makefile
|
||||
|
||||
|
||||
doc : info man
|
||||
|
||||
info : $(VPATH)/doc/$(pkgname).info
|
||||
|
||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
|
||||
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
|
||||
|
||||
man : $(VPATH)/doc/$(progname).1 $(VPATH)/doc/lziprecover.1
|
||||
|
||||
$(VPATH)/doc/$(progname).1 : $(progname)
|
||||
help2man -n 'reduces the size of files' \
|
||||
-o $@ ./$(progname)
|
||||
|
||||
$(VPATH)/doc/lziprecover.1 : lziprecover
|
||||
help2man -n 'recovers data from damaged lzip files' \
|
||||
-o $@ --no-info ./lziprecover
|
||||
|
||||
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
||||
./config.status
|
||||
|
||||
check : all
|
||||
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
||||
|
||||
install : all install-info install-man
|
||||
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
||||
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
||||
$(INSTALL_PROGRAM) ./lziprecover "$(DESTDIR)$(bindir)/lziprecover"
|
||||
|
||||
install-info :
|
||||
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" $(DESTDIR)$(infodir)/$(pkgname).info
|
||||
|
||||
install-man :
|
||||
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
$(INSTALL_DATA) $(VPATH)/doc/lziprecover.1 "$(DESTDIR)$(mandir)/man1/lziprecover.1"
|
||||
|
||||
install-strip : all
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
||||
|
||||
uninstall : uninstall-info uninstall-man
|
||||
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
||||
-rm -f "$(DESTDIR)$(bindir)/lziprecover"
|
||||
|
||||
uninstall-info :
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
|
||||
uninstall-man :
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/lziprecover.1"
|
||||
|
||||
dist : doc
|
||||
ln -sf $(VPATH) $(DISTNAME)
|
||||
tar -cvf $(DISTNAME).tar \
|
||||
$(DISTNAME)/AUTHORS \
|
||||
$(DISTNAME)/COPYING \
|
||||
$(DISTNAME)/ChangeLog \
|
||||
$(DISTNAME)/INSTALL \
|
||||
$(DISTNAME)/Makefile.in \
|
||||
$(DISTNAME)/NEWS \
|
||||
$(DISTNAME)/README \
|
||||
$(DISTNAME)/configure \
|
||||
$(DISTNAME)/doc/$(progname).1 \
|
||||
$(DISTNAME)/doc/lziprecover.1 \
|
||||
$(DISTNAME)/doc/$(pkgname).info \
|
||||
$(DISTNAME)/doc/$(pkgname).texinfo \
|
||||
$(DISTNAME)/testsuite/check.sh \
|
||||
$(DISTNAME)/testsuite/test.txt \
|
||||
$(DISTNAME)/testsuite/test_bad[1-5].lz \
|
||||
$(DISTNAME)/testsuite/test_sync.lz \
|
||||
$(DISTNAME)/testsuite/test_v[01].lz \
|
||||
$(DISTNAME)/testsuite/unzcrash.cc \
|
||||
$(DISTNAME)/*.h \
|
||||
$(DISTNAME)/*.cc
|
||||
rm -f $(DISTNAME)
|
||||
lzip -v -9 $(DISTNAME).tar
|
||||
|
||||
clean :
|
||||
-rm -f $(progname) $(progname)_profiled $(objs)
|
||||
-rm -f lziprecover lziprecover.o unzcrash unzcrash.o
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile config.status *.tar *.tar.lz
|
|
@ -0,0 +1,22 @@
|
|||
Changes in version 1.12:
|
||||
|
||||
The option "-F, --recompress", which forces recompression of files whose
|
||||
name already has the ".lz" or ".tlz" suffix, has been added.
|
||||
|
||||
For large values of "--match-length", compression ratio has been
|
||||
slightly increased and compression time has been reduced by up to 6%.
|
||||
|
||||
Compression time of option "-0" has been reduced by 2%.
|
||||
|
||||
Print only one status line for each multimember file when only one "-v"
|
||||
is specified.
|
||||
|
||||
Print up to 6 bytes of trailing garbage when "-vvvv" is specified.
|
||||
|
||||
Do not show the message "and `--stdout' was not specified" for file
|
||||
types that can't be read (directories, etc).
|
||||
|
||||
If "--verbose" is not specified, lziprecover now only shows errors and
|
||||
warnings.
|
||||
|
||||
Options "--bits", "--position" and "--size" has been added to unzcrash.
|
|
@ -0,0 +1,77 @@
|
|||
Description
|
||||
|
||||
Lzip is a lossless data compressor based on the LZMA algorithm, with
|
||||
very safe integrity checking and a user interface similar to the one of
|
||||
gzip or bzip2. Lzip decompresses almost as fast as gzip and compresses
|
||||
better than bzip2, which makes it well suited for software distribution
|
||||
and data archiving.
|
||||
|
||||
Lziprecover is a data recovery tool for lzip compressed files able to
|
||||
repair slightly damaged files, recover badly damaged files from two or
|
||||
more copies, and extract undamaged members from multi-member files. If
|
||||
the cause of file corruption is damaged media, the combination GNU
|
||||
ddrescue + lziprecover is the best option for recovering data from
|
||||
multiple damaged copies.
|
||||
|
||||
Lzip replaces every file given in the command line with a compressed
|
||||
version of itself, with the name "original_name.lz". Each compressed
|
||||
file has the same modification date, permissions, and, when possible,
|
||||
ownership as the corresponding original, so that these properties can be
|
||||
correctly restored at decompression time. Lzip is able to read from some
|
||||
types of non regular files if the "--stdout" option is specified.
|
||||
|
||||
If no file names are specified, lzip compresses (or decompresses) from
|
||||
standard input to standard output. In this case, lzip will decline to
|
||||
write compressed output to a terminal, as this would be entirely
|
||||
incomprehensible and therefore pointless.
|
||||
|
||||
Lzip will correctly decompress a file which is the concatenation of two
|
||||
or more compressed files. The result is the concatenation of the
|
||||
corresponding uncompressed files. Integrity testing of concatenated
|
||||
compressed files is also supported.
|
||||
|
||||
Lzip can produce multimember files and safely recover, with lziprecover,
|
||||
the undamaged members in case of file damage. Lzip can also split the
|
||||
compressed output in volumes of a given size, even when reading from
|
||||
standard input. This allows the direct creation of multivolume
|
||||
compressed tar archives.
|
||||
|
||||
Lzip will automatically use the smallest possible dictionary size
|
||||
without exceeding the given limit. Keep in mind that the decompression
|
||||
memory requirement is affected at compression time by the choice of
|
||||
dictionary size limit.
|
||||
|
||||
As a self-check for your protection, lzip stores in the member trailer
|
||||
the 32-bit CRC of the original data and the size of the original data,
|
||||
to make sure that the decompressed version of the data is identical to
|
||||
the original. This guards against corruption of the compressed data, and
|
||||
against undetected bugs in lzip (hopefully very unlikely). The chances
|
||||
of data corruption going undetected are microscopic, less than one
|
||||
chance in 4000 million for each member processed. Be aware, though, that
|
||||
the check occurs upon decompression, so it can only tell you that
|
||||
something is wrong. It can't help you recover the original uncompressed
|
||||
data.
|
||||
|
||||
Lzip implements a simplified version of the LZMA (Lempel-Ziv-Markov
|
||||
chain-Algorithm) algorithm. The high compression of LZMA comes from
|
||||
combining two basic, well-proven compression ideas: sliding dictionaries
|
||||
(LZ77/78) and markov models (the thing used by every compression
|
||||
algorithm that uses a range encoder or similar order-0 entropy coder as
|
||||
its last stage) with segregation of contexts according to what the bits
|
||||
are used for.
|
||||
|
||||
The ideas embodied in lzip are due to (at least) the following people:
|
||||
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
|
||||
the definition of Markov chains), G.N.N. Martin (for the definition of
|
||||
range encoding), Igor Pavlov (for putting all the above together in
|
||||
LZMA), and Julian Seward (for bzip2's CLI and the idea of unzcrash).
|
||||
|
||||
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
||||
|
||||
The file Makefile.in is a data file used by configure to produce the
|
||||
Makefile. It has the same copyright owner and permissions that configure
|
||||
itself.
|
|
@ -0,0 +1,8 @@
|
|||
#! /bin/sh
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
# Run this file to recreate the current configuration.
|
||||
#
|
||||
# This script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
exec /bin/sh ./configure --no-create
|
|
@ -0,0 +1,192 @@
|
|||
#! /bin/sh
|
||||
# configure script for Lzip - Data compressor based on the LZMA algorithm
|
||||
# Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
#
|
||||
# This configure script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
args=
|
||||
no_create=
|
||||
pkgname=lzip
|
||||
pkgversion=1.12
|
||||
progname=lzip
|
||||
srctrigger=lzip.h
|
||||
|
||||
# clear some things potentially inherited from environment.
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
srcdir=
|
||||
prefix=/usr/local
|
||||
exec_prefix='$(prefix)'
|
||||
bindir='$(exec_prefix)/bin'
|
||||
datadir='$(prefix)/share'
|
||||
infodir='$(datadir)/info'
|
||||
mandir='$(datadir)/man'
|
||||
sysconfdir='$(prefix)/etc'
|
||||
CXX=
|
||||
CPPFLAGS=
|
||||
CXXFLAGS='-Wall -W -O2'
|
||||
LDFLAGS=
|
||||
|
||||
# Loop over all args
|
||||
while [ -n "$1" ] ; do
|
||||
|
||||
# Get the first arg, and shuffle
|
||||
option=$1
|
||||
shift
|
||||
|
||||
# Add the argument quoted to args
|
||||
args="${args} \"${option}\""
|
||||
|
||||
# Split out the argument for options that take them
|
||||
case ${option} in
|
||||
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,'` ;;
|
||||
esac
|
||||
|
||||
# Process the options
|
||||
case ${option} in
|
||||
--help | --he* | -h)
|
||||
echo "Usage: configure [options]"
|
||||
echo
|
||||
echo "Options: [defaults in brackets]"
|
||||
echo " -h, --help display this help and exit"
|
||||
echo " -V, --version output version information and exit"
|
||||
echo " --srcdir=DIR find the sources in DIR [. or ..]"
|
||||
echo " --prefix=DIR install into DIR [${prefix}]"
|
||||
echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]"
|
||||
echo " --bindir=DIR user executables directory [${bindir}]"
|
||||
echo " --datadir=DIR base directory for doc and data [${datadir}]"
|
||||
echo " --infodir=DIR info files directory [${infodir}]"
|
||||
echo " --mandir=DIR man pages directory [${mandir}]"
|
||||
echo " --sysconfdir=DIR read-only single-machine data directory [${sysconfdir}]"
|
||||
echo " CXX=COMPILER C++ compiler to use [g++]"
|
||||
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
|
||||
echo
|
||||
exit 0 ;;
|
||||
--version | --ve* | -V)
|
||||
echo "Configure script for ${pkgname} version ${pkgversion}"
|
||||
exit 0 ;;
|
||||
--srcdir* | --sr*)
|
||||
srcdir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--prefix* | --pr*)
|
||||
prefix=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--exec-prefix* | --ex*)
|
||||
exec_prefix=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--bindir* | --bi*)
|
||||
bindir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--datadir* | --da*)
|
||||
datadir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--infodir* | --inf*)
|
||||
infodir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--mandir* | --ma*)
|
||||
mandir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--sysconfdir* | --sy*)
|
||||
sysconfdir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--no-create | --no-c*)
|
||||
no_create=yes ;;
|
||||
|
||||
CXX=*) CXX=${optarg} ;;
|
||||
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
|
||||
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
||||
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
||||
|
||||
--* | *=* | *-*-*) ;;
|
||||
*)
|
||||
echo "configure: Unrecognized option: \"${option}\"; use --help for usage." 1>&2
|
||||
exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Find the source files, if location was not specified.
|
||||
srcdirtext=
|
||||
if [ -z "${srcdir}" ] ; then
|
||||
srcdirtext="or . or .." ; srcdir=.
|
||||
if [ ! -r ${srcdir}/${srctrigger} ] ; then srcdir=.. ; fi
|
||||
if [ ! -r ${srcdir}/${srctrigger} ] ; then
|
||||
## the sed command below emulates the dirname command
|
||||
srcdir=`echo $0 | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -r ${srcdir}/${srctrigger} ] ; then
|
||||
exec 1>&2
|
||||
echo
|
||||
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}"
|
||||
echo "configure: (At least ${srctrigger} is missing)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set srcdir to . if that's what it is.
|
||||
if [ "`pwd`" = "`cd ${srcdir} ; pwd`" ] ; then srcdir=. ; fi
|
||||
|
||||
# checking whether we are using GNU C++.
|
||||
if [ -z "${CXX}" ] ; then # Let the user override the test.
|
||||
if [ -x /bin/g++ ] ||
|
||||
[ -x /usr/bin/g++ ] ||
|
||||
[ -x /usr/local/bin/g++ ] ; then
|
||||
CXX="g++"
|
||||
else
|
||||
CXX="c++"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ -z "${no_create}" ] ; then
|
||||
echo "creating config.status"
|
||||
rm -f config.status
|
||||
cat > config.status << EOF
|
||||
#! /bin/sh
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
# Run this file to recreate the current configuration.
|
||||
#
|
||||
# This script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
exec /bin/sh $0 ${args} --no-create
|
||||
EOF
|
||||
chmod +x config.status
|
||||
fi
|
||||
|
||||
echo "creating Makefile"
|
||||
echo "VPATH = ${srcdir}"
|
||||
echo "prefix = ${prefix}"
|
||||
echo "exec_prefix = ${exec_prefix}"
|
||||
echo "bindir = ${bindir}"
|
||||
echo "datadir = ${datadir}"
|
||||
echo "infodir = ${infodir}"
|
||||
echo "mandir = ${mandir}"
|
||||
echo "sysconfdir = ${sysconfdir}"
|
||||
echo "CXX = ${CXX}"
|
||||
echo "CPPFLAGS = ${CPPFLAGS}"
|
||||
echo "CXXFLAGS = ${CXXFLAGS}"
|
||||
echo "LDFLAGS = ${LDFLAGS}"
|
||||
rm -f Makefile
|
||||
cat > Makefile << EOF
|
||||
# Makefile for Lzip - Data compressor based on the LZMA algorithm
|
||||
# Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
#
|
||||
# This Makefile is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
||||
pkgname = ${pkgname}
|
||||
pkgversion = ${pkgversion}
|
||||
progname = ${progname}
|
||||
VPATH = ${srcdir}
|
||||
prefix = ${prefix}
|
||||
exec_prefix = ${exec_prefix}
|
||||
bindir = ${bindir}
|
||||
datadir = ${datadir}
|
||||
infodir = ${infodir}
|
||||
mandir = ${mandir}
|
||||
sysconfdir = ${sysconfdir}
|
||||
CXX = ${CXX}
|
||||
CPPFLAGS = ${CPPFLAGS}
|
||||
CXXFLAGS = ${CXXFLAGS}
|
||||
LDFLAGS = ${LDFLAGS}
|
||||
EOF
|
||||
cat ${srcdir}/Makefile.in >> Makefile
|
||||
|
||||
echo "OK. Now you can run make."
|
|
@ -0,0 +1,252 @@
|
|||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lzip.h"
|
||||
#include "decoder.h"
|
||||
|
||||
|
||||
const CRC32 crc32;
|
||||
|
||||
|
||||
// Returns the number of bytes really read.
|
||||
// If (returned value < size) and (errno == 0), means EOF was reached.
|
||||
//
|
||||
int readblock( const int fd, uint8_t * const buf, const int size )
|
||||
{
|
||||
int rest = size;
|
||||
errno = 0;
|
||||
while( rest > 0 )
|
||||
{
|
||||
errno = 0;
|
||||
const int n = read( fd, buf + size - rest, rest );
|
||||
if( n > 0 ) rest -= n;
|
||||
else if( n == 0 ) break;
|
||||
else if( errno != EINTR && errno != EAGAIN ) break;
|
||||
}
|
||||
return ( rest > 0 ) ? size - rest : size;
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of bytes really written.
|
||||
// If (returned value < size), it is always an error.
|
||||
//
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size )
|
||||
{
|
||||
int rest = size;
|
||||
errno = 0;
|
||||
while( rest > 0 )
|
||||
{
|
||||
errno = 0;
|
||||
const int n = write( fd, buf + size - rest, rest );
|
||||
if( n > 0 ) rest -= n;
|
||||
else if( errno && errno != EINTR && errno != EAGAIN ) break;
|
||||
}
|
||||
return ( rest > 0 ) ? size - rest : size;
|
||||
}
|
||||
|
||||
|
||||
bool Range_decoder::read_block()
|
||||
{
|
||||
if( !at_stream_end )
|
||||
{
|
||||
stream_pos = readblock( infd, buffer, buffer_size );
|
||||
if( stream_pos != buffer_size && errno ) exit(-1);
|
||||
at_stream_end = ( stream_pos < buffer_size );
|
||||
partial_member_pos += pos;
|
||||
pos = 0;
|
||||
}
|
||||
return pos < stream_pos;
|
||||
}
|
||||
|
||||
|
||||
void LZ_decoder::flush_data()
|
||||
{
|
||||
const int size = pos - stream_pos;
|
||||
if( size > 0 )
|
||||
{
|
||||
crc32.update( crc_, buffer + stream_pos, size );
|
||||
if( outfd >= 0 &&
|
||||
writeblock( outfd, buffer + stream_pos, size ) != size )
|
||||
exit(-1);
|
||||
if( pos >= buffer_size ) { partial_data_pos += pos; pos = 0; }
|
||||
stream_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LZ_decoder::verify_trailer() const
|
||||
{
|
||||
File_trailer trailer;
|
||||
const int trailer_size = File_trailer::size( member_version );
|
||||
const long long member_size = range_decoder.member_position() + trailer_size;
|
||||
bool error = false;
|
||||
|
||||
for( int i = 0; i < trailer_size && !error; ++i )
|
||||
{
|
||||
if( !range_decoder.finished() )
|
||||
trailer.data[i] = range_decoder.get_byte();
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
for( ; i < trailer_size; ++i ) trailer.data[i] = 0;
|
||||
}
|
||||
}
|
||||
if( member_version == 0 ) trailer.member_size( member_size );
|
||||
if( !range_decoder.code_is_zero() )
|
||||
{
|
||||
error = true;
|
||||
pp( "Range decoder final code is not zero" );
|
||||
}
|
||||
if( trailer.data_crc() != crc() )
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
if( trailer.data_size() != data_position() )
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
if( trailer.member_size() != member_size )
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
return !error;
|
||||
}
|
||||
|
||||
|
||||
// Return value: 0 = OK, 1 = decoder error, 2 = unexpected EOF,
|
||||
// 3 = trailer error, 4 = unknown marker found.
|
||||
int LZ_decoder::decode_member()
|
||||
{
|
||||
Bit_model bm_match[State::states][pos_states];
|
||||
Bit_model bm_rep[State::states];
|
||||
Bit_model bm_rep0[State::states];
|
||||
Bit_model bm_rep1[State::states];
|
||||
Bit_model bm_rep2[State::states];
|
||||
Bit_model bm_len[State::states][pos_states];
|
||||
Bit_model bm_dis_slot[max_dis_states][1<<dis_slot_bits];
|
||||
Bit_model bm_dis[modeled_distances-end_dis_model+1];
|
||||
Bit_model bm_align[dis_align_size];
|
||||
|
||||
unsigned int rep0 = 0; // rep[0-3] latest four distances
|
||||
unsigned int rep1 = 0; // used for efficient coding of
|
||||
unsigned int rep2 = 0; // repeated distances
|
||||
unsigned int rep3 = 0;
|
||||
|
||||
Len_decoder len_decoder;
|
||||
Len_decoder rep_match_len_decoder;
|
||||
Literal_decoder literal_decoder;
|
||||
State state;
|
||||
range_decoder.load();
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( range_decoder.finished() ) { flush_data(); return 2; }
|
||||
const int pos_state = data_position() & pos_state_mask;
|
||||
if( range_decoder.decode_bit( bm_match[state()][pos_state] ) == 0 )
|
||||
{
|
||||
const uint8_t prev_byte = get_prev_byte();
|
||||
if( state.is_char() )
|
||||
put_byte( literal_decoder.decode( range_decoder, prev_byte ) );
|
||||
else
|
||||
put_byte( literal_decoder.decode_matched( range_decoder, prev_byte,
|
||||
get_byte( rep0 ) ) );
|
||||
state.set_char();
|
||||
}
|
||||
else
|
||||
{
|
||||
int len;
|
||||
if( range_decoder.decode_bit( bm_rep[state()] ) == 1 )
|
||||
{
|
||||
len = 0;
|
||||
if( range_decoder.decode_bit( bm_rep0[state()] ) == 1 )
|
||||
{
|
||||
unsigned int distance;
|
||||
if( range_decoder.decode_bit( bm_rep1[state()] ) == 0 )
|
||||
distance = rep1;
|
||||
else
|
||||
{
|
||||
if( range_decoder.decode_bit( bm_rep2[state()] ) == 0 )
|
||||
distance = rep2;
|
||||
else { distance = rep3; rep3 = rep2; }
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( range_decoder.decode_bit( bm_len[state()][pos_state] ) == 0 )
|
||||
{ state.set_short_rep(); len = 1; }
|
||||
}
|
||||
if( len == 0 )
|
||||
{
|
||||
state.set_rep();
|
||||
len = min_match_len + rep_match_len_decoder.decode( range_decoder, pos_state );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned int rep0_saved = rep0;
|
||||
len = min_match_len + len_decoder.decode( range_decoder, pos_state );
|
||||
const int dis_slot = range_decoder.decode_tree( bm_dis_slot[get_dis_state(len)], dis_slot_bits );
|
||||
if( dis_slot < start_dis_model ) rep0 = dis_slot;
|
||||
else
|
||||
{
|
||||
const int direct_bits = ( dis_slot >> 1 ) - 1;
|
||||
rep0 = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
|
||||
if( dis_slot < end_dis_model )
|
||||
rep0 += range_decoder.decode_tree_reversed( bm_dis + rep0 - dis_slot, direct_bits );
|
||||
else
|
||||
{
|
||||
rep0 += range_decoder.decode( direct_bits - dis_align_bits ) << dis_align_bits;
|
||||
rep0 += range_decoder.decode_tree_reversed( bm_align, dis_align_bits );
|
||||
if( rep0 == 0xFFFFFFFFU ) // Marker found
|
||||
{
|
||||
rep0 = rep0_saved;
|
||||
range_decoder.normalize();
|
||||
flush_data();
|
||||
if( len == min_match_len ) // End Of Stream marker
|
||||
{
|
||||
if( verify_trailer() ) return 0; else return 3;
|
||||
}
|
||||
if( len == min_match_len + 1 ) // Sync Flush marker
|
||||
{
|
||||
range_decoder.load(); continue;
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
rep3 = rep2; rep2 = rep1; rep1 = rep0_saved;
|
||||
state.set_match();
|
||||
if( rep0 >= (unsigned int)dictionary_size ||
|
||||
( rep0 >= (unsigned int)pos && !partial_data_pos ) )
|
||||
{ flush_data(); return 1; }
|
||||
}
|
||||
copy_block( rep0, len );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Range_decoder
|
||||
{
|
||||
enum { buffer_size = 16384 };
|
||||
long long partial_member_pos;
|
||||
uint8_t * const buffer; // input buffer
|
||||
int pos; // current pos in buffer
|
||||
int stream_pos; // when reached, a new block must be read
|
||||
uint32_t code;
|
||||
uint32_t range;
|
||||
const int infd; // input file descriptor
|
||||
bool at_stream_end;
|
||||
|
||||
bool read_block();
|
||||
|
||||
public:
|
||||
Range_decoder( const int ifd )
|
||||
:
|
||||
partial_member_pos( 0 ),
|
||||
buffer( new uint8_t[buffer_size] ),
|
||||
pos( 0 ),
|
||||
stream_pos( 0 ),
|
||||
code( 0 ),
|
||||
range( 0xFFFFFFFFU ),
|
||||
infd( ifd ),
|
||||
at_stream_end( false ) {}
|
||||
|
||||
~Range_decoder() { delete[] buffer; }
|
||||
|
||||
bool code_is_zero() const { return ( code == 0 ); }
|
||||
bool finished() { return pos >= stream_pos && !read_block(); }
|
||||
long long member_position() const
|
||||
{ return partial_member_pos + pos; }
|
||||
void reset_member_position()
|
||||
{ partial_member_pos = -pos; }
|
||||
|
||||
uint8_t get_byte()
|
||||
{
|
||||
if( finished() ) return 0x55; // make code != 0
|
||||
return buffer[pos++];
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
code = 0;
|
||||
range = 0xFFFFFFFFU;
|
||||
for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte();
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
if( range <= 0x00FFFFFFU )
|
||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||
}
|
||||
|
||||
int decode( const int num_bits )
|
||||
{
|
||||
int symbol = 0;
|
||||
for( int i = num_bits; i > 0; --i )
|
||||
{
|
||||
symbol <<= 1;
|
||||
if( range <= 0x00FFFFFFU )
|
||||
{
|
||||
range <<= 7; code = (code << 8) | get_byte();
|
||||
if( code >= range ) { code -= range; symbol |= 1; }
|
||||
}
|
||||
else
|
||||
{
|
||||
range >>= 1;
|
||||
if( code >= range ) { code -= range; symbol |= 1; }
|
||||
}
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
int decode_bit( Bit_model & bm )
|
||||
{
|
||||
normalize();
|
||||
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
|
||||
if( code < bound )
|
||||
{
|
||||
range = bound;
|
||||
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
range -= bound;
|
||||
code -= bound;
|
||||
bm.probability -= bm.probability >> bit_model_move_bits;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int decode_tree( Bit_model bm[], const int num_bits )
|
||||
{
|
||||
int model = 1;
|
||||
for( int i = num_bits; i > 0; --i )
|
||||
model = ( model << 1 ) | decode_bit( bm[model] );
|
||||
return model - (1 << num_bits);
|
||||
}
|
||||
|
||||
int decode_tree_reversed( Bit_model bm[], const int num_bits )
|
||||
{
|
||||
int model = 1;
|
||||
int symbol = 0;
|
||||
for( int i = 0; i < num_bits; ++i )
|
||||
{
|
||||
const int bit = decode_bit( bm[model] );
|
||||
model <<= 1;
|
||||
if( bit ) { model |= 1; symbol |= (1 << i); }
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
int decode_matched( Bit_model bm[], const int match_byte )
|
||||
{
|
||||
Bit_model * const bm1 = bm + 0x100;
|
||||
int symbol = 1;
|
||||
for( int i = 7; i >= 0; --i )
|
||||
{
|
||||
const int match_bit = ( match_byte >> i ) & 1;
|
||||
const int bit = decode_bit( bm1[(match_bit<<8)+symbol] );
|
||||
symbol = ( symbol << 1 ) | bit;
|
||||
if( match_bit != bit )
|
||||
{
|
||||
while( --i >= 0 )
|
||||
symbol = ( symbol << 1 ) | decode_bit( bm[symbol] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return symbol & 0xFF;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Len_decoder
|
||||
{
|
||||
Bit_model choice1;
|
||||
Bit_model choice2;
|
||||
Bit_model bm_low[pos_states][len_low_symbols];
|
||||
Bit_model bm_mid[pos_states][len_mid_symbols];
|
||||
Bit_model bm_high[len_high_symbols];
|
||||
|
||||
public:
|
||||
int decode( Range_decoder & range_decoder, const int pos_state )
|
||||
{
|
||||
if( range_decoder.decode_bit( choice1 ) == 0 )
|
||||
return range_decoder.decode_tree( bm_low[pos_state], len_low_bits );
|
||||
if( range_decoder.decode_bit( choice2 ) == 0 )
|
||||
return len_low_symbols +
|
||||
range_decoder.decode_tree( bm_mid[pos_state], len_mid_bits );
|
||||
return len_low_symbols + len_mid_symbols +
|
||||
range_decoder.decode_tree( bm_high, len_high_bits );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Literal_decoder
|
||||
{
|
||||
Bit_model bm_literal[1<<literal_context_bits][0x300];
|
||||
|
||||
int lstate( const int prev_byte ) const
|
||||
{ return ( prev_byte >> ( 8 - literal_context_bits ) ); }
|
||||
|
||||
public:
|
||||
uint8_t decode( Range_decoder & range_decoder, const uint8_t prev_byte )
|
||||
{ return range_decoder.decode_tree( bm_literal[lstate(prev_byte)], 8 ); }
|
||||
|
||||
uint8_t decode_matched( Range_decoder & range_decoder,
|
||||
const uint8_t prev_byte, const uint8_t match_byte )
|
||||
{ return range_decoder.decode_matched( bm_literal[lstate(prev_byte)],
|
||||
match_byte ); }
|
||||
};
|
||||
|
||||
|
||||
class LZ_decoder
|
||||
{
|
||||
long long partial_data_pos;
|
||||
const int dictionary_size;
|
||||
const int buffer_size;
|
||||
uint8_t * const buffer; // output buffer
|
||||
int pos; // current pos in buffer
|
||||
int stream_pos; // first byte not yet written to file
|
||||
uint32_t crc_;
|
||||
const int outfd; // output file descriptor
|
||||
const int member_version;
|
||||
Range_decoder & range_decoder;
|
||||
|
||||
void flush_data();
|
||||
bool verify_trailer() const;
|
||||
|
||||
uint8_t get_prev_byte() const
|
||||
{
|
||||
const int i = ( ( pos > 0 ) ? pos : buffer_size ) - 1;
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
uint8_t get_byte( const int distance ) const
|
||||
{
|
||||
int i = pos - distance - 1;
|
||||
if( i < 0 ) i += buffer_size;
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
void put_byte( const uint8_t b )
|
||||
{
|
||||
buffer[pos] = b;
|
||||
if( ++pos >= buffer_size ) flush_data();
|
||||
}
|
||||
|
||||
void copy_block( const int distance, int len )
|
||||
{
|
||||
int i = pos - distance - 1;
|
||||
if( i < 0 ) i += buffer_size;
|
||||
if( len < buffer_size - max( pos, i ) && len <= abs( pos - i ) )
|
||||
{
|
||||
memcpy( buffer + pos, buffer + i, len );
|
||||
pos += len;
|
||||
}
|
||||
else for( ; len > 0; --len )
|
||||
{
|
||||
buffer[pos] = buffer[i];
|
||||
if( ++pos >= buffer_size ) flush_data();
|
||||
if( ++i >= buffer_size ) i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
LZ_decoder( const File_header & header, Range_decoder & rdec, const int ofd )
|
||||
:
|
||||
partial_data_pos( 0 ),
|
||||
dictionary_size( header.dictionary_size() ),
|
||||
buffer_size( max( 65536, dictionary_size ) ),
|
||||
buffer( new uint8_t[buffer_size] ),
|
||||
pos( 0 ),
|
||||
stream_pos( 0 ),
|
||||
crc_( 0xFFFFFFFFU ),
|
||||
outfd( ofd ),
|
||||
member_version( header.version() ),
|
||||
range_decoder( rdec )
|
||||
{ buffer[buffer_size-1] = 0; } // prev_byte of first_byte
|
||||
|
||||
~LZ_decoder() { delete[] buffer; }
|
||||
|
||||
uint32_t crc() const { return crc_ ^ 0xFFFFFFFFU; }
|
||||
|
||||
long long data_position() const
|
||||
{ return partial_data_pos + pos; }
|
||||
|
||||
int decode_member();
|
||||
};
|
|
@ -0,0 +1,643 @@
|
|||
#if !DECODER_ONLY
|
||||
|
||||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lzip.h"
|
||||
#include "encoder.h"
|
||||
|
||||
|
||||
Dis_slots dis_slots;
|
||||
Prob_prices prob_prices;
|
||||
|
||||
|
||||
bool Matchfinder::read_block()
|
||||
{
|
||||
if( !at_stream_end && stream_pos < buffer_size )
|
||||
{
|
||||
const int size = buffer_size - stream_pos;
|
||||
const int rd = readblock( infd, buffer + stream_pos, size );
|
||||
stream_pos += rd;
|
||||
if( rd != size && errno ) throw Error( "Read error" );
|
||||
at_stream_end = ( rd < size );
|
||||
}
|
||||
return pos < stream_pos;
|
||||
}
|
||||
|
||||
|
||||
Matchfinder::Matchfinder( const int dict_size, const int len_limit,
|
||||
const int ifd )
|
||||
:
|
||||
partial_data_pos( 0 ),
|
||||
prev_positions( new int32_t[num_prev_positions] ),
|
||||
pos( 0 ),
|
||||
cyclic_pos( 0 ),
|
||||
stream_pos( 0 ),
|
||||
match_len_limit_( len_limit ),
|
||||
cycles( ( len_limit < max_match_len ) ? 16 + ( len_limit / 2 ) : 256 ),
|
||||
infd( ifd ),
|
||||
at_stream_end( false )
|
||||
{
|
||||
const int buffer_size_limit = ( 2 * dict_size ) + before_size + after_size;
|
||||
buffer_size = max( 65536, dict_size );
|
||||
buffer = (uint8_t *)malloc( buffer_size );
|
||||
if( !buffer ) exit(-1);
|
||||
if( read_block() && !at_stream_end && buffer_size < buffer_size_limit )
|
||||
{
|
||||
buffer_size = buffer_size_limit;
|
||||
buffer = (uint8_t *)realloc( buffer, buffer_size );
|
||||
if( !buffer ) exit(-1);
|
||||
read_block();
|
||||
}
|
||||
if( at_stream_end && stream_pos < dict_size )
|
||||
dictionary_size_ = max( (int)min_dictionary_size, stream_pos );
|
||||
else dictionary_size_ = dict_size;
|
||||
pos_limit = buffer_size;
|
||||
if( !at_stream_end ) pos_limit -= after_size;
|
||||
prev_pos_tree = new int32_t[2*dictionary_size_];
|
||||
for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1;
|
||||
}
|
||||
|
||||
|
||||
void Matchfinder::reset()
|
||||
{
|
||||
const int size = stream_pos - pos;
|
||||
if( size > 0 ) memmove( buffer, buffer + pos, size );
|
||||
partial_data_pos = 0;
|
||||
stream_pos -= pos;
|
||||
pos = 0;
|
||||
cyclic_pos = 0;
|
||||
for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1;
|
||||
read_block();
|
||||
}
|
||||
|
||||
|
||||
void Matchfinder::move_pos()
|
||||
{
|
||||
if( ++cyclic_pos >= dictionary_size_ ) cyclic_pos = 0;
|
||||
if( ++pos >= pos_limit )
|
||||
{
|
||||
if( pos > stream_pos )
|
||||
internal_error( "pos > stream_pos in Matchfinder::move_pos" );
|
||||
if( !at_stream_end )
|
||||
{
|
||||
const int offset = pos - dictionary_size_ - before_size;
|
||||
const int size = stream_pos - offset;
|
||||
memmove( buffer, buffer + offset, size );
|
||||
partial_data_pos += offset;
|
||||
pos -= offset;
|
||||
stream_pos -= offset;
|
||||
for( int i = 0; i < num_prev_positions; ++i )
|
||||
if( prev_positions[i] >= 0 ) prev_positions[i] -= offset;
|
||||
for( int i = 0; i < 2 * dictionary_size_; ++i )
|
||||
if( prev_pos_tree[i] >= 0 ) prev_pos_tree[i] -= offset;
|
||||
read_block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Matchfinder::longest_match_len( int * const distances ) throw()
|
||||
{
|
||||
int len_limit = match_len_limit_;
|
||||
if( len_limit > available_bytes() )
|
||||
{
|
||||
len_limit = available_bytes();
|
||||
if( len_limit < 4 ) return 0;
|
||||
}
|
||||
|
||||
int maxlen = min_match_len - 1;
|
||||
const int min_pos = (pos >= dictionary_size_) ?
|
||||
(pos - dictionary_size_ + 1) : 0;
|
||||
const uint8_t * const data = buffer + pos;
|
||||
const int key2 = num_prev_positions4 + num_prev_positions3 +
|
||||
( ( (int)data[0] << 8 ) | data[1] );
|
||||
const uint32_t tmp = crc32[data[0]] ^ data[1] ^ ( (uint32_t)data[2] << 8 );
|
||||
const int key3 = num_prev_positions4 +
|
||||
(int)( tmp & ( num_prev_positions3 - 1 ) );
|
||||
const int key4 = (int)( ( tmp ^ ( crc32[data[3]] << 5 ) ) &
|
||||
( num_prev_positions4 - 1 ) );
|
||||
|
||||
if( distances )
|
||||
{
|
||||
int np = prev_positions[key2];
|
||||
if( np >= min_pos )
|
||||
{ distances[2] = pos - np - 1; maxlen = 2; }
|
||||
else distances[2] = 0x7FFFFFFF;
|
||||
np = prev_positions[key3];
|
||||
if( np >= min_pos && buffer[np] == data[0] )
|
||||
{ distances[3] = pos - np - 1; maxlen = 3; }
|
||||
else distances[3] = 0x7FFFFFFF;
|
||||
distances[4] = 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
prev_positions[key2] = pos;
|
||||
prev_positions[key3] = pos;
|
||||
int newpos = prev_positions[key4];
|
||||
prev_positions[key4] = pos;
|
||||
|
||||
int32_t * ptr0 = prev_pos_tree + ( cyclic_pos << 1 );
|
||||
int32_t * ptr1 = ptr0 + 1;
|
||||
int len = 0, len0 = 0, len1 = 0;
|
||||
|
||||
for( int count = cycles; ; )
|
||||
{
|
||||
if( newpos < min_pos || --count < 0 ) { *ptr0 = *ptr1 = -1; break; }
|
||||
const uint8_t * const newdata = buffer + newpos;
|
||||
while( len < len_limit && newdata[len] == data[len] ) ++len;
|
||||
|
||||
const int delta = pos - newpos;
|
||||
if( distances ) while( maxlen < len ) distances[++maxlen] = delta - 1;
|
||||
|
||||
int32_t * const newptr = prev_pos_tree +
|
||||
( ( cyclic_pos - delta +
|
||||
( ( cyclic_pos >= delta ) ? 0 : dictionary_size_ ) ) << 1 );
|
||||
|
||||
if( len < len_limit )
|
||||
{
|
||||
if( newdata[len] < data[len] )
|
||||
{
|
||||
*ptr0 = newpos;
|
||||
ptr0 = newptr + 1;
|
||||
newpos = *ptr0;
|
||||
len0 = len; if( len1 < len ) len = len1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr1 = newpos;
|
||||
ptr1 = newptr;
|
||||
newpos = *ptr1;
|
||||
len1 = len; if( len0 < len ) len = len0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = newptr[0];
|
||||
*ptr1 = newptr[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( distances )
|
||||
{
|
||||
if( distances[3] > distances[4] ) distances[3] = distances[4];
|
||||
if( distances[2] > distances[3] ) distances[2] = distances[3];
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
|
||||
void Range_encoder::flush_data()
|
||||
{
|
||||
if( pos > 0 )
|
||||
{
|
||||
if( outfd >= 0 && writeblock( outfd, buffer, pos ) != pos )
|
||||
throw Error( "Write error" );
|
||||
partial_member_pos += pos;
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Len_encoder::encode( Range_encoder & range_encoder, int symbol,
|
||||
const int pos_state )
|
||||
{
|
||||
symbol -= min_match_len;
|
||||
if( symbol < len_low_symbols )
|
||||
{
|
||||
range_encoder.encode_bit( choice1, 0 );
|
||||
range_encoder.encode_tree( bm_low[pos_state], symbol, len_low_bits );
|
||||
}
|
||||
else
|
||||
{
|
||||
range_encoder.encode_bit( choice1, 1 );
|
||||
if( symbol < len_low_symbols + len_mid_symbols )
|
||||
{
|
||||
range_encoder.encode_bit( choice2, 0 );
|
||||
range_encoder.encode_tree( bm_mid[pos_state], symbol - len_low_symbols, len_mid_bits );
|
||||
}
|
||||
else
|
||||
{
|
||||
range_encoder.encode_bit( choice2, 1 );
|
||||
range_encoder.encode_tree( bm_high, symbol - len_low_symbols - len_mid_symbols, len_high_bits );
|
||||
}
|
||||
}
|
||||
if( --counters[pos_state] <= 0 ) update_prices( pos_state );
|
||||
}
|
||||
|
||||
|
||||
void LZ_encoder::fill_align_prices() throw()
|
||||
{
|
||||
for( int i = 0; i < dis_align_size; ++i )
|
||||
align_prices[i] = price_symbol_reversed( bm_align, i, dis_align_bits );
|
||||
align_price_count = dis_align_size;
|
||||
}
|
||||
|
||||
|
||||
void LZ_encoder::fill_distance_prices() throw()
|
||||
{
|
||||
for( int dis = start_dis_model; dis < modeled_distances; ++dis )
|
||||
{
|
||||
const int dis_slot = dis_slots.table( dis );
|
||||
const int direct_bits = ( dis_slot >> 1 ) - 1;
|
||||
const int base = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
|
||||
const int price =
|
||||
price_symbol_reversed( bm_dis + base - dis_slot, dis - base, direct_bits );
|
||||
for( int dis_state = 0; dis_state < max_dis_states; ++dis_state )
|
||||
dis_prices[dis_state][dis] = price;
|
||||
}
|
||||
|
||||
for( int dis_state = 0; dis_state < max_dis_states; ++dis_state )
|
||||
{
|
||||
int * const dsp = dis_slot_prices[dis_state];
|
||||
const Bit_model * const bmds = bm_dis_slot[dis_state];
|
||||
int slot = 0;
|
||||
for( ; slot < end_dis_model && slot < num_dis_slots; ++slot )
|
||||
dsp[slot] = price_symbol( bmds, slot, dis_slot_bits );
|
||||
for( ; slot < num_dis_slots; ++slot )
|
||||
dsp[slot] = price_symbol( bmds, slot, dis_slot_bits ) +
|
||||
(((( slot >> 1 ) - 1 ) - dis_align_bits ) << price_shift );
|
||||
|
||||
int * const dp = dis_prices[dis_state];
|
||||
int dis = 0;
|
||||
for( ; dis < start_dis_model; ++dis )
|
||||
dp[dis] = dsp[dis];
|
||||
for( ; dis < modeled_distances; ++dis )
|
||||
dp[dis] += dsp[dis_slots.table( dis )];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return value == number of bytes advanced (ahead).
|
||||
// trials[0]..trials[retval-1] contain the steps to encode.
|
||||
// ( trials[0].dis == -1 && trials[0].price == 1 ) means literal.
|
||||
int LZ_encoder::sequence_optimizer( const int reps[num_rep_distances],
|
||||
const State & state )
|
||||
{
|
||||
int main_len;
|
||||
if( longest_match_found > 0 ) // from previous call
|
||||
{
|
||||
main_len = longest_match_found;
|
||||
longest_match_found = 0;
|
||||
}
|
||||
else main_len = read_match_distances();
|
||||
|
||||
int replens[num_rep_distances];
|
||||
int rep_index = 0;
|
||||
for( int i = 0; i < num_rep_distances; ++i )
|
||||
{
|
||||
replens[i] = matchfinder.true_match_len( 0, reps[i] + 1, max_match_len );
|
||||
if( replens[i] > replens[rep_index] ) rep_index = i;
|
||||
}
|
||||
if( replens[rep_index] >= matchfinder.match_len_limit() )
|
||||
{
|
||||
trials[0].dis = rep_index;
|
||||
trials[0].price = replens[rep_index];
|
||||
move_pos( replens[rep_index], true );
|
||||
return replens[rep_index];
|
||||
}
|
||||
|
||||
if( main_len >= matchfinder.match_len_limit() )
|
||||
{
|
||||
trials[0].dis = match_distances[matchfinder.match_len_limit()] +
|
||||
num_rep_distances;
|
||||
trials[0].price = main_len;
|
||||
move_pos( main_len, true );
|
||||
return main_len;
|
||||
}
|
||||
|
||||
{
|
||||
const int pos_state = matchfinder.data_position() & pos_state_mask;
|
||||
const uint8_t prev_byte = matchfinder[-1];
|
||||
const uint8_t cur_byte = matchfinder[0];
|
||||
const uint8_t match_byte = matchfinder[-reps[0]-1];
|
||||
|
||||
trials[0].state = state;
|
||||
for( int i = 0; i < num_rep_distances; ++i ) trials[0].reps[i] = reps[i];
|
||||
trials[1].dis = -1;
|
||||
trials[1].prev_index = 0;
|
||||
trials[1].price = price0( bm_match[state()][pos_state] );
|
||||
if( state.is_char() )
|
||||
trials[1].price += literal_encoder.price_symbol( prev_byte, cur_byte );
|
||||
else
|
||||
trials[1].price += literal_encoder.price_matched( prev_byte, cur_byte, match_byte );
|
||||
|
||||
const int match_price = price1( bm_match[state()][pos_state] );
|
||||
const int rep_match_price = match_price + price1( bm_rep[state()] );
|
||||
|
||||
if( match_byte == cur_byte )
|
||||
trials[1].update( 0, 0, rep_match_price + price_rep_len1( state, pos_state ) );
|
||||
|
||||
if( main_len < min_match_len )
|
||||
{
|
||||
trials[0].dis = trials[1].dis;
|
||||
trials[0].price = 1;
|
||||
matchfinder.move_pos();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( main_len <= replens[rep_index] )
|
||||
{
|
||||
main_len = replens[rep_index];
|
||||
for( int len = min_match_len; len <= main_len; ++len )
|
||||
trials[len].price = infinite_price;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int normal_match_price = match_price + price0( bm_rep[state()] );
|
||||
for( int len = min_match_len; len <= main_len; ++len )
|
||||
{
|
||||
trials[len].dis = match_distances[len] + num_rep_distances;
|
||||
trials[len].prev_index = 0;
|
||||
trials[len].price = normal_match_price +
|
||||
price_pair( match_distances[len], len, pos_state );
|
||||
}
|
||||
}
|
||||
|
||||
for( int rep = 0; rep < num_rep_distances; ++rep )
|
||||
{
|
||||
const int price = rep_match_price +
|
||||
price_rep( rep, state, pos_state );
|
||||
for( int len = min_match_len; len <= replens[rep]; ++len )
|
||||
trials[len].update( rep, 0, price +
|
||||
rep_match_len_encoder.price( len, pos_state ) );
|
||||
}
|
||||
}
|
||||
|
||||
int cur = 0;
|
||||
int num_trials = main_len;
|
||||
matchfinder.move_pos();
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( ++cur >= num_trials ) // no more initialized trials
|
||||
{
|
||||
backward( cur );
|
||||
return cur;
|
||||
}
|
||||
const int newlen = read_match_distances();
|
||||
if( newlen >= matchfinder.match_len_limit() )
|
||||
{
|
||||
longest_match_found = newlen;
|
||||
backward( cur );
|
||||
return cur;
|
||||
}
|
||||
|
||||
Trial & cur_trial = trials[cur];
|
||||
const int prev_index = cur_trial.prev_index;
|
||||
|
||||
cur_trial.state = trials[prev_index].state;
|
||||
|
||||
for( int i = 0; i < num_rep_distances; ++i )
|
||||
cur_trial.reps[i] = trials[prev_index].reps[i];
|
||||
if( prev_index == cur - 1 )
|
||||
{
|
||||
if( cur_trial.dis == 0 ) cur_trial.state.set_short_rep();
|
||||
else cur_trial.state.set_char();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( cur_trial.dis < num_rep_distances ) cur_trial.state.set_rep();
|
||||
else cur_trial.state.set_match();
|
||||
mtf_reps( cur_trial.dis, cur_trial.reps );
|
||||
}
|
||||
|
||||
const int pos_state = matchfinder.data_position() & pos_state_mask;
|
||||
const uint8_t prev_byte = matchfinder[-1];
|
||||
const uint8_t cur_byte = matchfinder[0];
|
||||
const uint8_t match_byte = matchfinder[-cur_trial.reps[0]-1];
|
||||
|
||||
int next_price = cur_trial.price +
|
||||
price0( bm_match[cur_trial.state()][pos_state] );
|
||||
if( cur_trial.state.is_char() )
|
||||
next_price += literal_encoder.price_symbol( prev_byte, cur_byte );
|
||||
else
|
||||
next_price += literal_encoder.price_matched( prev_byte, cur_byte, match_byte );
|
||||
matchfinder.move_pos();
|
||||
|
||||
Trial & next_trial = trials[cur+1];
|
||||
|
||||
next_trial.update( -1, cur, next_price );
|
||||
|
||||
const int match_price = cur_trial.price + price1( bm_match[cur_trial.state()][pos_state] );
|
||||
const int rep_match_price = match_price + price1( bm_rep[cur_trial.state()] );
|
||||
|
||||
if( match_byte == cur_byte && next_trial.dis != 0 )
|
||||
next_trial.update( 0, cur, rep_match_price +
|
||||
price_rep_len1( cur_trial.state, pos_state ) );
|
||||
|
||||
const int len_limit = min( min( max_num_trials - 1 - cur,
|
||||
matchfinder.available_bytes() ), matchfinder.match_len_limit() );
|
||||
if( len_limit < min_match_len ) continue;
|
||||
|
||||
for( int rep = 0; rep < num_rep_distances; ++rep )
|
||||
{
|
||||
const int dis = cur_trial.reps[rep] + 1;
|
||||
int len = 0;
|
||||
const uint8_t * const data = matchfinder.ptr_to_current_pos() - 1;
|
||||
while( len < len_limit && data[len] == data[len-dis] ) ++len;
|
||||
if( len >= min_match_len )
|
||||
{
|
||||
const int price = rep_match_price +
|
||||
price_rep( rep, cur_trial.state, pos_state );
|
||||
while( num_trials < cur + len )
|
||||
trials[++num_trials].price = infinite_price;
|
||||
for( ; len >= min_match_len; --len )
|
||||
trials[cur+len].update( rep, cur, price +
|
||||
rep_match_len_encoder.price( len, pos_state ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( newlen <= len_limit &&
|
||||
( newlen > min_match_len ||
|
||||
( newlen == min_match_len &&
|
||||
match_distances[min_match_len] < modeled_distances ) ) )
|
||||
{
|
||||
const int normal_match_price = match_price +
|
||||
price0( bm_rep[cur_trial.state()] );
|
||||
while( num_trials < cur + newlen )
|
||||
trials[++num_trials].price = infinite_price;
|
||||
|
||||
int dis = match_distances[min_match_len];
|
||||
int dis_state = get_dis_state( min_match_len );
|
||||
int dis_price = infinite_price;
|
||||
if( dis < modeled_distances )
|
||||
trials[cur+min_match_len].update( dis + num_rep_distances, cur,
|
||||
normal_match_price + dis_prices[dis_state][dis] +
|
||||
len_encoder.price( min_match_len, pos_state ) );
|
||||
for( int len = min_match_len + 1; len <= newlen; ++len )
|
||||
{
|
||||
if( dis != match_distances[len] || dis_state < max_dis_states - 1 )
|
||||
{
|
||||
dis = match_distances[len];
|
||||
dis_state = get_dis_state( len );
|
||||
dis_price = price_dis( dis, dis_state );
|
||||
}
|
||||
trials[cur+len].update( dis + num_rep_distances, cur,
|
||||
normal_match_price + dis_price +
|
||||
len_encoder.price( len, pos_state ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// End Of Stream mark => (dis == 0xFFFFFFFFU, len == min_match_len)
|
||||
void LZ_encoder::full_flush( const State & state )
|
||||
{
|
||||
const int pos_state = matchfinder.data_position() & pos_state_mask;
|
||||
range_encoder.encode_bit( bm_match[state()][pos_state], 1 );
|
||||
range_encoder.encode_bit( bm_rep[state()], 0 );
|
||||
encode_pair( 0xFFFFFFFFU, min_match_len, pos_state );
|
||||
range_encoder.flush();
|
||||
File_trailer trailer;
|
||||
trailer.data_crc( crc() );
|
||||
trailer.data_size( matchfinder.data_position() );
|
||||
trailer.member_size( range_encoder.member_position() + File_trailer::size() );
|
||||
for( int i = 0; i < File_trailer::size(); ++i )
|
||||
range_encoder.put_byte( trailer.data[i] );
|
||||
range_encoder.flush_data();
|
||||
}
|
||||
|
||||
|
||||
LZ_encoder::LZ_encoder( Matchfinder & mf, const File_header & header,
|
||||
const int outfd )
|
||||
:
|
||||
longest_match_found( 0 ),
|
||||
crc_( 0xFFFFFFFFU ),
|
||||
matchfinder( mf ),
|
||||
range_encoder( outfd ),
|
||||
len_encoder( matchfinder.match_len_limit() ),
|
||||
rep_match_len_encoder( matchfinder.match_len_limit() ),
|
||||
num_dis_slots( 2 * real_bits( matchfinder.dictionary_size() - 1 ) )
|
||||
{
|
||||
fill_align_prices();
|
||||
|
||||
for( int i = 0; i < File_header::size; ++i )
|
||||
range_encoder.put_byte( header.data[i] );
|
||||
}
|
||||
|
||||
|
||||
bool LZ_encoder::encode_member( const long long member_size )
|
||||
{
|
||||
const long long member_size_limit =
|
||||
member_size - File_trailer::size() - max_marker_size;
|
||||
const int fill_count = ( matchfinder.match_len_limit() > 12 ) ? 512 : 2048;
|
||||
int fill_counter = 0;
|
||||
int rep_distances[num_rep_distances];
|
||||
State state;
|
||||
for( int i = 0; i < num_rep_distances; ++i ) rep_distances[i] = 0;
|
||||
|
||||
if( matchfinder.data_position() != 0 ||
|
||||
range_encoder.member_position() != File_header::size )
|
||||
return false; // can be called only once
|
||||
|
||||
if( !matchfinder.finished() ) // encode first byte
|
||||
{
|
||||
const uint8_t prev_byte = 0;
|
||||
const uint8_t cur_byte = matchfinder[0];
|
||||
range_encoder.encode_bit( bm_match[state()][0], 0 );
|
||||
literal_encoder.encode( range_encoder, prev_byte, cur_byte );
|
||||
crc32.update( crc_, cur_byte );
|
||||
move_pos( 1 );
|
||||
}
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( matchfinder.finished() ) { full_flush( state ); return true; }
|
||||
if( fill_counter <= 0 )
|
||||
{ fill_distance_prices(); fill_counter = fill_count; }
|
||||
|
||||
int ahead = sequence_optimizer( rep_distances, state );
|
||||
if( ahead <= 0 ) return false;
|
||||
fill_counter -= ahead;
|
||||
|
||||
for( int i = 0; ; )
|
||||
{
|
||||
const int pos_state =
|
||||
( matchfinder.data_position() - ahead ) & pos_state_mask;
|
||||
const int dis = trials[i].dis;
|
||||
const int len = trials[i].price;
|
||||
|
||||
bool bit = ( dis < 0 && len == 1 );
|
||||
range_encoder.encode_bit( bm_match[state()][pos_state], !bit );
|
||||
if( bit ) // literal byte
|
||||
{
|
||||
const uint8_t prev_byte = matchfinder[-ahead-1];
|
||||
const uint8_t cur_byte = matchfinder[-ahead];
|
||||
crc32.update( crc_, cur_byte );
|
||||
if( state.is_char() )
|
||||
literal_encoder.encode( range_encoder, prev_byte, cur_byte );
|
||||
else
|
||||
{
|
||||
const uint8_t match_byte = matchfinder[-ahead-rep_distances[0]-1];
|
||||
literal_encoder.encode_matched( range_encoder,
|
||||
prev_byte, cur_byte, match_byte );
|
||||
}
|
||||
state.set_char();
|
||||
}
|
||||
else // match or repeated match
|
||||
{
|
||||
crc32.update( crc_, matchfinder.ptr_to_current_pos() - ahead, len );
|
||||
mtf_reps( dis, rep_distances );
|
||||
bit = ( dis < num_rep_distances );
|
||||
range_encoder.encode_bit( bm_rep[state()], bit );
|
||||
if( bit )
|
||||
{
|
||||
bit = ( dis == 0 );
|
||||
range_encoder.encode_bit( bm_rep0[state()], !bit );
|
||||
if( bit )
|
||||
range_encoder.encode_bit( bm_len[state()][pos_state], len > 1 );
|
||||
else
|
||||
{
|
||||
range_encoder.encode_bit( bm_rep1[state()], dis > 1 );
|
||||
if( dis > 1 )
|
||||
range_encoder.encode_bit( bm_rep2[state()], dis > 2 );
|
||||
}
|
||||
if( len == 1 ) state.set_short_rep();
|
||||
else
|
||||
{
|
||||
rep_match_len_encoder.encode( range_encoder, len, pos_state );
|
||||
state.set_rep();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encode_pair( dis - num_rep_distances, len, pos_state );
|
||||
state.set_match();
|
||||
}
|
||||
}
|
||||
ahead -= len; i += len;
|
||||
if( range_encoder.member_position() >= member_size_limit )
|
||||
{
|
||||
if( !matchfinder.dec_pos( ahead ) ) return false;
|
||||
full_flush( state );
|
||||
return true;
|
||||
}
|
||||
if( ahead <= 0 ) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,582 @@
|
|||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
enum { max_num_trials = 1 << 12,
|
||||
price_shift = 6 };
|
||||
|
||||
class Dis_slots
|
||||
{
|
||||
unsigned char data[1<<12];
|
||||
|
||||
public:
|
||||
void init() throw()
|
||||
{
|
||||
for( int slot = 0; slot < 4; ++slot ) data[slot] = slot;
|
||||
for( int i = 4, size = 2, slot = 4; slot < 24; slot += 2 )
|
||||
{
|
||||
memset( &data[i], slot, size );
|
||||
memset( &data[i+size], slot + 1, size );
|
||||
size <<= 1;
|
||||
i += size;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char table( const int dis ) const throw() { return data[dis]; }
|
||||
|
||||
int operator[]( const uint32_t dis ) const throw()
|
||||
{
|
||||
if( dis < (1 << 12) ) return data[dis];
|
||||
if( dis < (1 << 23) ) return data[dis>>11] + 22;
|
||||
return data[dis>>22] + 44;
|
||||
}
|
||||
};
|
||||
|
||||
extern Dis_slots dis_slots;
|
||||
|
||||
|
||||
class Prob_prices
|
||||
{
|
||||
int data[bit_model_total >> 2];
|
||||
|
||||
public:
|
||||
void init() throw()
|
||||
{
|
||||
const int num_bits = ( bit_model_total_bits - 2 );
|
||||
int j = 1, end = 2;
|
||||
data[0] = bit_model_total_bits << price_shift;
|
||||
for( int i = num_bits - 1; i >= 0; --i, end <<= 1 )
|
||||
{
|
||||
for( ; j < end; ++j )
|
||||
data[j] = ( i << price_shift ) +
|
||||
( ( (end - j) << price_shift ) >> ( num_bits - i - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
int operator[]( const int probability ) const throw()
|
||||
{ return data[probability >> 2]; }
|
||||
};
|
||||
|
||||
extern Prob_prices prob_prices;
|
||||
|
||||
|
||||
inline int price0( const Bit_model & bm ) throw()
|
||||
{ return prob_prices[bm.probability]; }
|
||||
|
||||
inline int price1( const Bit_model & bm ) throw()
|
||||
{ return prob_prices[bit_model_total-bm.probability]; }
|
||||
|
||||
inline int price_bit( const Bit_model & bm, const int bit ) throw()
|
||||
{ if( bit ) return price1( bm ); else return price0( bm ); }
|
||||
|
||||
|
||||
inline int price_symbol( const Bit_model bm[], int symbol, const int num_bits ) throw()
|
||||
{
|
||||
int price = 0;
|
||||
symbol |= ( 1 << num_bits );
|
||||
while( symbol > 1 )
|
||||
{
|
||||
const int bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += price_bit( bm[symbol], bit );
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
|
||||
inline int price_symbol_reversed( const Bit_model bm[], int symbol,
|
||||
const int num_bits ) throw()
|
||||
{
|
||||
int price = 0;
|
||||
int model = 1;
|
||||
for( int i = num_bits; i > 0; --i )
|
||||
{
|
||||
const int bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += price_bit( bm[model], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
|
||||
inline int price_matched( const Bit_model bm[], const int symbol,
|
||||
const int match_byte ) throw()
|
||||
{
|
||||
int price = 0;
|
||||
int model = 1;
|
||||
|
||||
for( int i = 7; i >= 0; --i )
|
||||
{
|
||||
const int match_bit = ( match_byte >> i ) & 1;
|
||||
int bit = ( symbol >> i ) & 1;
|
||||
price += price_bit( bm[(match_bit<<8)+model+0x100], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
if( match_bit != bit )
|
||||
{
|
||||
while( --i >= 0 )
|
||||
{
|
||||
bit = ( symbol >> i ) & 1;
|
||||
price += price_bit( bm[model], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
|
||||
class Matchfinder
|
||||
{
|
||||
enum { // bytes to keep in buffer before dictionary
|
||||
before_size = max_num_trials + 1,
|
||||
// bytes to keep in buffer after pos
|
||||
after_size = max_match_len,
|
||||
num_prev_positions4 = 1 << 20,
|
||||
num_prev_positions3 = 1 << 18,
|
||||
num_prev_positions2 = 1 << 16,
|
||||
num_prev_positions = num_prev_positions4 + num_prev_positions3 +
|
||||
num_prev_positions2 };
|
||||
|
||||
long long partial_data_pos;
|
||||
uint8_t * buffer; // input buffer
|
||||
int32_t * const prev_positions; // last seen position of key
|
||||
int32_t * prev_pos_tree;
|
||||
int dictionary_size_; // bytes to keep in buffer before pos
|
||||
int buffer_size;
|
||||
int pos; // current pos in buffer
|
||||
int cyclic_pos; // current pos in dictionary
|
||||
int stream_pos; // first byte not yet read from file
|
||||
int pos_limit; // when reached, a new block must be read
|
||||
const int match_len_limit_;
|
||||
const int cycles;
|
||||
const int infd; // input file descriptor
|
||||
bool at_stream_end; // stream_pos shows real end of file
|
||||
|
||||
bool read_block();
|
||||
|
||||
public:
|
||||
Matchfinder( const int dict_size, const int len_limit, const int ifd );
|
||||
|
||||
~Matchfinder()
|
||||
{ delete[] prev_pos_tree; delete[] prev_positions; free( buffer ); }
|
||||
|
||||
uint8_t operator[]( const int i ) const throw() { return buffer[pos+i]; }
|
||||
int available_bytes() const throw() { return stream_pos - pos; }
|
||||
long long data_position() const throw() { return partial_data_pos + pos; }
|
||||
int dictionary_size() const throw() { return dictionary_size_; }
|
||||
bool finished() const throw() { return at_stream_end && pos >= stream_pos; }
|
||||
int match_len_limit() const throw() { return match_len_limit_; }
|
||||
const uint8_t * ptr_to_current_pos() const throw() { return buffer + pos; }
|
||||
|
||||
bool dec_pos( const int ahead ) throw()
|
||||
{
|
||||
if( ahead < 0 || pos < ahead ) return false;
|
||||
pos -= ahead;
|
||||
cyclic_pos -= ahead;
|
||||
if( cyclic_pos < 0 ) cyclic_pos += dictionary_size_;
|
||||
return true;
|
||||
}
|
||||
|
||||
int true_match_len( const int index, const int distance, int len_limit ) const throw()
|
||||
{
|
||||
if( index + len_limit > available_bytes() )
|
||||
len_limit = available_bytes() - index;
|
||||
const uint8_t * const data = buffer + pos + index - distance;
|
||||
int i = 0;
|
||||
while( i < len_limit && data[i] == data[i+distance] ) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
void reset();
|
||||
void move_pos();
|
||||
int longest_match_len( int * const distances = 0 ) throw();
|
||||
};
|
||||
|
||||
|
||||
class Range_encoder
|
||||
{
|
||||
enum { buffer_size = 65536 };
|
||||
uint64_t low;
|
||||
long long partial_member_pos;
|
||||
uint8_t * const buffer; // output buffer
|
||||
int pos; // current pos in buffer
|
||||
uint32_t range;
|
||||
int ff_count;
|
||||
const int outfd; // output file descriptor
|
||||
uint8_t cache;
|
||||
|
||||
void shift_low()
|
||||
{
|
||||
const uint32_t carry = low >> 32;
|
||||
if( low < 0xFF000000U || carry == 1 )
|
||||
{
|
||||
put_byte( cache + carry );
|
||||
for( ; ff_count > 0; --ff_count ) put_byte( 0xFF + carry );
|
||||
cache = low >> 24;
|
||||
}
|
||||
else ++ff_count;
|
||||
low = ( low & 0x00FFFFFFU ) << 8;
|
||||
}
|
||||
|
||||
public:
|
||||
Range_encoder( const int ofd )
|
||||
:
|
||||
low( 0 ),
|
||||
partial_member_pos( 0 ),
|
||||
buffer( new uint8_t[buffer_size] ),
|
||||
pos( 0 ),
|
||||
range( 0xFFFFFFFFU ),
|
||||
ff_count( 0 ),
|
||||
outfd( ofd ),
|
||||
cache( 0 ) {}
|
||||
|
||||
~Range_encoder() { delete[] buffer; }
|
||||
|
||||
long long member_position() const throw()
|
||||
{ return partial_member_pos + pos + ff_count; }
|
||||
|
||||
void flush() { for( int i = 0; i < 5; ++i ) shift_low(); }
|
||||
void flush_data();
|
||||
|
||||
void put_byte( const uint8_t b )
|
||||
{
|
||||
buffer[pos] = b;
|
||||
if( ++pos >= buffer_size ) flush_data();
|
||||
}
|
||||
|
||||
void encode( const int symbol, const int num_bits )
|
||||
{
|
||||
for( int i = num_bits - 1; i >= 0; --i )
|
||||
{
|
||||
range >>= 1;
|
||||
if( (symbol >> i) & 1 ) low += range;
|
||||
if( range <= 0x00FFFFFFU ) { range <<= 8; shift_low(); }
|
||||
}
|
||||
}
|
||||
|
||||
void encode_bit( Bit_model & bm, const int bit )
|
||||
{
|
||||
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
|
||||
if( !bit )
|
||||
{
|
||||
range = bound;
|
||||
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
|
||||
}
|
||||
else
|
||||
{
|
||||
low += bound;
|
||||
range -= bound;
|
||||
bm.probability -= bm.probability >> bit_model_move_bits;
|
||||
}
|
||||
if( range <= 0x00FFFFFFU ) { range <<= 8; shift_low(); }
|
||||
}
|
||||
|
||||
void encode_tree( Bit_model bm[], const int symbol, const int num_bits )
|
||||
{
|
||||
int mask = ( 1 << ( num_bits - 1 ) );
|
||||
int model = 1;
|
||||
for( int i = num_bits; i > 0; --i, mask >>= 1 )
|
||||
{
|
||||
const int bit = ( symbol & mask );
|
||||
encode_bit( bm[model], bit );
|
||||
model <<= 1;
|
||||
if( bit ) model |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_tree_reversed( Bit_model bm[], int symbol, const int num_bits )
|
||||
{
|
||||
int model = 1;
|
||||
for( int i = num_bits; i > 0; --i )
|
||||
{
|
||||
const int bit = symbol & 1;
|
||||
encode_bit( bm[model], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_matched( Bit_model bm[], int symbol, int match_byte )
|
||||
{
|
||||
int model = 1;
|
||||
for( int i = 7; i >= 0; --i )
|
||||
{
|
||||
const int match_bit = ( match_byte >> i ) & 1;
|
||||
int bit = ( symbol >> i ) & 1;
|
||||
encode_bit( bm[(match_bit<<8)+model+0x100], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
if( match_bit != bit )
|
||||
{
|
||||
while( --i >= 0 )
|
||||
{
|
||||
bit = ( symbol >> i ) & 1;
|
||||
encode_bit( bm[model], bit );
|
||||
model = ( model << 1 ) | bit;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Len_encoder
|
||||
{
|
||||
Bit_model choice1;
|
||||
Bit_model choice2;
|
||||
Bit_model bm_low[pos_states][len_low_symbols];
|
||||
Bit_model bm_mid[pos_states][len_mid_symbols];
|
||||
Bit_model bm_high[len_high_symbols];
|
||||
int prices[pos_states][max_len_symbols];
|
||||
const int len_symbols;
|
||||
int counters[pos_states];
|
||||
|
||||
void update_prices( const int pos_state ) throw()
|
||||
{
|
||||
int * const pps = prices[pos_state];
|
||||
int tmp = price0( choice1 );
|
||||
int len = 0;
|
||||
for( ; len < len_low_symbols && len < len_symbols; ++len )
|
||||
pps[len] = tmp +
|
||||
price_symbol( bm_low[pos_state], len, len_low_bits );
|
||||
tmp = price1( choice1 );
|
||||
for( ; len < len_low_symbols + len_mid_symbols && len < len_symbols; ++len )
|
||||
pps[len] = tmp + price0( choice2 ) +
|
||||
price_symbol( bm_mid[pos_state], len - len_low_symbols, len_mid_bits );
|
||||
for( ; len < len_symbols; ++len )
|
||||
// using 4 slots per value makes "price" faster
|
||||
prices[3][len] = prices[2][len] = prices[1][len] = prices[0][len] =
|
||||
tmp + price1( choice2 ) +
|
||||
price_symbol( bm_high, len - len_low_symbols - len_mid_symbols, len_high_bits );
|
||||
counters[pos_state] = len_symbols;
|
||||
}
|
||||
|
||||
public:
|
||||
Len_encoder( const int len_limit )
|
||||
: len_symbols( len_limit + 1 - min_match_len )
|
||||
{
|
||||
for( int i = 0; i < pos_states; ++i ) update_prices( i );
|
||||
}
|
||||
|
||||
void encode( Range_encoder & range_encoder, int symbol,
|
||||
const int pos_state );
|
||||
|
||||
int price( const int symbol, const int pos_state ) const throw()
|
||||
{ return prices[pos_state][symbol - min_match_len]; }
|
||||
};
|
||||
|
||||
|
||||
class Literal_encoder
|
||||
{
|
||||
Bit_model bm_literal[1<<literal_context_bits][0x300];
|
||||
|
||||
int lstate( const uint8_t prev_byte ) const throw()
|
||||
{ return ( prev_byte >> ( 8 - literal_context_bits ) ); }
|
||||
|
||||
public:
|
||||
void encode( Range_encoder & range_encoder,
|
||||
uint8_t prev_byte, uint8_t symbol )
|
||||
{ range_encoder.encode_tree( bm_literal[lstate(prev_byte)], symbol, 8 ); }
|
||||
|
||||
void encode_matched( Range_encoder & range_encoder,
|
||||
uint8_t prev_byte, uint8_t symbol, uint8_t match_byte )
|
||||
{ range_encoder.encode_matched( bm_literal[lstate(prev_byte)],
|
||||
symbol, match_byte ); }
|
||||
|
||||
int price_symbol( uint8_t prev_byte, uint8_t symbol ) const throw()
|
||||
{ return ::price_symbol( bm_literal[lstate(prev_byte)], symbol, 8 ); }
|
||||
|
||||
int price_matched( uint8_t prev_byte, uint8_t symbol,
|
||||
uint8_t match_byte ) const throw()
|
||||
{ return ::price_matched( bm_literal[lstate(prev_byte)],
|
||||
symbol, match_byte ); }
|
||||
};
|
||||
|
||||
|
||||
class LZ_encoder
|
||||
{
|
||||
enum { infinite_price = 0x0FFFFFFF,
|
||||
max_marker_size = 16,
|
||||
num_rep_distances = 4 }; // must be 4
|
||||
|
||||
struct Trial
|
||||
{
|
||||
State state;
|
||||
int dis;
|
||||
int prev_index; // index of prev trial in trials[]
|
||||
int price; // dual use var; cumulative price, match length
|
||||
int reps[num_rep_distances];
|
||||
void update( const int d, const int p_i, const int pr ) throw()
|
||||
{ if( pr < price ) { dis = d; prev_index = p_i; price = pr; } }
|
||||
};
|
||||
|
||||
int longest_match_found;
|
||||
uint32_t crc_;
|
||||
|
||||
Bit_model bm_match[State::states][pos_states];
|
||||
Bit_model bm_rep[State::states];
|
||||
Bit_model bm_rep0[State::states];
|
||||
Bit_model bm_rep1[State::states];
|
||||
Bit_model bm_rep2[State::states];
|
||||
Bit_model bm_len[State::states][pos_states];
|
||||
Bit_model bm_dis_slot[max_dis_states][1<<dis_slot_bits];
|
||||
Bit_model bm_dis[modeled_distances-end_dis_model+1];
|
||||
Bit_model bm_align[dis_align_size];
|
||||
|
||||
Matchfinder & matchfinder;
|
||||
Range_encoder range_encoder;
|
||||
Len_encoder len_encoder;
|
||||
Len_encoder rep_match_len_encoder;
|
||||
Literal_encoder literal_encoder;
|
||||
|
||||
const int num_dis_slots;
|
||||
int match_distances[max_match_len+1];
|
||||
Trial trials[max_num_trials];
|
||||
|
||||
int dis_slot_prices[max_dis_states][2*max_dictionary_bits];
|
||||
int dis_prices[max_dis_states][modeled_distances];
|
||||
int align_prices[dis_align_size];
|
||||
int align_price_count;
|
||||
|
||||
void fill_align_prices() throw();
|
||||
void fill_distance_prices() throw();
|
||||
|
||||
uint32_t crc() const throw() { return crc_ ^ 0xFFFFFFFFU; }
|
||||
|
||||
// move-to-front dis in/into reps
|
||||
void mtf_reps( const int dis, int reps[num_rep_distances] ) throw()
|
||||
{
|
||||
if( dis >= num_rep_distances )
|
||||
{
|
||||
for( int i = num_rep_distances - 1; i > 0; --i ) reps[i] = reps[i-1];
|
||||
reps[0] = dis - num_rep_distances;
|
||||
}
|
||||
else if( dis > 0 )
|
||||
{
|
||||
const int distance = reps[dis];
|
||||
for( int i = dis; i > 0; --i ) reps[i] = reps[i-1];
|
||||
reps[0] = distance;
|
||||
}
|
||||
}
|
||||
|
||||
int price_rep_len1( const State & state, const int pos_state ) const throw()
|
||||
{
|
||||
return price0( bm_rep0[state()] ) + price0( bm_len[state()][pos_state] );
|
||||
}
|
||||
|
||||
int price_rep( const int rep, const State & state,
|
||||
const int pos_state ) const throw()
|
||||
{
|
||||
if( rep == 0 ) return price0( bm_rep0[state()] ) +
|
||||
price1( bm_len[state()][pos_state] );
|
||||
int price = price1( bm_rep0[state()] );
|
||||
if( rep == 1 )
|
||||
price += price0( bm_rep1[state()] );
|
||||
else
|
||||
{
|
||||
price += price1( bm_rep1[state()] );
|
||||
price += price_bit( bm_rep2[state()], rep - 2 );
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
int price_dis( const int dis, const int dis_state ) const throw()
|
||||
{
|
||||
if( dis < modeled_distances )
|
||||
return dis_prices[dis_state][dis];
|
||||
else
|
||||
return dis_slot_prices[dis_state][dis_slots[dis]] +
|
||||
align_prices[dis & (dis_align_size - 1)];
|
||||
}
|
||||
|
||||
int price_pair( const int dis, const int len, const int pos_state ) const throw()
|
||||
{
|
||||
if( len <= min_match_len && dis >= modeled_distances )
|
||||
return infinite_price;
|
||||
return len_encoder.price( len, pos_state ) +
|
||||
price_dis( dis, get_dis_state( len ) );
|
||||
}
|
||||
|
||||
void encode_pair( const uint32_t dis, const int len, const int pos_state ) throw()
|
||||
{
|
||||
len_encoder.encode( range_encoder, len, pos_state );
|
||||
const int dis_slot = dis_slots[dis];
|
||||
range_encoder.encode_tree( bm_dis_slot[get_dis_state(len)], dis_slot, dis_slot_bits );
|
||||
|
||||
if( dis_slot >= start_dis_model )
|
||||
{
|
||||
const int direct_bits = ( dis_slot >> 1 ) - 1;
|
||||
const uint32_t base = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
|
||||
const uint32_t direct_dis = dis - base;
|
||||
|
||||
if( dis_slot < end_dis_model )
|
||||
range_encoder.encode_tree_reversed( bm_dis + base - dis_slot,
|
||||
direct_dis, direct_bits );
|
||||
else
|
||||
{
|
||||
range_encoder.encode( direct_dis >> dis_align_bits, direct_bits - dis_align_bits );
|
||||
range_encoder.encode_tree_reversed( bm_align, direct_dis, dis_align_bits );
|
||||
if( --align_price_count <= 0 ) fill_align_prices();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_match_distances() throw()
|
||||
{
|
||||
int len = matchfinder.longest_match_len( match_distances );
|
||||
if( len == matchfinder.match_len_limit() )
|
||||
len += matchfinder.true_match_len( len, match_distances[len] + 1, max_match_len - len );
|
||||
return len;
|
||||
}
|
||||
|
||||
void move_pos( int n, bool skip = false )
|
||||
{
|
||||
while( --n >= 0 )
|
||||
{
|
||||
if( skip ) skip = false;
|
||||
else matchfinder.longest_match_len();
|
||||
matchfinder.move_pos();
|
||||
}
|
||||
}
|
||||
|
||||
void backward( int cur )
|
||||
{
|
||||
int & dis = trials[cur].dis;
|
||||
while( cur > 0 )
|
||||
{
|
||||
const int prev_index = trials[cur].prev_index;
|
||||
Trial & prev_trial = trials[prev_index];
|
||||
prev_trial.price = cur - prev_index; // len
|
||||
cur = dis; dis = prev_trial.dis; prev_trial.dis = cur;
|
||||
cur = prev_index;
|
||||
}
|
||||
}
|
||||
|
||||
int sequence_optimizer( const int reps[num_rep_distances],
|
||||
const State & state );
|
||||
|
||||
void full_flush( const State & state );
|
||||
|
||||
public:
|
||||
LZ_encoder( Matchfinder & mf, const File_header & header, const int outfd );
|
||||
|
||||
bool encode_member( const long long member_size );
|
||||
|
||||
long long member_position() const throw()
|
||||
{ return range_encoder.member_position(); }
|
||||
};
|
|
@ -0,0 +1,378 @@
|
|||
#if !DECODER_ONLY
|
||||
|
||||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lzip.h"
|
||||
#include "encoder.h"
|
||||
#include "fast_encoder.h"
|
||||
|
||||
|
||||
bool Fmatchfinder::read_block()
|
||||
{
|
||||
if( !at_stream_end && stream_pos < buffer_size )
|
||||
{
|
||||
const int size = buffer_size - stream_pos;
|
||||
const int rd = readblock( infd, buffer + stream_pos, size );
|
||||
stream_pos += rd;
|
||||
if( rd != size && errno ) throw Error( "Read error" );
|
||||
at_stream_end = ( rd < size );
|
||||
}
|
||||
return pos < stream_pos;
|
||||
}
|
||||
|
||||
|
||||
Fmatchfinder::Fmatchfinder( const int ifd )
|
||||
:
|
||||
partial_data_pos( 0 ),
|
||||
prev_positions( new int32_t[num_prev_positions] ),
|
||||
pos( 0 ),
|
||||
cyclic_pos( 0 ),
|
||||
key4( 0 ),
|
||||
stream_pos( 0 ),
|
||||
match_len_limit_( 16 ),
|
||||
infd( ifd ),
|
||||
at_stream_end( false )
|
||||
{
|
||||
const int dict_size = 65536;
|
||||
const int buffer_size_limit = ( 16 * dict_size ) + before_size + after_size;
|
||||
buffer_size = dict_size;
|
||||
buffer = (uint8_t *)malloc( buffer_size );
|
||||
if( !buffer ) exit(-1);
|
||||
if( read_block() && !at_stream_end && buffer_size < buffer_size_limit )
|
||||
{
|
||||
buffer_size = buffer_size_limit;
|
||||
buffer = (uint8_t *)realloc( buffer, buffer_size );
|
||||
if( !buffer ) exit(-1);
|
||||
read_block();
|
||||
}
|
||||
if( at_stream_end && stream_pos < dict_size )
|
||||
dictionary_size_ = max( (int)min_dictionary_size, stream_pos );
|
||||
else dictionary_size_ = dict_size;
|
||||
pos_limit = buffer_size;
|
||||
if( !at_stream_end ) pos_limit -= after_size;
|
||||
prev_pos_chain = new int32_t[dictionary_size_];
|
||||
for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1;
|
||||
}
|
||||
|
||||
|
||||
void Fmatchfinder::reset()
|
||||
{
|
||||
const int size = stream_pos - pos;
|
||||
if( size > 0 ) memmove( buffer, buffer + pos, size );
|
||||
partial_data_pos = 0;
|
||||
stream_pos -= pos;
|
||||
pos = 0;
|
||||
cyclic_pos = 0;
|
||||
key4 = 0;
|
||||
for( int i = 0; i < num_prev_positions; ++i ) prev_positions[i] = -1;
|
||||
read_block();
|
||||
}
|
||||
|
||||
|
||||
void Fmatchfinder::move_pos()
|
||||
{
|
||||
if( ++cyclic_pos >= dictionary_size_ ) cyclic_pos = 0;
|
||||
if( ++pos >= pos_limit )
|
||||
{
|
||||
if( pos > stream_pos )
|
||||
internal_error( "pos > stream_pos in Fmatchfinder::move_pos" );
|
||||
if( !at_stream_end )
|
||||
{
|
||||
const int offset = pos - dictionary_size_ - before_size;
|
||||
const int size = stream_pos - offset;
|
||||
memmove( buffer, buffer + offset, size );
|
||||
partial_data_pos += offset;
|
||||
pos -= offset;
|
||||
stream_pos -= offset;
|
||||
for( int i = 0; i < num_prev_positions; ++i )
|
||||
if( prev_positions[i] >= 0 ) prev_positions[i] -= offset;
|
||||
for( int i = 0; i < dictionary_size_; ++i )
|
||||
if( prev_pos_chain[i] >= 0 ) prev_pos_chain[i] -= offset;
|
||||
read_block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Fmatchfinder::longest_match_len( int * const distance )
|
||||
{
|
||||
int len_limit = match_len_limit_;
|
||||
if( len_limit > available_bytes() )
|
||||
{
|
||||
len_limit = available_bytes();
|
||||
if( len_limit < 4 ) return 0;
|
||||
}
|
||||
|
||||
const uint8_t * const data = buffer + pos;
|
||||
key4 = ( ( key4 << 4 ) ^ data[3] ) & ( num_prev_positions - 1 );
|
||||
|
||||
int newpos = prev_positions[key4];
|
||||
prev_positions[key4] = pos;
|
||||
|
||||
int32_t * ptr0 = prev_pos_chain + cyclic_pos;
|
||||
int maxlen = 0;
|
||||
|
||||
for( int count = 4; ; )
|
||||
{
|
||||
if( newpos < (pos - dictionary_size_ + 1) || newpos < 0 || --count < 0 )
|
||||
{ *ptr0 = -1; break; }
|
||||
const uint8_t * const newdata = buffer + newpos;
|
||||
int len = 0;
|
||||
if( newdata[maxlen] == data[maxlen] )
|
||||
while( len < len_limit && newdata[len] == data[len] ) ++len;
|
||||
|
||||
const int delta = pos - newpos;
|
||||
if( maxlen < len ) { maxlen = len; *distance = delta - 1; }
|
||||
|
||||
int32_t * const newptr = prev_pos_chain +
|
||||
( cyclic_pos - delta +
|
||||
( ( cyclic_pos >= delta ) ? 0 : dictionary_size_ ) );
|
||||
|
||||
if( len < len_limit )
|
||||
{
|
||||
*ptr0 = newpos;
|
||||
ptr0 = newptr;
|
||||
newpos = *ptr0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr0 = *newptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
|
||||
void Fmatchfinder::longest_match_len()
|
||||
{
|
||||
int len_limit = match_len_limit_;
|
||||
if( len_limit > available_bytes() )
|
||||
{
|
||||
len_limit = available_bytes();
|
||||
if( len_limit < 4 ) return;
|
||||
}
|
||||
|
||||
const uint8_t * const data = buffer + pos;
|
||||
key4 = ( ( key4 << 4 ) ^ data[3] ) & ( num_prev_positions - 1 );
|
||||
|
||||
const int newpos = prev_positions[key4];
|
||||
prev_positions[key4] = pos;
|
||||
|
||||
int32_t * const ptr0 = prev_pos_chain + cyclic_pos;
|
||||
|
||||
if( newpos < (pos - dictionary_size_ + 1) || newpos < 0 ) *ptr0 = -1;
|
||||
else
|
||||
{
|
||||
const uint8_t * const newdata = buffer + newpos;
|
||||
if( newdata[len_limit-1] != data[len_limit-1] ||
|
||||
memcmp( newdata, data, len_limit - 1 ) ) *ptr0 = newpos;
|
||||
else
|
||||
{
|
||||
int idx = cyclic_pos - pos + newpos;
|
||||
if( idx < 0 ) idx += dictionary_size_;
|
||||
*ptr0 = prev_pos_chain[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return value == number of bytes advanced (len).
|
||||
// *disp returns the distance to encode.
|
||||
// ( *disp == -1 && len == 1 ) means literal.
|
||||
int FLZ_encoder::sequence_optimizer( const int reps[num_rep_distances],
|
||||
int * const disp, const State & state )
|
||||
{
|
||||
const int main_len = read_match_distances();
|
||||
|
||||
int replen = 0;
|
||||
int rep_index = 0;
|
||||
for( int i = 0; i < num_rep_distances; ++i )
|
||||
{
|
||||
const int len = fmatchfinder.true_match_len( 0, reps[i] + 1, max_match_len );
|
||||
if( len > replen ) { replen = len; rep_index = i; }
|
||||
}
|
||||
if( replen > min_match_len && replen + 4 > main_len )
|
||||
{
|
||||
*disp = rep_index;
|
||||
move_pos( replen, true );
|
||||
return replen;
|
||||
}
|
||||
|
||||
if( main_len > min_match_len ||
|
||||
( main_len == min_match_len && match_distance < modeled_distances ) )
|
||||
{
|
||||
*disp = num_rep_distances + match_distance;
|
||||
move_pos( main_len, true );
|
||||
return main_len;
|
||||
}
|
||||
|
||||
const uint8_t cur_byte = fmatchfinder[0];
|
||||
const uint8_t match_byte = fmatchfinder[-reps[0]-1];
|
||||
|
||||
*disp = -1;
|
||||
if( match_byte == cur_byte )
|
||||
{
|
||||
const uint8_t prev_byte = fmatchfinder[-1];
|
||||
const int pos_state = fmatchfinder.data_position() & pos_state_mask;
|
||||
int price = price0( bm_match[state()][pos_state] );
|
||||
if( state.is_char() )
|
||||
price += literal_encoder.price_symbol( prev_byte, cur_byte );
|
||||
else
|
||||
price += literal_encoder.price_matched( prev_byte, cur_byte, match_byte );
|
||||
const int short_rep_price = price1( bm_match[state()][pos_state] ) +
|
||||
price1( bm_rep[state()] ) +
|
||||
price0( bm_rep0[state()] ) +
|
||||
price0( bm_len[state()][pos_state] );
|
||||
if( short_rep_price < price ) *disp = 0;
|
||||
}
|
||||
|
||||
fmatchfinder.move_pos();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// End Of Stream mark => (dis == 0xFFFFFFFFU, len == min_match_len)
|
||||
void FLZ_encoder::full_flush( const State & state )
|
||||
{
|
||||
const int pos_state = fmatchfinder.data_position() & pos_state_mask;
|
||||
range_encoder.encode_bit( bm_match[state()][pos_state], 1 );
|
||||
range_encoder.encode_bit( bm_rep[state()], 0 );
|
||||
encode_pair( 0xFFFFFFFFU, min_match_len, pos_state );
|
||||
range_encoder.flush();
|
||||
File_trailer trailer;
|
||||
trailer.data_crc( crc() );
|
||||
trailer.data_size( fmatchfinder.data_position() );
|
||||
trailer.member_size( range_encoder.member_position() + File_trailer::size() );
|
||||
for( int i = 0; i < File_trailer::size(); ++i )
|
||||
range_encoder.put_byte( trailer.data[i] );
|
||||
range_encoder.flush_data();
|
||||
}
|
||||
|
||||
|
||||
FLZ_encoder::FLZ_encoder( Fmatchfinder & mf, const File_header & header,
|
||||
const int outfd )
|
||||
:
|
||||
crc_( 0xFFFFFFFFU ),
|
||||
fmatchfinder( mf ),
|
||||
range_encoder( outfd ),
|
||||
len_encoder( fmatchfinder.match_len_limit() ),
|
||||
rep_match_len_encoder( fmatchfinder.match_len_limit() ),
|
||||
num_dis_slots( 2 * real_bits( fmatchfinder.dictionary_size() - 1 ) )
|
||||
{
|
||||
for( int i = 0; i < File_header::size; ++i )
|
||||
range_encoder.put_byte( header.data[i] );
|
||||
}
|
||||
|
||||
|
||||
bool FLZ_encoder::encode_member( const long long member_size )
|
||||
{
|
||||
const long long member_size_limit =
|
||||
member_size - File_trailer::size() - max_marker_size;
|
||||
int rep_distances[num_rep_distances];
|
||||
State state;
|
||||
for( int i = 0; i < num_rep_distances; ++i ) rep_distances[i] = 0;
|
||||
|
||||
if( fmatchfinder.data_position() != 0 ||
|
||||
range_encoder.member_position() != File_header::size )
|
||||
return false; // can be called only once
|
||||
|
||||
if( !fmatchfinder.finished() ) // encode first byte
|
||||
{
|
||||
const uint8_t prev_byte = 0;
|
||||
const uint8_t cur_byte = fmatchfinder[0];
|
||||
range_encoder.encode_bit( bm_match[state()][0], 0 );
|
||||
literal_encoder.encode( range_encoder, prev_byte, cur_byte );
|
||||
crc32.update( crc_, cur_byte );
|
||||
move_pos( 1 );
|
||||
}
|
||||
|
||||
while( true )
|
||||
{
|
||||
if( fmatchfinder.finished() ) { full_flush( state ); return true; }
|
||||
|
||||
const int pos_state = fmatchfinder.data_position() & pos_state_mask;
|
||||
int dis;
|
||||
const int len = sequence_optimizer( rep_distances, &dis, state );
|
||||
if( len <= 0 ) return false;
|
||||
|
||||
bool bit = ( dis < 0 && len == 1 );
|
||||
range_encoder.encode_bit( bm_match[state()][pos_state], !bit );
|
||||
if( bit ) // literal byte
|
||||
{
|
||||
const uint8_t prev_byte = fmatchfinder[-len-1];
|
||||
const uint8_t cur_byte = fmatchfinder[-len];
|
||||
crc32.update( crc_, cur_byte );
|
||||
if( state.is_char() )
|
||||
literal_encoder.encode( range_encoder, prev_byte, cur_byte );
|
||||
else
|
||||
{
|
||||
const uint8_t match_byte = fmatchfinder[-len-rep_distances[0]-1];
|
||||
literal_encoder.encode_matched( range_encoder,
|
||||
prev_byte, cur_byte, match_byte );
|
||||
}
|
||||
state.set_char();
|
||||
}
|
||||
else // match or repeated match
|
||||
{
|
||||
crc32.update( crc_, fmatchfinder.ptr_to_current_pos() - len, len );
|
||||
mtf_reps( dis, rep_distances );
|
||||
bit = ( dis < num_rep_distances );
|
||||
range_encoder.encode_bit( bm_rep[state()], bit );
|
||||
if( bit )
|
||||
{
|
||||
bit = ( dis == 0 );
|
||||
range_encoder.encode_bit( bm_rep0[state()], !bit );
|
||||
if( bit )
|
||||
range_encoder.encode_bit( bm_len[state()][pos_state], len > 1 );
|
||||
else
|
||||
{
|
||||
range_encoder.encode_bit( bm_rep1[state()], dis > 1 );
|
||||
if( dis > 1 )
|
||||
range_encoder.encode_bit( bm_rep2[state()], dis > 2 );
|
||||
}
|
||||
if( len == 1 ) state.set_short_rep();
|
||||
else
|
||||
{
|
||||
rep_match_len_encoder.encode( range_encoder, len, pos_state );
|
||||
state.set_rep();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encode_pair( dis - num_rep_distances, len, pos_state );
|
||||
state.set_match();
|
||||
}
|
||||
}
|
||||
if( range_encoder.member_position() >= member_size_limit )
|
||||
{
|
||||
full_flush( state );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Fmatchfinder
|
||||
{
|
||||
enum { // bytes to keep in buffer before dictionary
|
||||
before_size = max_match_len + 1,
|
||||
// bytes to keep in buffer after pos
|
||||
after_size = max_match_len,
|
||||
num_prev_positions = 1 << 16 };
|
||||
|
||||
long long partial_data_pos;
|
||||
uint8_t * buffer; // input buffer
|
||||
int32_t * const prev_positions; // last seen position of key
|
||||
int32_t * prev_pos_chain;
|
||||
int dictionary_size_; // bytes to keep in buffer before pos
|
||||
int buffer_size;
|
||||
int pos; // current pos in buffer
|
||||
int cyclic_pos; // current pos in dictionary
|
||||
int key4; // key made from latest 4 bytes
|
||||
int stream_pos; // first byte not yet read from file
|
||||
int pos_limit; // when reached, a new block must be read
|
||||
const int match_len_limit_;
|
||||
const int infd; // input file descriptor
|
||||
bool at_stream_end; // stream_pos shows real end of file
|
||||
|
||||
bool read_block();
|
||||
|
||||
public:
|
||||
Fmatchfinder( const int ifd );
|
||||
|
||||
~Fmatchfinder()
|
||||
{ delete[] prev_pos_chain; delete[] prev_positions; free( buffer ); }
|
||||
|
||||
uint8_t operator[]( const int i ) const { return buffer[pos+i]; }
|
||||
int available_bytes() const { return stream_pos - pos; }
|
||||
long long data_position() const { return partial_data_pos + pos; }
|
||||
int dictionary_size() const { return dictionary_size_; }
|
||||
bool finished() const { return at_stream_end && pos >= stream_pos; }
|
||||
int match_len_limit() const { return match_len_limit_; }
|
||||
const uint8_t * ptr_to_current_pos() const { return buffer + pos; }
|
||||
|
||||
int true_match_len( const int index, const int distance, int len_limit ) const
|
||||
{
|
||||
if( index + len_limit > available_bytes() )
|
||||
len_limit = available_bytes() - index;
|
||||
const uint8_t * const data = buffer + pos + index - distance;
|
||||
int i = 0;
|
||||
while( i < len_limit && data[i] == data[i+distance] ) ++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
void reset();
|
||||
void move_pos();
|
||||
int longest_match_len( int * const distance );
|
||||
void longest_match_len();
|
||||
};
|
||||
|
||||
|
||||
class FLZ_encoder
|
||||
{
|
||||
enum { max_marker_size = 16,
|
||||
num_rep_distances = 4 }; // must be 4
|
||||
|
||||
uint32_t crc_;
|
||||
|
||||
Bit_model bm_match[State::states][pos_states];
|
||||
Bit_model bm_rep[State::states];
|
||||
Bit_model bm_rep0[State::states];
|
||||
Bit_model bm_rep1[State::states];
|
||||
Bit_model bm_rep2[State::states];
|
||||
Bit_model bm_len[State::states][pos_states];
|
||||
Bit_model bm_dis_slot[max_dis_states][1<<dis_slot_bits];
|
||||
Bit_model bm_dis[modeled_distances-end_dis_model+1];
|
||||
Bit_model bm_align[dis_align_size];
|
||||
|
||||
Fmatchfinder & fmatchfinder;
|
||||
Range_encoder range_encoder;
|
||||
Len_encoder len_encoder;
|
||||
Len_encoder rep_match_len_encoder;
|
||||
Literal_encoder literal_encoder;
|
||||
|
||||
const int num_dis_slots;
|
||||
int match_distance;
|
||||
|
||||
uint32_t crc() const { return crc_ ^ 0xFFFFFFFFU; }
|
||||
|
||||
// move-to-front dis in/into reps
|
||||
void mtf_reps( const int dis, int reps[num_rep_distances] )
|
||||
{
|
||||
if( dis >= num_rep_distances )
|
||||
{
|
||||
for( int i = num_rep_distances - 1; i > 0; --i ) reps[i] = reps[i-1];
|
||||
reps[0] = dis - num_rep_distances;
|
||||
}
|
||||
else if( dis > 0 )
|
||||
{
|
||||
const int distance = reps[dis];
|
||||
for( int i = dis; i > 0; --i ) reps[i] = reps[i-1];
|
||||
reps[0] = distance;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_pair( const uint32_t dis, const int len, const int pos_state )
|
||||
{
|
||||
len_encoder.encode( range_encoder, len, pos_state );
|
||||
const int dis_slot = dis_slots[dis];
|
||||
range_encoder.encode_tree( bm_dis_slot[get_dis_state(len)], dis_slot, dis_slot_bits );
|
||||
|
||||
if( dis_slot >= start_dis_model )
|
||||
{
|
||||
const int direct_bits = ( dis_slot >> 1 ) - 1;
|
||||
const uint32_t base = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
|
||||
const uint32_t direct_dis = dis - base;
|
||||
|
||||
if( dis_slot < end_dis_model )
|
||||
range_encoder.encode_tree_reversed( bm_dis + base - dis_slot,
|
||||
direct_dis, direct_bits );
|
||||
else
|
||||
{
|
||||
range_encoder.encode( direct_dis >> dis_align_bits, direct_bits - dis_align_bits );
|
||||
range_encoder.encode_tree_reversed( bm_align, direct_dis, dis_align_bits );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int read_match_distances()
|
||||
{
|
||||
int len = fmatchfinder.longest_match_len( &match_distance );
|
||||
if( len == fmatchfinder.match_len_limit() )
|
||||
len += fmatchfinder.true_match_len( len, match_distance + 1, max_match_len - len );
|
||||
return len;
|
||||
}
|
||||
|
||||
void move_pos( int n, bool skip = false )
|
||||
{
|
||||
while( --n >= 0 )
|
||||
{
|
||||
if( skip ) skip = false;
|
||||
else fmatchfinder.longest_match_len();
|
||||
fmatchfinder.move_pos();
|
||||
}
|
||||
}
|
||||
|
||||
int sequence_optimizer( const int reps[num_rep_distances],
|
||||
int * const disp, const State & state );
|
||||
|
||||
void full_flush( const State & state );
|
||||
|
||||
public:
|
||||
FLZ_encoder( Fmatchfinder & mf, const File_header & header, const int outfd );
|
||||
|
||||
bool encode_member( const long long member_size );
|
||||
|
||||
long long member_position() const
|
||||
{ return range_encoder.member_position(); }
|
||||
};
|
|
@ -0,0 +1,264 @@
|
|||
#define max(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
#define min(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class State
|
||||
{
|
||||
unsigned char st;
|
||||
|
||||
public:
|
||||
enum { states = 12 };
|
||||
State() : st( 0 ) {}
|
||||
unsigned char operator()() const { return st; }
|
||||
bool is_char() const { return st < 7; }
|
||||
|
||||
void set_char()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_match()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_rep()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_short_rep()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11 };
|
||||
st = next[st];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
min_dictionary_bits = 12,
|
||||
min_dictionary_size = 1 << min_dictionary_bits,
|
||||
max_dictionary_bits = 29,
|
||||
max_dictionary_size = 1 << max_dictionary_bits,
|
||||
literal_context_bits = 3,
|
||||
pos_state_bits = 2,
|
||||
pos_states = 1 << pos_state_bits,
|
||||
pos_state_mask = pos_states - 1,
|
||||
|
||||
dis_slot_bits = 6,
|
||||
start_dis_model = 4,
|
||||
end_dis_model = 14,
|
||||
modeled_distances = 1 << (end_dis_model / 2),
|
||||
dis_align_bits = 4,
|
||||
dis_align_size = 1 << dis_align_bits,
|
||||
|
||||
len_low_bits = 3,
|
||||
len_mid_bits = 3,
|
||||
len_high_bits = 8,
|
||||
len_low_symbols = 1 << len_low_bits,
|
||||
len_mid_symbols = 1 << len_mid_bits,
|
||||
len_high_symbols = 1 << len_high_bits,
|
||||
max_len_symbols = len_low_symbols + len_mid_symbols + len_high_symbols,
|
||||
|
||||
min_match_len = 2, // must be 2
|
||||
max_match_len = min_match_len + max_len_symbols - 1, // 273
|
||||
min_match_len_limit = 5,
|
||||
|
||||
max_dis_states = 4 };
|
||||
|
||||
inline int get_dis_state( int len )
|
||||
{
|
||||
len -= min_match_len;
|
||||
if( len >= max_dis_states ) len = max_dis_states - 1;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
enum { bit_model_move_bits = 5,
|
||||
bit_model_total_bits = 11,
|
||||
bit_model_total = 1 << bit_model_total_bits };
|
||||
|
||||
struct Bit_model
|
||||
{
|
||||
unsigned int probability;
|
||||
Bit_model() : probability( bit_model_total / 2 ) {}
|
||||
};
|
||||
|
||||
|
||||
class CRC32
|
||||
{
|
||||
uint32_t data[256]; // Table of CRCs of all 8-bit messages.
|
||||
|
||||
public:
|
||||
CRC32()
|
||||
{
|
||||
for( unsigned int n = 0; n < 256; ++n )
|
||||
{
|
||||
unsigned int c = n;
|
||||
for( int k = 0; k < 8; ++k )
|
||||
{ if( c & 1 ) c = 0xEDB88320U ^ ( c >> 1 ); else c >>= 1; }
|
||||
data[n] = c;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t operator[]( const uint8_t byte ) const { return data[byte]; }
|
||||
void update( uint32_t & crc, const uint8_t byte ) const
|
||||
{ crc = data[(crc^byte)&0xFF] ^ ( crc >> 8 ); }
|
||||
void update( uint32_t & crc, const uint8_t * const buffer, const int size ) const
|
||||
{
|
||||
for( int i = 0; i < size; ++i )
|
||||
crc = data[(crc^buffer[i])&0xFF] ^ ( crc >> 8 );
|
||||
}
|
||||
};
|
||||
|
||||
extern const CRC32 crc32;
|
||||
|
||||
|
||||
inline int real_bits( const int value )
|
||||
{
|
||||
int bits = 0;
|
||||
for( int i = 1, mask = 1; mask > 0; ++i, mask <<= 1 )
|
||||
if( value & mask ) bits = i;
|
||||
return bits;
|
||||
}
|
||||
|
||||
const uint8_t magic_string[4] = { 'L', 'Z', 'I', 'P' };
|
||||
|
||||
struct File_header
|
||||
{
|
||||
uint8_t data[6]; // 0-3 magic bytes
|
||||
// 4 version
|
||||
// 5 coded_dict_size
|
||||
enum { size = 6 };
|
||||
|
||||
void set_magic()
|
||||
{ memcpy( data, magic_string, 4 ); data[4] = 1; }
|
||||
|
||||
bool verify_magic() const
|
||||
{ return ( memcmp( data, magic_string, 4 ) == 0 ); }
|
||||
|
||||
uint8_t version() const { return data[4]; }
|
||||
bool verify_version() const { return ( data[4] <= 1 ); }
|
||||
|
||||
int dictionary_size() const
|
||||
{
|
||||
int sz = ( 1 << ( data[5] & 0x1F ) );
|
||||
if( sz > min_dictionary_size && sz <= max_dictionary_size )
|
||||
sz -= ( sz / 16 ) * ( ( data[5] >> 5 ) & 0x07 );
|
||||
return sz;
|
||||
}
|
||||
|
||||
bool dictionary_size( const int sz )
|
||||
{
|
||||
if( sz >= min_dictionary_size && sz <= max_dictionary_size )
|
||||
{
|
||||
data[5] = real_bits( sz - 1 );
|
||||
if( sz > min_dictionary_size )
|
||||
{
|
||||
const int base_size = 1 << data[5];
|
||||
const int wedge = base_size / 16;
|
||||
for( int i = 7; i >= 1; --i )
|
||||
if( base_size - ( i * wedge ) >= sz )
|
||||
{ data[5] |= ( i << 5 ); break; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct File_trailer
|
||||
{
|
||||
uint8_t data[20]; // 0-3 CRC32 of the uncompressed data
|
||||
// 4-11 size of the uncompressed data
|
||||
// 12-19 member size including header and trailer
|
||||
|
||||
static int size( const int version = 1 )
|
||||
{ return ( ( version >= 1 ) ? 20 : 12 ); }
|
||||
|
||||
uint32_t data_crc() const
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
for( int i = 3; i >= 0; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void data_crc( uint32_t crc )
|
||||
{ for( int i = 0; i <= 3; ++i ) { data[i] = (uint8_t)crc; crc >>= 8; } }
|
||||
|
||||
long long data_size() const
|
||||
{
|
||||
long long tmp = 0;
|
||||
for( int i = 11; i >= 4; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void data_size( long long sz )
|
||||
{
|
||||
for( int i = 4; i <= 11; ++i ) { data[i] = (uint8_t)sz; sz >>= 8; }
|
||||
}
|
||||
|
||||
long long member_size() const
|
||||
{
|
||||
long long tmp = 0;
|
||||
for( int i = 19; i >= 12; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void member_size( long long sz )
|
||||
{
|
||||
for( int i = 12; i <= 19; ++i ) { data[i] = (uint8_t)sz; sz >>= 8; }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Error
|
||||
{
|
||||
const char * const msg;
|
||||
Error( const char * const s ) : msg( s ) {}
|
||||
};
|
||||
|
||||
|
||||
// defined in main.cc lziprecover.cc
|
||||
void show_error( const char * const msg, const int errcode = 0,
|
||||
const bool help = false );
|
||||
void internal_error( const char * const msg );
|
||||
|
||||
// defined in decoder.cc
|
||||
int readblock( const int fd, uint8_t * const buf, const int size );
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size );
|
||||
|
||||
// XXX
|
||||
extern void pp(const char *p=NULL);
|
||||
|
|
@ -0,0 +1,545 @@
|
|||
/* Lzip - Data compressor based on the LZMA algorithm
|
||||
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Return values: 0 for a normal exit, 1 for environmental problems
|
||||
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
|
||||
corrupt or invalid input file, 3 for an internal consistency error
|
||||
(eg, bug) which caused lzip to panic.
|
||||
*/
|
||||
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__MSVCRT__)
|
||||
#include <io.h>
|
||||
#define fchmod(x,y) 0
|
||||
#define fchown(x,y,z) 0
|
||||
#define SIGHUP SIGTERM
|
||||
#define S_ISSOCK(x) 0
|
||||
#define S_IRGRP 0
|
||||
#define S_IWGRP 0
|
||||
#define S_IROTH 0
|
||||
#define S_IWOTH 0
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "lzip.h"
|
||||
#include "decoder.h"
|
||||
|
||||
#if !DECODER_ONLY
|
||||
#include "encoder.h"
|
||||
#include "fast_encoder.h"
|
||||
#endif
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
#error "Environments where CHAR_BIT != 8 are not supported."
|
||||
#endif
|
||||
|
||||
#ifndef LLONG_MAX
|
||||
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
|
||||
#endif
|
||||
#ifndef LLONG_MIN
|
||||
#define LLONG_MIN (-LLONG_MAX - 1LL)
|
||||
#endif
|
||||
#ifndef ULLONG_MAX
|
||||
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
#endif
|
||||
|
||||
|
||||
void pp(const char *p) { if (p) fputs(p, stderr); }
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const Program_name = "Lzip";
|
||||
const char * const program_name = "lzip";
|
||||
const char * const program_year = "2011";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
#ifdef O_BINARY
|
||||
const int o_binary = O_BINARY;
|
||||
#else
|
||||
const int o_binary = 0;
|
||||
#endif
|
||||
|
||||
struct { const char * from; const char * to; } const known_extensions[] = {
|
||||
{ ".lz", "" },
|
||||
{ ".tlz", ".tar" },
|
||||
{ 0, 0 } };
|
||||
|
||||
struct Lzma_options
|
||||
{
|
||||
int dictionary_size; // 4KiB..512MiB
|
||||
int match_len_limit; // 5..273
|
||||
};
|
||||
|
||||
enum Mode { m_compress, m_decompress, m_test };
|
||||
|
||||
int outfd = -1;
|
||||
int verbosity = 0;
|
||||
bool delete_output_on_interrupt = false;
|
||||
|
||||
|
||||
void show_help()
|
||||
{
|
||||
printf( "%s - Data compressor based on the LZMA algorithm.\n", Program_name );
|
||||
printf( "<< Most of these are unsupported. Compressing/decompressing from stdin to stdout is the right way! >>\n" );
|
||||
printf( "\nUsage: %s [options] [files]\n", invocation_name );
|
||||
printf( "\nOptions:\n" );
|
||||
printf( " -h, --help display this help and exit\n" );
|
||||
printf( " -V, --version output version information and exit\n" );
|
||||
printf( " -b, --member-size=<n> set member size limit in bytes\n" );
|
||||
printf( " -c, --stdout send output to standard output\n" );
|
||||
printf( " -d, --decompress decompress\n" );
|
||||
printf( " -f, --force overwrite existing output files\n" );
|
||||
printf( " -F, --recompress force recompression of compressed files\n" );
|
||||
printf( " -k, --keep keep (don't delete) input files\n" );
|
||||
printf( " -m, --match-length=<n> set match length limit in bytes [36]\n" );
|
||||
printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" );
|
||||
printf( " -q, --quiet suppress all messages\n" );
|
||||
printf( " -s, --dictionary-size=<n> set dictionary size limit in bytes [8MiB]\n" );
|
||||
printf( " -S, --volume-size=<n> set volume size limit in bytes\n" );
|
||||
printf( " -t, --test test compressed file integrity\n" );
|
||||
printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" );
|
||||
printf( " -0 .. -9 set compression level [default 6]\n" );
|
||||
printf( " --fast alias for -0\n" );
|
||||
printf( " --best alias for -9\n" );
|
||||
printf( "If no file names are given, %s compresses or decompresses\n", program_name );
|
||||
printf( "from standard input to standard output.\n" );
|
||||
printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" );
|
||||
printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
|
||||
printf( "\nReport bugs to lzip-bug@nongnu.org\n" );
|
||||
printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
|
||||
}
|
||||
|
||||
|
||||
void show_version()
|
||||
{
|
||||
printf( "%s %s\n", Program_name, PROGVERSION );
|
||||
printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
|
||||
printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" );
|
||||
printf( "This is free software: you are free to change and redistribute it.\n" );
|
||||
printf( "There is NO WARRANTY, to the extent permitted by law.\n" );
|
||||
}
|
||||
|
||||
|
||||
const char * format_num( long long num )
|
||||
{
|
||||
const char * const prefix[8] =
|
||||
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
|
||||
enum { buf_size = 16, factor = 1024 };
|
||||
static char buf[buf_size];
|
||||
const char *p = "";
|
||||
|
||||
for( int i = 0; i < 8 && ( llabs( num ) > 9999 ||
|
||||
( llabs( num ) >= factor && num % factor == 0 ) ); ++i )
|
||||
{ num /= factor; p = prefix[i]; }
|
||||
snprintf( buf, buf_size, "%lld %s", num, p );
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
bool open_outstream( const bool force )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool check_tty( const int infd, const Mode program_mode )
|
||||
{
|
||||
if( program_mode == m_compress && outfd >= 0 && isatty( outfd ) )
|
||||
{
|
||||
show_error( "I won't write compressed data to a terminal.", 0, true );
|
||||
return false;
|
||||
}
|
||||
if( ( program_mode == m_decompress || program_mode == m_test ) &&
|
||||
isatty( infd ) )
|
||||
{
|
||||
show_error( "I won't read compressed data from a terminal.", 0, true );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void cleanup_and_fail( const int retval )
|
||||
{
|
||||
exit( retval );
|
||||
}
|
||||
|
||||
|
||||
// Set permissions, owner and times.
|
||||
void close_and_set_permissions( const struct stat * const in_statsp )
|
||||
{
|
||||
bool error = false;
|
||||
if( in_statsp )
|
||||
{
|
||||
if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 &&
|
||||
errno != EPERM ) ||
|
||||
fchmod( outfd, in_statsp->st_mode ) != 0 )
|
||||
error = true;
|
||||
// fchown will in many cases return with EPERM, which can be safely ignored.
|
||||
}
|
||||
if( close( outfd ) == 0 ) outfd = -1;
|
||||
else cleanup_and_fail( 1 );
|
||||
delete_output_on_interrupt = false;
|
||||
if( !in_statsp ) return;
|
||||
if( !error )
|
||||
{
|
||||
struct utimbuf t;
|
||||
t.actime = in_statsp->st_atime;
|
||||
t.modtime = in_statsp->st_mtime;
|
||||
//if( utime( output_filename.c_str(), &t ) != 0 ) error = true;
|
||||
}
|
||||
if( error )
|
||||
{
|
||||
show_error( "Can't change output file attributes." );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool next_filename()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !DECODER_ONLY
|
||||
int compress( const long long member_size, const long long volume_size,
|
||||
const Lzma_options & encoder_options, const int infd,
|
||||
const struct stat * const in_statsp )
|
||||
{
|
||||
File_header header;
|
||||
header.set_magic();
|
||||
if( !header.dictionary_size( encoder_options.dictionary_size ) ||
|
||||
encoder_options.match_len_limit < min_match_len_limit ||
|
||||
encoder_options.match_len_limit > max_match_len )
|
||||
internal_error( "invalid argument to encoder" );
|
||||
int retval = 0;
|
||||
|
||||
Matchfinder matchfinder( header.dictionary_size(),
|
||||
encoder_options.match_len_limit, infd );
|
||||
header.dictionary_size( matchfinder.dictionary_size() );
|
||||
|
||||
long long in_size = 0, out_size = 0, partial_volume_size = 0;
|
||||
while( true ) // encode one member per iteration
|
||||
{
|
||||
LZ_encoder encoder( matchfinder, header, outfd );
|
||||
const long long size =
|
||||
min( member_size, volume_size - partial_volume_size );
|
||||
if( !encoder.encode_member( size ) )
|
||||
{ pp( "Encoder error" ); retval = 1; break; }
|
||||
in_size += matchfinder.data_position();
|
||||
out_size += encoder.member_position();
|
||||
if( matchfinder.finished() ) break;
|
||||
partial_volume_size += encoder.member_position();
|
||||
if( partial_volume_size >= volume_size - min_dictionary_size )
|
||||
{
|
||||
partial_volume_size = 0;
|
||||
if( delete_output_on_interrupt )
|
||||
{
|
||||
close_and_set_permissions( in_statsp );
|
||||
if( !next_filename() )
|
||||
{ pp( "Too many volume files" ); retval = 1; break; }
|
||||
if( !open_outstream( true ) ) { retval = 1; break; }
|
||||
delete_output_on_interrupt = true;
|
||||
}
|
||||
}
|
||||
matchfinder.reset();
|
||||
}
|
||||
|
||||
if( retval == 0 && verbosity >= 1 )
|
||||
{
|
||||
if( in_size <= 0 || out_size <= 0 )
|
||||
fprintf( stderr, "No data compressed.\n" );
|
||||
else
|
||||
fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
|
||||
"%5.2f%% saved, %lld in, %lld out.\n",
|
||||
(double)in_size / out_size,
|
||||
( 8.0 * out_size ) / in_size,
|
||||
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
|
||||
in_size, out_size );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int fcompress( const long long member_size, const long long volume_size,
|
||||
const int infd,
|
||||
const struct stat * const in_statsp )
|
||||
{
|
||||
if( verbosity >= 1 ) pp();
|
||||
File_header header;
|
||||
header.set_magic();
|
||||
int retval = 0;
|
||||
|
||||
Fmatchfinder fmatchfinder( infd );
|
||||
header.dictionary_size( fmatchfinder.dictionary_size() );
|
||||
|
||||
long long in_size = 0, out_size = 0, partial_volume_size = 0;
|
||||
while( true ) // encode one member per iteration
|
||||
{
|
||||
FLZ_encoder encoder( fmatchfinder, header, outfd );
|
||||
const long long size =
|
||||
min( member_size, volume_size - partial_volume_size );
|
||||
if( !encoder.encode_member( size ) )
|
||||
{ pp( "Encoder error" ); retval = 1; break; }
|
||||
in_size += fmatchfinder.data_position();
|
||||
out_size += encoder.member_position();
|
||||
if( fmatchfinder.finished() ) break;
|
||||
partial_volume_size += encoder.member_position();
|
||||
if( partial_volume_size >= volume_size - min_dictionary_size )
|
||||
{
|
||||
partial_volume_size = 0;
|
||||
if( delete_output_on_interrupt )
|
||||
{
|
||||
close_and_set_permissions( in_statsp );
|
||||
if( !next_filename() )
|
||||
{ pp( "Too many volume files" ); retval = 1; break; }
|
||||
if( !open_outstream( true ) ) { retval = 1; break; }
|
||||
delete_output_on_interrupt = true;
|
||||
}
|
||||
}
|
||||
fmatchfinder.reset();
|
||||
}
|
||||
|
||||
if( retval == 0 && verbosity >= 1 )
|
||||
{
|
||||
if( in_size <= 0 || out_size <= 0 )
|
||||
fprintf( stderr, "No data compressed.\n" );
|
||||
else
|
||||
fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
|
||||
"%5.2f%% saved, %lld in, %lld out.\n",
|
||||
(double)in_size / out_size,
|
||||
( 8.0 * out_size ) / in_size,
|
||||
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
|
||||
in_size, out_size );
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
int decompress( const int infd, const bool testing )
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
Range_decoder rdec( infd );
|
||||
long long partial_file_pos = 0;
|
||||
for( bool first_member = true; ; first_member = false )
|
||||
{
|
||||
File_header header;
|
||||
int size;
|
||||
rdec.reset_member_position();
|
||||
for( size = 0; size < File_header::size && !rdec.finished(); ++size )
|
||||
header.data[size] = rdec.get_byte();
|
||||
if( rdec.finished() ) // End Of File
|
||||
{
|
||||
if( first_member )
|
||||
{ pp( "Error reading member header" ); retval = 1; }
|
||||
break;
|
||||
}
|
||||
if( !header.verify_magic() )
|
||||
{
|
||||
if( first_member )
|
||||
{ pp( "Bad magic number (file not in lzip format)" ); retval = 2; }
|
||||
break;
|
||||
}
|
||||
if( !header.verify_version() )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{ pp();
|
||||
fprintf( stderr, "Version %d member format not supported.\n",
|
||||
header.version() ); }
|
||||
retval = 2; break;
|
||||
}
|
||||
if( header.dictionary_size() < min_dictionary_size ||
|
||||
header.dictionary_size() > max_dictionary_size )
|
||||
{ pp( "Invalid dictionary size in member header" ); retval = 2; break; }
|
||||
|
||||
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
|
||||
{
|
||||
pp();
|
||||
if( verbosity >= 2 )
|
||||
fprintf( stderr, "version %d, dictionary size %7sB. ",
|
||||
header.version(),
|
||||
format_num( header.dictionary_size() ) );
|
||||
}
|
||||
LZ_decoder decoder( header, rdec, outfd );
|
||||
|
||||
const int result = decoder.decode_member();
|
||||
partial_file_pos += rdec.member_position();
|
||||
if( result != 0 )
|
||||
{
|
||||
if( verbosity >= 0 && result <= 2 )
|
||||
{
|
||||
pp();
|
||||
if( result == 2 )
|
||||
fprintf( stderr, "File ends unexpectedly at pos %lld\n",
|
||||
partial_file_pos );
|
||||
else
|
||||
fprintf( stderr, "Decoder error at pos %lld\n",
|
||||
partial_file_pos );
|
||||
}
|
||||
retval = 2; break;
|
||||
}
|
||||
if( verbosity >= 2 )
|
||||
{ if( testing ) fprintf( stderr, "ok\n" );
|
||||
else fprintf( stderr, "done\n" ); }
|
||||
}
|
||||
if( verbosity == 1 && retval == 0 )
|
||||
{ if( testing ) fprintf( stderr, "ok\n" );
|
||||
else fprintf( stderr, "done\n" ); }
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
void show_error( const char * const msg, const int errcode, const bool help )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{
|
||||
if( msg && msg[0] )
|
||||
{
|
||||
fprintf( stderr, "%s: %s", program_name, msg );
|
||||
if( errcode > 0 )
|
||||
fprintf( stderr, ": %s", strerror( errcode ) );
|
||||
fprintf( stderr, "\n" );
|
||||
}
|
||||
if( help && invocation_name && invocation_name[0] )
|
||||
fprintf( stderr, "Try `%s --help' for more information.\n",
|
||||
invocation_name );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void internal_error( const char * const msg )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
|
||||
exit( 3 );
|
||||
}
|
||||
|
||||
|
||||
int main( const int argc, const char * const argv[] )
|
||||
{
|
||||
// Mapping from gzip/bzip2 style 1..9 compression modes
|
||||
// to the corresponding LZMA compression modes.
|
||||
const Lzma_options option_mapping[] =
|
||||
{
|
||||
{ 1 << 16, 16 }, // -0 entry values not used
|
||||
{ 1 << 20, 5 }, // -1
|
||||
{ 3 << 19, 6 }, // -2
|
||||
{ 1 << 21, 8 }, // -3
|
||||
{ 3 << 20, 12 }, // -4
|
||||
{ 1 << 22, 20 }, // -5
|
||||
{ 1 << 23, 36 }, // -6
|
||||
{ 1 << 24, 68 }, // -7
|
||||
{ 3 << 23, 132 }, // -8
|
||||
{ 1 << 25, 273 } }; // -9
|
||||
Lzma_options encoder_options = option_mapping[6]; // default = "-6"
|
||||
long long member_size = LLONG_MAX;
|
||||
long long volume_size = LLONG_MAX;
|
||||
int infd = -1;
|
||||
Mode program_mode = m_compress;
|
||||
bool keep_input_files = false;
|
||||
bool to_stdout = false;
|
||||
bool zero = false;
|
||||
invocation_name = argv[0];
|
||||
|
||||
// Greatly simplified argument parsing
|
||||
int argind = 1;
|
||||
for( ; argind < argc; ++argind )
|
||||
{
|
||||
const int code = argv[argind][1];
|
||||
switch( code )
|
||||
{
|
||||
case 'c': to_stdout = true; break;
|
||||
case 'd': program_mode = m_decompress; break;
|
||||
case 'h': show_help(); return 0;
|
||||
case 'k': keep_input_files = true; break;
|
||||
case 'q': verbosity = -1; break;
|
||||
zero = false; break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
case 'V': show_version(); return 0;
|
||||
default : internal_error( "uncaught option" );
|
||||
}
|
||||
} // end process options
|
||||
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
_setmode( STDIN_FILENO, O_BINARY );
|
||||
_setmode( STDOUT_FILENO, O_BINARY );
|
||||
#endif
|
||||
|
||||
if( program_mode == m_test )
|
||||
outfd = -1;
|
||||
#if !DECODER_ONLY
|
||||
else if( program_mode == m_compress )
|
||||
{
|
||||
dis_slots.init();
|
||||
prob_prices.init();
|
||||
}
|
||||
#endif
|
||||
|
||||
int retval = 0;
|
||||
{
|
||||
struct stat in_stats;
|
||||
|
||||
infd = STDIN_FILENO;
|
||||
outfd = STDOUT_FILENO;
|
||||
|
||||
if( !check_tty( infd, program_mode ) ) return 1;
|
||||
|
||||
const struct stat * const in_statsp = 0;
|
||||
//pp.set_name( "-" );
|
||||
int tmp = 0;
|
||||
#if !DECODER_ONLY
|
||||
if( program_mode == m_compress )
|
||||
{
|
||||
if( zero )
|
||||
tmp = fcompress( member_size, volume_size, infd, in_statsp );
|
||||
else
|
||||
tmp = compress( member_size, volume_size, encoder_options, infd,
|
||||
in_statsp );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
tmp = decompress( infd, program_mode == m_test );
|
||||
if( tmp > retval ) retval = tmp;
|
||||
//if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
|
||||
|
||||
if( delete_output_on_interrupt )
|
||||
close_and_set_permissions( in_statsp );
|
||||
}
|
||||
if( outfd >= 0 && close( outfd ) != 0 )
|
||||
{
|
||||
show_error( "Can't close stdout", errno );
|
||||
if( retval < 1 ) retval = 1;
|
||||
}
|
||||
return retval;
|
||||
}
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,5 @@
|
|||
./lzma-native < lzma-native > lzma-native.lz
|
||||
./lzma-native -d < lzma-native.lz > lzma-native.post
|
||||
ls -al lzma-native*
|
||||
diff lzma-native lzma-native.post
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
return returnValue;
|
||||
},
|
||||
|
||||
compress: function(data) {
|
||||
return this.run(data);
|
||||
},
|
||||
|
||||
decompress: function(data) {
|
||||
return this.run(data, true);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
// This is lzma.js, powered by lzip (which is GPL, source code at https://github.com/kripken/lzma.js)
|
||||
var LZMA = {
|
||||
run: function(data, decompress) {
|
||||
var inputIndex = 0;
|
||||
var returnValue = [];
|
||||
var Module = {
|
||||
arguments: ['-q'].concat(decompress ? ['-d'] : []),
|
||||
stdin: function() { return inputIndex < data.length ? data[inputIndex++] : null },
|
||||
stdout: function(x) { if (x !== null) returnValue.push(x) }
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// js -m -n -e "load('lzma-decoder.js')" test-decoder.js
|
||||
|
||||
function assertEq(a, b) {
|
||||
if (a !== b) {
|
||||
throw 'Should have been equal: ' + a + ' : ' + b;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function assertNeq(a, b) {
|
||||
try {
|
||||
assertEq(a, b);
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
throw 'Should have not been equal: ' + a + ' : ' + b;
|
||||
}
|
||||
|
||||
function byteCompare(a, b) {
|
||||
assertEq(JSON.stringify(new Uint8Array(a)), JSON.stringify(new Uint8Array(b)));
|
||||
}
|
||||
|
||||
function testSimple() {
|
||||
print('testing simple..');
|
||||
var data = [100, 200, 200, 200, 200, 200, 200, 100, 100, 200, 200, 200, 200, 0, 1];
|
||||
var compressed = [76,90,73,80,1,12,0,50,50,28,-1,-1,-1,-1,-16,0,0,0,-34,-10,-9,-43,2,0,0,0,0,0,0,0,38,0,0,0,0,0,
|
||||
0,0,76,90,73,80,1,12,0,100,105,61,-1,-1,-1,-1,-32,0,0,0,-46,66,-98,-91,5,0,0,0,0,0,0,0,38,
|
||||
0,0,0,0,0,0,0,76,90,73,80,1,12,0,50,100,27,-1,-1,-1,-2,0,0,0,29,25,-105,10,2,0,0,0,0,0,0,0,
|
||||
37,0,0,0,0,0,0,0,76,90,73,80,1,12,0,100,104,-67,-1,-1,-1,-1,-32,0,0,0,-55,-55,-99,-101,4,0,0,0,
|
||||
0,0,0,0,38,0,0,0,0,0,0,0,76,90,73,80,1,12,0,0,0,121,-128,-83,-1,-1,-20,-57,0,0,105,34,-34,54,2,
|
||||
0,0,0,0,0,0,0,38,0,0,0,0,0,0,0];
|
||||
var decompressed = LZMA.decompress(compressed);
|
||||
byteCompare(data, decompressed);
|
||||
}
|
||||
|
||||
testSimple();
|
||||
|
||||
print('ok.');
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<body>
|
||||
<script>
|
||||
var print = function(x) { console.log(x) };
|
||||
</script>
|
||||
<script src="lzma-full.js"></script>
|
||||
<script src="test-full.js"></script>
|
||||
See web console..
|
||||
</body>
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// js -m -n -e "load('lzma-full.js')" test-full.js
|
||||
|
||||
function assertEq(a, b) {
|
||||
if (a !== b) {
|
||||
throw 'Should have been equal: ' + a + ' : ' + b;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function assertNeq(a, b) {
|
||||
try {
|
||||
assertEq(a, b);
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
throw 'Should have not been equal: ' + a + ' : ' + b;
|
||||
}
|
||||
|
||||
function byteCompare(a, b) {
|
||||
assertEq(a.length, b.length);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
assertEq(a[i]&255, b[i]&255);
|
||||
}
|
||||
}
|
||||
|
||||
function testSimple() {
|
||||
print('testing simple..');
|
||||
var data = [100, 200, 200, 200, 200, 200, 200, 100, 100, 200, 200, 200, 200, 0, 1];
|
||||
var compressed = LZMA.compress(data);
|
||||
var decompressed = LZMA.decompress(compressed);
|
||||
|
||||
byteCompare(data, decompressed);
|
||||
assertNeq(data.length, compressed.length);
|
||||
}
|
||||
|
||||
function testBig() {
|
||||
print('testing big..');
|
||||
var seed1 = 100;
|
||||
var seed2 = 200;
|
||||
var last = 255;
|
||||
function fakeRandom() {
|
||||
// numbers from http://triptico.com/docs/sp_random.html
|
||||
seed1 = ((seed1 * 58321) + 11113) | 0;
|
||||
var ret = (seed1 >> 16) & 255;
|
||||
seed2 = ((seed2 * 58321) + 11113) | 0;
|
||||
if (seed2 % 5) {
|
||||
return last;
|
||||
}
|
||||
last = ret;
|
||||
return last;
|
||||
}
|
||||
print(' ..generating data..');
|
||||
var size = 1*1024*1024;
|
||||
var data = new Array(size);
|
||||
for (var i = 0; i < size; i++) {
|
||||
data[i] = fakeRandom();
|
||||
}
|
||||
|
||||
print(' ..compressing ' + data.length + ' bytes..');
|
||||
var t = Date.now();
|
||||
var compressed = LZMA.compress(data);
|
||||
print(' ..took ' + ((Date.now() - t)/1000).toFixed(2) + ' secs');
|
||||
print(' ..decompressing ' + compressed.length + ' bytes..');
|
||||
t = Date.now();
|
||||
var decompressed = LZMA.decompress(compressed);
|
||||
print(' ..took ' + ((Date.now() - t)/1000).toFixed(2) + ' secs');
|
||||
print(' ..got ' + decompressed.length + ' bytes..');
|
||||
|
||||
byteCompare(data, decompressed);
|
||||
assertNeq(data.length, compressed.length);
|
||||
print(' ..decompressed == original');
|
||||
}
|
||||
|
||||
testSimple();
|
||||
testBig();
|
||||
|
||||
print('ok.');
|
||||
|
Загрузка…
Ссылка в новой задаче