185 Commits

Author SHA1 Message Date
Lasse Collin
cb072b7c84 Check for LZMA_FILTER_RESERVED_START in filter_flags_encoder.c.
Use LZMA_PROG_ERROR instead of LZMA_HEADER_ERROR if the Filter ID
is in the reserved range. This allows Block Header encoder to
detect unallowed Filter IDs, which is good for Stream encoder.
2008-09-10 17:02:00 +03:00
Lasse Collin
123ab0acec Filter handling cleanups 2008-09-10 16:44:32 +03:00
Lasse Collin
9cfcd0c4f2 Comments 2008-09-10 00:33:00 +03:00
Lasse Collin
2ba01bfa75 Cleaned up Block encoder and moved the no longer shared
code from block_private.h to block_decoder.c. Now the Block
encoder doesn't need compressed_size and uncompressed_size
from lzma_block structure to be initialized.
2008-09-10 00:27:02 +03:00
Lasse Collin
07efcb5a6b Changed Filter ID of LZMA to 0x20. 2008-09-07 10:23:13 +03:00
Lasse Collin
32fe5fa541 Comments 2008-09-06 23:42:50 +03:00
Lasse Collin
0a31ed9d5e Some API cleanups 2008-09-06 15:14:30 +03:00
Lasse Collin
da98df5440 Added support for raw encoding and decoding to the command
line tool, and made various cleanups. --lzma was renamed to
--lzma1 to prevent people from accidentally using LZMA when
they want LZMA2.
2008-09-04 11:53:06 +03:00
Lasse Collin
2496aee8a7 Don't allow LZMA_SYNC_FLUSH with decoders anymore. There's
simply nothing that would use it. Allow LZMA_FINISH to the
decoders, which will usually ignore it (auto decoder and
Stream decoder being exceptions).
2008-09-04 10:39:15 +03:00
Lasse Collin
bea301c26d Minor updates to the file format specification. 2008-09-03 17:06:25 +03:00
Lasse Collin
9c75b089b4 Command line tool fixes 2008-09-02 19:33:32 +03:00
Lasse Collin
bab0590504 Auto decoder cleanup 2008-09-02 19:31:42 +03:00
Lasse Collin
689602336d Updated auto decoder to handle LZMA_CONCATENATED when decoding
LZMA_Alone files. Decoding of concatenated LZMA_Alone files is
intentionally not supported, so it is better to put this in
auto decoder than LZMA_Alone decoder.
2008-09-02 19:12:12 +03:00
Lasse Collin
80c4158f19 Stream decoder cleanups 2008-09-02 14:56:52 +03:00
Lasse Collin
fc68165745 Some fixes to LZ encoder. 2008-09-02 11:45:39 +03:00
Lasse Collin
ede675f9ac Fix wrong pointer calculation in LZMA encoder. 2008-08-31 11:47:01 +03:00
Lasse Collin
3b34851de1 Sort of garbage collection commit. :-| Many things are still
broken. API has changed a lot and it will still change a
little more here and there. The command line tool doesn't
have all the required changes to reflect the API changes, so
it's easy to get "internal error" or trigger assertions.
2008-08-28 22:53:15 +03:00
Lasse Collin
57b9a145a5 Fix test_filter_flags to match the new restriction of lc+lp. 2008-06-20 17:16:32 +03:00
Lasse Collin
eaafc4367c Remove some redundant code from LZMA encoder. 2008-06-20 16:19:54 +03:00
Lasse Collin
0809c46534 Add limit of lc + lp <= 4. Now we can allocate the
literal coder as part of the main LZMA encoder or
decoder structure.

Make the LZMA decoder to rely on the current internal API
to free the allocated memory in case an error occurs.
2008-06-19 16:35:08 +03:00
Lasse Collin
d25ab1b961 Comments 2008-06-18 21:45:19 +03:00
Lasse Collin
6368a2fa59 Delete old code that was supposed to be already deleted
from test_block_header.c.
2008-06-18 19:19:02 +03:00
Lasse Collin
7d17818cec Update the code to mostly match the new simpler file format
specification. Simplify things by removing most of the
support for known uncompressed size in most places.
There are some miscellaneous changes here and there too.

The API of liblzma has got many changes and still some
more will be done soon. While most of the code has been
updated, some things are not fixed (the command line tool
will choke with invalid filter chain, if nothing else).

Subblock filter is somewhat broken for now. It will be
updated once the encoded format of the Subblock filter
has been decided.
2008-06-18 18:02:10 +03:00
Lasse Collin
bf6348d1a3 Update the file format specification draft. The new one is
a lot simpler than the previous versions, but it also means
that the existing code will change a lot.
2008-06-17 15:03:46 +03:00
Lasse Collin
803194ddd2 Fix uninitialized variable in LZMA encoder. This was
introduced in 369f72fd65.
2008-06-11 21:42:47 +03:00
Lasse Collin
0ea98e52ba Improve command line integer parsing a little in lzma and
lzmadec to make them accept also KiB in addition Ki etc.
Fix also memory usage information in lzmadec --help.
2008-06-11 15:08:44 +03:00
Lasse Collin
436fa5fae9 s/decompressed/compressed/ in the command line tool's
error message.
2008-06-10 20:36:12 +03:00
Lasse Collin
369f72fd65 Fix a buffer overflow in the LZMA encoder. It was due to my
misunderstanding of the code. There's no tiny fix for this
problem, so I also cleaned up the code in general.

This reduces the speed of the encoder 2-5 % in the fastest
compression mode ("lzma -1"). High compression modes should
have no noticeable performance difference.

This commit breaks things (especially LZMA_SYNC_FLUSH) but I
will fix them once the new format and LZMA2 has been roughly
implemented. Plain LZMA won't support LZMA_SYNC_FLUSH at all
and won't be supported in the new .lzma format. This may
change still but this is what it looks like now.

Support for known uncompressed size (that is, LZMA or LZMA2
without EOPM) is likely to go away. This means there will
be API changes.
2008-06-01 12:48:17 +03:00
Lasse Collin
e55e0e873c Typo fixes from meyering. 2008-05-30 11:53:41 +03:00
Lasse Collin
ed6664146f Remove support for pre-C89 libc versions that lack memcpy,
memmove, and memset.
2008-05-11 14:24:42 +03:00
Lasse Collin
b09464bf9a Improved C99 compiler detection in configure.ac. It will
pass -std=gnu99 instead of -std=c99 to GCC now, but -pedantic
should still give warnings about GNU extensions like before
except with some special keywords like asm().
2008-05-11 14:17:21 +03:00
Lasse Collin
11de5d5267 Bunch of grammar fixes from meyering. 2008-05-06 15:15:07 +03:00
Lasse Collin
dc192b6343 Typo fix 2008-05-06 13:41:05 +03:00
Lasse Collin
944b62b932 Don't print an error message on broken pipe unless --verbose
is used.
2008-05-04 22:29:27 +03:00
Lasse Collin
8e074349e4 Fix a crash with --format=alone if other filters than LZMA
are specified on the command line.
2008-04-30 22:16:17 +03:00
Lasse Collin
2f361ac19b Updated THANKS. 2008-04-28 17:08:27 +03:00
Lasse Collin
3be21fb12f Fixed wrong spelling "limitter" to "limiter". This affects
liblzma's API.
2008-04-28 17:06:34 +03:00
Lasse Collin
beeb810608 Prevent LZ encoder from hanging with known uncompressed
size. The "fix" breaks LZMA_SYNC_FLUSH at end of stream
with known uncompressed size, but since it currently seems
likely that support for encoding with known uncompressed
size will go away anyway, I'm not fixing this problem now.
2008-04-25 15:39:50 +03:00
Lasse Collin
c324325f9f Removed src/liblzma/common/sysdefs.h symlink, which was
annoying, because "make dist" put two copies of sysdefs.h
into the tarball instead of the symlink.
2008-04-25 13:58:56 +03:00
Lasse Collin
d3ba30243c Added memusage.c to debug directory. 2008-04-25 13:41:29 +03:00
Lasse Collin
8f804c29aa Bumped version number to 4.999.3alpha. It will become 5.0.0
once we have a stable release (won't be very soon). The
version number is no longer related to version of LZMA SDK.

Made some small Automake-related changes to toplevel
Makefile.am and configure.ac.
2008-04-25 13:32:35 +03:00
Lasse Collin
c99037ea10 Fix a memory leak by calling free(extra->data) in
lzma_extra_free().
2008-04-24 20:25:39 +03:00
Lasse Collin
22ba3b0b50 Make unlzma and lzcat symlinks. 2008-04-24 20:23:05 +03:00
Lasse Collin
17c36422d4 Fixed a bug in command line option parsing. 2008-04-24 20:20:27 +03:00
Lasse Collin
283f939974 Added two assert()s. 2008-04-24 20:19:20 +03:00
Lasse Collin
eb348a60b6 Switch to uint16_t as the type of range coder probabilities. 2008-04-24 19:22:53 +03:00
Lasse Collin
6c5306e312 Fix wrong return type (uint32_t -> bool). 2008-04-24 18:39:57 +03:00
Lasse Collin
712cfe3ebf Fix data corruption in LZ encoder with LZMA_SYNC_FLUSH. 2008-04-24 18:38:00 +03:00
Lasse Collin
bc04486e36 Fix fastpos problem in Makefile.am when built with --enable-small. 2008-04-24 17:33:01 +03:00
Lasse Collin
7ab493924e Use 64-bit integer as range encoder's cache size. This fixes a
theoretical data corruption, which should be very hard to trigger
even intentionally.
2008-04-24 17:30:51 +03:00
Lasse Collin
641998c3e1 Replaced the range decoder optimization that used arithmetic
right shift with as fast version that doesn't need
arithmetic right shift. Removed the related check from
configure.ac.
2008-03-24 16:38:40 +02:00
Lasse Collin
ad999efd27 Take advantage of arithmetic right shift in range decoder. 2008-03-22 14:39:34 +02:00
Lasse Collin
03e0e8a0d7 Added autoconf check to detect if we can use arithmetic
right shift for optimizations.
2008-03-22 14:18:29 +02:00
Lasse Collin
7521bbdc83 Update a comment to use the variable name rep_len_decoder.
(And BTW, the previous commit actually did change the
program logic slightly.)
2008-03-22 01:26:36 +02:00
Lasse Collin
63b74d000e Demystified the "state" variable in LZMA code. Use the
word literal instead of char for better consistency.
There are still some names with _char instead of _literal
in lzma_optimum, these may be changed later.

Renamed length coder variables.

This commit doesn't change the program logic.
2008-03-22 00:57:33 +02:00
Lasse Collin
e6eb0a2675 Fix data corruption in LZMA encoder. Note that this bug was
specific to liblzma and was *not* present in LZMA SDK.
2008-03-14 23:16:11 +02:00
Lasse Collin
7d516f5129 Fix a comment API header. 2008-03-14 21:32:37 +02:00
Lasse Collin
748d6e4274 Make lzma_stream.next_in const. Let's see if anyone complains. 2008-03-12 23:14:50 +02:00
Lasse Collin
bfde3b24a5 Apply a minor speed optimization to LZMA decoder. 2008-03-11 15:35:34 +02:00
Lasse Collin
f310c50286 Initialize the last byte of the dictionary to zero so that
lz_get_byte(lz, 0) returns zero. This was broken by
1a3b218598.
2008-03-11 15:17:16 +02:00
Lasse Collin
5ead36cf7f Really fix the price count initialization. 2008-03-10 15:57:55 +02:00
Lasse Collin
d4d7feb83d Updated THANKS. 2008-03-10 13:47:17 +02:00
Lasse Collin
0541c5ea63 Initialize align_price_count and match_price_count in
lzma_encoder_init.c. While we don't call
fill_distances_prices() and fill_align_prices() in
lzma_lzma_encoder_init(), we still need to initialize
these two variables so that the fill functions get
called in lzma_encoder_getoptimum.c in the beginning
of a stream.
2008-03-10 13:46:48 +02:00
Lasse Collin
596fa1fac7 Always initialize lz->temp_size in lz_decoder.c. temp_size did
get initialized as a side-effect after allocating a new decoder,
but not when the decoder was reused.
2008-03-10 13:44:29 +02:00
Lasse Collin
45e43e1695 Don't fill allocated memory with 0xFD when debugging is
enabled. It hides errors from Valgrind.
2008-03-10 13:41:25 +02:00
Lasse Collin
c0e19e0662 Remove two redundant validity checks from the LZMA decoder.
These are already checked elsewhere, so omitting these
gives (very) tiny speed up.
2008-02-28 10:24:31 +02:00
Lasse Collin
de74858062 Tiny clean up to file-format.txt. 2008-02-06 13:25:32 +02:00
Lasse Collin
1a3b218598 Don't memzero() the history buffer when initializing LZ
decoder. There's no danger of information leak here, so
it isn't required. Doing memzero() takes a lot of time
with large dictionaries, which could make it easier to
construct DoS attack to consume too much CPU time.
2008-02-02 14:51:06 +02:00
Lasse Collin
7e796e312b Do uncompressed size validation in raw encoder. This way
it gets done for not only raw encoder, but also Block
and LZMA_Alone encoders.
2008-02-01 08:39:26 +02:00
Lasse Collin
7dd48578a3 Avoid unneeded function call in raw_common.c. 2008-02-01 08:32:05 +02:00
Lasse Collin
b596fac963 Updated THANKS. 2008-01-26 21:42:38 +02:00
Lasse Collin
e9f6e9c075 Added note.GNU-stack to x86 assembler files. It is needed
when using non-executable stack.
2008-01-26 21:40:23 +02:00
Lasse Collin
4c7ad179c7 Added api/lzma/easy.h. I had forgot to add this to the
git repo. Thanks to Stephan Kulow.
2008-01-26 19:12:50 +02:00
Lasse Collin
288b232f54 Added more test files. 2008-01-26 11:09:17 +02:00
Lasse Collin
c467b0defc Added more test files. 2008-01-26 10:47:55 +02:00
Lasse Collin
f9842f7127 Return LZMA_HEADER_ERROR if LZMA_SYNC_FLUSH is used with any
of the so called simple filters. If there is demand, limited
support for LZMA_SYNC_FLUSH may be added in future.

After this commit, using LZMA_SYNC_FLUSH shouldn't cause
undefined behavior in any situation.
2008-01-26 00:25:34 +02:00
Lasse Collin
e988ea1d1a Added more Multi-Block test files. Improved some
descriptions in the test files' README.
2008-01-25 23:50:35 +02:00
Lasse Collin
4441e00418 Combine lzma_options_block validation needed by both Block
encoder and decoder, and put the shared things to
block_private.h. Improved the checks a little so that
they may detect too big Compressed Size at initialization
time if lzma_options_block.total_size or .total_limit is
known.

Allow encoding and decoding Blocks with combinations of
fields that are not allowed by the file format specification.
Doing this requires that the application passes such a
combination in lzma_options_lzma; liblzma doesn't do that,
but it's not impossible that someone could find them useful
in some custom file format.
2008-01-25 23:12:36 +02:00
Lasse Collin
bf4200c818 Added test_memlimit.c. 2008-01-25 19:21:22 +02:00
Lasse Collin
7b8fc7e6b5 Improved the memory limitter:
- Added lzma_memlimit_max() and lzma_memlimit_reached()
    API functions.
  - Added simple estimation of malloc()'s memory usage
    overhead.
  - Fixed integer overflow detection in lzma_memlimit_alloc().
  - Made some white space cleanups and added more comments.

The description of lzma_memlimit_max() in memlimit.h is bad
and should be improved.
2008-01-25 19:20:28 +02:00
Lasse Collin
e0c3d0043d Use more parenthesis in succeed() macro in tests/tests.h. 2008-01-25 13:55:52 +02:00
Lasse Collin
1fd76d4881 Added more Multi-Block Stream test files. 2008-01-24 14:49:34 +02:00
Lasse Collin
6e27b1098a Added bunch of test files containing Multi-Block Streams. 2008-01-24 00:46:05 +02:00
Lasse Collin
db9df0a960 Fix decoding of empty Metadata Blocks, that don't have
even the Metadata Flags field. Earlier the code allowed
such files; now they are prohibited as the file format
specification requires.
2008-01-23 23:43:00 +02:00
Lasse Collin
765f0b05f6 Fix a bug related to 99e12af4e2.
lzma_metadata.header_metadata_size was not properly set to
zero if the Metadata had only the Metadata Flags field.
2008-01-23 23:38:18 +02:00
Lasse Collin
3a7cc5c3de Fix decoding of Extra Records that have empty Data. 2008-01-23 23:35:49 +02:00
Lasse Collin
e5fdec93e2 Add the trailing '\0' to lzma_extra.data as the API header
already documents.
2008-01-23 22:02:38 +02:00
Lasse Collin
ed40dc5a2c Added debug/full_flush.c. 2008-01-23 21:21:21 +02:00
Lasse Collin
ae0cd09a66 Return LZMA_STREAM_END instead of LZMA_OK if
LZMA_SYNC_FLUSH or LZMA_FULL_FLUSH is used when
there's no unfinished Block open.
2008-01-23 21:05:33 +02:00
Lasse Collin
0e80ded13d Added bad-single-none-footer_filter_flags.lzma and
bad-single-none-too_long_vli.lzma.
2008-01-23 20:05:01 +02:00
Lasse Collin
8c8eb14055 Fixed a typo. 2008-01-23 13:42:35 +02:00
Lasse Collin
980f65a9a1 Fix a memory leak in the Subblock encoder. 2008-01-23 13:40:45 +02:00
Lasse Collin
99e12af4e2 Fix Size of Header Metadata Block handling. Now
lzma_metadata.header_metadata_size == LZMA_VLI_VALUE_UNKNOWN
is not allowed at all. To indicate missing Header Metadata
Block, header_metadata_size must be set to zero. This is
what Metadata decoder does after this patch too.

Note that other missing fields in lzma_metadata are still
indicated with LZMA_VLI_VALUE_UNKNOWN. This isn't as
illogical as it sounds at first, because missing Size of
Header Metadata Block means that Header Metadata Block is
not present in the Stream. With other Metadata fields,
a missing field means only that the value is unknown.
2008-01-23 13:36:07 +02:00
Lasse Collin
58b78ab20c Fix a memory leak in metadata_decoder.c. 2008-01-23 13:15:55 +02:00
Lasse Collin
4d8cdbdab4 Fix the fix 863028cb7a which
just moved to problem. Now it's really fixed.
2008-01-23 13:13:58 +02:00
Lasse Collin
67321de963 Take advantage of return_if_error() macro in
lzma_info_metadata_set() in info.c.
2008-01-23 00:21:04 +02:00
Lasse Collin
863028cb7a Fixed a dangling pointer that caused invalid free(). 2008-01-23 00:18:32 +02:00
Lasse Collin
cf49f42a6b Added lzma_easy_* functions. These should make using
liblzma as easy as using zlib, because the easy API
don't require developers to know any fancy LZMA options.

Note that Multi-Block Stream encoding is currently broken.
The easy API should be OK, the bug(s) are elsewhere.
2008-01-22 22:49:24 +02:00
Lasse Collin
1747b85a43 Fix Multi-Block Stream encoder's EOPM usage. 2008-01-22 21:16:22 +02:00
Lasse Collin
0ed6f1adce Made lzma_extra pointers const in lzma_options_stream. 2008-01-22 00:15:11 +02:00
Lasse Collin
305afa38f6 Updated debug/sync_flush.c. 2008-01-20 20:15:21 +02:00
Lasse Collin
d53e9b7705 Added debug/repeat.c. 2008-01-20 20:14:26 +02:00
Lasse Collin
107259e306 Fix alignment handling bugs in Subblock encoder.
This leaves one known alignment bug unfixed: If repeat count
doesn't fit into 28-bit integer, the encoder has to split
this to multiple Subblocks with Subblock Type `Repeating Data'.
The extra Subblocks may have wrong alignment. Correct alignment
is restored after the split Repeating Data has been completely
written out.

Since the encoder doesn't even try to fix the alignment unless
the size of Data is at least 4 bytes, to trigger this bug you
need at least 4 GiB of repeating data with sequence length of
4 or more bytes. Since the worst thing done by this bug is
misaligned data (no data corruption), this bug simply isn't
worth fixing, because a proper fix isn't simple.
2008-01-20 20:12:58 +02:00
Lasse Collin
e141fe1895 Implemented LZMA_SYNC_FLUSH support to the Subblock encoder.
The API for handing Subfilters was changed to make it
consistent with LZMA_SYNC_FLUSH.

A few sanity checks were added for Subfilter handling. Some
small bugs were fixed. More comments were added.
2008-01-19 21:16:33 +02:00
Lasse Collin
23c227a864 Revised the Delta filter implementation. The initialization
function is still shared between encoder and decoder, but the
actual coding is in separate files for encoder and decoder.

There are now separate functions for the actual delta
calculation depending on if Delta is the last filter in the
chain or not. If it is the last, the new code copies the
data from input to output buffer and does the delta
calculation at the same time. The old code first copied the
data, then did the delta in the target buffer, which required
reading through the data twice.

Support for LZMA_SYNC_FLUSH was added to the Delta encoder.
This doesn't change anything in the file format.
2008-01-19 15:19:21 +02:00
Lasse Collin
61dc82f3e3 Added the debug directory and the first debug tool
(sync_flush). These tools are not built unless the
user runs "make" in the debug directory.
2008-01-18 20:18:08 +02:00
Lasse Collin
0ae3208db9 Added test files to test usage of flush marker in LZMA. 2008-01-18 20:13:00 +02:00
Lasse Collin
ab5feaf1fc Fix LZMA_SYNC_FLUSH handling in LZ and LZMA encoders.
That code is now almost completely in LZ coder, where
it can be shared with other LZ77-based algorithms in
future.
2008-01-18 20:02:52 +02:00
Lasse Collin
079c4f7fc2 Don't add -g to CFLAGS when --enable-debug is specified.
It's the job of the user to put that in CFLAGS.
2008-01-18 17:21:24 +02:00
Lasse Collin
61d1784d8f Set stdin and stdout to binary mode on Windows. This patch is
a forward port of b7b22fcb979a16d3a47c8001f058c9f7d4416068
from lzma-utils-legacy.git. I don't know if the new code base
builds on Windows, but this is a start.
2008-01-18 14:17:37 +02:00
Lasse Collin
c9cba97691 Added test_compress.sh and bunch of files needed by it.
This new set of tests compress and decompress several
test files with many different compression options.
This set of tests will be extended later.
2008-01-18 00:50:29 +02:00
Lasse Collin
33be3c0e24 Subblock decoder: Don't exit the main loop in decode_buffer()
too early if we hit End of Input while decoding a Subblock of
type Repeating Data. To keep the loop termination condition
elegant, the order of enumerations in coder->sequence were
changed.

To keep the case-labels in roughly the same order as the
enumerations in coder->sequence, large chunks of code was
moved around. This made the diff big and ugly compared to
the amount of the actual changes made.
2008-01-17 18:56:53 +02:00
Lasse Collin
b254bd97b1 Fix wrong too small size of argument unfiltered_max
in ia64_coder_init(). It triggered assert() in
simple_coder.c, and could have caused a buffer overflow.

This error was probably a copypaste mistake, since most
of the simple filters use unfiltered_max = 4.
2008-01-17 17:39:42 +02:00
Lasse Collin
8f5794c8f1 Added --delta to the output of "lzma --help". 2008-01-17 17:27:45 +02:00
Lasse Collin
f88590e001 Fix Subblock docoder: If Subblock filter was used with known
Uncompressed Size, and the last output byte was from RLE,
the code didn't stop decoding as it should have done.
2008-01-17 13:14:20 +02:00
Lasse Collin
bc0b945ca3 Tiny non-technical edits to file-format.txt. 2008-01-16 16:33:37 +02:00
Lasse Collin
7599bb7064 Plugged a memory leak in stream_decoder.c. 2008-01-16 14:48:04 +02:00
Lasse Collin
0b58153931 Added memory leak detection to lzmadec.c. 2008-01-16 14:47:27 +02:00
Lasse Collin
5b5b13c7bb Added lzma_memlimit_count(). 2008-01-16 14:46:50 +02:00
Lasse Collin
19389f2b82 Added ARRAY_SIZE(array) macro. 2008-01-16 14:31:44 +02:00
Lasse Collin
9bc33a54cb Make Uncompresed Size validation more strict
in alone_decoder.c.
2008-01-16 13:27:03 +02:00
Lasse Collin
01d71d60b7 Free the allocated memory in lzmadec if debugging is
enabled. This should make it possible to detect possible
memory leaks with Valgrind.
2008-01-15 17:46:59 +02:00
Lasse Collin
8235e6e5b2 Fix memory leaks from test_block_header.c. 2008-01-15 16:25:38 +02:00
Lasse Collin
f10fc6a69d Use fastpos.h when encoding LZMA dictionary size in
Filter Flags encoder.
2008-01-15 14:23:35 +02:00
Lasse Collin
e5728142a2 Revised the fastpos code. It now uses the slightly faster
table-based version from LZMA SDK 4.57. This should be
fast on most systems.

A simpler and smaller alternative version is also provided.
On some CPUs this can be even a little faster than the
default table-based version (see comments in fastpos.h),
but on most systems the table-based code is faster.
2008-01-15 14:02:22 +02:00
Lasse Collin
10437b5b56 Added bsr.h. 2008-01-15 13:32:13 +02:00
Lasse Collin
f3c88e8b8d Fixed assembler detection in configure.ac, and added
detection for x86_64.
2008-01-15 13:29:14 +02:00
Lasse Collin
54ec204f58 Omit invalid space from printf() format string
in price_table_gen.c.
2008-01-15 12:20:41 +02:00
Lasse Collin
01b4b19f49 Removed a few unused macros from lzma_common.h. 2008-01-15 09:54:34 +02:00
Lasse Collin
19bd7f3cf2 Fix a typo in lzma_encoder.c. 2008-01-15 08:37:42 +02:00
Lasse Collin
9f9b198301 Convert bittree_get_price() and bittree_reverse_get_price()
from macros to inline functions.
2008-01-15 08:36:25 +02:00
Lasse Collin
78e85cb1a7 Fix CRC code in case --enable-small is used. 2008-01-15 07:44:59 +02:00
Lasse Collin
949d4346e2 Fix typo in test_index.c. 2008-01-15 07:41:39 +02:00
Lasse Collin
d13d693155 Added precomputed range coder probability price table. 2008-01-15 07:40:21 +02:00
Lasse Collin
362dc3843b Remove RC_BUFFER_SIZE from lzma_encoder_private.h
and replace it with a sanity check.
2008-01-14 13:42:43 +02:00
Lasse Collin
e22b37968d Major changes to LZ encoder, LZMA encoder, and range encoder.
These changes implement support for LZMA_SYNC_FLUSH in LZMA
encoder, and move the temporary buffer needed by range encoder
from lzma_range_encoder structure to lzma_lz_encoder.
2008-01-14 13:39:54 +02:00
Lasse Collin
b59ef39737 Added one assert() to process.c of the command line tool. 2008-01-14 13:34:29 +02:00
Lasse Collin
9547e734a0 Don't use coder->lz.stream_end_was_reached in assertions
in match_c.h.
2008-01-14 12:09:52 +02:00
Lasse Collin
3e09e1c058 In lzma_read_match_distances(), don't use
coder->lz.stream_end_was_reached. That variable
will be removed, and the check isn't required anyway.
Rearrange the check so that it doesn't make one to
think that there could be an integer overflow.
2008-01-14 12:08:02 +02:00
Lasse Collin
a670fec802 Small LZMA_SYNC_FLUSH fixes to Block and Single-Stream encoders. 2008-01-14 11:56:41 +02:00
Lasse Collin
3599dba957 More fixes to LZMA decoder's flush marker handling. 2008-01-14 11:54:56 +02:00
Lasse Collin
f73c2ab607 Eliminate lzma_lz_encoder.must_move_pos. It's needed
only in one place which isn't performance criticial.
2008-01-10 17:13:42 +02:00
Lasse Collin
382808514a Define HAVE_ASM_X86 when x86 assembler optimizations are
used. This #define will be useful for inline assembly.
2008-01-09 20:05:57 +02:00
Lasse Collin
0e70fbe403 Added good-single-none-empty_3.lzma and
bad-single-none-empty.lzma.
2008-01-09 12:06:46 +02:00
Lasse Collin
379fbbe84d Take advantage of return_if_error() in block_decoder.c. 2008-01-08 23:11:59 +02:00
Lasse Collin
97d5fa8207 Updated tests/files/README. 2008-01-08 23:10:57 +02:00
Lasse Collin
3bb9bb3109 Added test files with empty Compressed Data. 2008-01-08 23:05:40 +02:00
Lasse Collin
7054c5f588 Fix decoding of Blocks that have only Block Header. 2008-01-08 22:58:42 +02:00
Lasse Collin
753e4d95cd Added good-single-subblock_implicit.lzma. 2008-01-08 22:27:46 +02:00
Lasse Collin
faeac7b7ac Disable CRC32 from Block Headers when --check=none
has been specified.
2008-01-08 18:50:30 +02:00
Lasse Collin
a751126dbb Fixed encoding of empty files. Arguments to is_size_valid()
were in wrong order in block_encoder.c.
2008-01-08 13:36:29 +02:00
Lasse Collin
9080267603 Added a few test files. 2008-01-08 13:35:36 +02:00
Lasse Collin
b4943ccf73 Avoid using ! in test_files.sh, because that doesn't work
with some ancient /bin/sh versions.
2008-01-08 12:29:58 +02:00
Lasse Collin
e2417b2b91 More pre-C99 inttypes.h compatibility fixes. Now the code
should work even if the system has no inttypes.h.
2008-01-08 00:48:30 +02:00
Lasse Collin
5d227e51c2 Updated fi.po although it's currently pretty much crap. 2008-01-07 23:25:32 +02:00
Lasse Collin
c7189d981a Test for $GCC = yes instead of if it is non-empty. This
way it is possible to use ac_cv_c_compiler_gnu=no to
force configure to think it is using non-GNU C compiler.
2008-01-07 23:14:25 +02:00
Lasse Collin
3dbbea82b7 Added test_files.sh to tests/Makefile.am so it gets
included in the tarball with "make dist".
2008-01-07 21:49:41 +02:00
Lasse Collin
2fd2d18154 Cosmetic edit to test_files.sh. 2008-01-07 18:22:24 +02:00
Lasse Collin
9a71d57310 Added tests/files/README. 2008-01-07 18:09:44 +02:00
Lasse Collin
47f48fe993 Tell in COPYING that everything in tests/files is
public domain.
2008-01-07 14:20:57 +02:00
Lasse Collin
3502b3e1d0 Cleaned up the tests/files directory. 2008-01-07 14:19:05 +02:00
Lasse Collin
908b2ac604 Added test_files.sh to test decoding of the files in
the tests/files directory. It doesn't test the malicious
files yet.
2008-01-07 13:49:19 +02:00
Lasse Collin
ecb2a6548f Updated README regarding the assembler optimizations. 2008-01-07 11:23:13 +02:00
Lasse Collin
eacb805043 Updated THANKS. 2008-01-07 10:58:00 +02:00
Lasse Collin
1239649f96 Cosmetic changes to configure.ac. 2008-01-06 21:47:17 +02:00
Lasse Collin
88ee301ec2 Automatically disable assembler code on Darwin x86.
Darwin has different ABI than GNU+Linux and Solaris,
thus the assembler code doesn't assemble on Darwin.
2008-01-06 19:46:38 +02:00
Lasse Collin
c15a7abf66 With printf(), use PRIu64 with a cast to uint64_t instead
of %zu, because some pre-C99 libc versions don't support %zu.
2008-01-06 19:45:27 +02:00
Lasse Collin
4e7e54c4c5 Introduced compatibility with systems that have pre-C99
or no inttypes.h. This is useful when the compiler has
good enough support for C99, but libc headers don't.

Changed liblzma API so that sys/types.h and inttypes.h
have to be #included before #including lzma.h. On systems
that don't have C99 inttypes.h, it's the problem of the
applications to provide the required types and macros
before #including lzma.h.

If lzma.h defined the missing types and macros, it could
conflict with third-party applications whose configure
has detected that the types are missing and defined them
in config.h already. An alternative would have been
introducing lzma_uint32 and similar types, but that would
just be an extra pain on modern systems.
2008-01-06 16:27:41 +02:00
Lasse Collin
a71864f77d Fix typo in comment (INT64_MAX -> UINT64_MAX). 2008-01-05 19:57:00 +02:00
Lasse Collin
072927905a Rearranged testing of GCC-specific flags. 2008-01-05 19:42:04 +02:00
Lasse Collin
d160ee3259 Another bug fix for flush marker detection. 2008-01-05 01:20:24 +02:00
Lasse Collin
fc67f79f60 Fix stupid bugs in flush marker detection. 2008-01-04 21:37:01 +02:00
Lasse Collin
0029cbbabe Added support for flush marker, which will be in files
that use LZMA_SYNC_FLUSH with encoder (not implemented
yet). This is a new feature in the raw LZMA format,
which isn't supported by old decoders. This shouldn't
be a problem in practice, since lzma_alone_encoder()
will not allow LZMA_SYNC_FLUSH, and thus not allow
creating files on decodable with old decoders.

Made lzma_decoder.c to require tab width of 4 characters
if one wants to fit the code in 80 columns. This makes
the code easier to read.
2008-01-04 21:30:33 +02:00
Lasse Collin
bbfd1f6ab0 Moved range decoder initialization (reading the first
five input bytes) from LZMA decoder to range decoder
header. Did the same for decoding of direct bits.
2008-01-04 20:45:05 +02:00
Lasse Collin
5db745cd2a Added a note to README that --disable-assembler
must be used on Darwin.
2007-12-14 11:15:21 +02:00
Lasse Collin
44b333d461 Use the filename suffix .S instead of .s for assembler files
so that the preprocessor removes the /* */ style comments,
which are not supported by some non-GNU assemblers (Solaris)
that otherwise work with this code.
2007-12-14 10:07:10 +02:00
Lasse Collin
ec1c82b2e8 Fixed wrong symbol name in crc64_x86.s. 2007-12-14 09:59:05 +02:00
Lasse Collin
2881570df6 Use .globl instead of .global in x86 assembler code for
better portability. Still needs fixing the commenting.
2007-12-14 09:53:24 +02:00
Lasse Collin
698470b8f3 Fixed a few short options that take an argument.
short_opts[] was missing colons to indicate
required argument. Thanks to Fabio Pedretti for
the bug report.
2007-12-13 20:14:37 +02:00
Lasse Collin
918bcb0e07 Removed uncompressed size tracking from Delta encoder too. 2007-12-11 17:08:04 +02:00
Lasse Collin
3e16d51dd6 Remove uncompressed size tracking from the filter encoders.
It's not strictly needed there, and just complicates the
code. LZ encoder never even had this feature.

The primary reason to have uncompressed size tracking in
filter encoders was validating that the application
doesn't give different amount of input that it had
promised. A side effect was to validate internal workings
of liblzma.

Uncompressed size tracking is still present in the Block
encoder. Maybe it should be added to LZMA_Alone and raw
encoders too. It's simpler to have one coder just to
validate the uncompressed size instead of having it
in every filter.
2007-12-11 16:49:19 +02:00
Lasse Collin
5286723e0d Get rid of no-NLS gnulib. I don't know how to get it
working with Automake. People who want smaller lzmadec
should use --disable-nls on non-GNU systems.
2007-12-11 14:10:53 +02:00
Lasse Collin
ce8b036a6c Fixed a typo in tests/Makefile.am which prevented
building the tests if gnulib was needed.
2007-12-11 14:09:35 +02:00
Lasse Collin
7c1ad41eb6 Fixed wrong type of flags_size in Subblock encoder. 2007-12-11 11:18:58 +02:00
Lasse Collin
ce64df7162 Bumped version number to 4.42.3alpha. 2007-12-10 20:44:16 +02:00
300 changed files with 17922 additions and 16889 deletions

View File

@@ -5,7 +5,8 @@ LZMA Utils Licenses
Different licenses apply to different files in this package. Here
is a rough summary of which license apply to which parts of this
package (but check the individual files to be sure!):
- Everything under src/liblzma/check is public domain.
- Everything under src/liblzma/check and tests/files is public
domain.
- Everything else under the src directory is under the GNU LGPL
2.1 or (at your opinion) any later version.
- Outside the src directory, there are some files that are under

View File

@@ -12,6 +12,7 @@
## Lesser General Public License for more details.
##
DIST_SUBDIRS = lib src po tests debug
SUBDIRS =
if COND_GNULIB
@@ -20,7 +21,6 @@ endif
SUBDIRS += src po tests
EXTRA_DIST = \
m4 \
config.rpath \
@@ -32,4 +32,8 @@ EXTRA_DIST = \
COPYING.LGPLv2.1
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = foreign
# This works with GNU tar and gives cleaner package than normal 'make dist'.
mydist:
TAR_OPTIONS='--owner=0 --group=0 --numeric-owner --mode=u+rw,go+r-w' \
$(MAKE) dist-gzip

35
README
View File

@@ -59,6 +59,35 @@ Supported platforms
in C89 or C++.
Version numbering
Starting from LZMA Utils 5, the version number of LZMA Utils has
absolutely nothing to do with the version number of LZMA SDK or
7-Zip. The new version number format of LZMA Utils is X.Y.ZS:
- X is the major version. When this is incremented, the library
API and ABI break.
- Y is the minor version. It is incremented when new features are
added without breaking existing API or ABI. Even Y indicates
stable release and odd Y indicates unstable (alpha or beta
version).
- Z is the revision. This has different meaning for stable and
unstable releases:
* Stable: Z is incremented when bugs get fixed without adding
any new features.
* Unstable: Z is just a counter. API or ABI of features added
in earlier unstable releases having the same X.Y may break.
- S indicates stability of the release. It is missing from the
stable releases where Y is an even number. When Y is odd, S
is either "alpha" or "beta" to make it very clear that such
versions are not stable releases. The same X.Y.Z combination is
not used for more than one stability level i.e. after X.Y.Zalpha,
the next version can be X.Y.(Z+1)beta but not X.Y.Zbeta.
configure options
If you are not familiar with `configure' scripts, read the file
@@ -113,7 +142,11 @@ configure options
All the assembler code in liblzma is position-independent
code, which is suitable for use in shared libraries and
position-independent executables.
position-independent executables. So far only i386
instructions are used, but the code is optimized for i686
class CPUs. If you are compiling liblzma exclusively for
pre-i686 systems, you may want to disable the assembler
code.
--enable-small
Omits precomputed tables. This makes liblzma a few KiB

4
THANKS
View File

@@ -6,17 +6,21 @@ Some people have helped more, some less, some don't even know they have
been helpful, but nevertheless everyone's help has been important. :-)
In alphabetical order:
- Mark Adler
- Nelson H. F. Beebe
- Anders F. Björklund
- İsmail Dönmez
- Jean-loup Gailly
- Per Øyvind Karlsen
- Ville Koskinen
- Stephan Kulow
- Jim Meyering
- Igor Pavlov
- Mikko Pouru
- Alexandre Sauvé
- Julian Seward
- Paul Townsend
- Mohammed Adnène Trojette
- Andreas Zieringer
Also thanks to all the people who have participated the Tukaani project
and others who I have forgot.

View File

@@ -26,7 +26,7 @@ AC_PREREQ(2.61)
# [LZMA] instead of [LZMA utils] since I prefer to have lzma-version.tar.gz
# instead of lzma-utils-version.tar.gz.
AC_INIT([LZMA], [4.42.2alpha], [lasse.collin@tukaani.org])
AC_INIT([LZMA], [4.999.5alpha], [lasse.collin@tukaani.org])
AC_CONFIG_SRCDIR([src/liblzma/common/common.h])
AC_CONFIG_HEADER([config.h])
@@ -39,22 +39,30 @@ echo "System type:"
# This is needed to know if assembler optimizations can be used.
AC_CANONICAL_HOST
echo
echo "Configure options:"
# Enable/disable debugging code:
#############
# Debugging #
#############
AC_MSG_CHECKING([if debugging code should be compiled])
AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [Enable debugging code.]),
[], enable_debug=no)
if test "x$enable_debug" = xyes; then
CFLAGS="-g $CFLAGS"
AC_MSG_RESULT([yes])
else
AC_DEFINE(NDEBUG, 1, [Define to disable debugging code.])
AC_MSG_RESULT([no])
fi
# Enable/disable the encoder components:
###########
# Encoder #
###########
AC_MSG_CHECKING([if encoder components should be built])
AC_ARG_ENABLE(encoder, AC_HELP_STRING([--disable-encoder],
[Do not build the encoder components.]),
@@ -68,7 +76,11 @@ else
fi
AM_CONDITIONAL(COND_MAIN_ENCODER, test "x$enable_encoder" = xyes)
# Enable/disable the decoder components:
###########
# Decoder #
###########
AC_MSG_CHECKING([if decoder components should be built])
AC_ARG_ENABLE(decoder, AC_HELP_STRING([--disable-decoder],
[Do not build the decoder components.]),
@@ -85,146 +97,146 @@ else
fi
AM_CONDITIONAL(COND_MAIN_DECODER, test "x$enable_decoder" = xyes)
# Filters
AC_MSG_CHECKING([which filters to build])
AC_ARG_ENABLE(filters, AC_HELP_STRING([--enable-filters=],
[Comma-separated list of filters to build. Default=all.
Filters used in encoding are needed also in decoding.
Available filters: copy subblock x86 powerpc ia64
arm armthumb sparc delta lzma]),
[], [enable_filters=copy,subblock,x86,powerpc,ia64,arm,armthumb,sparc,delta,lzma])
enable_filters=`echo "$enable_filters" | sed 's/,/ /g'`
enable_filters_copy=no
enable_filters_subblock=no
enable_filters_x86=no
enable_filters_powerpc=no
enable_filters_ia64=no
enable_filters_arm=no
enable_filters_armthumb=no
enable_filters_sparc=no
enable_filters_delta=no
enable_filters_lzma=no
enable_simple_filters=no
if test "x$enable_filters" = xno || test "x$enable_filters" = x; then
AC_MSG_RESULT([])
AC_MSG_ERROR([Please enable at least one filter.])
###########
# Filters #
###########
m4_define([SUPPORTED_FILTERS], [lzma,lzma2,subblock,delta,x86,powerpc,ia64,arm,armthumb,sparc])dnl
m4_define([SIMPLE_FILTERS], [x86,powerpc,ia64,arm,armthumb,sparc])
m4_define([LZ_FILTERS], [lzma,lzma2])
m4_foreach([NAME], [SUPPORTED_FILTERS],
[enable_filter_[]NAME=no
enable_encoder_[]NAME=no
enable_decoder_[]NAME=no
])dnl
AC_MSG_CHECKING([which encoders to build])
AC_ARG_ENABLE([encoders], AC_HELP_STRING([--enable-encoders=LIST],
[Comma-separated list of encoders to build. Default=all.
Available encoders:]
m4_translit(m4_defn([SUPPORTED_FILTERS]), [,], [ ])),
[], [enable_encoders=SUPPORTED_FILTERS])
enable_encoders=`echo "$enable_encoders" | sed 's/,/ /g'`
if test "x$enable_encoders" = xno || test "x$enable_encoders" = x; then
AC_MSG_RESULT([(none)])
else
for arg in $enable_filters
for arg in $enable_encoders
do
case $arg in
copy)
enable_filters_copy=yes
AC_DEFINE([HAVE_FILTER_COPY], 1,
[Define to 1 if support for the
Copy filter is enabled.])
;;
subblock)
enable_filters_subblock=yes
AC_DEFINE([HAVE_FILTER_SUBBLOCK], 1,
[Define to 1 if support for the
Subblock filter is enabled.])
;;
x86)
enable_filters_x86=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_X86], 1,
[Define to 1 if support for the
x86 (BCJ) filter is enabled.])
;;
powerpc)
enable_filters_powerpc=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_POWERPC], 1,
[Define to 1 if support for the
PowerPC filter is enabled.])
;;
ia64)
enable_filters_ia64=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_IA64], 1,
[Define to 1 if support for the
IA64 filter is enabled.])
;;
arm)
enable_filters_arm=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_ARM], 1,
[Define to 1 if support for the
ARM filter is enabled.])
;;
armthumb)
enable_filters_armthumb=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_ARMTHUMB], 1,
[Define to 1 if support for the
ARMThumb filter is enabled.])
;;
sparc)
enable_filters_sparc=yes
enable_simple_filters=yes
AC_DEFINE([HAVE_FILTER_SPARC], 1,
[Define to 1 if support for the
SPARC filter is enabled.])
;;
delta)
enable_filters_delta=yes
AC_DEFINE([HAVE_FILTER_DELTA], 1,
[Define to 1 if support for the
Delta filter is enabled.])
;;
lzma)
enable_filters_lzma=yes
AC_DEFINE([HAVE_FILTER_LZMA], 1,
[Define to 1 if support for the
LZMA filter is enabled.])
;;
case $arg in m4_foreach([NAME], [SUPPORTED_FILTERS], [
NAME)
enable_filter_[]NAME=yes
enable_encoder_[]NAME=yes
AC_DEFINE(HAVE_ENCODER_[]m4_toupper(NAME), [1],
[Define to 1 if] NAME [encoder is enabled.])
;;])
*)
AC_MSG_RESULT([])
AC_MSG_ERROR([unknown filter: $arg])
;;
esac
done
AC_MSG_RESULT([$enable_filters])
AC_MSG_RESULT([$enable_encoders])
fi
if test "x$enable_simple_filters" = xyes ; then
AC_DEFINE([HAVE_FILTER_SIMPLE], 1, [Define to 1 if support for any
of the so called simple filters is enabled.])
fi
AM_CONDITIONAL(COND_FILTER_COPY, test "x$enable_filters_copy" = xyes)
AM_CONDITIONAL(COND_FILTER_SUBBLOCK, test "x$enable_filters_subblock" = xyes)
AM_CONDITIONAL(COND_FILTER_X86, test "x$enable_filters_x86" = xyes)
AM_CONDITIONAL(COND_FILTER_POWERPC, test "x$enable_filters_powerpc" = xyes)
AM_CONDITIONAL(COND_FILTER_IA64, test "x$enable_filters_ia64" = xyes)
AM_CONDITIONAL(COND_FILTER_ARM, test "x$enable_filters_arm" = xyes)
AM_CONDITIONAL(COND_FILTER_ARMTHUMB, test "x$enable_filters_armthumb" = xyes)
AM_CONDITIONAL(COND_FILTER_SPARC, test "x$enable_filters_sparc" = xyes)
AM_CONDITIONAL(COND_FILTER_DELTA, test "x$enable_filters_delta" = xyes)
AM_CONDITIONAL(COND_FILTER_LZMA, test "x$enable_filters_lzma" = xyes)
AM_CONDITIONAL(COND_MAIN_SIMPLE, test "x$enable_simple_filters" = xyes)
# Which match finders should be enabled:
AC_MSG_CHECKING([which decoders to build])
AC_ARG_ENABLE([decoders], AC_HELP_STRING([--enable-decoders=LIST],
[Comma-separated list of decoders to build. Default=all.
Available decoders are the same as available encoders.]),
[], [enable_decoders=SUPPORTED_FILTERS])
enable_decoders=`echo "$enable_decoders" | sed 's/,/ /g'`
if test "x$enable_decoders" = xno || test "x$enable_decoders" = x; then
AC_MSG_RESULT([(none)])
else
for arg in $enable_decoders
do
case $arg in m4_foreach([NAME], [SUPPORTED_FILTERS], [
NAME)
enable_filter_[]NAME=yes
enable_decoder_[]NAME=yes
AC_DEFINE(HAVE_DECODER_[]m4_toupper(NAME), [1],
[Define to 1 if] NAME [decoder is enabled.])
;;])
*)
AC_MSG_RESULT([])
AC_MSG_ERROR([unknown filter: $arg])
;;
esac
done
# LZMA2 requires that LZMA is enabled.
test "x$enable_encoder_lzma2" = xyes && enable_encoder_lzma=yes
test "x$enable_decoder_lzma2" = xyes && enable_decoder_lzma=yes
AC_MSG_RESULT([$enable_decoders])
fi
if test "x$enable_encoder_lzma2$enable_encoder_lzma" = xyesno \
|| test "x$enable_decoder_lzma2$enable_decoder_lzma" = xyesno; then
AC_MSG_ERROR([LZMA2 requires that LZMA is also enabled.])
fi
m4_foreach([NAME], [SUPPORTED_FILTERS],
[AM_CONDITIONAL(COND_FILTER_[]m4_toupper(NAME), test "x$enable_filter_[]NAME" = xyes)
AM_CONDITIONAL(COND_ENCODER_[]m4_toupper(NAME), test "x$enable_encoder_[]NAME" = xyes)
AM_CONDITIONAL(COND_DECODER_[]m4_toupper(NAME), test "x$enable_decoder_[]NAME" = xyes)
])dnl
# The so called "simple filters" share common code.
enable_filter_simple=no
enable_encoder_simple=no
enable_decoder_simple=no
m4_foreach([NAME], [SIMPLE_FILTERS],
[test "x$enable_filter_[]NAME" = xyes && enable_filter_simple=yes
test "x$enable_encoder_[]NAME" = xyes && enable_encoder_simple=yes
test "x$enable_decoder_[]NAME" = xyes && enable_decoder_simple=yes
])dnl
AM_CONDITIONAL(COND_FILTER_SIMPLE, test "x$enable_filter_simple" = xyes)
AM_CONDITIONAL(COND_ENCODER_SIMPLE, test "x$enable_encoder_simple" = xyes)
AM_CONDITIONAL(COND_DECODER_SIMPLE, test "x$enable_decoder_simple" = xyes)
# LZ-based filters share common code.
enable_filter_lz=no
enable_encoder_lz=no
enable_decoder_lz=no
m4_foreach([NAME], [LZ_FILTERS],
[test "x$enable_filter_[]NAME" = xyes && enable_filter_lz=yes
test "x$enable_encoder_[]NAME" = xyes && enable_encoder_lz=yes
test "x$enable_decoder_[]NAME" = xyes && enable_decoder_lz=yes
])dnl
AM_CONDITIONAL(COND_FILTER_LZ, test "x$enable_filter_lz" = xyes)
AM_CONDITIONAL(COND_ENCODER_LZ, test "x$enable_encoder_lz" = xyes)
AM_CONDITIONAL(COND_DECODER_LZ, test "x$enable_decoder_lz" = xyes)
#################
# Match finders #
#################
m4_define([SUPPORTED_MATCH_FINDERS], [hc3,hc4,bt2,bt3,bt4])
m4_foreach([NAME], [SUPPORTED_MATCH_FINDERS],
[enable_match_finder_[]NAME=no
])
AC_MSG_CHECKING([which match finders to build])
AC_ARG_ENABLE(match-finders, AC_HELP_STRING([--enable-match-finders=],
AC_ARG_ENABLE(match-finders, AC_HELP_STRING([--enable-match-finders=LIST],
[Comma-separated list of match finders to build. Default=all.
At least one match finder is required for encoding with
the LZMA filter.
Available match finders: hc3 hc4 bt2 bt3 bt4]), [],
[enable_match_finders=hc3,hc4,bt2,bt3,bt4])
the LZMA filter. Available match finders:]
m4_translit(m4_defn([SUPPORTED_MATCH_FINDERS]), [,], [ ])), [],
[enable_match_finders=SUPPORTED_MATCH_FINDERS])
enable_match_finders=`echo "$enable_match_finders" | sed 's/,/ /g'`
enable_match_finders_hc3=no
enable_match_finders_hc4=no
enable_match_finders_bt2=no
enable_match_finders_bt3=no
enable_match_finders_bt4=no
if test "x$enable_encoder" = xyes && test "x$enable_filters_lzma" = xyes ; then
if test "x$enable_encoder" = xyes && test "x$enable_encoder_lz" = xyes ; then
for arg in $enable_match_finders
do
case $arg in
hc3) enable_match_finders_hc3=yes ;;
hc4) enable_match_finders_hc4=yes ;;
bt2) enable_match_finders_bt2=yes ;;
bt3) enable_match_finders_bt3=yes ;;
bt4) enable_match_finders_bt4=yes ;;
case $arg in m4_foreach([NAME], [SUPPORTED_MATCH_FINDERS], [
NAME)
enable_match_finder_[]NAME=yes
AC_DEFINE(HAVE_MF_[]m4_toupper(NAME), [1],
[Define to 1 to enable] NAME [match finder.])
;;])
*)
AC_MSG_RESULT([])
AC_MSG_ERROR([unknown match finder: $arg])
@@ -233,48 +245,39 @@ if test "x$enable_encoder" = xyes && test "x$enable_filters_lzma" = xyes ; then
done
AC_MSG_RESULT([$enable_match_finders])
else
AC_MSG_RESULT([(none because not building the LZMA encoder)])
AC_MSG_RESULT([(none because not building any LZ-based encoder)])
fi
AM_CONDITIONAL(COND_MF_HC3, test "x$enable_match_finders_hc3" = xyes)
AM_CONDITIONAL(COND_MF_HC4, test "x$enable_match_finders_hc4" = xyes)
AM_CONDITIONAL(COND_MF_BT2, test "x$enable_match_finders_bt2" = xyes)
AM_CONDITIONAL(COND_MF_BT3, test "x$enable_match_finders_bt3" = xyes)
AM_CONDITIONAL(COND_MF_BT4, test "x$enable_match_finders_bt4" = xyes)
# Which integrity checks to build
####################
# Integrity checks #
####################
m4_define([SUPPORTED_CHECKS], [crc32,crc64,sha256])
m4_foreach([NAME], [SUPPORTED_FILTERS],
[enable_check_[]NAME=no
])dnl
AC_MSG_CHECKING([which integrity checks to build])
AC_ARG_ENABLE(checks, AC_HELP_STRING([--enable-checks=],
AC_ARG_ENABLE(checks, AC_HELP_STRING([--enable-checks=LIST],
[Comma-separated list of integrity checks to build.
Default=all. Available integrity checks: crc32 crc64 sha256]),
[], [enable_checks=crc32,crc64,sha256])
Default=all. Available integrity checks:]
m4_translit(m4_defn([SUPPORTED_CHECKS]), [,], [ ])),
[], [enable_checks=SUPPORTED_CHECKS])
enable_checks=`echo "$enable_checks" | sed 's/,/ /g'`
enable_checks_crc32=no
enable_checks_crc64=no
enable_checks_sha256=no
if test "x$enable_checks" = xno || test "x$enable_checks" = x; then
AC_MSG_RESULT([(none)])
else
for arg in $enable_checks
do
case $arg in
crc32)
enable_checks_crc32=yes
AC_DEFINE([HAVE_CHECK_CRC32], 1,
[Define to 1 if CRC32 support
is enabled.])
;;
crc64)
enable_checks_crc64=yes
AC_DEFINE([HAVE_CHECK_CRC64], 1,
[Define to 1 if CRC64 support
is enabled.])
;;
sha256)
enable_checks_sha256=yes
AC_DEFINE([HAVE_CHECK_SHA256], 1,
[Define to 1 if SHA256 support
is enabled.])
;;
case $arg in m4_foreach([NAME], [SUPPORTED_CHECKS], [
NAME)
enable_check_[]NAME=yes
AC_DEFINE(HAVE_CHECK_[]m4_toupper(NAME), [1],
[Define to 1 if] NAME
[integrity check is enabled.])
;;])
*)
AC_MSG_RESULT([])
AC_MSG_ERROR([unknown integrity check: $arg])
@@ -286,39 +289,93 @@ fi
if test "x$enable_checks_crc32" = xno ; then
AC_MSG_ERROR([For now, the CRC32 check must always be enabled.])
fi
AM_CONDITIONAL(COND_CHECK_CRC32, test "x$enable_checks_crc32" = xyes)
AM_CONDITIONAL(COND_CHECK_CRC64, test "x$enable_checks_crc64" = xyes)
AM_CONDITIONAL(COND_CHECK_SHA256, test "x$enable_checks_sha256" = xyes)
# Assembler optimizations
m4_foreach([NAME], [SUPPORTED_CHECKS],
[AM_CONDITIONAL(COND_CHECK_[]m4_toupper(NAME), test "x$enable_check_[]NAME" = xyes)
])dnl
###########################
# Assembler optimizations #
###########################
AC_MSG_CHECKING([if assembler optimizations should be used])
AC_ARG_ENABLE(assembler, AC_HELP_STRING([--disable-assembler],
[Do not use assembler optimizations even if such exist
for the architecture.]),
[], [enable_assembler=yes])
[], [enable_assembler=yes])
if test "x$enable_assembler" = xyes; then
case $host_cpu in
i?86) enable_assembler=x86 ;;
x86_64) enable_assembler=x86_64 ;;
*) enable_assembler=no ;;
esac
# Darwin has different ABI than GNU+Linux and Solaris,
# and the assembler code doesn't assemble.
case $host_os in
darwin*) enable_assembler=no ;;
*) ;;
esac
fi
case $enable_assembler in
x86|no) ;;
x86)
AC_DEFINE([HAVE_ASM_X86], 1,
[Define to 1 if using x86 assembler optimizations.])
;;
x86_64)
AC_DEFINE([HAVE_ASM_X86_64], 1,
[Define to 1 if using x86_64 assembler optimizations.])
;;
no)
;;
*)
AC_MSG_RESULT([])
AC_MSG_ERROR([--enable-assembler accepts only \`yes', \`no', or \`x86'.])
AC_MSG_ERROR([--enable-assembler accepts only \`yes', \`no', \`x86', or \`x86_64'.])
;;
esac
AC_MSG_RESULT([$enable_assembler])
AM_CONDITIONAL(COND_ASM_X86, test "x$enable_assembler" = xx86)
AM_CONDITIONAL(COND_ASM_X86_64, test "x$enable_assembler" = xx86_64)
################################
# Fast unaligned memory access #
################################
AC_MSG_CHECKING([if unaligned memory access should be used])
AC_ARG_ENABLE(unaligned-access, AC_HELP_STRING([--enable-unaligned-access],
[Enable if the system supports *fast* unaligned memory access
with 16-bit and 32-bit integers. By default, this is enabled
only on x86, x86_64, and big endian PowerPC.]),
[], [enable_unaligned_access=auto])
if test "x$enable_unaligned_access" = xauto ; then
case $host_cpu in
i?86|x86_64|powerpc|powerpc64)
enable_unaligned_access=yes
;;
*)
enable_unaligned_access=no
;;
esac
fi
if test "x$enable_unaligned_access" = xyes ; then
AC_DEFINE([HAVE_FAST_UNALIGNED_ACCESS], [1], [Define to 1 if
the system supports fast unaligned memory access.])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
#####################
# Size optimization #
#####################
# Size optimization
AC_MSG_CHECKING([if small size is preferred over speed])
AC_ARG_ENABLE(small, AC_HELP_STRING([--enable-small],
[Omit precomputed tables to make liblzma a few kilobytes
smaller. This will increase startup time of applications
slightly, because the tables need to be computed first.]),
[], [enable_small=no])
[Make liblzma smaller and a little slower.
This is disabled by default to optimize for speed.]),
[], [enable_small=no])
if test "x$enable_small" = xyes; then
AC_DEFINE([HAVE_SMALL], 1, [Define to 1 if optimizing for size.])
elif test "x$enable_small" != xno; then
@@ -328,24 +385,25 @@ fi
AC_MSG_RESULT([$enable_small])
AM_CONDITIONAL(COND_SMALL, test "x$enable_small" = xyes)
echo
echo "Initializing Automake:"
# There's no C++ or Fortran in LZMA Utils:
CXX=no
F77=no
AM_INIT_AUTOMAKE
AC_USE_SYSTEM_EXTENSIONS
###############################################################################
# Checks for programs.
###############################################################################
echo
echo "Initializing Automake:"
AM_INIT_AUTOMAKE([1.10 foreign tar-v7 filename-length-max=99])
AC_PROG_LN_S
AC_PROG_CC_C99
if test x$ac_cv_prog_cc_c99 = xno ; then
AC_MSG_ERROR([No C99 compiler was found.])
fi
AM_PROG_CC_C_O
AM_PROG_AS
AC_PROG_LN_S
AC_USE_SYSTEM_EXTENSIONS
echo
echo "Threading support:"
@@ -354,6 +412,8 @@ CC="$PTHREAD_CC"
echo
echo "Initializing Libtool:"
CXX=no
F77=no
AC_PROG_LIBTOOL
@@ -392,9 +452,20 @@ AC_CHECK_HEADERS([assert.h errno.h byteswap.h sys/param.h sys/sysctl.h],
# Checks for typedefs, structures, and compiler characteristics.
###############################################################################
dnl We don't need these as long as we need a C99 compiler anyway.
dnl AC_C_INLINE
dnl AC_C_RESTRICT
AC_HEADER_STDBOOL
AC_C_INLINE
AC_C_RESTRICT
AC_TYPE_UINT8_T
AC_TYPE_INT32_T
AC_TYPE_UINT32_T
AC_TYPE_INT64_T
AC_TYPE_UINT64_T
AC_TYPE_UINTPTR_T
AC_CHECK_SIZEOF([size_t])
# The command line tool can copy high resolution timestamps if such
# information is availabe in struct stat. Otherwise one second accuracy
@@ -402,11 +473,7 @@ AC_C_RESTRICT
AC_CHECK_MEMBERS([struct stat.st_atim.tv_nsec, struct stat.st_mtim.tv_nsec,
struct stat.st_atimespec.tv_nsec, struct stat.st_mtimespec.tv_nsec])
# It is very unlikely that you want to build liblzma without
# large file support.
AC_SYS_LARGEFILE
# At the moment, the only endian-dependent part should be the integrity checks.
AC_C_BIGENDIAN
@@ -419,7 +486,7 @@ gl_GETOPT
# Functions that are not mandatory i.e. we have alternatives for them
# or we can just drop some functionality:
AC_CHECK_FUNCS([memcpy memmove memset futimes futimesat])
AC_CHECK_FUNCS([futimes futimesat])
# Check how to find out the amount of physical memory in the system. The
# lzma command line tool uses this to automatically limits its memory usage.
@@ -516,7 +583,7 @@ main()
Wno_uninitialized=no
if test -n "$GCC" ; then
if test "x$GCC" = xyes ; then
echo
echo "GCC extensions:"
gl_VISIBILITY
@@ -545,13 +612,28 @@ if test -n "$GCC" ; then
# * -Winline, -Wdisabled-optimization, -Wunsafe-loop-optimizations
# don't seem so useful here; at least the last one gives some
# warnings which are not bugs.
for NEW_FLAG in -Wextra -Wformat=2 -Winit-self -Wstrict-aliasing=2 \
-Wfloat-equal -Wshadow -Wpointer-arith \
-Wbad-function-cast -Wwrite-strings \
-Waggregate-return -Wstrict-prototypes \
-Wold-style-definition -Wmissing-prototypes \
-Wmissing-declarations -Wmissing-noreturn \
-Wredundant-decls
#
# The flags are in reverse order below so they end up in "beautiful"
# order on the actual command line.
for NEW_FLAG in \
-Wredundant-decls \
-Wmissing-noreturn \
-Wmissing-declarations \
-Wmissing-prototypes \
-Wold-style-definition \
-Wstrict-prototypes \
-Waggregate-return \
-Wwrite-strings \
-Wbad-function-cast \
-Wpointer-arith \
-Wshadow \
-Wfloat-equal \
-Wstrict-aliasing=2 \
-Winit-self \
-Wformat=2 \
-Wextra \
-Wall \
-pedantic
do
AC_MSG_CHECKING([if $CC accepts $NEW_FLAG])
OLD_CFLAGS="$CFLAGS"
@@ -571,9 +653,6 @@ if test -n "$GCC" ; then
if test "x$enable_werror" = "xyes"; then
CFLAGS="-Werror $CFLAGS"
fi
# IIRC these work with all GCC versions that support -std=c99:
CFLAGS="-std=c99 -pedantic -Wall $CFLAGS"
fi
AM_CONDITIONAL([COND_WNO_UNINITIALIZED], test "x$Wno_uninitialized" = "xyes")
@@ -600,15 +679,17 @@ AC_CONFIG_FILES([
src/liblzma/api/Makefile
src/liblzma/common/Makefile
src/liblzma/check/Makefile
src/liblzma/rangecoder/Makefile
src/liblzma/lz/Makefile
src/liblzma/lzma/Makefile
src/liblzma/simple/Makefile
src/liblzma/subblock/Makefile
src/liblzma/rangecoder/Makefile
src/liblzma/delta/Makefile
src/liblzma/simple/Makefile
src/lzma/Makefile
src/lzmadec/Makefile
src/scripts/Makefile
tests/Makefile
debug/Makefile
])
AC_OUTPUT

36
debug/Makefile.am Normal file
View File

@@ -0,0 +1,36 @@
##
## Copyright (C) 2008 Lasse Collin
##
## This library is free software; you can redistribute it and/or
## modify it under the terms of the GNU Lesser General Public
## License as published by the Free Software Foundation; either
## version 2.1 of the License, or (at your option) any later version.
##
## This library is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## Lesser General Public License for more details.
##
noinst_PROGRAMS = \
repeat \
sync_flush \
full_flush \
memusage \
crc32 \
known_sizes \
hex2bin
AM_CPPFLAGS = \
-I@top_srcdir@/src/common \
-I@top_srcdir@/src/liblzma/api
AM_LDFLAGS = -static
LDADD = \
@top_builddir@/src/liblzma/liblzma.la \
@LTLIBINTL@
if COND_GNULIB
LDADD += @top_builddir@/lib/libgnu.a
endif

17
debug/README Normal file
View File

@@ -0,0 +1,17 @@
Debug tools
-----------
This directory contains a few tiny programs that may be helpful when
debugging LZMA Utils.
These tools are not meant to be installed. Often one needs to edit
the source code a little to make the programs do the wanted things.
If you don't know how these programs could help you, it is likely
that they really are useless to you.
These aren't intended to be used as example programs. They take some
shortcuts here and there, which correct programs should not do. Many
possible errors (especially I/O errors) are ignored. Don't report
bugs or send patches to fix this kind of bugs.

View File

@@ -1,9 +1,9 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file block_private.h
/// \brief Common stuff for Block encoder and decoder
/// \file crc32.c
/// \brief Primitive CRC32 calculation tool
//
// Copyright (C) 2007 Lasse Collin
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -17,30 +17,29 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_BLOCK_COMMON_H
#define LZMA_BLOCK_COMMON_H
#include "sysdefs.h"
#include <stdio.h>
#include "common.h"
static inline bool
update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
int
main(void)
{
if (limit > LZMA_VLI_VALUE_MAX)
limit = LZMA_VLI_VALUE_MAX;
uint32_t crc = 0;
if (limit < *size || limit - *size < add)
return true;
do {
uint8_t buf[BUFSIZ];
const size_t size = fread(buf, 1, sizeof(buf), stdin);
crc = lzma_crc32(buf, size, crc);
} while (!ferror(stdin) && !feof(stdin));
*size += add;
//printf("%08" PRIX32 "\n", crc);
return false;
// I want it little endian so it's easy to work with hex editor.
printf("%02" PRIX32 " ", crc & 0xFF);
printf("%02" PRIX32 " ", (crc >> 8) & 0xFF);
printf("%02" PRIX32 " ", (crc >> 16) & 0xFF);
printf("%02" PRIX32 " ", crc >> 24);
printf("\n");
return 0;
}
static inline bool
is_size_valid(lzma_vli size, lzma_vli reference)
{
return reference == LZMA_VLI_VALUE_UNKNOWN || reference == size;
}
#endif

105
debug/full_flush.c Normal file
View File

@@ -0,0 +1,105 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file full_flush.c
/// \brief Encode files using LZMA_FULL_FLUSH
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <stdio.h>
static lzma_stream strm = LZMA_STREAM_INIT;
static FILE *file_in;
static void
encode(size_t size, lzma_action action)
{
static const size_t CHUNK = 64;
uint8_t in[CHUNK];
uint8_t out[CHUNK];
lzma_ret ret;
do {
if (strm.avail_in == 0 && size > 0) {
const size_t amount = MIN(size, CHUNK);
strm.avail_in = fread(in, 1, amount, file_in);
strm.next_in = in;
size -= amount; // Intentionally not using avail_in.
}
strm.next_out = out;
strm.avail_out = CHUNK;
ret = lzma_code(&strm, size == 0 ? action : LZMA_RUN);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
fprintf(stderr, "%s:%u: %s: ret == %d\n",
__FILE__, __LINE__, __func__, ret);
exit(1);
}
fwrite(out, 1, CHUNK - strm.avail_out, stdout);
} while (size > 0 || strm.avail_out == 0);
if ((action == LZMA_RUN && ret != LZMA_OK)
|| (action != LZMA_RUN && ret != LZMA_STREAM_END)) {
fprintf(stderr, "%s:%u: %s: ret == %d\n",
__FILE__, __LINE__, __func__, ret);
exit(1);
}
}
int
main(int argc, char **argv)
{
lzma_init_encoder();
file_in = argc > 1 ? fopen(argv[1], "rb") : stdin;
// Config
lzma_filter filters[LZMA_BLOCK_FILTERS_MAX + 1];
filters[0].id = LZMA_FILTER_LZMA2;
filters[0].options = (void *)&lzma_preset_lzma[0];
filters[1].id = LZMA_VLI_VALUE_UNKNOWN;
// Init
if (lzma_stream_encoder(&strm, filters, LZMA_CHECK_SHA256) != LZMA_OK) {
fprintf(stderr, "init failed\n");
exit(1);
}
// if (lzma_easy_encoder(&strm, 1)) {
// fprintf(stderr, "init failed\n");
// exit(1);
// }
// Encoding
encode(0, LZMA_FULL_FLUSH);
encode(6, LZMA_FULL_FLUSH);
encode(0, LZMA_FULL_FLUSH);
encode(7, LZMA_FULL_FLUSH);
encode(0, LZMA_FULL_FLUSH);
encode(0, LZMA_FINISH);
// Clean up
lzma_end(&strm);
return 0;
}

54
debug/hex2bin.c Normal file
View File

@@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file hex2bin.c
/// \brief Converts hexadecimal input strings to binary
//
// This code has been put into the public domain.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <stdio.h>
#include <ctype.h>
static int
getbin(int x)
{
if (x >= '0' && x <= '9')
return x - '0';
if (x >= 'A' && x <= 'F')
return x - 'A' + 10;
return x - 'a' + 10;
}
int
main(void)
{
while (true) {
int byte = getchar();
if (byte == EOF)
return 0;
if (!isxdigit(byte))
continue;
const int digit = getchar();
if (digit == EOF || !isxdigit(digit)) {
fprintf(stderr, "Invalid input\n");
return 1;
}
byte = (getbin(byte) << 4) | getbin(digit);
if (putchar(byte) == EOF) {
perror(NULL);
return 1;
}
}
}

135
debug/known_sizes.c Normal file
View File

@@ -0,0 +1,135 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file known_sizes.c
/// \brief Encodes .lzma Stream with sizes known in Block Header
///
/// The input file is encoded in RAM, and the known Compressed Size
/// and/or Uncompressed Size values are stored in the Block Header.
/// As of writing there's no such Stream encoder in liblzma.
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include <stdio.h>
// Support file sizes up to 1 MiB. We use this for output space too, so files
// close to 1 MiB had better compress at least a little or we have a buffer
// overflow.
#define BUFFER_SIZE (1U << 20)
int
main(void)
{
// Allocate the buffers.
uint8_t *in = malloc(BUFFER_SIZE);
uint8_t *out = malloc(BUFFER_SIZE);
if (in == NULL || out == NULL)
return 1;
// Fill the input buffer.
const size_t in_size = fread(in, 1, BUFFER_SIZE, stdin);
// Filter setup
lzma_filter filters[] = {
{
.id = LZMA_FILTER_LZMA2,
.options = (void *)(&lzma_preset_lzma[0])
},
{
.id = LZMA_VLI_VALUE_UNKNOWN
}
};
lzma_block block = {
.check = LZMA_CHECK_CRC32,
.compressed_size = BUFFER_SIZE, // Worst case reserve
.uncompressed_size = in_size,
.filters = filters,
};
// FIXME Insane paranoia in liblzma.
if (lzma_block_header_size(&block) != LZMA_OK)
return 1;
// We don't actually know the compressed size, so don't tell it to
// Block encoder.
block.compressed_size = LZMA_VLI_VALUE_UNKNOWN;
lzma_stream strm = LZMA_STREAM_INIT;
if (lzma_block_encoder(&strm, &block) != LZMA_OK)
return 1;
// Reserve space for Stream Header and Block Header.
size_t out_size = LZMA_STREAM_HEADER_SIZE + block.header_size;
strm.next_in = in;
strm.avail_in = in_size;
strm.next_out = out + out_size;
strm.avail_out = BUFFER_SIZE - out_size;
if (lzma_code(&strm, LZMA_FINISH) != LZMA_STREAM_END)
return 1;
out_size += strm.total_out;
if (lzma_block_header_encode(&block, out + LZMA_STREAM_HEADER_SIZE)
!= LZMA_OK)
return 1;
lzma_index *idx = lzma_index_init(NULL, NULL);
if (idx == NULL)
return 1;
if (lzma_index_append(idx, NULL, block.header_size + strm.total_out,
strm.total_in) != LZMA_OK)
return 1;
if (lzma_index_encoder(&strm, idx) != LZMA_OK)
return 1;
if (lzma_code(&strm, LZMA_RUN) != LZMA_STREAM_END)
return 1;
out_size += strm.total_out;
lzma_end(&strm);
lzma_index_end(idx, NULL);
// Encode the Stream Header and Stream Footer. backwards_size is
// needed only for the Stream Footer.
lzma_stream_flags sf = {
.backward_size = strm.total_out,
.check = block.check,
};
if (lzma_stream_header_encode(&sf, out) != LZMA_OK)
return 1;
if (lzma_stream_footer_encode(&sf, out + out_size) != LZMA_OK)
return 1;
out_size += LZMA_STREAM_HEADER_SIZE;
// Write out the file.
fwrite(out, 1, out_size, stdout);
return 0;
}

57
debug/memusage.c Normal file
View File

@@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file memusage.c
/// \brief Calculates memory usage using lzma_memory_usage()
///
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <stdio.h>
int
main(void)
{
lzma_init();
lzma_options_lzma lzma = {
.dictionary_size = (1 << 27) + (1 << 26),
.literal_context_bits = 3,
.literal_pos_bits = 0,
.pos_bits = 2,
.preset_dictionary = NULL,
.preset_dictionary_size = 0,
.mode = LZMA_MODE_NORMAL,
.fast_bytes = 48,
.match_finder = LZMA_MF_BT4,
.match_finder_cycles = 0,
};
/*
lzma_options_filter filters[] = {
{ LZMA_FILTER_LZMA,
(lzma_options_lzma *)&lzma_preset_lzma[6 - 1] },
{ UINT64_MAX, NULL }
};
*/
lzma_filter filters[] = {
{ LZMA_FILTER_LZMA, &lzma },
{ UINT64_MAX, NULL }
};
printf("Encoder: %10" PRIu64 " B\n", lzma_memusage_encoder(filters));
printf("Decoder: %10" PRIu64 " B\n", lzma_memusage_decoder(filters));
return 0;
}

View File

@@ -1,9 +1,13 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file raw_decoder.h
/// \brief Raw decoder initialization API
/// \file repeat.c
/// \brief Repeats given string given times
///
/// This program can be useful when debugging run-length encoder in
/// the Subblock filter, especially the condition when repeat count
/// doesn't fit into 28-bit integer.
//
// Copyright (C) 2007 Lasse Collin
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -17,14 +21,23 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_RAW_DECODER_H
#define LZMA_RAW_DECODER_H
#include "raw_common.h"
#include "sysdefs.h"
#include <stdio.h>
extern lzma_ret lzma_raw_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_options_filter *options,
lzma_vli uncompressed_size, bool implicit);
int
main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "Usage: %s COUNT STRING\n", argv[0]);
exit(1);
}
#endif
unsigned long long count = strtoull(argv[1], NULL, 10);
const size_t size = strlen(argv[2]);
while (count-- != 0)
fwrite(argv[2], 1, size, stdout);
return !!(ferror(stdout) || fclose(stdout));
}

141
debug/sync_flush.c Normal file
View File

@@ -0,0 +1,141 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file sync_flush.c
/// \brief Encode files using LZMA_SYNC_FLUSH
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <stdio.h>
static lzma_stream strm = LZMA_STREAM_INIT;
static FILE *file_in;
static void
encode(size_t size, lzma_action action)
{
static const size_t CHUNK = 64;
uint8_t in[CHUNK];
uint8_t out[CHUNK];
lzma_ret ret;
do {
if (strm.avail_in == 0 && size > 0) {
const size_t amount = MIN(size, CHUNK);
strm.avail_in = fread(in, 1, amount, file_in);
strm.next_in = in;
size -= amount; // Intentionally not using avail_in.
}
strm.next_out = out;
strm.avail_out = CHUNK;
ret = lzma_code(&strm, size == 0 ? action : LZMA_RUN);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
fprintf(stderr, "%s:%u: %s: ret == %d\n",
__FILE__, __LINE__, __func__, ret);
exit(1);
}
fwrite(out, 1, CHUNK - strm.avail_out, stdout);
} while (size > 0 || strm.avail_out == 0);
if ((action == LZMA_RUN && ret != LZMA_OK)
|| (action != LZMA_RUN && ret != LZMA_STREAM_END)) {
fprintf(stderr, "%s:%u: %s: ret == %d\n",
__FILE__, __LINE__, __func__, ret);
exit(1);
}
}
int
main(int argc, char **argv)
{
lzma_init_encoder();
file_in = argc > 1 ? fopen(argv[1], "rb") : stdin;
// Config
lzma_options_lzma opt_lzma = {
.dictionary_size = 1 << 16,
.literal_context_bits = LZMA_LITERAL_CONTEXT_BITS_DEFAULT,
.literal_pos_bits = LZMA_LITERAL_POS_BITS_DEFAULT,
.pos_bits = LZMA_POS_BITS_DEFAULT,
.preset_dictionary = NULL,
.persistent = true,
.mode = LZMA_MODE_NORMAL,
.fast_bytes = 32,
.match_finder = LZMA_MF_HC3,
.match_finder_cycles = 0,
};
lzma_options_delta opt_delta = {
.distance = 16
};
lzma_options_subblock opt_subblock = {
.allow_subfilters = true,
.alignment = 8, // LZMA_SUBBLOCK_ALIGNMENT_DEFAULT,
.subblock_data_size = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT,
.rle = 1, // LZMA_SUBBLOCK_RLE_OFF,
.subfilter_mode = LZMA_SUBFILTER_SET,
};
opt_subblock.subfilter_options.id = LZMA_FILTER_LZMA;
opt_subblock.subfilter_options.options = &opt_lzma;
opt_subblock.subfilter_options.id = LZMA_FILTER_DELTA;
opt_subblock.subfilter_options.options = &opt_delta;
lzma_filter filters[LZMA_BLOCK_FILTERS_MAX + 1];
filters[0].id = LZMA_FILTER_LZMA2;
filters[0].options = &opt_lzma;
filters[1].id = LZMA_VLI_VALUE_UNKNOWN;
// Init
if (lzma_stream_encoder(&strm, filters, LZMA_CHECK_CRC32) != LZMA_OK) {
fprintf(stderr, "init failed\n");
exit(1);
}
// Encoding
/*
encode(0, LZMA_SYNC_FLUSH);
encode(6, LZMA_SYNC_FLUSH);
encode(0, LZMA_SYNC_FLUSH);
encode(7, LZMA_SYNC_FLUSH);
encode(0, LZMA_SYNC_FLUSH);
encode(0, LZMA_FINISH);
*/
encode(53, LZMA_SYNC_FLUSH);
// opt_lzma.literal_context_bits = 2;
// opt_lzma.literal_pos_bits = 1;
// opt_lzma.pos_bits = 0;
encode(404, LZMA_FINISH);
// Clean up
lzma_end(&strm);
return 0;
// Prevent useless warnings so we don't need to have special CFLAGS
// to disable -Werror.
(void)opt_lzma;
(void)opt_subblock;
(void)opt_delta;
}

View File

@@ -80,8 +80,8 @@ Q: Which file formats are supported by LZMA Utils?
A: Even when the raw LZMA stream is always the same, it can be wrapped
in different container formats. The preferred format is the new .lzma
format. It has magic bytes (the first six bytes: 0xFF 'L' 'Z' 'M'
'A' 0x00). The format supports chaining up to seven filters filters,
splitting data to multiple blocks for easier multi-threading and rough
'A' 0x00). The format supports chaining up to seven filters, splitting
data to multiple blocks for easier multi-threading and rough
random-access reading. The file integrity is verified using CRC32,
CRC64, or SHA256, and by verifying the uncompressed size of the file.

File diff suppressed because it is too large Load Diff

View File

@@ -247,7 +247,7 @@ y.x.1. Single-Block Stream
this prevents it from producing too much output in case of (possibly
intentionally) corrupt file.
Calculate the the start offset of the Stream:
Calculate the start offset of the Stream:
backward_offset - backward_size - LZMA_STREAM_HEADER_SIZE

View File

@@ -5,8 +5,14 @@ Introduction to liblzma
Writing applications to work with liblzma
liblzma API is split in several subheaders to improve readability and
maintainance. The subheaders must not be #included directly; simply
use `#include <lzma.h>' instead.
maintainance. The subheaders must not be #included directly. lzma.h
requires that certain integer types and macros are available when
the header is #included. On systems that have inttypes.h that conforms
to C99, the following will work:
#include <sys/types.h>
#include <inttypes.h>
#include <lzma.h>
Those who have used zlib should find liblzma's API easy to use.
To developers who haven't used zlib before, I recommend learning

View File

@@ -86,8 +86,8 @@ Using liblzma securely
The simplest solution is to use setrlimit() if the kernel supports
RLIMIT_AS, which limits the memory usage of the whole process.
For more portable and fine-grained limitting, you can use
memory limitter functions found from <lzma/memlimit.h>.
For more portable and fine-grained limiting, you can use
memory limiter functions found from <lzma/memlimit.h>.
1.2.1. Encoder
@@ -118,24 +118,24 @@ Using liblzma securely
1.2.2. Decoder
A single-threaded decoder should simply use a memory limitter and
A single-threaded decoder should simply use a memory limiter and
indicate an error if it runs out of memory.
Memory-limitting with multi-threaded decoding is tricky. The simple
Memory-limiting with multi-threaded decoding is tricky. The simple
solution is to divide the maximum allowed memory usage with the
maximum allowed threads, and give each Block decoder their own
independent lzma_memory_limitter. The drawback is that if one Block
independent lzma_memory_limiter. The drawback is that if one Block
needs notably more RAM than any other Block, the decoder will run out
of memory when in reality there would be plenty of free RAM.
An attractive alternative would be using shared lzma_memory_limitter.
An attractive alternative would be using shared lzma_memory_limiter.
Depending on the application and the expected type of input, this may
either be the best solution or a source of hard-to-repeat problems.
Consider the following requirements:
- You use at maximum of n threads.
- You use a maximum of n threads.
- x(i) is the decoder memory requirements of the Block number i
in an expected input Stream.
- The memory limitter is set to higher value than the sum of n
- The memory limiter is set to higher value than the sum of n
highest values x(i).
(If you are better at explaining the above conditions, please
@@ -150,7 +150,7 @@ Using liblzma securely
Most .lzma files have all the Blocks encoded with identical settings,
or at least the memory usage won't vary dramatically. That's why most
multi-threaded decoders probably want to use the simple "separate
lzma_memory_limitter for each thread" solution, possibly fallbacking
lzma_memory_limiter for each thread" solution, possibly falling back
to single-threaded mode in case the per-thread memory limits aren't
enough in multi-threaded mode.
@@ -206,7 +206,7 @@ FIXME: Memory usage of Stream info.
creating a denial of service like piping decoded a Data Block to
another process would do.
At first it would seem that using a memory limitter would prevent
At first it would seem that using a memory limiter would prevent
this issue as a side effect. But it does so only if the application
requests liblzma to allocate the Extra Records and provide them to
the application. If Extra Records aren't requested, they aren't

View File

@@ -15,19 +15,11 @@
## Not using gnulib-tool, at least for now. Less mess this way.
## We need two builds of libgnu: one with NLS and one without.
## This is because lzma uses NLS but lzmadec doesn't, while
## both need GNU getopt_long().
noinst_LIBRARIES = libgnu.a libgnu_nls.a
noinst_LIBRARIES = libgnu.a
libgnu_a_SOURCES =
libgnu_a_DEPENDENCIES = $(LIBOBJS)
libgnu_a_LIBADD = $(LIBOBJS)
libgnu_a_CPPFLAGS = -DDISABLE_NLS=1
libgnu_nls_a_SOURCES =
libgnu_nls_a_DEPENDENCIES = $(LIBOBJS)
libgnu_nls_a_LIBADD = $(LIBOBJS)
EXTRA_DIST = gettext.h getopt_.h getopt.c getopt1.c getopt_int.h
BUILT_SOURCES = $(GETOPT_H)

View File

@@ -5,7 +5,7 @@ msgid ""
msgstr ""
"Project-Id-Version: fi\n"
"Report-Msgid-Bugs-To: lasse.collin@tukaani.org\n"
"POT-Creation-Date: 2007-12-10 14:34+0200\n"
"POT-Creation-Date: 2008-01-07 21:30+0200\n"
"PO-Revision-Date: 2007-08-09 22:14+0300\n"
"Last-Translator: Lasse Collin <lasse.collin@tukaani.org>\n"
"Language-Team: Finnish\n"
@@ -124,14 +124,14 @@ msgstr ""
msgid "With no FILE, or when FILE is -, read standard input.\n"
msgstr "Jos TIEDOSTOa ei ole annettu, tai se on \"-\", luetaan vakiosyötettä.\n"
#: src/lzma/help.c:143
#: src/lzma/help.c:144
msgid "On this system and configuration, the tool will use"
msgstr "Tässä järjestelmässä näillä asetuksilla, tämä työkalu käyttää"
#: src/lzma/help.c:144
#: src/lzma/help.c:145
#, c-format
msgid " * roughly %zu MiB of memory at maximum; and\n"
msgstr " * korkeintaan %zu MiB keskusmuistia (suurpiirteinen rajoitus); ja\n"
msgid " * roughly %<PRIu64> MiB of memory at maximum; and\n"
msgstr " * korkeintaan %<PRIu64> MiB keskusmuistia (suurpiirteinen rajoitus); ja\n"
#: src/lzma/help.c:147
msgid ""
@@ -141,7 +141,7 @@ msgstr ""
" * korkeintaan yhtä säiettä pakkaukseen tai purkuun.\n"
"\n"
#: src/lzma/help.c:151
#: src/lzma/help.c:152
#, c-format
msgid "Report bugs to <%s> (in English or Finnish).\n"
msgstr ""

View File

@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file check_byteswap.h
/// \brief Byteswapping needed by the checks
/// \file bswap.h
/// \brief Byte swapping
//
// This code has been put into the public domain.
//
@@ -11,18 +11,19 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_CHECK_BYTESWAP_H
#define LZMA_CHECK_BYTESWAP_H
#ifndef LZMA_BSWAP_H
#define LZMA_BSWAP_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
// NOTE: We assume that config.h is already #included.
// byteswap.h is a GNU extension. It contains inline assembly versions
// for byteswapping. When byteswap.h is not available, we use generic code.
#ifdef HAVE_BYTESWAP_H
# include <byteswap.h>
#else
# define bswap_16(num) \
(((num) << 8) | ((num) >> 8))
# define bswap_32(num) \
( (((num) << 24) ) \
| (((num) << 8) & UINT32_C(0x00FF0000)) \

167
src/common/integer.h Normal file
View File

@@ -0,0 +1,167 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file integer.h
/// \brief Reading and writing integers from and to buffers
//
// This code has been put into the public domain.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_INTEGER_H
#define LZMA_INTEGER_H
// I'm aware of AC_CHECK_ALIGNED_ACCESS_REQUIRED from Autoconf archive, but
// it's not useful here. We don't care if unaligned access is supported,
// we care if it is fast. Some systems can emulate unaligned access in
// software, which is horribly slow; we want to use byte-by-byte access on
// such systems but the Autoconf test would detect such a system as
// supporting unaligned access.
//
// NOTE: HAVE_FAST_UNALIGNED_ACCESS indicates only support for 16-bit and
// 32-bit integer loads and stores. 64-bit integers may or may not work.
// That's why 64-bit functions are commented out.
#ifdef HAVE_FAST_UNALIGNED_ACCESS
// On big endian, we need byte swapping.
//
// TODO: Big endian PowerPC supports byte swapping load and store instructions
// that also allow unaligned access. Inline assembler could be OK for that.
#ifdef WORDS_BIGENDIAN
# include "bswap.h"
# define integer_le_16(n) bswap_16(n)
# define integer_le_32(n) bswap_32(n)
# define integer_le_64(n) bswap_64(n)
#else
# define integer_le_16(n) (n)
# define integer_le_32(n) (n)
# define integer_le_64(n) (n)
#endif
static inline uint16_t
integer_read_16(const uint8_t buf[static 2])
{
uint16_t ret = *(const uint16_t *)(buf);
return integer_le_16(ret);
}
static inline uint32_t
integer_read_32(const uint8_t buf[static 4])
{
uint32_t ret = *(const uint32_t *)(buf);
return integer_le_32(ret);
}
/*
static inline uint64_t
integer_read_64(const uint8_t buf[static 8])
{
uint64_t ret = *(const uint64_t *)(buf);
return integer_le_64(ret);
}
*/
static inline void
integer_write_16(uint8_t buf[static 2], uint16_t num)
{
*(uint16_t *)(buf) = integer_le_16(num);
}
static inline void
integer_write_32(uint8_t buf[static 4], uint32_t num)
{
*(uint32_t *)(buf) = integer_le_32(num);
}
/*
static inline void
integer_write_64(uint8_t buf[static 8], uint64_t num)
{
*(uint64_t *)(buf) = integer_le_64(num);
}
*/
#else
static inline uint16_t
integer_read_16(const uint8_t buf[static 2])
{
uint16_t ret = buf[0] | (buf[1] << 8);
return ret;
}
static inline uint32_t
integer_read_32(const uint8_t buf[static 4])
{
uint32_t ret = buf[0];
ret |= (uint32_t)(buf[1]) << 8;
ret |= (uint32_t)(buf[2]) << 16;
ret |= (uint32_t)(buf[3]) << 24;
return ret;
}
/*
static inline uint64_t
integer_read_64(const uint8_t buf[static 8])
{
uint64_t ret = buf[0];
ret |= (uint64_t)(buf[1]) << 8;
ret |= (uint64_t)(buf[2]) << 16;
ret |= (uint64_t)(buf[3]) << 24;
ret |= (uint64_t)(buf[4]) << 32;
ret |= (uint64_t)(buf[5]) << 40;
ret |= (uint64_t)(buf[6]) << 48;
ret |= (uint64_t)(buf[7]) << 56;
return ret;
}
*/
static inline void
integer_write_16(uint8_t buf[static 2], uint16_t num)
{
buf[0] = (uint8_t)(num);
buf[1] = (uint8_t)(num >> 8);
}
static inline void
integer_write_32(uint8_t buf[static 4], uint32_t num)
{
buf[0] = (uint8_t)(num);
buf[1] = (uint8_t)(num >> 8);
buf[2] = (uint8_t)(num >> 16);
buf[3] = (uint8_t)(num >> 24);
}
/*
static inline void
integer_write_64(uint8_t buf[static 8], uint64_t num)
{
buf[0] = (uint8_t)(num);
buf[1] = (uint8_t)(num >> 8);
buf[2] = (uint8_t)(num >> 16);
buf[3] = (uint8_t)(num >> 24);
buf[4] = (uint8_t)(num >> 32);
buf[5] = (uint8_t)(num >> 40);
buf[6] = (uint8_t)(num >> 48);
buf[7] = (uint8_t)(num >> 56);
}
*/
#endif
#endif

View File

@@ -14,17 +14,6 @@
#ifndef PHYSMEM_H
#define PHYSMEM_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <inttypes.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#if defined(HAVE_PHYSMEM_SYSCTL) || defined(HAVE_NCPU_SYSCTL)
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>

View File

@@ -31,10 +31,97 @@
# include <config.h>
#endif
#include "lzma.h"
// size_t and NULL
#include <stddef.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
// C99 says that inttypes.h always includes stdint.h, but some systems
// don't do that, and require including stdint.h separately.
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
// Some pre-C99 systems have SIZE_MAX in limits.h instead of stdint.h. The
// limits are also used to figure out some macros missing from pre-C99 systems.
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
// Be more compatible with systems that have non-conforming inttypes.h.
// We assume that int is 32-bit and that long is either 32-bit or 64-bit.
// Full Autoconf test could be more correct, but this should work well enough.
// Note that this duplicates some code from lzma.h, but this is better since
// we can work without inttypes.h thanks to Autoconf tests.
#ifndef UINT32_C
# if UINT_MAX != 4294967295U
# error UINT32_C is not defined and unsiged int is not 32-bit.
# endif
# define UINT32_C(n) n ## U
#endif
#ifndef UINT32_MAX
# define UINT32_MAX UINT32_C(4294967295)
#endif
#ifndef PRIu32
# define PRIu32 "u"
#endif
#ifndef PRIX32
# define PRIX32 "X"
#endif
#if ULONG_MAX == 4294967295UL
# ifndef UINT64_C
# define UINT64_C(n) n ## ULL
# endif
# ifndef PRIu64
# define PRIu64 "llu"
# endif
# ifndef PRIX64
# define PRIX64 "llX"
# endif
#else
# ifndef UINT64_C
# define UINT64_C(n) n ## UL
# endif
# ifndef PRIu64
# define PRIu64 "lu"
# endif
# ifndef PRIX64
# define PRIX64 "lX"
# endif
#endif
#ifndef UINT64_MAX
# define UINT64_MAX UINT64_C(18446744073709551615)
#endif
// The code currently assumes that size_t is either 32-bit or 64-bit.
#ifndef SIZE_MAX
# if SIZEOF_SIZE_T == 4
# define SIZE_MAX UINT32_MAX
# elif SIZEOF_SIZE_T == 8
# define SIZE_MAX UINT64_MAX
# else
# error sizeof(size_t) is not 32-bit or 64-bit
# endif
#endif
#if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
# error sizeof(size_t) is not 32-bit or 64-bit
#endif
#include <stdlib.h>
// Pre-C99 systems lack stdbool.h. All the code in LZMA Utils must be written
// so that it works with fake bool type, for example:
//
// bool foo = (flags & 0x100) != 0;
// bool bar = !!(flags & 0x100);
//
// This works with the real C99 bool but breaks with fake bool:
//
// bool baz = (flags & 0x100);
//
#ifdef HAVE_STDBOOL_H
# include <stdbool.h>
#else
@@ -53,11 +140,13 @@ typedef unsigned char _Bool;
# ifdef NDEBUG
# define assert(x)
# else
// TODO: Pretty bad assert() macro.
// TODO: Pretty bad assert macro.
# define assert(x) (!(x) && abort())
# endif
#endif
// string.h should be enough but let's include strings.h and memory.h too if
// they exists, since that shouldn't do any harm, but may improve portability.
#ifdef HAVE_STRING_H
# include <string.h>
#endif
@@ -70,24 +159,15 @@ typedef unsigned char _Bool;
# include <memory.h>
#endif
#include "lzma.h"
////////////
// Macros //
////////////
#ifndef HAVE_MEMCPY
# define memcpy(dest, src, n) bcopy(src, dest, n)
#endif
#ifndef HAVE_MEMMOVE
# define memmove(dest, src, n) bcopy(src, dest, n)
#endif
#ifdef HAVE_MEMSET
# define memzero(s, n) memset(s, 0, n)
#else
# define memzero(s, n) bzero(s, n)
#endif
#undef memzero
#define memzero(s, n) memset(s, 0, n)
#ifndef MIN
# define MIN(x, y) ((x) < (y) ? (x) : (y))
@@ -97,4 +177,8 @@ typedef unsigned char _Bool;
# define MAX(x, y) ((x) > (y) ? (x) : (y))
#endif
#ifndef ARRAY_SIZE
# define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
#endif
#endif

View File

@@ -22,11 +22,15 @@ liblzma_la_LIBADD = \
common/libcommon.la \
check/libcheck.la
if COND_FILTER_LZ
SUBDIRS += lz
liblzma_la_LIBADD += lz/liblz.la
endif
if COND_FILTER_LZMA
SUBDIRS += lz lzma rangecoder
SUBDIRS += lzma rangecoder
liblzma_la_LIBADD += \
lz/liblz.la \
lzma/liblzma4.la \
lzma/liblzma2.la \
rangecoder/librangecoder.la
endif
@@ -35,7 +39,12 @@ SUBDIRS += subblock
liblzma_la_LIBADD += subblock/libsubblock.la
endif
if COND_MAIN_SIMPLE
if COND_FILTER_DELTA
SUBDIRS += delta
liblzma_la_LIBADD += delta/libdelta.la
endif
if COND_FILTER_SIMPLE
SUBDIRS += simple
liblzma_la_LIBADD += simple/libsimple.la
endif

View File

@@ -15,24 +15,18 @@
nobase_include_HEADERS = \
lzma.h \
lzma/alignment.h \
lzma/alone.h \
lzma/auto.h \
lzma/base.h \
lzma/block.h \
lzma/check.h \
lzma/copy.h \
lzma/container.h \
lzma/delta.h \
lzma/extra.h \
lzma/filter.h \
lzma/index.h \
lzma/info.h \
lzma/index_hash.h \
lzma/init.h \
lzma/lzma.h \
lzma/memlimit.h \
lzma/metadata.h \
lzma/raw.h \
lzma/simple.h \
lzma/stream.h \
lzma/stream_flags.h \
lzma/subblock.h \
lzma/version.h \

View File

@@ -22,18 +22,97 @@
#ifndef LZMA_H
#define LZMA_H
/********************
* External headers *
********************/
/*****************************
* Required standard headers *
*****************************/
/* size_t */
#include <sys/types.h>
/**
* liblzma API headers need some standard types and macros. To allow
* including lzma.h without requiring the application to include other
* headers first, lzma.h includes the required standard headers unless
* they already seem to be included.
*
* Here's what types and macros are needed and from which headers:
* - stddef.h: size_t, NULL
* - stdint.h: uint8_t, uint32_t, uint64_t, UINT32_C(n), uint64_C(n),
* UINT32_MAX, UINT64_MAX
*
* However, inttypes.h is a little more portable than stdint.h, although
* inttypes.h declares some unneeded things compared to plain stdint.h.
*
* The hacks below aren't perfect, specifically they assume that inttypes.h
* exists and that it typedefs at least uint8_t, uint32_t, and uint64_t,
* and that unsigned int is 32-bit. If your application already takes care
* of setting up all the types properly (for example by using gnulib's
* stdint.h or inttypes.h), feel free to define LZMA_MANUAL_HEADERS before
* including lzma.h.
*
* Some could argue that liblzma API should provide all the required types,
* for example lzma_uint64, LZMA_UINT64_C(n), and LZMA_UINT64_MAX. This was
* seen unnecessary mess, since most systems already provide all the necessary
* types and macros in the standard headers.
*
* Note that liblzma API still has lzma_bool, because using stdbool.h would
* break C89 and C++ programs on many systems.
*/
/* NULL */
/* stddef.h even in C++ so that we get size_t in global namespace. */
#include <stddef.h>
/* uint8_t, uint32_t, uint64_t, UINT32_C, UINT64_C, UINT64_MAX. */
#include <inttypes.h>
#if !defined(UINT32_C) || !defined(UINT64_C) \
|| !defined(UINT32_MAX) || !defined(UINT64_MAX)
# ifdef __cplusplus
/*
* C99 sections 7.18.2 and 7.18.4 specify that in C++
* implementations define the limit and constant macros only
* if specifically requested. Note that if you want the
* format macros too, you need to define __STDC_FORMAT_MACROS
* before including lzma.h, since re-including inttypes.h
* with __STDC_FORMAT_MACROS defined doesn't necessarily work.
*/
# ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS 1
# endif
# ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS 1
# endif
# endif
# include <inttypes.h>
/*
* Some old systems have only the typedefs in inttypes.h, and lack
* all the macros. For those systems, we need a few more hacks.
* We assume that unsigned int is 32-bit and unsigned long is either
* 32-bit or 64-bit. If these hacks aren't enough, the application
* has to use setup the types manually before including lzma.h.
*/
# ifndef UINT32_C
# define UINT32_C(n) n # U
# endif
# ifndef UINT64_C
/* Get ULONG_MAX. */
# ifndef __cplusplus
# include <limits.h>
# else
# include <climits>
# endif
# if ULONG_MAX == 4294967295UL
# define UINT64_C(n) n ## ULL
# else
# define UINT64_C(n) n ## UL
# endif
# endif
# ifndef UINT32_MAX
# define UINT32_MAX (UINT32_C(4294967295))
# endif
# ifndef UINT64_MAX
# define UINT64_MAX (UINT64_C(18446744073709551615))
# endif
#endif
/******************
@@ -45,20 +124,50 @@
* break anything if these are sometimes enabled and sometimes not, only
* affects warnings and optimizations.
*/
#if defined(__GNUC__) && __GNUC__ >= 3
#if __GNUC__ >= 3
# ifndef lzma_attribute
# define lzma_attribute(attr) __attribute__(attr)
# endif
# ifndef lzma_restrict
# define lzma_restrict __restrict__
# endif
/* warn_unused_result was added in GCC 3.4. */
# ifndef lzma_attr_warn_unused_result
# if __GNUC__ == 3 && __GNUC_MINOR__ < 4
# define lzma_attr_warn_unused_result
# endif
# endif
#else
# ifndef lzma_attribute
# define lzma_attribute(attr)
# endif
# ifndef lzma_restrict
# define lzma_restrict
# if __STDC_VERSION__ >= 199901L
# define lzma_restrict restrict
# else
# define lzma_restrict
# endif
# endif
# define lzma_attr_warn_unused_result
#endif
#ifndef lzma_attr_pure
# define lzma_attr_pure lzma_attribute((__pure__))
#endif
#ifndef lzma_attr_const
# define lzma_attr_const lzma_attribute((__const__))
#endif
#ifndef lzma_attr_warn_unused_result
# define lzma_attr_warn_unused_result \
lzma_attribute((__warn_unused_result__))
#endif
@@ -77,38 +186,30 @@ extern "C" {
#define LZMA_H_INTERNAL 1
/* Basic features */
#include "lzma/version.h"
#include "lzma/init.h"
#include "lzma/base.h"
#include "lzma/vli.h"
#include "lzma/filter.h"
#include "lzma/check.h"
/* Filters */
#include "lzma/copy.h"
#include "lzma/filter.h"
#include "lzma/subblock.h"
#include "lzma/simple.h"
#include "lzma/delta.h"
#include "lzma/lzma.h"
/* Container formats and Metadata */
#include "lzma/block.h"
#include "lzma/index.h"
#include "lzma/extra.h"
#include "lzma/metadata.h"
#include "lzma/stream.h"
#include "lzma/alone.h"
#include "lzma/raw.h"
#include "lzma/auto.h"
/* Container formats */
#include "lzma/container.h"
/* Advanced features */
#include "lzma/info.h"
#include "lzma/alignment.h"
#include "lzma/alignment.h" /* FIXME */
#include "lzma/block.h"
#include "lzma/index.h"
#include "lzma/index_hash.h"
#include "lzma/stream_flags.h"
#include "lzma/memlimit.h"
/* Version number */
#include "lzma/version.h"
/*
* All subheaders included. Undefine LZMA_H_INTERNAL to prevent applications
* re-including the subheaders.

View File

@@ -27,7 +27,7 @@
* FIXME desc
*/
extern uint32_t lzma_alignment_input(
const lzma_options_filter *filters, uint32_t guess);
const lzma_filter *filters, uint32_t guess);
/**
@@ -36,7 +36,7 @@ extern uint32_t lzma_alignment_input(
* Knowing the alignment of the output data is useful e.g. in the Block
* encoder which tries to align the Compressed Data field optimally.
*
* \param filters Pointer to lzma_options_filter array, whose last
* \param filters Pointer to lzma_filter array, whose last
* member must have .id = LZMA_VLI_VALUE_UNKNOWN.
* \param guess The value to return if the alignment of the output
* is the same as the alignment of the input data.
@@ -57,4 +57,4 @@ extern uint32_t lzma_alignment_input(
* options), UINT32_MAX is returned.
*/
extern uint32_t lzma_alignment_output(
const lzma_options_filter *filters, uint32_t guess);
const lzma_filter *filters, uint32_t guess);

View File

@@ -1,82 +0,0 @@
/**
* \file lzma/alone.h
* \brief Handling of the legacy LZMA_Alone format
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Options for files in the LZMA_Alone format
*/
typedef struct {
/**
* \brief Uncompressed Size and usage of End of Payload Marker
*
* In contrast to .lzma Blocks, LZMA_Alone format cannot have both
* uncompressed size field in the header and end of payload marker.
* If you don't know the uncompressed size beforehand, set it to
* LZMA_VLI_VALUE_UNKNOWN and liblzma will embed end of payload
* marker.
*/
lzma_vli uncompressed_size;
/**
* \brief LZMA options
*
* The LZMA_Alone format supports only one filter: the LZMA filter.
*
* \note There exists also an undocumented variant of the
* LZMA_Alone format, which uses the x86 filter in
* addition to LZMA. This format was never supported
* by LZMA Utils and is not supported by liblzma either.
*/
lzma_options_lzma lzma;
} lzma_options_alone;
/**
* \brief Initializes LZMA_Alone encoder
*
* LZMA_Alone files have the suffix .lzma like the .lzma Stream files.
* LZMA_Alone format supports only one filter, the LZMA filter. There is
* no support for integrity checks like CRC32.
*
* Use this format if and only if you need to create files readable by
* legacy LZMA tools.
*
* LZMA_Alone encoder doesn't support LZMA_SYNC_FLUSH or LZMA_FULL_FLUSH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_alone_encoder(
lzma_stream *strm, const lzma_options_alone *options);
/**
* \brief Initializes decoder for LZMA_Alone file
*
* The LZMA_Alone decoder supports LZMA_SYNC_FLUSH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
*/
extern lzma_ret lzma_alone_decoder(lzma_stream *strm);

View File

@@ -1,41 +0,0 @@
/**
* \file lzma/auto.h
* \brief Decoder with automatic file format detection
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Decode .lzma Streams and LZMA_Alone files with autodetection
*
* Autodetects between the .lzma Stream and LZMA_Alone formats, and
* calls lzma_stream_decoder_init() or lzma_alone_decoder_init() once
* the type of the file has been detected.
*
* \param strm Pointer to propertily prepared lzma_stream
* \param header Pointer to hold a pointer to Extra Records read
* from the Header Metadata Block. Use NULL if
* you don't care about Extra Records.
* \param footer Same as header, but for Footer Metadata Block.
*
* \return - LZMA_OK: Initialization was successful.
* - LZMA_MEM_ERROR: Cannot allocate memory.
*/
extern lzma_ret lzma_auto_decoder(lzma_stream *strm,
lzma_extra **header, lzma_extra **footer);

View File

@@ -33,28 +33,193 @@
typedef unsigned char lzma_bool;
/**
* \brief Type of reserved enumeration variable in structures
*
* To avoid breaking library ABI when new features are added, several
* structures contain extra variables that may be used in future. Since
* sizeof(enum) can be different than sizeof(int), and sizeof(enum) may
* even vary depending on the range of enumeration constants, we specify
* a separate type to be used for reserved enumeration variables. All
* enumeration constants in liblzma API will be non-negative and less
* than 128, which should guarantee that the ABI won't break even when
* new constants are added to existing enumerations.
*/
typedef enum {
LZMA_RESERVED_ENUM = 0
} lzma_reserved_enum;
/**
* \brief Return values used by several functions in liblzma
*
* Check the descriptions of specific functions to find out which return
* values they can return and the exact meanings of the values in every
* situation. The descriptions given here are only suggestive.
* values they can return. With some functions the return values may have
* more specific meanings than described here; those differences are
* described per-function basis.
*/
typedef enum {
LZMA_OK = 0,
LZMA_OK = 0,
/**<
* \brief Operation completed successfully
*/
LZMA_STREAM_END = 1,
LZMA_STREAM_END = 1,
/**<
* \brief End of stream was reached
*
* The application should pick the last remaining output
* bytes from strm->next_out.
* In encoder, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
* LZMA_FINISH was finished. In decoder, this indicates
* that all the data was successfully decoded.
*
* In all cases, when LZMA_STREAM_END is returned, the last
* output bytes should be picked from strm->next_out.
*/
LZMA_PROG_ERROR = -2,
LZMA_NO_CHECK = 2,
/**<
* \brief Input stream has no integrity check
*
* This return value can be returned only if the
* LZMA_TELL_NO_CHECK flag was used when initializing
* the decoder. LZMA_NO_CHECK is just a warning, and
* the decoding can be continued normally.
*
* It is possible to call lzma_get_check() immediatelly after
* lzma_code has returned LZMA_NO_CHECK. The result will
* naturally be LZMA_CHECK_NONE, but the possibility to call
* lzma_get_check() may be convenient in some applications.
*/
LZMA_UNSUPPORTED_CHECK = 3,
/**<
* \brief Cannot calculate the integrity check
*
* The usage of this return value is slightly different in
* encoders and decoders.
*
* Encoders can return this value only from the initialization
* function. If initialization fails with this value, the
* encoding cannot be done, because there's no way to produce
* output with the correct integrity check.
*
* Decoders can return this value only from the lzma_code
* function and only if the LZMA_TELL_UNSUPPORTED_CHECK flag
* was used when initializing the decoder. The decoding can
* still be continued normally even if the check type is
* unsupported, but naturally the check will not be validated,
* and possible errors may go undetected.
*
* With decoder, it is possible to call lzma_get_check()
* immediatelly after lzma_code has returned
* LZMA_UNSUPPORTED_CHECK. This way it is possible to find
* out what the unsupported Check ID was.
*/
LZMA_GET_CHECK = 4,
/**<
* \brief Integrity check type is now available
*
* This value can be returned only by the lzma_code() function
* and only if the decoder was initialized with the
* LZMA_TELL_ANY_CHECK flag. LZMA_GET_CHECK tells the
* application that it may now call lzma_get_check() to find
* out the Check ID. This can be used, for example, to
* implement a decoder that accepts only files that have
* strong enough integrity check.
*/
LZMA_MEM_ERROR = 5,
/**<
* \brief Cannot allocate memory
*
* Memory allocation failed, or the size of the allocation
* would be greater than SIZE_MAX.
*
* Due to lazy coding, the coding cannot be continued even
* if more memory were made available after LZMA_MEM_ERROR.
*/
LZMA_MEMLIMIT_ERROR = 6,
/**
* \brief Memory usage limit was reached
*
* Decoder would need more memory than allowed by the
* specified memory usage limit. To continue decoding,
* the memory usage limit has to be increased. See functions
* lzma_memlimit_get() and lzma_memlimit_set().
*/
LZMA_FORMAT_ERROR = 7,
/**<
* \brief Unknown file format
*
* The decoder did not recognize the input as supported file
* format. This error can occur, for example, when trying to
* decode LZMA_Alone format file with lzma_stream_decoder,
* because lzma_stream_decoder accepts only the new .lzma
* format.
*/
LZMA_HEADER_ERROR = 8,
/**<
* \brief Invalid or unsupported options
*
* Invalid or unsupported options, for example
* - unsupported filter(s) or filter options; or
* - reserved bits set in headers (decoder only).
*
* Rebuilding liblzma with more features enabled, or
* upgrading to a newer version of liblzma may help.
*/
LZMA_DATA_ERROR = 9,
/**<
* \brief Data is corrupt
*
* The usage of this return value is different in encoders
* and decoders. In both encoder and decoder, the coding
* cannot continue after this error.
*
* Encoders return this if size limits of the target file
* format would be exceeded. These limits are huge, thus
* getting this error from an encoder is mostly theoretical.
* For example, the maximum compressed and uncompressed
* size of a Stream created with lzma_stream_encoder is
* 2^63 - 1 bytes (one byte less than 8 EiB).
*
* Decoders return this error if the input data is corrupt.
* This can mean, for example, invalid CRC32 in headers
* or invalid check of uncompressed data.
*/
LZMA_BUF_ERROR = 10,
/**<
* \brief No progress is possible
*
* This error code is returned when the coder cannot consume
* any new input and produce any new output. The most common
* reason for this error is that the input stream being
* decoded is truncated or corrupt.
*
* This error is not fatal. Coding can be continued normally
* by providing more input and/or more output space, if
* possible.
*
* Typically the first call to lzma_code() that can do no
* progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only
* the second consecutive call doing no progress will return
* LZMA_BUF_ERROR. This is by design.
*
* With zlib, Z_BUF_ERROR may be returned even if the
* application is doing nothing wrong. The above hack
* guarantees that liblzma never returns LZMA_BUF_ERROR
* to properly written applications unless the input file
* is truncated or corrupt. This should simplify the
* applications a little.
*/
LZMA_PROG_ERROR = 11,
/**<
* \brief Programming error
*
@@ -73,70 +238,24 @@ typedef enum {
* can be a sign of a bug in liblzma. See the documentation
* how to report bugs.
*/
LZMA_DATA_ERROR = -3,
/**<
* \brief Data is corrupt
*
* - Encoder: The input size doesn't match the uncompressed
* size given to lzma_*_encoder_init().
* - Decoder: The input is corrupt. This includes corrupted
* header, corrupted compressed data, and unmatching
* integrity Check.
*
* \todo What can be done if encoder returns this?
* Probably can continue by fixing the input
* amount, but make sure.
*/
LZMA_MEM_ERROR = -4,
/**<
* \brief Cannot allocate memory
*
* Memory allocation failed.
*/
LZMA_BUF_ERROR = -5,
/**<
* \brief No progress is possible
*
* This may happen when avail_in or avail_out is zero.
*
* \note This error is not fatal. Coding can continue
* normally once the reason for this error has
* been fixed.
*/
LZMA_HEADER_ERROR = -6,
/**<
* \brief Invalid or unsupported header
*
* Invalid or unsupported options, for example
* - unsupported filter(s) or filter options; or
* - reserved bits set in headers (decoder only).
*
* Rebuilding liblzma with more features enabled, or
* upgrading to a newer version of liblzma may help.
*/
LZMA_UNSUPPORTED_CHECK = -7,
/**<
* \brief Check type is unknown
*
* The type of Check is not supported, and thus the Check
* cannot be calculated. In the encoder, this is an error.
* In the decoder, this is only a warning and decoding can
* still proceed normally (but the Check is ignored).
*/
} lzma_ret;
/**
* \brief The `action' argument for lzma_code()
*
* After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or LZMA_FINISH,
* the same `action' must is used until lzma_code() returns LZMA_STREAM_END.
* Also, the amount of input (that is, strm->avail_in) must not be modified
* by the application until lzma_code() returns LZMA_STREAM_END. Changing the
* `action' or modifying the amount of input will make lzma_code() return
* LZMA_PROG_ERROR.
*/
typedef enum {
LZMA_RUN = 0,
/**<
* \brief Continue coding
*
* Encoder: Encode as much input as possible. Some internal
* buffering will probably be done (depends on the filter
* chain in use), which causes latency: the input used won't
@@ -152,27 +271,37 @@ typedef enum {
LZMA_SYNC_FLUSH = 1,
/**<
* Encoder: Makes all the data given to liblzma via next_in
* available in next_out without resetting the filters. Call
* lzma_code() with LZMA_SYNC_FLUSH until it returns
* LZMA_STREAM_END. Then continue encoding normally.
* \brief Make all the input available at output
*
* \note Synchronous flushing is supported only by
* some filters. Some filters support it only
* partially.
* Normally the encoder introduces some latency.
* LZMA_SYNC_FLUSH forces all the buffered data to be
* available at output without resetting the internal
* state of the encoder. This way it is possible to use
* compressed stream for example for communication over
* network.
*
* Decoder: Asks the decoder to decode only as much as is
* needed to fill next_out. This decreases latency with some
* filters, but is likely to decrease also throughput. It is
* a good idea to use this flag only when it is likely that
* you don't need more output soon.
* Only some filters support LZMA_SYNC_FLUSH. Trying to use
* LZMA_SYNC_FLUSH with filters that don't support it will
* make lzma_code() return LZMA_HEADER_ERROR. For example,
* LZMA1 doesn't support LZMA_SYNC_FLUSH but LZMA2 does.
*
* \note With decoder, this is not comparable to
* zlib's Z_SYNC_FLUSH.
* Using LZMA_SYNC_FLUSH very often can dramatically reduce
* the compression ratio. With some filters (for example,
* LZMA2), finetuning the compression options may help
* mitigate this problem significantly.
*
* Decoders don't support LZMA_SYNC_FLUSH.
*/
LZMA_FULL_FLUSH = 2,
/**<
* \brief Make all the input available at output
*
* This is like LZMA_SYNC_FLUSH except that this resets the
* internal encoder state.
*
*
*
* Finishes encoding of the current Data Block. All the input
* data going to the current Data Block must have been given
* to the encoder (the last bytes can still be pending in
@@ -180,19 +309,30 @@ typedef enum {
* it returns LZMA_STREAM_END. Then continue normally with
* LZMA_RUN or finish the Stream with LZMA_FINISH.
*
* This action is supported only by Multi-Block Stream
* encoder. If there is no unfinished Data Block, no empty
* Data Block is created.
* This action is supported only by Stream encoder and easy
* encoder (which uses Stream encoder). If there is no
* unfinished Block, no empty Block is created.
*/
LZMA_FINISH = 3
/**<
* Finishes the encoding operation. All the input data must
* \brief Finish the coding operation
*
*
*
*
* Finishes the coding operation. All the input data must
* have been given to the encoder (the last bytes can still
* be pending in next_in). Call lzma_code() with LZMA_FINISH
* until it returns LZMA_STREAM_END.
* until it returns LZMA_STREAM_END. Once LZMA_FINISH has
* been used, the amount of input must no longer be changed
* by the application.
*
* This action is not supported by decoders.
* When decoding, using LZMA_FINISH is optional unless the
* LZMA_CONCATENATED flag was used when the decoder was
* initialized. When LZMA_CONCATENATED was not used, the only
* effect of LZMA_FINISH is that the amount of input must not
* be changed just like in the encoder.
*/
} lzma_action;
@@ -201,8 +341,10 @@ typedef enum {
* \brief Custom functions for memory handling
*
* A pointer to lzma_allocator may be passed via lzma_stream structure
* to liblzma. The library will use these functions for memory handling
* instead of the default malloc() and free().
* to liblzma, and some advanced function take pointer lzma_allocator as
* a separate function argument. The library will use the functions
* specified in lzma_allocator for memory handling instead of the default
* malloc() and free().
*
* liblzma doesn't make an internal copy of lzma_allocator. Thus, it is
* OK to change these function pointers in the middle of the coding
@@ -214,11 +356,6 @@ typedef struct {
/**
* \brief Pointer to custom memory allocation function
*
* Set this to point to your custom memory allocation function.
* It can be useful for example if you want to limit how much
* memory liblzma is allowed to use: for this, you may use
* a pointer to lzma_memory_alloc().
*
* If you don't want a custom allocator, but still want
* custom free(), set this to NULL and liblzma will use
* the standard malloc().
@@ -235,24 +372,32 @@ typedef struct {
* size nmemb * size, or NULL if allocation fails
* for some reason. When allocation fails, functions
* of liblzma return LZMA_MEM_ERROR.
*
* For performance reasons, the allocator should not waste time
* zeroing the allocated buffers. This is not only about speed, but
* also memory usage, since the operating system kernel doesn't
* necessarily allocate the requested memory until it is actually
* used. With small input files liblzma may actually need only a
* fraction of the memory that it requested for allocation.
*
* \note LZMA_MEM_ERROR is also used when the size of the
* allocation would be greater than SIZE_MAX. Thus,
* don't assume that the custom allocator must have
* returned NULL if some function from liblzma
* returns LZMA_MEM_ERROR.
*/
void *(*alloc)(void *opaque, size_t nmemb, size_t size);
/**
* \brief Pointer to custom memory freeing function
*
* Set this to point to your custom memory freeing function.
* If lzma_memory_alloc() is used as allocator, this should
* be set to lzma_memory_free().
*
* If you don't want a custom freeing function, but still
* want a custom allocator, set this to NULL and liblzma
* will use the standard free().
*
* \param opaque lzma_allocator.opaque (see below)
* \param ptr Pointer returned by
* lzma_allocator.alloc(), or when it
* is set to NULL, a pointer returned
* \param ptr Pointer returned by lzma_allocator.alloc(),
* or when it is set to NULL, a pointer returned
* by the standard malloc().
*/
void (*free)(void *opaque, void *ptr);
@@ -264,11 +409,7 @@ typedef struct {
* and lzma_allocator.free(). This intended to ease implementing
* custom memory allocation functions for use with liblzma.
*
* When using lzma_memory_alloc() and lzma_memory_free(), opaque
* must point to lzma_memory_limitter structure allocated and
* initialized with lzma_memory_limitter_create().
*
* If you don't need this, you should set it to NULL.
* If you don't need this, you should set this to NULL.
*/
void *opaque;
@@ -291,31 +432,33 @@ typedef struct lzma_internal_s lzma_internal;
* - defining custom memory hander functions; and
* - holding a pointer to coder-specific internal data structures.
*
* Before calling any of the lzma_*_init() functions the first time,
* the application must reset lzma_stream to LZMA_STREAM_INIT. The
* lzma_*_init() function will verify the options, allocate internal
* data structures and store pointer to them into `internal'. Finally
* total_in and total_out are reset to zero. In contrast to zlib,
* next_in and avail_in are ignored by the initialization functions.
* The typical usage
*
* The actual coding is done with the lzma_code() function. Application
* must update next_in, avail_in, next_out, and avail_out between
* calls to lzma_decode() just like with zlib.
* - After allocating lzma_stream (on stack or with malloc()), it must be
* initialized to LZMA_STREAM_INIT (see LZMA_STREAM_INIT for details).
*
* In contrast to zlib, even the decoder requires that there always
* is at least one byte space in next_out; if avail_out == 0,
* LZMA_BUF_ERROR is returned immediatelly. This shouldn't be a problem
* for most applications that already use zlib, but it's still worth
* checking your application.
* - Initialize a coder to the lzma_stream, for example by using
* lzma_easy_encoder() or lzma_auto_decoder(). In contrast to zlib,
* strm->next_in and strm->next_out are ignored by all initialization
* functions, thus it is safe to not initialize them yet. The
* initialization functions always set strm->total_in and strm->total_out
* to zero.
*
* - Use lzma_code() to do the actual work.
*
* - Once the coding has been finished, the existing lzma_stream can be
* reused. It is OK to reuse lzma_stream with different initialization
* function without calling lzma_end() first. Old allocations are
* automatically freed.
*
* - Finally, use lzma_end() to free the allocated memory.
*
* Application may modify values of total_in and total_out as it wants.
* They are updated by liblzma to match the amount of data read and
* written, but liblzma doesn't use the values internally.
*
* Application must not touch the `internal' pointer.
*/
typedef struct {
uint8_t *next_in; /**< Pointer to the next input byte. */
const uint8_t *next_in; /**< Pointer to the next input byte. */
size_t avail_in; /**< Number of available input bytes in next_in. */
uint64_t total_in; /**< Total number of bytes read by liblzma. */
@@ -329,9 +472,22 @@ typedef struct {
*/
lzma_allocator *allocator;
/** Internal state is not visible to outsiders. */
/** Internal state is not visible to applications. */
lzma_internal *internal;
/**
* Reserved space to allow possible future extensions without
* breaking the ABI. Excluding the initialization of this structure,
* you should not touch these, because the names of these variables
* may change.
*/
void *reserved_ptr1;
void *reserved_ptr2;
uint64_t reserved_int1;
uint64_t reserved_int2;
lzma_reserved_enum reserved_enum1;
lzma_reserved_enum reserved_enum2;
} lzma_stream;
@@ -343,58 +499,35 @@ typedef struct {
* has been allocated yet:
*
* lzma_stream strm = LZMA_STREAM_INIT;
*/
#define LZMA_STREAM_INIT { NULL, 0, 0, NULL, 0, 0, NULL, NULL }
/**
* \brief Initialization for lzma_stream
*
* This is like LZMA_STREAM_INIT, but this can be used when the lzma_stream
* has already been allocated:
* If you need to initialize a dynamically allocated lzma_stream, you can use
* memset(strm_pointer, 0, sizeof(lzma_stream)). Strictly speaking, this
* violates the C standard since NULL may have different internal
* representation than zero, but it should be portable enough in practice.
* Anyway, for maximum portability, you can use something like this:
*
* lzma_stream *strm = malloc(sizeof(lzma_stream));
* if (strm == NULL)
* return LZMA_MEM_ERROR;
* *strm = LZMA_STREAM_INIT_VAR;
* lzma_stream tmp = LZMA_STREAM_INIT;
* *strm = tmp;
*/
extern const lzma_stream LZMA_STREAM_INIT_VAR;
#define LZMA_STREAM_INIT \
{ NULL, 0, 0, NULL, 0, 0, NULL, NULL, NULL, NULL, 0, 0, 0, 0 }
/**
* \brief Encodes or decodes data
*
* Once the lzma_stream has been successfully initialized (e.g. with
* lzma_stream_encoder_single()), the actual encoding or decoding is
* done using this function.
* lzma_stream_encoder()), the actual encoding or decoding is done
* using this function. The application has to update strm->next_in,
* strm->avail_in, strm->next_out, and strm->avail_out to pass input
* to and get output from liblzma.
*
* \return Some coders may have more exact meaning for different return
* values, which are mentioned separately in the description of
* the initialization functions. Here are the typical meanings:
* - LZMA_OK: So far all good.
* - LZMA_STREAM_END:
* - Encoder: LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
* LZMA_FINISH completed.
* - Decoder: End of uncompressed data was reached.
* - LZMA_BUF_ERROR: Unable to progress. Provide more input or
* output space, and call this function again. This cannot
* occur if both avail_in and avail_out were non-zero (or
* there's a bug in liblzma).
* - LZMA_MEM_ERROR: Unable to allocate memory. Due to lazy
* programming, the coding cannot continue even if the
* application could free more memory. The next call must
* be lzma_end() or some initialization function.
* - LZMA_DATA_ERROR:
* - Encoder: Filter(s) cannot process the given data.
* - Decoder: Compressed data is corrupt.
* - LZMA_HEADER_ERROR: Unsupported options. Rebuilding liblzma
* with more features enabled or upgrading to a newer version
* may help, although usually this is a sign of invalid options
* (encoder) or corrupted input data (decoder).
* - LZMA_PROG_ERROR: Invalid arguments or the internal state
* of the coder is corrupt.
* See the description of the coder-specific initialization function to find
* out what `action' values are supported by the coder. See documentation of
* lzma_ret for the possible return values.
*/
extern lzma_ret lzma_code(lzma_stream *strm, lzma_action action);
extern lzma_ret lzma_code(lzma_stream *strm, lzma_action action)
lzma_attr_warn_unused_result;
/**

View File

@@ -32,6 +32,21 @@
* later calls to lzma_code().
*/
typedef struct {
/**
* \brief Size of the Block Header
*
* Read by:
* - lzma_block_header_encode()
* - lzma_block_header_decode()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_size()
*/
uint32_t header_size;
# define LZMA_BLOCK_HEADER_SIZE_MIN 8
# define LZMA_BLOCK_HEADER_SIZE_MAX 1024
/**
* \brief Type of integrity Check
*
@@ -39,89 +54,12 @@ typedef struct {
* Header, thus its value must be provided also when decoding.
*
* Read by:
* - lzma_block_header_encode()
* - lzma_block_header_decode()
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_check_type check;
/**
* \brief Precense of CRC32 of the Block Header
*
* Set this to true if CRC32 of the Block Header should be
* calculated and stored in the Block Header.
*
* There is no way to autodetect if CRC32 is present in the Block
* Header, thus this information must be provided also when decoding.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
* - lzma_block_header_decoder()
*/
lzma_bool has_crc32;
/**
* \brief Usage of End of Payload Marker
*
* If this is true, End of Payload Marker is used even if
* Uncompressed Size is known.
*
* Read by:
* - lzma_block_header_encoder()
* - lzma_block_encoder()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_decoder()
*/
lzma_bool has_eopm;
/**
* \brief True if the Block is a Metadata Block
*
* If this is true, the Metadata bit will be set in the Block Header.
* It is up to the application to store correctly formatted data
* into Metadata Block.
*
* Read by:
* - lzma_block_header_encoder()
*
* Written by:
* - lzma_block_header_decoder()
*/
lzma_bool is_metadata;
/**
* \brief True if Uncompressed Size is in Block Footer
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_bool has_uncompressed_size_in_footer;
/**
* \brief True if Backward Size is in Block Footer
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_bool has_backward_size;
/**
* \brief True if Block coder should take care of Padding
*
* In liblzma, Stream decoder sets this to true when decoding
* Header Metadata Block or Data Blocks from Multi-Block Stream,
* and to false when decoding Single-Block Stream or Footer
* Metadata Block from a Multi-Block Stream.
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_bool handle_padding;
lzma_check check;
/**
* \brief Size of the Compressed Data in bytes
@@ -134,12 +72,11 @@ typedef struct {
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
* - lzma_block_encoder()
* - lzma_block_header_encode()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_decoder()
* - lzma_block_header_decode()
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
@@ -163,167 +100,60 @@ typedef struct {
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
* - lzma_block_encoder()
* - lzma_block_header_encode()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_decoder()
* - lzma_block_header_decode()
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_vli uncompressed_size;
/**
* \brief Number of bytes to reserve for Compressed Size
*
* This is useful if you want to be able to store the Compressed Size
* to the Block Header, but you don't know it when starting to encode.
* Setting this to non-zero value at maximum of LZMA_VLI_BYTES_MAX,
* the Block Header encoder will force the Compressed Size field to
* occupy specified number of bytes. You can later rewrite the Block
* Header to contain correct information by using otherwise identical
* lzma_options_block structure except the correct compressed_size.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
*
* Written by:
* - lzma_block_header_decoder()
*/
uint32_t compressed_reserve;
/**
* \brief Number of bytes to reserve for Uncompressed Size
*
* See the description of compressed_size above.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
*
* Written by:
* - lzma_block_header_decoder()
*/
uint32_t uncompressed_reserve;
/**
* \brief Total Size of the Block in bytes
*
* This is useful in the decoder, which can verify the Total Size
* if it is known from Index.
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_vli total_size;
/**
* \brief Upper limit of Total Size
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_vli total_limit;
/**
* \brief Upper limit of Uncompressed Size
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*/
lzma_vli uncompressed_limit;
/**
* \brief Array of filters
*
* There can be at maximum of seven filters. The end of the array
* is marked with .id = LZMA_VLI_VALUE_UNKNOWN. Minimum number of
* filters is zero; in that case, an implicit Copy filter is used.
* There can be 1-4 filters. The end of the array is marked with
* .id = LZMA_VLI_VALUE_UNKNOWN.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
* - lzma_block_header_encode()
* - lzma_block_encoder()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_decoder(): Note that this does NOT free()
* the old filter options structures. If decoding fails, the
* caller must take care of freeing the options structures
* that may have been allocated and decoded before the error
* occurred.
* - lzma_block_header_decode(): Note that this does NOT free()
* the old filter options structures. All unused filters[] will
* have .id == LZMA_VLI_VALUE_UNKNOWN and .options == NULL. If
* decoding fails, all filters[] are guaranteed to be
* LZMA_VLI_VALUE_UNKNOWN and NULL.
*
* \note Because of the array is terminated with
* .id = LZMA_VLI_VALUE_UNKNOWN, the actual array must
* have LZMA_BLOCK_FILTERS_MAX + 1 members or the Block
* Header decoder will overflow the buffer.
*/
lzma_options_filter filters[8];
lzma_filter *filters;
# define LZMA_BLOCK_FILTERS_MAX 4
/**
* \brief Size of the Padding field
*
* The Padding field exist to allow aligning the Compressed Data field
* optimally in the Block. See lzma_options_stream.alignment in
* stream.h for more information.
*
* If you want the Block Header encoder to automatically calculate
* optimal size for the Padding field by looking at the information
* in filters[], set this to LZMA_BLOCK_HEADER_PADDING_AUTO. In that
* case, you must also set the aligmnet variable to tell the the
* encoder the aligmnet of the beginning of the Block Header.
*
* The decoder never sets this to LZMA_BLOCK_HEADER_PADDING_AUTO.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder(): Note that this doesn't
* accept LZMA_BLOCK_HEADER_PADDING_AUTO.
*
* Written by (these never set padding to
* LZMA_BLOCK_HEADER_PADDING_AUTO):
* - lzma_block_header_size()
* - lzma_block_header_decoder()
*/
int32_t padding;
# define LZMA_BLOCK_HEADER_PADDING_AUTO (-1)
# define LZMA_BLOCK_HEADER_PADDING_MIN 0
# define LZMA_BLOCK_HEADER_PADDING_MAX 31
/**
* \brief Alignment of the beginning of the Block Header
*
* This variable is read only if padding has been set to
* LZMA_BLOCK_HEADER_PADDING_AUTO.
*
* Read by:
* - lzma_block_header_size()
* - lzma_block_header_encoder()
*/
uint32_t alignment;
/**
* \brief Size of the Block Header
*
* Read by:
* - lzma_block_encoder()
* - lzma_block_decoder()
*
* Written by:
* - lzma_block_header_size()
* - lzma_block_header_decoder()
*/
uint32_t header_size;
} lzma_options_block;
} lzma_block;
/**
* \brief Calculates the size of Header Padding and Block Header
* \brief Decodes the Block Header Size field
*
* To decode Block Header using lzma_block_header_decode(), the size of the
* Block Header has to be known and stored into lzma_block.header_size.
* The size can be calculated from the first byte of a Block using this macro.
* Note that if the first byte is 0x00, it indicates beginning of Index; use
* this macro only when the byte is not 0x00.
*/
#define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
/**
* \brief Calculates the size of Block Header
*
* \return - LZMA_OK: Size calculated successfully and stored to
* options->header_size.
@@ -334,7 +164,8 @@ typedef struct {
* may return LZMA_OK even if lzma_block_header_encode() or
* lzma_block_encoder() would fail.
*/
extern lzma_ret lzma_block_header_size(lzma_options_block *options);
extern lzma_ret lzma_block_header_size(lzma_block *options)
lzma_attr_warn_unused_result;
/**
@@ -353,24 +184,66 @@ extern lzma_ret lzma_block_header_size(lzma_options_block *options);
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_block_header_encode(
uint8_t *out, const lzma_options_block *options);
const lzma_block *options, uint8_t *out)
lzma_attr_warn_unused_result;
/**
* \brief Initializes Block Header decoder
* \brief Decodes Block Header
*
* Because the results of this decoder are placed into *options,
* strm->next_in, strm->avail_in, and strm->total_in are not used.
* Decoding of the Block options is done with a single call instead of
* first initializing and then doing the actual work with lzma_code().
*
* The only valid `action' with lzma_code() is LZMA_RUN.
* \param options Destination for block options
* \param allocator lzma_allocator for custom allocator functions.
* Set to NULL to use malloc().
* \param in Beginning of the input buffer. This must be
* at least options->header_size bytes.
*
* \return - LZMA_OK: Encoding was successful. options->header_size
* \return - LZMA_OK: Decoding was successful. options->header_size
* bytes were written to output buffer.
* - LZMA_HEADER_ERROR: Invalid or unsupported options.
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_block_header_decoder(
lzma_stream *strm, lzma_options_block *options);
extern lzma_ret lzma_block_header_decode(lzma_block *options,
lzma_allocator *allocator, const uint8_t *in)
lzma_attr_warn_unused_result;
/**
* \brief Sets Compressed Size according to Total Size
*
* Block Header stores Compressed Size, but Index has Total Size. If the
* application has already parsed the Index and is now decoding Blocks,
* it can calculate Compressed Size from Total Size. This function does
* exactly that with error checking, so application doesn't need to check,
* for example, if the value in Index is too small to contain even the
* Block Header. Note that you need to call this function after decoding
* the Block Header field.
*
* \return - LZMA_OK: options->compressed_size was set successfully.
* - LZMA_DATA_ERROR: total_size is too small compared to
* options->header_size and lzma_check_sizes[options->check].
* - LZMA_PROG_ERROR: Some values are invalid. For example,
* total_size and options->header_size must be multiples
* of four, total_size must be at least 12, and
* options->header_size between 8 and 1024 inclusive.
*/
extern lzma_ret lzma_block_total_size_set(
lzma_block *options, lzma_vli total_size)
lzma_attr_warn_unused_result;
/**
* \brief Calculates Total Size
*
* This function can be useful after decoding a Block to get Total Size
* that is stored in Index.
*
* \return Total Size on success, or zero on error.
*/
extern lzma_vli lzma_block_total_size_get(const lzma_block *options)
lzma_attr_pure;
/**
@@ -391,8 +264,8 @@ extern lzma_ret lzma_block_header_decoder(
*
* lzma_code() can return FIXME
*/
extern lzma_ret lzma_block_encoder(
lzma_stream *strm, lzma_options_block *options);
extern lzma_ret lzma_block_encoder(lzma_stream *strm, lzma_block *options)
lzma_attr_warn_unused_result;
/**
@@ -405,5 +278,5 @@ extern lzma_ret lzma_block_encoder(
* - LZMA_PROG_ERROR
* - LZMA_MEM_ERROR
*/
extern lzma_ret lzma_block_decoder(
lzma_stream *strm, lzma_options_block *options);
extern lzma_ret lzma_block_decoder(lzma_stream *strm, lzma_block *options)
lzma_attr_warn_unused_result;

View File

@@ -43,26 +43,26 @@ typedef enum {
* Size of the Check field: 4 bytes
*/
LZMA_CHECK_CRC64 = 3,
LZMA_CHECK_CRC64 = 4,
/**<
* CRC64 using the polynomial from the ECMA-182 standard
*
* Size of the Check field: 8 bytes
*/
LZMA_CHECK_SHA256 = 5
LZMA_CHECK_SHA256 = 10
/**<
* SHA-256
*
* Size of the Check field: 32 bytes
*/
} lzma_check_type;
} lzma_check;
/**
* \brief Maximum valid Check ID
*
* The .lzma file format specification specifies eight Check IDs (0-7). Some
* The .lzma file format specification specifies eight Check IDs (0-15). Some
* of them are only reserved i.e. no actual Check algorithm has been assigned.
* Still liblzma accepts any of these eight IDs for future compatibility
* when decoding files. If a valid but unsupported Check ID is detected,
@@ -70,29 +70,38 @@ typedef enum {
*
* FIXME bad desc
*/
#define LZMA_CHECK_ID_MAX 7
#define LZMA_CHECK_ID_MAX 15
/**
* \brief Check IDs supported by this liblzma build
*
* If lzma_available_checks[n] is true, the Check ID n is supported by this
* liblzma build. You can assume that LZMA_CHECK_NONE and LZMA_CHECK_CRC32
* are always available.
* \brief Maximum size of a Check field
*/
extern const lzma_bool lzma_available_checks[LZMA_CHECK_ID_MAX + 1];
#define LZMA_CHECK_SIZE_MAX 64
/**
* \brief Size of the Check field with different Check IDs
* \brief Test if the given Check ID is supported
*
* Returns true if the given Check ID is supported by this liblzma build.
* Otherwise false is returned. It is safe to call this with a value that
* is not in the range [0, 15]; in that case the return value is always false.
*/
extern lzma_bool lzma_check_is_supported(lzma_check check)
lzma_attr_const;
/**
* \brief Get the size of the Check field with given Check ID
*
* Although not all Check IDs have a check algorithm associated, the size of
* every Check is already frozen. This array contains the size (in bytes) of
* the Check field with specified Check ID. The values are taken from the
* section 2.2.2 of the .lzma file format specification:
* { 0, 4, 4, 8, 16, 32, 32, 64 }
* every Check is already frozen. This function returns the size (in bytes) of
* the Check field with the specified Check ID. The values are taken from the
* section 2.1.1.2 of the .lzma file format specification:
* { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }
*
* If the argument is not in the range [0, 15], UINT32_MAX is returned.
*/
extern const uint32_t lzma_check_sizes[LZMA_CHECK_ID_MAX + 1];
extern uint32_t lzma_check_size(lzma_check check) lzma_attr_const;
/**
@@ -109,7 +118,8 @@ extern const uint32_t lzma_check_sizes[LZMA_CHECK_ID_MAX + 1];
* \return Updated CRC value, which can be passed to this function
* again to continue CRC calculation.
*/
extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc);
extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
lzma_attr_pure;
/**
@@ -119,10 +129,21 @@ extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc);
*
* This function is used similarly to lzma_crc32(). See its documentation.
*/
extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
lzma_attr_pure;
/*
* SHA256 functions are currently not exported to public API.
* Contact the author if you think it should be.
*/
/**
* \brief Get the type of the integrity check
*
* This function can be called only immediatelly after lzma_code() has
* returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK.
* Calling this function in any other situation has undefined behavior.
*/
extern lzma_check lzma_get_check(const lzma_stream *strm);

View File

@@ -0,0 +1,266 @@
/**
* \file lzma/container.h
* \brief File formats
*
* \author Copyright (C) 1999-2008 Igor Pavlov
* \author Copyright (C) 2007-2008 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/************
* Encoding *
************/
/**
* \brief Compression level names for lzma_easy_* functions
*
* At the moment, all the compression levels support LZMA_SYNC_FLUSH.
* In future there may be levels that don't support LZMA_SYNC_FLUSH.
* However, the LZMA_SYNC_FLUSH support won't be removed from the
* existing compression levels.
*
* \note If liblzma is built without encoder support, or with some
* filters disabled, some of the compression levels may be
* unsupported. In that case, the initialization functions
* will return LZMA_HEADER_ERROR.
*/
typedef enum {
LZMA_EASY_COPY = 0,
/**<
* No compression; the data is just wrapped into .lzma
* container.
*/
LZMA_EASY_LZMA2_1 = 1,
/**<
* LZMA2 filter with fast compression (fast in terms of LZMA2).
* If you are interested in the exact options used, see
* lzma_preset_lzma[0]. Note that the exact options may
* change between liblzma versions.
*
* At the moment, the command line tool uses these settings
* when `lzma -1' is used. In future, the command line tool
* may default to some more complex way to determine the
* settings used e.g. the type of files being compressed.
*
* LZMA_EASY_LZMA_2 is equivalent to lzma_preset_lzma[1]
* and so on.
*/
LZMA_EASY_LZMA_2 = 2,
LZMA_EASY_LZMA_3 = 3,
LZMA_EASY_LZMA_4 = 4,
LZMA_EASY_LZMA_5 = 5,
LZMA_EASY_LZMA_6 = 6,
LZMA_EASY_LZMA_7 = 7,
LZMA_EASY_LZMA_8 = 8,
LZMA_EASY_LZMA_9 = 9,
} lzma_easy_level;
/**
* \brief Default compression level
*
* Data Blocks contain the actual compressed data. It's not straightforward
* to recommend a default level, because in some cases keeping the resource
* usage relatively low is more important that getting the maximum
* compression ratio.
*/
#define LZMA_EASY_DEFAULT LZMA_EASY_LZMA2_7
/**
* \brief Calculates rough memory requirements of a compression level
*
* This function is a wrapper for lzma_memory_usage(), which is declared
* in filter.h.
*
* \return Approximate memory usage of the encoder with the given
* compression level in mebibytes (value * 1024 * 1024 bytes).
* On error (e.g. compression level is not supported),
* UINT32_MAX is returned.
*/
extern uint64_t lzma_easy_memory_usage(lzma_easy_level level)
lzma_attr_pure;
/**
* \brief Initializes .lzma Stream encoder
*
* This function is intended for those who just want to use the basic features
* if liblzma (that is, most developers out there). Lots of assumptions are
* made, which are correct or at least good enough for most situations.
*
* \param strm Pointer to lzma_stream that is at least initialized
* with LZMA_STREAM_INIT.
* \param level Compression level to use. This selects a set of
* compression settings from a list of compression
* presets.
*
* \return - LZMA_OK: Initialization succeeded. Use lzma_code() to
* encode your data.
* - LZMA_MEM_ERROR: Memory allocation failed. All memory
* previously allocated for *strm is now freed.
* - LZMA_HEADER_ERROR: The given compression level is not
* supported by this build of liblzma.
*
* If initialization succeeds, use lzma_code() to do the actual encoding.
* Valid values for `action' (the second argument of lzma_code()) are
* LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future,
* there may be compression levels that don't support LZMA_SYNC_FLUSH.
*/
extern lzma_ret lzma_easy_encoder(lzma_stream *strm, lzma_easy_level level)
lzma_attr_warn_unused_result;
/**
* \brief Initializes .lzma Stream encoder
*
* \param strm Pointer to properly prepared lzma_stream
* \param filters Array of filters. This must be terminated with
* filters[n].id = LZMA_VLI_VALUE_UNKNOWN. There must
* be 1-4 filters, but there are restrictions on how
* multiple filters can be combined. FIXME Tell where
* to find more information.
* \param check Type of the integrity check to calculate from
* uncompressed data.
*
* \return - LZMA_OK: Initialization was successful.
* - LZMA_MEM_ERROR
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_stream_encoder(lzma_stream *strm,
const lzma_filter *filters, lzma_check check)
lzma_attr_warn_unused_result;
/**
* \brief Initializes LZMA_Alone (deprecated file format) encoder
*
* LZMA_Alone files have the suffix .lzma like the .lzma Stream files.
* LZMA_Alone format supports only one filter, the LZMA filter. There is
* no support for integrity checks like CRC32.
*
* Use this format if and only if you need to create files readable by
* legacy LZMA tools such as LZMA Utils 4.32.x.
*
* LZMA_Alone encoder doesn't support LZMA_SYNC_FLUSH or LZMA_FULL_FLUSH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_alone_encoder(
lzma_stream *strm, const lzma_options_lzma *options)
lzma_attr_warn_unused_result;
/************
* Decoding *
************/
/**
* This flag makes lzma_code() return LZMA_NO_CHECK if the input stream
* being decoded has no integrity check. Note that when used with
* lzma_auto_decoder(), all LZMA_Alone files will trigger LZMA_NO_CHECK
* if LZMA_TELL_NO_CHECK is used.
*/
#define LZMA_TELL_NO_CHECK UINT32_C(0x01)
/**
* This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input
* stream has an integrity check, but the type of the integrity check is not
* supported by this liblzma version or build. Such files can still be
* decoded, but the integrity check cannot be verified.
*/
#define LZMA_TELL_UNSUPPORTED_CHECK UINT32_C(0x02)
/**
* This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type
* of the integrity check is known. The type can then be got with
* lzma_get_check().
*/
#define LZMA_TELL_ANY_CHECK UINT32_C(0x04)
/**
* This flag enables decoding of concatenated files with file formats that
* allow concatenating compressed files as is. From the formats currently
* supported by liblzma, only the new .lzma format allows concatenated files.
* Concatenated files are not allowed with the LZMA_Alone format.
*
* This flag also affects the usage of the `action' argument for lzma_code().
* When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END
* unless LZMA_FINISH is used as `action'. Thus, the application has to set
* LZMA_FINISH in the same way as it does when encoding.
*
* If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH
* as `action' for lzma_code(), but the usage of LZMA_FINISH isn't required.
*/
#define LZMA_CONCATENATED UINT32_C(0x08)
/**
* \brief Initializes decoder for .lzma Stream
*
* \param strm Pointer to properly prepared lzma_stream
* \param memlimit Rough memory usage limit as bytes
*
* \return - LZMA_OK: Initialization was successful.
* - LZMA_MEM_ERROR: Cannot allocate memory.
* - LZMA_HEADER_ERROR: Unsupported flags
*/
extern lzma_ret lzma_stream_decoder(
lzma_stream *strm, uint64_t memlimit, uint32_t flags)
lzma_attr_warn_unused_result;
/**
* \brief Decode .lzma Streams and LZMA_Alone files with autodetection
*
* Autodetects between the .lzma Stream and LZMA_Alone formats, and
* calls lzma_stream_decoder() or lzma_alone_decoder() once the type
* of the file has been detected.
*
* \param strm Pointer to propertily prepared lzma_stream
* \param memlimit Rough memory usage limit as bytes
* \param flags Bitwise-or of flags, or zero for no flags.
*
* \return - LZMA_OK: Initialization was successful.
* - LZMA_MEM_ERROR: Cannot allocate memory.
* - LZMA_HEADER_ERROR: Unsupported flags
*/
extern lzma_ret lzma_auto_decoder(
lzma_stream *strm, uint64_t memlimit, uint32_t flags)
lzma_attr_warn_unused_result;
/**
* \brief Initializes decoder for LZMA_Alone file
*
* Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
* There is no need to use LZMA_FINISH, but allowing it may simplify
* certain types of applications.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
*/
extern lzma_ret lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
lzma_attr_warn_unused_result;

View File

@@ -1,29 +0,0 @@
/**
* \file lzma/copy.h
* \brief Copy filter
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Filter ID
*
* Filter ID of the Copy filter. This is used as lzma_options_filter.id.
*/
#define LZMA_FILTER_COPY LZMA_VLI_C(0x00)

View File

@@ -24,9 +24,21 @@
/**
* \brief Filter ID
*
* Filter ID of the Delta filter. This is used as lzma_options_filter.id.
* Filter ID of the Delta filter. This is used as lzma_filter.id.
*/
#define LZMA_FILTER_DELTA LZMA_VLI_C(0x20)
#define LZMA_FILTER_DELTA LZMA_VLI_C(0x03)
/**
* \brief Type of the delta calculation
*
* Currently only byte-wise delta is supported. Other possible types could
* be, for example, delta of 16/32/64-bit little/big endian integers, but
* these are not currently planned since byte-wise delta is almost as good.
*/
typedef enum {
LZMA_DELTA_TYPE_BYTE
} lzma_delta_type;
/**
@@ -35,8 +47,14 @@
* These options are needed by both encoder and decoder.
*/
typedef struct {
/** For now, this must always be LZMA_DELTA_TYPE_BYTE. */
lzma_delta_type type;
/**
* \brief Delta distance as bytes
* \brief Delta distance
*
* With the only currently supported type, LZMA_DELTA_TYPE_BYTE,
* the distance is as bytes.
*
* Examples:
* - 16-bit stereo audio: distance = 4 bytes
@@ -46,4 +64,16 @@ typedef struct {
# define LZMA_DELTA_DISTANCE_MIN 1
# define LZMA_DELTA_DISTANCE_MAX 256
/**
* \brief Reserved space for possible future extensions
*
* You should not touch these, because the names of these variables
* may change. These are and will never be used when type is
* LZMA_DELTA_TYPE_BYTE, so it is safe to leave these uninitialized.
*/
uint32_t reserved_int1;
uint32_t reserved_int2;
void *reserved_ptr1;
void *reserved_ptr2;
} lzma_options_delta;

View File

@@ -1,114 +0,0 @@
/**
* \file lzma/extra.h
* \brief Handling of Extra Records in Metadata
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/*
* Extra Record IDs
*
* See the .lzma file format specification for description what each
* Extra Record type exactly means.
*
* If you ever need to update .lzma files with Extra Records, note that
* the Record IDs are divided in two categories:
* - Safe-to-Copy Records may be preserved as is when the
* Stream is modified in ways that don't change the actual
* uncompressed data. Examples of such operatings include
* recompressing and adding, modifying, or deleting unrelated
* Extra Records.
* - Unsafe-to-Copy Records should be removed (and possibly
* recreated) when any kind of changes are made to the Stream.
*/
#define LZMA_EXTRA_PADDING 0x00
#define LZMA_EXTRA_OPENPGP 0x01
#define LZMA_EXTRA_FILTERS 0x02
#define LZMA_EXTRA_COMMENT 0x03
#define LZMA_EXTRA_CHECKS 0x04
#define LZMA_EXTRA_FILENAME 0x05
#define LZMA_EXTRA_MTIME 0x07
#define LZMA_EXTRA_MTIME_HR 0x09
#define LZMA_EXTRA_MIME_TYPE 0x0B
#define LZMA_EXTRA_HOMEPAGE 0x0D
/**
* \brief Extra Records
*
* The .lzma format provides a way to store custom information along
* the actual compressed content. Information about these Records
* are passed to and from liblzma via this linked list.
*/
typedef struct lzma_extra_s lzma_extra;
struct lzma_extra_s {
/**
* \brief Pointer to the next Extra Record
*
* This is NULL on the last Extra Record.
*/
lzma_extra *next;
/**
* \brief Record ID
*
* Extra Record IDs are divided in three categories:
* - Zero is a special case used for padding. It doesn't have
* Size of Data fields.
* - Odd IDs (1, 3, 5, ...) are Safe-to-Copy IDs.
* These can be preserved as is if the Stream is
* modified in a way that doesn't alter the actual
* uncompressed content.
* - Even IDs (2, 4, 6, ...) are Unsafe-to-Copy IDs.
* If the .lzma Stream is modified in any way,
* the Extra Records having a sensitive ID should
* be removed or updated accordingly.
*
* Refer to the .lzma file format specification for
* the up to date list of Extra Record IDs.
*/
lzma_vli id;
/**
* \brief Size of the Record data
*
* In case of strings, this should not include the
* trailing '\0'.
*/
size_t size;
/**
* \brief Record data
*
* Record data is often a string in UTF-8 encoding,
* but it can be arbitrary binary data. In case of
* strings, the trailing '\0' is usually not stored
* in the .lzma file.
*
* To ease working with Extra Records containing strings,
* liblzma always adds '\0' to the end of data even when
* it wasn't present in the .lzma file. This '\0' is not
* counted in the size of the data.
*/
uint8_t *data;
};
extern void lzma_extra_free(lzma_extra *extra, lzma_allocator *allocator);

View File

@@ -51,55 +51,171 @@ typedef struct {
*/
void *options;
} lzma_options_filter;
} lzma_filter;
/**
* \brief Filters available for encoding
* \brief Test if the given Filter ID is supported for encoding
*
* Pointer to an array containing the list of available Filter IDs that
* can be used for encoding. The last element is LZMA_VLI_VALUE_UNKNOWN.
* Returns true if the give Filter ID is supported for encoding by this
* liblzma build. Otherwise false is returned.
*
* If lzma_available_filter_encoders[0] == LZMA_VLI_VALUE_UNKNOWN, the
* encoder components haven't been built at all. This means that the
* encoding-specific functions are probably missing from the library
* API/ABI completely.
* There is no way to list which filters are available in this particular
* liblzma version and build. It would be useless, because the application
* couldn't know what kind of options the filter would need.
*/
extern const lzma_vli *const lzma_available_filter_encoders;
extern lzma_bool lzma_filter_encoder_is_supported(lzma_vli id);
/**
* \brief Filters available for decoding
* \brief Test if the given Filter ID is supported for decoding
*
* Pointer to an array containing the list of available Filter IDs that
* can be used for decoding. The last element is LZMA_VLI_VALUE_UNKNOWN.
*
* If lzma_available_filter_decoders[0] == LZMA_VLI_VALUE_UNKNOWN, the
* decoder components haven't been built at all. This means that the
* decoding-specific functions are probably missing from the library
* API/ABI completely.
* Returns true if the give Filter ID is supported for decoding by this
* liblzma build. Otherwise false is returned.
*/
extern const lzma_vli *const lzma_available_filter_decoders;
extern lzma_bool lzma_filter_decoder_is_supported(lzma_vli id);
/**
* \brief Calculate rough memory requirements for given filter chain
* \brief Calculate rough memory requirements for raw encoder
*
* \param filters Array of filters terminated with
* .id == LZMA_VLI_VALUE_UNKNOWN.
* \param is_encoder Set to true when calculating memory requirements
* of an encoder; false for decoder.
*
* \return Number of mebibytes (MiB i.e. 2^20) required for the given
* encoder or decoder filter chain.
*
* \note If calculating memory requirements of encoder, lzma_init() or
* lzma_init_encoder() must have been called earlier. Similarly,
* if calculating memory requirements of decoder, lzma_init() or
* lzma_init_decoder() must have been called earlier.
* \return Rough number of bytes required for the given filter chain
* when encoding.
*/
extern uint32_t lzma_memory_usage(
const lzma_options_filter *filters, lzma_bool is_encoder);
extern uint64_t lzma_memusage_encoder(const lzma_filter *filters)
lzma_attr_pure;
/**
* \brief Calculate rough memory requirements for raw decoder
*
* \param filters Array of filters terminated with
* .id == LZMA_VLI_VALUE_UNKNOWN.
*
* \return Rough number of bytes required for the given filter chain
* when decoding.
*/
extern uint64_t lzma_memusage_decoder(const lzma_filter *filters)
lzma_attr_pure;
/**
* \brief Initialize raw encoder
*
* This function may be useful when implementing custom file formats.
*
* \param strm Pointer to properly prepared lzma_stream
* \param options Array of lzma_filter structures.
* The end of the array must be marked with
* .id = LZMA_VLI_VALUE_UNKNOWN. The minimum
* number of filters is one and the maximum is four.
*
* The `action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
* filter chain supports it), or LZMA_FINISH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_raw_encoder(
lzma_stream *strm, const lzma_filter *options)
lzma_attr_warn_unused_result;
/**
* \brief Initialize raw decoder
*
* The initialization of raw decoder goes similarly to raw encoder.
*
* The `action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using
* LZMA_FINISH is not required, it is supported just for convenience.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_raw_decoder(
lzma_stream *strm, const lzma_filter *options)
lzma_attr_warn_unused_result;
/**
* \brief Get the size of the Filter Properties field
*
* This function may be useful when implementing custom file formats
* using the raw encoder and decoder.
*
* \param size Pointer to uint32_t to hold the size of the properties
* \param filter Filter ID and options (the size of the propeties may
* vary depending on the options)
*
* \return - LZMA_OK
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*
* \note This function validates the Filter ID, but does not
* necessarily validate the options. Thus, it is possible
* that this returns LZMA_OK while the following call to
* lzma_properties_encode() returns LZMA_HEADER_ERROR.
*/
extern lzma_ret lzma_properties_size(
uint32_t *size, const lzma_filter *filter);
/**
* \brief Encode the Filter Properties field
*
* \param filter Filter ID and options
* \param props Buffer to hold the encoded options. The size of
* buffer must have been already determined with
* lzma_properties_size().
*
* \return - LZMA_OK
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*
* \note Even this function won't validate more options than actually
* necessary. Thus, it is possible that encoding the properties
* succeeds but using the same options to initialize the encoder
* will fail.
*
* \note It is OK to skip calling this function if
* lzma_properties_size() indicated that the size
* of the Filter Properties field is zero.
*/
extern lzma_ret lzma_properties_encode(
const lzma_filter *filter, uint8_t *props);
/**
* \brief Decode the Filter Properties field
*
* \param filter filter->id must have been set to the correct
* Filter ID. filter->options doesn't need to be
* initialized (it's not freed by this function). The
* decoded options will be stored to filter->options.
* filter->options is set to NULL if there are no
* properties or if an error occurs.
* \param allocator Custom memory allocator used to allocate the
* options. Set to NULL to use the default malloc(),
* and in case of an error, also free().
* \param props Input buffer containing the properties.
* \param props_size Size of the properties. This must be the exact
* size; giving too much or too little input will
* return LZMA_HEADER_ERROR.
*
* \return - LZMA_OK
* - LZMA_HEADER_ERROR
* - LZMA_MEM_ERROR
*/
extern lzma_ret lzma_properties_decode(
lzma_filter *filter, lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
/**
@@ -119,10 +235,11 @@ extern uint32_t lzma_memory_usage(
* - LZMA_PROG_ERROR: Invalid options
*
* \note If you need to calculate size of List of Filter Flags,
* you need to loop over every lzma_options_filter entry.
* you need to loop over every lzma_filter entry.
*/
extern lzma_ret lzma_filter_flags_size(
uint32_t *size, const lzma_options_filter *options);
uint32_t *size, const lzma_filter *options)
lzma_attr_warn_unused_result;
/**
@@ -143,8 +260,9 @@ extern lzma_ret lzma_filter_flags_size(
* buffer space (you should have checked it with
* lzma_filter_flags_size()).
*/
extern lzma_ret lzma_filter_flags_encode(uint8_t *out, size_t *out_pos,
size_t out_size, const lzma_options_filter *options);
extern lzma_ret lzma_filter_flags_encode(const lzma_filter *options,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_attr_warn_unused_result;
/**
@@ -162,5 +280,7 @@ extern lzma_ret lzma_filter_flags_encode(uint8_t *out, size_t *out_pos,
* - LZMA_MEM_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_filter_flags_decoder(
lzma_stream *strm, lzma_options_filter *options);
extern lzma_ret lzma_filter_flags_decode(
lzma_filter *options, lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
lzma_attr_warn_unused_result;

View File

@@ -22,63 +22,221 @@
/**
* \brief
*
* FIXME desc
* \brief Opaque data type to hold the Index
*/
typedef struct lzma_index_s lzma_index;
struct lzma_index_s {
/**
* \brief Index Record and its location
*/
typedef struct {
/**
* \brief Total Size of the Block
*
* This includes Block Header, Compressed Data, and Block Footer.
* Total Size of a Block.
*/
lzma_vli total_size;
/**
* \brief Uncompressed Size of the Block
* Uncompressed Size of a Block
*/
lzma_vli uncompressed_size;
/**
* \brief Pointer to the next Index Record
*
* This is NULL on the last Index Record.
* Offset of the first byte of a Block relative to the beginning
* of the Stream, or if there are multiple Indexes combined,
* relative to the beginning of the first Stream.
*/
lzma_index *next;
};
lzma_vli stream_offset;
/**
* Uncompressed offset
*/
lzma_vli uncompressed_offset;
} lzma_index_record;
/**
* \brief Allocate and initialize a new lzma_index structure
*
* If i is NULL, a new lzma_index structure is allocated, initialized,
* and a pointer to it returned. If allocation fails, NULL is returned.
*
* If i is non-NULL, it is reinitialized and the same pointer returned.
* In this case, return value cannot be NULL or a different pointer than
* the i given as argument.
*/
extern lzma_index *lzma_index_init(lzma_index *i, lzma_allocator *allocator)
lzma_attr_warn_unused_result;
/**
* \brief Deallocate the Index
*/
extern void lzma_index_end(lzma_index *i, lzma_allocator *allocator);
/**
* \brief Add a new Record to an Index
*
* \param index Pointer to a lzma_index structure
* \param total_size Total Size of a Block
* \param uncompressed_size Uncompressed Size of a Block, or
* LZMA_VLI_VALUE_UNKNOWN to indicate padding.
*
* Appending a new Record does not affect the read position.
*
* \return - LZMA_OK
* - LZMA_DATA_ERROR: Compressed or uncompressed size of the
* Stream or size of the Index field would grow too big.
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_index_append(lzma_index *i, lzma_allocator *allocator,
lzma_vli total_size, lzma_vli uncompressed_size)
lzma_attr_warn_unused_result;
/**
* \brief Get the number of Records
*/
extern lzma_vli lzma_index_count(const lzma_index *i) lzma_attr_pure;
/**
* \brief Get the size of the Index field as bytes
*
* This is needed to verify the Index Size field from the Stream Footer.
*/
extern lzma_vli lzma_index_size(const lzma_index *i) lzma_attr_pure;
/**
* \brief Get the total size of the Blocks
*
* This doesn't include the Stream Header, Stream Footer, Stream Padding,
* or Index fields.
*/
extern lzma_vli lzma_index_total_size(const lzma_index *i) lzma_attr_pure;
/**
* \brief Get the total size of the Stream
*
* If multiple Indexes have been combined, this works as if the Blocks
* were in a single Stream.
*/
extern lzma_vli lzma_index_stream_size(const lzma_index *i) lzma_attr_pure;
/**
* \brief Get the total size of the file
*
* When no Indexes have been combined with lzma_index_cat(), this function is
* identical to lzma_index_stream_size(). If multiple Indexes have been
* combined, this includes also the possible Stream Padding fields.
*/
extern lzma_vli lzma_index_file_size(const lzma_index *i) lzma_attr_pure;
/**
* \brief Get the uncompressed size of the Stream
*/
extern lzma_vli lzma_index_uncompressed_size(const lzma_index *i)
lzma_attr_pure;
/**
* \brief Get the next Record from the Index
*/
extern lzma_bool lzma_index_read(lzma_index *i, lzma_index_record *record)
lzma_attr_warn_unused_result;
/**
* \brief Rewind the Index
*
* Rewind the Index so that next call to lzma_index_read() will return the
* first Record.
*/
extern void lzma_index_rewind(lzma_index *i);
/**
* \brief Locate a Record
*
* When the Index is available, it is possible to do random-access reading
* with granularity of Block size.
*
* \param i Pointer to lzma_index structure
* \param record Pointer to a structure to hold the search results
* \param target Uncompressed target offset
*
* If the target is smaller than the uncompressed size of the Stream (can be
* checked with lzma_index_uncompressed_size()):
* - Information about the Record containing the requested uncompressed
* offset is stored into *record.
* - Read offset will be adjusted so that calling lzma_index_read() can be
* used to read subsequent Records.
* - This function returns false.
*
* If target is greater than the uncompressed size of the Stream, *record
* and the read position are not modified, and this function returns true.
*/
extern lzma_bool lzma_index_locate(
lzma_index *i, lzma_index_record *record, lzma_vli target)
lzma_attr_warn_unused_result;
/**
* \brief Concatenate Indexes of two Streams
*
*
*
* \param dest Destination Index after which src is appended Source
* \param src Index. The memory allocated for this is either moved
* to be part of *dest or freed iff the function call
* succeeds, and src will be an invalid pointer.
* \param allocator Custom memory allocator; can be NULL to use
* malloc() and free().
* \param padding Size of the Stream Padding field between Streams.
*
* \return - LZMA_OK: Indexes concatenated successfully.
* - LZMA_DATA_ERROR: *dest would grow too big.
* - LZMA_MEM_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_index_cat(lzma_index *lzma_restrict dest,
lzma_index *lzma_restrict src,
lzma_allocator *allocator, lzma_vli padding)
lzma_attr_warn_unused_result;
/**
* \brief Duplicates an Index list
*
* \return A copy of the Index list, or NULL if memory allocation
* failed or the original Index was empty.
* \return A copy of the Index, or NULL if memory allocation failed.
*/
extern lzma_index *lzma_index_dup(
const lzma_index *index, lzma_allocator *allocator);
/**
* \brief Frees an Index list
*
* All Index Recors in the list are freed. This function is convenient when
* getting rid of lzma_metadata structures containing an Index.
*/
extern void lzma_index_free(lzma_index *index, lzma_allocator *allocator);
/**
* \brief Calculates information about the Index
*
* \return LZMA_OK on success, LZMA_PROG_ERROR on error. FIXME
*/
extern lzma_ret lzma_index_count(const lzma_index *index, size_t *count,
lzma_vli *lzma_restrict total_size,
lzma_vli *lzma_restrict uncompressed_size);
const lzma_index *i, lzma_allocator *allocator)
lzma_attr_warn_unused_result;
/**
* \brief Compares if two Index lists are identical
*/
extern lzma_bool lzma_index_is_equal(const lzma_index *a, const lzma_index *b);
extern lzma_bool lzma_index_equal(const lzma_index *a, const lzma_index *b)
lzma_attr_pure;
/**
* \brief Initializes Index encoder
*/
extern lzma_ret lzma_index_encoder(lzma_stream *strm, lzma_index *i)
lzma_attr_warn_unused_result;
/**
* \brief Initializes Index decoder
*/
extern lzma_ret lzma_index_decoder(lzma_stream *strm, lzma_index **i)
lzma_attr_warn_unused_result;

View File

@@ -0,0 +1,98 @@
/**
* \file lzma/index_hash.h
* \brief Validates Index by using a hash function
*
* Instead of constructing complete Index while decoding Blocks, Index hash
* calculates a hash of the Block sizes and Index, and then compares the
* hashes. This way memory usage is constant even with large number of
* Blocks and huge Index.
*
* \author Copyright (C) 2008 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Opaque data type to hold the Index hash
*/
typedef struct lzma_index_hash_s lzma_index_hash;
/**
* \brief Allocate and initialize a new lzma_index_hash structure
*
* If index_hash is NULL, a new lzma_index_hash structure is allocated,
* initialized, and a pointer to it returned. If allocation fails, NULL
* is returned.
*
* If index_hash is non-NULL, it is reinitialized and the same pointer
* returned. In this case, return value cannot be NULL or a different
* pointer than the index_hash given as argument.
*/
extern lzma_index_hash *lzma_index_hash_init(
lzma_index_hash *index_hash, lzma_allocator *allocator)
lzma_attr_warn_unused_result;
/**
* \brief Deallocate the Index hash
*/
extern void lzma_index_hash_end(
lzma_index_hash *index_hash, lzma_allocator *allocator);
/**
* \brief Add a new Record to an Index hash
*
* \param index Pointer to a lzma_index_hash structure
* \param total_size Total Size of a Block
* \param uncompressed_size Uncompressed Size of a Block
*
* \return - LZMA_OK
* - LZMA_DATA_ERROR: Compressed or uncompressed size of the
* Stream or size of the Index field would grow too big.
* - LZMA_PROG_ERROR: Invalid arguments or this function is being
* used when lzma_index_hash_decode() has already been used.
*/
extern lzma_ret lzma_index_hash_append(lzma_index_hash *index_hash,
lzma_vli total_size, lzma_vli uncompressed_size)
lzma_attr_warn_unused_result;
/**
* \brief Decode the Index field
*
* \return - LZMA_OK: So far good, but more input is needed.
* - LZMA_STREAM_END: Index decoded successfully and it matches
* the Records given with lzma_index_hash_append().
* - LZMA_DATA_ERROR: Index is corrupt or doesn't match the
* information given with lzma_index_hash_append().
* - LZMA_PROG_ERROR
*
* \note Once decoding of the Index field has been started, no more
* Records can be added using lzma_index_hash_append().
*/
extern lzma_ret lzma_index_hash_decode(lzma_index_hash *index_hash,
const uint8_t *in, size_t *in_pos, size_t in_size)
lzma_attr_warn_unused_result;
/**
* \brief Get the size of the Index field as bytes
*
* This is needed to verify the Index Size field from the Stream Footer.
*/
extern lzma_vli lzma_index_hash_size(const lzma_index_hash *index_hash)
lzma_attr_pure;

View File

@@ -1,315 +0,0 @@
/**
* \file lzma/info.h
* \brief Handling of Stream size information
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**********
* Basics *
**********/
/**
* \brief Opaque data type to hold the size information
*/
typedef struct lzma_info_s lzma_info;
typedef struct {
/**
* \brief Total Size of this Block
*
* This can be LZMA_VLI_VALUE_UNKNOWN.
*/
lzma_vli total_size;
/**
* \brief Uncompressed Size of this Block
*
* This can be LZMA_VLI_VALUE_UNKNOWN.
*/
lzma_vli uncompressed_size;
/**
* \brief Offset of the first byte of the Block
*
* In encoder, this is useful to find out the alignment of the Block.
*
* In decoder, this is useful when doing random-access reading
* with help from lzma_info_data_locate().
*/
lzma_vli stream_offset;
/**
* \brief Uncompressed offset of the Block
*
* Offset of the first uncompressed byte of the Block relative to
* all uncompressed data in the Block.
* FIXME desc
*/
lzma_vli uncompressed_offset;
/**
* \brief Pointers to internal data structures
*
* Applications must not touch these.
*/
void *internal[4];
} lzma_info_iter;
typedef enum {
LZMA_INFO_STREAM_START,
LZMA_INFO_HEADER_METADATA,
LZMA_INFO_TOTAL,
LZMA_INFO_UNCOMPRESSED,
LZMA_INFO_FOOTER_METADATA
} lzma_info_size;
/**
* \brief Allocates and initializes a new lzma_info structure
*
* If info is NULL, a new lzma_info structure is allocated, initialized, and
* a pointer to it returned. If allocation fails, NULL is returned.
*
* If info is non-NULL, it is reinitialized and the same pointer returned.
* (In this case, return value cannot be NULL or a different pointer than
* the info given as argument.)
*/
extern lzma_info *lzma_info_init(lzma_info *info, lzma_allocator *allocator);
/**
* \brief Resets lzma_info
*
* This is like calling lzma_info_end() and lzma_info_create(), but
* re-uses the existing base structure.
*/
extern void lzma_info_reset(
lzma_info *info, lzma_allocator *allocator);
/**
* \brief Frees memory allocated for a lzma_info structure
*/
extern void lzma_info_free(lzma_info *info, lzma_allocator *allocator);
/************************
* Setting known values *
************************/
/**
* \brief Set a known size value
*
* \param info Pointer returned by lzma_info_create()
* \param type Any value from lzma_info_size
* \param size Value to set or verify
*
* \return LZMA_OK on success, LZMA_DATA_ERROR if the size doesn't
* match the existing information, or LZMA_PROG_ERROR
* if type is invalid or size is not a valid VLI.
*/
extern lzma_ret lzma_info_size_set(
lzma_info *info, lzma_info_size type, lzma_vli size);
/**
* \brief Sets the Index
*
* The given lzma_index list is "absorbed" by this function. The application
* must not access it after this function call, even if this function returns
* an error.
*
* \note The given lzma_index will at some point get freed by the
* lzma_info_* functions. If you use a custom lzma_allocator,
* make sure that it can free the lzma_index.
*/
extern lzma_ret lzma_info_index_set(
lzma_info *info, lzma_allocator *allocator,
lzma_index *index, lzma_bool eat_index);
/**
* \brief Sets information from a known Metadata Block
*
* This is a shortcut for calling lzma_info_size_set() with different type
* arguments, lzma_info_index_set() with metadata->index.
*/
extern lzma_ret lzma_info_metadata_set(lzma_info *info,
lzma_allocator *allocator, lzma_metadata *metadata,
lzma_bool is_header_metadata, lzma_bool eat_index);
/***************
* Incremental *
***************/
/**
* \brief Prepares an iterator to be used with given lzma_info structure
*
*
*/
extern void lzma_info_iter_begin(lzma_info *info, lzma_info_iter *iter);
/**
* \brief Moves to the next Index Record
*
*
*/
extern lzma_ret lzma_info_iter_next(
lzma_info_iter *iter, lzma_allocator *allocator);
/**
* \brief Sets or verifies the sizes in the Index Record
*
* \param iter Pointer to iterator to be set or verified
* \param total_size
* Total Size in bytes or LZMA_VLI_VALUE_UNKNOWN
* \param uncompressed_size
* Uncompressed Size or LZMA_VLI_VALUE_UNKNOWN
*
* \return - LZMA_OK: All OK.
* - LZMA_DATA_ERROR: Given sizes don't match with the already
* known sizes.
* - LZMA_PROG_ERROR: Internal error, possibly integer
* overflow (e.g. the sum of all the known sizes is too big)
*/
extern lzma_ret lzma_info_iter_set(lzma_info_iter *iter,
lzma_vli total_size, lzma_vli uncompressed_size);
/**
* \brief Locates a Data Block
*
* \param iter Properly initialized iterator
* \param allocator Pointer to lzma_allocator or NULL
* \param uncompressed_offset
* Target offset to locate. The final offset
* will be equal or smaller than this.
* \param allow_alloc True if this function is allowed to call
* lzma_info_iter_next() to allocate a new Record
* if the requested offset reached end of Index
* Record list. Note that if Index has been marked
* final, lzma_info_iter_next() is never called.
*
* \return - LZMA_OK: All OK, *iter updated accordingly.
* - LZMA_DATA_ERROR: Trying to search past the end of the Index
* Record list, and allocating a new Record was not allowed
* either because allow_alloc was false or Index was final.
* - LZMA_PROG_ERROR: Internal error (probably integer
* overflow causing some lzma_vli getting too big).
*/
extern lzma_ret lzma_info_iter_locate(lzma_info_iter *iter,
lzma_allocator *allocator, lzma_vli uncompressed_offset,
lzma_bool allow_alloc);
/**
* \brief Finishes incrementally constructed Index
*
* This sets the known Total Size and Uncompressed of the Data Blocks
* based on the information collected from the Index Records, and marks
* the Index as final.
*/
extern lzma_ret lzma_info_index_finish(lzma_info *info);
/***************************
* Reading the information *
***************************/
/**
* \brief Gets a known size
*
*
*/
extern lzma_vli lzma_info_size_get(
const lzma_info *info, lzma_info_size type);
extern lzma_vli lzma_info_metadata_locate(
const lzma_info *info, lzma_bool is_header_metadata);
/**
* \brief Gets a pointer to the beginning of the Index list
*
* If detach is true, the Index will be detached from the lzma_info
* structure, and thus not be modified or freed by lzma_info_end().
*
* If detach is false, the application must not modify the Index in any way.
* Also, the Index list is guaranteed to be valid only till the next call
* to any lzma_info_* function.
*/
extern lzma_index *lzma_info_index_get(lzma_info *info, lzma_bool detach);
extern size_t lzma_info_index_count_get(const lzma_info *info);
extern uint32_t lzma_info_metadata_alignment_get(
const lzma_info *info, lzma_bool is_header_metadata);
/**
* \brief Locate a Block containing the given uncompressed offset
*
* This function is useful when you need to do random-access reading in
* a Multi-Block Stream.
*
* \param info Pointer to lzma_info that has at least one
* Index Record. The Index doesn't need to be finished.
* \param uncompressed_target
* Uncompressed target offset which the caller would
* like to locate from the Stream.
* \param stream_offset
* Starting offset (relative to the beginning the Stream)
* of the Block containing the requested location.
* \param uncompressed_offset
* The actual uncompressed offset of the beginning of
* the Block. uncompressed_offset <= uncompressed_target
* is always true; the application needs to uncompress
* uncompressed_target - uncompressed_offset bytes to
* reach the requested target offset.
* \param total_size
* Total Size of the Block. If the Index is incomplete,
* this may be LZMA_VLI_VALUE_UNKNOWN indicating unknown
* size.
* \param uncompressed_size
* Uncompressed Size of the Block. If the Index is
* incomplete, this may be LZMA_VLI_VALUE_UNKNOWN
* indicating unknown size. The application must pass
* this value to the Block decoder to verify FIXME
*
* \return
*
* \note This function is currently implemented as a linear search.
* If there are many Index Records, this can be really slow.
* This can be improved in newer liblzma versions if needed.
*/
extern lzma_bool lzma_info_data_locate(const lzma_info *info,
lzma_vli uncompressed_target,
lzma_vli *lzma_restrict stream_offset,
lzma_vli *lzma_restrict uncompressed_offset,
lzma_vli *lzma_restrict total_size,
lzma_vli *lzma_restrict uncompressed_size);

View File

@@ -38,7 +38,7 @@
* still shouldn't be done when there are multiple threads running.
*
* lzma_init() initializes all internal static variables by calling
* lzma_lzma_init_encoder() and lzma_init_decoder().
* lzma_init_encoder() and lzma_init_decoder().
*
* If you need only encoder, decoder, or neither-encoder-nor-decoder
* functions, you may use other initialization functions, which initialize

View File

@@ -24,43 +24,11 @@
/**
* \brief Filter ID
*
* Filter ID of the LZMA filter. This is used as lzma_options_filter.id.
* Filter ID of the LZMA filter. This is used as lzma_filter.id.
*/
#define LZMA_FILTER_LZMA LZMA_VLI_C(0x40)
#define LZMA_FILTER_LZMA LZMA_VLI_C(0x20)
/**
* \brief LZMA compression modes
*
* Currently there are only two modes. Earlier LZMA SDKs had also third
* mode between fast and best.
*/
typedef enum {
LZMA_MODE_INVALID = -1,
/**<
* \brief Invalid mode
*
* Used as array terminator in lzma_available_modes.
*/
LZMA_MODE_FAST = 0,
/**<
* \brief Fast compression
*
* Fast mode is usually at its best when combined with
* a hash chain match finder.
*/
LZMA_MODE_BEST = 2
/**<
* \brief Best compression ratio
*
* This is usually notably slower than fast mode. Use this
* together with binary tree match finders to expose the
* full potential of the LZMA encoder.
*/
} lzma_mode;
#define LZMA_FILTER_LZMA2 LZMA_VLI_C(0x21)
/**
@@ -128,6 +96,72 @@ typedef enum {
} lzma_match_finder;
/**
* \brief Test if given match finder is supported
*
* Returns true if the given match finder is supported by this liblzma build.
* Otherwise false is returned. It is safe to call this with a value that
* isn't listed in lzma_match_finder enumeration; the return value will be
* false.
*
* There is no way to list which match finders are available in this
* particular liblzma version and build. It would be useless, because
* a new match finder, which the application developer wasn't aware,
* could require giving additional options to the encoder that the older
* match finders don't need.
*/
extern lzma_bool lzma_mf_is_supported(lzma_match_finder match_finder)
lzma_attr_const;
/**
* \brief LZMA compression modes
*
* This selects the function used to analyze the data produced by the match
* finder.
*/
typedef enum {
LZMA_MODE_INVALID = -1,
/**<
* \brief Invalid mode
*
* Used as array terminator in lzma_available_modes.
*/
LZMA_MODE_FAST = 0,
/**<
* \brief Fast compression
*
* Fast mode is usually at its best when combined with
* a hash chain match finder.
*/
LZMA_MODE_NORMAL = 1
/**<
* \brief Normal compression
*
* This is usually notably slower than fast mode. Use this
* together with binary tree match finders to expose the
* full potential of the LZMA encoder.
*/
} lzma_mode;
/**
* \brief Test if given compression mode is supported
*
* Returns true if the given compression mode is supported by this liblzma
* build. Otherwise false is returned. It is safe to call this with a value
* that isn't listed in lzma_mode enumeration; the return value will be false.
*
* There is no way to list which modes are available in this particular
* liblzma version and build. It would be useless, because a new compression
* mode, which the application developer wasn't aware, could require giving
* additional options to the encoder that the older modes don't need.
*/
extern lzma_bool lzma_mode_is_available(lzma_mode mode) lzma_attr_const;
/**
* \brief Options specific to the LZMA method handler
*/
@@ -152,57 +186,10 @@ typedef struct {
* because it uses the target buffer as the dictionary.
*/
uint32_t dictionary_size;
# define LZMA_DICTIONARY_SIZE_MIN 1
# define LZMA_DICTIONARY_SIZE_MIN (UINT32_C(1) << 12)
# define LZMA_DICTIONARY_SIZE_MAX (UINT32_C(1) << 30)
# define LZMA_DICTIONARY_SIZE_DEFAULT (UINT32_C(1) << 23)
/**
* \brief Number of literal context bits
*
* How many of the highest bits of the previous uncompressed
* eight-bit byte (also known as `literal') are taken into
* account when predicting the bits of the next literal.
*
* \todo Example
*/
uint32_t literal_context_bits;
# define LZMA_LITERAL_CONTEXT_BITS_MIN 0
# define LZMA_LITERAL_CONTEXT_BITS_MAX 8
# define LZMA_LITERAL_CONTEXT_BITS_DEFAULT 3
/**
* \brief Number of literal position bits
*
* How many of the lowest bits of the current position (number
* of bytes from the beginning of the uncompressed data) in the
* uncompressed data is taken into account when predicting the
* bits of the next literal (a single eight-bit byte).
*
* \todo Example
*/
uint32_t literal_pos_bits;
# define LZMA_LITERAL_POS_BITS_MIN 0
# define LZMA_LITERAL_POS_BITS_MAX 4
# define LZMA_LITERAL_POS_BITS_DEFAULT 0
/**
* \brief Number of position bits
*
* How many of the lowest bits of the current position in the
* uncompressed data is taken into account when estimating
* probabilities of matches. A match is a sequence of bytes for
* which a matching sequence is found from the dictionary and
* thus can be stored as distance-length pair.
*
* Example: If most of the matches occur at byte positions
* of 8 * n + 3, that is, 3, 11, 19, ... set pos_bits to 3,
* because 2**3 == 8.
*/
uint32_t pos_bits;
# define LZMA_POS_BITS_MIN 0
# define LZMA_POS_BITS_MAX 4
# define LZMA_POS_BITS_DEFAULT 2
/**
* \brief Pointer to an initial dictionary
*
@@ -241,10 +228,70 @@ typedef struct {
*/
uint32_t preset_dictionary_size;
/**
* \brief Number of literal context bits
*
* How many of the highest bits of the previous uncompressed
* eight-bit byte (also known as `literal') are taken into
* account when predicting the bits of the next literal.
*
* \todo Example
*/
uint32_t literal_context_bits;
# define LZMA_LITERAL_CONTEXT_BITS_MIN 0
# define LZMA_LITERAL_CONTEXT_BITS_MAX 4
# define LZMA_LITERAL_CONTEXT_BITS_DEFAULT 3
/**
* \brief Number of literal position bits
*
* How many of the lowest bits of the current position (number
* of bytes from the beginning of the uncompressed data) in the
* uncompressed data is taken into account when predicting the
* bits of the next literal (a single eight-bit byte).
*
* \todo Example
*/
uint32_t literal_pos_bits;
# define LZMA_LITERAL_POS_BITS_MIN 0
# define LZMA_LITERAL_POS_BITS_MAX 4
# define LZMA_LITERAL_POS_BITS_DEFAULT 0
/**
* \brief Number of position bits
*
* How many of the lowest bits of the current position in the
* uncompressed data is taken into account when estimating
* probabilities of matches. A match is a sequence of bytes for
* which a matching sequence is found from the dictionary and
* thus can be stored as distance-length pair.
*
* Example: If most of the matches occur at byte positions
* of 8 * n + 3, that is, 3, 11, 19, ... set pos_bits to 3,
* because 2**3 == 8.
*/
uint32_t pos_bits;
# define LZMA_POS_BITS_MIN 0
# define LZMA_POS_BITS_MAX 4
# define LZMA_POS_BITS_DEFAULT 2
/******************************************
* LZMA options needed only when encoding *
******************************************/
/**
* \brief Indicate if the options structure is persistent
*
* If this is true, the application must keep this options structure
* available after the LZMA2 encoder has been initialized. With
* persistent structure it is possible to change some encoder options
* in the middle of the encoding process without resetting the encoder.
*
* This option is used only by LZMA2. LZMA1 ignores this and it is
* safeto not initialize this when encoding with LZMA1.
*/
lzma_bool persistent;
/** LZMA compression mode */
lzma_mode mode;
@@ -275,34 +322,35 @@ typedef struct {
*/
uint32_t match_finder_cycles;
/**
* \brief Reserved space for possible future extensions
*
* You should not touch these, because the names of these variables
* may change. These are and will never be used with the currently
* supported options, so it is safe to leave these uninitialized.
*/
uint32_t reserved_int1;
uint32_t reserved_int2;
uint32_t reserved_int3;
uint32_t reserved_int4;
void *reserved_ptr1;
void *reserved_ptr2;
} lzma_options_lzma;
/**
* \brief Available LZMA encoding modes
* \brief Maximum sum of literal_context_bits and literal_pos_bits
*
* Pointer to an array containing the list of available encoding modes.
*
* This variable is available only if LZMA encoder has been enabled.
* literal_context_bits + literal_pos_bits <= LZMA_LITERAL_BITS_MAX
*/
extern const lzma_mode *const lzma_available_modes;
/**
* \brief Available match finders
*
* Pointer to an array containing the list of available match finders.
* The last element is LZMA_MF_INVALID.
*
* This variable is available only if LZMA encoder has been enabled.
*/
extern const lzma_match_finder *const lzma_available_match_finders;
#define LZMA_LITERAL_BITS_MAX 4
/**
* \brief Table of presets for the LZMA filter
*
* lzma_presets[0] is the fastest and lzma_preset_lzma[8] is the slowest.
* lzma_preset_lzma[0] is the fastest and lzma_preset_lzma[8] is the slowest.
* These presets match the switches -1 .. -9 of the lzma command line tool
*
* The preset values are subject to changes between liblzma versions.

View File

@@ -1,6 +1,6 @@
/**
* \file lzma/memlimit.h
* \brief Memory usage limitter
* \brief Memory usage limiter
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
@@ -22,7 +22,7 @@
/**
* \brief Opaque data type used with the memory usage limitting functions
* \brief Opaque data type used with the memory usage limiting functions
*/
typedef struct lzma_memlimit_s lzma_memlimit;
@@ -39,7 +39,7 @@ typedef struct lzma_memlimit_s lzma_memlimit;
* to these functions can be used in lzma_allocator structure, which makes
* it easy to limit memory usage with liblzma.
*
* The memory limitter functions are not tied to limitting memory usage
* The memory limiter functions are not tied to limiting memory usage
* with liblzma itself. You can use them with anything you like.
*
* In multi-threaded applications, only one thread at once may use the same
@@ -58,7 +58,8 @@ typedef struct lzma_memlimit_s lzma_memlimit;
* lzma_memlimit_ can be used even if lzma_init() hasn't been
* called.
*/
extern lzma_memlimit *lzma_memlimit_create(size_t limit);
extern lzma_memlimit *lzma_memlimit_create(size_t limit)
lzma_attr_warn_unused_result;
/**
@@ -79,7 +80,8 @@ extern void lzma_memlimit_set(lzma_memlimit *mem, size_t limit);
/**
* \brief Gets the current memory usage limit
*/
extern size_t lzma_memlimit_get(const lzma_memlimit *mem);
extern size_t lzma_memlimit_get(const lzma_memlimit *mem)
lzma_attr_pure;
/**
@@ -89,7 +91,54 @@ extern size_t lzma_memlimit_get(const lzma_memlimit *mem);
* thus it will always be larger than the total number of
* bytes allocated via lzma_memlimit_alloc().
*/
extern size_t lzma_memlimit_used(const lzma_memlimit *mem);
extern size_t lzma_memlimit_used(const lzma_memlimit *mem)
lzma_attr_pure;
/**
* \brief Gets the maximum amount of memory required in total
*
* Returns how much memory was or would have been allocated at the same time.
* If lzma_memlimit_alloc() was requested so much memory that the limit
* would have been exceeded or malloc() simply ran out of memory, the
* requested amount is still included to the value returned by
* lzma_memlimit_max(). This may be used as a hint how much bigger memory
* limit would have been needed.
*
* If the clear flag is set, the internal variable holding the maximum
* value is set to the current memory usage (the same value as returned
* by lzma_memlimit_used()).
*
* \note Usually liblzma needs to allocate many chunks of memory, and
* displaying a message like "memory usage limit reached, at
* least 1024 bytes would have been needed" may be confusing,
* because the next allocation could have been e.g. 8 MiB.
*
* \todo The description of this function is unclear.
*/
extern size_t lzma_memlimit_max(lzma_memlimit *mem, lzma_bool clear);
/**
* \brief Checks if memory limit was reached at some point
*
* This function is useful to find out if the reason for LZMA_MEM_ERROR
* was running out of memory or hitting the memory usage limit imposed
* by lzma_memlimit_alloc(). If the clear argument is true, the internal
* flag, that indicates that limit was reached, is cleared.
*/
extern lzma_bool lzma_memlimit_reached(lzma_memlimit *mem, lzma_bool clear);
/**
* \brief Gets the number of allocations owned by the memory limiter
*
* The count does not include the helper structures; if no memory has
* been allocated with lzma_memlimit_alloc() or all memory allocated
* has been freed or detached, this will return zero.
*/
extern size_t lzma_memlimit_count(const lzma_memlimit *mem)
lzma_attr_pure;
/**
@@ -112,11 +161,12 @@ extern size_t lzma_memlimit_used(const lzma_memlimit *mem);
* invalid amount of memory being allocated.
*/
extern void *lzma_memlimit_alloc(
lzma_memlimit *mem, size_t nmemb, size_t size);
lzma_memlimit *mem, size_t nmemb, size_t size)
lzma_attr_warn_unused_result;
/**
* \brief Removes the pointer from memory limitting list
* \brief Removes the pointer from memory limiting list
*
* \param mem Pointer to a lzma_memlimit structure returned
* earlier by lzma_memry_limit_create().
@@ -144,9 +194,9 @@ extern void lzma_memlimit_free(lzma_memlimit *mem, void *ptr);
/**
* \brief Frees the memory allocated for and by the memory usage limitter
* \brief Frees the memory allocated for and by the memory usage limiter
*
* \param mem Pointer to memory limitter
* \param mem Pointer to memory limiter
* \param free_allocated If this is non-zero, all the memory allocated
* by lzma_memlimit_alloc() using *mem is also
* freed if it hasn't already been freed with

View File

@@ -1,100 +0,0 @@
/**
* \file lzma/metadata.h
* \brief Metadata handling
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Information stored into a Metadata Block
*
* This structure holds all the information that can be stored to
* a Metadata Block.
*/
typedef struct {
/**
* \brief Size of Header Metadata Block
*/
lzma_vli header_metadata_size;
/**
* \brief Total Size of the Stream
*/
lzma_vli total_size;
/**
* \brief Uncompressed Size of the Stream
*/
lzma_vli uncompressed_size;
/**
* \brief Index of the Blocks stored in the Stream
*/
lzma_index *index;
/**
* \brief Extra information
*/
lzma_extra *extra;
} lzma_metadata;
/**
* \brief Calculate the encoded size of Metadata
*
* \return Uncompressed size of the Metadata in encoded form. This value
* may be passed to Block encoder as Uncompressed Size when using
* Metadata filter. On error, zero is returned.
*/
extern lzma_vli lzma_metadata_size(const lzma_metadata *metadata);
/**
* \brief Initializes Metadata encoder
*
* \param coder Pointer to a pointer to hold Metadata encoder's
* internal state. Original value is ignored, thus
* you don't need to initialize the pointer.
* \param allocator Custom memory allocator; usually NULL.
* \param metadata Pointer to Metadata to encoded
*
* \return - LZMA_OK: Initialization succeeded.
* - LZMA_MEM_ERROR: Cannot allocate memory for *coder.
*
* The initialization function makes internal copy of the *metadata structure.
* However, the linked lists metadata->index and metadata->extra are NOT
* copied. Thus, the application may destroy *metadata after initialization
* if it likes, but not Index or Extra.
*/
extern lzma_ret lzma_metadata_encoder(lzma_stream *strm,
lzma_options_block *options, const lzma_metadata *metadata);
/**
* \brief Initializes Metadata decoder
*
* \param want_extra If this is true, Extra Records will be stored
* to metadata->extra. If this is false, Extra
* Records will be parsed but not stored anywhere,
* metadata->extra will be set to NULL.
*/
extern lzma_ret lzma_metadata_decoder(
lzma_stream *strm, lzma_options_block *options,
lzma_metadata *metadata, lzma_bool want_extra);

View File

@@ -1,72 +0,0 @@
/**
* \file lzma/raw.h
* \brief Raw encoder and decoder
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Initializes raw encoder
*
* This function may be useful when implementing custom file formats.
*
* \param strm Pointer to properly prepared lzma_stream
* \param options Array of lzma_options_filter structures.
* The end of the array must be marked with
* .id = LZMA_VLI_VALUE_UNKNOWN. The minimum
* number of filters is zero; the maximum is
* determined by available memory.
* \param uncompressed_size
* Size of the uncompressed data. If it is unknown,
* use LZMA_VLI_VALUE_UNKNOWN. You need to give the
* same value to the raw decoder to decode the data.
* \param allow_implicit
* If true, an implicit Copy or Subblock filter should be
* automatically added when needed. If this is false and
* an implicit filter would be needed, LZMA_PROG_ERROR is
* returned.
*
* The `action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
* filter chain support it), or LZMA_FINISH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_raw_encoder(
lzma_stream *strm, const lzma_options_filter *options,
lzma_vli uncompressed_size, lzma_bool allow_implicit);
/**
* \brief Initializes raw decoder
*
* The initialization of raw decoder goes similarly to raw encoder.
*
* The `action' with lzma_code() can be LZMA_RUN or LZMA_SYNC_FLUSH.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_HEADER_ERROR
* - LZMA_PROG_ERROR
*/
extern lzma_ret lzma_raw_decoder(
lzma_stream *strm, const lzma_options_filter *options,
lzma_vli uncompressed_size, lzma_bool allow_implicit);

View File

@@ -21,7 +21,7 @@
#endif
/* Filter IDs for lzma_options_filter.id */
/* Filter IDs for lzma_filter.id */
#define LZMA_FILTER_X86 LZMA_VLI_C(0x04)
/**<
@@ -64,6 +64,15 @@
*
* If options with non-default values have been specified when encoding,
* the same options must also be specified when decoding.
*
* \note At the moment, none of the simple filters support
* LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified,
* LZMA_HEADER_ERROR will be returned. If there is need,
* partial support for LZMA_SYNC_FLUSH can be added in future.
* Partial means that flushing would be possible only at
* offsets that are multiple of 2, 4, or 16 depending on
* the filter, except x86 which cannot be made to support
* LZMA_SYNC_FLUSH predictably.
*/
typedef struct {
/**

View File

@@ -1,178 +0,0 @@
/**
* \file lzma/stream.h
* \brief .lzma Stream handling
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#ifndef LZMA_H_INTERNAL
# error Never include this file directly. Use <lzma.h> instead.
#endif
/**
* \brief Options for .lzma Stream encoder
*/
typedef struct {
/**
* \brief Type of integrity Check
*
* The type of the integrity Check is stored into Stream Header
* and Stream Footer. The same Check is used for all Blocks in
* the Stream.
*/
lzma_check_type check;
/**
* \brief Precense of CRC32 of the Block Header
*
* Set this to true if CRC32 of every Block Header should be
* calculated and stored in the Block Header. This is recommended.
*
* This setting is stored into Stream Header and Stream Footer.
*/
lzma_bool has_crc32;
/**
* \brief Uncompressed Size in bytes
*
* This is somewhat advanced feature. Most users want to set this to
* LZMA_VLI_VALUE_UNKNOWN to indicate unknown Uncompressed Size.
*
* If the Uncompressed Size of the Stream being encoded is known,
* it can be stored to the beginning of the Stream. The details
* differ for Single-Block and Multi-Block Streams:
* - With Single-Block Streams, the Uncompressed Size is stored to
* the Block Header and End of Payload Marker is omitted.
* - With Multi-Block Streams, the Uncompressed Size is stored to
* the Header Metadata Block. The Uncompressed Size of the Blocks
* will be unknown, because liblzma cannot predict how the
* application is going to split the data in Blocks.
*/
lzma_vli uncompressed_size;
/**
* \brief Alignment of the beginning of the Stream
*
* Certain filters handle data in bigger chunks than single bytes.
* This affects two things:
* - Performance: aligned memory access is usually faster.
* - Further compression ratio in custom file formats: if you
* encode multiple Blocks with some non-compression filter
* such as LZMA_FILTER_POWERPC, it is a good idea to keep
* the inter-Block alignment correct to maximize compression
* ratio when all these Blocks are finally compressed as a
* single step.
*
* Usually the Stream is stored into its own file, thus
* the alignment is usually zero.
*/
uint32_t alignment;
/**
* \brief Array of filters used to encode Data Blocks
*
* There can be at maximum of seven filters. The end of the array is
* marked with .id = LZMA_VLI_VALUE_UNKNOWN. (That's why the array
* has eight members.) Minimum number of filters is zero; in that
* case, an implicit Copy filter is used.
*/
lzma_options_filter filters[8];
/**
* \brief Array of filters used to encode Metadata Blocks
*
* This is like filters[] but for Metadata Blocks. If Metadata
* Blocks are compressed, they usually are compressed with
* settings that require only little memory to uncompress e.g.
* LZMA with 64 KiB dictionary.
*
* \todo Recommend a preset.
*
* When liblzma sees that the Metadata Block would be very small
* even in uncompressed form, it is not compressed no matter
* what filter have been set here. This is to avoid possibly
* increasing the size of the Metadata Block with bad compression,
* and to avoid useless overhead of filters in uncompression phase.
*/
lzma_options_filter metadata_filters[8];
/**
* \brief Extra information in the Header Metadata Block
*/
lzma_extra *header;
/**
* \brief Extra information in the Footer Metadata Block
*
* It is enough to set this pointer any time before calling
* lzma_code() with LZMA_FINISH as the second argument.
*/
lzma_extra *footer;
} lzma_options_stream;
/**
* \brief Initializes Single-Block .lzma Stream encoder
*
* This is the function that most developers are looking for. :-) It
* compresses using the specified options without storing any extra
* information.
*
* \todo Describe that is_metadata is ignored, maybe something else.
*/
extern lzma_ret lzma_stream_encoder_single(
lzma_stream *strm, const lzma_options_stream *options);
/**
* \brief Initializes Multi-Block .lzma Stream encoder
*
*/
extern lzma_ret lzma_stream_encoder_multi(
lzma_stream *strm, const lzma_options_stream *options);
/**
* \brief Initializes decoder for .lzma Stream
*
* \param strm Pointer to propertily prepared lzma_stream
* \param header Pointer to hold a pointer to Extra Records read
* from the Header Metadata Block. Use NULL if
* you don't care about Extra Records.
* \param footer Same as header, but for Footer Metadata Block.
*
* \return - LZMA_OK: Initialization was successful.
* - LZMA_MEM_ERROR: Cannot allocate memory.
*
* If header and/or footer are not NULL, *header and/or *footer will be
* initially set to NULL.
*
* The application can detect that Header Metadata Block has been completely
* parsed when the decoder procudes some output the first time. If *header
* is still NULL, there was no Extra field in the Header Metadata Block (or
* the whole Header Metadata Block wasn't present at all).
*
* The application can detect that Footer Metadata Block has been parsed
* completely when lzma_code() returns LZMA_STREAM_END. If *footer is still
* NULL, there was no Extra field in the Footer Metadata Block.
*
* \note If you use lzma_memory_limitter, the Extra Records will be
* allocated with it, and thus remain in the lzma_memory_limitter
* even after they get exported to the application via *header
* and *footer pointers.
*/
extern lzma_ret lzma_stream_decoder(lzma_stream *strm,
lzma_extra **header, lzma_extra **footer);

View File

@@ -1,6 +1,6 @@
/**
* \file lzma/stream_flags.h
* \brief .lzma Stream Header and Stream tail encoder and decoder
* \brief .lzma Stream Header and Stream Footer encoder and decoder
*
* \author Copyright (C) 1999-2006 Igor Pavlov
* \author Copyright (C) 2007 Lasse Collin
@@ -22,121 +22,118 @@
/**
* \brief Size of Stream Header
* \brief Size of Stream Header and Stream Footer
*
* Magic Bytes (6) + Stream Flags (1) + CRC32 (4)
* Stream Header and Stream Footer have the same size and they are not
* going to change even if a newer version of the .lzma file format is
* developed in future.
*/
#define LZMA_STREAM_HEADER_SIZE (6 + 1 + 4)
#define LZMA_STREAM_HEADER_SIZE 12
/**
* \brief Size of Stream tail
*
* Because Stream Footer already has a defined meaning in the file format
* specification, we use Stream tail to denote these two fields:
* Stream Flags (1) + Magic Bytes (2)
*/
#define LZMA_STREAM_TAIL_SIZE (1 + 2)
/**
* Options for encoding and decoding Stream Header and Stream tail
* Options for encoding and decoding Stream Header and Stream Footer
*/
typedef struct {
/**
* Backward Size must be a multiple of four bytes. In this Stream
* format version Backward Size is the size of the Index field.
*/
lzma_vli backward_size;
# define LZMA_BACKWARD_SIZE_MIN 4
# define LZMA_BACKWARD_SIZE_MAX (LZMA_VLI_C(1) << 34)
/**
* Type of the Check calculated from uncompressed data
*/
lzma_check_type check;
/**
* True if Block Headers have the CRC32 field. Note that the CRC32
* field is always present in the Stream Header.
*/
lzma_bool has_crc32;
/**
* True if the Stream is a Multi-Block Stream.
*/
lzma_bool is_multi;
lzma_check check;
} lzma_stream_flags;
#define lzma_stream_flags_is_equal(a, b) \
((a).check == (b).check \
&& (a).has_crc32 == (b).has_crc32 \
&& (a).is_multi == (b).is_multi)
/**
* \brief Encodes Stream Header
* \brief Encode Stream Header
*
* Encoding of the Stream Header is done with a single call instead of
* first initializing and then doing the actual work with lzma_code().
*
* \param out Beginning of the output buffer
* \param out_pos out[*out_pos] is the next write position. This
* is updated by the encoder.
* \param out_size out[out_size] is the first byte to not write.
* \param out Beginning of the output buffer of
* LZMA_STREAM_HEADER_SIZE bytes.
* \param options Stream Header options to be encoded.
* options->index_size is ignored and doesn't
* need to be initialized.
*
* \return - LZMA_OK: Encoding was successful.
* - LZMA_PROG_ERROR: Invalid options.
* - LZMA_BUF_ERROR: Not enough output buffer space.
*/
extern lzma_ret lzma_stream_header_encode(
uint8_t *out, const lzma_stream_flags *options);
const lzma_stream_flags *options, uint8_t *out)
lzma_attr_warn_unused_result;
/**
* \brief Encodes Stream tail
* \brief Encode Stream Footer
*
* \param out Beginning of the output buffer of
* LZMA_STREAM_HEADER_SIZE bytes.
* \param options Stream Footer options to be encoded.
*
* \return - LZMA_OK: Encoding was successful.
* - LZMA_PROG_ERROR: Invalid options.
*/
extern lzma_ret lzma_stream_footer_encode(
const lzma_stream_flags *options, uint8_t *out)
lzma_attr_warn_unused_result;
/**
* \brief Decode Stream Header
*
* \param footer Pointer to a pointer that will hold the
* allocated buffer. Caller must free it once
* it isn't needed anymore.
* \param footer_size Pointer to a variable that will the final size
* of the footer buffer.
* \param allocator lzma_allocator for custom allocator functions.
* Set to NULL to use malloc().
* \param options Stream Header options to be encoded.
* \param in Beginning of the input buffer of
* LZMA_STREAM_HEADER_SIZE bytes.
*
* \return - LZMA_OK: Success; *header and *header_size set.
* - LZMA_PROG_ERROR: *options is invalid.
* - LZMA_MEM_ERROR: Cannot allocate memory.
* options->index_size is always set to LZMA_VLI_VALUE_UNKNOWN. This is to
* help comparing Stream Flags from Stream Header and Stream Footer with
* lzma_stream_flags_equal().
*
* \return - LZMA_OK: Decoding was successful.
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
* buffer cannot be Stream Header.
* - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header
* is corrupt.
* - LZMA_HEADER_ERROR: Unsupported options are present
* in the header.
*/
extern lzma_ret lzma_stream_tail_encode(
uint8_t *out, const lzma_stream_flags *options);
extern lzma_ret lzma_stream_header_decode(
lzma_stream_flags *options, const uint8_t *in)
lzma_attr_warn_unused_result;
/**
* \brief Initializes Stream Header decoder
* \brief Decode Stream Footer
*
* \param strm Pointer to lzma_stream used to pass input data
* \param options Target structure for parsed results
* \param options Stream Header options to be encoded.
* \param in Beginning of the input buffer of
* LZMA_STREAM_HEADER_SIZE bytes.
*
* \return - LZMA_OK: Successfully initialized
* - LZMA_MEM_ERROR: Cannot allocate memory
*
* The actual decoding is done with lzma_code() and freed with lzma_end().
* \return - LZMA_OK: Decoding was successful.
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
* buffer cannot be Stream Footer.
* - LZMA_DATA_ERROR: CRC32 doesn't match, thus the footer
* is corrupt.
* - LZMA_HEADER_ERROR: Unsupported options are present
* in the footer.
*/
extern lzma_ret lzma_stream_header_decoder(
lzma_stream *strm, lzma_stream_flags *options);
extern lzma_ret lzma_stream_footer_decode(
lzma_stream_flags *options, const uint8_t *in)
lzma_attr_warn_unused_result;
/**
* \brief Initializes Stream tail decoder
* \brief Compare two lzma_stream_flags structures
*
* \param strm Pointer to lzma_stream used to pass input data
* \param options Target structure for parsed results.
* \param decode_uncompressed_size
* Set to true if the first field to decode is
* Uncompressed Size. Set to false if the first
* field to decode is Backward Size.
* index_size values are compared only if both are not LZMA_VLI_VALUE_UNKNOWN.
*
* \return - LZMA_OK: Successfully initialized
* - LZMA_MEM_ERROR: Cannot allocate memory
*
* The actual decoding is done with lzma_code() and freed with lzma_end().
* \return true if both structures are considered equal; false otherwise.
*/
extern lzma_ret lzma_stream_tail_decoder(
lzma_stream *strm, lzma_stream_flags *options);
extern lzma_bool lzma_stream_flags_equal(
const lzma_stream_flags *a, const lzma_stream_flags *b)
lzma_attr_pure;

View File

@@ -24,7 +24,7 @@
/**
* \brief Filter ID
*
* Filter ID of the Subblock filter. This is used as lzma_options_filter.id.
* Filter ID of the Subblock filter. This is used as lzma_filter.id.
*/
#define LZMA_FILTER_SUBBLOCK LZMA_VLI_C(0x01)
@@ -95,9 +95,10 @@ typedef struct {
* input_offset % alignment == output_offset % alignment
*
* The Subblock filter assumes that the first output byte will be
* written to a position in the output stream that is properly aligned.
*
* FIXME desc
* written to a position in the output stream that is properly
* aligned. This requirement is automatically met when the start
* offset of the Stream or Block is correctly told to Block or
* Stream encoder.
*/
uint32_t alignment;
# define LZMA_SUBBLOCK_ALIGNMENT_MIN 1
@@ -161,16 +162,17 @@ typedef struct {
*
* When subfilter_mode is LZMA_SUBFILTER_NONE, the application may
* put Subfilter options to subfilter_options structure, and then
* set subfilter_mode to LZMA_SUBFILTER_SET. This implies setting
* flush to true. No new input data will be read until the Subfilter
* has been enabled. Once the Subfilter has been enabled, liblzma
* will set subfilter_mode to LZMA_SUBFILTER_RUN.
* set subfilter_mode to LZMA_SUBFILTER_SET. No new input data will
* be read until the Subfilter has been enabled. Once the Subfilter
* has been enabled, liblzma will set subfilter_mode to
* LZMA_SUBFILTER_RUN.
*
* When subfilter_mode is LZMA_SUBFILTER_RUN, the application may
* set subfilter_mode to LZMA_SUBFILTER_FINISH. No new input data
* will be read until the Subfilter has been finished. Once the
* Subfilter has been finished, liblzma will set subfilter_mode
* to LZMA_SUBFILTER_NONE.
* set subfilter_mode to LZMA_SUBFILTER_FINISH. All the input
* currently available will be encoded before unsetting the
* Subfilter. Application must not change the amount of available
* input until the Subfilter has finished. Once the Subfilter has
* finished, liblzma will set subfilter_mode to LZMA_SUBFILTER_NONE.
*
* If the intent is to have Subfilter enabled to the very end of
* the data, it is not needed to separately disable Subfilter with
@@ -178,6 +180,11 @@ typedef struct {
* of lzma_code() will make the Subblock encoder to disable the
* Subfilter once all the data has been ran through the Subfilter.
*
* After the first call with LZMA_SYNC_FLUSH or LZMA_FINISH, the
* application must not change subfilter_mode until LZMA_STREAM_END.
* Setting LZMA_SUBFILTER_SET/LZMA_SUBFILTER_FINISH and
* LZMA_SYNC_FLUSH/LZMA_FINISH _at the same time_ is fine.
*
* \note This variable is ignored if allow_subfilters is false.
*/
lzma_subfilter_mode subfilter_mode;
@@ -192,6 +199,6 @@ typedef struct {
*
* \note This variable is ignored if allow_subfilters is false.
*/
lzma_options_filter subfilter_options;
lzma_filter subfilter_options;
} lzma_options_subblock;

View File

@@ -24,36 +24,34 @@
/**
* \brief Compile-time version number
*
* The version number is of format xyyyuuus where
* - x is the major LZMA SDK version
* - yyy is the minor LZMA SDK version
* - uuu is LZMA Utils version (reset to zero every time SDK version
* is incremented)
* The version number is of format xyyyzzzs where
* - x = major
* - yyy = minor
* - zzz = revision
* - s indicates stability: 0 = alpha, 1 = beta, 2 = stable
*
* See the README file for details about the version numbering.
*
* \note The version number of LZMA Utils (and thus liblzma)
* has nothing to with the version number of LZMA SDK.
*/
#define LZMA_VERSION UINT32_C(40420010)
#define LZMA_VERSION UINT32_C(49990050)
/**
* \brief liblzma version number as an integer
*
* This is the value of LZMA_VERSION macro at the compile time of liblzma.
* Returns the value of LZMA_VERSION macro at the compile time of liblzma.
* This allows the application to compare if it was built against the same,
* older, or newer version of liblzma that is currently running.
*/
extern const uint32_t lzma_version_number;
extern uint32_t lzma_version_number(void) lzma_attr_const;
/**
* \brief Returns versions number of liblzma as a string
* \brief Version number of liblzma as a string
*
* This function may be useful if you want to display which version of
* libilzma your application is currently using.
*
* \return Returns a pointer to a statically allocated string constant,
* which contains the version number of liblzma. The format of
* the version string is usually (but not necessarily) x.y.z
* e.g. "4.42.1". Alpha and beta versions contain a suffix
* ("4.42.0alpha").
* liblzma your application is currently using.
*/
extern const char *const lzma_version_string;
extern const char *lzma_version_string(void) lzma_attr_const;

View File

@@ -71,112 +71,55 @@ typedef uint64_t lzma_vli;
((vli) <= LZMA_VLI_VALUE_MAX || (vli) == LZMA_VLI_VALUE_UNKNOWN)
/**
* \brief Sets VLI to given value with error checking
*
* \param dest Target variable which must have type of lzma_vli.
* \param src New value to be stored to dest.
* \param limit Maximum allowed value for src.
*
* \return False on success, true on error. If an error occurred,
* dest is left in undefined state (i.e. it's possible that
* it will be different in newer liblzma versions).
*/
#define lzma_vli_set_lim(dest, src, limit) \
((src) > (limit) || ((dest) = (src)) > (limit))
/**
* \brief
*/
#define lzma_vli_add_lim(dest, src, limit) \
((src) > (limit) || ((dest) += (src)) > (limit))
#define lzma_vli_add2_lim(dest, src1, src2, limit) \
(lzma_vli_add_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit))
#define lzma_vli_add3_lim(dest, src1, src2, src3, limit) \
(lzma_vli_add_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit) \
|| lzma_vli_add_lim(dest, src3, limit))
#define lzma_vli_add4_lim(dest, src1, src2, src3, src4, limit) \
(lzma_vli_add_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit) \
|| lzma_vli_add_lim(dest, src3, limit) \
|| lzma_vli_add_lim(dest, src4, limit))
#define lzma_vli_sum_lim(dest, src1, src2, limit) \
(lzma_vli_set_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit))
#define lzma_vli_sum3_lim(dest, src1, src2, src3, limit) \
(lzma_vli_set_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit) \
|| lzma_vli_add_lim(dest, src3, limit))
#define lzma_vli_sum4_lim(dest, src1, src2, src3, src4, limit) \
(lzma_vli_set_lim(dest, src1, limit) \
|| lzma_vli_add_lim(dest, src2, limit) \
|| lzma_vli_add_lim(dest, src3, limit) \
|| lzma_vli_add_lim(dest, src4, limit))
#define lzma_vli_set(dest, src) lzma_vli_set_lim(dest, src, LZMA_VLI_VALUE_MAX)
#define lzma_vli_add(dest, src) lzma_vli_add_lim(dest, src, LZMA_VLI_VALUE_MAX)
#define lzma_vli_add2(dest, src1, src2) \
lzma_vli_add2_lim(dest, src1, src2, LZMA_VLI_VALUE_MAX)
#define lzma_vli_add3(dest, src1, src2, src3) \
lzma_vli_add3_lim(dest, src1, src2, src3, LZMA_VLI_VALUE_MAX)
#define lzma_vli_add4(dest, src1, src2, src3, src4) \
lzma_vli_add4_lim(dest, src1, src2, src3, src4, LZMA_VLI_VALUE_MAX)
#define lzma_vli_sum(dest, src1, src2) \
lzma_vli_sum_lim(dest, src1, src2, LZMA_VLI_VALUE_MAX)
#define lzma_vli_sum3(dest, src1, src2, src3) \
lzma_vli_sum3_lim(dest, src1, src2, src3, LZMA_VLI_VALUE_MAX)
#define lzma_vli_sum4(dest, src1, src2, src3, src4) \
lzma_vli_sum4_lim(dest, src1, src2, src3, src4, LZMA_VLI_VALUE_MAX)
/**
* \brief Encodes variable-length integer
*
* In the new .lzma format, most integers are encoded in variable-length
* In the .lzma format, most integers are encoded in variable-length
* representation. This saves space when smaller values are more likely
* than bigger values.
*
* The encoding scheme encodes seven bits to every byte, using minimum
* number of bytes required to represent the given value. In other words,
* it puts 7-63 bits into 1-9 bytes. This implementation limits the number
* of bits used to 63, thus num must be at maximum of INT64_MAX / 2. You
* may use LZMA_VLI_VALUE_MAX for clarity.
* number of bytes required to represent the given value. Encodings that use
* non-minimum number of bytes are invalid, thus every integer has exactly
* one encoded representation. The maximum number of bits in a VLI is 63,
* thus the vli argument must be at maximum of UINT64_MAX / 2. You should
* use LZMA_VLI_VALUE_MAX for clarity.
*
* This function has two modes: single-call and multi-call. Single-call mode
* encodes the whole integer at once; it is an error if the output buffer is
* too small. Multi-call mode saves the position in *vli_pos, and thus it is
* possible to continue encoding if the buffer becomes full before the whole
* integer has been encoded.
*
* \param vli Integer to be encoded
* \param vli_pos How many bytes have already been written out. This
* must be less than 9 before calling this function.
* \param vli_size Minimum size that the variable-length representation
* must take. This is useful if you want to use
* variable-length integers as padding. Usually you want
* to set this to zero. The maximum allowed value is 9.
* \param vli_pos How many VLI-encoded bytes have already been written
* out. When starting to encode a new integer, *vli_pos
* must be set to zero. To use single-call encoding,
* set vli_pos to NULL.
* \param out Beginning of the output buffer
* \param out_pos The next byte will be written to out[*out_pos].
* \param out_size Size of the out buffer; the first byte into
* which no data is written to is out[out_size].
*
* \return - LZMA_OK: So far all OK, but the integer is not
* \return Slightly different return values are used in multi-call and
* single-call modes.
*
* Single-call (vli_pos == NULL):
* - LZMA_OK: Integer successfully encoded.
* - LZMA_PROG_ERROR: Arguments are not sane. This can be due
* to too little output space; single-call mode doesn't use
* LZMA_BUF_ERROR, since the application should have checked
* the encoded size with lzma_vli_size().
*
* Multi-call (vli_pos != NULL):
* - LZMA_OK: So far all OK, but the integer is not
* completely written out yet.
* - LZMA_STREAM_END: Integer successfully encoded.
* - LZMA_BUF_ERROR: No output space (*out_pos == out_size)
* - LZMA_BUF_ERROR: No output space was provided.
* - LZMA_PROG_ERROR: Arguments are not sane.
*/
extern lzma_ret lzma_vli_encode(
lzma_vli vli, size_t *lzma_restrict vli_pos, size_t vli_size,
lzma_vli vli, size_t *lzma_restrict vli_pos,
uint8_t *lzma_restrict out, size_t *lzma_restrict out_pos,
size_t out_size);
@@ -184,22 +127,36 @@ extern lzma_ret lzma_vli_encode(
/**
* \brief Decodes variable-length integer
*
* Like lzma_vli_encode(), this function has single-call and multi-call modes.
*
* \param vli Pointer to decoded integer. The decoder will
* initialize it to zero when *vli_pos == 0, so
* application isn't required to initialize *vli.
* \param vli_pos How many bytes have already been decoded. When
* starting to decode a new integer, *vli_pos must
* be initialized to zero.
* be initialized to zero. To use single-call decoding,
* set this to NULL.
* \param in Beginning of the input buffer
* \param in_pos The next byte will be read from in[*in_pos].
* \param in_size Size of the input buffer; the first byte that
* won't be read is in[in_size].
*
* \return - LZMA_OK: So far all OK, but the integer is not
* \return Slightly different return values are used in multi-call and
* single-call modes.
*
* Single-call (vli_pos == NULL):
* - LZMA_OK: Integer successfully decoded.
* - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting
* the end of the input buffer before the whole integer was
* decoded; providing no input at all will use LZMA_DATA_ERROR.
* - LZMA_PROG_ERROR: Arguments are not sane.
*
* Multi-call (vli_pos != NULL):
* - LZMA_OK: So far all OK, but the integer is not
* completely decoded yet.
* - LZMA_STREAM_END: Integer successfully decoded.
* - LZMA_BUF_ERROR: No input data (*in_pos == in_size)
* - LZMA_DATA_ERROR: Integer is longer than nine bytes.
* - LZMA_DATA_ERROR: Integer is corrupt.
* - LZMA_BUF_ERROR: No input was provided.
* - LZMA_PROG_ERROR: Arguments are not sane.
*/
extern lzma_ret lzma_vli_decode(lzma_vli *lzma_restrict vli,
@@ -208,37 +165,10 @@ extern lzma_ret lzma_vli_decode(lzma_vli *lzma_restrict vli,
/**
* \brief Decodes variable-length integer reading buffer backwards
*
* The variable-length integer encoding is designed so that it can be read
* either from the beginning to the end, or from the end to the beginning.
* This feature is needed to make the Stream parseable backwards;
* specifically, to read the Backward Size field in Stream Footer.
*
* \param vli Pointer to variable to hold the decoded integer.
* \param in Beginning of the input buffer
* \param in_size Number of bytes available in the in[] buffer.
* On successful decoding, this is updated to match
* the number of bytes used. (in[*in_size - 1] is the
* first byte to process. After successful decoding,
* in[*in_size] will point to the first byte of the
* variable-length integer.)
*
* \return - LZMA_OK: Decoding successful
* - LZMA_DATA_ERROR: No valid variable-length integer was found.
* - LZMA_BUF_ERROR: Not enough input. Note that in practice,
* this tends to be a sign of broken input, because the
* applications usually do give as much input to this function
* as the applications have available.
*/
extern lzma_ret lzma_vli_reverse_decode(
lzma_vli *vli, const uint8_t *in, size_t *in_size);
/**
* \brief Gets the minimum number of bytes required to encode vli
* \brief Gets the number of bytes required to encode vli
*
* \return Number of bytes on success (1-9). If vli isn't valid,
* zero is returned.
*/
extern size_t lzma_vli_size(lzma_vli vli);
extern uint32_t lzma_vli_size(lzma_vli vli)
lzma_attr_pure;

View File

@@ -14,7 +14,6 @@ libcheck_la_SOURCES = \
check.c \
check.h \
check_init.c \
check_byteswap.h \
crc_macros.h
libcheck_la_CPPFLAGS = \
-I@top_srcdir@/src/liblzma/api \
@@ -23,7 +22,7 @@ libcheck_la_CPPFLAGS = \
if COND_CHECK_CRC32
if COND_ASM_X86
libcheck_la_SOURCES += crc32_x86.s
libcheck_la_SOURCES += crc32_x86.S
else
libcheck_la_SOURCES += crc32.c
endif
@@ -40,7 +39,7 @@ endif
if COND_CHECK_CRC64
if COND_ASM_X86
libcheck_la_SOURCES += crc64_x86.s
libcheck_la_SOURCES += crc64_x86.S
else
libcheck_la_SOURCES += crc64.c
endif

View File

@@ -13,99 +13,127 @@
#include "check.h"
// See the .lzma header format specification section 2.2.2.
LZMA_API const uint32_t lzma_check_sizes[8] = { 0, 4, 4, 8, 16, 32, 32, 64 };
extern LZMA_API lzma_bool
lzma_check_is_supported(lzma_check type)
{
if ((unsigned)(type) > LZMA_CHECK_ID_MAX)
return false;
LZMA_API const lzma_bool lzma_available_checks[LZMA_CHECK_ID_MAX + 1] = {
true, // LZMA_CHECK_NONE
static const lzma_bool available_checks[LZMA_CHECK_ID_MAX + 1] = {
true, // LZMA_CHECK_NONE
#ifdef HAVE_CHECK_CRC32
true,
true,
#else
false,
false,
#endif
false, // Reserved
false, // Reserved
false, // Reserved
#ifdef HAVE_CHECK_CRC64
true,
true,
#else
false,
false,
#endif
false, // Reserved
false, // Reserved
false, // Reserved
false, // Reserved
false, // Reserved
false, // Reserved
#ifdef HAVE_CHECK_SHA256
true,
true,
#else
false,
false,
#endif
false, // Reserved
false, // Reserved
};
false, // Reserved
false, // Reserved
false, // Reserved
false, // Reserved
false, // Reserved
};
return available_checks[(unsigned)(type)];
}
extern lzma_ret
lzma_check_init(lzma_check *check, lzma_check_type type)
extern LZMA_API uint32_t
lzma_check_size(lzma_check type)
{
lzma_ret ret = LZMA_OK;
if ((unsigned)(type) > LZMA_CHECK_ID_MAX)
return UINT32_MAX;
// See file-format.txt section 2.1.1.2.
static const uint8_t check_sizes[LZMA_CHECK_ID_MAX + 1] = {
0,
4, 4, 4,
8, 8, 8,
16, 16, 16,
32, 32, 32,
64, 64, 64
};
return check_sizes[(unsigned)(type)];
}
extern void
lzma_check_init(lzma_check_state *check, lzma_check type)
{
switch (type) {
case LZMA_CHECK_NONE:
break;
#ifdef HAVE_CHECK_CRC32
case LZMA_CHECK_CRC32:
check->crc32 = 0;
check->state.crc32 = 0;
break;
#endif
#ifdef HAVE_CHECK_CRC64
case LZMA_CHECK_CRC64:
check->crc64 = 0;
check->state.crc64 = 0;
break;
#endif
#ifdef HAVE_CHECK_SHA256
case LZMA_CHECK_SHA256:
lzma_sha256_init(&check->sha256);
lzma_sha256_init(check);
break;
#endif
default:
if (type <= LZMA_CHECK_ID_MAX)
ret = LZMA_UNSUPPORTED_CHECK;
else
ret = LZMA_PROG_ERROR;
break;
}
return ret;
return;
}
extern void
lzma_check_update(lzma_check *check, lzma_check_type type,
lzma_check_update(lzma_check_state *check, lzma_check type,
const uint8_t *buf, size_t size)
{
switch (type) {
#ifdef HAVE_CHECK_CRC32
case LZMA_CHECK_CRC32:
check->crc32 = lzma_crc32(buf, size, check->crc32);
check->state.crc32 = lzma_crc32(buf, size, check->state.crc32);
break;
#endif
#ifdef HAVE_CHECK_CRC64
case LZMA_CHECK_CRC64:
check->crc64 = lzma_crc64(buf, size, check->crc64);
check->state.crc64 = lzma_crc64(buf, size, check->state.crc64);
break;
#endif
#ifdef HAVE_CHECK_SHA256
case LZMA_CHECK_SHA256:
lzma_sha256_update(buf, size, &check->sha256);
lzma_sha256_update(buf, size, check);
break;
#endif
@@ -118,43 +146,30 @@ lzma_check_update(lzma_check *check, lzma_check_type type,
extern void
lzma_check_finish(lzma_check *check, lzma_check_type type)
lzma_check_finish(lzma_check_state *check, lzma_check type)
{
#ifdef HAVE_CHECK_SHA256
if (type == LZMA_CHECK_SHA256)
lzma_sha256_finish(&check->sha256);
switch (type) {
#ifdef HAVE_CHECK_CRC32
case LZMA_CHECK_CRC32:
check->buffer.u32[0] = integer_le_32(check->state.crc32);
break;
#endif
return;
}
/*
extern bool
lzma_check_compare(
lzma_check *check1, lzma_check *check2, lzma_check_type type)
{
bool ret;
switch (type) {
case LZMA_CHECK_NONE:
break;
case LZMA_CHECK_CRC32:
ret = check1->crc32 != check2->crc32;
break;
#ifdef HAVE_CHECK_CRC64
case LZMA_CHECK_CRC64:
ret = check1->crc64 != check2->crc64;
check->buffer.u64[0] = integer_le_64(check->state.crc64);
break;
#endif
#ifdef HAVE_CHECK_SHA256
case LZMA_CHECK_SHA256:
lzma_sha256_finish(check);
break;
#endif
default:
// Unsupported check
assert(type <= 7);
ret = false;
break;
}
return ret;
return;
}
*/

View File

@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file check.h
/// \brief Prototypes for different check functions
/// \brief Internal API to different integrity check functions
//
// This code has been put into the public domain.
//
@@ -17,28 +17,44 @@
#include "common.h"
// Index hashing needs the best possible hash function (preferably
// a cryptographic hash) for maximum reliability.
#if defined(HAVE_CHECK_SHA256)
# define LZMA_CHECK_BEST LZMA_CHECK_SHA256
#elif defined(HAVE_CHECK_CRC64)
# define LZMA_CHECK_BEST LZMA_CHECK_CRC64
#else
# define LZMA_CHECK_BEST LZMA_CHECK_CRC32
#endif
/// \brief Structure to hold internal state of the check being calculated
///
/// \note This is not in the public API because this structure may
/// change in future if new integrity check algorithms are added.
typedef struct {
/// Internal state
uint32_t state[8];
/// Buffer to hold the final result and a temporary buffer for SHA256.
union {
uint8_t u8[64];
uint32_t u32[16];
uint64_t u64[8];
} buffer;
/// Temporary 8-byte aligned buffer to hold incomplete chunk.
/// After lzma_check_finish(), the first 32 bytes will contain
/// the final digest in big endian byte order.
uint8_t buffer[64];
/// Check-specific data
union {
uint32_t crc32;
uint64_t crc64;
/// Size of the message excluding padding
uint64_t size;
struct {
/// Internal state
uint32_t state[8];
} lzma_sha256;
/// Size of the message excluding padding
uint64_t size;
} sha256;
} state;
/// \note This is not in the public API because this structure will
/// change in future.
typedef union {
uint32_t crc32;
uint64_t crc64;
lzma_sha256 sha256;
} lzma_check;
} lzma_check_state;
#ifdef HAVE_SMALL
@@ -49,7 +65,6 @@ extern const uint32_t lzma_crc32_table[8][256];
extern const uint64_t lzma_crc64_table[4][256];
#endif
// Generic
/// \brief Initializes *check depending on type
///
@@ -57,46 +72,31 @@ extern const uint64_t lzma_crc64_table[4][256];
/// supported by the current version or build of liblzma.
/// LZMA_PROG_ERROR if type > LZMA_CHECK_ID_MAX.
///
extern lzma_ret lzma_check_init(lzma_check *check, lzma_check_type type);
extern void lzma_check_init(lzma_check_state *check, lzma_check type);
/// \brief Updates *check
///
extern void lzma_check_update(lzma_check *check, lzma_check_type type,
extern void lzma_check_update(lzma_check_state *check, lzma_check type,
const uint8_t *buf, size_t size);
/// \brief Finishes *check
///
extern void lzma_check_finish(lzma_check *check, lzma_check_type type);
extern void lzma_check_finish(lzma_check_state *check, lzma_check type);
/*
/// \brief Compare two checks
///
/// \return false if the checks are identical; true if they differ.
///
extern bool lzma_check_compare(
lzma_check *check1, lzma_check *check2, lzma_check_type type);
*/
// CRC32
extern void lzma_crc32_init(void);
// CRC64
extern void lzma_crc64_init(void);
// SHA256
extern void lzma_sha256_init(lzma_sha256 *sha256);
extern void lzma_sha256_init(lzma_check_state *check);
extern void lzma_sha256_update(
const uint8_t *buf, size_t size, lzma_sha256 *sha256);
extern void lzma_sha256_finish(lzma_sha256 *sha256);
const uint8_t *buf, size_t size, lzma_check_state *check);
extern void lzma_sha256_finish(lzma_check_state *check);
#endif

View File

@@ -13,14 +13,11 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include <config.h>
# include "check.h"
#endif
#include <sys/types.h>
#include <inttypes.h>
#ifdef WORDS_BIGENDIAN
# include "check_byteswap.h"
# include "../../common/bswap.h"
#endif

View File

@@ -11,9 +11,7 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "common.h"
#ifdef WORDS_BIGENDIAN
# include "crc32_table_be.h"

View File

@@ -1,7 +1,5 @@
/* This file has been automatically generated by crc32_tablegen.c. */
#include <inttypes.h>
const uint32_t lzma_crc32_table[8][256] = {
{
0x00000000, 0x96300777, 0x2C610EEE, 0xBA510999,

View File

@@ -1,7 +1,5 @@
/* This file has been automatically generated by crc32_tablegen.c. */
#include <inttypes.h>
const uint32_t lzma_crc32_table[8][256] = {
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,

View File

@@ -3,7 +3,7 @@
/// \file crc32_tablegen.c
/// \brief Generates CRC32 crc32_table.c
///
/// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c crc32_init.c
/// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c
/// Add -DWORDS_BIGENDIAN to generate big endian table.
//
// This code has been put into the public domain.
@@ -18,10 +18,7 @@
#include <inttypes.h>
#include <stdio.h>
extern void lzma_crc32_init(void);
extern uint32_t lzma_crc32_table[8][256];
#include "crc32_init.c"
int
@@ -31,7 +28,6 @@ main()
printf("/* This file has been automatically generated by "
"crc32_tablegen.c. */\n\n"
"#include <inttypes.h>\n\n"
"const uint32_t lzma_crc32_table[8][256] = {\n\t{");
for (size_t s = 0; s < 8; ++s) {

View File

@@ -45,7 +45,7 @@ init_table(void)
*/
.text
.global lzma_crc32
.globl lzma_crc32
.type lzma_crc32, @function
.align 16
@@ -215,3 +215,12 @@ lzma_crc32:
ret
.size lzma_crc32, .-lzma_crc32
/*
* This is needed to support non-executable stack. It's ugly to
* use __linux__ here, but I don't know a way to detect when
* we are using GNU assembler.
*/
#if defined(__ELF__) && defined(__linux__)
.section .note.GNU-stack,"",@progbits
#endif

View File

@@ -13,14 +13,11 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include <config.h>
# include "check.h"
#endif
#include <sys/types.h>
#include <inttypes.h>
#ifdef WORDS_BIGENDIAN
# include "check_byteswap.h"
# include "../../common/bswap.h"
#endif

View File

@@ -11,9 +11,7 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "common.h"
#ifdef WORDS_BIGENDIAN
# include "crc64_table_be.h"

View File

@@ -1,7 +1,5 @@
/* This file has been automatically generated by crc64_tablegen.c. */
#include <inttypes.h>
const uint64_t lzma_crc64_table[4][256] = {
{
UINT64_C(0x0000000000000000), UINT64_C(0x6F5FA703BE4C2EB3),

View File

@@ -1,7 +1,5 @@
/* This file has been automatically generated by crc64_tablegen.c. */
#include <inttypes.h>
const uint64_t lzma_crc64_table[4][256] = {
{
UINT64_C(0x0000000000000000), UINT64_C(0xB32E4CBE03A75F6F),

View File

@@ -3,7 +3,7 @@
/// \file crc64_tablegen.c
/// \brief Generates CRC64 crc64_table.c
///
/// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c crc64_init.c
/// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c
/// Add -DWORDS_BIGENDIAN to generate big endian table.
//
// This code has been put into the public domain.
@@ -18,10 +18,7 @@
#include <inttypes.h>
#include <stdio.h>
extern void lzma_crc64_init(void);
extern uint64_t lzma_crc64_table[4][256];
#include "crc64_init.c"
int
@@ -31,7 +28,6 @@ main()
printf("/* This file has been automatically generated by "
"crc64_tablegen.c. */\n\n"
"#include <inttypes.h>\n\n"
"const uint64_t lzma_crc64_table[4][256] = {\n\t{");
for (size_t s = 0; s < 4; ++s) {

View File

@@ -38,7 +38,7 @@ init_table(void)
*/
.text
.global lzma_crc64
.globl lzma_crc64
.type lzma_crc64, @function
.align 16
@@ -200,4 +200,13 @@ lzma_crc64:
popl %ebx
ret
.size lzma_crc32, .-lzma_crc32
.size lzma_crc64, .-lzma_crc64
/*
* This is needed to support non-executable stack. It's ugly to
* use __linux__ here, but I don't know a way to detect when
* we are using GNU assembler.
*/
#if defined(__ELF__) && defined(__linux__)
.section .note.GNU-stack,"",@progbits
#endif

View File

@@ -12,7 +12,7 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef WORDS_BIGENDIAN
# include "check_byteswap.h"
# include "../../common/bswap.h"
# define A(x) ((x) >> 24)
# define B(x) (((x) >> 16) & 0xFF)

View File

@@ -20,7 +20,7 @@
#include "check.h"
#ifndef WORDS_BIGENDIAN
# include "check_byteswap.h"
# include "../../common/bswap.h"
#endif
// At least on x86, GCC is able to optimize this to a rotate instruction.
@@ -104,18 +104,18 @@ transform(uint32_t state[static 8], const uint32_t data[static 16])
static void
process(lzma_sha256 *sha256)
process(lzma_check_state *check)
{
#ifdef WORDS_BIGENDIAN
transform(sha256->state, (uint32_t *)(sha256->buffer));
transform(check->state.sha256.state, check->buffer.u32);
#else
uint32_t data[16];
for (size_t i = 0; i < 16; ++i)
data[i] = bswap_32(*((uint32_t*)(sha256->buffer) + i));
data[i] = bswap_32(check->buffer.u32[i]);
transform(sha256->state, data);
transform(check->state.sha256.state, data);
#endif
return;
@@ -123,41 +123,41 @@ process(lzma_sha256 *sha256)
extern void
lzma_sha256_init(lzma_sha256 *sha256)
lzma_sha256_init(lzma_check_state *check)
{
static const uint32_t s[8] = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
};
memcpy(sha256->state, s, sizeof(s));
sha256->size = 0;
memcpy(check->state.sha256.state, s, sizeof(s));
check->state.sha256.size = 0;
return;
}
extern void
lzma_sha256_update(const uint8_t *buf, size_t size, lzma_sha256 *sha256)
lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
{
// Copy the input data into a properly aligned temporary buffer.
// This way we can be called with arbitrarily sized buffers
// (no need to be multiple of 64 bytes), and the code works also
// on architectures that don't allow unaligned memory access.
while (size > 0) {
const size_t copy_start = sha256->size & 0x3F;
const size_t copy_start = check->state.sha256.size & 0x3F;
size_t copy_size = 64 - copy_start;
if (copy_size > size)
copy_size = size;
memcpy(sha256->buffer + copy_start, buf, copy_size);
memcpy(check->buffer.u8 + copy_start, buf, copy_size);
buf += copy_size;
size -= copy_size;
sha256->size += copy_size;
check->state.sha256.size += copy_size;
if ((sha256->size & 0x3F) == 0)
process(sha256);
if ((check->state.sha256.size & 0x3F) == 0)
process(check);
}
return;
@@ -165,38 +165,38 @@ lzma_sha256_update(const uint8_t *buf, size_t size, lzma_sha256 *sha256)
extern void
lzma_sha256_finish(lzma_sha256 *sha256)
lzma_sha256_finish(lzma_check_state *check)
{
// Add padding as described in RFC 3174 (it describes SHA-1 but
// the same padding style is used for SHA-256 too).
size_t pos = sha256->size & 0x3F;
sha256->buffer[pos++] = 0x80;
size_t pos = check->state.sha256.size & 0x3F;
check->buffer.u8[pos++] = 0x80;
while (pos != 64 - 8) {
if (pos == 64) {
process(sha256);
process(check);
pos = 0;
}
sha256->buffer[pos++] = 0x00;
check->buffer.u8[pos++] = 0x00;
}
// Convert the message size from bytes to bits.
sha256->size *= 8;
check->state.sha256.size *= 8;
#ifdef WORDS_BIGENDIAN
*(uint64_t *)(sha256->buffer + 64 - 8) = sha256->size;
check->buffer.u64[(64 - 8) / 8] = check->state.sha256.size;
#else
*(uint64_t *)(sha256->buffer + 64 - 8) = bswap_64(sha256->size);
check->buffer.u64[(64 - 8) / 8] = bswap_64(check->state.sha256.size);
#endif
process(sha256);
process(check);
for (size_t i = 0; i < 8; ++i)
#ifdef WORDS_BIGENDIAN
((uint32_t *)(sha256->buffer))[i] = sha256->state[i];
check->buffer.u32[i] = check->state.sha256.state[i];
#else
((uint32_t *)(sha256->buffer))[i] = bswap_32(sha256->state[i]);
check->buffer.u32[i] = bswap_32(check->state.sha256.state[i]);
#endif
return;

View File

@@ -16,59 +16,44 @@ noinst_LTLIBRARIES = libcommon.la
libcommon_la_CPPFLAGS = \
-I@top_srcdir@/src/liblzma/api \
-I@top_srcdir@/src/liblzma/check \
-I@top_srcdir@/src/liblzma/rangecoder \
-I@top_srcdir@/src/liblzma/lz \
-I@top_srcdir@/src/liblzma/lzma \
-I@top_srcdir@/src/liblzma/simple \
-I@top_srcdir@/src/liblzma/subblock \
-I@top_srcdir@/src/liblzma/rangecoder
-I@top_srcdir@/src/liblzma/delta \
-I@top_srcdir@/src/liblzma/simple
libcommon_la_SOURCES = \
common.c \
common.h \
sysdefs.h \
allocator.c \
block_private.h \
extra.c \
features.c \
bsr.h \
block_util.c \
filter_common.c \
filter_common.h \
index.c \
info.c \
index.h \
init.c \
memory_limitter.c \
memory_usage.c \
next_coder.c \
raw_common.c \
raw_common.h \
code.c \
version.c
if COND_FILTER_COPY
libcommon_la_SOURCES += \
copy_coder.c \
copy_coder.h
endif
if COND_FILTER_DELTA
libcommon_la_SOURCES += \
delta_coder.c \
delta_coder.h
endif
memory_limiter.c \
stream_flags_common.c \
stream_flags_common.h \
vli_size.c
if COND_MAIN_ENCODER
libcommon_la_SOURCES += \
alignment.c \
auto_decoder.c \
alone_encoder.c \
block_encoder.c \
block_encoder.h \
block_header_encoder.c \
easy.c \
filter_encoder.c \
filter_encoder.h \
filter_flags_encoder.c \
index_encoder.c \
index_encoder.h \
init_encoder.c \
metadata_encoder.c \
metadata_encoder.h \
raw_encoder.c \
raw_encoder.h \
stream_common.c \
stream_common.h \
stream_encoder_single.c \
stream_encoder_multi.c \
stream_encoder.c \
stream_encoder.h \
stream_flags_encoder.c \
vli_encoder.c
endif
@@ -77,18 +62,19 @@ if COND_MAIN_DECODER
libcommon_la_SOURCES += \
alone_decoder.c \
alone_decoder.h \
auto_decoder.c \
block_decoder.c \
block_decoder.h \
block_header_decoder.c \
filter_decoder.c \
filter_decoder.h \
filter_flags_decoder.c \
index_decoder.c \
index_hash.c \
init_decoder.c \
metadata_decoder.c \
metadata_decoder.h \
raw_decoder.c \
raw_decoder.h \
stream_decoder.c \
stream_decoder.h \
stream_flags_decoder.c \
stream_flags_decoder.h \
vli_decoder.c \
vli_reverse_decoder.c
vli_decoder.c
endif

View File

@@ -21,11 +21,10 @@
extern LZMA_API uint32_t
lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess)
lzma_alignment_input(const lzma_filter *filters, uint32_t guess)
{
for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
switch (filters[i].id) {
case LZMA_FILTER_COPY:
case LZMA_FILTER_DELTA:
// The same as the input, check the next filter.
continue;
@@ -67,11 +66,10 @@ lzma_alignment_input(const lzma_options_filter *filters, uint32_t guess)
extern LZMA_API uint32_t
lzma_alignment_output(const lzma_options_filter *filters, uint32_t guess)
lzma_alignment_output(const lzma_filter *filters, uint32_t guess)
{
// Check if there is only an implicit Copy filter.
if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return guess;
return UINT32_MAX;
// Find the last filter in the chain.
size_t i = 0;
@@ -80,7 +78,6 @@ lzma_alignment_output(const lzma_options_filter *filters, uint32_t guess)
do {
switch (filters[i].id) {
case LZMA_FILTER_COPY:
case LZMA_FILTER_DELTA:
// It's the same as the input alignment, so
// check the next filter.

View File

@@ -1,57 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file allocator.c
/// \brief Allocating and freeing memory
//
// Copyright (C) 2007 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#undef lzma_free
extern void * lzma_attribute((malloc))
lzma_alloc(size_t size, lzma_allocator *allocator)
{
// Some malloc() variants return NULL if called with size == 0.
if (size == 0)
size = 1;
void *ptr;
if (allocator != NULL && allocator->alloc != NULL)
ptr = allocator->alloc(allocator->opaque, 1, size);
else
ptr = malloc(size);
#if !defined(NDEBUG) && defined(HAVE_MEMSET)
// This helps to catch some stupid mistakes.
if (ptr != NULL)
memset(ptr, 0xFD, size);
#endif
return ptr;
}
extern void
lzma_free(void *ptr, lzma_allocator *allocator)
{
if (allocator != NULL && allocator->free != NULL)
allocator->free(allocator->opaque, ptr);
else
free(ptr);
return;
}

View File

@@ -19,6 +19,7 @@
#include "alone_decoder.h"
#include "lzma_decoder.h"
#include "lz_decoder.h"
struct lzma_coder_s {
@@ -32,9 +33,18 @@ struct lzma_coder_s {
SEQ_CODE,
} sequence;
/// Position in the header fields
size_t pos;
lzma_options_alone options;
/// Uncompressed size decoded from the header
lzma_vli uncompressed_size;
/// Memory usage limit
uint64_t memlimit;
/// Options decoded from the header needed to initialize
/// the LZMA decoder
lzma_options_lzma options;
};
@@ -50,33 +60,37 @@ alone_decode(lzma_coder *coder,
&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
switch (coder->sequence) {
case SEQ_PROPERTIES:
if (lzma_lzma_decode_properties(
&coder->options.lzma, in[*in_pos]))
return LZMA_DATA_ERROR;
if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
return LZMA_FORMAT_ERROR;
coder->sequence = SEQ_DICTIONARY_SIZE;
++*in_pos;
break;
case SEQ_DICTIONARY_SIZE:
coder->options.lzma.dictionary_size
coder->options.dictionary_size
|= (size_t)(in[*in_pos]) << (coder->pos * 8);
if (++coder->pos == 4) {
// A hack to ditch tons of false positives: We allow
// only dictionary sizes that are a power of two.
// LZMA_Alone didn't create other kinds of files,
// although it's not impossible that files with
// other dictionary sizes exist. Well, if someone
// complains, this will be reconsidered.
size_t count = 0;
for (size_t i = 0; i < 32; ++i)
if (coder->options.lzma.dictionary_size
& (UINT32_C(1) << i))
++count;
if (coder->options.dictionary_size
> LZMA_DICTIONARY_SIZE_MAX)
return LZMA_FORMAT_ERROR;
if (count > 1)
return LZMA_DATA_ERROR;
// A hack to ditch tons of false positives: We allow
// only dictionary sizes that are 2^n or 2^n + 2^(n-1).
// LZMA_Alone created only files with 2^n, but accepts
// any dictionary size. If someone complains, this
// will be reconsidered.
uint32_t d = coder->options.dictionary_size - 1;
d |= d >> 2;
d |= d >> 3;
d |= d >> 4;
d |= d >> 8;
d |= d >> 16;
++d;
if (d != coder->options.dictionary_size)
return LZMA_FORMAT_ERROR;
coder->pos = 0;
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
@@ -86,7 +100,7 @@ alone_decode(lzma_coder *coder,
break;
case SEQ_UNCOMPRESSED_SIZE:
coder->options.uncompressed_size
coder->uncompressed_size
|= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
if (++coder->pos == 8) {
@@ -94,11 +108,10 @@ alone_decode(lzma_coder *coder,
// if the uncompressed size is known, it must be less
// than 256 GiB. Again, if someone complains, this
// will be reconsidered.
if (coder->options.uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN
&& coder->options.uncompressed_size
if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
&& coder->uncompressed_size
>= (LZMA_VLI_C(1) << 38))
return LZMA_DATA_ERROR;
return LZMA_FORMAT_ERROR;
coder->pos = 0;
coder->sequence = SEQ_CODER_INIT;
@@ -108,13 +121,24 @@ alone_decode(lzma_coder *coder,
break;
case SEQ_CODER_INIT: {
// Two is enough because there won't be implicit filters.
// FIXME It is unfair that this doesn't add a fixed amount
// like lzma_memusage_common() does.
const uint64_t memusage
= lzma_lzma_decoder_memusage(&coder->options);
// Use LZMA_PROG_ERROR since LZMA_Alone decoder cannot be
// built without LZMA support.
// FIXME TODO Make the above comment true.
if (memusage == UINT64_MAX)
return LZMA_PROG_ERROR;
if (memusage > coder->memlimit)
return LZMA_MEMLIMIT_ERROR;
lzma_filter_info filters[2] = {
{
.init = &lzma_lzma_decoder_init,
.options = &coder->options.lzma,
.uncompressed_size = coder->options
.uncompressed_size,
.options = &coder->options,
}, {
.init = NULL,
}
@@ -125,6 +149,10 @@ alone_decode(lzma_coder *coder,
if (ret != LZMA_OK)
return ret;
// Use a hack to set the uncompressed size.
lzma_lz_decoder_uncompressed(coder->next.coder,
coder->uncompressed_size);
coder->sequence = SEQ_CODE;
}
@@ -147,15 +175,18 @@ alone_decode(lzma_coder *coder,
static void
alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_ret
alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
extern lzma_ret
lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
uint64_t memlimit)
{
lzma_next_coder_init(lzma_alone_decoder_init, next, allocator);
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
@@ -168,30 +199,21 @@ alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
next->coder->sequence = SEQ_PROPERTIES;
next->coder->pos = 0;
next->coder->options.lzma.dictionary_size = 0;
next->coder->options.uncompressed_size = 0;
next->coder->options.dictionary_size = 0;
next->coder->uncompressed_size = 0;
next->coder->memlimit = memlimit;
return LZMA_OK;
}
extern lzma_ret
lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
{
// We need to use _init2 because we don't pass any varadic args.
lzma_next_coder_init2(next, allocator, alone_decoder_init,
alone_decoder_init, allocator);
}
extern LZMA_API lzma_ret
lzma_alone_decoder(lzma_stream *strm)
lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
{
lzma_next_strm_init2(strm, alone_decoder_init,
alone_decoder_init, strm->allocator);
lzma_next_strm_init(lzma_alone_decoder_init, strm, memlimit);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}

View File

@@ -17,8 +17,13 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_ALONE_DECODER_H
#define LZMA_ALONE_DECODER_H
#include "common.h"
extern lzma_ret lzma_alone_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator);
extern lzma_ret lzma_alone_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, uint64_t memlimit);
#endif

View File

@@ -21,19 +21,19 @@
#include "lzma_encoder.h"
#define ALONE_HEADER_SIZE (1 + 4 + 8)
struct lzma_coder_s {
lzma_next_coder next;
enum {
SEQ_PROPERTIES,
SEQ_DICTIONARY_SIZE,
SEQ_UNCOMPRESSED_SIZE,
SEQ_HEADER,
SEQ_CODE,
} sequence;
size_t pos;
lzma_options_alone options;
size_t header_pos;
uint8_t header[ALONE_HEADER_SIZE];
};
@@ -47,47 +47,23 @@ alone_encode(lzma_coder *coder,
{
while (*out_pos < out_size)
switch (coder->sequence) {
case SEQ_PROPERTIES:
if (lzma_lzma_encode_properties(
&coder->options.lzma, out + *out_pos)) {
return LZMA_PROG_ERROR;
}
case SEQ_HEADER:
lzma_bufcpy(coder->header, &coder->header_pos,
ALONE_HEADER_SIZE,
out, out_pos, out_size);
if (coder->header_pos < ALONE_HEADER_SIZE)
return LZMA_OK;
coder->sequence = SEQ_DICTIONARY_SIZE;
++*out_pos;
coder->sequence = SEQ_CODE;
break;
case SEQ_DICTIONARY_SIZE:
out[*out_pos] = coder->options.lzma.dictionary_size
>> (coder->pos * 8);
if (++coder->pos == 4) {
coder->pos = 0;
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
}
++*out_pos;
break;
case SEQ_UNCOMPRESSED_SIZE:
out[*out_pos] = coder->options.uncompressed_size
>> (coder->pos * 8);
if (++coder->pos == 8) {
coder->pos = 0;
coder->sequence = SEQ_CODE;
}
++*out_pos;
break;
case SEQ_CODE: {
case SEQ_CODE:
return coder->next.code(coder->next.coder,
allocator, in, in_pos, in_size,
out, out_pos, out_size, action);
}
default:
assert(0);
return LZMA_PROG_ERROR;
}
@@ -98,7 +74,7 @@ alone_encode(lzma_coder *coder,
static void
alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
@@ -107,8 +83,10 @@ alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
// At least for now, this is not used by any internal function.
static lzma_ret
alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_options_alone *options)
const lzma_options_lzma *options)
{
lzma_next_coder_init(alone_encoder_init, next, allocator);
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
@@ -119,23 +97,45 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
next->coder->next = LZMA_NEXT_CODER_INIT;
}
// Initialize the LZMA_Alone coder variables.
next->coder->sequence = SEQ_PROPERTIES;
next->coder->pos = 0;
next->coder->options = *options;
// Basic initializations
next->coder->sequence = SEQ_HEADER;
next->coder->header_pos = 0;
// Verify uncompressed_size since the other functions assume that
// it is valid.
if (!lzma_vli_is_valid(next->coder->options.uncompressed_size))
// Encode the header:
// - Properties (1 byte)
if (lzma_lzma_lclppb_encode(options, next->coder->header))
return LZMA_PROG_ERROR;
// - Dictionary size (4 bytes)
if (options->dictionary_size < LZMA_DICTIONARY_SIZE_MIN
|| options->dictionary_size > LZMA_DICTIONARY_SIZE_MAX)
return LZMA_PROG_ERROR;
// Round up to to the next 2^n or 2^n + 2^(n - 1) depending on which
// one is the next. While the header would allow any 32-bit integer,
// we do this to keep the decoder of liblzma accepting the resulting
// files.
//
// FIXME Maybe LZMA_Alone needs some lower limit for maximum
// dictionary size? Must check decoders from old LZMA SDK version.
uint32_t d = options->dictionary_size - 1;
d |= d >> 2;
d |= d >> 3;
d |= d >> 4;
d |= d >> 8;
d |= d >> 16;
++d;
integer_write_32(next->coder->header + 1, d);
// - Uncompressed size (always unknown and using EOPM)
memset(next->coder->header + 1 + 4, 0xFF, 8);
// Initialize the LZMA encoder.
const lzma_filter_info filters[2] = {
{
.init = &lzma_lzma_encoder_init,
.options = &next->coder->options.lzma,
.uncompressed_size = next->coder->options
.uncompressed_size,
.options = (void *)(options),
}, {
.init = NULL,
}
@@ -156,9 +156,9 @@ lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern LZMA_API lzma_ret
lzma_alone_encoder(lzma_stream *strm, const lzma_options_alone *options)
lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
{
lzma_next_strm_init(strm, alone_encoder_init, options);
lzma_next_strm_init(alone_encoder_init, strm, options);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;

View File

@@ -17,16 +17,22 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "stream_decoder.h"
#include "alone_decoder.h"
struct lzma_coder_s {
/// Stream decoder or LZMA_Alone decoder
lzma_next_coder next;
lzma_extra **header;
lzma_extra **footer;
bool initialized;
uint64_t memlimit;
uint32_t flags;
enum {
SEQ_INIT,
SEQ_CODE,
SEQ_FINISH,
} sequence;
};
@@ -36,42 +42,97 @@ auto_decode(lzma_coder *coder, lzma_allocator *allocator,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
if (!coder->initialized) {
switch (coder->sequence) {
case SEQ_INIT:
if (*in_pos >= in_size)
return LZMA_OK;
lzma_ret ret;
// Update the sequence now, because we want to continue from
// SEQ_CODE even if we return some LZMA_*_CHECK.
coder->sequence = SEQ_CODE;
if (in[*in_pos] == 0xFF)
ret = lzma_stream_decoder_init(&coder->next, allocator,
coder->header, coder->footer);
else
ret = lzma_alone_decoder_init(&coder->next, allocator);
// Detect the file format. For now this is simple, since if
// it doesn't start with 0xFF (the first magic byte of the
// new format), it has to be LZMA_Alone, or something that
// we don't support at all.
if (in[*in_pos] == 0xFF) {
return_if_error(lzma_stream_decoder_init(
&coder->next, allocator,
coder->memlimit, coder->flags));
} else {
return_if_error(lzma_alone_decoder_init(&coder->next,
allocator, coder->memlimit));
if (ret != LZMA_OK)
// If the application wants to know about missing
// integrity check or about the check in general, we
// need to handle it here, because LZMA_Alone decoder
// doesn't accept any flags.
if (coder->flags & LZMA_TELL_NO_CHECK)
return LZMA_NO_CHECK;
if (coder->flags & LZMA_TELL_ANY_CHECK)
return LZMA_GET_CHECK;
}
// Fall through
case SEQ_CODE: {
const lzma_ret ret = coder->next.code(
coder->next.coder, allocator,
in, in_pos, in_size,
out, out_pos, out_size, action);
if (ret != LZMA_STREAM_END
|| (coder->flags & LZMA_CONCATENATED) == 0)
return ret;
coder->initialized = true;
coder->sequence = SEQ_FINISH;
}
return coder->next.code(coder->next.coder, allocator,
in, in_pos, in_size, out, out_pos, out_size, action);
// Fall through
case SEQ_FINISH:
// When LZMA_DECODE_CONCATENATED was used and we were decoding
// LZMA_Alone file, we need to check check that there is no
// trailing garbage and wait for LZMA_FINISH.
if (*in_pos < in_size)
return LZMA_DATA_ERROR;
return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
default:
assert(0);
return LZMA_PROG_ERROR;
}
}
static void
auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_check
auto_decoder_get_check(const lzma_coder *coder)
{
// It is LZMA_Alone if get_check is NULL.
return coder->next.get_check == NULL ? LZMA_CHECK_NONE
: coder->next.get_check(coder->next.coder);
}
static lzma_ret
auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_extra **header, lzma_extra **footer)
uint64_t memlimit, uint32_t flags)
{
lzma_next_coder_init(auto_decoder_init, next, allocator);
if (flags & ~LZMA_SUPPORTED_FLAGS)
return LZMA_HEADER_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
@@ -79,35 +140,25 @@ auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
next->code = &auto_decode;
next->end = &auto_decoder_end;
next->get_check = &auto_decoder_get_check;
next->coder->next = LZMA_NEXT_CODER_INIT;
}
next->coder->header = header;
next->coder->footer = footer;
next->coder->initialized = false;
next->coder->memlimit = memlimit;
next->coder->flags = flags;
next->coder->sequence = SEQ_INIT;
return LZMA_OK;
}
/*
extern lzma_ret
lzma_auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_extra **header, lzma_extra **footer)
{
lzma_next_coder_init(
auto_decoder_init, next, allocator, header, footer);
}
*/
extern LZMA_API lzma_ret
lzma_auto_decoder(lzma_stream *strm, lzma_extra **header, lzma_extra **footer)
lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
{
lzma_next_strm_init(strm, auto_decoder_init, header, footer);
lzma_next_strm_init(auto_decoder_init, strm, memlimit, flags);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}

View File

@@ -18,37 +18,23 @@
///////////////////////////////////////////////////////////////////////////////
#include "block_decoder.h"
#include "block_private.h"
#include "raw_decoder.h"
#include "filter_decoder.h"
#include "check.h"
struct lzma_coder_s {
enum {
SEQ_CODE,
SEQ_CHECK,
SEQ_UNCOMPRESSED_SIZE,
SEQ_BACKWARD_SIZE,
SEQ_PADDING,
SEQ_END,
SEQ_CHECK,
} sequence;
/// The filters in the chain; initialized with lzma_raw_decoder_init().
lzma_next_coder next;
/// Decoding options; we also write Total Size, Compressed Size, and
/// Uncompressed Size back to this structure when the encoding has
/// been finished.
lzma_options_block *options;
/// Position in variable-length integers (and in some other places).
size_t pos;
/// Check of the uncompressed data
lzma_check check;
/// Total Size calculated while encoding
lzma_vli total_size;
/// Decoding options; we also write Compressed Size and Uncompressed
/// Size back to this structure when the encoding has been finished.
lzma_block *options;
/// Compressed Size calculated while encoding
lzma_vli compressed_size;
@@ -56,81 +42,38 @@ struct lzma_coder_s {
/// Uncompressed Size calculated while encoding
lzma_vli uncompressed_size;
/// Maximum allowed total_size
lzma_vli total_limit;
/// Maximum allowed Compressed Size; this takes into account the
/// size of the Block Header and Check fields when Compressed Size
/// is unknown.
lzma_vli compressed_limit;
/// Maximum allowed uncompressed_size
lzma_vli uncompressed_limit;
/// Position when reading the Check field
size_t check_pos;
/// Temporary location for the Uncompressed Size and Backward Size
/// fields in Block Footer.
lzma_vli tmp;
/// Size of the Backward Size field - This is needed so that we
/// can verify the Backward Size and still keep updating total_size.
size_t size_of_backward_size;
/// Check of the uncompressed data
lzma_check_state check;
};
static lzma_ret
update_sequence(lzma_coder *coder)
static inline bool
update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
{
switch (coder->sequence) {
case SEQ_CODE:
if (coder->options->check != LZMA_CHECK_NONE) {
lzma_check_finish(&coder->check,
coder->options->check);
coder->sequence = SEQ_CHECK;
break;
}
if (limit > LZMA_VLI_VALUE_MAX)
limit = LZMA_VLI_VALUE_MAX;
// Fall through
if (limit < *size || limit - *size < add)
return true;
case SEQ_CHECK:
if (coder->options->has_uncompressed_size_in_footer) {
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
break;
}
*size += add;
// Fall through
return false;
}
case SEQ_UNCOMPRESSED_SIZE:
if (coder->options->has_backward_size) {
coder->sequence = SEQ_BACKWARD_SIZE;
break;
}
// Fall through
case SEQ_BACKWARD_SIZE:
if (coder->options->handle_padding) {
coder->sequence = SEQ_PADDING;
break;
}
case SEQ_PADDING:
if (!is_size_valid(coder->total_size,
coder->options->total_size)
|| !is_size_valid(coder->compressed_size,
coder->options->compressed_size)
|| !is_size_valid(coder->uncompressed_size,
coder->options->uncompressed_size))
return LZMA_DATA_ERROR;
// Copy the values into coder->options. The caller
// may use this information to construct Index.
coder->options->total_size = coder->total_size;
coder->options->compressed_size = coder->compressed_size;
coder->options->uncompressed_size = coder->uncompressed_size;
return LZMA_STREAM_END;
default:
assert(0);
return LZMA_PROG_ERROR;
}
return LZMA_OK;
static inline bool
is_size_valid(lzma_vli size, lzma_vli reference)
{
return reference == LZMA_VLI_VALUE_UNKNOWN || reference == size;
}
@@ -140,32 +83,25 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
// Special case when the Block has only Block Header.
if (coder->sequence == SEQ_END)
return LZMA_STREAM_END;
// FIXME: Termination condition should work but could be cleaner.
while (*out_pos < out_size && (*in_pos < in_size
|| coder->sequence == SEQ_CODE))
switch (coder->sequence) {
case SEQ_CODE: {
const size_t in_start = *in_pos;
const size_t out_start = *out_pos;
lzma_ret ret = coder->next.code(coder->next.coder,
const lzma_ret ret = coder->next.code(coder->next.coder,
allocator, in, in_pos, in_size,
out, out_pos, out_size, action);
const size_t in_used = *in_pos - in_start;
const size_t out_used = *out_pos - out_start;
if (update_size(&coder->total_size, in_used,
coder->total_limit)
|| update_size(&coder->compressed_size,
in_used,
coder->options->compressed_size)
// NOTE: We compare to compressed_limit here, which prevents
// the total size of the Block growing past LZMA_VLI_VALUE_MAX.
if (update_size(&coder->compressed_size, in_used,
coder->compressed_limit)
|| update_size(&coder->uncompressed_size,
out_used, coder->uncompressed_limit))
out_used,
coder->options->uncompressed_size))
return LZMA_DATA_ERROR;
lzma_check_update(&coder->check, coder->options->check,
@@ -174,132 +110,78 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
if (ret != LZMA_STREAM_END)
return ret;
ret = update_sequence(coder);
if (ret != LZMA_OK)
return ret;
break;
coder->sequence = SEQ_PADDING;
}
case SEQ_CHECK:
switch (coder->options->check) {
case LZMA_CHECK_CRC32:
if (((coder->check.crc32 >> (coder->pos * 8))
& 0xFF) != in[*in_pos])
return LZMA_DATA_ERROR;
break;
case LZMA_CHECK_CRC64:
if (((coder->check.crc64 >> (coder->pos * 8))
& 0xFF) != in[*in_pos])
return LZMA_DATA_ERROR;
break;
case LZMA_CHECK_SHA256:
if (coder->check.sha256.buffer[coder->pos]
!= in[*in_pos])
return LZMA_DATA_ERROR;
break;
default:
assert(coder->options->check != LZMA_CHECK_NONE);
assert(coder->options->check <= LZMA_CHECK_ID_MAX);
break;
}
if (update_size(&coder->total_size, 1, coder->total_limit))
return LZMA_DATA_ERROR;
++*in_pos;
if (++coder->pos == lzma_check_sizes[coder->options->check]) {
const lzma_ret ret = update_sequence(coder);
if (ret != LZMA_OK)
return ret;
coder->pos = 0;
}
break;
case SEQ_UNCOMPRESSED_SIZE: {
const size_t in_start = *in_pos;
lzma_ret ret = lzma_vli_decode(&coder->tmp,
&coder->pos, in, in_pos, in_size);
if (update_size(&coder->total_size, *in_pos - in_start,
coder->total_limit))
return LZMA_DATA_ERROR;
if (ret != LZMA_STREAM_END)
return ret;
if (coder->tmp != coder->uncompressed_size)
return LZMA_DATA_ERROR;
coder->pos = 0;
coder->tmp = 0;
ret = update_sequence(coder);
if (ret != LZMA_OK)
return ret;
break;
}
case SEQ_BACKWARD_SIZE: {
const size_t in_start = *in_pos;
lzma_ret ret = lzma_vli_decode(&coder->tmp,
&coder->pos, in, in_pos, in_size);
const size_t in_used = *in_pos - in_start;
if (update_size(&coder->total_size, in_used,
coder->total_limit))
return LZMA_DATA_ERROR;
coder->size_of_backward_size += in_used;
if (ret != LZMA_STREAM_END)
return ret;
if (coder->tmp != coder->total_size
- coder->size_of_backward_size)
return LZMA_DATA_ERROR;
ret = update_sequence(coder);
if (ret != LZMA_OK)
return ret;
break;
}
// Fall through
case SEQ_PADDING:
if (in[*in_pos] == 0x00) {
if (update_size(&coder->total_size, 1,
coder->total_limit))
// Compressed Data is padded to a multiple of four bytes.
while (coder->compressed_size & 3) {
if (*in_pos >= in_size)
return LZMA_OK;
if (in[(*in_pos)++] != 0x00)
return LZMA_DATA_ERROR;
++*in_pos;
break;
if (update_size(&coder->compressed_size, 1,
coder->compressed_limit))
return LZMA_DATA_ERROR;
}
return update_sequence(coder);
// Compressed and Uncompressed Sizes are now at their final
// values. Verify that they match the values given to us.
if (!is_size_valid(coder->compressed_size,
coder->options->compressed_size)
|| !is_size_valid(coder->uncompressed_size,
coder->options->uncompressed_size))
return LZMA_DATA_ERROR;
default:
return LZMA_PROG_ERROR;
// Copy the values into coder->options. The caller
// may use this information to construct Index.
coder->options->compressed_size = coder->compressed_size;
coder->options->uncompressed_size = coder->uncompressed_size;
if (coder->options->check == LZMA_CHECK_NONE)
return LZMA_STREAM_END;
lzma_check_finish(&coder->check, coder->options->check);
coder->sequence = SEQ_CHECK;
// Fall through
case SEQ_CHECK: {
const bool chksup = lzma_check_is_supported(
coder->options->check);
while (*in_pos < in_size) {
// coder->check.buffer[] may be uninitialized when
// the Check ID is not supported.
if (chksup && coder->check.buffer.u8[coder->check_pos]
!= in[*in_pos]) {
++*in_pos;
return LZMA_DATA_ERROR;
}
++*in_pos;
if (++coder->check_pos == lzma_check_size(
coder->options->check))
return LZMA_STREAM_END;
}
return LZMA_OK;
}
}
return LZMA_OK;
return LZMA_PROG_ERROR;
}
static void
block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
@@ -307,11 +189,21 @@ block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
extern lzma_ret
lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_options_block *options)
lzma_block *options)
{
// This is pretty similar to lzma_block_encoder_init().
// See comments there.
lzma_next_coder_init(lzma_block_decoder_init, next, allocator);
// While lzma_block_total_size_get() is meant to calculate the Total
// Size, it also validates the options excluding the filters.
if (lzma_block_total_size_get(options) == 0)
return LZMA_PROG_ERROR;
// options->check is used for array indexing so we need to know that
// it is in the valid range.
if ((unsigned)(options->check) > LZMA_CHECK_ID_MAX)
return LZMA_PROG_ERROR;
// Allocate and initialize *next->coder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
@@ -322,74 +214,41 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
next->coder->next = LZMA_NEXT_CODER_INIT;
}
if (!lzma_vli_is_valid(options->total_size)
|| !lzma_vli_is_valid(options->compressed_size)
|| !lzma_vli_is_valid(options->uncompressed_size)
|| !lzma_vli_is_valid(options->total_size)
|| !lzma_vli_is_valid(options->total_limit)
|| !lzma_vli_is_valid(options->uncompressed_limit)
|| (options->uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN
&& options->uncompressed_size
> options->uncompressed_limit)
|| (options->total_size != LZMA_VLI_VALUE_UNKNOWN
&& options->total_size
> options->total_limit)
|| (!options->has_eopm && options->uncompressed_size
== LZMA_VLI_VALUE_UNKNOWN)
|| options->header_size > options->total_size
|| (options->handle_padding
&& (options->has_uncompressed_size_in_footer
|| options->has_backward_size)))
return LZMA_PROG_ERROR;
return_if_error(lzma_check_init(&next->coder->check, options->check));
if (!options->has_eopm && options->uncompressed_size == 0) {
if (!is_size_valid(0, options->compressed_size))
return LZMA_PROG_ERROR;
if (options->check != LZMA_CHECK_NONE) {
lzma_check_finish(&next->coder->check, options->check);
next->coder->sequence = SEQ_CHECK;
} else if (options->handle_padding) {
next->coder->sequence = SEQ_PADDING;
} else {
next->coder->sequence = SEQ_END;
}
} else {
next->coder->sequence = SEQ_CODE;
}
return_if_error(lzma_raw_decoder_init(&next->coder->next, allocator,
options->filters, options->has_eopm
? LZMA_VLI_VALUE_UNKNOWN
: options->uncompressed_size,
true));
// Basic initializations
next->coder->sequence = SEQ_CODE;
next->coder->options = options;
next->coder->pos = 0;
next->coder->total_size = options->header_size;
next->coder->compressed_size = 0;
next->coder->uncompressed_size = 0;
next->coder->total_limit
= MIN(options->total_size, options->total_limit);
next->coder->uncompressed_limit = MIN(options->uncompressed_size,
options->uncompressed_limit);
next->coder->tmp = 0;
next->coder->size_of_backward_size = 0;
return LZMA_OK;
// If Compressed Size is not known, we calculate the maximum allowed
// value so that Total Size of the Block still is a valid VLI and
// a multiple of four.
next->coder->compressed_limit
= options->compressed_size == LZMA_VLI_VALUE_UNKNOWN
? (LZMA_VLI_VALUE_MAX & ~LZMA_VLI_C(3))
- options->header_size
- lzma_check_size(options->check)
: options->compressed_size;
// Initialize the check. It's caller's problem if the Check ID is not
// supported, and the Block decoder cannot verify the Check field.
// Caller can test lzma_checks[options->check].
next->coder->check_pos = 0;
lzma_check_init(&next->coder->check, options->check);
// Initialize the filter chain.
return lzma_raw_decoder_init(&next->coder->next, allocator,
options->filters);
}
extern LZMA_API lzma_ret
lzma_block_decoder(lzma_stream *strm, lzma_options_block *options)
lzma_block_decoder(lzma_stream *strm, lzma_block *options)
{
lzma_next_strm_init(strm, lzma_block_decoder_init, options);
lzma_next_strm_init(lzma_block_decoder_init, strm, options);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}

View File

@@ -24,6 +24,6 @@
extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_block *options);
lzma_allocator *allocator, lzma_block *options);
#endif

View File

@@ -18,11 +18,25 @@
///////////////////////////////////////////////////////////////////////////////
#include "block_encoder.h"
#include "block_private.h"
#include "raw_encoder.h"
#include "filter_encoder.h"
#include "check.h"
/// The maximum size of a single Block is limited by the maximum size of
/// a Stream, which is 2^63 - 1 bytes (i.e. LZMA_VLI_VALUE_MAX). We could
/// take into account the headers etc. to determine the exact maximum size
/// of the Compressed Data field, but the complexity would give us nothing
/// useful. Instead, limit the size of Compressed Data so that even with
/// biggest possible Block Header and Check fields the total size of the
/// Block stays as valid VLI. This way we don't produce incorrect output
/// if someone will really try creating a Block of 8 EiB.
///
/// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
/// the Compressed Data field, it will still stay in the proper limit.
#define COMPRESSED_SIZE_MAX ((LZMA_VLI_VALUE_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
- LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
struct lzma_coder_s {
/// The filters in the chain; initialized with lzma_raw_decoder_init().
lzma_next_coder next;
@@ -30,41 +44,25 @@ struct lzma_coder_s {
/// Encoding options; we also write Total Size, Compressed Size, and
/// Uncompressed Size back to this structure when the encoding has
/// been finished.
lzma_options_block *options;
lzma_block *options;
enum {
SEQ_CODE,
SEQ_CHECK_FINISH,
SEQ_CHECK_COPY,
SEQ_UNCOMPRESSED_SIZE,
SEQ_BACKWARD_SIZE,
SEQ_PADDING,
SEQ_CHECK,
} sequence;
/// Position in .header and .check.
size_t pos;
/// Check of the uncompressed data
lzma_check check;
/// Total Size calculated while encoding
lzma_vli total_size;
/// Compressed Size calculated while encoding
lzma_vli compressed_size;
/// Uncompressed Size calculated while encoding
lzma_vli uncompressed_size;
/// Maximum allowed total_size
lzma_vli total_limit;
/// Position when writing out the Check field
size_t check_pos;
/// Maximum allowed uncompressed_size
lzma_vli uncompressed_limit;
/// Backward Size - This is a copy of total_size right before
/// the Backward Size field.
lzma_vli backward_size;
/// Check of the uncompressed data
lzma_check_state check;
};
@@ -75,26 +73,9 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
// Check that our amount of input stays in proper limits.
if (coder->options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
if (action == LZMA_FINISH) {
if (coder->options->uncompressed_size
- coder->uncompressed_size
!= (lzma_vli)(in_size - *in_pos))
return LZMA_DATA_ERROR;
} else {
if (coder->options->uncompressed_size
- coder->uncompressed_size
< (lzma_vli)(in_size - *in_pos))
return LZMA_DATA_ERROR;
}
} else if (LZMA_VLI_VALUE_MAX - coder->uncompressed_size
< (lzma_vli)(in_size - *in_pos)) {
return LZMA_DATA_ERROR;
}
if (LZMA_VLI_VALUE_MAX - coder->uncompressed_size < in_size - *in_pos)
return LZMA_PROG_ERROR;
// Main loop
while (*out_pos < out_size
&& (*in_pos < in_size || action == LZMA_FINISH))
switch (coder->sequence) {
case SEQ_CODE: {
const size_t in_start = *in_pos;
@@ -107,13 +88,11 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator,
const size_t in_used = *in_pos - in_start;
const size_t out_used = *out_pos - out_start;
if (update_size(&coder->total_size, out_used,
coder->total_limit)
|| update_size(&coder->compressed_size,
out_used,
coder->options->compressed_size))
if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
return LZMA_DATA_ERROR;
coder->compressed_size += out_used;
// No need to check for overflow because we have already
// checked it at the beginning of this function.
coder->uncompressed_size += in_used;
@@ -121,192 +100,94 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator,
lzma_check_update(&coder->check, coder->options->check,
in + in_start, in_used);
if (ret != LZMA_STREAM_END)
if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
return ret;
assert(*in_pos == in_size);
assert(action == LZMA_FINISH);
// Compressed and Uncompressed Sizes are now at their final
// values. Verify that they match the values give to us.
if (!is_size_valid(coder->compressed_size,
coder->options->compressed_size)
|| !is_size_valid(coder->uncompressed_size,
coder->options->uncompressed_size))
return LZMA_DATA_ERROR;
coder->sequence = SEQ_CHECK_FINISH;
break;
coder->sequence = SEQ_PADDING;
}
case SEQ_CHECK_FINISH:
if (coder->options->check == LZMA_CHECK_NONE) {
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
break;
}
lzma_check_finish(&coder->check, coder->options->check);
coder->sequence = SEQ_CHECK_COPY;
// Fall through
case SEQ_CHECK_COPY:
assert(lzma_check_sizes[coder->options->check] > 0);
switch (coder->options->check) {
case LZMA_CHECK_CRC32:
out[*out_pos] = coder->check.crc32 >> (coder->pos * 8);
break;
case LZMA_CHECK_CRC64:
out[*out_pos] = coder->check.crc64 >> (coder->pos * 8);
break;
case LZMA_CHECK_SHA256:
out[*out_pos] = coder->check.sha256.buffer[coder->pos];
break;
default:
assert(0);
return LZMA_PROG_ERROR;
}
++*out_pos;
if (update_size(&coder->total_size, 1, coder->total_limit))
return LZMA_DATA_ERROR;
if (++coder->pos == lzma_check_sizes[coder->options->check]) {
coder->pos = 0;
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
}
break;
case SEQ_UNCOMPRESSED_SIZE:
if (coder->options->has_uncompressed_size_in_footer) {
const size_t out_start = *out_pos;
const lzma_ret ret = lzma_vli_encode(
coder->uncompressed_size,
&coder->pos, 1,
out, out_pos, out_size);
// Updating the size this way instead of doing in a
// single chunk using lzma_vli_size(), because this
// way we detect when exactly we are going out of
// our limits.
if (update_size(&coder->total_size,
*out_pos - out_start,
coder->total_limit))
return LZMA_DATA_ERROR;
if (ret != LZMA_STREAM_END)
return ret;
coder->pos = 0;
}
coder->backward_size = coder->total_size;
coder->sequence = SEQ_BACKWARD_SIZE;
break;
case SEQ_BACKWARD_SIZE:
if (coder->options->has_backward_size) {
const size_t out_start = *out_pos;
const lzma_ret ret = lzma_vli_encode(
coder->backward_size, &coder->pos, 1,
out, out_pos, out_size);
if (update_size(&coder->total_size,
*out_pos - out_start,
coder->total_limit))
return LZMA_DATA_ERROR;
if (ret != LZMA_STREAM_END)
return ret;
}
coder->sequence = SEQ_PADDING;
break;
case SEQ_PADDING:
if (coder->options->handle_padding) {
assert(!coder->options
->has_uncompressed_size_in_footer);
assert(!coder->options->has_backward_size);
assert(coder->options->total_size != LZMA_VLI_VALUE_UNKNOWN);
// Pad Compressed Data to a multiple of four bytes.
while (coder->compressed_size & 3) {
if (*out_pos >= out_size)
return LZMA_OK;
if (coder->total_size < coder->options->total_size) {
out[*out_pos] = 0x00;
++*out_pos;
out[*out_pos] = 0x00;
++*out_pos;
if (update_size(&coder->total_size, 1,
coder->total_limit))
return LZMA_DATA_ERROR;
break;
}
// No need to use check for overflow here since we
// have already checked in SEQ_CODE that Compressed
// Size will stay in proper limits.
++coder->compressed_size;
}
// Now also Total Size is known. Verify it.
if (!is_size_valid(coder->total_size,
coder->options->total_size))
return LZMA_DATA_ERROR;
// Copy the values into coder->options. The caller
// may use this information to construct Index.
coder->options->total_size = coder->total_size;
coder->options->compressed_size = coder->compressed_size;
coder->options->uncompressed_size = coder->uncompressed_size;
return LZMA_STREAM_END;
if (coder->options->check == LZMA_CHECK_NONE)
return LZMA_STREAM_END;
default:
return LZMA_PROG_ERROR;
lzma_check_finish(&coder->check, coder->options->check);
coder->sequence = SEQ_CHECK;
// Fall through
case SEQ_CHECK: {
const uint32_t check_size
= lzma_check_size(coder->options->check);
while (*out_pos < out_size) {
out[*out_pos] = coder->check.buffer.u8[
coder->check_pos];
++*out_pos;
if (++coder->check_pos == check_size)
return LZMA_STREAM_END;
}
return LZMA_OK;
}
}
return LZMA_OK;
return LZMA_PROG_ERROR;
}
static void
block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_ret
block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_options_block *options)
extern lzma_ret
lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_block *options)
{
// Validate some options.
if (options == NULL
|| !lzma_vli_is_valid(options->total_size)
|| !lzma_vli_is_valid(options->compressed_size)
|| !lzma_vli_is_valid(options->uncompressed_size)
|| !lzma_vli_is_valid(options->total_size)
|| !lzma_vli_is_valid(options->total_limit)
|| !lzma_vli_is_valid(options->uncompressed_limit)
|| (options->uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN
&& options->uncompressed_size
> options->uncompressed_limit)
|| (options->total_size != LZMA_VLI_VALUE_UNKNOWN
&& options->total_size
> options->total_limit)
|| (!options->has_eopm && options->uncompressed_size
== LZMA_VLI_VALUE_UNKNOWN)
|| (options->handle_padding && (options->total_size
== LZMA_VLI_VALUE_UNKNOWN
|| options->has_uncompressed_size_in_footer
|| options->has_backward_size))
|| options->header_size > options->total_size)
lzma_next_coder_init(lzma_block_encoder_init, next, allocator);
// While lzma_block_total_size_get() is meant to calculate the Total
// Size, it also validates the options excluding the filters.
if (lzma_block_total_size_get(options) == 0)
return LZMA_PROG_ERROR;
// If the Check ID is not supported, we cannot calculate the check and
// thus not create a proper Block.
if ((unsigned)(options->check) > LZMA_CHECK_ID_MAX)
return LZMA_PROG_ERROR;
if (!lzma_check_is_supported(options->check))
return LZMA_UNSUPPORTED_CHECK;
// Allocate and initialize *next->coder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
@@ -318,55 +199,26 @@ block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
next->coder->next = LZMA_NEXT_CODER_INIT;
}
// Initialize the check.
return_if_error(lzma_check_init(&next->coder->check, options->check));
// If End of Payload Marker is not used and Uncompressed Size is zero,
// Compressed Data is empty. That is, we don't call the encoder at all.
// We initialize it though; it allows detecting invalid options.
if (!options->has_eopm && options->uncompressed_size == 0) {
// Also Compressed Size must also be zero if it has been
// given to us.
if (!is_size_valid(options->compressed_size, 0))
return LZMA_PROG_ERROR;
next->coder->sequence = SEQ_CHECK_FINISH;
} else {
next->coder->sequence = SEQ_CODE;
}
// Other initializations
// Basic initializations
next->coder->sequence = SEQ_CODE;
next->coder->options = options;
next->coder->pos = 0;
next->coder->total_size = options->header_size;
next->coder->compressed_size = 0;
next->coder->uncompressed_size = 0;
next->coder->total_limit
= MIN(options->total_size, options->total_limit);
next->coder->uncompressed_limit = MIN(options->uncompressed_size,
options->uncompressed_limit);
// Initialize the check
next->coder->check_pos = 0;
lzma_check_init(&next->coder->check, options->check);
// Initialize the requested filters.
return lzma_raw_encoder_init(&next->coder->next, allocator,
options->filters, options->has_eopm
? LZMA_VLI_VALUE_UNKNOWN
: options->uncompressed_size,
true);
}
extern lzma_ret
lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_options_block *options)
{
lzma_next_coder_init(block_encoder_init, next, allocator, options);
options->filters);
}
extern LZMA_API lzma_ret
lzma_block_encoder(lzma_stream *strm, lzma_options_block *options)
lzma_block_encoder(lzma_stream *strm, lzma_block *options)
{
lzma_next_strm_init(strm, block_encoder_init, options);
lzma_next_strm_init(lzma_block_encoder_init, strm, options);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;

View File

@@ -24,6 +24,6 @@
extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_block *options);
lzma_allocator *allocator, lzma_block *options);
#endif

View File

@@ -21,353 +21,111 @@
#include "check.h"
struct lzma_coder_s {
lzma_options_block *options;
enum {
SEQ_FLAGS_1,
SEQ_FLAGS_2,
SEQ_COMPRESSED_SIZE,
SEQ_UNCOMPRESSED_SIZE,
SEQ_FILTER_FLAGS_INIT,
SEQ_FILTER_FLAGS_DECODE,
SEQ_CRC32,
SEQ_PADDING
} sequence;
/// Position in variable-length integers
size_t pos;
/// CRC32 of the Block Header
uint32_t crc32;
lzma_next_coder filter_flags_decoder;
};
static bool
update_sequence(lzma_coder *coder)
{
switch (coder->sequence) {
case SEQ_FLAGS_2:
if (coder->options->compressed_size
!= LZMA_VLI_VALUE_UNKNOWN) {
coder->pos = 0;
coder->sequence = SEQ_COMPRESSED_SIZE;
break;
}
// Fall through
case SEQ_COMPRESSED_SIZE:
if (coder->options->uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN) {
coder->pos = 0;
coder->sequence = SEQ_UNCOMPRESSED_SIZE;
break;
}
// Fall through
case SEQ_UNCOMPRESSED_SIZE:
coder->pos = 0;
// Fall through
case SEQ_FILTER_FLAGS_DECODE:
if (coder->options->filters[coder->pos].id
!= LZMA_VLI_VALUE_UNKNOWN) {
coder->sequence = SEQ_FILTER_FLAGS_INIT;
break;
}
if (coder->options->has_crc32) {
coder->pos = 0;
coder->sequence = SEQ_CRC32;
break;
}
case SEQ_CRC32:
if (coder->options->padding != 0) {
coder->pos = 0;
coder->sequence = SEQ_PADDING;
break;
}
return true;
default:
assert(0);
return true;
}
return false;
}
static lzma_ret
block_header_decode(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
size_t *restrict out_pos lzma_attribute((unused)),
size_t out_size lzma_attribute((unused)),
lzma_action action lzma_attribute((unused)))
{
while (*in_pos < in_size)
switch (coder->sequence) {
case SEQ_FLAGS_1:
// Check that the reserved bit is unset. Use HEADER_ERROR
// because newer version of liblzma may support the reserved
// bit, although it is likely that this is just a broken file.
if (in[*in_pos] & 0x40)
return LZMA_HEADER_ERROR;
// Number of filters: we prepare appropriate amount of
// variables for variable-length integer parsing. The
// initialization function has already reset the rest
// of the values to LZMA_VLI_VALUE_UNKNOWN, which allows
// us to later know how many filters there are.
for (int i = (int)(in[*in_pos] & 0x07) - 1; i >= 0; --i)
coder->options->filters[i].id = 0;
// End of Payload Marker flag
coder->options->has_eopm = (in[*in_pos] & 0x08) != 0;
// Compressed Size: Prepare for variable-length integer
// parsing if it is known.
if (in[*in_pos] & 0x10)
coder->options->compressed_size = 0;
// Uncompressed Size: the same.
if (in[*in_pos] & 0x20)
coder->options->uncompressed_size = 0;
// Is Metadata Block flag
coder->options->is_metadata = (in[*in_pos] & 0x80) != 0;
// We need at least one: Uncompressed Size or EOPM.
if (coder->options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN
&& !coder->options->has_eopm)
return LZMA_DATA_ERROR;
// Update header CRC32.
coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
++*in_pos;
coder->sequence = SEQ_FLAGS_2;
break;
case SEQ_FLAGS_2:
// Check that the reserved bits are unset.
if (in[*in_pos] & 0xE0)
return LZMA_DATA_ERROR;
// Get the size of Header Padding.
coder->options->padding = in[*in_pos] & 0x1F;
coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
++*in_pos;
if (update_sequence(coder))
return LZMA_STREAM_END;
break;
case SEQ_COMPRESSED_SIZE: {
// Store the old input position to be used when
// updating coder->header_crc32.
const size_t in_start = *in_pos;
const lzma_ret ret = lzma_vli_decode(
&coder->options->compressed_size,
&coder->pos, in, in_pos, in_size);
const size_t in_used = *in_pos - in_start;
coder->options->compressed_reserve += in_used;
assert(coder->options->compressed_reserve
<= LZMA_VLI_BYTES_MAX);
coder->options->header_size += in_used;
coder->crc32 = lzma_crc32(in + in_start, in_used,
coder->crc32);
if (ret != LZMA_STREAM_END)
return ret;
if (update_sequence(coder))
return LZMA_STREAM_END;
break;
}
case SEQ_UNCOMPRESSED_SIZE: {
const size_t in_start = *in_pos;
const lzma_ret ret = lzma_vli_decode(
&coder->options->uncompressed_size,
&coder->pos, in, in_pos, in_size);
const size_t in_used = *in_pos - in_start;
coder->options->uncompressed_reserve += in_used;
assert(coder->options->uncompressed_reserve
<= LZMA_VLI_BYTES_MAX);
coder->options->header_size += in_used;
coder->crc32 = lzma_crc32(in + in_start, in_used,
coder->crc32);
if (ret != LZMA_STREAM_END)
return ret;
if (update_sequence(coder))
return LZMA_STREAM_END;
break;
}
case SEQ_FILTER_FLAGS_INIT: {
assert(coder->options->filters[coder->pos].id
!= LZMA_VLI_VALUE_UNKNOWN);
const lzma_ret ret = lzma_filter_flags_decoder_init(
&coder->filter_flags_decoder, allocator,
&coder->options->filters[coder->pos]);
if (ret != LZMA_OK)
return ret;
coder->sequence = SEQ_FILTER_FLAGS_DECODE;
}
// Fall through
case SEQ_FILTER_FLAGS_DECODE: {
const size_t in_start = *in_pos;
const lzma_ret ret = coder->filter_flags_decoder.code(
coder->filter_flags_decoder.coder,
allocator, in, in_pos, in_size,
NULL, NULL, 0, LZMA_RUN);
const size_t in_used = *in_pos - in_start;
coder->options->header_size += in_used;
coder->crc32 = lzma_crc32(in + in_start,
in_used, coder->crc32);
if (ret != LZMA_STREAM_END)
return ret;
++coder->pos;
if (update_sequence(coder))
return LZMA_STREAM_END;
break;
}
case SEQ_CRC32:
assert(coder->options->has_crc32);
if (in[*in_pos] != ((coder->crc32 >> (coder->pos * 8)) & 0xFF))
return LZMA_DATA_ERROR;
++*in_pos;
++coder->pos;
// Check if we reached end of the CRC32 field.
if (coder->pos == 4) {
coder->options->header_size += 4;
if (update_sequence(coder))
return LZMA_STREAM_END;
}
break;
case SEQ_PADDING:
if (in[*in_pos] != 0x00)
return LZMA_DATA_ERROR;
++*in_pos;
++coder->options->header_size;
++coder->pos;
if (coder->pos < (size_t)(coder->options->padding))
break;
return LZMA_STREAM_END;
default:
return LZMA_PROG_ERROR;
}
return LZMA_OK;
}
static void
block_header_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
free_properties(lzma_block *options, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->filter_flags_decoder, allocator);
lzma_free(coder, allocator);
return;
}
extern lzma_ret
lzma_block_header_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_block *options)
{
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
next->code = &block_header_decode;
next->end = &block_header_decoder_end;
next->coder->filter_flags_decoder = LZMA_NEXT_CODER_INIT;
}
// Assume that Compressed Size and Uncompressed Size are unknown.
options->compressed_size = LZMA_VLI_VALUE_UNKNOWN;
options->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
// We will calculate the sizes of these fields too so that the
// application may rewrite the header if it wishes so.
options->compressed_reserve = 0;
options->uncompressed_reserve = 0;
// The Block Flags field is always present, so include its size here
// and we don't need to worry about it in block_header_decode().
options->header_size = 2;
// Reset filters[] to indicate empty list of filters.
// See SEQ_FLAGS_1 in block_header_decode() for reasoning of this.
for (size_t i = 0; i < 8; ++i) {
// Free allocated filter options. The last array member is not
// touched after the initialization in the beginning of
// lzma_block_header_decode(), so we don't need to touch that here.
for (size_t i = 0; i < LZMA_BLOCK_FILTERS_MAX; ++i) {
lzma_free(options->filters[i].options, allocator);
options->filters[i].id = LZMA_VLI_VALUE_UNKNOWN;
options->filters[i].options = NULL;
}
next->coder->options = options;
next->coder->sequence = SEQ_FLAGS_1;
next->coder->pos = 0;
next->coder->crc32 = 0;
return LZMA_OK;
return;
}
extern LZMA_API lzma_ret
lzma_block_header_decoder(lzma_stream *strm,
lzma_options_block *options)
lzma_block_header_decode(lzma_block *options,
lzma_allocator *allocator, const uint8_t *in)
{
lzma_next_strm_init(strm, lzma_block_header_decoder_init, options);
// NOTE: We consider the header to be corrupt not only when the
// CRC32 doesn't match, but also when variable-length integers
// are invalid or over 63 bits, or if the header is too small
// to contain the claimed information.
strm->internal->supported_actions[LZMA_RUN] = true;
// Initialize the filter options array. This way the caller can
// safely free() the options even if an error occurs in this function.
for (size_t i = 0; i <= LZMA_BLOCK_FILTERS_MAX; ++i) {
options->filters[i].id = LZMA_VLI_VALUE_UNKNOWN;
options->filters[i].options = NULL;
}
size_t in_size = options->header_size;
// Validate. The caller must have set options->header_size with
// lzma_block_header_size_decode() macro, so it is a programming error
// if these tests fail.
if (in_size < LZMA_BLOCK_HEADER_SIZE_MIN
|| in_size > LZMA_BLOCK_HEADER_SIZE_MAX
|| (in_size & 3)
|| lzma_block_header_size_decode(in[0]) != in_size)
return LZMA_PROG_ERROR;
// Exclude the CRC32 field.
in_size -= 4;
// Verify CRC32
if (lzma_crc32(in, in_size, 0) != integer_read_32(in + in_size))
return LZMA_DATA_ERROR;
// Check for unsupported flags.
if (in[1] & 0x3C)
return LZMA_HEADER_ERROR;
// Start after the Block Header Size and Block Flags fields.
size_t in_pos = 2;
// Compressed Size
if (in[1] & 0x40) {
return_if_error(lzma_vli_decode(&options->compressed_size,
NULL, in, &in_pos, in_size));
if (options->compressed_size > LZMA_VLI_VALUE_MAX / 4 - 1)
return LZMA_DATA_ERROR;
options->compressed_size = (options->compressed_size + 1) * 4;
// Check that Total Size (that is, size of
// Block Header + Compressed Data + Check) is
// representable as a VLI.
if (lzma_block_total_size_get(options) == 0)
return LZMA_DATA_ERROR;
} else {
options->compressed_size = LZMA_VLI_VALUE_UNKNOWN;
}
// Uncompressed Size
if (in[1] & 0x80)
return_if_error(lzma_vli_decode(&options->uncompressed_size,
NULL, in, &in_pos, in_size));
else
options->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
// Filter Flags
const size_t filter_count = (in[1] & 3) + 1;
for (size_t i = 0; i < filter_count; ++i) {
const lzma_ret ret = lzma_filter_flags_decode(
&options->filters[i], allocator,
in, &in_pos, in_size);
if (ret != LZMA_OK) {
free_properties(options, allocator);
return ret;
}
}
// Padding
while (in_pos < in_size) {
if (in[in_pos++] != 0x00) {
free_properties(options, allocator);
// Possibly some new field present so use
// LZMA_HEADER_ERROR instead of LZMA_DATA_ERROR.
return LZMA_HEADER_ERROR;
}
}
return LZMA_OK;
}

View File

@@ -22,190 +22,132 @@
extern LZMA_API lzma_ret
lzma_block_header_size(lzma_options_block *options)
lzma_block_header_size(lzma_block *options)
{
// Block Flags take two bytes.
size_t size = 2;
// Block Header Size + Block Flags + CRC32.
size_t size = 1 + 1 + 4;
// Compressed Size
if (!lzma_vli_is_valid(options->compressed_size)) {
return LZMA_PROG_ERROR;
} else if (options->compressed_reserve != 0) {
// Make sure that the known Compressed Size fits into the
// reserved space. Note that lzma_vli_size() will return zero
// if options->compressed_size is LZMA_VLI_VALUE_UNKNOWN, so
// we don't need to handle that special case separately.
if (options->compressed_reserve > LZMA_VLI_BYTES_MAX
|| lzma_vli_size(options->compressed_size)
> (size_t)(options->compressed_reserve))
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
if (options->compressed_size > LZMA_VLI_VALUE_MAX / 4 - 1
|| options->compressed_size == 0
|| (options->compressed_size & 3))
return LZMA_PROG_ERROR;
size += options->compressed_reserve;
} else if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
// Compressed Size is known. We have already checked
// that is is a valid VLI, and since it isn't
// LZMA_VLI_VALUE_UNKNOWN, we can be sure that
// lzma_vli_size() will succeed.
size += lzma_vli_size(options->compressed_size);
size += lzma_vli_size(options->compressed_size / 4 - 1);
}
// Uncompressed Size
if (!lzma_vli_is_valid(options->uncompressed_size)) {
return LZMA_PROG_ERROR;
} else if (options->uncompressed_reserve != 0) {
if (options->uncompressed_reserve > LZMA_VLI_BYTES_MAX
|| lzma_vli_size(options->uncompressed_size)
> (size_t)(options->uncompressed_reserve))
if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
const size_t add = lzma_vli_size(options->uncompressed_size);
if (add == 0)
return LZMA_PROG_ERROR;
size += options->uncompressed_reserve;
} else if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
size += lzma_vli_size(options->uncompressed_size);
size += add;
}
// List of Filter Flags
if (options->filters == NULL
|| options->filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_PROG_ERROR;
for (size_t i = 0; options->filters[i].id != LZMA_VLI_VALUE_UNKNOWN;
++i) {
// Don't allow too many filters.
if (i == 7)
if (i == 4)
return LZMA_PROG_ERROR;
uint32_t tmp;
const lzma_ret ret = lzma_filter_flags_size(&tmp,
options->filters + i);
if (ret != LZMA_OK)
return ret;
uint32_t add;
return_if_error(lzma_filter_flags_size(&add,
options->filters + i));
size += tmp;
size += add;
}
// CRC32
if (options->has_crc32)
size += 4;
// Pad to a multiple of four bytes.
options->header_size = (size + 3) & ~(size_t)(3);
// Padding
int32_t padding;
if (options->padding == LZMA_BLOCK_HEADER_PADDING_AUTO) {
const uint32_t preferred = lzma_alignment_output(
options->filters, 1);
const uint32_t unaligned = size + options->alignment;
padding = (int32_t)(unaligned % preferred);
if (padding != 0)
padding = preferred - padding;
} else if (options->padding >= LZMA_BLOCK_HEADER_PADDING_MIN
&& options->padding <= LZMA_BLOCK_HEADER_PADDING_MAX) {
padding = options->padding;
} else {
return LZMA_PROG_ERROR;
}
// All success. Copy the calculated values to the options structure.
options->padding = padding;
options->header_size = size + (size_t)(padding);
// NOTE: We don't verify that Total Size of the Block stays within
// limits. This is because it is possible that we are called with
// exaggerated values to reserve space for Block Header, and later
// called again with lower, real values.
return LZMA_OK;
}
extern LZMA_API lzma_ret
lzma_block_header_encode(uint8_t *out, const lzma_options_block *options)
lzma_block_header_encode(const lzma_block *options, uint8_t *out)
{
// We write the Block Flags later.
if (options->header_size < 2)
if ((options->header_size & 3)
|| options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
|| options->header_size > LZMA_BLOCK_HEADER_SIZE_MAX)
return LZMA_PROG_ERROR;
const size_t out_size = options->header_size;
// Indicate the size of the buffer _excluding_ the CRC32 field.
const size_t out_size = options->header_size - 4;
// Store the Block Header Size.
out[0] = out_size / 4;
// We write Block Flags a little later.
size_t out_pos = 2;
// Compressed Size
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
|| options->compressed_reserve != 0) {
const lzma_vli size = options->compressed_size
!= LZMA_VLI_VALUE_UNKNOWN
? options->compressed_size : 0;
size_t vli_pos = 0;
if (lzma_vli_encode(
size, &vli_pos, options->compressed_reserve,
out, &out_pos, out_size) != LZMA_STREAM_END)
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN) {
// Compressed Size must be non-zero, fit into a 63-bit
// integer and be a multiple of four. Also the Total Size
// of the Block must fit into 63-bit integer.
if (options->compressed_size == 0
|| (options->compressed_size & 3)
|| options->compressed_size
> LZMA_VLI_VALUE_MAX
|| lzma_block_total_size_get(options) == 0)
return LZMA_PROG_ERROR;
return_if_error(lzma_vli_encode(
options->compressed_size / 4 - 1, NULL,
out, &out_pos, out_size));
}
// Uncompressed Size
if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
|| options->uncompressed_reserve != 0) {
const lzma_vli size = options->uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN
? options->uncompressed_size : 0;
size_t vli_pos = 0;
if (lzma_vli_encode(
size, &vli_pos, options->uncompressed_reserve,
out, &out_pos, out_size) != LZMA_STREAM_END)
return LZMA_PROG_ERROR;
}
if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
return_if_error(lzma_vli_encode(
options->uncompressed_size, NULL,
out, &out_pos, out_size));
// Filter Flags
size_t filter_count;
for (filter_count = 0; options->filters[filter_count].id
!= LZMA_VLI_VALUE_UNKNOWN; ++filter_count) {
// There can be at maximum of seven filters.
if (filter_count == 7)
if (options->filters == NULL
|| options->filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_PROG_ERROR;
size_t filter_count = 0;
do {
// There can be at maximum of four filters.
if (filter_count == 4)
return LZMA_PROG_ERROR;
const lzma_ret ret = lzma_filter_flags_encode(out, &out_pos,
out_size, options->filters + filter_count);
// FIXME: Don't return LZMA_BUF_ERROR.
if (ret != LZMA_OK)
return ret;
}
return_if_error(lzma_filter_flags_encode(
options->filters + filter_count,
out, &out_pos, out_size));
// Block Flags 1
out[0] = filter_count;
} while (options->filters[++filter_count].id
!= LZMA_VLI_VALUE_UNKNOWN);
if (options->has_eopm)
out[0] |= 0x08;
else if (options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_PROG_ERROR;
// Block Flags
out[1] = filter_count - 1;
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN
|| options->compressed_reserve != 0)
out[0] |= 0x10;
if (options->compressed_size != LZMA_VLI_VALUE_UNKNOWN)
out[1] |= 0x40;
if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN
|| options->uncompressed_reserve != 0)
out[0] |= 0x20;
if (options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
out[1] |= 0x80;
if (options->is_metadata)
out[0] |= 0x80;
// Block Flags 2
if (options->padding < LZMA_BLOCK_HEADER_PADDING_MIN
|| options->padding > LZMA_BLOCK_HEADER_PADDING_MAX)
return LZMA_PROG_ERROR;
out[1] = (uint8_t)(options->padding);
// Padding
memzero(out + out_pos, out_size - out_pos);
// CRC32
if (options->has_crc32) {
if (out_size - out_pos < 4)
return LZMA_PROG_ERROR;
const uint32_t crc = lzma_crc32(out, out_pos, 0);
for (size_t i = 0; i < 4; ++i)
out[out_pos++] = crc >> (i * 8);
}
// Padding - the amount of available space must now match with
// the size of the Padding field.
if (out_size - out_pos != (size_t)(options->padding))
return LZMA_PROG_ERROR;
memzero(out + out_pos, (size_t)(options->padding));
integer_write_32(out + out_size, lzma_crc32(out, out_size, 0));
return LZMA_OK;
}

View File

@@ -0,0 +1,73 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file block_header.c
/// \brief Utility functions to handle lzma_block
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
extern LZMA_API lzma_ret
lzma_block_total_size_set(lzma_block *options, lzma_vli total_size)
{
// Validate.
if (options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
|| options->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
|| (options->header_size & 3)
|| (unsigned)(options->check) > LZMA_CHECK_ID_MAX
|| (total_size & 3))
return LZMA_PROG_ERROR;
const uint32_t container_size = options->header_size
+ lzma_check_size(options->check);
// Validate that Compressed Size will be greater than zero.
if (container_size <= total_size)
return LZMA_DATA_ERROR;
options->compressed_size = total_size - container_size;
return LZMA_OK;
}
extern LZMA_API lzma_vli
lzma_block_total_size_get(const lzma_block *options)
{
// Validate the values that we are interested in.
if (options->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
|| options->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
|| (options->header_size & 3)
|| (unsigned)(options->check) > LZMA_CHECK_ID_MAX)
return 0;
// If Compressed Size is unknown, return that we cannot know
// Total Size either.
if (options->compressed_size == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_VLI_VALUE_UNKNOWN;
const lzma_vli total_size = options->compressed_size
+ options->header_size
+ lzma_check_size(options->check);
// Validate the calculated Total Size.
if (options->compressed_size > LZMA_VLI_VALUE_MAX
|| (options->compressed_size & 3)
|| total_size > LZMA_VLI_VALUE_MAX)
return 0;
return total_size;
}

61
src/liblzma/common/bsr.h Normal file
View File

@@ -0,0 +1,61 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file bsr.h
/// \brief Bit scan reverse
//
// This code has been put into the public domain.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_BSR_H
#define LZMA_BSR_H
// NOTE: Both input and output variables for lzma_bsr must be uint32_t.
#if defined(__GNUC__) && (defined (HAVE_ASM_X86) || defined(HAVE_ASM_X86_64))
# define lzma_bsr(dest, n) \
__asm__("bsrl %1, %0" : "=r" (dest) : "rm" (n))
#else
# define lzma_bsr(dest, n) dest = lzma_bsr_helper(n)
static inline uint32_t
lzma_bsr_helper(uint32_t n)
{
assert(n != 0);
uint32_t i = 31;
if ((n & UINT32_C(0xFFFF0000)) == 0) {
n <<= 16;
i = 15;
}
if ((n & UINT32_C(0xFF000000)) == 0) {
n <<= 8;
i -= 8;
}
if ((n & UINT32_C(0xF0000000)) == 0) {
n <<= 4;
i -= 4;
}
if ((n & UINT32_C(0xC0000000)) == 0) {
n <<= 2;
i -= 2;
}
if ((n & UINT32_C(0x80000000)) == 0)
--i;
return i;
}
#endif
#endif

View File

@@ -1,9 +1,9 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file code.c
/// \brief zlib-like API wrapper for liblzma's internal API
/// \file common.h
/// \brief Common functions needed in many places in liblzma
//
// Copyright (C) 2007 Lasse Collin
// Copyright (C) 2007-2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,17 +20,115 @@
#include "common.h"
LZMA_API const lzma_stream LZMA_STREAM_INIT_VAR = {
.next_in = NULL,
.avail_in = 0,
.total_in = 0,
.next_out = NULL,
.avail_out = 0,
.total_out = 0,
.allocator = NULL,
.internal = NULL,
};
/////////////
// Version //
/////////////
extern LZMA_API uint32_t
lzma_version_number(void)
{
return LZMA_VERSION;
}
extern LZMA_API const char *
lzma_version_string(void)
{
return PACKAGE_VERSION;
}
///////////////////////
// Memory allocation //
///////////////////////
extern void * lzma_attribute((malloc))
lzma_alloc(size_t size, lzma_allocator *allocator)
{
// Some malloc() variants return NULL if called with size == 0.
if (size == 0)
size = 1;
void *ptr;
if (allocator != NULL && allocator->alloc != NULL)
ptr = allocator->alloc(allocator->opaque, 1, size);
else
ptr = malloc(size);
return ptr;
}
extern void
lzma_free(void *ptr, lzma_allocator *allocator)
{
if (allocator != NULL && allocator->free != NULL)
allocator->free(allocator->opaque, ptr);
else
free(ptr);
return;
}
//////////
// Misc //
//////////
extern size_t
lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size)
{
const size_t in_avail = in_size - *in_pos;
const size_t out_avail = out_size - *out_pos;
const size_t copy_size = MIN(in_avail, out_avail);
memcpy(out + *out_pos, in + *in_pos, copy_size);
*in_pos += copy_size;
*out_pos += copy_size;
return copy_size;
}
extern lzma_ret
lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters)
{
lzma_next_coder_init(filters[0].init, next, allocator);
return filters[0].init == NULL
? LZMA_OK : filters[0].init(next, allocator, filters);
}
extern void
lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator)
{
if (next->init != (uintptr_t)(NULL)) {
// To avoid tiny end functions that simply call
// lzma_free(coder, allocator), we allow leaving next->end
// NULL and call lzma_free() here.
if (next->end != NULL)
next->end(next->coder, allocator);
else
lzma_free(next->coder, allocator);
// Reset the variables so the we don't accidentally think
// that it is an already initialized coder.
*next = LZMA_NEXT_CODER_INIT;
}
return;
}
//////////////////////////////////////
// External to internal API wrapper //
//////////////////////////////////////
extern lzma_ret
lzma_strm_init(lzma_stream *strm)
@@ -191,13 +289,17 @@ extern LZMA_API void
lzma_end(lzma_stream *strm)
{
if (strm != NULL && strm->internal != NULL) {
if (strm->internal->next.end != NULL)
strm->internal->next.end(strm->internal->next.coder,
strm->allocator);
lzma_next_end(&strm->internal->next, strm->allocator);
lzma_free(strm->internal, strm->allocator);
strm->internal = NULL;
}
return;
}
extern LZMA_API lzma_check
lzma_get_check(const lzma_stream *strm)
{
return strm->internal->next.get_check(strm->internal->next.coder);
}

View File

@@ -3,7 +3,7 @@
/// \file common.h
/// \brief Definitions common to the whole liblzma library
//
// Copyright (C) 2007 Lasse Collin
// Copyright (C) 2007-2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -20,7 +20,8 @@
#ifndef LZMA_COMMON_H
#define LZMA_COMMON_H
#include "sysdefs.h"
#include "../../common/sysdefs.h"
#include "../../common/integer.h"
// Don't use ifdef...
#if HAVE_VISIBILITY
@@ -30,20 +31,47 @@
#endif
// These allow helping the compiler in some often-executed branches, whose
// result is almost always the same.
#ifdef __GNUC__
# define likely(expr) __builtin_expect(expr, true)
# define unlikely(expr) __builtin_expect(expr, false)
#else
# define likely(expr) (expr)
# define unlikely(expr) (expr)
#endif
/// Size of temporary buffers needed in some filters
#define LZMA_BUFFER_SIZE 4096
/// Start of internal Filter ID space. These IDs must never be used
/// in Streams.
#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
/// Internal helper filter used by Subblock decoder. It is mapped to an
/// otherwise invalid Filter ID, which is impossible to get from any input
/// file (even if malicious file).
#define LZMA_FILTER_SUBBLOCK_HELPER (UINT64_MAX - 2)
#define LZMA_FILTER_SUBBLOCK_HELPER (LZMA_FILTER_RESERVED_START + 1)
/// Supported flags that can be passed to lzma_stream_decoder()
/// or lzma_auto_decoder().
#define LZMA_SUPPORTED_FLAGS \
( LZMA_TELL_NO_CHECK \
| LZMA_TELL_UNSUPPORTED_CHECK \
| LZMA_TELL_ANY_CHECK \
| LZMA_CONCATENATED )
///////////
// Types //
///////////
/// Type of encoder/decoder specific data; the actual structure is defined
/// differently in different coders.
typedef struct lzma_coder_s lzma_coder;
typedef struct lzma_next_coder_s lzma_next_coder;
@@ -51,10 +79,15 @@ typedef struct lzma_next_coder_s lzma_next_coder;
typedef struct lzma_filter_info_s lzma_filter_info;
/// Type of a function used to initialize a filter encoder or decoder
typedef lzma_ret (*lzma_init_function)(
lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters);
/// Type of a function to do some kind of coding work (filters, Stream,
/// Block encoders/decoders etc.). Some special coders use don't use both
/// input and output buffers, but for simplicity they still use this same
/// function prototype.
typedef lzma_ret (*lzma_code_function)(
lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
@@ -62,10 +95,24 @@ typedef lzma_ret (*lzma_code_function)(
size_t *restrict out_pos, size_t out_size,
lzma_action action);
/// Type of a function to free the memory allocated for the coder
typedef void (*lzma_end_function)(
lzma_coder *coder, lzma_allocator *allocator);
/// Raw coder validates and converts an array of lzma_filter structures to
/// an array of lzma_filter_info structures. This array is used with
/// lzma_next_filter_init to initialize the filter chain.
struct lzma_filter_info_s {
/// Pointer to function used to initialize the filter.
/// This is NULL to indicate end of array.
lzma_init_function init;
/// Pointer to filter's options structure
void *options;
};
/// Hold data and function pointers of the next filter in the chain.
struct lzma_next_coder_s {
/// Pointer to coder-specific data
@@ -73,28 +120,50 @@ struct lzma_next_coder_s {
/// "Pointer" to init function. This is never called here.
/// We need only to detect if we are initializing a coder
/// that was allocated earlier. See code.c and next_coder.c.
/// that was allocated earlier. See lzma_next_coder_init and
/// lzma_next_strm_init macros in this file.
uintptr_t init;
/// Pointer to function to do the actual coding
lzma_code_function code;
/// Pointer to function to free lzma_next_coder.coder
/// Pointer to function to free lzma_next_coder.coder. This can
/// be NULL; in that case, lzma_free is called to free
/// lzma_next_coder.coder.
lzma_end_function end;
/// Pointer to function to return the type of the integrity check.
/// Most coders won't support this.
lzma_check (*get_check)(const lzma_coder *coder);
/// Pointer to function to get and/or change the memory usage limit.
/// If memlimit == 0, the limit is not changed.
uint64_t (*memconfig)(lzma_coder *coder, uint64_t memlimit);
};
/// Macro to initialize lzma_next_coder structure
#define LZMA_NEXT_CODER_INIT \
(lzma_next_coder){ \
.coder = NULL, \
.init = 0, \
.init = (uintptr_t)(NULL), \
.code = NULL, \
.end = NULL, \
.get_check = NULL, \
.memconfig = NULL, \
}
/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to
/// this is stored in lzma_stream.
struct lzma_internal_s {
/// The actual coder that should do something useful
lzma_next_coder next;
/// Track the state of the coder. This is used to validate arguments
/// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH
/// is used on every call to lzma_code until next.code has returned
/// LZMA_STREAM_END.
enum {
ISEQ_RUN,
ISEQ_SYNC_FLUSH,
@@ -104,37 +173,20 @@ struct lzma_internal_s {
ISEQ_ERROR,
} sequence;
bool supported_actions[4];
bool allow_buf_error;
/// A copy of lzma_stream avail_in. This is used to verify that the
/// amount of input doesn't change once e.g. LZMA_FINISH has been
/// used.
size_t avail_in;
/// Indicates which lzma_action values are allowed by next.code.
bool supported_actions[4];
/// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
/// made (no input consumed and no output produced by next.code).
bool allow_buf_error;
};
struct lzma_filter_info_s {
/// Pointer to function used to initialize the filter.
/// This is NULL to indicate end of array.
lzma_init_function init;
/// Pointer to filter's options structure
void *options;
/// Uncompressed size of the filter, or LZMA_VLI_VALUE_UNKNOWN
/// if unknown.
lzma_vli uncompressed_size;
};
/*
typedef struct {
lzma_init_function init;
uint32_t (*input_alignment)(lzma_vli id, const void *options);
uint32_t (*output_alignment)(lzma_vli id, const void *options);
bool changes_uncompressed_size;
bool supports_eopm;
} lzma_filter_hook;
*/
///////////////
// Functions //
///////////////
@@ -146,126 +198,69 @@ extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
/// Frees memory
extern void lzma_free(void *ptr, lzma_allocator *allocator);
/// Initializes lzma_stream FIXME desc
/// Allocates strm->internal if it is NULL, and initializes *strm and
/// strm->internal. This function is only called via lzma_next_strm_init macro.
extern lzma_ret lzma_strm_init(lzma_stream *strm);
///
/// Initializes the next filter in the chain, if any. This takes care of
/// freeing the memory of previously initialized filter if it is different
/// than the filter being initialized now. This way the actual filter
/// initialization functions don't need to use lzma_next_coder_init macro.
extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
///
extern void lzma_next_coder_end(lzma_next_coder *next,
lzma_allocator *allocator);
/// Frees the memory allocated for next->coder either using next->end or,
/// if next->end is NULL, using lzma_free.
extern void lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator);
extern lzma_ret lzma_filter_flags_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_filter *options);
extern lzma_ret lzma_block_header_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_block *options);
extern lzma_ret lzma_stream_encoder_single_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_options_stream *options);
extern lzma_ret lzma_stream_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_extra **header, lzma_extra **footer);
/// \brief Wrapper for memcpy()
///
/// This function copies as much data as possible from in[] to out[] and
/// updates *in_pos and *out_pos accordingly.
///
static inline size_t
bufcpy(const uint8_t *restrict in, size_t *restrict in_pos, size_t in_size,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size)
{
const size_t in_avail = in_size - *in_pos;
const size_t out_avail = out_size - *out_pos;
const size_t copy_size = MIN(in_avail, out_avail);
memcpy(out + *out_pos, in + *in_pos, copy_size);
*in_pos += copy_size;
*out_pos += copy_size;
return copy_size;
}
/// \brief Initializing the next coder
///
/// lzma_next_coder can point to different types of coders. The existing
/// coder may be different than what we are initializing now. In that case
/// we must git rid of the old coder first. Otherwise we reuse the existing
/// coder structure.
///
#define lzma_next_coder_init2(next, allocator, cmpfunc, func, ...) \
do { \
if ((uintptr_t)(&cmpfunc) != (next)->init) \
lzma_next_coder_end(next, allocator); \
const lzma_ret ret = func(next, __VA_ARGS__); \
if (ret == LZMA_OK) { \
(next)->init = (uintptr_t)(&cmpfunc); \
assert((next)->code != NULL); \
assert((next)->end != NULL); \
} else { \
lzma_next_coder_end(next, allocator); \
} \
return ret; \
} while (0)
/// \brief Initializing lzma_next_coder
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_coder_init(func, next, allocator, ...) \
lzma_next_coder_init2(next, allocator, \
func, func, allocator, __VA_ARGS__)
/// \brief Initializing lzma_stream
///
/// lzma_strm initialization with more detailed options.
#define lzma_next_strm_init2(strm, cmpfunc, func, ...) \
do { \
lzma_ret ret = lzma_strm_init(strm); \
if (ret != LZMA_OK) \
return ret; \
if ((uintptr_t)(&cmpfunc) != (strm)->internal->next.init) \
lzma_next_coder_end(\
&(strm)->internal->next, (strm)->allocator); \
ret = func(&(strm)->internal->next, __VA_ARGS__); \
if (ret != LZMA_OK) { \
lzma_end(strm); \
return ret; \
} \
(strm)->internal->next.init = (uintptr_t)(&cmpfunc); \
assert((strm)->internal->next.code != NULL); \
assert((strm)->internal->next.end != NULL); \
} while (0)
/// \brief Initializing lzma_stream
///
/// Call the initialization function, which must take at least one
/// argument in addition to lzma_next_coder and lzma_allocator.
#define lzma_next_strm_init(strm, func, ...) \
lzma_next_strm_init2(strm, func, func, (strm)->allocator, __VA_ARGS__)
/// Copy as much data as possible from in[] to out[] and update *in_pos
/// and *out_pos accordingly. Returns the number of bytes copied.
extern size_t lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size);
/// \brief Return if expression doesn't evaluate to LZMA_OK
///
/// There are several situations where we want to return immediatelly
/// with the value of expr if it isn't LZMA_OK. This macro shortens
/// the code a bit.
///
/// the code a little.
#define return_if_error(expr) \
do { \
const lzma_ret ret_ = expr; \
const lzma_ret ret_ = (expr); \
if (ret_ != LZMA_OK) \
return ret_; \
} while (0)
/// If next isn't already initialized, free the previous coder. Then mark
/// that next is _possibly_ initialized for the coder using this macro.
/// "Possibly" means that if e.g. allocation of next->coder fails, the
/// structure isn't actually initialized for this coder, but leaving
/// next->init to func is still OK.
#define lzma_next_coder_init(func, next, allocator) \
do { \
if ((uintptr_t)(&func) != (next)->init) \
lzma_next_end(next, allocator); \
(next)->init = (uintptr_t)(&func); \
} while (0)
/// Initializes lzma_strm and calls func() to initialize strm->internal->next.
/// (The function being called will use lzma_next_coder_init()). If
/// initialization fails, memory that wasn't freed by func() is freed
/// along strm->internal.
#define lzma_next_strm_init(func, strm, ...) \
do { \
return_if_error(lzma_strm_init(strm)); \
const lzma_ret ret_ = func(&(strm)->internal->next, \
(strm)->allocator, __VA_ARGS__); \
if (ret_ != LZMA_OK) { \
lzma_end(strm); \
return ret_; \
} \
} while (0)
#endif

View File

@@ -1,165 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file copy_coder.c
/// \brief The Copy filter encoder and decoder
//
// Copyright (C) 2007 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "copy_coder.h"
struct lzma_coder_s {
lzma_next_coder next;
lzma_vli uncompressed_size;
};
#ifdef HAVE_ENCODER
static lzma_ret
copy_encode(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
// If we aren't the last filter in the chain, the Copy filter
// is totally useless. Note that it is job of the next coder to
// take care of Uncompressed Size, so we don't need to update our
// coder->uncompressed_size at all.
if (coder->next.code != NULL)
return coder->next.code(coder->next.coder, allocator,
in, in_pos, in_size, out, out_pos, out_size,
action);
// If we get here, we are the last filter in the chain.
assert(coder->uncompressed_size <= LZMA_VLI_VALUE_MAX);
const size_t in_avail = in_size - *in_pos;
// Check that we don't have too much input.
if ((lzma_vli)(in_avail) > coder->uncompressed_size)
return LZMA_DATA_ERROR;
// Check that once LZMA_FINISH has been given, the amount of input
// matches uncompressed_size, which is always known.
if (action == LZMA_FINISH
&& coder->uncompressed_size != (lzma_vli)(in_avail))
return LZMA_DATA_ERROR;
// We are the last coder in the chain.
// Just copy as much data as possible.
const size_t in_used = bufcpy(
in, in_pos, in_size, out, out_pos, out_size);
// Update uncompressed_size if it is known.
if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
coder->uncompressed_size -= in_used;
// LZMA_SYNC_FLUSH and LZMA_FINISH are the same thing for us.
if ((action != LZMA_RUN && *in_pos == in_size)
|| coder->uncompressed_size == 0)
return LZMA_STREAM_END;
return LZMA_OK;
}
#endif
#ifdef HAVE_DECODER
static lzma_ret
copy_decode(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
if (coder->next.code != NULL)
return coder->next.code(coder->next.coder, allocator,
in, in_pos, in_size, out, out_pos, out_size,
action);
assert(coder->uncompressed_size <= LZMA_VLI_VALUE_MAX);
const size_t in_avail = in_size - *in_pos;
// Limit in_size so that we don't copy too much.
if ((lzma_vli)(in_avail) > coder->uncompressed_size)
in_size = *in_pos + (size_t)(coder->uncompressed_size);
// We are the last coder in the chain.
// Just copy as much data as possible.
const size_t in_used = bufcpy(
in, in_pos, in_size, out, out_pos, out_size);
// Update uncompressed_size if it is known.
if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
coder->uncompressed_size -= in_used;
return coder->uncompressed_size == 0 ? LZMA_STREAM_END : LZMA_OK;
}
#endif
static void
copy_coder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_ret
copy_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters, lzma_code_function encode)
{
// Allocate memory for the decoder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
next->code = encode;
next->end = &copy_coder_end;
next->coder->next = LZMA_NEXT_CODER_INIT;
}
// Copy Uncompressed Size which is used to limit the output size.
next->coder->uncompressed_size = filters[0].uncompressed_size;
// Initialize the next decoder in the chain, if any.
return lzma_next_filter_init(
&next->coder->next, allocator, filters + 1);
}
#ifdef HAVE_ENCODER
extern lzma_ret
lzma_copy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters)
{
lzma_next_coder_init(copy_coder_init, next, allocator, filters,
&copy_encode);
}
#endif
#ifdef HAVE_DECODER
extern lzma_ret
lzma_copy_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters)
{
lzma_next_coder_init(copy_coder_init, next, allocator, filters,
&copy_decode);
}
#endif

View File

@@ -1,204 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file delta_coder.c
/// \brief Encoder and decoder for the Delta filter
//
// Copyright (C) 2007 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "delta_coder.h"
struct lzma_coder_s {
/// Next coder in the chain
lzma_next_coder next;
/// Uncompressed size - This is needed when we are the last
/// filter in the chain.
lzma_vli uncompressed_size;
/// Delta distance
size_t distance;
/// True if we are encoding; false if decoding
bool is_encoder;
/// Position in history[]
uint8_t pos;
/// Buffer to hold history of the original data
uint8_t history[LZMA_DELTA_DISTANCE_MAX];
};
static void
encode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size)
{
const size_t distance = coder->distance;
for (size_t i = 0; i < size; ++i) {
const uint8_t tmp = coder->history[
(distance + coder->pos) & 0xFF];
coder->history[coder->pos--] = buffer[i];
buffer[i] -= tmp;
}
return;
}
static void
decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size)
{
const size_t distance = coder->distance;
for (size_t i = 0; i < size; ++i) {
buffer[i] += coder->history[(distance + coder->pos) & 0xFF];
coder->history[coder->pos--] = buffer[i];
}
return;
}
static lzma_ret
delta_code(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
const size_t out_start = *out_pos;
size_t size;
lzma_ret ret;
if (coder->next.code == NULL) {
const size_t in_avail = in_size - *in_pos;
if (coder->is_encoder) {
// Check that we don't have too much input.
if ((lzma_vli)(in_avail) > coder->uncompressed_size)
return LZMA_DATA_ERROR;
// Check that once LZMA_FINISH has been given, the
// amount of input matches uncompressed_size if it
// is known.
if (action == LZMA_FINISH && coder->uncompressed_size
!= LZMA_VLI_VALUE_UNKNOWN
&& coder->uncompressed_size
!= (lzma_vli)(in_avail))
return LZMA_DATA_ERROR;
} else {
// Limit in_size so that we don't copy too much.
if ((lzma_vli)(in_avail) > coder->uncompressed_size)
in_size = *in_pos + (size_t)(
coder->uncompressed_size);
}
size = bufcpy(in, in_pos, in_size, out, out_pos, out_size);
if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
coder->uncompressed_size -= size;
// action can be LZMA_FINISH only in the encoder.
ret = (action == LZMA_FINISH && *in_pos == in_size)
|| coder->uncompressed_size == 0
? LZMA_STREAM_END : LZMA_OK;
} else {
ret = coder->next.code(coder->next.coder, allocator,
in, in_pos, in_size, out, out_pos, out_size,
action);
if (ret != LZMA_OK && ret != LZMA_STREAM_END)
return ret;
size = *out_pos - out_start;
}
if (coder->is_encoder)
encode_buffer(coder, out + out_start, size);
else
decode_buffer(coder, out + out_start, size);
return ret;
}
static void
delta_coder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_coder_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_ret
delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
// Allocate memory for the decoder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
next->code = &delta_code;
next->end = &delta_coder_end;
next->coder->next = LZMA_NEXT_CODER_INIT;
}
// Copy Uncompressed Size which is used to limit the output size.
next->coder->uncompressed_size = filters[0].uncompressed_size;
// The coder acts slightly differently as encoder and decoder.
next->coder->is_encoder = is_encoder;
// Set the delta distance.
if (filters[0].options == NULL)
return LZMA_PROG_ERROR;
next->coder->distance = ((lzma_options_delta *)(filters[0].options))
->distance;
if (next->coder->distance < LZMA_DELTA_DISTANCE_MIN
|| next->coder->distance > LZMA_DELTA_DISTANCE_MAX)
return LZMA_HEADER_ERROR;
// Initialize the rest of the variables.
next->coder->pos = 0;
memzero(next->coder->history, LZMA_DELTA_DISTANCE_MAX);
// Initialize the next decoder in the chain, if any.
return lzma_next_filter_init(&next->coder->next,
allocator, filters + 1);
}
#ifdef HAVE_ENCODER
extern lzma_ret
lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return delta_coder_init(next, allocator, filters, true);
}
#endif
#ifdef HAVE_DECODER
extern lzma_ret
lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return delta_coder_init(next, allocator, filters, false);
}
#endif

124
src/liblzma/common/easy.c Normal file
View File

@@ -0,0 +1,124 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file easy.c
/// \brief Easy Stream encoder initialization
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "stream_encoder.h"
struct lzma_coder_s {
lzma_next_coder stream_encoder;
/// We need to keep the filters array available in case
/// LZMA_FULL_FLUSH is used.
lzma_filter filters[5];
};
static bool
easy_set_filters(lzma_filter *filters, uint32_t level)
{
bool error = false;
if (level == 0) {
// TODO FIXME Use Subblock or LZMA2 with no compression.
error = true;
#ifdef HAVE_ENCODER_LZMA2
} else if (level <= 9) {
filters[0].id = LZMA_FILTER_LZMA2;
filters[0].options = (void *)(&lzma_preset_lzma[level - 1]);
filters[1].id = LZMA_VLI_VALUE_UNKNOWN;
#endif
} else {
error = true;
}
return error;
}
static lzma_ret
easy_encode(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size, lzma_action action)
{
return coder->stream_encoder.code(
coder->stream_encoder.coder, allocator,
in, in_pos, in_size, out, out_pos, out_size, action);
}
static void
easy_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_next_end(&coder->stream_encoder, allocator);
lzma_free(coder, allocator);
return;
}
static lzma_ret
easy_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_easy_level level)
{
lzma_next_coder_init(easy_encoder_init, next, allocator);
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
next->code = &easy_encode;
next->end = &easy_encoder_end;
next->coder->stream_encoder = LZMA_NEXT_CODER_INIT;
}
if (easy_set_filters(next->coder->filters, level))
return LZMA_HEADER_ERROR;
return lzma_stream_encoder_init(&next->coder->stream_encoder,
allocator, next->coder->filters, LZMA_CHECK_CRC32);
}
extern LZMA_API lzma_ret
lzma_easy_encoder(lzma_stream *strm, lzma_easy_level level)
{
lzma_next_strm_init(easy_encoder_init, strm, level);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}
extern LZMA_API uint64_t
lzma_easy_memory_usage(lzma_easy_level level)
{
lzma_filter filters[5];
if (easy_set_filters(filters, level))
return UINT32_MAX;
return lzma_memusage_encoder(filters);
}

View File

@@ -1,70 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file features.c
/// \brief Information about features enabled at compile time
//
// Copyright (C) 2007 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
static const lzma_vli filters[] = {
#ifdef HAVE_FILTER_COPY
LZMA_FILTER_COPY,
#endif
#ifdef HAVE_FILTER_SUBBLOCK
LZMA_FILTER_SUBBLOCK,
#endif
#ifdef HAVE_FILTER_X86
LZMA_FILTER_X86,
#endif
#ifdef HAVE_FILTER_POWERPC
LZMA_FILTER_POWERPC,
#endif
#ifdef HAVE_FILTER_IA64
LZMA_FILTER_IA64,
#endif
#ifdef HAVE_FILTER_ARM
LZMA_FILTER_ARM,
#endif
#ifdef HAVE_FILTER_ARMTHUMB
LZMA_FILTER_ARMTHUMB,
#endif
#ifdef HAVE_FILTER_SPARC
LZMA_FILTER_SPARC,
#endif
#ifdef HAVE_FILTER_DELTA
LZMA_FILTER_DELTA,
#endif
#ifdef HAVE_FILTER_LZMA
LZMA_FILTER_LZMA,
#endif
LZMA_VLI_VALUE_UNKNOWN
};
LZMA_API const lzma_vli *const lzma_available_filter_encoders = filters;
LZMA_API const lzma_vli *const lzma_available_filter_decoders = filters;

View File

@@ -0,0 +1,262 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_common.c
/// \brief Filter-specific stuff common for both encoder and decoder
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "filter_common.h"
static const struct {
/// Filter ID
lzma_vli id;
/// True if it is OK to use this filter as non-last filter in
/// the chain.
bool non_last_ok;
/// True if it is OK to use this filter as the last filter in
/// the chain.
bool last_ok;
/// True if the filter may change the size of the data (that is, the
/// amount of encoded output can be different than the amount of
/// uncompressed input).
bool changes_size;
} features[] = {
#if defined (HAVE_ENCODER_LZMA) || defined(HAVE_DECODER_LZMA)
{
.id = LZMA_FILTER_LZMA,
.non_last_ok = false,
.last_ok = true,
.changes_size = true,
},
#endif
#ifdef HAVE_DECODER_LZMA2
{
.id = LZMA_FILTER_LZMA2,
.non_last_ok = false,
.last_ok = true,
.changes_size = true,
},
#endif
#if defined(HAVE_ENCODER_SUBBLOCK) || defined(HAVE_DECODER_SUBBLOCK)
{
.id = LZMA_FILTER_SUBBLOCK,
.non_last_ok = true,
.last_ok = true,
.changes_size = true,
},
#endif
#ifdef HAVE_DECODER_X86
{
.id = LZMA_FILTER_X86,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
{
.id = LZMA_FILTER_POWERPC,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#ifdef HAVE_DECODER_IA64
{
.id = LZMA_FILTER_IA64,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
{
.id = LZMA_FILTER_ARM,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
{
.id = LZMA_FILTER_ARMTHUMB,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
{
.id = LZMA_FILTER_SPARC,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
{
.id = LZMA_FILTER_DELTA,
.non_last_ok = true,
.last_ok = false,
.changes_size = false,
},
#endif
{
.id = LZMA_VLI_VALUE_UNKNOWN
}
};
static lzma_ret
validate_chain(const lzma_filter *filters, size_t *count)
{
// There must be at least one filter.
if (filters == NULL || filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_PROG_ERROR;
// Number of non-last filters that may change the size of the data
// significantly (that is, more than 1-2 % or so).
size_t changes_size_count = 0;
// True if it is OK to add a new filter after the current filter.
bool non_last_ok = true;
// True if the last filter in the given chain is actually usable as
// the last filter. Only filters that support embedding End of Payload
// Marker can be used as the last filter in the chain.
bool last_ok = false;
size_t i = 0;
do {
size_t j;
for (j = 0; filters[i].id != features[j].id; ++j)
if (features[j].id == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_HEADER_ERROR;
// If the previous filter in the chain cannot be a non-last
// filter, the chain is invalid.
if (!non_last_ok)
return LZMA_HEADER_ERROR;
non_last_ok = features[j].non_last_ok;
last_ok = features[j].last_ok;
changes_size_count += features[j].changes_size;
} while (filters[++i].id != LZMA_VLI_VALUE_UNKNOWN);
// There must be 1-4 filters. The last filter must be usable as
// the last filter in the chain. At maximum of three filters are
// allowed to change the size of the data.
if (i > LZMA_BLOCK_FILTERS_MAX || !last_ok || changes_size_count > 3)
return LZMA_HEADER_ERROR;
*count = i;
return LZMA_OK;
}
extern lzma_ret
lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *options,
lzma_filter_find coder_find, bool is_encoder)
{
// Do some basic validation and get the number of filters.
size_t count;
return_if_error(validate_chain(options, &count));
// Set the filter functions and copy the options pointer.
lzma_filter_info filters[LZMA_BLOCK_FILTERS_MAX + 1];
if (is_encoder) {
for (size_t i = 0; i < count; ++i) {
// The order of the filters is reversed in the
// encoder. It allows more efficient handling
// of the uncompressed data.
const size_t j = count - i - 1;
const lzma_filter_coder *const fc
= coder_find(options[i].id);
if (fc == NULL || fc->init == NULL)
return LZMA_HEADER_ERROR;
filters[j].init = fc->init;
filters[j].options = options[i].options;
}
} else {
for (size_t i = 0; i < count; ++i) {
const lzma_filter_coder *const fc
= coder_find(options[i].id);
if (fc == NULL || fc->init == NULL)
return LZMA_HEADER_ERROR;
filters[i].init = fc->init;
filters[i].options = options[i].options;
}
}
// Terminate the array.
filters[count].init = NULL;
// Initialize the filters.
const lzma_ret ret = lzma_next_filter_init(next, allocator, filters);
if (ret != LZMA_OK)
lzma_next_end(next, allocator);
return ret;
}
extern uint64_t
lzma_memusage_coder(lzma_filter_find coder_find,
const lzma_filter *filters)
{
// The chain has to have at least one filter.
if (filters[0].id == LZMA_VLI_VALUE_UNKNOWN)
return UINT64_MAX;
uint64_t total = 0;
size_t i = 0;
do {
const lzma_filter_coder *const fc
= coder_find(filters[i].id);
if (fc == NULL)
return UINT64_MAX; // Unsupported Filter ID
if (fc->memusage == NULL) {
// This filter doesn't have a function to calculate
// the memory usage. Such filters need only little
// memory, so we use 1 KiB as a good estimate.
total += 1024;
} else {
// Call the filter-specific memory usage calculation
// function.
const uint64_t usage
= fc->memusage(filters[i].options);
if (usage == UINT64_MAX)
return UINT64_MAX; // Invalid options
total += usage;
}
} while (filters[++i].id != LZMA_VLI_VALUE_UNKNOWN);
// Add some fixed amount of extra. It's to compensate memory usage
// of Stream, Block etc. coders, malloc() overhead, stack etc.
return total + (1U << 15);
}

View File

@@ -0,0 +1,55 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_common.c
/// \brief Filter-specific stuff common for both encoder and decoder
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_FILTER_COMMON_H
#define LZMA_FILTER_COMMON_H
#include "common.h"
/// Both lzma_filter_encoder and lzma_filter_decoder begin with these members.
typedef struct {
/// Filter ID
lzma_vli id;
/// Initializes the filter encoder and calls lzma_next_filter_init()
/// for filters + 1.
lzma_init_function init;
/// Calculates memory usage of the encoder. If the options are
/// invalid, UINT64_MAX is returned.
uint64_t (*memusage)(const void *options);
} lzma_filter_coder;
typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id);
extern lzma_ret lzma_raw_coder_init(
lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *filters,
lzma_filter_find coder_find, bool is_encoder);
extern uint64_t lzma_memusage_coder(lzma_filter_find coder_find,
const lzma_filter *filters);
#endif

View File

@@ -0,0 +1,206 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_decoder.c
/// \brief Filter ID mapping to filter-specific functions
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "filter_decoder.h"
#include "filter_common.h"
#include "lzma_decoder.h"
#include "lzma2_decoder.h"
#include "subblock_decoder.h"
#include "subblock_decoder_helper.h"
#include "simple_decoder.h"
#include "delta_decoder.h"
typedef struct {
/// Filter ID
lzma_vli id;
/// Initializes the filter encoder and calls lzma_next_filter_init()
/// for filters + 1.
lzma_init_function init;
/// Calculates memory usage of the encoder. If the options are
/// invalid, UINT64_MAX is returned.
uint64_t (*memusage)(const void *options);
/// Decodes Filter Properties.
///
/// \return - LZMA_OK: Properties decoded successfully.
/// - LZMA_HEADER_ERROR: Unsupported properties
/// - LZMA_MEM_ERROR: Memory allocation failed.
lzma_ret (*props_decode)(void **options, lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
} lzma_filter_decoder;
static const lzma_filter_decoder decoders[] = {
#ifdef HAVE_DECODER_LZMA
{
.id = LZMA_FILTER_LZMA,
.init = &lzma_lzma_decoder_init,
.memusage = &lzma_lzma_decoder_memusage,
.props_decode = &lzma_lzma_props_decode,
},
#endif
#ifdef HAVE_DECODER_LZMA2
{
.id = LZMA_FILTER_LZMA2,
.init = &lzma_lzma2_decoder_init,
.memusage = &lzma_lzma2_decoder_memusage,
.props_decode = &lzma_lzma2_props_decode,
},
#endif
#ifdef HAVE_DECODER_SUBBLOCK
{
.id = LZMA_FILTER_SUBBLOCK,
.init = &lzma_subblock_decoder_init,
// .memusage = &lzma_subblock_decoder_memusage,
.props_decode = NULL,
},
{
.id = LZMA_FILTER_SUBBLOCK_HELPER,
.init = &lzma_subblock_decoder_helper_init,
.memusage = NULL,
.props_decode = NULL,
},
#endif
#ifdef HAVE_DECODER_X86
{
.id = LZMA_FILTER_X86,
.init = &lzma_simple_x86_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_POWERPC
{
.id = LZMA_FILTER_POWERPC,
.init = &lzma_simple_powerpc_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_IA64
{
.id = LZMA_FILTER_IA64,
.init = &lzma_simple_ia64_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_ARM
{
.id = LZMA_FILTER_ARM,
.init = &lzma_simple_arm_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_ARMTHUMB
{
.id = LZMA_FILTER_ARMTHUMB,
.init = &lzma_simple_armthumb_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_SPARC
{
.id = LZMA_FILTER_SPARC,
.init = &lzma_simple_sparc_decoder_init,
.memusage = NULL,
.props_decode = &lzma_simple_props_decode,
},
#endif
#ifdef HAVE_DECODER_DELTA
{
.id = LZMA_FILTER_DELTA,
.init = &lzma_delta_decoder_init,
.memusage = NULL,
.props_decode = &lzma_delta_props_decode,
},
#endif
};
static const lzma_filter_decoder *
decoder_find(lzma_vli id)
{
for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i)
if (decoders[i].id == id)
return decoders + i;
return NULL;
}
extern LZMA_API lzma_bool
lzma_filter_decoder_is_supported(lzma_vli id)
{
return decoder_find(id) != NULL;
}
extern lzma_ret
lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *options)
{
return lzma_raw_coder_init(next, allocator,
options, (lzma_filter_find)(&decoder_find), false);
}
extern LZMA_API lzma_ret
lzma_raw_decoder(lzma_stream *strm, const lzma_filter *options)
{
lzma_next_strm_init(lzma_raw_decoder_init, strm, options);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}
extern LZMA_API uint64_t
lzma_memusage_decoder(const lzma_filter *filters)
{
return lzma_memusage_coder(
(lzma_filter_find)(&decoder_find), filters);
}
extern LZMA_API lzma_ret
lzma_properties_decode(lzma_filter *filter, lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
// Make it always NULL so that the caller can always safely free() it.
filter->options = NULL;
const lzma_filter_decoder *const fd = decoder_find(filter->id);
if (fd == NULL)
return LZMA_HEADER_ERROR;
if (fd->props_decode == NULL)
return props_size == 0 ? LZMA_OK : LZMA_HEADER_ERROR;
return fd->props_decode(
&filter->options, allocator, props, props_size);
}

View File

@@ -1,9 +1,9 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file metadata_encoder.h
/// \brief Encodes metadata to be stored into Metadata Blocks
/// \file filter_decoder.c
/// \brief Filter ID mapping to filter-specific functions
//
// Copyright (C) 2007 Lasse Collin
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -17,14 +17,14 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_METADATA_ENCODER_H
#define LZMA_METADATA_ENCODER_H
#ifndef LZMA_FILTER_DECODER_H
#define LZMA_FILTER_DECODER_H
#include "common.h"
extern lzma_ret lzma_metadata_encoder_init(
extern lzma_ret lzma_raw_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_options_block *options, const lzma_metadata *metadata);
const lzma_filter *options);
#endif

View File

@@ -0,0 +1,278 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_decoder.c
/// \brief Filter ID mapping to filter-specific functions
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#include "filter_encoder.h"
#include "filter_common.h"
#include "lzma_encoder.h"
#include "lzma2_encoder.h"
#include "subblock_encoder.h"
#include "simple_encoder.h"
#include "delta_encoder.h"
typedef struct {
/// Filter ID
lzma_vli id;
/// Initializes the filter encoder and calls lzma_next_filter_init()
/// for filters + 1.
lzma_init_function init;
/// Calculates memory usage of the encoder. If the options are
/// invalid, UINT64_MAX is returned.
uint64_t (*memusage)(const void *options);
/// Calculates the minimum sane size for Blocks (or other types of
/// chunks) to which the input data can be splitted to make
/// multithreaded encoding possible. If this is NULL, it is assumed
/// that the encoder is fast enough with single thread.
lzma_vli (*chunk_size)(const void *options);
/// Tells the size of the Filter Properties field. If options are
/// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed
/// is used.
lzma_ret (*props_size_get)(uint32_t *size, const void *options);
uint32_t props_size_fixed;
/// Encodes Filter Properties.
///
/// \return - LZMA_OK: Properties encoded sucessfully.
/// - LZMA_HEADER_ERROR: Unsupported options
/// - LZMA_PROG_ERROR: Invalid options or not enough
/// output space
lzma_ret (*props_encode)(const void *options, uint8_t *out);
} lzma_filter_encoder;
static const lzma_filter_encoder encoders[] = {
#ifdef HAVE_ENCODER_LZMA
{
.id = LZMA_FILTER_LZMA,
.init = &lzma_lzma_encoder_init,
.memusage = &lzma_lzma_encoder_memusage,
.chunk_size = NULL, // FIXME
.props_size_get = NULL,
.props_size_fixed = 5,
.props_encode = &lzma_lzma_props_encode,
},
#endif
#ifdef HAVE_ENCODER_LZMA2
{
.id = LZMA_FILTER_LZMA2,
.init = &lzma_lzma2_encoder_init,
.memusage = &lzma_lzma2_encoder_memusage,
.chunk_size = NULL, // FIXME
.props_size_get = NULL,
.props_size_fixed = 1,
.props_encode = &lzma_lzma2_props_encode,
},
#endif
#ifdef HAVE_ENCODER_SUBBLOCK
{
.id = LZMA_FILTER_SUBBLOCK,
.init = &lzma_subblock_encoder_init,
// .memusage = &lzma_subblock_encoder_memusage,
.chunk_size = NULL,
.props_size_get = NULL,
.props_size_fixed = 0,
.props_encode = NULL,
},
#endif
#ifdef HAVE_ENCODER_X86
{
.id = LZMA_FILTER_X86,
.init = &lzma_simple_x86_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_POWERPC
{
.id = LZMA_FILTER_POWERPC,
.init = &lzma_simple_powerpc_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_IA64
{
.id = LZMA_FILTER_IA64,
.init = &lzma_simple_ia64_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_ARM
{
.id = LZMA_FILTER_ARM,
.init = &lzma_simple_arm_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_ARMTHUMB
{
.id = LZMA_FILTER_ARMTHUMB,
.init = &lzma_simple_armthumb_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_SPARC
{
.id = LZMA_FILTER_SPARC,
.init = &lzma_simple_sparc_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
#endif
#ifdef HAVE_ENCODER_DELTA
{
.id = LZMA_FILTER_DELTA,
.init = &lzma_delta_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.props_size_get = NULL,
.props_size_fixed = 1,
.props_encode = &lzma_delta_props_encode,
},
#endif
};
static const lzma_filter_encoder *
encoder_find(lzma_vli id)
{
for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
if (encoders[i].id == id)
return encoders + i;
return NULL;
}
extern LZMA_API lzma_bool
lzma_filter_encoder_is_supported(lzma_vli id)
{
return encoder_find(id) != NULL;
}
extern lzma_ret
lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *options)
{
return lzma_raw_coder_init(next, allocator,
options, (lzma_filter_find)(&encoder_find), true);
}
extern LZMA_API lzma_ret
lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options)
{
lzma_next_strm_init(lzma_raw_coder_init, strm, options,
(lzma_filter_find)(&encoder_find), true);
strm->internal->supported_actions[LZMA_RUN] = true;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;
}
extern LZMA_API uint64_t
lzma_memusage_encoder(const lzma_filter *filters)
{
return lzma_memusage_coder(
(lzma_filter_find)(&encoder_find), filters);
}
extern LZMA_API lzma_vli
lzma_chunk_size(const lzma_filter *filters)
{
lzma_vli max = 0;
for (size_t i = 0; filters[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
const lzma_filter_encoder *const fe
= encoder_find(filters[i].id);
if (fe->chunk_size != NULL) {
const lzma_vli size
= fe->chunk_size(filters[i].options);
if (size == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_VLI_VALUE_UNKNOWN;
if (size > max)
max = size;
}
}
return max;
}
extern LZMA_API lzma_ret
lzma_properties_size(uint32_t *size, const lzma_filter *filter)
{
const lzma_filter_encoder *const fe = encoder_find(filter->id);
if (fe == NULL) {
// Unknown filter - if the Filter ID is a proper VLI,
// return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
// because it's possible that we just don't have support
// compiled in for the requested filter.
return filter->id <= LZMA_VLI_VALUE_MAX
? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
}
if (fe->props_size_get == NULL) {
// No props_size_get() function, use props_size_fixed.
*size = fe->props_size_fixed;
return LZMA_OK;
}
return fe->props_size_get(size, filter->options);
}
extern LZMA_API lzma_ret
lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
{
const lzma_filter_encoder *const fe = encoder_find(filter->id);
if (fe == NULL)
return LZMA_PROG_ERROR;
if (fe->props_encode == NULL)
return LZMA_OK;
return fe->props_encode(filter->options, props);
}

View File

@@ -0,0 +1,34 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file filter_encoder.c
/// \brief Filter ID mapping to filter-specific functions
//
// Copyright (C) 2008 Lasse Collin
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_FILTER_ENCODER_H
#define LZMA_FILTER_ENCODER_H
#include "common.h"
// FIXME !!! Public API
extern lzma_vli lzma_chunk_size(const lzma_filter *filters);
extern lzma_ret lzma_raw_encoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *options);
#endif

View File

@@ -17,366 +17,37 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "lzma_decoder.h"
struct lzma_coder_s {
lzma_options_filter *options;
enum {
SEQ_MISC,
SEQ_ID,
SEQ_SIZE,
SEQ_PROPERTIES,
} sequence;
/// \brief Position in variable-length integers
size_t pos;
/// \brief Size of Filter Properties
lzma_vli properties_size;
};
#ifdef HAVE_FILTER_SUBBLOCK
static lzma_ret
properties_subblock(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *in lzma_attribute((unused)),
size_t *in_pos lzma_attribute((unused)),
size_t in_size lzma_attribute((unused)))
{
if (coder->properties_size != 0)
return LZMA_HEADER_ERROR;
coder->options->options = lzma_alloc(
sizeof(lzma_options_subblock), allocator);
if (coder->options->options == NULL)
return LZMA_MEM_ERROR;
((lzma_options_subblock *)(coder->options->options))
->allow_subfilters = true;
return LZMA_STREAM_END;
}
#endif
#ifdef HAVE_FILTER_SIMPLE
static lzma_ret
properties_simple(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
if (coder->properties_size == 0)
return LZMA_STREAM_END;
if (coder->properties_size != 4)
return LZMA_HEADER_ERROR;
lzma_options_simple *options = coder->options->options;
if (options == NULL) {
options = lzma_alloc(sizeof(lzma_options_simple), allocator);
if (options == NULL)
return LZMA_MEM_ERROR;
options->start_offset = 0;
coder->options->options = options;
}
while (coder->pos < 4) {
if (*in_pos == in_size)
return LZMA_OK;
options->start_offset
|= (uint32_t)(in[*in_pos]) << (8 * coder->pos);
++*in_pos;
++coder->pos;
}
// Don't leave an options structure allocated if start_offset is zero.
if (options->start_offset == 0) {
lzma_free(options, allocator);
coder->options->options = NULL;
}
return LZMA_STREAM_END;
}
#endif
#ifdef HAVE_FILTER_DELTA
static lzma_ret
properties_delta(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
if (coder->properties_size != 1)
return LZMA_HEADER_ERROR;
if (*in_pos == in_size)
return LZMA_OK;
lzma_options_delta *options = lzma_alloc(
sizeof(lzma_options_delta), allocator);
if (options == NULL)
return LZMA_MEM_ERROR;
coder->options->options = options;
options->distance = (uint32_t)(in[*in_pos]) + 1;
++*in_pos;
return LZMA_STREAM_END;
}
#endif
#ifdef HAVE_FILTER_LZMA
static lzma_ret
properties_lzma(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
// LZMA properties are always two bytes (at least for now).
if (coder->properties_size != 2)
return LZMA_HEADER_ERROR;
assert(coder->pos < 2);
while (*in_pos < in_size) {
switch (coder->pos) {
case 0:
// Allocate the options structure.
coder->options->options = lzma_alloc(
sizeof(lzma_options_lzma), allocator);
if (coder->options->options == NULL)
return LZMA_MEM_ERROR;
// Decode lc, lp, and pb.
if (lzma_lzma_decode_properties(
coder->options->options, in[*in_pos]))
return LZMA_HEADER_ERROR;
++*in_pos;
++coder->pos;
break;
case 1: {
lzma_options_lzma *options = coder->options->options;
// Check that reserved bits are unset.
if (in[*in_pos] & 0xC0)
return LZMA_HEADER_ERROR;
// Decode the dictionary size. See the file format
// specification section 4.3.4.2 to understand this.
if (in[*in_pos] == 0) {
options->dictionary_size = 1;
} else if (in[*in_pos] > 59) {
// Dictionary size is over 1 GiB.
// It's not supported at the moment.
return LZMA_HEADER_ERROR;
# if LZMA_DICTIONARY_SIZE_MAX != UINT32_C(1) << 30
# error Update the if()-condition a few lines
# error above to match LZMA_DICTIONARY_SIZE_MAX.
# endif
} else {
options->dictionary_size
= 2 | ((in[*in_pos] + 1) & 1);
options->dictionary_size
<<= (in[*in_pos] - 1) / 2;
}
++*in_pos;
return LZMA_STREAM_END;
}
}
}
assert(coder->pos < 2);
return LZMA_OK;
}
#endif
static lzma_ret
filter_flags_decode(lzma_coder *coder, lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
size_t *restrict out_pos lzma_attribute((unused)),
size_t out_size lzma_attribute((unused)),
lzma_action action lzma_attribute((unused)))
{
while (*in_pos < in_size || coder->sequence == SEQ_PROPERTIES)
switch (coder->sequence) {
case SEQ_MISC:
// Determine the Filter ID and Size of Filter Properties.
if (in[*in_pos] >= 0xE0) {
// Using External ID. Prepare the ID
// for variable-length integer parsing.
coder->options->id = 0;
if (in[*in_pos] == 0xFF) {
// Mark that Size of Filter Properties is
// unknown, so we know later that there is
// external Size of Filter Properties present.
coder->properties_size
= LZMA_VLI_VALUE_UNKNOWN;
} else {
// Take Size of Filter Properties from Misc.
coder->properties_size = in[*in_pos] - 0xE0;
}
coder->sequence = SEQ_ID;
} else {
// The Filter ID is the same as Misc.
coder->options->id = in[*in_pos];
// The Size of Filter Properties can be calculated
// from Misc too.
coder->properties_size = in[*in_pos] / 0x20;
coder->sequence = SEQ_PROPERTIES;
}
++*in_pos;
break;
case SEQ_ID: {
const lzma_ret ret = lzma_vli_decode(&coder->options->id,
&coder->pos, in, in_pos, in_size);
if (ret != LZMA_STREAM_END)
return ret;
if (coder->properties_size == LZMA_VLI_VALUE_UNKNOWN) {
// We have also external Size of Filter
// Properties. Prepare the size for
// variable-length integer parsing.
coder->properties_size = 0;
coder->sequence = SEQ_SIZE;
} else {
coder->sequence = SEQ_PROPERTIES;
}
// Reset pos for its next job.
coder->pos = 0;
break;
}
case SEQ_SIZE: {
const lzma_ret ret = lzma_vli_decode(&coder->properties_size,
&coder->pos, in, in_pos, in_size);
if (ret != LZMA_STREAM_END)
return ret;
coder->pos = 0;
coder->sequence = SEQ_PROPERTIES;
break;
}
case SEQ_PROPERTIES: {
lzma_ret (*get_properties)(lzma_coder *coder,
lzma_allocator *allocator, const uint8_t *in,
size_t *in_pos, size_t in_size);
switch (coder->options->id) {
#ifdef HAVE_FILTER_COPY
case LZMA_FILTER_COPY:
return coder->properties_size > 0
? LZMA_HEADER_ERROR : LZMA_STREAM_END;
#endif
#ifdef HAVE_FILTER_SUBBLOCK
case LZMA_FILTER_SUBBLOCK:
get_properties = &properties_subblock;
break;
#endif
#ifdef HAVE_FILTER_SIMPLE
# ifdef HAVE_FILTER_X86
case LZMA_FILTER_X86:
# endif
# ifdef HAVE_FILTER_POWERPC
case LZMA_FILTER_POWERPC:
# endif
# ifdef HAVE_FILTER_IA64
case LZMA_FILTER_IA64:
# endif
# ifdef HAVE_FILTER_ARM
case LZMA_FILTER_ARM:
# endif
# ifdef HAVE_FILTER_ARMTHUMB
case LZMA_FILTER_ARMTHUMB:
# endif
# ifdef HAVE_FILTER_SPARC
case LZMA_FILTER_SPARC:
# endif
get_properties = &properties_simple;
break;
#endif
#ifdef HAVE_FILTER_DELTA
case LZMA_FILTER_DELTA:
get_properties = &properties_delta;
break;
#endif
#ifdef HAVE_FILTER_LZMA
case LZMA_FILTER_LZMA:
get_properties = &properties_lzma;
break;
#endif
default:
return LZMA_HEADER_ERROR;
}
return get_properties(coder, allocator, in, in_pos, in_size);
}
default:
return LZMA_PROG_ERROR;
}
return LZMA_OK;
}
static void
filter_flags_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
{
lzma_free(coder, allocator);
return;
}
extern lzma_ret
lzma_filter_flags_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_options_filter *options)
{
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
next->code = &filter_flags_decode;
next->end = &filter_flags_decoder_end;
}
options->id = 0;
options->options = NULL;
next->coder->options = options;
next->coder->sequence = SEQ_MISC;
next->coder->pos = 0;
next->coder->properties_size = 0;
return LZMA_OK;
}
#include "filter_decoder.h"
extern LZMA_API lzma_ret
lzma_filter_flags_decoder(lzma_stream *strm, lzma_options_filter *options)
lzma_filter_flags_decode(
lzma_filter *filter, lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
lzma_next_strm_init(strm, lzma_filter_flags_decoder_init, options);
// Set the pointer to NULL so the caller can always safely free it.
filter->options = NULL;
strm->internal->supported_actions[LZMA_RUN] = true;
// Filter ID
return_if_error(lzma_vli_decode(&filter->id, NULL,
in, in_pos, in_size));
return LZMA_OK;
if (filter->id >= LZMA_FILTER_RESERVED_START)
return LZMA_DATA_ERROR;
// Size of Properties
lzma_vli props_size;
return_if_error(lzma_vli_decode(&props_size, NULL,
in, in_pos, in_size));
// Filter Properties
if (in_size - *in_pos < props_size)
return LZMA_DATA_ERROR;
const lzma_ret ret = lzma_properties_decode(
filter, allocator, in + *in_pos, props_size);
*in_pos += props_size;
return ret;
}

View File

@@ -17,343 +17,47 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "lzma_encoder.h"
#include "filter_encoder.h"
/// \brief Calculates the size of the Filter Properties field
///
/// This currently can return only LZMA_OK or LZMA_HEADER_ERROR, but
/// with some new filters it may return also LZMA_PROG_ERROR.
static lzma_ret
get_properties_size(uint32_t *size, const lzma_options_filter *options)
extern LZMA_API lzma_ret
lzma_filter_flags_size(uint32_t *size, const lzma_filter *filter)
{
lzma_ret ret = LZMA_OK;
if (filter->id >= LZMA_FILTER_RESERVED_START)
return LZMA_PROG_ERROR;
switch (options->id) {
#ifdef HAVE_FILTER_COPY
case LZMA_FILTER_COPY:
*size = 0;
break;
#endif
return_if_error(lzma_properties_size(size, filter));
#ifdef HAVE_FILTER_SUBBLOCK
case LZMA_FILTER_SUBBLOCK:
*size = 0;
break;
#endif
*size += lzma_vli_size(filter->id) + lzma_vli_size(*size);
#ifdef HAVE_FILTER_SIMPLE
# ifdef HAVE_FILTER_X86
case LZMA_FILTER_X86:
# endif
# ifdef HAVE_FILTER_POWERPC
case LZMA_FILTER_POWERPC:
# endif
# ifdef HAVE_FILTER_IA64
case LZMA_FILTER_IA64:
# endif
# ifdef HAVE_FILTER_ARM
case LZMA_FILTER_ARM:
# endif
# ifdef HAVE_FILTER_ARMTHUMB
case LZMA_FILTER_ARMTHUMB:
# endif
# ifdef HAVE_FILTER_SPARC
case LZMA_FILTER_SPARC:
# endif
if (options->options == NULL || ((const lzma_options_simple *)(
options->options))->start_offset == 0)
*size = 0;
else
*size = 4;
break;
#endif
#ifdef HAVE_FILTER_DELTA
case LZMA_FILTER_DELTA:
*size = 1;
break;
#endif
#ifdef HAVE_FILTER_LZMA
case LZMA_FILTER_LZMA:
*size = 2;
break;
#endif
default:
// Unknown filter - if the Filter ID is a proper VLI,
// return LZMA_HEADER_ERROR instead of LZMA_PROG_ERROR,
// because it's possible that we just don't have support
// compiled in for the requested filter.
ret = options->id <= LZMA_VLI_VALUE_MAX
? LZMA_HEADER_ERROR : LZMA_PROG_ERROR;
break;
}
return ret;
return LZMA_OK;
}
extern LZMA_API lzma_ret
lzma_filter_flags_size(uint32_t *size, const lzma_options_filter *options)
lzma_filter_flags_encode(const lzma_filter *filter,
uint8_t *out, size_t *out_pos, size_t out_size)
{
// Get size of Filter Properties.
uint32_t prop_size;
const lzma_ret ret = get_properties_size(&prop_size, options);
if (ret != LZMA_OK)
return ret;
// Size of Filter ID field if it exists.
size_t id_size;
size_t prop_size_size;
if (options->id < 0xE0
&& (lzma_vli)(prop_size) == options->id / 0x20) {
// ID and Size of Filter Properties fit into Misc.
id_size = 0;
prop_size_size = 0;
} else {
// At least Filter ID is stored using the External ID field.
id_size = lzma_vli_size(options->id);
if (id_size == 0)
return LZMA_PROG_ERROR;
if (prop_size <= 30) {
// Size of Filter Properties fits into Misc still.
prop_size_size = 0;
} else {
// The Size of Filter Properties field is used too.
prop_size_size = lzma_vli_size(prop_size);
if (prop_size_size == 0)
return LZMA_PROG_ERROR;
}
}
// 1 is for the Misc field.
*size = 1 + id_size + prop_size_size + prop_size;
return LZMA_OK;
}
#ifdef HAVE_FILTER_SIMPLE
/// Encodes Filter Properties of the so called simple filters
static lzma_ret
properties_simple(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_simple *options)
{
if (options == NULL || options->start_offset == 0)
return LZMA_OK;
if (out_size - *out_pos < 4)
return LZMA_BUF_ERROR;
for (size_t i = 0; i < 4; ++i)
out[(*out_pos)++] = options->start_offset >> (i * 8);
return LZMA_OK;
}
#endif
#ifdef HAVE_FILTER_DELTA
/// Encodes Filter Properties of the Delta filter
static lzma_ret
properties_delta(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_delta *options)
{
if (options == NULL)
// Filter ID
if (filter->id >= LZMA_FILTER_RESERVED_START)
return LZMA_PROG_ERROR;
// It's possible that newer liblzma versions will support larger
// distance values.
if (options->distance < LZMA_DELTA_DISTANCE_MIN
|| options->distance > LZMA_DELTA_DISTANCE_MAX)
return LZMA_HEADER_ERROR;
return_if_error(lzma_vli_encode(filter->id, NULL,
out, out_pos, out_size));
if (out_size - *out_pos < 1)
return LZMA_BUF_ERROR;
out[*out_pos] = options->distance - LZMA_DELTA_DISTANCE_MIN;
++*out_pos;
return LZMA_OK;
}
#endif
#ifdef HAVE_FILTER_LZMA
/// Encodes LZMA Properties and Dictionary Flags (two bytes)
static lzma_ret
properties_lzma(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_lzma *options)
{
if (options == NULL)
return LZMA_PROG_ERROR;
if (out_size - *out_pos < 2)
return LZMA_BUF_ERROR;
// LZMA Properties
if (lzma_lzma_encode_properties(options, out + *out_pos))
return LZMA_HEADER_ERROR;
++*out_pos;
// Dictionary flags
//
// Dictionary size is encoded using six bits of
// which one is mantissa and five are exponent.
//
// There are some limits that must hold to keep
// this coding working.
# if LZMA_DICTIONARY_SIZE_MAX > UINT32_MAX / 2
# error LZMA_DICTIONARY_SIZE_MAX is too big.
# endif
# if LZMA_DICTIONARY_SIZE_MIN < 1
# error LZMA_DICTIONARY_SIZE_MIN cannot be zero.
# endif
// Validate it:
if (options->dictionary_size < LZMA_DICTIONARY_SIZE_MIN
|| options->dictionary_size > LZMA_DICTIONARY_SIZE_MAX)
return LZMA_HEADER_ERROR;
if (options->dictionary_size == 1) {
// Special case
out[*out_pos] = 0x00;
} else {
// TODO This could be more elegant.
uint32_t i = 1;
while (((2 | ((i + 1) & 1)) << ((i - 1) / 2))
< options->dictionary_size)
++i;
out[*out_pos] = i;
}
++*out_pos;
return LZMA_OK;
}
#endif
extern LZMA_API lzma_ret
lzma_filter_flags_encode(uint8_t *out, size_t *out_pos, size_t out_size,
const lzma_options_filter *options)
{
// Minimum output is one byte (everything fits into Misc).
// The caller should have checked that there is enough output space,
// so we return LZMA_PROG_ERROR instead of LZMA_BUF_ERROR.
if (*out_pos >= out_size)
return LZMA_PROG_ERROR;
// Get size of Filter Properties.
uint32_t prop_size;
lzma_ret ret = get_properties_size(&prop_size, options);
if (ret != LZMA_OK)
return ret;
// Misc, External ID, and Size of Properties
if (options->id < 0xE0
&& (lzma_vli)(prop_size) == options->id / 0x20) {
// ID and Size of Filter Properties fit into Misc.
out[*out_pos] = options->id;
++*out_pos;
} else if (prop_size <= 30) {
// Size of Filter Properties fits into Misc.
out[*out_pos] = prop_size + 0xE0;
++*out_pos;
// External ID is used to encode the Filter ID. If encoding
// the VLI fails, it's because the caller has given as too
// little output space, which it should have checked already.
// So return LZMA_PROG_ERROR, not LZMA_BUF_ERROR.
size_t dummy = 0;
if (lzma_vli_encode(options->id, &dummy, 1,
out, out_pos, out_size) != LZMA_STREAM_END)
return LZMA_PROG_ERROR;
} else {
// Nothing fits into Misc.
out[*out_pos] = 0xFF;
++*out_pos;
// External ID is used to encode the Filter ID.
size_t dummy = 0;
if (lzma_vli_encode(options->id, &dummy, 1,
out, out_pos, out_size) != LZMA_STREAM_END)
return LZMA_PROG_ERROR;
// External Size of Filter Properties
dummy = 0;
if (lzma_vli_encode(prop_size, &dummy, 1,
out, out_pos, out_size) != LZMA_STREAM_END)
return LZMA_PROG_ERROR;
}
// Size of Properties
uint32_t props_size;
return_if_error(lzma_properties_size(&props_size, filter));
return_if_error(lzma_vli_encode(props_size, NULL,
out, out_pos, out_size));
// Filter Properties
switch (options->id) {
#ifdef HAVE_FILTER_COPY
case LZMA_FILTER_COPY:
assert(prop_size == 0);
ret = options->options == NULL ? LZMA_OK : LZMA_HEADER_ERROR;
break;
#endif
if (out_size - *out_pos < props_size)
return LZMA_PROG_ERROR;
#ifdef HAVE_FILTER_SUBBLOCK
case LZMA_FILTER_SUBBLOCK:
assert(prop_size == 0);
ret = LZMA_OK;
break;
#endif
return_if_error(lzma_properties_encode(filter, out + *out_pos));
#ifdef HAVE_FILTER_SIMPLE
# ifdef HAVE_FILTER_X86
case LZMA_FILTER_X86:
# endif
# ifdef HAVE_FILTER_POWERPC
case LZMA_FILTER_POWERPC:
# endif
# ifdef HAVE_FILTER_IA64
case LZMA_FILTER_IA64:
# endif
# ifdef HAVE_FILTER_ARM
case LZMA_FILTER_ARM:
# endif
# ifdef HAVE_FILTER_ARMTHUMB
case LZMA_FILTER_ARMTHUMB:
# endif
# ifdef HAVE_FILTER_SPARC
case LZMA_FILTER_SPARC:
# endif
ret = properties_simple(out, out_pos, out_size,
options->options);
break;
#endif
*out_pos += props_size;
#ifdef HAVE_FILTER_DELTA
case LZMA_FILTER_DELTA:
ret = properties_delta(out, out_pos, out_size,
options->options);
break;
#endif
#ifdef HAVE_FILTER_LZMA
case LZMA_FILTER_LZMA:
ret = properties_lzma(out, out_pos, out_size,
options->options);
break;
#endif
default:
assert(0);
ret = LZMA_PROG_ERROR;
break;
}
return ret;
return LZMA_OK;
}

View File

@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file index.c
/// \brief Handling of Index in Metadata
/// \brief Handling of Index
//
// Copyright (C) 2007 Lasse Collin
//
@@ -17,124 +17,733 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "index.h"
/**
* \brief Duplicates an Index list
*
* \return A copy of the Index list, or NULL if memory allocation
* failed or the original Index was empty.
*/
extern LZMA_API lzma_index *
lzma_index_dup(const lzma_index *old_current, lzma_allocator *allocator)
/// Number of Records to allocate at once.
#define INDEX_GROUP_SIZE 256
typedef struct lzma_index_group_s lzma_index_group;
struct lzma_index_group_s {
/// Next group
lzma_index_group *prev;
/// Previous group
lzma_index_group *next;
/// Index of the last Record in this group
size_t last;
/// Total Size fields as cumulative sum relative to the beginning
/// of the group. The total size of the group is total_sums[last].
lzma_vli total_sums[INDEX_GROUP_SIZE];
/// Uncompressed Size fields as cumulative sum relative to the
/// beginning of the group. The uncompressed size of the group is
/// uncompressed_sums[last].
lzma_vli uncompressed_sums[INDEX_GROUP_SIZE];
/// True if the Record is padding
bool paddings[INDEX_GROUP_SIZE];
};
struct lzma_index_s {
/// Total size of the Blocks and padding
lzma_vli total_size;
/// Uncompressed size of the Stream
lzma_vli uncompressed_size;
/// Number of non-padding records. This is needed by Index encoder.
lzma_vli count;
/// Size of the List of Records field; this is updated every time
/// a new non-padding Record is added.
lzma_vli index_list_size;
/// This is zero if no Indexes have been combined with
/// lzma_index_cat(). With combined Indexes, this contains the sizes
/// of all but latest the Streams, including possible Stream Padding
/// fields.
lzma_vli padding_size;
/// First group of Records
lzma_index_group *head;
/// Last group of Records
lzma_index_group *tail;
/// Tracking the read position
struct {
/// Group where the current read position is.
lzma_index_group *group;
/// The most recently read record in *group
lzma_vli record;
/// Uncompressed offset of the beginning of *group relative
/// to the beginning of the Stream
lzma_vli uncompressed_offset;
/// Compressed offset of the beginning of *group relative
/// to the beginning of the Stream
lzma_vli stream_offset;
} current;
/// Information about earlier Indexes when multiple Indexes have
/// been combined.
struct {
/// Sum of the Record counts of the all but the last Stream.
lzma_vli count;
/// Sum of the List of Records fields of all but the last
/// Stream. This is needed when a new Index is concatenated
/// to this lzma_index structure.
lzma_vli index_list_size;
} old;
};
static void
free_index_list(lzma_index *i, lzma_allocator *allocator)
{
lzma_index *new_head = NULL;
lzma_index *new_current = NULL;
lzma_index_group *g = i->head;
while (old_current != NULL) {
lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
if (i == NULL) {
lzma_index_free(new_head, allocator);
return NULL;
}
i->total_size = old_current->total_size;
i->uncompressed_size = old_current->uncompressed_size;
i->next = NULL;
if (new_head == NULL)
new_head = i;
else
new_current->next = i;
new_current = i;
old_current = old_current->next;
}
return new_head;
}
/**
* \brief Frees an Index list
*
* All Index Recors in the list are freed. This function is convenient when
* getting rid of lzma_metadata structures containing an Index.
*/
extern LZMA_API void
lzma_index_free(lzma_index *i, lzma_allocator *allocator)
{
while (i != NULL) {
lzma_index *tmp = i->next;
lzma_free(i, allocator);
i = tmp;
while (g != NULL) {
lzma_index_group *tmp = g->next;
lzma_free(g, allocator);
g = tmp;
}
return;
}
/**
* \brief Calculates properties of an Index list
*
*
*/
extern LZMA_API lzma_ret
lzma_index_count(const lzma_index *i, size_t *count,
lzma_vli *lzma_restrict total_size,
lzma_vli *lzma_restrict uncompressed_size)
extern LZMA_API lzma_index *
lzma_index_init(lzma_index *i, lzma_allocator *allocator)
{
*count = 0;
*total_size = 0;
*uncompressed_size = 0;
while (i != NULL) {
if (i->total_size == LZMA_VLI_VALUE_UNKNOWN) {
*total_size = LZMA_VLI_VALUE_UNKNOWN;
} else if (i->total_size > LZMA_VLI_VALUE_MAX) {
return LZMA_PROG_ERROR;
} else if (*total_size != LZMA_VLI_VALUE_UNKNOWN) {
*total_size += i->total_size;
if (*total_size > LZMA_VLI_VALUE_MAX)
return LZMA_PROG_ERROR;
}
if (i->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN) {
*uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
} else if (i->uncompressed_size > LZMA_VLI_VALUE_MAX) {
return LZMA_PROG_ERROR;
} else if (*uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
*uncompressed_size += i->uncompressed_size;
if (*uncompressed_size > LZMA_VLI_VALUE_MAX)
return LZMA_PROG_ERROR;
}
++*count;
i = i->next;
if (i == NULL) {
i = lzma_alloc(sizeof(lzma_index), allocator);
if (i == NULL)
return NULL;
} else {
free_index_list(i, allocator);
}
// FIXME ?
if (*total_size == LZMA_VLI_VALUE_UNKNOWN
|| *uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
return LZMA_HEADER_ERROR;
i->total_size = 0;
i->uncompressed_size = 0;
i->count = 0;
i->index_list_size = 0;
i->padding_size = 0;
i->head = NULL;
i->tail = NULL;
i->current.group = NULL;
i->old.count = 0;
i->old.index_list_size = 0;
return i;
}
extern LZMA_API void
lzma_index_end(lzma_index *i, lzma_allocator *allocator)
{
if (i != NULL) {
free_index_list(i, allocator);
lzma_free(i, allocator);
}
return;
}
extern LZMA_API lzma_vli
lzma_index_count(const lzma_index *i)
{
return i->count;
}
extern LZMA_API lzma_vli
lzma_index_size(const lzma_index *i)
{
return index_size(i->count, i->index_list_size);
}
extern LZMA_API lzma_vli
lzma_index_total_size(const lzma_index *i)
{
return i->total_size;
}
extern LZMA_API lzma_vli
lzma_index_stream_size(const lzma_index *i)
{
// Stream Header + Blocks + Index + Stream Footer
return LZMA_STREAM_HEADER_SIZE + i->total_size
+ index_size(i->count, i->index_list_size)
+ LZMA_STREAM_HEADER_SIZE;
}
extern LZMA_API lzma_vli
lzma_index_file_size(const lzma_index *i)
{
// If multiple Streams are concatenated, the Stream Header, Index,
// and Stream Footer fields of all but the last Stream are already
// included in padding_size. Thus, we need to calculate only the
// size of the last Index, not all Indexes.
return i->total_size + i->padding_size
+ index_size(i->count - i->old.count,
i->index_list_size - i->old.index_list_size)
+ LZMA_STREAM_HEADER_SIZE * 2;
}
extern LZMA_API lzma_vli
lzma_index_uncompressed_size(const lzma_index *i)
{
return i->uncompressed_size;
}
extern uint32_t
lzma_index_padding_size(const lzma_index *i)
{
return (LZMA_VLI_C(4)
- index_size_unpadded(i->count, i->index_list_size)) & 3;
}
/// Helper function for index_append()
static lzma_ret
index_append_real(lzma_index *i, lzma_allocator *allocator,
lzma_vli total_size, lzma_vli uncompressed_size,
bool is_padding)
{
// Add the new record.
if (i->tail == NULL || i->tail->last == INDEX_GROUP_SIZE - 1) {
// Allocate a new group.
lzma_index_group *g = lzma_alloc(sizeof(lzma_index_group),
allocator);
if (g == NULL)
return LZMA_MEM_ERROR;
// Initialize the group and set its first record.
g->prev = i->tail;
g->next = NULL;
g->last = 0;
g->total_sums[0] = total_size;
g->uncompressed_sums[0] = uncompressed_size;
g->paddings[0] = is_padding;
// If this is the first group, make it the head.
if (i->head == NULL)
i->head = g;
else
i->tail->next = g;
// Make it the new tail.
i->tail = g;
} else {
// i->tail has space left for at least one record.
i->tail->total_sums[i->tail->last + 1]
= i->tail->total_sums[i->tail->last]
+ total_size;
i->tail->uncompressed_sums[i->tail->last + 1]
= i->tail->uncompressed_sums[i->tail->last]
+ uncompressed_size;
i->tail->paddings[i->tail->last + 1] = is_padding;
++i->tail->last;
}
return LZMA_OK;
}
extern LZMA_API lzma_bool
lzma_index_is_equal(const lzma_index *a, const lzma_index *b)
static lzma_ret
index_append(lzma_index *i, lzma_allocator *allocator, lzma_vli total_size,
lzma_vli uncompressed_size, bool is_padding)
{
while (a != NULL && b != NULL) {
if (a->total_size != b->total_size || a->uncompressed_size
!= b->uncompressed_size)
return false;
if (total_size > LZMA_VLI_VALUE_MAX
|| uncompressed_size > LZMA_VLI_VALUE_MAX)
return LZMA_DATA_ERROR;
a = a->next;
b = b->next;
// This looks a bit ugly. We want to first validate that the Index
// and Stream stay in valid limits after adding this Record. After
// validating, we may need to allocate a new lzma_index_group (it's
// slightly more correct to validate before allocating, YMMV).
lzma_ret ret;
if (is_padding) {
assert(uncompressed_size == 0);
// First update the info so we can validate it.
i->padding_size += total_size;
if (i->padding_size > LZMA_VLI_VALUE_MAX
|| lzma_index_file_size(i)
> LZMA_VLI_VALUE_MAX)
ret = LZMA_DATA_ERROR; // Would grow past the limits.
else
ret = index_append_real(i, allocator,
total_size, uncompressed_size, true);
// If something went wrong, undo the updated value.
if (ret != LZMA_OK)
i->padding_size -= total_size;
} else {
// First update the overall info so we can validate it.
const lzma_vli index_list_size_add
= lzma_vli_size(total_size / 4 - 1)
+ lzma_vli_size(uncompressed_size);
i->total_size += total_size;
i->uncompressed_size += uncompressed_size;
++i->count;
i->index_list_size += index_list_size_add;
if (i->total_size > LZMA_VLI_VALUE_MAX
|| i->uncompressed_size > LZMA_VLI_VALUE_MAX
|| lzma_index_size(i) > LZMA_BACKWARD_SIZE_MAX
|| lzma_index_file_size(i)
> LZMA_VLI_VALUE_MAX)
ret = LZMA_DATA_ERROR; // Would grow past the limits.
else
ret = index_append_real(i, allocator,
total_size, uncompressed_size, false);
if (ret != LZMA_OK) {
// Something went wrong. Undo the updates.
i->total_size -= total_size;
i->uncompressed_size -= uncompressed_size;
--i->count;
i->index_list_size -= index_list_size_add;
}
}
return a == b;
return ret;
}
extern LZMA_API lzma_ret
lzma_index_append(lzma_index *i, lzma_allocator *allocator,
lzma_vli total_size, lzma_vli uncompressed_size)
{
return index_append(i, allocator,
total_size, uncompressed_size, false);
}
/// Initialize i->current to point to the first Record.
static bool
init_current(lzma_index *i)
{
if (i->head == NULL) {
assert(i->count == 0);
return true;
}
assert(i->count > 0);
i->current.group = i->head;
i->current.record = 0;
i->current.stream_offset = LZMA_STREAM_HEADER_SIZE;
i->current.uncompressed_offset = 0;
return false;
}
/// Go backward to the previous group.
static void
previous_group(lzma_index *i)
{
assert(i->current.group->prev != NULL);
// Go to the previous group first.
i->current.group = i->current.group->prev;
i->current.record = i->current.group->last;
// Then update the offsets.
i->current.stream_offset -= i->current.group
->total_sums[i->current.group->last];
i->current.uncompressed_offset -= i->current.group
->uncompressed_sums[i->current.group->last];
return;
}
/// Go forward to the next group.
static void
next_group(lzma_index *i)
{
assert(i->current.group->next != NULL);
// Update the offsets first.
i->current.stream_offset += i->current.group
->total_sums[i->current.group->last];
i->current.uncompressed_offset += i->current.group
->uncompressed_sums[i->current.group->last];
// Then go to the next group.
i->current.record = 0;
i->current.group = i->current.group->next;
return;
}
/// Set *info from i->current.
static void
set_info(const lzma_index *i, lzma_index_record *info)
{
info->total_size = i->current.group->total_sums[i->current.record];
info->uncompressed_size = i->current.group->uncompressed_sums[
i->current.record];
info->stream_offset = i->current.stream_offset;
info->uncompressed_offset = i->current.uncompressed_offset;
// If it's not the first Record in this group, we need to do some
// adjustements.
if (i->current.record > 0) {
// _sums[] are cumulative, thus we need to substract the
// _previous _sums[] to get the sizes of this Record.
info->total_size -= i->current.group
->total_sums[i->current.record - 1];
info->uncompressed_size -= i->current.group
->uncompressed_sums[i->current.record - 1];
// i->current.{total,uncompressed}_offsets have the offset
// of the beginning of the group, thus we need to add the
// appropriate amount to get the offsetes of this Record.
info->stream_offset += i->current.group
->total_sums[i->current.record - 1];
info->uncompressed_offset += i->current.group
->uncompressed_sums[i->current.record - 1];
}
return;
}
extern LZMA_API lzma_bool
lzma_index_read(lzma_index *i, lzma_index_record *info)
{
if (i->current.group == NULL) {
// We are at the beginning of the Record list. Set up
// i->current point at the first Record. Return if there
// are no Records.
if (init_current(i))
return true;
} else do {
// Try to go the next Record.
if (i->current.record < i->current.group->last)
++i->current.record;
else if (i->current.group->next == NULL)
return true;
else
next_group(i);
} while (i->current.group->paddings[i->current.record]);
// We found a new Record. Set the information to *info.
set_info(i, info);
return false;
}
extern LZMA_API void
lzma_index_rewind(lzma_index *i)
{
i->current.group = NULL;
return;
}
extern LZMA_API lzma_bool
lzma_index_locate(lzma_index *i, lzma_index_record *info, lzma_vli target)
{
// Check if it is possible to fullfill the request.
if (target >= i->uncompressed_size)
return true;
// Now we know that we will have an answer. Initialize the current
// read position if needed.
if (i->current.group == NULL && init_current(i))
return true;
// Locate the group where the wanted Block is. First search forward.
while (i->current.uncompressed_offset <= target) {
// If the first uncompressed byte of the next group is past
// the target offset, it has to be this or an earlier group.
if (i->current.uncompressed_offset + i->current.group
->uncompressed_sums[i->current.group->last]
> target)
break;
// Go forward to the next group.
next_group(i);
}
// Then search backward.
while (i->current.uncompressed_offset > target)
previous_group(i);
// Now the target Block is somewhere in i->current.group. Offsets
// in groups are relative to the beginning of the group, thus
// we must adjust the target before starting the search loop.
assert(target >= i->current.uncompressed_offset);
target -= i->current.uncompressed_offset;
// Use binary search to locate the exact Record. It is the first
// Record whose uncompressed_sums[] value is greater than target.
// This is because we want the rightmost Record that fullfills the
// search criterion. It is possible that there are empty Blocks or
// padding, we don't want to return them.
size_t left = 0;
size_t right = i->current.group->last;
while (left < right) {
const size_t pos = left + (right - left) / 2;
if (i->current.group->uncompressed_sums[pos] <= target)
left = pos + 1;
else
right = pos;
}
i->current.record = left;
#ifndef NDEBUG
// The found Record must not be padding or have zero uncompressed size.
assert(!i->current.group->paddings[i->current.record]);
if (i->current.record == 0)
assert(i->current.group->uncompressed_sums[0] > 0);
else
assert(i->current.group->uncompressed_sums[i->current.record]
- i->current.group->uncompressed_sums[
i->current.record - 1] > 0);
#endif
set_info(i, info);
return false;
}
extern LZMA_API lzma_ret
lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
lzma_allocator *allocator, lzma_vli padding)
{
if (dest == NULL || src == NULL || dest == src
|| padding > LZMA_VLI_VALUE_MAX)
return LZMA_PROG_ERROR;
// Check that the combined size of the Indexes stays within limits.
{
const lzma_vli dest_size = lzma_index_file_size(dest);
const lzma_vli src_size = lzma_index_file_size(src);
if (dest_size + src_size > LZMA_VLI_VALUE_UNKNOWN
|| dest_size + src_size + padding
> LZMA_VLI_VALUE_UNKNOWN)
return LZMA_DATA_ERROR;
}
// Add a padding Record to take into account the size of
// Index + Stream Footer + Stream Padding + Stream Header.
//
// NOTE: This cannot overflow, because Index Size is always
// far smaller than LZMA_VLI_VALUE_MAX, and adding two VLIs
// (Index Size and padding) doesn't overflow. It may become
// an invalid VLI if padding is huge, but that is caught by
// index_append().
padding += index_size(dest->count - dest->old.count,
dest->index_list_size
- dest->old.index_list_size)
+ LZMA_STREAM_HEADER_SIZE * 2;
// Add the padding Record.
return_if_error(index_append(
dest, allocator, padding, 0, true));
// Avoid wasting lots of memory if src->head has only a few records
// that fit into dest->tail. That is, combine two groups if possible.
//
// NOTE: We know that dest->tail != NULL since we just appended
// a padding Record. But we don't know about src->head.
if (src->head != NULL && src->head->last + 1
<= INDEX_GROUP_SIZE - dest->tail->last - 1) {
// Copy the first Record.
dest->tail->total_sums[dest->tail->last + 1]
= dest->tail->total_sums[dest->tail->last]
+ src->head->total_sums[0];
dest->tail->uncompressed_sums[dest->tail->last + 1]
= dest->tail->uncompressed_sums[dest->tail->last]
+ src->head->uncompressed_sums[0];
dest->tail->paddings[dest->tail->last + 1]
= src->head->paddings[0];
++dest->tail->last;
// Copy the rest.
for (size_t i = 1; i < src->head->last; ++i) {
dest->tail->total_sums[dest->tail->last + 1]
= dest->tail->total_sums[dest->tail->last]
+ src->head->total_sums[i + 1]
- src->head->total_sums[i];
dest->tail->uncompressed_sums[dest->tail->last + 1]
= dest->tail->uncompressed_sums[
dest->tail->last]
+ src->head->uncompressed_sums[i + 1]
- src->head->uncompressed_sums[i];
dest->tail->paddings[dest->tail->last + 1]
= src->head->paddings[i + 1];
++dest->tail->last;
}
// Free the head group of *src. Don't bother updating prev
// pointers since those won't be used for anything before
// we deallocate the whole *src structure.
lzma_index_group *tmp = src->head;
src->head = src->head->next;
lzma_free(tmp, allocator);
}
// If there are groups left in *src, join them as is. Note that if we
// are combining already combined Indexes, src->head can be non-NULL
// even if we just combined the old src->head to dest->tail.
if (src->head != NULL) {
src->head->prev = dest->tail;
dest->tail->next = src->head;
dest->tail = src->tail;
}
// Update information about earlier Indexes. Only the last Index
// from *src won't be counted in dest->old. The last Index is left
// open and can be even appended with lzma_index_append().
dest->old.count = dest->count + src->old.count;
dest->old.index_list_size
= dest->index_list_size + src->old.index_list_size;
// Update overall information.
dest->total_size += src->total_size;
dest->uncompressed_size += src->uncompressed_size;
dest->count += src->count;
dest->index_list_size += src->index_list_size;
dest->padding_size += src->padding_size;
// *src has nothing left but the base structure.
lzma_free(src, allocator);
return LZMA_OK;
}
extern LZMA_API lzma_index *
lzma_index_dup(const lzma_index *src, lzma_allocator *allocator)
{
lzma_index *dest = lzma_alloc(sizeof(lzma_index), allocator);
if (dest == NULL)
return NULL;
// Copy the base structure except the pointers.
*dest = *src;
dest->head = NULL;
dest->tail = NULL;
dest->current.group = NULL;
// Copy the Records.
const lzma_index_group *src_group = src->head;
while (src_group != NULL) {
// Allocate a new group.
lzma_index_group *dest_group = lzma_alloc(
sizeof(lzma_index_group), allocator);
if (dest_group == NULL) {
lzma_index_end(dest, allocator);
return NULL;
}
// Set the pointers.
dest_group->prev = dest->tail;
dest_group->next = NULL;
if (dest->head == NULL)
dest->head = dest_group;
else
dest->tail->next = dest_group;
dest->tail = dest_group;
dest_group->last = src_group->last;
// Copy the arrays so that we don't read uninitialized memory.
const size_t count = src_group->last + 1;
memcpy(dest_group->total_sums, src_group->total_sums,
sizeof(lzma_vli) * count);
memcpy(dest_group->uncompressed_sums,
src_group->uncompressed_sums,
sizeof(lzma_vli) * count);
memcpy(dest_group->paddings, src_group->paddings,
sizeof(bool) * count);
// Copy also the read position.
if (src_group == src->current.group)
dest->current.group = dest->tail;
src_group = src_group->next;
}
return dest;
}
extern LZMA_API lzma_bool
lzma_index_equal(const lzma_index *a, const lzma_index *b)
{
// No point to compare more if the pointers are the same.
if (a == b)
return true;
// Compare the basic properties.
if (a->total_size != b->total_size
|| a->uncompressed_size != b->uncompressed_size
|| a->index_list_size != b->index_list_size
|| a->count != b->count)
return false;
// Compare the Records.
const lzma_index_group *ag = a->head;
const lzma_index_group *bg = b->head;
while (ag != NULL && bg != NULL) {
const size_t count = ag->last + 1;
if (ag->last != bg->last
|| memcmp(ag->total_sums,
bg->total_sums,
sizeof(lzma_vli) * count) != 0
|| memcmp(ag->uncompressed_sums,
bg->uncompressed_sums,
sizeof(lzma_vli) * count) != 0
|| memcmp(ag->paddings, bg->paddings,
sizeof(bool) * count) != 0)
return false;
ag = ag->next;
bg = bg->next;
}
return ag == NULL && bg == NULL;
}

Some files were not shown because too many files have changed in this diff Show More