Merge branch 'upstream-liblzma' into update-liblzma

* upstream-liblzma:
  liblzma 2018-04-29 (b5be61cc)
This commit is contained in:
Brad King
2018-08-06 10:24:55 -04:00
96 changed files with 3476 additions and 1046 deletions

View File

@@ -47,7 +47,7 @@ XZ Utils Licensing
naturally it is not legally required. Here is an example of a good
notice to put into "about box" or into documentation:
This software includes code from XZ Utils <http://tukaani.org/xz/>.
This software includes code from XZ Utils <https://tukaani.org/xz/>.
The following license texts are included in the following files:
- COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1

View File

@@ -17,7 +17,7 @@
#define MY_VERSION LZMA_VERSION_MAJOR,LZMA_VERSION_MINOR,LZMA_VERSION_PATCH,MY_BUILD
#define MY_FILENAME MY_NAME MY_SUFFIX
#define MY_COMPANY "The Tukaani Project <http://tukaani.org/>"
#define MY_COMPANY "The Tukaani Project <https://tukaani.org/>"
#define MY_PRODUCT PACKAGE_NAME " <" PACKAGE_URL ">"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

View File

@@ -175,6 +175,16 @@ typedef unsigned char _Bool;
# include <memory.h>
#endif
// As of MSVC 2013, inline and restrict are supported with
// non-standard keywords.
#if defined(_WIN32) && defined(_MSC_VER)
# ifndef inline
# define inline __inline
# endif
# ifndef restrict
# define restrict __restrict
# endif
#endif
////////////
// Macros //

View File

@@ -106,6 +106,17 @@
#endif
////////////////////////////////
// Compiler-specific features //
////////////////////////////////
// Newer Intel C compilers require immintrin.h for _bit_scan_reverse()
// and such functions.
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500)
# include <immintrin.h>
#endif
///////////////////
// Byte swapping //
///////////////////
@@ -329,8 +340,8 @@ unaligned_read32le(const uint8_t *buf)
static inline void
unaligned_write16be(uint8_t *buf, uint16_t num)
{
buf[0] = num >> 8;
buf[1] = num;
buf[0] = (uint8_t)(num >> 8);
buf[1] = (uint8_t)num;
return;
}
@@ -338,8 +349,8 @@ unaligned_write16be(uint8_t *buf, uint16_t num)
static inline void
unaligned_write16le(uint8_t *buf, uint16_t num)
{
buf[0] = num;
buf[1] = num >> 8;
buf[0] = (uint8_t)num;
buf[1] = (uint8_t)(num >> 8);
return;
}
@@ -347,10 +358,10 @@ unaligned_write16le(uint8_t *buf, uint16_t num)
static inline void
unaligned_write32be(uint8_t *buf, uint32_t num)
{
buf[0] = num >> 24;
buf[1] = num >> 16;
buf[2] = num >> 8;
buf[3] = num;
buf[0] = (uint8_t)(num >> 24);
buf[1] = (uint8_t)(num >> 16);
buf[2] = (uint8_t)(num >> 8);
buf[3] = (uint8_t)num;
return;
}
@@ -358,10 +369,10 @@ unaligned_write32be(uint8_t *buf, uint32_t num)
static inline void
unaligned_write32le(uint8_t *buf, uint32_t num)
{
buf[0] = num;
buf[1] = num >> 8;
buf[2] = num >> 16;
buf[3] = num >> 24;
buf[0] = (uint8_t)num;
buf[1] = (uint8_t)(num >> 8);
buf[2] = (uint8_t)(num >> 16);
buf[3] = (uint8_t)(num >> 24);
return;
}

View File

@@ -82,12 +82,20 @@
# if !defined(UINT32_C) || !defined(UINT64_C) \
|| !defined(UINT32_MAX) || !defined(UINT64_MAX)
/*
* MSVC has no C99 support, and thus it cannot be used to
* compile liblzma. The liblzma API has to still be usable
* from MSVC, so we need to define the required standard
* integer types here.
* MSVC versions older than 2013 have no C99 support, and
* thus they cannot be used to compile liblzma. Using an
* existing liblzma.dll with old MSVC can work though(*),
* but we need to define the required standard integer
* types here in a MSVC-specific way.
*
* (*) If you do this, the existing liblzma.dll probably uses
* a different runtime library than your MSVC-built
* application. Mixing runtimes is generally bad, but
* in this case it should work as long as you avoid
* the few rarely-needed liblzma functions that allocate
* memory and expect the caller to free it using free().
*/
# if defined(_WIN32) && defined(_MSC_VER)
# if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1800
typedef unsigned __int8 uint8_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
@@ -211,7 +219,11 @@
*/
#ifndef lzma_nothrow
# if defined(__cplusplus)
# define lzma_nothrow throw()
# if __cplusplus >= 201103L
# define lzma_nothrow noexcept
# else
# define lzma_nothrow throw()
# endif
# elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
# define lzma_nothrow __attribute__((__nothrow__))
# else
@@ -286,7 +298,7 @@ extern "C" {
#include "lzma/filter.h"
#include "lzma/bcj.h"
#include "lzma/delta.h"
#include "lzma/lzma.h"
#include "lzma/lzma12.h"
/* Container formats */
#include "lzma/container.h"

View File

@@ -240,12 +240,12 @@ typedef enum {
/**
* \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.
* After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FULL_BARRIER,
* 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,
@@ -293,7 +293,7 @@ typedef enum {
*
* All the input data going to the current Block must have
* been given to the encoder (the last bytes can still be
* pending in* next_in). Call lzma_code() with LZMA_FULL_FLUSH
* pending in *next_in). Call lzma_code() with LZMA_FULL_FLUSH
* until it returns LZMA_STREAM_END. Then continue normally
* with LZMA_RUN or finish the Stream with LZMA_FINISH.
*
@@ -302,6 +302,29 @@ typedef enum {
* no unfinished Block, no empty Block is created.
*/
LZMA_FULL_BARRIER = 4,
/**<
* \brief Finish encoding of the current Block
*
* This is like LZMA_FULL_FLUSH except that this doesn't
* necessarily wait until all the input has been made
* available via the output buffer. That is, lzma_code()
* might return LZMA_STREAM_END as soon as all the input
* has been consumed (avail_in == 0).
*
* LZMA_FULL_BARRIER is useful with a threaded encoder if
* one wants to split the .xz Stream into Blocks at specific
* offsets but doesn't care if the output isn't flushed
* immediately. Using LZMA_FULL_BARRIER allows keeping
* the threads busy while LZMA_FULL_FLUSH would make
* lzma_code() wait until all the threads have finished
* until more data could be passed to the encoder.
*
* With a lzma_stream initialized with the single-threaded
* lzma_stream_encoder() or lzma_easy_encoder(),
* LZMA_FULL_BARRIER is an alias for LZMA_FULL_FLUSH.
*/
LZMA_FINISH = 3
/**<
* \brief Finish the coding operation
@@ -332,11 +355,19 @@ typedef enum {
* malloc() and free(). C++ users should note that the custom memory
* handling functions must not throw exceptions.
*
* 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
* process, but obviously it must be done carefully to make sure that the
* replacement `free' can deallocate memory allocated by the earlier
* `alloc' function(s).
* Single-threaded mode only: 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 process, but obviously it must be done
* carefully to make sure that the replacement `free' can deallocate
* memory allocated by the earlier `alloc' function(s).
*
* Multithreaded mode: liblzma might internally store pointers to the
* lzma_allocator given via the lzma_stream structure. The application
* must not change the allocator pointer in lzma_stream or the contents
* of the pointed lzma_allocator structure until lzma_end() has been used
* to free the memory associated with that lzma_stream. The allocation
* functions might be called simultaneously from multiple threads, and
* thus they must be thread safe.
*/
typedef struct {
/**
@@ -448,7 +479,8 @@ typedef struct lzma_internal_s lzma_internal;
*
* Application may modify the 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 aren't used for anything else.
* written but aren't used for anything else except as a possible return
* values from lzma_get_progress().
*/
typedef struct {
const uint8_t *next_in; /**< Pointer to the next input byte. */
@@ -464,8 +496,10 @@ typedef struct {
*
* In most cases this is NULL which makes liblzma use
* the standard malloc() and free().
*
* \note In 5.0.x this is not a const pointer.
*/
lzma_allocator *allocator;
const lzma_allocator *allocator;
/** Internal state is not visible to applications. */
lzma_internal *internal;
@@ -546,6 +580,25 @@ extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action)
extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow;
/**
* \brief Get progress information
*
* In single-threaded mode, applications can get progress information from
* strm->total_in and strm->total_out. In multi-threaded mode this is less
* useful because a significant amount of both input and output data gets
* buffered internally by liblzma. This makes total_in and total_out give
* misleading information and also makes the progress indicator updates
* non-smooth.
*
* This function gives realistic progress information also in multi-threaded
* mode by taking into account the progress made by each thread. In
* single-threaded mode *progress_in and *progress_out are set to
* strm->total_in and strm->total_out, respectively.
*/
extern LZMA_API(void) lzma_get_progress(lzma_stream *strm,
uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
/**
* \brief Get the memory usage of decoder filter chain
*
@@ -591,11 +644,16 @@ extern LZMA_API(uint64_t) lzma_memlimit_get(const lzma_stream *strm)
* This function is supported only when *strm has been initialized with
* a function that takes a memlimit argument.
*
* liblzma 5.2.3 and earlier has a bug where memlimit value of 0 causes
* this function to do nothing (leaving the limit unchanged) and still
* return LZMA_OK. Later versions treat 0 as if 1 had been specified (so
* lzma_memlimit_get() will return 1 even if you specify 0 here).
*
* \return - LZMA_OK: New memory usage limit successfully set.
* - LZMA_MEMLIMIT_ERROR: The new limit is too small.
* The limit was not changed.
* - LZMA_PROG_ERROR: Invalid arguments, e.g. *strm doesn't
* support memory usage limit or memlimit was zero.
* support memory usage limit.
*/
extern LZMA_API(lzma_ret) lzma_memlimit_set(
lzma_stream *strm, uint64_t memlimit) lzma_nothrow;

View File

@@ -31,11 +31,16 @@ typedef struct {
/**
* \brief Block format version
*
* To prevent API and ABI breakages if new features are needed in
* the Block field, a version number is used to indicate which
* fields in this structure are in use. For now, version must always
* be zero. With non-zero version, most Block related functions will
* return LZMA_OPTIONS_ERROR.
* To prevent API and ABI breakages when new features are needed,
* a version number is used to indicate which fields in this
* structure are in use:
* - liblzma >= 5.0.0: version = 0 is supported.
* - liblzma >= 5.1.4beta: Support for version = 1 was added,
* which adds the ignore_check field.
*
* If version is greater than one, most Block related functions
* will return LZMA_OPTIONS_ERROR (lzma_block_header_decode() works
* with any version value).
*
* Read by:
* - All functions that take pointer to lzma_block as argument,
@@ -233,7 +238,28 @@ typedef struct {
lzma_reserved_enum reserved_enum2;
lzma_reserved_enum reserved_enum3;
lzma_reserved_enum reserved_enum4;
lzma_bool reserved_bool1;
/**
* \brief A flag to Block decoder to not verify the Check field
*
* This field is supported by liblzma >= 5.1.4beta if .version >= 1.
*
* If this is set to true, the integrity check won't be calculated
* and verified. Unless you know what you are doing, you should
* leave this to false. (A reason to set this to true is when the
* file integrity is verified externally anyway and you want to
* speed up the decompression, which matters mostly when using
* SHA-256 as the integrity check.)
*
* If .version >= 1, read by:
* - lzma_block_decoder()
* - lzma_block_buffer_decode()
*
* Written by (.version is ignored):
* - lzma_block_header_decode() always sets this to false
*/
lzma_bool ignore_check;
lzma_bool reserved_bool2;
lzma_bool reserved_bool3;
lzma_bool reserved_bool4;
@@ -310,10 +336,14 @@ extern LZMA_API(lzma_ret) lzma_block_header_encode(
/**
* \brief Decode Block Header
*
* block->version should be set to the highest value supported by the
* application; currently the only possible version is zero. This function
* will set version to the lowest value that still supports all the features
* required by the Block Header.
* block->version should (usually) be set to the highest value supported
* by the application. If the application sets block->version to a value
* higher than supported by the current liblzma version, this function will
* downgrade block->version to the highest value supported by it. Thus one
* should check the value of block->version after calling this function if
* block->version was set to a non-zero value and the application doesn't
* otherwise know that the liblzma version being used is new enough to
* support the specified block->version.
*
* The size of the Block Header must have already been decoded with
* lzma_block_header_size_decode() macro and stored to block->header_size.
@@ -344,7 +374,7 @@ extern LZMA_API(lzma_ret) lzma_block_header_encode(
* block->header_size is invalid or block->filters is NULL.
*/
extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block,
lzma_allocator *allocator, const uint8_t *in)
const lzma_allocator *allocator, const uint8_t *in)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -493,7 +523,25 @@ extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size)
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
lzma_block *block, lzma_allocator *allocator,
lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_nothrow lzma_attr_warn_unused_result;
/**
* \brief Single-call uncompressed .xz Block encoder
*
* This is like lzma_block_buffer_encode() except this doesn't try to
* compress the data and instead encodes the data using LZMA2 uncompressed
* chunks. The required output buffer size can be determined with
* lzma_block_buffer_bound().
*
* Since the data won't be compressed, this function ignores block->filters.
* This function doesn't take lzma_allocator because this function doesn't
* allocate any memory from the heap.
*/
extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -527,7 +575,7 @@ extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_block_buffer_decode(
lzma_block *block, lzma_allocator *allocator,
lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_nothrow;

View File

@@ -60,6 +60,131 @@
#define LZMA_PRESET_EXTREME (UINT32_C(1) << 31)
/**
* \brief Multithreading options
*/
typedef struct {
/**
* \brief Flags
*
* Set this to zero if no flags are wanted.
*
* No flags are currently supported.
*/
uint32_t flags;
/**
* \brief Number of worker threads to use
*/
uint32_t threads;
/**
* \brief Maximum uncompressed size of a Block
*
* The encoder will start a new .xz Block every block_size bytes.
* Using LZMA_FULL_FLUSH or LZMA_FULL_BARRIER with lzma_code()
* the caller may tell liblzma to start a new Block earlier.
*
* With LZMA2, a recommended block size is 2-4 times the LZMA2
* dictionary size. With very small dictionaries, it is recommended
* to use at least 1 MiB block size for good compression ratio, even
* if this is more than four times the dictionary size. Note that
* these are only recommendations for typical use cases; feel free
* to use other values. Just keep in mind that using a block size
* less than the LZMA2 dictionary size is waste of RAM.
*
* Set this to 0 to let liblzma choose the block size depending
* on the compression options. For LZMA2 it will be 3*dict_size
* or 1 MiB, whichever is more.
*
* For each thread, about 3 * block_size bytes of memory will be
* allocated. This may change in later liblzma versions. If so,
* the memory usage will probably be reduced, not increased.
*/
uint64_t block_size;
/**
* \brief Timeout to allow lzma_code() to return early
*
* Multithreading can make liblzma to consume input and produce
* output in a very bursty way: it may first read a lot of input
* to fill internal buffers, then no input or output occurs for
* a while.
*
* In single-threaded mode, lzma_code() won't return until it has
* either consumed all the input or filled the output buffer. If
* this is done in multithreaded mode, it may cause a call
* lzma_code() to take even tens of seconds, which isn't acceptable
* in all applications.
*
* To avoid very long blocking times in lzma_code(), a timeout
* (in milliseconds) may be set here. If lzma_code() would block
* longer than this number of milliseconds, it will return with
* LZMA_OK. Reasonable values are 100 ms or more. The xz command
* line tool uses 300 ms.
*
* If long blocking times are fine for you, set timeout to a special
* value of 0, which will disable the timeout mechanism and will make
* lzma_code() block until all the input is consumed or the output
* buffer has been filled.
*
* \note Even with a timeout, lzma_code() might sometimes take
* somewhat long time to return. No timing guarantees
* are made.
*/
uint32_t timeout;
/**
* \brief Compression preset (level and possible flags)
*
* The preset is set just like with lzma_easy_encoder().
* The preset is ignored if filters below is non-NULL.
*/
uint32_t preset;
/**
* \brief Filter chain (alternative to a preset)
*
* If this is NULL, the preset above is used. Otherwise the preset
* is ignored and the filter chain specified here is used.
*/
const lzma_filter *filters;
/**
* \brief Integrity check type
*
* See check.h for available checks. The xz command line tool
* defaults to LZMA_CHECK_CRC64, which is a good choice if you
* are unsure.
*/
lzma_check check;
/*
* Reserved space to allow possible future extensions without
* breaking the ABI. 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.
*/
lzma_reserved_enum reserved_enum1;
lzma_reserved_enum reserved_enum2;
lzma_reserved_enum reserved_enum3;
uint32_t reserved_int1;
uint32_t reserved_int2;
uint32_t reserved_int3;
uint32_t reserved_int4;
uint64_t reserved_int5;
uint64_t reserved_int6;
uint64_t reserved_int7;
uint64_t reserved_int8;
void *reserved_ptr1;
void *reserved_ptr2;
void *reserved_ptr3;
void *reserved_ptr4;
} lzma_mt;
/**
* \brief Calculate approximate memory usage of easy encoder
*
@@ -165,7 +290,8 @@ extern LZMA_API(lzma_ret) lzma_easy_encoder(
*/
extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(
uint32_t preset, lzma_check check,
lzma_allocator *allocator, const uint8_t *in, size_t in_size,
const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
@@ -190,6 +316,49 @@ extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm,
lzma_nothrow lzma_attr_warn_unused_result;
/**
* \brief Calculate approximate memory usage of multithreaded .xz encoder
*
* Since doing the encoding in threaded mode doesn't affect the memory
* requirements of single-threaded decompressor, you can use
* lzma_easy_decoder_memusage(options->preset) or
* lzma_raw_decoder_memusage(options->filters) to calculate
* the decompressor memory requirements.
*
* \param options Compression options
*
* \return Number of bytes of memory required for encoding with the
* given options. If an error occurs, for example due to
* unsupported preset or filter chain, UINT64_MAX is returned.
*/
extern LZMA_API(uint64_t) lzma_stream_encoder_mt_memusage(
const lzma_mt *options) lzma_nothrow lzma_attr_pure;
/**
* \brief Initialize multithreaded .xz Stream encoder
*
* This provides the functionality of lzma_easy_encoder() and
* lzma_stream_encoder() as a single function for multithreaded use.
*
* The supported actions for lzma_code() are LZMA_RUN, LZMA_FULL_FLUSH,
* LZMA_FULL_BARRIER, and LZMA_FINISH. Support for LZMA_SYNC_FLUSH might be
* added in the future.
*
* \param strm Pointer to properly prepared lzma_stream
* \param options Pointer to multithreaded compression options
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
* - LZMA_UNSUPPORTED_CHECK
* - LZMA_OPTIONS_ERROR
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_stream_encoder_mt(
lzma_stream *strm, const lzma_mt *options)
lzma_nothrow lzma_attr_warn_unused_result;
/**
* \brief Initialize .lzma encoder (legacy file format)
*
@@ -269,7 +438,8 @@ extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size)
*/
extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
lzma_filter *filters, lzma_check check,
lzma_allocator *allocator, const uint8_t *in, size_t in_size,
const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -304,6 +474,30 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
#define LZMA_TELL_ANY_CHECK UINT32_C(0x04)
/**
* This flag makes lzma_code() not calculate and verify the integrity check
* of the compressed data in .xz files. This means that invalid integrity
* check values won't be detected and LZMA_DATA_ERROR won't be returned in
* such cases.
*
* This flag only affects the checks of the compressed data itself; the CRC32
* values in the .xz headers will still be verified normally.
*
* Don't use this flag unless you know what you are doing. Possible reasons
* to use this flag:
*
* - Trying to recover data from a corrupt .xz file.
*
* - Speeding up decompression, which matters mostly with SHA-256
* or with files that have compressed extremely well. It's recommended
* to not use this flag for this purpose unless the file integrity is
* verified externally in some other way.
*
* Support for this flag was added in liblzma 5.1.4beta.
*/
#define LZMA_IGNORE_CHECK UINT32_C(0x10)
/**
* This flag enables decoding of concatenated files with file formats that
* allow concatenating compressed files as is. From the formats currently
@@ -326,7 +520,10 @@ extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
*
* \param strm Pointer to properly prepared lzma_stream
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
* to effectively disable the limiter.
* to effectively disable the limiter. liblzma
* 5.2.3 and earlier don't allow 0 here and return
* LZMA_PROG_ERROR; later versions treat 0 as if 1
* had been specified.
* \param flags Bitwise-or of zero or more of the decoder flags:
* LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
* LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED
@@ -350,7 +547,10 @@ extern LZMA_API(lzma_ret) lzma_stream_decoder(
*
* \param strm Pointer to properly prepared lzma_stream
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
* to effectively disable the limiter.
* to effectively disable the limiter. liblzma
* 5.2.3 and earlier don't allow 0 here and return
* LZMA_PROG_ERROR; later versions treat 0 as if 1
* had been specified.
* \param flags Bitwise-or of flags, or zero for no flags.
*
* \return - LZMA_OK: Initialization was successful.
@@ -366,9 +566,16 @@ extern LZMA_API(lzma_ret) lzma_auto_decoder(
/**
* \brief Initialize .lzma decoder (legacy file format)
*
* \param strm Pointer to properly prepared lzma_stream
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
* to effectively disable the limiter. liblzma
* 5.2.3 and earlier don't allow 0 here and return
* LZMA_PROG_ERROR; later versions treat 0 as if 1
* had been specified.
*
* 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.
* There is no need to use LZMA_FINISH, but it's allowed because it may
* simplify certain types of applications.
*
* \return - LZMA_OK
* - LZMA_MEM_ERROR
@@ -418,7 +625,8 @@ extern LZMA_API(lzma_ret) lzma_alone_decoder(
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(
uint64_t *memlimit, uint32_t flags, lzma_allocator *allocator,
uint64_t *memlimit, uint32_t flags,
const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
lzma_nothrow lzma_attr_warn_unused_result;

View File

@@ -116,8 +116,9 @@ extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id)
* is not NULL.
* - LZMA_PROG_ERROR: src or dest is NULL.
*/
extern LZMA_API(lzma_ret) lzma_filters_copy(const lzma_filter *src,
lzma_filter *dest, lzma_allocator *allocator) lzma_nothrow;
extern LZMA_API(lzma_ret) lzma_filters_copy(
const lzma_filter *src, lzma_filter *dest,
const lzma_allocator *allocator) lzma_nothrow;
/**
@@ -256,7 +257,7 @@ extern LZMA_API(lzma_ret) lzma_filters_update(
* won't necessarily meet that bound.)
*/
extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
const lzma_filter *filters, lzma_allocator *allocator,
const lzma_filter *filters, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size, uint8_t *out,
size_t *out_pos, size_t out_size) lzma_nothrow;
@@ -280,7 +281,7 @@ extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
* which no data is written to is out[out_size].
*/
extern LZMA_API(lzma_ret) lzma_raw_buffer_decode(
const lzma_filter *filters, lzma_allocator *allocator,
const lzma_filter *filters, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
@@ -356,7 +357,7 @@ extern LZMA_API(lzma_ret) lzma_properties_encode(
* - LZMA_MEM_ERROR
*/
extern LZMA_API(lzma_ret) lzma_properties_decode(
lzma_filter *filter, lzma_allocator *allocator,
lzma_filter *filter, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size) lzma_nothrow;
@@ -419,6 +420,6 @@ extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter,
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_filter_flags_decode(
lzma_filter *filter, lzma_allocator *allocator,
lzma_filter *filter, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
lzma_nothrow lzma_attr_warn_unused_result;

View File

@@ -48,3 +48,17 @@
* of RAM on the specific operating system.
*/
extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow;
/**
* \brief Get the number of processor cores or threads
*
* This function may be useful when determining how many threads to use.
* If the hardware supports more than one thread per CPU core, the number
* of hardware threads is returned if that information is available.
*
* \brief On success, the number of available CPU threads or cores is
* returned. If this information isn't available or an error
* occurs, zero is returned.
*/
extern LZMA_API(uint32_t) lzma_cputhreads(void) lzma_nothrow;

View File

@@ -303,7 +303,7 @@ extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i)
* \return On success, a pointer to an empty initialized lzma_index is
* returned. If allocation fails, NULL is returned.
*/
extern LZMA_API(lzma_index *) lzma_index_init(lzma_allocator *allocator)
extern LZMA_API(lzma_index *) lzma_index_init(const lzma_allocator *allocator)
lzma_nothrow;
@@ -312,8 +312,8 @@ extern LZMA_API(lzma_index *) lzma_index_init(lzma_allocator *allocator)
*
* If i is NULL, this does nothing.
*/
extern LZMA_API(void) lzma_index_end(lzma_index *i, lzma_allocator *allocator)
lzma_nothrow;
extern LZMA_API(void) lzma_index_end(
lzma_index *i, const lzma_allocator *allocator) lzma_nothrow;
/**
@@ -341,7 +341,7 @@ extern LZMA_API(void) lzma_index_end(lzma_index *i, lzma_allocator *allocator)
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_index_append(
lzma_index *i, lzma_allocator *allocator,
lzma_index *i, const lzma_allocator *allocator,
lzma_vli unpadded_size, lzma_vli uncompressed_size)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -564,8 +564,8 @@ extern LZMA_API(lzma_bool) lzma_index_iter_locate(
* - LZMA_MEM_ERROR
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_index_cat(
lzma_index *dest, lzma_index *src, lzma_allocator *allocator)
extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *dest, lzma_index *src,
const lzma_allocator *allocator)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -575,7 +575,7 @@ extern LZMA_API(lzma_ret) lzma_index_cat(
* \return A copy of the lzma_index, or NULL if memory allocation failed.
*/
extern LZMA_API(lzma_index *) lzma_index_dup(
const lzma_index *i, lzma_allocator *allocator)
const lzma_index *i, const lzma_allocator *allocator)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -586,8 +586,7 @@ extern LZMA_API(lzma_index *) lzma_index_dup(
* \param i Pointer to lzma_index which should be encoded.
*
* The valid `action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
* It is enough to use only one of them (you can choose freely; use LZMA_RUN
* to support liblzma versions older than 5.0.0).
* It is enough to use only one of them (you can choose freely).
*
* \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
* - LZMA_MEM_ERROR
@@ -610,16 +609,21 @@ extern LZMA_API(lzma_ret) lzma_index_encoder(
* to a new lzma_index, which the application
* has to later free with lzma_index_end().
* \param memlimit How much memory the resulting lzma_index is
* allowed to require.
* allowed to require. liblzma 5.2.3 and earlier
* don't allow 0 here and return LZMA_PROG_ERROR;
* later versions treat 0 as if 1 had been specified.
*
* The valid `action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
* It is enough to use only one of them (you can choose freely; use LZMA_RUN
* to support liblzma versions older than 5.0.0).
* Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
* There is no need to use LZMA_FINISH, but it's allowed because it may
* simplify certain types of applications.
*
* \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
* - LZMA_MEM_ERROR
* - LZMA_MEMLIMIT_ERROR
* - LZMA_PROG_ERROR
*
* liblzma 5.2.3 and older list also LZMA_MEMLIMIT_ERROR here
* but that error code has never been possible from this
* initialization function.
*/
extern LZMA_API(lzma_ret) lzma_index_decoder(
lzma_stream *strm, lzma_index **i, uint64_t memlimit)
@@ -677,6 +681,6 @@ extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i,
* - LZMA_PROG_ERROR
*/
extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
uint64_t *memlimit, lzma_allocator *allocator,
uint64_t *memlimit, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
lzma_nothrow;

View File

@@ -37,7 +37,7 @@ typedef struct lzma_index_hash_s lzma_index_hash;
* pointer than the index_hash that was given as an argument.
*/
extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
lzma_index_hash *index_hash, lzma_allocator *allocator)
lzma_index_hash *index_hash, const lzma_allocator *allocator)
lzma_nothrow lzma_attr_warn_unused_result;
@@ -45,7 +45,7 @@ extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
* \brief Deallocate lzma_index_hash structure
*/
extern LZMA_API(void) lzma_index_hash_end(
lzma_index_hash *index_hash, lzma_allocator *allocator)
lzma_index_hash *index_hash, const lzma_allocator *allocator)
lzma_nothrow;

View File

@@ -1,5 +1,5 @@
/**
* \file lzma/lzma.h
* \file lzma/lzma12.h
* \brief LZMA1 and LZMA2 filters
*/

View File

@@ -21,8 +21,8 @@
* Version number split into components
*/
#define LZMA_VERSION_MAJOR 5
#define LZMA_VERSION_MINOR 0
#define LZMA_VERSION_PATCH 8
#define LZMA_VERSION_MINOR 2
#define LZMA_VERSION_PATCH 4
#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
#ifndef LZMA_VERSION_COMMIT

View File

@@ -15,6 +15,53 @@
#include "common.h"
// If the function for external SHA-256 is missing, use the internal SHA-256
// code. Due to how configure works, these defines can only get defined when
// both a usable header and a type have already been found.
#if !(defined(HAVE_CC_SHA256_INIT) \
|| defined(HAVE_SHA256_INIT) \
|| defined(HAVE_SHA256INIT))
# define HAVE_INTERNAL_SHA256 1
#endif
#if defined(HAVE_INTERNAL_SHA256)
// Nothing
#elif defined(HAVE_COMMONCRYPTO_COMMONDIGEST_H)
# include <CommonCrypto/CommonDigest.h>
#elif defined(HAVE_SHA256_H)
# include <sys/types.h>
# include <sha256.h>
#elif defined(HAVE_SHA2_H)
# include <sys/types.h>
# include <sha2.h>
#endif
#if defined(HAVE_INTERNAL_SHA256)
/// State for the internal SHA-256 implementation
typedef struct {
/// Internal state
uint32_t state[8];
/// Size of the message excluding padding
uint64_t size;
} lzma_sha256_state;
#elif defined(HAVE_CC_SHA256_CTX)
typedef CC_SHA256_CTX lzma_sha256_state;
#elif defined(HAVE_SHA256_CTX)
typedef SHA256_CTX lzma_sha256_state;
#elif defined(HAVE_SHA2_CTX)
typedef SHA2_CTX lzma_sha256_state;
#endif
#if defined(HAVE_INTERNAL_SHA256)
// Nothing
#elif defined(HAVE_CC_SHA256_INIT)
# define LZMA_SHA256FUNC(x) CC_SHA256_ ## x
#elif defined(HAVE_SHA256_INIT)
# define LZMA_SHA256FUNC(x) SHA256_ ## x
#elif defined(HAVE_SHA256INIT)
# define LZMA_SHA256FUNC(x) SHA256 ## x
#endif
// Index hashing needs the best possible hash function (preferably
// a cryptographic hash) for maximum reliability.
@@ -43,14 +90,7 @@ typedef struct {
union {
uint32_t crc32;
uint64_t crc64;
struct {
/// Internal state
uint32_t state[8];
/// Size of the message excluding padding
uint64_t size;
} sha256;
lzma_sha256_state sha256;
} state;
} lzma_check_state;
@@ -82,6 +122,8 @@ extern void lzma_check_update(lzma_check_state *check, lzma_check type,
extern void lzma_check_finish(lzma_check_state *check, lzma_check type);
#ifndef LZMA_SHA256FUNC
/// Prepare SHA-256 state for new input.
extern void lzma_sha256_init(lzma_check_state *check);
@@ -92,4 +134,39 @@ extern void lzma_sha256_update(
/// Finish the SHA-256 calculation and store the result to check->buffer.u8.
extern void lzma_sha256_finish(lzma_check_state *check);
#else
static inline void
lzma_sha256_init(lzma_check_state *check)
{
LZMA_SHA256FUNC(Init)(&check->state.sha256);
}
static inline void
lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
{
#if defined(HAVE_CC_SHA256_INIT) && SIZE_MAX > UINT32_MAX
// Darwin's CC_SHA256_Update takes uint32_t as the buffer size,
// so use a loop to support size_t.
while (size > UINT32_MAX) {
LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, UINT32_MAX);
buf += UINT32_MAX;
size -= UINT32_MAX;
}
#endif
LZMA_SHA256FUNC(Update)(&check->state.sha256, buf, size);
}
static inline void
lzma_sha256_finish(lzma_check_state *check)
{
LZMA_SHA256FUNC(Final)(check->buffer.u8, &check->state.sha256);
}
#endif
#endif

View File

@@ -21,22 +21,22 @@
//
///////////////////////////////////////////////////////////////////////////////
// Avoid bogus warnings in transform().
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __GNUC__ > 4
# pragma GCC diagnostic ignored "-Wuninitialized"
#endif
#include "check.h"
// At least on x86, GCC is able to optimize this to a rotate instruction.
#define rotr_32(num, amount) ((num) >> (amount) | (num) << (32 - (amount)))
// Rotate a uint32_t. GCC can optimize this to a rotate instruction
// at least on x86.
static inline uint32_t
rotr_32(uint32_t num, unsigned amount)
{
return (num >> amount) | (num << (32 - amount));
}
#define blk0(i) (W[i] = data[i])
#define blk0(i) (W[i] = conv32be(data[i]))
#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \
+ s0(W[(i - 15) & 15]))
#define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x, y, z) ((x & y) | (z & (x | y)))
#define Maj(x, y, z) ((x & (y ^ z)) + (y & z))
#define a(i) T[(0 - i) & 7]
#define b(i) T[(1 - i) & 7]
@@ -47,16 +47,17 @@
#define g(i) T[(6 - i) & 7]
#define h(i) T[(7 - i) & 7]
#define R(i) \
h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] \
+ (j ? blk2(i) : blk0(i)); \
#define R(i, j, blk) \
h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] + blk; \
d(i) += h(i); \
h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
#define R0(i) R(i, 0, blk0(i))
#define R2(i) R(i, j, blk2(i))
#define S0(x) (rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22))
#define S1(x) (rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25))
#define s0(x) (rotr_32(x, 7) ^ rotr_32(x, 18) ^ (x >> 3))
#define s1(x) (rotr_32(x, 17) ^ rotr_32(x, 19) ^ (x >> 10))
#define S0(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 9), 11), 2)
#define S1(x) rotr_32(x ^ rotr_32(x ^ rotr_32(x, 14), 5), 6)
#define s0(x) (rotr_32(x ^ rotr_32(x, 11), 7) ^ (x >> 3))
#define s1(x) (rotr_32(x ^ rotr_32(x, 2), 17) ^ (x >> 10))
static const uint32_t SHA256_K[64] = {
@@ -88,12 +89,18 @@ transform(uint32_t state[8], const uint32_t data[16])
// Copy state[] to working vars.
memcpy(T, state, sizeof(T));
// 64 operations, partially loop unrolled
for (unsigned int j = 0; j < 64; j += 16) {
R( 0); R( 1); R( 2); R( 3);
R( 4); R( 5); R( 6); R( 7);
R( 8); R( 9); R(10); R(11);
R(12); R(13); R(14); R(15);
// The first 16 operations unrolled
R0( 0); R0( 1); R0( 2); R0( 3);
R0( 4); R0( 5); R0( 6); R0( 7);
R0( 8); R0( 9); R0(10); R0(11);
R0(12); R0(13); R0(14); R0(15);
// The remaining 48 operations partially unrolled
for (unsigned int j = 16; j < 64; j += 16) {
R2( 0); R2( 1); R2( 2); R2( 3);
R2( 4); R2( 5); R2( 6); R2( 7);
R2( 8); R2( 9); R2(10); R2(11);
R2(12); R2(13); R2(14); R2(15);
}
// Add the working vars back into state[].
@@ -111,18 +118,7 @@ transform(uint32_t state[8], const uint32_t data[16])
static void
process(lzma_check_state *check)
{
#ifdef WORDS_BIGENDIAN
transform(check->state.sha256.state, check->buffer.u32);
#else
uint32_t data[16];
for (size_t i = 0; i < 16; ++i)
data[i] = bswap32(check->buffer.u32[i]);
transform(check->state.sha256.state, data);
#endif
return;
}

View File

@@ -15,7 +15,7 @@
#include "lz_decoder.h"
struct lzma_coder_s {
typedef struct {
lzma_next_coder next;
enum {
@@ -46,17 +46,19 @@ struct lzma_coder_s {
/// Options decoded from the header needed to initialize
/// the LZMA decoder
lzma_options_lzma options;
};
} lzma_alone_coder;
static lzma_ret
alone_decode(lzma_coder *coder,
lzma_allocator *allocator lzma_attribute((__unused__)),
alone_decode(void *coder_ptr,
const lzma_allocator *allocator lzma_attribute((__unused__)),
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)
{
lzma_alone_coder *coder = coder_ptr;
while (*out_pos < out_size
&& (coder->sequence == SEQ_CODE || *in_pos < in_size))
switch (coder->sequence) {
@@ -166,8 +168,9 @@ alone_decode(lzma_coder *coder,
static void
alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
alone_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_alone_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -175,9 +178,11 @@ alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
alone_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
alone_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
uint64_t *old_memlimit, uint64_t new_memlimit)
{
lzma_alone_coder *coder = coder_ptr;
*memusage = coder->memusage;
*old_memlimit = coder->memlimit;
@@ -193,34 +198,34 @@ alone_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
extern lzma_ret
lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_alone_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
uint64_t memlimit, bool picky)
{
lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
if (memlimit == 0)
return LZMA_PROG_ERROR;
lzma_alone_coder *coder = next->coder;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &alone_decode;
next->end = &alone_decoder_end;
next->memconfig = &alone_decoder_memconfig;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
next->coder->sequence = SEQ_PROPERTIES;
next->coder->picky = picky;
next->coder->pos = 0;
next->coder->options.dict_size = 0;
next->coder->options.preset_dict = NULL;
next->coder->options.preset_dict_size = 0;
next->coder->uncompressed_size = 0;
next->coder->memlimit = memlimit;
next->coder->memusage = LZMA_MEMUSAGE_BASE;
coder->sequence = SEQ_PROPERTIES;
coder->picky = picky;
coder->pos = 0;
coder->options.dict_size = 0;
coder->options.preset_dict = NULL;
coder->options.preset_dict_size = 0;
coder->uncompressed_size = 0;
coder->memlimit = my_max(1, memlimit);
coder->memusage = LZMA_MEMUSAGE_BASE;
return LZMA_OK;
}

View File

@@ -17,7 +17,7 @@
extern lzma_ret lzma_alone_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
uint64_t memlimit, bool picky);
#endif

View File

@@ -17,7 +17,7 @@
#define ALONE_HEADER_SIZE (1 + 4 + 8)
struct lzma_coder_s {
typedef struct {
lzma_next_coder next;
enum {
@@ -27,17 +27,19 @@ struct lzma_coder_s {
size_t header_pos;
uint8_t header[ALONE_HEADER_SIZE];
};
} lzma_alone_coder;
static lzma_ret
alone_encode(lzma_coder *coder,
lzma_allocator *allocator lzma_attribute((__unused__)),
alone_encode(void *coder_ptr,
const lzma_allocator *allocator lzma_attribute((__unused__)),
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)
{
lzma_alone_coder *coder = coder_ptr;
while (*out_pos < out_size)
switch (coder->sequence) {
case SEQ_HEADER:
@@ -65,8 +67,9 @@ alone_encode(lzma_coder *coder,
static void
alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
alone_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_alone_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -75,28 +78,31 @@ 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,
alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
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)
lzma_alone_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_alone_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &alone_encode;
next->end = &alone_encoder_end;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Basic initializations
next->coder->sequence = SEQ_HEADER;
next->coder->header_pos = 0;
coder->sequence = SEQ_HEADER;
coder->header_pos = 0;
// Encode the header:
// - Properties (1 byte)
if (lzma_lzma_lclppb_encode(options, next->coder->header))
if (lzma_lzma_lclppb_encode(options, coder->header))
return LZMA_OPTIONS_ERROR;
// - Dictionary size (4 bytes)
@@ -116,10 +122,10 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
if (d != UINT32_MAX)
++d;
unaligned_write32le(next->coder->header + 1, d);
unaligned_write32le(coder->header + 1, d);
// - Uncompressed size (always unknown and using EOPM)
memset(next->coder->header + 1 + 4, 0xFF, 8);
memset(coder->header + 1 + 4, 0xFF, 8);
// Initialize the LZMA encoder.
const lzma_filter_info filters[2] = {
@@ -131,13 +137,13 @@ alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
}
};
return lzma_next_filter_init(&next->coder->next, allocator, filters);
return lzma_next_filter_init(&coder->next, allocator, filters);
}
/*
extern lzma_ret
lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_alone_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_options_alone *options)
{
lzma_next_coder_init(&alone_encoder_init, next, allocator, options);

View File

@@ -14,7 +14,7 @@
#include "alone_decoder.h"
struct lzma_coder_s {
typedef struct {
/// Stream decoder or LZMA_Alone decoder
lzma_next_coder next;
@@ -26,15 +26,17 @@ struct lzma_coder_s {
SEQ_CODE,
SEQ_FINISH,
} sequence;
};
} lzma_auto_coder;
static lzma_ret
auto_decode(lzma_coder *coder, lzma_allocator *allocator,
auto_decode(void *coder_ptr, const 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)
{
lzma_auto_coder *coder = coder_ptr;
switch (coder->sequence) {
case SEQ_INIT:
if (*in_pos >= in_size)
@@ -100,8 +102,9 @@ auto_decode(lzma_coder *coder, lzma_allocator *allocator,
static void
auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
auto_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_auto_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -109,8 +112,10 @@ auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_check
auto_decoder_get_check(const lzma_coder *coder)
auto_decoder_get_check(const void *coder_ptr)
{
const lzma_auto_coder *coder = coder_ptr;
// 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);
@@ -118,9 +123,11 @@ auto_decoder_get_check(const lzma_coder *coder)
static lzma_ret
auto_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
auto_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
uint64_t *old_memlimit, uint64_t new_memlimit)
{
lzma_auto_coder *coder = coder_ptr;
lzma_ret ret;
if (coder->next.memconfig != NULL) {
@@ -132,7 +139,10 @@ auto_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
// the current memory usage.
*memusage = LZMA_MEMUSAGE_BASE;
*old_memlimit = coder->memlimit;
ret = LZMA_OK;
if (new_memlimit != 0 && new_memlimit < *memusage)
ret = LZMA_MEMLIMIT_ERROR;
}
if (ret == LZMA_OK && new_memlimit != 0)
@@ -143,32 +153,31 @@ auto_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
static lzma_ret
auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
auto_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
uint64_t memlimit, uint32_t flags)
{
lzma_next_coder_init(&auto_decoder_init, next, allocator);
if (memlimit == 0)
return LZMA_PROG_ERROR;
if (flags & ~LZMA_SUPPORTED_FLAGS)
return LZMA_OPTIONS_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_auto_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_auto_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &auto_decode;
next->end = &auto_decoder_end;
next->get_check = &auto_decoder_get_check;
next->memconfig = &auto_decoder_memconfig;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
next->coder->memlimit = memlimit;
next->coder->flags = flags;
next->coder->sequence = SEQ_INIT;
coder->memlimit = my_max(1, memlimit);
coder->flags = flags;
coder->sequence = SEQ_INIT;
return LZMA_OK;
}

View File

@@ -14,7 +14,7 @@
extern LZMA_API(lzma_ret)
lzma_block_buffer_decode(lzma_block *block, lzma_allocator *allocator,
lzma_block_buffer_decode(lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{

View File

@@ -10,6 +10,7 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "block_buffer_encoder.h"
#include "block_encoder.h"
#include "filter_encoder.h"
#include "lzma2_encoder.h"
@@ -28,8 +29,8 @@
+ LZMA_CHECK_SIZE_MAX + 3) & ~3)
static lzma_vli
lzma2_bound(lzma_vli uncompressed_size)
static uint64_t
lzma2_bound(uint64_t uncompressed_size)
{
// Prevent integer overflow in overhead calculation.
if (uncompressed_size > COMPRESSED_SIZE_MAX)
@@ -39,7 +40,7 @@ lzma2_bound(lzma_vli uncompressed_size)
// uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX,
// multiply by the size of per-chunk header, and add one byte for
// the end marker.
const lzma_vli overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
const uint64_t overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
/ LZMA2_CHUNK_MAX)
* LZMA2_HEADER_UNCOMPRESSED + 1;
@@ -51,30 +52,36 @@ lzma2_bound(lzma_vli uncompressed_size)
}
extern LZMA_API(size_t)
lzma_block_buffer_bound(size_t uncompressed_size)
extern uint64_t
lzma_block_buffer_bound64(uint64_t uncompressed_size)
{
// For now, if the data doesn't compress, we always use uncompressed
// chunks of LZMA2. In future we may use Subblock filter too, but
// but for simplicity we probably will still use the same bound
// calculation even though Subblock filter would have slightly less
// overhead.
lzma_vli lzma2_size = lzma2_bound(uncompressed_size);
// If the data doesn't compress, we always use uncompressed
// LZMA2 chunks.
uint64_t lzma2_size = lzma2_bound(uncompressed_size);
if (lzma2_size == 0)
return 0;
// Take Block Padding into account.
lzma2_size = (lzma2_size + 3) & ~LZMA_VLI_C(3);
lzma2_size = (lzma2_size + 3) & ~UINT64_C(3);
#if SIZE_MAX < LZMA_VLI_MAX
// Catch the possible integer overflow on 32-bit systems. There's no
// overflow on 64-bit systems, because lzma2_bound() already takes
// No risk of integer overflow because lzma2_bound() already takes
// into account the size of the headers in the Block.
if (SIZE_MAX - HEADERS_BOUND < lzma2_size)
return HEADERS_BOUND + lzma2_size;
}
extern LZMA_API(size_t)
lzma_block_buffer_bound(size_t uncompressed_size)
{
uint64_t ret = lzma_block_buffer_bound64(uncompressed_size);
#if SIZE_MAX < UINT64_MAX
// Catch the possible integer overflow on 32-bit systems.
if (ret > SIZE_MAX)
return 0;
#endif
return HEADERS_BOUND + lzma2_size;
return ret;
}
@@ -82,9 +89,6 @@ static lzma_ret
block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{
// TODO: Figure out if the last filter is LZMA2 or Subblock and use
// that filter to encode the uncompressed chunks.
// Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at
// all, but LZMA2 always requires a dictionary, so use the minimum
// value to minimize memory usage of the decoder.
@@ -160,16 +164,11 @@ block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
static lzma_ret
block_encode_normal(lzma_block *block, lzma_allocator *allocator,
block_encode_normal(lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{
// Find out the size of the Block Header.
block->compressed_size = lzma2_bound(in_size);
if (block->compressed_size == 0)
return LZMA_DATA_ERROR;
block->uncompressed_size = in_size;
return_if_error(lzma_block_header_size(block));
// Reserve space for the Block Header and skip it for now.
@@ -221,10 +220,11 @@ block_encode_normal(lzma_block *block, lzma_allocator *allocator,
}
extern LZMA_API(lzma_ret)
lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
static lzma_ret
block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
uint8_t *out, size_t *out_pos, size_t out_size,
bool try_to_compress)
{
// Validate the arguments.
if (block == NULL || (in == NULL && in_size != 0) || out == NULL
@@ -233,11 +233,11 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
// The contents of the structure may depend on the version so
// check the version before validating the contents of *block.
if (block->version != 0)
if (block->version > 1)
return LZMA_OPTIONS_ERROR;
if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
|| block->filters == NULL)
|| (try_to_compress && block->filters == NULL))
return LZMA_PROG_ERROR;
if (!lzma_check_is_supported(block->check))
@@ -258,9 +258,19 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
out_size -= check_size;
// Initialize block->uncompressed_size and calculate the worst-case
// value for block->compressed_size.
block->uncompressed_size = in_size;
block->compressed_size = lzma2_bound(in_size);
if (block->compressed_size == 0)
return LZMA_DATA_ERROR;
// Do the actual compression.
const lzma_ret ret = block_encode_normal(block, allocator,
in, in_size, out, out_pos, out_size);
lzma_ret ret = LZMA_BUF_ERROR;
if (try_to_compress)
ret = block_encode_normal(block, allocator,
in, in_size, out, out_pos, out_size);
if (ret != LZMA_OK) {
// If the error was something else than output buffer
// becoming full, return the error now.
@@ -303,3 +313,25 @@ lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
return LZMA_OK;
}
extern LZMA_API(lzma_ret)
lzma_block_buffer_encode(lzma_block *block, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{
return block_buffer_encode(block, allocator,
in, in_size, out, out_pos, out_size, true);
}
extern LZMA_API(lzma_ret)
lzma_block_uncomp_encode(lzma_block *block,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{
// It won't allocate any memory from heap so no need
// for lzma_allocator.
return block_buffer_encode(block, NULL,
in, in_size, out, out_pos, out_size, false);
}

View File

@@ -0,0 +1,24 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file block_buffer_encoder.h
/// \brief Single-call .xz Block encoder
//
// Author: Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_BLOCK_BUFFER_ENCODER_H
#define LZMA_BLOCK_BUFFER_ENCODER_H
#include "common.h"
/// uint64_t version of lzma_block_buffer_bound(). It is used by
/// stream_encoder_mt.c. Probably the original lzma_block_buffer_bound()
/// should have been 64-bit, but fixing it would break the ABI.
extern uint64_t lzma_block_buffer_bound64(uint64_t uncompressed_size);
#endif

View File

@@ -15,7 +15,7 @@
#include "check.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_CODE,
SEQ_PADDING,
@@ -45,7 +45,10 @@ struct lzma_coder_s {
/// Check of the uncompressed data
lzma_check_state check;
};
/// True if the integrity check won't be calculated and verified.
bool ignore_check;
} lzma_block_coder;
static inline bool
@@ -71,11 +74,13 @@ is_size_valid(lzma_vli size, lzma_vli reference)
static lzma_ret
block_decode(lzma_coder *coder, lzma_allocator *allocator,
block_decode(void *coder_ptr, const 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)
{
lzma_block_coder *coder = coder_ptr;
switch (coder->sequence) {
case SEQ_CODE: {
const size_t in_start = *in_pos;
@@ -97,8 +102,9 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
coder->block->uncompressed_size))
return LZMA_DATA_ERROR;
lzma_check_update(&coder->check, coder->block->check,
out + out_start, out_used);
if (!coder->ignore_check)
lzma_check_update(&coder->check, coder->block->check,
out + out_start, out_used);
if (ret != LZMA_STREAM_END)
return ret;
@@ -140,7 +146,9 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
if (coder->block->check == LZMA_CHECK_NONE)
return LZMA_STREAM_END;
lzma_check_finish(&coder->check, coder->block->check);
if (!coder->ignore_check)
lzma_check_finish(&coder->check, coder->block->check);
coder->sequence = SEQ_CHECK;
// Fall through
@@ -155,7 +163,8 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
// Validate the Check only if we support it.
// coder->check.buffer may be uninitialized
// when the Check ID is not supported.
if (lzma_check_is_supported(coder->block->check)
if (!coder->ignore_check
&& lzma_check_is_supported(coder->block->check)
&& memcmp(coder->block->raw_check,
coder->check.buffer.u8,
check_size) != 0)
@@ -170,8 +179,9 @@ block_decode(lzma_coder *coder, lzma_allocator *allocator,
static void
block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_block_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -179,7 +189,7 @@ block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
extern lzma_ret
lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
lzma_block *block)
{
lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
@@ -191,27 +201,29 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
|| !lzma_vli_is_valid(block->uncompressed_size))
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)
// Allocate *next->coder if needed.
lzma_block_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &block_decode;
next->end = &block_decoder_end;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Basic initializations
next->coder->sequence = SEQ_CODE;
next->coder->block = block;
next->coder->compressed_size = 0;
next->coder->uncompressed_size = 0;
coder->sequence = SEQ_CODE;
coder->block = block;
coder->compressed_size = 0;
coder->uncompressed_size = 0;
// If Compressed Size is not known, we calculate the maximum allowed
// value so that encoded size of the Block (including Block Padding)
// is still a valid VLI and a multiple of four.
next->coder->compressed_limit
coder->compressed_limit
= block->compressed_size == LZMA_VLI_UNKNOWN
? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
- block->header_size
@@ -221,11 +233,14 @@ lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
// 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_check_is_supported(block->check).
next->coder->check_pos = 0;
lzma_check_init(&next->coder->check, block->check);
coder->check_pos = 0;
lzma_check_init(&coder->check, block->check);
coder->ignore_check = block->version >= 1
? block->ignore_check : false;
// Initialize the filter chain.
return lzma_raw_decoder_init(&next->coder->next, allocator,
return lzma_raw_decoder_init(&coder->next, allocator,
block->filters);
}

View File

@@ -17,6 +17,6 @@
extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_block *block);
const lzma_allocator *allocator, lzma_block *block);
#endif

View File

@@ -15,7 +15,7 @@
#include "check.h"
struct lzma_coder_s {
typedef struct {
/// The filters in the chain; initialized with lzma_raw_decoder_init().
lzma_next_coder next;
@@ -41,15 +41,17 @@ struct lzma_coder_s {
/// Check of the uncompressed data
lzma_check_state check;
};
} lzma_block_coder;
static lzma_ret
block_encode(lzma_coder *coder, lzma_allocator *allocator,
block_encode(void *coder_ptr, const 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)
{
lzma_block_coder *coder = coder_ptr;
// Check that our amount of input stays in proper limits.
if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
return LZMA_DATA_ERROR;
@@ -134,8 +136,9 @@ block_encode(lzma_coder *coder, lzma_allocator *allocator,
static void
block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
block_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_block_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -143,10 +146,12 @@ block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
block_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
block_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
const lzma_filter *filters lzma_attribute((__unused__)),
const lzma_filter *reversed_filters)
{
lzma_block_coder *coder = coder_ptr;
if (coder->sequence != SEQ_CODE)
return LZMA_PROG_ERROR;
@@ -156,7 +161,7 @@ block_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
extern lzma_ret
lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
lzma_block *block)
{
lzma_next_coder_init(&lzma_block_encoder_init, next, allocator);
@@ -166,7 +171,7 @@ lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
// The contents of the structure may depend on the version so
// check the version first.
if (block->version != 0)
if (block->version > 1)
return LZMA_OPTIONS_ERROR;
// If the Check ID is not supported, we cannot calculate the check and
@@ -178,30 +183,31 @@ lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
return LZMA_UNSUPPORTED_CHECK;
// Allocate and initialize *next->coder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_block_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &block_encode;
next->end = &block_encoder_end;
next->update = &block_encoder_update;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Basic initializations
next->coder->sequence = SEQ_CODE;
next->coder->block = block;
next->coder->compressed_size = 0;
next->coder->uncompressed_size = 0;
next->coder->pos = 0;
coder->sequence = SEQ_CODE;
coder->block = block;
coder->compressed_size = 0;
coder->uncompressed_size = 0;
coder->pos = 0;
// Initialize the check
lzma_check_init(&next->coder->check, block->check);
lzma_check_init(&coder->check, block->check);
// Initialize the requested filters.
return lzma_raw_encoder_init(&next->coder->next, allocator,
block->filters);
return lzma_raw_encoder_init(&coder->next, allocator, block->filters);
}

View File

@@ -42,6 +42,6 @@
extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, lzma_block *block);
const lzma_allocator *allocator, lzma_block *block);
#endif

View File

@@ -15,7 +15,7 @@
static void
free_properties(lzma_block *block, lzma_allocator *allocator)
free_properties(lzma_block *block, const lzma_allocator *allocator)
{
// Free allocated filter options. The last array member is not
// touched after the initialization in the beginning of
@@ -32,7 +32,7 @@ free_properties(lzma_block *block, lzma_allocator *allocator)
extern LZMA_API(lzma_ret)
lzma_block_header_decode(lzma_block *block,
lzma_allocator *allocator, const uint8_t *in)
const lzma_allocator *allocator, const uint8_t *in)
{
// NOTE: We consider the header to be corrupt not only when the
// CRC32 doesn't match, but also when variable-length integers
@@ -46,8 +46,16 @@ lzma_block_header_decode(lzma_block *block,
block->filters[i].options = NULL;
}
// Always zero for now.
block->version = 0;
// Versions 0 and 1 are supported. If a newer version was specified,
// we need to downgrade it.
if (block->version > 1)
block->version = 1;
// This isn't a Block Header option, but since the decompressor will
// read it if version >= 1, it's better to initialize it here than
// to expect the caller to do it since in almost all cases this
// should be false.
block->ignore_check = false;
// Validate Block Header Size and Check type. The caller must have
// already set these, so it is a programming error if this test fails.

View File

@@ -17,7 +17,7 @@
extern LZMA_API(lzma_ret)
lzma_block_header_size(lzma_block *block)
{
if (block->version != 0)
if (block->version > 1)
return LZMA_OPTIONS_ERROR;
// Block Header Size + Block Flags + CRC32.

View File

@@ -51,7 +51,7 @@ lzma_block_unpadded_size(const lzma_block *block)
// NOTE: This function is used for validation too, so it is
// essential that these checks are always done even if
// Compressed Size is unknown.
if (block == NULL || block->version != 0
if (block == NULL || block->version > 1
|| block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
|| block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
|| (block->header_size & 3)

View File

@@ -36,7 +36,7 @@ lzma_version_string(void)
///////////////////////
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
lzma_alloc(size_t size, lzma_allocator *allocator)
lzma_alloc(size_t size, const lzma_allocator *allocator)
{
// Some malloc() variants return NULL if called with size == 0.
if (size == 0)
@@ -53,8 +53,29 @@ lzma_alloc(size_t size, lzma_allocator *allocator)
}
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
{
// Some calloc() 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);
if (ptr != NULL)
memzero(ptr, size);
} else {
ptr = calloc(1, size);
}
return ptr;
}
extern void
lzma_free(void *ptr, lzma_allocator *allocator)
lzma_free(void *ptr, const lzma_allocator *allocator)
{
if (allocator != NULL && allocator->free != NULL)
allocator->free(allocator->opaque, ptr);
@@ -88,7 +109,7 @@ lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
extern lzma_ret
lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
lzma_next_coder_init(filters[0].init, next, allocator);
@@ -99,7 +120,7 @@ lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_next_filter_update(lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *reversed_filters)
{
// Check that the application isn't trying to change the Filter ID.
@@ -117,7 +138,7 @@ lzma_next_filter_update(lzma_next_coder *next, lzma_allocator *allocator,
extern void
lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator)
lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
{
if (next->init != (uintptr_t)(NULL)) {
// To avoid tiny end functions that simply call
@@ -156,10 +177,8 @@ lzma_strm_init(lzma_stream *strm)
strm->internal->next = LZMA_NEXT_CODER_INIT;
}
strm->internal->supported_actions[LZMA_RUN] = false;
strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false;
strm->internal->supported_actions[LZMA_FULL_FLUSH] = false;
strm->internal->supported_actions[LZMA_FINISH] = false;
memzero(strm->internal->supported_actions,
sizeof(strm->internal->supported_actions));
strm->internal->sequence = ISEQ_RUN;
strm->internal->allow_buf_error = false;
@@ -178,7 +197,7 @@ lzma_code(lzma_stream *strm, lzma_action action)
|| (strm->next_out == NULL && strm->avail_out != 0)
|| strm->internal == NULL
|| strm->internal->next.code == NULL
|| (unsigned int)(action) > LZMA_FINISH
|| (unsigned int)(action) > LZMA_ACTION_MAX
|| !strm->internal->supported_actions[action])
return LZMA_PROG_ERROR;
@@ -213,6 +232,10 @@ lzma_code(lzma_stream *strm, lzma_action action)
case LZMA_FINISH:
strm->internal->sequence = ISEQ_FINISH;
break;
case LZMA_FULL_BARRIER:
strm->internal->sequence = ISEQ_FULL_BARRIER;
break;
}
break;
@@ -240,6 +263,13 @@ lzma_code(lzma_stream *strm, lzma_action action)
break;
case ISEQ_FULL_BARRIER:
if (action != LZMA_FULL_BARRIER
|| strm->internal->avail_in != strm->avail_in)
return LZMA_PROG_ERROR;
break;
case ISEQ_END:
return LZMA_STREAM_END;
@@ -265,7 +295,9 @@ lzma_code(lzma_stream *strm, lzma_action action)
strm->internal->avail_in = strm->avail_in;
switch (ret) {
// Cast is needed to silence a warning about LZMA_TIMED_OUT, which
// isn't part of lzma_ret enumeration.
switch ((unsigned int)(ret)) {
case LZMA_OK:
// Don't return LZMA_BUF_ERROR when it happens the first time.
// This is to avoid returning LZMA_BUF_ERROR when avail_out
@@ -281,9 +313,16 @@ lzma_code(lzma_stream *strm, lzma_action action)
}
break;
case LZMA_TIMED_OUT:
strm->internal->allow_buf_error = false;
ret = LZMA_OK;
break;
case LZMA_STREAM_END:
if (strm->internal->sequence == ISEQ_SYNC_FLUSH
|| strm->internal->sequence == ISEQ_FULL_FLUSH)
|| strm->internal->sequence == ISEQ_FULL_FLUSH
|| strm->internal->sequence
== ISEQ_FULL_BARRIER)
strm->internal->sequence = ISEQ_RUN;
else
strm->internal->sequence = ISEQ_END;
@@ -323,6 +362,22 @@ lzma_end(lzma_stream *strm)
}
extern LZMA_API(void)
lzma_get_progress(lzma_stream *strm,
uint64_t *progress_in, uint64_t *progress_out)
{
if (strm->internal->next.get_progress != NULL) {
strm->internal->next.get_progress(strm->internal->next.coder,
progress_in, progress_out);
} else {
*progress_in = strm->total_in;
*progress_out = strm->total_out;
}
return;
}
extern LZMA_API(lzma_check)
lzma_get_check(const lzma_stream *strm)
{
@@ -380,8 +435,10 @@ lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
|| strm->internal->next.memconfig == NULL)
return LZMA_PROG_ERROR;
if (new_memlimit != 0 && new_memlimit < LZMA_MEMUSAGE_BASE)
return LZMA_MEMLIMIT_ERROR;
// Zero is a special value that cannot be used as an actual limit.
// If 0 was specified, use 1 instead.
if (new_memlimit == 0)
new_memlimit = 1;
return strm->internal->next.memconfig(strm->internal->next.coder,
&memusage, &old_memlimit, new_memlimit);

View File

@@ -48,6 +48,13 @@
#define LZMA_BUFFER_SIZE 4096
/// Maximum number of worker threads within one multithreaded component.
/// The limit exists solely to make it simpler to prevent integer overflows
/// when allocating structures etc. This should be big enough for now...
/// the code won't scale anywhere close to this number anyway.
#define LZMA_THREADS_MAX 16384
/// Starting value for memory usage estimates. Instead of calculating size
/// of _every_ structure and taking into account malloc() overhead etc., we
/// add a base size to all memory usage estimates. It's not very accurate
@@ -65,12 +72,20 @@
( LZMA_TELL_NO_CHECK \
| LZMA_TELL_UNSUPPORTED_CHECK \
| LZMA_TELL_ANY_CHECK \
| LZMA_IGNORE_CHECK \
| LZMA_CONCATENATED )
/// Type of encoder/decoder specific data; the actual structure is defined
/// differently in different coders.
typedef struct lzma_coder_s lzma_coder;
/// Largest valid lzma_action value as unsigned integer.
#define LZMA_ACTION_MAX ((unsigned int)(LZMA_FULL_BARRIER))
/// Special return value (lzma_ret) to indicate that a timeout was reached
/// and lzma_code() must not return LZMA_BUF_ERROR. This is converted to
/// LZMA_OK in lzma_code(). This is not in the lzma_ret enumeration because
/// there's no need to have it in the public API.
#define LZMA_TIMED_OUT 32
typedef struct lzma_next_coder_s lzma_next_coder;
@@ -79,7 +94,7 @@ 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,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters);
/// Type of a function to do some kind of coding work (filters, Stream,
@@ -87,7 +102,7 @@ typedef lzma_ret (*lzma_init_function)(
/// 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,
void *coder, const 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,
@@ -95,7 +110,7 @@ typedef lzma_ret (*lzma_code_function)(
/// Type of a function to free the memory allocated for the coder
typedef void (*lzma_end_function)(
lzma_coder *coder, lzma_allocator *allocator);
void *coder, const lzma_allocator *allocator);
/// Raw coder validates and converts an array of lzma_filter structures to
@@ -118,7 +133,7 @@ struct lzma_filter_info_s {
/// Hold data and function pointers of the next filter in the chain.
struct lzma_next_coder_s {
/// Pointer to coder-specific data
lzma_coder *coder;
void *coder;
/// Filter ID. This is LZMA_VLI_UNKNOWN when this structure doesn't
/// point to a filter coder.
@@ -138,18 +153,23 @@ struct lzma_next_coder_s {
/// lzma_next_coder.coder.
lzma_end_function end;
/// Pointer to a function to get progress information. If this is NULL,
/// lzma_stream.total_in and .total_out are used instead.
void (*get_progress)(void *coder,
uint64_t *progress_in, uint64_t *progress_out);
/// 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);
lzma_check (*get_check)(const void *coder);
/// Pointer to function to get and/or change the memory usage limit.
/// If new_memlimit == 0, the limit is not changed.
lzma_ret (*memconfig)(lzma_coder *coder, uint64_t *memusage,
lzma_ret (*memconfig)(void *coder, uint64_t *memusage,
uint64_t *old_memlimit, uint64_t new_memlimit);
/// Update the filter-specific options or the whole filter chain
/// in the encoder.
lzma_ret (*update)(lzma_coder *coder, lzma_allocator *allocator,
lzma_ret (*update)(void *coder, const lzma_allocator *allocator,
const lzma_filter *filters,
const lzma_filter *reversed_filters);
};
@@ -163,6 +183,7 @@ struct lzma_next_coder_s {
.id = LZMA_VLI_UNKNOWN, \
.code = NULL, \
.end = NULL, \
.get_progress = NULL, \
.get_check = NULL, \
.memconfig = NULL, \
.update = NULL, \
@@ -184,6 +205,7 @@ struct lzma_internal_s {
ISEQ_SYNC_FLUSH,
ISEQ_FULL_FLUSH,
ISEQ_FINISH,
ISEQ_FULL_BARRIER,
ISEQ_END,
ISEQ_ERROR,
} sequence;
@@ -194,7 +216,7 @@ struct lzma_internal_s {
size_t avail_in;
/// Indicates which lzma_action values are allowed by next.code.
bool supported_actions[4];
bool supported_actions[LZMA_ACTION_MAX + 1];
/// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
/// made (no input consumed and no output produced by next.code).
@@ -203,11 +225,17 @@ struct lzma_internal_s {
/// Allocates memory
extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
extern void *lzma_alloc(size_t size, const lzma_allocator *allocator)
lzma_attribute((__malloc__)) lzma_attr_alloc_size(1);
/// Allocates memory and zeroes it (like calloc()). This can be faster
/// than lzma_alloc() + memzero() while being backward compatible with
/// custom allocators.
extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
lzma_alloc_zero(size_t size, const lzma_allocator *allocator);
/// Frees memory
extern void lzma_free(void *ptr, lzma_allocator *allocator);
extern void lzma_free(void *ptr, const lzma_allocator *allocator);
/// Allocates strm->internal if it is NULL, and initializes *strm and
@@ -219,17 +247,19 @@ extern lzma_ret lzma_strm_init(lzma_stream *strm);
/// 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);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
/// Update the next filter in the chain, if any. This checks that
/// the application is not trying to change the Filter IDs.
extern lzma_ret lzma_next_filter_update(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *reversed_filters);
/// 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 void lzma_next_end(lzma_next_coder *next,
const lzma_allocator *allocator);
/// Copy as much data as possible from in[] to out[] and update *in_pos

View File

@@ -15,8 +15,8 @@
extern LZMA_API(lzma_ret)
lzma_easy_buffer_encode(uint32_t preset, lzma_check check,
lzma_allocator *allocator, const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
const lzma_allocator *allocator, const uint8_t *in,
size_t in_size, uint8_t *out, size_t *out_pos, size_t out_size)
{
lzma_options_easy opt_easy;
if (lzma_easy_preset(&opt_easy, preset))

View File

@@ -11,7 +11,6 @@
///////////////////////////////////////////////////////////////////////////////
#include "easy_preset.h"
#include "stream_encoder.h"
extern LZMA_API(lzma_ret)

View File

@@ -14,7 +14,8 @@
extern LZMA_API(lzma_ret)
lzma_raw_buffer_decode(const lzma_filter *filters, lzma_allocator *allocator,
lzma_raw_buffer_decode(
const lzma_filter *filters, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{

View File

@@ -14,9 +14,10 @@
extern LZMA_API(lzma_ret)
lzma_raw_buffer_encode(const lzma_filter *filters, lzma_allocator *allocator,
const uint8_t *in, size_t in_size, uint8_t *out,
size_t *out_pos, size_t out_size)
lzma_raw_buffer_encode(
const lzma_filter *filters, const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{
// Validate what isn't validated later in filter_common.c.
if ((in == NULL && in_size != 0) || out == NULL

View File

@@ -123,7 +123,7 @@ static const struct {
extern LZMA_API(lzma_ret)
lzma_filters_copy(const lzma_filter *src, lzma_filter *dest,
lzma_allocator *allocator)
const lzma_allocator *allocator)
{
if (src == NULL || dest == NULL)
return LZMA_PROG_ERROR;
@@ -239,7 +239,7 @@ validate_chain(const lzma_filter *filters, size_t *count)
extern lzma_ret
lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_raw_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *options,
lzma_filter_find coder_find, bool is_encoder)
{

View File

@@ -36,7 +36,7 @@ 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,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *filters,
lzma_filter_find coder_find, bool is_encoder);

View File

@@ -35,7 +35,8 @@ typedef struct {
/// \return - LZMA_OK: Properties decoded successfully.
/// - LZMA_OPTIONS_ERROR: Unsupported properties
/// - LZMA_MEM_ERROR: Memory allocation failed.
lzma_ret (*props_decode)(void **options, lzma_allocator *allocator,
lzma_ret (*props_decode)(
void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
} lzma_filter_decoder;
@@ -136,7 +137,7 @@ lzma_filter_decoder_is_supported(lzma_vli id)
extern lzma_ret
lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_raw_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *options)
{
return lzma_raw_coder_init(next, allocator,
@@ -165,7 +166,7 @@ lzma_raw_decoder_memusage(const lzma_filter *filters)
extern LZMA_API(lzma_ret)
lzma_properties_decode(lzma_filter *filter, lzma_allocator *allocator,
lzma_properties_decode(lzma_filter *filter, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
// Make it always NULL so that the caller can always safely free() it.

View File

@@ -17,7 +17,7 @@
extern lzma_ret lzma_raw_decoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *options);
#endif

View File

@@ -30,11 +30,11 @@ typedef struct {
/// 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 split 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);
/// Calculates the recommended Uncompressed Size for .xz Blocks to
/// which the input data can be split to make multithreaded
/// encoding possible. If this is NULL, it is assumed that
/// the encoder is fast enough with single thread.
uint64_t (*block_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
@@ -59,7 +59,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_LZMA1,
.init = &lzma_lzma_encoder_init,
.memusage = &lzma_lzma_encoder_memusage,
.chunk_size = NULL, // FIXME
.block_size = NULL, // FIXME
.props_size_get = NULL,
.props_size_fixed = 5,
.props_encode = &lzma_lzma_props_encode,
@@ -70,7 +70,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_LZMA2,
.init = &lzma_lzma2_encoder_init,
.memusage = &lzma_lzma2_encoder_memusage,
.chunk_size = NULL, // FIXME
.block_size = &lzma_lzma2_block_size, // FIXME
.props_size_get = NULL,
.props_size_fixed = 1,
.props_encode = &lzma_lzma2_props_encode,
@@ -81,7 +81,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_X86,
.init = &lzma_simple_x86_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -91,7 +91,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_POWERPC,
.init = &lzma_simple_powerpc_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -101,7 +101,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_IA64,
.init = &lzma_simple_ia64_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -111,7 +111,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_ARM,
.init = &lzma_simple_arm_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -121,7 +121,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_ARMTHUMB,
.init = &lzma_simple_armthumb_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -131,7 +131,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_SPARC,
.init = &lzma_simple_sparc_encoder_init,
.memusage = NULL,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = &lzma_simple_props_size,
.props_encode = &lzma_simple_props_encode,
},
@@ -141,7 +141,7 @@ static const lzma_filter_encoder encoders[] = {
.id = LZMA_FILTER_DELTA,
.init = &lzma_delta_encoder_init,
.memusage = &lzma_delta_coder_memusage,
.chunk_size = NULL,
.block_size = NULL,
.props_size_get = NULL,
.props_size_fixed = 1,
.props_encode = &lzma_delta_props_encode,
@@ -196,7 +196,7 @@ lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
extern lzma_ret
lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_raw_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *options)
{
return lzma_raw_coder_init(next, allocator,
@@ -226,20 +226,19 @@ lzma_raw_encoder_memusage(const lzma_filter *filters)
}
/*
extern LZMA_API(lzma_vli)
lzma_chunk_size(const lzma_filter *filters)
extern uint64_t
lzma_mt_block_size(const lzma_filter *filters)
{
lzma_vli max = 0;
uint64_t max = 0;
for (size_t i = 0; filters[i].id != LZMA_VLI_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_UNKNOWN)
return LZMA_VLI_UNKNOWN;
if (fe->block_size != NULL) {
const uint64_t size
= fe->block_size(filters[i].options);
if (size == 0)
return 0;
if (size > max)
max = size;
@@ -248,7 +247,6 @@ lzma_chunk_size(const lzma_filter *filters)
return max;
}
*/
extern LZMA_API(lzma_ret)

View File

@@ -16,12 +16,12 @@
#include "common.h"
// FIXME: Might become a part of the public API once finished.
// extern lzma_vli lzma_chunk_size(const lzma_filter *filters);
// FIXME: Might become a part of the public API.
extern uint64_t lzma_mt_block_size(const lzma_filter *filters);
extern lzma_ret lzma_raw_encoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *filters);
#endif

View File

@@ -15,7 +15,7 @@
extern LZMA_API(lzma_ret)
lzma_filter_flags_decode(
lzma_filter *filter, lzma_allocator *allocator,
lzma_filter *filter, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
// Set the pointer to NULL so the caller can always safely free it.

View File

@@ -1,7 +1,7 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file stream_encoder.h
/// \brief Encodes .xz Streams
/// \file hardware_cputhreads.c
/// \brief Get the number of CPU threads or cores
//
// Author: Lasse Collin
//
@@ -10,14 +10,13 @@
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_STREAM_ENCODER_H
#define LZMA_STREAM_ENCODER_H
#include "common.h"
#include "tuklib_cpucores.h"
extern lzma_ret lzma_stream_encoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
const lzma_filter *filters, lzma_check check);
#endif
extern LZMA_API(uint32_t)
lzma_cputhreads(void)
{
return tuklib_cpucores();
}

View File

@@ -191,8 +191,8 @@ index_tree_init(index_tree *tree)
/// Helper for index_tree_end()
static void
index_tree_node_end(index_tree_node *node, lzma_allocator *allocator,
void (*free_func)(void *node, lzma_allocator *allocator))
index_tree_node_end(index_tree_node *node, const lzma_allocator *allocator,
void (*free_func)(void *node, const lzma_allocator *allocator))
{
// The tree won't ever be very huge, so recursion should be fine.
// 20 levels in the tree is likely quite a lot already in practice.
@@ -202,22 +202,21 @@ index_tree_node_end(index_tree_node *node, lzma_allocator *allocator,
if (node->right != NULL)
index_tree_node_end(node->right, allocator, free_func);
if (free_func != NULL)
free_func(node, allocator);
lzma_free(node, allocator);
free_func(node, allocator);
return;
}
/// Free the meory allocated for a tree. If free_func is not NULL,
/// it is called on each node before freeing the node. This is used
/// to free the Record groups from each index_stream before freeing
/// the index_stream itself.
/// Free the memory allocated for a tree. Each node is freed using the
/// given free_func which is either &lzma_free or &index_stream_end.
/// The latter is used to free the Record groups from each index_stream
/// before freeing the index_stream itself.
static void
index_tree_end(index_tree *tree, lzma_allocator *allocator,
void (*free_func)(void *node, lzma_allocator *allocator))
index_tree_end(index_tree *tree, const lzma_allocator *allocator,
void (*free_func)(void *node, const lzma_allocator *allocator))
{
assert(free_func != NULL);
if (tree->root != NULL)
index_tree_node_end(tree->root, allocator, free_func);
@@ -339,8 +338,8 @@ index_tree_locate(const index_tree *tree, lzma_vli target)
/// Allocate and initialize a new Stream using the given base offsets.
static index_stream *
index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base,
lzma_vli stream_number, lzma_vli block_number_base,
lzma_allocator *allocator)
uint32_t stream_number, lzma_vli block_number_base,
const lzma_allocator *allocator)
{
index_stream *s = lzma_alloc(sizeof(index_stream), allocator);
if (s == NULL)
@@ -368,16 +367,17 @@ index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base,
/// Free the memory allocated for a Stream and its Record groups.
static void
index_stream_end(void *node, lzma_allocator *allocator)
index_stream_end(void *node, const lzma_allocator *allocator)
{
index_stream *s = node;
index_tree_end(&s->groups, allocator, NULL);
index_tree_end(&s->groups, allocator, &lzma_free);
lzma_free(s, allocator);
return;
}
static lzma_index *
index_init_plain(lzma_allocator *allocator)
index_init_plain(const lzma_allocator *allocator)
{
lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
if (i != NULL) {
@@ -395,7 +395,7 @@ index_init_plain(lzma_allocator *allocator)
extern LZMA_API(lzma_index *)
lzma_index_init(lzma_allocator *allocator)
lzma_index_init(const lzma_allocator *allocator)
{
lzma_index *i = index_init_plain(allocator);
if (i == NULL)
@@ -414,7 +414,7 @@ lzma_index_init(lzma_allocator *allocator)
extern LZMA_API(void)
lzma_index_end(lzma_index *i, lzma_allocator *allocator)
lzma_index_end(lzma_index *i, const lzma_allocator *allocator)
{
// NOTE: If you modify this function, check also the bottom
// of lzma_index_cat().
@@ -637,7 +637,7 @@ lzma_index_stream_padding(lzma_index *i, lzma_vli stream_padding)
extern LZMA_API(lzma_ret)
lzma_index_append(lzma_index *i, lzma_allocator *allocator,
lzma_index_append(lzma_index *i, const lzma_allocator *allocator,
lzma_vli unpadded_size, lzma_vli uncompressed_size)
{
// Validate.
@@ -765,7 +765,7 @@ index_cat_helper(const index_cat_info *info, index_stream *this)
extern LZMA_API(lzma_ret)
lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
lzma_allocator *allocator)
const lzma_allocator *allocator)
{
const lzma_vli dest_file_size = lzma_index_file_size(dest);
@@ -829,6 +829,9 @@ lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
s->groups.rightmost = &newg->node;
lzma_free(g, allocator);
// NOTE: newg isn't leaked here because
// newg == (void *)&newg->node.
}
}
@@ -859,7 +862,7 @@ lzma_index_cat(lzma_index *restrict dest, lzma_index *restrict src,
/// Duplicate an index_stream.
static index_stream *
index_dup_stream(const index_stream *src, lzma_allocator *allocator)
index_dup_stream(const index_stream *src, const lzma_allocator *allocator)
{
// Catch a somewhat theoretical integer overflow.
if (src->record_count > PREALLOC_MAX)
@@ -869,11 +872,8 @@ index_dup_stream(const index_stream *src, lzma_allocator *allocator)
index_stream *dest = index_stream_init(src->node.compressed_base,
src->node.uncompressed_base, src->number,
src->block_number_base, allocator);
// Return immediately if allocation failed or if there are
// no groups to duplicate.
if (dest == NULL || src->groups.leftmost == NULL)
return dest;
if (dest == NULL)
return NULL;
// Copy the overall information.
dest->record_count = src->record_count;
@@ -881,6 +881,10 @@ index_dup_stream(const index_stream *src, lzma_allocator *allocator)
dest->stream_flags = src->stream_flags;
dest->stream_padding = src->stream_padding;
// Return if there are no groups to duplicate.
if (src->groups.leftmost == NULL)
return dest;
// Allocate memory for the Records. We put all the Records into
// a single group. It's simplest and also tends to make
// lzma_index_locate() a little bit faster with very big Indexes.
@@ -919,7 +923,7 @@ index_dup_stream(const index_stream *src, lzma_allocator *allocator)
extern LZMA_API(lzma_index *)
lzma_index_dup(const lzma_index *src, lzma_allocator *allocator)
lzma_index_dup(const lzma_index *src, const lzma_allocator *allocator)
{
// Allocate the base structure (no initial Stream).
lzma_index *dest = index_init_plain(allocator);
@@ -1008,6 +1012,8 @@ iter_set_info(lzma_index_iter *iter)
iter->internal[ITER_GROUP].p = NULL;
}
// NOTE: lzma_index_iter.stream.number is lzma_vli but we use uint32_t
// internally.
iter->stream.number = stream->number;
iter->stream.block_count = stream->record_count;
iter->stream.compressed_offset = stream->node.compressed_base;

View File

@@ -14,7 +14,7 @@
#include "check.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_INDICATOR,
SEQ_COUNT,
@@ -50,11 +50,11 @@ struct lzma_coder_s {
/// CRC32 of the List of Records field
uint32_t crc32;
};
} lzma_index_coder;
static lzma_ret
index_decode(lzma_coder *coder, lzma_allocator *allocator,
index_decode(void *coder_ptr, const lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size,
uint8_t *restrict out lzma_attribute((__unused__)),
@@ -62,6 +62,8 @@ index_decode(lzma_coder *coder, lzma_allocator *allocator,
size_t out_size lzma_attribute((__unused__)),
lzma_action action lzma_attribute((__unused__)))
{
lzma_index_coder *coder = coder_ptr;
// Similar optimization as in index_encoder.c
const size_t in_start = *in_pos;
lzma_ret ret = LZMA_OK;
@@ -207,8 +209,9 @@ out:
static void
index_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
index_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_index_coder *coder = coder_ptr;
lzma_index_end(coder->index, allocator);
lzma_free(coder, allocator);
return;
@@ -216,9 +219,11 @@ index_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
index_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
uint64_t *old_memlimit, uint64_t new_memlimit)
{
lzma_index_coder *coder = coder_ptr;
*memusage = lzma_index_memusage(1, coder->count);
*old_memlimit = coder->memlimit;
@@ -234,7 +239,7 @@ index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
static lzma_ret
index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
index_decoder_reset(lzma_index_coder *coder, const lzma_allocator *allocator,
lzma_index **i, uint64_t memlimit)
{
// Remember the pointer given by the application. We will set it
@@ -251,7 +256,7 @@ index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
// Initialize the rest.
coder->sequence = SEQ_INDICATOR;
coder->memlimit = memlimit;
coder->memlimit = my_max(1, memlimit);
coder->count = 0; // Needs to be initialized due to _memconfig().
coder->pos = 0;
coder->crc32 = 0;
@@ -261,28 +266,30 @@ index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
static lzma_ret
index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
index_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
lzma_index **i, uint64_t memlimit)
{
lzma_next_coder_init(&index_decoder_init, next, allocator);
if (i == NULL || memlimit == 0)
if (i == NULL)
return LZMA_PROG_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_index_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &index_decode;
next->end = &index_decoder_end;
next->memconfig = &index_decoder_memconfig;
next->coder->index = NULL;
coder->index = NULL;
} else {
lzma_index_end(next->coder->index, allocator);
lzma_index_end(coder->index, allocator);
}
return index_decoder_reset(next->coder, allocator, i, memlimit);
return index_decoder_reset(coder, allocator, i, memlimit);
}
@@ -299,8 +306,8 @@ lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
extern LZMA_API(lzma_ret)
lzma_index_buffer_decode(
lzma_index **i, uint64_t *memlimit, lzma_allocator *allocator,
lzma_index_buffer_decode(lzma_index **i, uint64_t *memlimit,
const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size)
{
// Sanity checks
@@ -309,7 +316,7 @@ lzma_index_buffer_decode(
return LZMA_PROG_ERROR;
// Initialize the decoder.
lzma_coder coder;
lzma_index_coder coder;
return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));
// Store the input start position so that we can restore it in case

View File

@@ -15,7 +15,7 @@
#include "check.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_INDICATOR,
SEQ_COUNT,
@@ -37,12 +37,12 @@ struct lzma_coder_s {
/// CRC32 of the List of Records field
uint32_t crc32;
};
} lzma_index_coder;
static lzma_ret
index_encode(lzma_coder *coder,
lzma_allocator *allocator lzma_attribute((__unused__)),
index_encode(void *coder_ptr,
const lzma_allocator *allocator lzma_attribute((__unused__)),
const uint8_t *restrict in lzma_attribute((__unused__)),
size_t *restrict in_pos lzma_attribute((__unused__)),
size_t in_size lzma_attribute((__unused__)),
@@ -50,6 +50,8 @@ index_encode(lzma_coder *coder,
size_t out_size,
lzma_action action lzma_attribute((__unused__)))
{
lzma_index_coder *coder = coder_ptr;
// Position where to start calculating CRC32. The idea is that we
// need to call lzma_crc32() only once per call to index_encode().
const size_t out_start = *out_pos;
@@ -159,7 +161,7 @@ out:
static void
index_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
index_encoder_end(void *coder, const lzma_allocator *allocator)
{
lzma_free(coder, allocator);
return;
@@ -167,7 +169,7 @@ index_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
static void
index_encoder_reset(lzma_coder *coder, const lzma_index *i)
index_encoder_reset(lzma_index_coder *coder, const lzma_index *i)
{
lzma_index_iter_init(&coder->iter, i);
@@ -181,7 +183,7 @@ index_encoder_reset(lzma_coder *coder, const lzma_index *i)
extern lzma_ret
lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_index_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_index *i)
{
lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
@@ -190,7 +192,7 @@ lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
return LZMA_PROG_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
next->coder = lzma_alloc(sizeof(lzma_index_coder), allocator);
if (next->coder == NULL)
return LZMA_MEM_ERROR;
@@ -230,7 +232,7 @@ lzma_index_buffer_encode(const lzma_index *i,
// The Index encoder needs just one small data structure so we can
// allocate it on stack.
lzma_coder coder;
lzma_index_coder coder;
index_encoder_reset(&coder, i);
// Do the actual encoding. This should never fail, but store

View File

@@ -17,7 +17,7 @@
extern lzma_ret lzma_index_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_index *i);
const lzma_allocator *allocator, const lzma_index *i);
#endif

View File

@@ -70,7 +70,8 @@ struct lzma_index_hash_s {
extern LZMA_API(lzma_index_hash *)
lzma_index_hash_init(lzma_index_hash *index_hash, lzma_allocator *allocator)
lzma_index_hash_init(lzma_index_hash *index_hash,
const lzma_allocator *allocator)
{
if (index_hash == NULL) {
index_hash = lzma_alloc(sizeof(lzma_index_hash), allocator);
@@ -101,7 +102,8 @@ lzma_index_hash_init(lzma_index_hash *index_hash, lzma_allocator *allocator)
extern LZMA_API(void)
lzma_index_hash_end(lzma_index_hash *index_hash, lzma_allocator *allocator)
lzma_index_hash_end(lzma_index_hash *index_hash,
const lzma_allocator *allocator)
{
lzma_free(index_hash, allocator);
return;

View File

@@ -0,0 +1,175 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file memcmplen.h
/// \brief Optimized comparison of two buffers
//
// Author: Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef LZMA_MEMCMPLEN_H
#define LZMA_MEMCMPLEN_H
#include "common.h"
#ifdef HAVE_IMMINTRIN_H
# include <immintrin.h>
#endif
/// Find out how many equal bytes the two buffers have.
///
/// \param buf1 First buffer
/// \param buf2 Second buffer
/// \param len How many bytes have already been compared and will
/// be assumed to match
/// \param limit How many bytes to compare at most, including the
/// already-compared bytes. This must be significantly
/// smaller than UINT32_MAX to avoid integer overflows.
/// Up to LZMA_MEMCMPLEN_EXTRA bytes may be read past
/// the specified limit from both buf1 and buf2.
///
/// \return Number of equal bytes in the buffers is returned.
/// This is always at least len and at most limit.
///
/// \note LZMA_MEMCMPLEN_EXTRA defines how many extra bytes may be read.
/// It's rounded up to 2^n. This extra amount needs to be
/// allocated in the buffers being used. It needs to be
/// initialized too to keep Valgrind quiet.
static inline uint32_t lzma_attribute((__always_inline__))
lzma_memcmplen(const uint8_t *buf1, const uint8_t *buf2,
uint32_t len, uint32_t limit)
{
assert(len <= limit);
assert(limit <= UINT32_MAX / 2);
#if defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
&& ((TUKLIB_GNUC_REQ(3, 4) && defined(__x86_64__)) \
|| (defined(__INTEL_COMPILER) && defined(__x86_64__)) \
|| (defined(__INTEL_COMPILER) && defined(_M_X64)) \
|| (defined(_MSC_VER) && defined(_M_X64)))
// NOTE: This will use 64-bit unaligned access which
// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit, but
// it's convenient here at least as long as it's x86-64 only.
//
// I keep this x86-64 only for now since that's where I know this
// to be a good method. This may be fine on other 64-bit CPUs too.
// On big endian one should use xor instead of subtraction and switch
// to __builtin_clzll().
#define LZMA_MEMCMPLEN_EXTRA 8
while (len < limit) {
const uint64_t x = *(const uint64_t *)(buf1 + len)
- *(const uint64_t *)(buf2 + len);
if (x != 0) {
# if defined(_M_X64) // MSVC or Intel C compiler on Windows
unsigned long tmp;
_BitScanForward64(&tmp, x);
len += (uint32_t)tmp >> 3;
# else // GCC, clang, or Intel C compiler
len += (uint32_t)__builtin_ctzll(x) >> 3;
# endif
return my_min(len, limit);
}
len += 8;
}
return limit;
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) \
&& defined(HAVE__MM_MOVEMASK_EPI8) \
&& ((defined(__GNUC__) && defined(__SSE2_MATH__)) \
|| (defined(__INTEL_COMPILER) && defined(__SSE2__)) \
|| (defined(_MSC_VER) && defined(_M_IX86_FP) \
&& _M_IX86_FP >= 2))
// NOTE: Like above, this will use 128-bit unaligned access which
// TUKLIB_FAST_UNALIGNED_ACCESS wasn't meant to permit.
//
// SSE2 version for 32-bit and 64-bit x86. On x86-64 the above
// version is sometimes significantly faster and sometimes
// slightly slower than this SSE2 version, so this SSE2
// version isn't used on x86-64.
# define LZMA_MEMCMPLEN_EXTRA 16
while (len < limit) {
const uint32_t x = 0xFFFF ^ _mm_movemask_epi8(_mm_cmpeq_epi8(
_mm_loadu_si128((const __m128i *)(buf1 + len)),
_mm_loadu_si128((const __m128i *)(buf2 + len))));
if (x != 0) {
# if defined(__INTEL_COMPILER)
len += _bit_scan_forward(x);
# elif defined(_MSC_VER)
unsigned long tmp;
_BitScanForward(&tmp, x);
len += tmp;
# else
len += __builtin_ctz(x);
# endif
return my_min(len, limit);
}
len += 16;
}
return limit;
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && !defined(WORDS_BIGENDIAN)
// Generic 32-bit little endian method
# define LZMA_MEMCMPLEN_EXTRA 4
while (len < limit) {
uint32_t x = *(const uint32_t *)(buf1 + len)
- *(const uint32_t *)(buf2 + len);
if (x != 0) {
if ((x & 0xFFFF) == 0) {
len += 2;
x >>= 16;
}
if ((x & 0xFF) == 0)
++len;
return my_min(len, limit);
}
len += 4;
}
return limit;
#elif defined(TUKLIB_FAST_UNALIGNED_ACCESS) && defined(WORDS_BIGENDIAN)
// Generic 32-bit big endian method
# define LZMA_MEMCMPLEN_EXTRA 4
while (len < limit) {
uint32_t x = *(const uint32_t *)(buf1 + len)
^ *(const uint32_t *)(buf2 + len);
if (x != 0) {
if ((x & 0xFFFF0000) == 0) {
len += 2;
x <<= 16;
}
if ((x & 0xFF000000) == 0)
++len;
return my_min(len, limit);
}
len += 4;
}
return limit;
#else
// Simple portable version that doesn't use unaligned access.
# define LZMA_MEMCMPLEN_EXTRA 0
while (len < limit && buf1[len] == buf2[len])
++len;
return len;
#endif
}
#endif

View File

@@ -0,0 +1,184 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file outqueue.c
/// \brief Output queue handling in multithreaded coding
//
// Author: Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#include "outqueue.h"
/// This is to ease integer overflow checking: We may allocate up to
/// 2 * LZMA_THREADS_MAX buffers and we need some extra memory for other
/// data structures (that's the second /2).
#define BUF_SIZE_MAX (UINT64_MAX / LZMA_THREADS_MAX / 2 / 2)
static lzma_ret
get_options(uint64_t *bufs_alloc_size, uint32_t *bufs_count,
uint64_t buf_size_max, uint32_t threads)
{
if (threads > LZMA_THREADS_MAX || buf_size_max > BUF_SIZE_MAX)
return LZMA_OPTIONS_ERROR;
// The number of buffers is twice the number of threads.
// This wastes RAM but keeps the threads busy when buffers
// finish out of order.
//
// NOTE: If this is changed, update BUF_SIZE_MAX too.
*bufs_count = threads * 2;
*bufs_alloc_size = *bufs_count * buf_size_max;
return LZMA_OK;
}
extern uint64_t
lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads)
{
uint64_t bufs_alloc_size;
uint32_t bufs_count;
if (get_options(&bufs_alloc_size, &bufs_count, buf_size_max, threads)
!= LZMA_OK)
return UINT64_MAX;
return sizeof(lzma_outq) + bufs_count * sizeof(lzma_outbuf)
+ bufs_alloc_size;
}
extern lzma_ret
lzma_outq_init(lzma_outq *outq, const lzma_allocator *allocator,
uint64_t buf_size_max, uint32_t threads)
{
uint64_t bufs_alloc_size;
uint32_t bufs_count;
// Set bufs_count and bufs_alloc_size.
return_if_error(get_options(&bufs_alloc_size, &bufs_count,
buf_size_max, threads));
// Allocate memory if needed.
if (outq->buf_size_max != buf_size_max
|| outq->bufs_allocated != bufs_count) {
lzma_outq_end(outq, allocator);
#if SIZE_MAX < UINT64_MAX
if (bufs_alloc_size > SIZE_MAX)
return LZMA_MEM_ERROR;
#endif
outq->bufs = lzma_alloc(bufs_count * sizeof(lzma_outbuf),
allocator);
outq->bufs_mem = lzma_alloc((size_t)(bufs_alloc_size),
allocator);
if (outq->bufs == NULL || outq->bufs_mem == NULL) {
lzma_outq_end(outq, allocator);
return LZMA_MEM_ERROR;
}
}
// Initialize the rest of the main structure. Initialization of
// outq->bufs[] is done when they are actually needed.
outq->buf_size_max = (size_t)(buf_size_max);
outq->bufs_allocated = bufs_count;
outq->bufs_pos = 0;
outq->bufs_used = 0;
outq->read_pos = 0;
return LZMA_OK;
}
extern void
lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator)
{
lzma_free(outq->bufs, allocator);
outq->bufs = NULL;
lzma_free(outq->bufs_mem, allocator);
outq->bufs_mem = NULL;
return;
}
extern lzma_outbuf *
lzma_outq_get_buf(lzma_outq *outq)
{
// Caller must have checked it with lzma_outq_has_buf().
assert(outq->bufs_used < outq->bufs_allocated);
// Initialize the new buffer.
lzma_outbuf *buf = &outq->bufs[outq->bufs_pos];
buf->buf = outq->bufs_mem + outq->bufs_pos * outq->buf_size_max;
buf->size = 0;
buf->finished = false;
// Update the queue state.
if (++outq->bufs_pos == outq->bufs_allocated)
outq->bufs_pos = 0;
++outq->bufs_used;
return buf;
}
extern bool
lzma_outq_is_readable(const lzma_outq *outq)
{
uint32_t i = outq->bufs_pos - outq->bufs_used;
if (outq->bufs_pos < outq->bufs_used)
i += outq->bufs_allocated;
return outq->bufs[i].finished;
}
extern lzma_ret
lzma_outq_read(lzma_outq *restrict outq, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size,
lzma_vli *restrict unpadded_size,
lzma_vli *restrict uncompressed_size)
{
// There must be at least one buffer from which to read.
if (outq->bufs_used == 0)
return LZMA_OK;
// Get the buffer.
uint32_t i = outq->bufs_pos - outq->bufs_used;
if (outq->bufs_pos < outq->bufs_used)
i += outq->bufs_allocated;
lzma_outbuf *buf = &outq->bufs[i];
// If it isn't finished yet, we cannot read from it.
if (!buf->finished)
return LZMA_OK;
// Copy from the buffer to output.
lzma_bufcpy(buf->buf, &outq->read_pos, buf->size,
out, out_pos, out_size);
// Return if we didn't get all the data from the buffer.
if (outq->read_pos < buf->size)
return LZMA_OK;
// The buffer was finished. Tell the caller its size information.
*unpadded_size = buf->unpadded_size;
*uncompressed_size = buf->uncompressed_size;
// Free this buffer for further use.
--outq->bufs_used;
outq->read_pos = 0;
return LZMA_STREAM_END;
}

View File

@@ -0,0 +1,156 @@
///////////////////////////////////////////////////////////////////////////////
//
/// \file outqueue.h
/// \brief Output queue handling in multithreaded coding
//
// Author: Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#include "common.h"
/// Output buffer for a single thread
typedef struct {
/// Pointer to the output buffer of lzma_outq.buf_size_max bytes
uint8_t *buf;
/// Amount of data written to buf
size_t size;
/// Additional size information
lzma_vli unpadded_size;
lzma_vli uncompressed_size;
/// True when no more data will be written into this buffer.
///
/// \note This is read by another thread and thus access
/// to this variable needs a mutex.
bool finished;
} lzma_outbuf;
typedef struct {
/// Array of buffers that are used cyclically.
lzma_outbuf *bufs;
/// Memory allocated for all the buffers
uint8_t *bufs_mem;
/// Amount of buffer space available in each buffer
size_t buf_size_max;
/// Number of buffers allocated
uint32_t bufs_allocated;
/// Position in the bufs array. The next buffer to be taken
/// into use is bufs[bufs_pos].
uint32_t bufs_pos;
/// Number of buffers in use
uint32_t bufs_used;
/// Position in the buffer in lzma_outq_read()
size_t read_pos;
} lzma_outq;
/**
* \brief Calculate the memory usage of an output queue
*
* \return Approximate memory usage in bytes or UINT64_MAX on error.
*/
extern uint64_t lzma_outq_memusage(uint64_t buf_size_max, uint32_t threads);
/// \brief Initialize an output queue
///
/// \param outq Pointer to an output queue. Before calling
/// this function the first time, *outq should
/// have been zeroed with memzero() so that this
/// function knows that there are no previous
/// allocations to free.
/// \param allocator Pointer to allocator or NULL
/// \param buf_size_max Maximum amount of data that a single buffer
/// in the queue may need to store.
/// \param threads Number of buffers that may be in use
/// concurrently. Note that more than this number
/// of buffers will actually get allocated to
/// improve performance when buffers finish
/// out of order.
///
/// \return - LZMA_OK
/// - LZMA_MEM_ERROR
///
extern lzma_ret lzma_outq_init(
lzma_outq *outq, const lzma_allocator *allocator,
uint64_t buf_size_max, uint32_t threads);
/// \brief Free the memory associated with the output queue
extern void lzma_outq_end(lzma_outq *outq, const lzma_allocator *allocator);
/// \brief Get a new buffer
///
/// lzma_outq_has_buf() must be used to check that there is a buffer
/// available before calling lzma_outq_get_buf().
///
extern lzma_outbuf *lzma_outq_get_buf(lzma_outq *outq);
/// \brief Test if there is data ready to be read
///
/// Call to this function must be protected with the same mutex that
/// is used to protect lzma_outbuf.finished.
///
extern bool lzma_outq_is_readable(const lzma_outq *outq);
/// \brief Read finished data
///
/// \param outq Pointer to an output queue
/// \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].
/// \param unpadded_size Unpadded Size from the Block encoder
/// \param uncompressed_size Uncompressed Size from the Block encoder
///
/// \return - LZMA: All OK. Either no data was available or the buffer
/// being read didn't become empty yet.
/// - LZMA_STREAM_END: The buffer being read was finished.
/// *unpadded_size and *uncompressed_size were set.
///
/// \note This reads lzma_outbuf.finished variables and thus call
/// to this function needs to be protected with a mutex.
///
extern lzma_ret lzma_outq_read(lzma_outq *restrict outq,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size, lzma_vli *restrict unpadded_size,
lzma_vli *restrict uncompressed_size);
/// \brief Test if there is at least one buffer free
///
/// This must be used before getting a new buffer with lzma_outq_get_buf().
///
static inline bool
lzma_outq_has_buf(const lzma_outq *outq)
{
return outq->bufs_used < outq->bufs_allocated;
}
/// \brief Test if the queue is completely empty
static inline bool
lzma_outq_is_empty(const lzma_outq *outq)
{
return outq->bufs_used == 0;
}

View File

@@ -15,7 +15,7 @@
extern LZMA_API(lzma_ret)
lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
lzma_allocator *allocator,
const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
uint8_t *out, size_t *out_pos, size_t out_size)
{

View File

@@ -42,7 +42,8 @@ lzma_stream_buffer_bound(size_t uncompressed_size)
extern LZMA_API(lzma_ret)
lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
lzma_allocator *allocator, const uint8_t *in, size_t in_size,
const lzma_allocator *allocator,
const uint8_t *in, size_t in_size,
uint8_t *out, size_t *out_pos_ptr, size_t out_size)
{
// Sanity checks

View File

@@ -14,7 +14,7 @@
#include "block_decoder.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_STREAM_HEADER,
SEQ_BLOCK_HEADER,
@@ -57,6 +57,10 @@ struct lzma_coder_s {
/// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
bool tell_any_check;
/// If true, we will tell the Block decoder to skip calculating
/// and verifying the integrity check.
bool ignore_check;
/// If true, we will decode concatenated Streams that possibly have
/// Stream Padding between or after them. LZMA_STREAM_END is returned
/// once the application isn't giving us any new input, and we aren't
@@ -76,11 +80,11 @@ struct lzma_coder_s {
/// Buffer to hold Stream Header, Block Header, and Stream Footer.
/// Block Header has biggest maximum size.
uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
};
} lzma_stream_coder;
static lzma_ret
stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator)
stream_decoder_reset(lzma_stream_coder *coder, const lzma_allocator *allocator)
{
// Initialize the Index hash used to verify the Index.
coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
@@ -96,11 +100,13 @@ stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
stream_decode(lzma_coder *coder, lzma_allocator *allocator,
stream_decode(void *coder_ptr, const 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)
{
lzma_stream_coder *coder = coder_ptr;
// When decoding the actual Block, it may be able to produce more
// output even if we don't give it any new input.
while (true)
@@ -182,8 +188,8 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator,
coder->pos = 0;
// Version 0 is currently the only possible version.
coder->block_options.version = 0;
// Version 1 is needed to support the .ignore_check option.
coder->block_options.version = 1;
// Set up a buffer to hold the filter chain. Block Header
// decoder will initialize all members of this array so
@@ -195,6 +201,11 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator,
return_if_error(lzma_block_header_decode(&coder->block_options,
allocator, coder->buffer));
// If LZMA_IGNORE_CHECK was used, this flag needs to be set.
// It has to be set after lzma_block_header_decode() because
// it always resets this to false.
coder->block_options.ignore_check = coder->ignore_check;
// Check the memory usage limit.
const uint64_t memusage = lzma_raw_decoder_memusage(filters);
lzma_ret ret;
@@ -366,8 +377,9 @@ stream_decode(lzma_coder *coder, lzma_allocator *allocator,
static void
stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
stream_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_stream_coder *coder = coder_ptr;
lzma_next_end(&coder->block_decoder, allocator);
lzma_index_hash_end(coder->index_hash, allocator);
lzma_free(coder, allocator);
@@ -376,16 +388,19 @@ stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_check
stream_decoder_get_check(const lzma_coder *coder)
stream_decoder_get_check(const void *coder_ptr)
{
const lzma_stream_coder *coder = coder_ptr;
return coder->stream_flags.check;
}
static lzma_ret
stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
stream_decoder_memconfig(void *coder_ptr, uint64_t *memusage,
uint64_t *old_memlimit, uint64_t new_memlimit)
{
lzma_stream_coder *coder = coder_ptr;
*memusage = coder->memusage;
*old_memlimit = coder->memlimit;
@@ -401,41 +416,42 @@ stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
extern lzma_ret
lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_stream_decoder_init(
lzma_next_coder *next, const lzma_allocator *allocator,
uint64_t memlimit, uint32_t flags)
{
lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator);
if (memlimit == 0)
return LZMA_PROG_ERROR;
if (flags & ~LZMA_SUPPORTED_FLAGS)
return LZMA_OPTIONS_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_stream_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &stream_decode;
next->end = &stream_decoder_end;
next->get_check = &stream_decoder_get_check;
next->memconfig = &stream_decoder_memconfig;
next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
next->coder->index_hash = NULL;
coder->block_decoder = LZMA_NEXT_CODER_INIT;
coder->index_hash = NULL;
}
next->coder->memlimit = memlimit;
next->coder->memusage = LZMA_MEMUSAGE_BASE;
next->coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
next->coder->tell_unsupported_check
coder->memlimit = my_max(1, memlimit);
coder->memusage = LZMA_MEMUSAGE_BASE;
coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
coder->tell_unsupported_check
= (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
next->coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
next->coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
next->coder->first_stream = true;
coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0;
coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
coder->first_stream = true;
return stream_decoder_reset(next->coder, allocator);
return stream_decoder_reset(coder, allocator);
}

View File

@@ -15,7 +15,8 @@
#include "common.h"
extern lzma_ret lzma_stream_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, uint64_t memlimit, uint32_t flags);
extern lzma_ret lzma_stream_decoder_init(
lzma_next_coder *next, const lzma_allocator *allocator,
uint64_t memlimit, uint32_t flags);
#endif

View File

@@ -10,12 +10,11 @@
//
///////////////////////////////////////////////////////////////////////////////
#include "stream_encoder.h"
#include "block_encoder.h"
#include "index_encoder.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_STREAM_HEADER,
SEQ_BLOCK_INIT,
@@ -26,7 +25,7 @@ struct lzma_coder_s {
} sequence;
/// True if Block encoder has been initialized by
/// lzma_stream_encoder_init() or stream_encoder_update()
/// stream_encoder_init() or stream_encoder_update()
/// and thus doesn't need to be initialized in stream_encode().
bool block_encoder_is_initialized;
@@ -56,11 +55,11 @@ struct lzma_coder_s {
/// Buffer to hold Stream Header, Block Header, and Stream Footer.
/// Block Header has biggest maximum size.
uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
};
} lzma_stream_coder;
static lzma_ret
block_encoder_init(lzma_coder *coder, lzma_allocator *allocator)
block_encoder_init(lzma_stream_coder *coder, const lzma_allocator *allocator)
{
// Prepare the Block options. Even though Block encoder doesn't need
// compressed_size, uncompressed_size, and header_size to be
@@ -79,11 +78,13 @@ block_encoder_init(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
stream_encode(lzma_coder *coder, lzma_allocator *allocator,
stream_encode(void *coder_ptr, const 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)
{
lzma_stream_coder *coder = coder_ptr;
// Main loop
while (*out_pos < out_size)
switch (coder->sequence) {
@@ -126,7 +127,7 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator,
}
// Initialize the Block encoder unless it was already
// initialized by lzma_stream_encoder_init() or
// initialized by stream_encoder_init() or
// stream_encoder_update().
if (!coder->block_encoder_is_initialized)
return_if_error(block_encoder_init(coder, allocator));
@@ -147,11 +148,12 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator,
}
case SEQ_BLOCK_ENCODE: {
static const lzma_action convert[4] = {
static const lzma_action convert[LZMA_ACTION_MAX + 1] = {
LZMA_RUN,
LZMA_SYNC_FLUSH,
LZMA_FINISH,
LZMA_FINISH,
LZMA_FINISH,
};
const lzma_ret ret = coder->block_encoder.code(
@@ -209,8 +211,10 @@ stream_encode(lzma_coder *coder, lzma_allocator *allocator,
static void
stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
stream_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_stream_coder *coder = coder_ptr;
lzma_next_end(&coder->block_encoder, allocator);
lzma_next_end(&coder->index_encoder, allocator);
lzma_index_end(coder->index, allocator);
@@ -224,10 +228,12 @@ stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
stream_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
const lzma_filter *filters,
const lzma_filter *reversed_filters)
{
lzma_stream_coder *coder = coder_ptr;
if (coder->sequence <= SEQ_BLOCK_INIT) {
// There is no incomplete Block waiting to be finished,
// thus we can change the whole filter chain. Start by
@@ -262,39 +268,42 @@ stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
}
extern lzma_ret
lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
static lzma_ret
stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter *filters, lzma_check check)
{
lzma_next_coder_init(&lzma_stream_encoder_init, next, allocator);
lzma_next_coder_init(&stream_encoder_init, next, allocator);
if (filters == NULL)
return LZMA_PROG_ERROR;
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_stream_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_stream_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &stream_encode;
next->end = &stream_encoder_end;
next->update = &stream_encoder_update;
next->coder->filters[0].id = LZMA_VLI_UNKNOWN;
next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
next->coder->index_encoder = LZMA_NEXT_CODER_INIT;
next->coder->index = NULL;
coder->filters[0].id = LZMA_VLI_UNKNOWN;
coder->block_encoder = LZMA_NEXT_CODER_INIT;
coder->index_encoder = LZMA_NEXT_CODER_INIT;
coder->index = NULL;
}
// Basic initializations
next->coder->sequence = SEQ_STREAM_HEADER;
next->coder->block_options.version = 0;
next->coder->block_options.check = check;
coder->sequence = SEQ_STREAM_HEADER;
coder->block_options.version = 0;
coder->block_options.check = check;
// Initialize the Index
lzma_index_end(next->coder->index, allocator);
next->coder->index = lzma_index_init(allocator);
if (next->coder->index == NULL)
lzma_index_end(coder->index, allocator);
coder->index = lzma_index_init(allocator);
if (coder->index == NULL)
return LZMA_MEM_ERROR;
// Encode the Stream Header
@@ -303,16 +312,15 @@ lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
.check = check,
};
return_if_error(lzma_stream_header_encode(
&stream_flags, next->coder->buffer));
&stream_flags, coder->buffer));
next->coder->buffer_pos = 0;
next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
coder->buffer_pos = 0;
coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
// Initialize the Block encoder. This way we detect unsupported
// filter chains when initializing the Stream encoder instead of
// giving an error after Stream Header has already written out.
return stream_encoder_update(
next->coder, allocator, filters, NULL);
return stream_encoder_update(coder, allocator, filters, NULL);
}
@@ -320,11 +328,12 @@ extern LZMA_API(lzma_ret)
lzma_stream_encoder(lzma_stream *strm,
const lzma_filter *filters, lzma_check check)
{
lzma_next_strm_init(lzma_stream_encoder_init, strm, filters, check);
lzma_next_strm_init(stream_encoder_init, strm, filters, check);
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_FULL_BARRIER] = true;
strm->internal->supported_actions[LZMA_FINISH] = true;
return LZMA_OK;

File diff suppressed because it is too large Load Diff

View File

@@ -15,8 +15,9 @@
static void
delta_coder_end(lzma_coder *coder, lzma_allocator *allocator)
delta_coder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_delta_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder, allocator);
return;
@@ -24,18 +25,21 @@ delta_coder_end(lzma_coder *coder, lzma_allocator *allocator)
extern lzma_ret
lzma_delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_delta_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
// Allocate memory for the decoder if needed.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_delta_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_delta_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
// End function is the same for encoder and decoder.
next->end = &delta_coder_end;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Validate the options.
@@ -44,15 +48,14 @@ lzma_delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
// Set the delta distance.
const lzma_options_delta *opt = filters[0].options;
next->coder->distance = opt->dist;
coder->distance = opt->dist;
// Initialize the rest of the variables.
next->coder->pos = 0;
memzero(next->coder->history, LZMA_DELTA_DIST_MAX);
coder->pos = 0;
memzero(coder->history, LZMA_DELTA_DIST_MAX);
// Initialize the next decoder in the chain, if any.
return lzma_next_filter_init(&next->coder->next,
allocator, filters + 1);
return lzma_next_filter_init(&coder->next, allocator, filters + 1);
}
@@ -66,5 +69,5 @@ lzma_delta_coder_memusage(const void *options)
|| opt->dist > LZMA_DELTA_DIST_MAX)
return UINT64_MAX;
return sizeof(lzma_coder);
return sizeof(lzma_delta_coder);
}

View File

@@ -15,7 +15,7 @@
static void
decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size)
decode_buffer(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
{
const size_t distance = coder->distance;
@@ -27,11 +27,13 @@ decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size)
static lzma_ret
delta_decode(lzma_coder *coder, lzma_allocator *allocator,
delta_decode(void *coder_ptr, const 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)
{
lzma_delta_coder *coder = coder_ptr;
assert(coder->next.code != NULL);
const size_t out_start = *out_pos;
@@ -47,7 +49,7 @@ delta_decode(lzma_coder *coder, lzma_allocator *allocator,
extern lzma_ret
lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_delta_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
next->code = &delta_decode;
@@ -56,7 +58,7 @@ lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_delta_props_decode(void **options, lzma_allocator *allocator,
lzma_delta_props_decode(void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
if (props_size != 1)

View File

@@ -16,10 +16,11 @@
#include "delta_common.h"
extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_delta_props_decode(
void **options, lzma_allocator *allocator,
void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
#endif

View File

@@ -18,7 +18,7 @@
/// is the first filter in the chain (and thus the last filter in the
/// encoder's filter stack).
static void
copy_and_encode(lzma_coder *coder,
copy_and_encode(lzma_delta_coder *coder,
const uint8_t *restrict in, uint8_t *restrict out, size_t size)
{
const size_t distance = coder->distance;
@@ -35,7 +35,7 @@ copy_and_encode(lzma_coder *coder,
/// Encodes the data in place. This is used when we are the last filter
/// in the chain (and thus non-last filter in the encoder's filter stack).
static void
encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size)
encode_in_place(lzma_delta_coder *coder, uint8_t *buffer, size_t size)
{
const size_t distance = coder->distance;
@@ -49,11 +49,13 @@ encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size)
static lzma_ret
delta_encode(lzma_coder *coder, lzma_allocator *allocator,
delta_encode(void *coder_ptr, const 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)
{
lzma_delta_coder *coder = coder_ptr;
lzma_ret ret;
if (coder->next.code == NULL) {
@@ -84,10 +86,12 @@ delta_encode(lzma_coder *coder, lzma_allocator *allocator,
static lzma_ret
delta_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
delta_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
const lzma_filter *filters_null lzma_attribute((__unused__)),
const lzma_filter *reversed_filters)
{
lzma_delta_coder *coder = coder_ptr;
// Delta doesn't and will never support changing the options in
// the middle of encoding. If the app tries to change them, we
// simply ignore them.
@@ -97,7 +101,7 @@ delta_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
extern lzma_ret
lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
next->code = &delta_encode;

View File

@@ -16,7 +16,8 @@
#include "delta_common.h"
extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_delta_props_encode(const void *options, uint8_t *out);

View File

@@ -15,7 +15,7 @@
#include "delta_common.h"
struct lzma_coder_s {
typedef struct {
/// Next coder in the chain
lzma_next_coder next;
@@ -27,11 +27,11 @@ struct lzma_coder_s {
/// Buffer to hold history of the original data
uint8_t history[LZMA_DELTA_DIST_MAX];
};
} lzma_delta_coder;
extern lzma_ret lzma_delta_coder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters);
#endif

View File

@@ -16,4 +16,4 @@ URL: @PACKAGE_URL@
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -llzma
Libs.private: @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
Libs.private: @PTHREAD_CFLAGS@ @LIBS@

View File

@@ -20,7 +20,7 @@
#include "lz_decoder.h"
struct lzma_coder_s {
typedef struct {
/// Dictionary (history buffer)
lzma_dict dict;
@@ -48,7 +48,7 @@ struct lzma_coder_s {
size_t size;
uint8_t buffer[LZMA_BUFFER_SIZE];
} temp;
};
} lzma_coder;
static void
@@ -125,13 +125,15 @@ decode_buffer(lzma_coder *coder,
static lzma_ret
lz_decode(lzma_coder *coder,
lzma_allocator *allocator lzma_attribute((__unused__)),
lz_decode(void *coder_ptr,
const lzma_allocator *allocator lzma_attribute((__unused__)),
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)
{
lzma_coder *coder = coder_ptr;
if (coder->next.code == NULL)
return decode_buffer(coder, in, in_pos, in_size,
out, out_pos, out_size);
@@ -184,8 +186,10 @@ lz_decode(lzma_coder *coder,
static void
lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
lz_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder->dict.buf, allocator);
@@ -200,31 +204,33 @@ lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
extern lzma_ret
lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lz_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters,
lzma_ret (*lz_init)(lzma_lz_decoder *lz,
lzma_allocator *allocator, const void *options,
const lzma_allocator *allocator, const void *options,
lzma_lz_options *lz_options))
{
// Allocate the base structure if it isn't already allocated.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &lz_decode;
next->end = &lz_decoder_end;
next->coder->dict.buf = NULL;
next->coder->dict.size = 0;
next->coder->lz = LZMA_LZ_DECODER_INIT;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->dict.buf = NULL;
coder->dict.size = 0;
coder->lz = LZMA_LZ_DECODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Allocate and initialize the LZ-based decoder. It will also give
// us the dictionary size.
lzma_lz_options lz_options;
return_if_error(lz_init(&next->coder->lz, allocator,
return_if_error(lz_init(&coder->lz, allocator,
filters[0].options, &lz_options));
// If the dictionary size is very small, increase it to 4096 bytes.
@@ -248,14 +254,14 @@ lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));
// Allocate and initialize the dictionary.
if (next->coder->dict.size != lz_options.dict_size) {
lzma_free(next->coder->dict.buf, allocator);
next->coder->dict.buf
if (coder->dict.size != lz_options.dict_size) {
lzma_free(coder->dict.buf, allocator);
coder->dict.buf
= lzma_alloc(lz_options.dict_size, allocator);
if (next->coder->dict.buf == NULL)
if (coder->dict.buf == NULL)
return LZMA_MEM_ERROR;
next->coder->dict.size = lz_options.dict_size;
coder->dict.size = lz_options.dict_size;
}
lz_decoder_reset(next->coder);
@@ -268,21 +274,20 @@ lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
const size_t copy_size = my_min(lz_options.preset_dict_size,
lz_options.dict_size);
const size_t offset = lz_options.preset_dict_size - copy_size;
memcpy(next->coder->dict.buf, lz_options.preset_dict + offset,
memcpy(coder->dict.buf, lz_options.preset_dict + offset,
copy_size);
next->coder->dict.pos = copy_size;
next->coder->dict.full = copy_size;
coder->dict.pos = copy_size;
coder->dict.full = copy_size;
}
// Miscellaneous initializations
next->coder->next_finished = false;
next->coder->this_finished = false;
next->coder->temp.pos = 0;
next->coder->temp.size = 0;
coder->next_finished = false;
coder->this_finished = false;
coder->temp.pos = 0;
coder->temp.size = 0;
// Initialize the next filter in the chain, if any.
return lzma_next_filter_init(&next->coder->next, allocator,
filters + 1);
return lzma_next_filter_init(&coder->next, allocator, filters + 1);
}
@@ -294,7 +299,8 @@ lzma_lz_decoder_memusage(size_t dictionary_size)
extern void
lzma_lz_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
lzma_lz_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size)
{
lzma_coder *coder = coder_ptr;
coder->lz.set_uncompressed(coder->lz.coder, uncompressed_size);
}

View File

@@ -53,21 +53,20 @@ typedef struct {
typedef struct {
/// Data specific to the LZ-based decoder
lzma_coder *coder;
void *coder;
/// Function to decode from in[] to *dict
lzma_ret (*code)(lzma_coder *restrict coder,
lzma_ret (*code)(void *coder,
lzma_dict *restrict dict, const uint8_t *restrict in,
size_t *restrict in_pos, size_t in_size);
void (*reset)(lzma_coder *coder, const void *options);
void (*reset)(void *coder, const void *options);
/// Set the uncompressed size
void (*set_uncompressed)(lzma_coder *coder,
lzma_vli uncompressed_size);
void (*set_uncompressed)(void *coder, lzma_vli uncompressed_size);
/// Free allocated resources
void (*end)(lzma_coder *coder, lzma_allocator *allocator);
void (*end)(void *coder, const lzma_allocator *allocator);
} lzma_lz_decoder;
@@ -83,15 +82,16 @@ typedef struct {
extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters,
const lzma_allocator *allocator,
const lzma_filter_info *filters,
lzma_ret (*lz_init)(lzma_lz_decoder *lz,
lzma_allocator *allocator, const void *options,
const lzma_allocator *allocator, const void *options,
lzma_lz_options *lz_options));
extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size);
extern void lzma_lz_decoder_uncompressed(
lzma_coder *coder, lzma_vli uncompressed_size);
void *coder, lzma_vli uncompressed_size);
//////////////////////

View File

@@ -20,8 +20,10 @@
# include "lz_encoder_hash_table.h"
#endif
#include "memcmplen.h"
struct lzma_coder_s {
typedef struct {
/// LZ-based encoder e.g. LZMA
lzma_lz_encoder lz;
@@ -30,7 +32,7 @@ struct lzma_coder_s {
/// Next coder in the chain
lzma_next_coder next;
};
} lzma_coder;
/// \brief Moves the data in the input window to free space for new data
@@ -76,8 +78,9 @@ move_window(lzma_mf *mf)
/// This function must not be called once it has returned LZMA_STREAM_END.
///
static lzma_ret
fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
size_t *in_pos, size_t in_size, lzma_action action)
fill_window(lzma_coder *coder, const lzma_allocator *allocator,
const uint8_t *in, size_t *in_pos, size_t in_size,
lzma_action action)
{
assert(coder->mf.read_pos <= coder->mf.write_pos);
@@ -107,6 +110,12 @@ fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
coder->mf.write_pos = write_pos;
// Silence Valgrind. lzma_memcmplen() can read extra bytes
// and Valgrind will give warnings if those bytes are uninitialized
// because Valgrind cannot see that the values of the uninitialized
// bytes are eventually ignored.
memzero(coder->mf.buffer + write_pos, LZMA_MEMCMPLEN_EXTRA);
// If end of stream has been reached or flushing completed, we allow
// the encoder to process all the input (that is, read_pos is allowed
// to reach write_pos). Otherwise we keep keep_size_after bytes
@@ -130,7 +139,7 @@ fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
&& coder->mf.read_pos < coder->mf.read_limit) {
// Match finder may update coder->pending and expects it to
// start from zero, so use a temporary variable.
const size_t pending = coder->mf.pending;
const uint32_t pending = coder->mf.pending;
coder->mf.pending = 0;
// Rewind read_pos so that the match finder can hash
@@ -148,12 +157,14 @@ fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
static lzma_ret
lz_encode(lzma_coder *coder, lzma_allocator *allocator,
lz_encode(void *coder_ptr, const 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)
{
lzma_coder *coder = coder_ptr;
while (*out_pos < out_size
&& (*in_pos < in_size || action != LZMA_RUN)) {
// Read more data to coder->mf.buffer if needed.
@@ -179,7 +190,7 @@ lz_encode(lzma_coder *coder, lzma_allocator *allocator,
static bool
lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator,
lz_encoder_prepare(lzma_mf *mf, const lzma_allocator *allocator,
const lzma_lz_options *lz_options)
{
// For now, the dictionary size is limited to 1.5 GiB. This may grow
@@ -325,25 +336,22 @@ lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator,
hs += HASH_4_SIZE;
*/
// If the above code calculating hs is modified, make sure that
// this assertion stays valid (UINT32_MAX / 5 is not strictly the
// exact limit). If it doesn't, you need to calculate that
// hash_size_sum + sons_count cannot overflow.
assert(hs < UINT32_MAX / 5);
const uint32_t old_count = mf->hash_size_sum + mf->sons_count;
mf->hash_size_sum = hs;
const uint32_t old_hash_count = mf->hash_count;
const uint32_t old_sons_count = mf->sons_count;
mf->hash_count = hs;
mf->sons_count = mf->cyclic_size;
if (is_bt)
mf->sons_count *= 2;
const uint32_t new_count = mf->hash_size_sum + mf->sons_count;
// Deallocate the old hash array if it exists and has different size
// than what is needed now.
if (old_count != new_count) {
if (old_hash_count != mf->hash_count
|| old_sons_count != mf->sons_count) {
lzma_free(mf->hash, allocator);
mf->hash = NULL;
lzma_free(mf->son, allocator);
mf->son = NULL;
}
// Maximum number of match finder cycles
@@ -360,14 +368,23 @@ lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator,
static bool
lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator,
lz_encoder_init(lzma_mf *mf, const lzma_allocator *allocator,
const lzma_lz_options *lz_options)
{
// Allocate the history buffer.
if (mf->buffer == NULL) {
mf->buffer = lzma_alloc(mf->size, allocator);
// lzma_memcmplen() is used for the dictionary buffer
// so we need to allocate a few extra bytes to prevent
// it from reading past the end of the buffer.
mf->buffer = lzma_alloc(mf->size + LZMA_MEMCMPLEN_EXTRA,
allocator);
if (mf->buffer == NULL)
return true;
// Keep Valgrind happy with lzma_memcmplen() and initialize
// the extra bytes whose value may get read but which will
// effectively get ignored.
memzero(mf->buffer + mf->size, LZMA_MEMCMPLEN_EXTRA);
}
// Use cyclic_size as initial mf->offset. This allows
@@ -381,44 +398,49 @@ lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator,
mf->write_pos = 0;
mf->pending = 0;
// Allocate match finder's hash array.
const size_t alloc_count = mf->hash_size_sum + mf->sons_count;
#if UINT32_MAX >= SIZE_MAX / 4
// Check for integer overflow. (Huge dictionaries are not
// possible on 32-bit CPU.)
if (alloc_count > SIZE_MAX / sizeof(uint32_t))
if (mf->hash_count > SIZE_MAX / sizeof(uint32_t)
|| mf->sons_count > SIZE_MAX / sizeof(uint32_t))
return true;
#endif
// Allocate and initialize the hash table. Since EMPTY_HASH_VALUE
// is zero, we can use lzma_alloc_zero() or memzero() for mf->hash.
//
// We don't need to initialize mf->son, but not doing that may
// make Valgrind complain in normalization (see normalize() in
// lz_encoder_mf.c). Skipping the initialization is *very* good
// when big dictionary is used but only small amount of data gets
// actually compressed: most of the mf->son won't get actually
// allocated by the kernel, so we avoid wasting RAM and improve
// initialization speed a lot.
if (mf->hash == NULL) {
mf->hash = lzma_alloc(alloc_count * sizeof(uint32_t),
mf->hash = lzma_alloc_zero(mf->hash_count * sizeof(uint32_t),
allocator);
if (mf->hash == NULL)
mf->son = lzma_alloc(mf->sons_count * sizeof(uint32_t),
allocator);
if (mf->hash == NULL || mf->son == NULL) {
lzma_free(mf->hash, allocator);
mf->hash = NULL;
lzma_free(mf->son, allocator);
mf->son = NULL;
return true;
}
} else {
/*
for (uint32_t i = 0; i < mf->hash_count; ++i)
mf->hash[i] = EMPTY_HASH_VALUE;
*/
memzero(mf->hash, mf->hash_count * sizeof(uint32_t));
}
mf->son = mf->hash + mf->hash_size_sum;
mf->cyclic_pos = 0;
// Initialize the hash table. Since EMPTY_HASH_VALUE is zero, we
// can use memset().
/*
for (uint32_t i = 0; i < hash_size_sum; ++i)
mf->hash[i] = EMPTY_HASH_VALUE;
*/
memzero(mf->hash, (size_t)(mf->hash_size_sum) * sizeof(uint32_t));
// We don't need to initialize mf->son, but not doing that will
// make Valgrind complain in normalization (see normalize() in
// lz_encoder_mf.c).
//
// Skipping this initialization is *very* good when big dictionary is
// used but only small amount of data gets actually compressed: most
// of the mf->hash won't get actually allocated by the kernel, so
// we avoid wasting RAM and improve initialization speed a lot.
//memzero(mf->son, (size_t)(mf->sons_count) * sizeof(uint32_t));
// Handle preset dictionary.
if (lz_options->preset_dict != NULL
&& lz_options->preset_dict_size > 0) {
@@ -445,7 +467,8 @@ lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
lzma_mf mf = {
.buffer = NULL,
.hash = NULL,
.hash_size_sum = 0,
.son = NULL,
.hash_count = 0,
.sons_count = 0,
};
@@ -454,17 +477,19 @@ lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
return UINT64_MAX;
// Calculate the memory usage.
return (uint64_t)(mf.hash_size_sum + mf.sons_count)
* sizeof(uint32_t)
+ (uint64_t)(mf.size) + sizeof(lzma_coder);
return ((uint64_t)(mf.hash_count) + mf.sons_count) * sizeof(uint32_t)
+ mf.size + sizeof(lzma_coder);
}
static void
lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
lz_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder->mf.son, allocator);
lzma_free(coder->mf.hash, allocator);
lzma_free(coder->mf.buffer, allocator);
@@ -479,10 +504,12 @@ lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
lz_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
const lzma_filter *filters_null lzma_attribute((__unused__)),
const lzma_filter *reversed_filters)
{
lzma_coder *coder = coder_ptr;
if (coder->lz.options_update == NULL)
return LZMA_PROG_ERROR;
@@ -495,10 +522,10 @@ lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
extern lzma_ret
lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lz_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters,
lzma_ret (*lz_init)(lzma_lz_encoder *lz,
lzma_allocator *allocator, const void *options,
const lzma_allocator *allocator, const void *options,
lzma_lz_options *lz_options))
{
#ifdef HAVE_SMALL
@@ -507,45 +534,51 @@ lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
#endif
// Allocate and initialize the base data structure.
if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (next->coder == NULL)
lzma_coder *coder = next->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &lz_encode;
next->end = &lz_encoder_end;
next->update = &lz_encoder_update;
next->coder->lz.coder = NULL;
next->coder->lz.code = NULL;
next->coder->lz.end = NULL;
coder->lz.coder = NULL;
coder->lz.code = NULL;
coder->lz.end = NULL;
next->coder->mf.buffer = NULL;
next->coder->mf.hash = NULL;
next->coder->mf.hash_size_sum = 0;
next->coder->mf.sons_count = 0;
// mf.size is initialized to silence Valgrind
// when used on optimized binaries (GCC may reorder
// code in a way that Valgrind gets unhappy).
coder->mf.buffer = NULL;
coder->mf.size = 0;
coder->mf.hash = NULL;
coder->mf.son = NULL;
coder->mf.hash_count = 0;
coder->mf.sons_count = 0;
next->coder->next = LZMA_NEXT_CODER_INIT;
coder->next = LZMA_NEXT_CODER_INIT;
}
// Initialize the LZ-based encoder.
lzma_lz_options lz_options;
return_if_error(lz_init(&next->coder->lz, allocator,
return_if_error(lz_init(&coder->lz, allocator,
filters[0].options, &lz_options));
// Setup the size information into next->coder->mf and deallocate
// Setup the size information into coder->mf and deallocate
// old buffers if they have wrong size.
if (lz_encoder_prepare(&next->coder->mf, allocator, &lz_options))
if (lz_encoder_prepare(&coder->mf, allocator, &lz_options))
return LZMA_OPTIONS_ERROR;
// Allocate new buffers if needed, and do the rest of
// the initialization.
if (lz_encoder_init(&next->coder->mf, allocator, &lz_options))
if (lz_encoder_init(&coder->mf, allocator, &lz_options))
return LZMA_MEM_ERROR;
// Initialize the next filter in the chain, if any.
return lzma_next_filter_init(&next->coder->next, allocator,
filters + 1);
return lzma_next_filter_init(&coder->next, allocator, filters + 1);
}

View File

@@ -119,7 +119,7 @@ struct lzma_mf_s {
lzma_action action;
/// Number of elements in hash[]
uint32_t hash_size_sum;
uint32_t hash_count;
/// Number of elements in son[]
uint32_t sons_count;
@@ -191,19 +191,18 @@ typedef struct {
typedef struct {
/// Data specific to the LZ-based encoder
lzma_coder *coder;
void *coder;
/// Function to encode from *dict to out[]
lzma_ret (*code)(lzma_coder *restrict coder,
lzma_ret (*code)(void *coder,
lzma_mf *restrict mf, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size);
/// Free allocated resources
void (*end)(lzma_coder *coder, lzma_allocator *allocator);
void (*end)(void *coder, const lzma_allocator *allocator);
/// Update the options in the middle of the encoding.
lzma_ret (*options_update)(lzma_coder *coder,
const lzma_filter *filter);
lzma_ret (*options_update)(void *coder, const lzma_filter *filter);
} lzma_lz_encoder;
@@ -296,10 +295,10 @@ mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size,
extern lzma_ret lzma_lz_encoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters,
lzma_ret (*lz_init)(lzma_lz_encoder *lz,
lzma_allocator *allocator, const void *options,
const lzma_allocator *allocator, const void *options,
lzma_lz_options *lz_options));

View File

@@ -13,6 +13,7 @@
#include "lz_encoder.h"
#include "lz_encoder_hash.h"
#include "memcmplen.h"
/// \brief Find matches starting from the current byte
@@ -65,9 +66,7 @@ lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
// here because the match distances are zero based.
const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
while (len_best < limit
&& p1[len_best] == p2[len_best])
++len_best;
len_best = lzma_memcmplen(p1, p2, len_best, limit);
}
}
@@ -116,24 +115,27 @@ normalize(lzma_mf *mf)
= (MUST_NORMALIZE_POS - mf->cyclic_size);
// & (~(UINT32_C(1) << 10) - 1);
const uint32_t count = mf->hash_size_sum + mf->sons_count;
uint32_t *hash = mf->hash;
for (uint32_t i = 0; i < count; ++i) {
for (uint32_t i = 0; i < mf->hash_count; ++i) {
// If the distance is greater than the dictionary size,
// we can simply mark the hash element as empty.
//
// NOTE: Only the first mf->hash_size_sum elements are
// initialized for sure. There may be uninitialized elements
// in mf->son. Since we go through both mf->hash and
// mf->son here in normalization, Valgrind may complain
// that the "if" below depends on uninitialized value. In
// this case it is safe to ignore the warning. See also the
// comments in lz_encoder_init() in lz_encoder.c.
if (hash[i] <= subvalue)
hash[i] = EMPTY_HASH_VALUE;
if (mf->hash[i] <= subvalue)
mf->hash[i] = EMPTY_HASH_VALUE;
else
hash[i] -= subvalue;
mf->hash[i] -= subvalue;
}
for (uint32_t i = 0; i < mf->sons_count; ++i) {
// Do the same for mf->son.
//
// NOTE: There may be uninitialized elements in mf->son.
// Valgrind may complain that the "if" below depends on
// an uninitialized value. In this case it is safe to ignore
// the warning. See also the comments in lz_encoder_init()
// in lz_encoder.c.
if (mf->son[i] <= subvalue)
mf->son[i] = EMPTY_HASH_VALUE;
else
mf->son[i] -= subvalue;
}
// Update offset to match the new locations.
@@ -269,10 +271,7 @@ hc_find_func(
+ (delta > cyclic_pos ? cyclic_size : 0)];
if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
uint32_t len = 0;
while (++len != len_limit)
if (pb[len] != cur[len])
break;
uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit);
if (len_best < len) {
len_best = len;
@@ -318,9 +317,8 @@ lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
uint32_t len_best = 2;
if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
for ( ; len_best != len_limit; ++len_best)
if (*(cur + len_best - delta2) != cur[len_best])
break;
len_best = lzma_memcmplen(cur - delta2, cur,
len_best, len_limit);
matches[0].len = len_best;
matches[0].dist = delta2 - 1;
@@ -397,9 +395,8 @@ lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
}
if (matches_count != 0) {
for ( ; len_best != len_limit; ++len_best)
if (*(cur + len_best - delta2) != cur[len_best])
break;
len_best = lzma_memcmplen(cur - delta2, cur,
len_best, len_limit);
matches[matches_count - 1].len = len_best;
@@ -484,9 +481,7 @@ bt_find_func(
uint32_t len = my_min(len0, len1);
if (pb[len] == cur[len]) {
while (++len != len_limit)
if (pb[len] != cur[len])
break;
len = lzma_memcmplen(pb, cur, len + 1, len_limit);
if (len_best < len) {
len_best = len;
@@ -549,9 +544,7 @@ bt_skip_func(
uint32_t len = my_min(len0, len1);
if (pb[len] == cur[len]) {
while (++len != len_limit)
if (pb[len] != cur[len])
break;
len = lzma_memcmplen(pb, cur, len + 1, len_limit);
if (len == len_limit) {
*ptr1 = pair[0];
@@ -639,9 +632,8 @@ lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
uint32_t len_best = 2;
if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
for ( ; len_best != len_limit; ++len_best)
if (*(cur + len_best - delta2) != cur[len_best])
break;
len_best = lzma_memcmplen(
cur, cur - delta2, len_best, len_limit);
matches[0].len = len_best;
matches[0].dist = delta2 - 1;
@@ -712,9 +704,8 @@ lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
}
if (matches_count != 0) {
for ( ; len_best != len_limit; ++len_best)
if (*(cur + len_best - delta2) != cur[len_best])
break;
len_best = lzma_memcmplen(
cur, cur - delta2, len_best, len_limit);
matches[matches_count - 1].len = len_best;

View File

@@ -14,15 +14,15 @@
#ifndef LZMA_FASTPOS_H
#define LZMA_FASTPOS_H
// LZMA encodes match distances (positions) by storing the highest two
// bits using a six-bit value [0, 63], and then the missing lower bits.
// Dictionary size is also stored using this encoding in the new .lzma
// LZMA encodes match distances by storing the highest two bits using
// a six-bit value [0, 63], and then the missing lower bits.
// Dictionary size is also stored using this encoding in the .xz
// file format header.
//
// fastpos.h provides a way to quickly find out the correct six-bit
// values. The following table gives some examples of this encoding:
//
// pos return
// dist return
// 0 0
// 1 1
// 2 2
@@ -48,10 +48,10 @@
// Provided functions or macros
// ----------------------------
//
// get_pos_slot(pos) is the basic version. get_pos_slot_2(pos)
// assumes that pos >= FULL_DISTANCES, thus the result is at least
// FULL_DISTANCES_BITS * 2. Using get_pos_slot(pos) instead of
// get_pos_slot_2(pos) would give the same result, but get_pos_slot_2(pos)
// get_dist_slot(dist) is the basic version. get_dist_slot_2(dist)
// assumes that dist >= FULL_DISTANCES, thus the result is at least
// FULL_DISTANCES_BITS * 2. Using get_dist_slot(dist) instead of
// get_dist_slot_2(dist) would give the same result, but get_dist_slot_2(dist)
// should be tiny bit faster due to the assumption being made.
//
//
@@ -76,13 +76,14 @@
// slightly faster, but sometimes it is a lot slower.
#ifdef HAVE_SMALL
# define get_pos_slot(pos) ((pos) <= 4 ? (pos) : get_pos_slot_2(pos))
# define get_dist_slot(dist) \
((dist) <= 4 ? (dist) : get_dist_slot_2(dist))
static inline uint32_t
get_pos_slot_2(uint32_t pos)
get_dist_slot_2(uint32_t dist)
{
const uint32_t i = bsr32(pos);
return (i + i) + ((pos >> (i - 1)) & 1);
const uint32_t i = bsr32(dist);
return (i + i) + ((dist >> (i - 1)) & 1);
}
@@ -99,39 +100,39 @@ extern const uint8_t lzma_fastpos[1 << FASTPOS_BITS];
#define fastpos_limit(extra, n) \
(UINT32_C(1) << (FASTPOS_BITS + fastpos_shift(extra, n)))
#define fastpos_result(pos, extra, n) \
lzma_fastpos[(pos) >> fastpos_shift(extra, n)] \
#define fastpos_result(dist, extra, n) \
lzma_fastpos[(dist) >> fastpos_shift(extra, n)] \
+ 2 * fastpos_shift(extra, n)
static inline uint32_t
get_pos_slot(uint32_t pos)
get_dist_slot(uint32_t dist)
{
// If it is small enough, we can pick the result directly from
// the precalculated table.
if (pos < fastpos_limit(0, 0))
return lzma_fastpos[pos];
if (dist < fastpos_limit(0, 0))
return lzma_fastpos[dist];
if (pos < fastpos_limit(0, 1))
return fastpos_result(pos, 0, 1);
if (dist < fastpos_limit(0, 1))
return fastpos_result(dist, 0, 1);
return fastpos_result(pos, 0, 2);
return fastpos_result(dist, 0, 2);
}
#ifdef FULL_DISTANCES_BITS
static inline uint32_t
get_pos_slot_2(uint32_t pos)
get_dist_slot_2(uint32_t dist)
{
assert(pos >= FULL_DISTANCES);
assert(dist >= FULL_DISTANCES);
if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 0);
if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 0);
if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 1))
return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 1);
if (dist < fastpos_limit(FULL_DISTANCES_BITS - 1, 1))
return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 1);
return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 2);
return fastpos_result(dist, FULL_DISTANCES_BITS - 1, 2);
}
#endif

View File

@@ -16,7 +16,7 @@
#include "lzma_decoder.h"
struct lzma_coder_s {
typedef struct {
enum sequence {
SEQ_CONTROL,
SEQ_UNCOMPRESSED_1,
@@ -50,14 +50,16 @@ struct lzma_coder_s {
bool need_dictionary_reset;
lzma_options_lzma options;
};
} lzma_lzma2_coder;
static lzma_ret
lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict,
lzma2_decode(void *coder_ptr, lzma_dict *restrict dict,
const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size)
{
lzma_lzma2_coder *restrict coder = coder_ptr;
// With SEQ_LZMA it is possible that no new input is needed to do
// some progress. The rest of the sequences assume that there is
// at least one byte of input.
@@ -209,8 +211,10 @@ lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict,
static void
lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
lzma2_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_lzma2_coder *coder = coder_ptr;
assert(coder->lzma.end == NULL);
lzma_free(coder->lzma.coder, allocator);
@@ -221,34 +225,36 @@ lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
lzma2_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
const void *opt, lzma_lz_options *lz_options)
{
if (lz->coder == NULL) {
lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (lz->coder == NULL)
lzma_lzma2_coder *coder = lz->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
lz->coder = coder;
lz->code = &lzma2_decode;
lz->end = &lzma2_decoder_end;
lz->coder->lzma = LZMA_LZ_DECODER_INIT;
coder->lzma = LZMA_LZ_DECODER_INIT;
}
const lzma_options_lzma *options = opt;
lz->coder->sequence = SEQ_CONTROL;
lz->coder->need_properties = true;
lz->coder->need_dictionary_reset = options->preset_dict == NULL
coder->sequence = SEQ_CONTROL;
coder->need_properties = true;
coder->need_dictionary_reset = options->preset_dict == NULL
|| options->preset_dict_size == 0;
return lzma_lzma_decoder_create(&lz->coder->lzma,
return lzma_lzma_decoder_create(&coder->lzma,
allocator, options, lz_options);
}
extern lzma_ret
lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lzma2_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
// LZMA2 can only be the last filter in the chain. This is enforced
@@ -263,13 +269,13 @@ lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern uint64_t
lzma_lzma2_decoder_memusage(const void *options)
{
return sizeof(lzma_coder)
return sizeof(lzma_lzma2_coder)
+ lzma_lzma_decoder_memusage_nocheck(options);
}
extern lzma_ret
lzma_lzma2_props_decode(void **options, lzma_allocator *allocator,
lzma_lzma2_props_decode(void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
if (props_size != 1)

View File

@@ -17,12 +17,13 @@
#include "common.h"
extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern uint64_t lzma_lzma2_decoder_memusage(const void *options);
extern lzma_ret lzma_lzma2_props_decode(
void **options, lzma_allocator *allocator,
void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
#endif

View File

@@ -17,7 +17,7 @@
#include "lzma2_encoder.h"
struct lzma_coder_s {
typedef struct {
enum {
SEQ_INIT,
SEQ_LZMA_ENCODE,
@@ -27,7 +27,7 @@ struct lzma_coder_s {
} sequence;
/// LZMA encoder
lzma_coder *lzma;
void *lzma;
/// LZMA options currently in use.
lzma_options_lzma opt_cur;
@@ -48,11 +48,11 @@ struct lzma_coder_s {
/// Buffer to hold the chunk header and LZMA compressed data
uint8_t buf[LZMA2_HEADER_MAX + LZMA2_CHUNK_MAX];
};
} lzma_lzma2_coder;
static void
lzma2_header_lzma(lzma_coder *coder)
lzma2_header_lzma(lzma_lzma2_coder *coder)
{
assert(coder->uncompressed_size > 0);
assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
@@ -108,7 +108,7 @@ lzma2_header_lzma(lzma_coder *coder)
static void
lzma2_header_uncompressed(lzma_coder *coder)
lzma2_header_uncompressed(lzma_lzma2_coder *coder)
{
assert(coder->uncompressed_size > 0);
assert(coder->uncompressed_size <= LZMA2_CHUNK_MAX);
@@ -133,10 +133,12 @@ lzma2_header_uncompressed(lzma_coder *coder)
static lzma_ret
lzma2_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma2_encode(void *coder_ptr, lzma_mf *restrict mf,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size)
{
lzma_lzma2_coder *restrict coder = coder_ptr;
while (*out_pos < out_size)
switch (coder->sequence) {
case SEQ_INIT:
@@ -262,8 +264,9 @@ lzma2_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
static void
lzma2_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
lzma2_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_lzma2_coder *coder = coder_ptr;
lzma_free(coder->lzma, allocator);
lzma_free(coder, allocator);
return;
@@ -271,8 +274,10 @@ lzma2_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
lzma2_encoder_options_update(lzma_coder *coder, const lzma_filter *filter)
lzma2_encoder_options_update(void *coder_ptr, const lzma_filter *filter)
{
lzma_lzma2_coder *coder = coder_ptr;
// New options can be set only when there is no incomplete chunk.
// This is the case at the beginning of the raw stream and right
// after LZMA_SYNC_FLUSH.
@@ -304,36 +309,38 @@ lzma2_encoder_options_update(lzma_coder *coder, const lzma_filter *filter)
static lzma_ret
lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
lzma2_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
const void *options, lzma_lz_options *lz_options)
{
if (options == NULL)
return LZMA_PROG_ERROR;
if (lz->coder == NULL) {
lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
if (lz->coder == NULL)
lzma_lzma2_coder *coder = lz->coder;
if (coder == NULL) {
coder = lzma_alloc(sizeof(lzma_lzma2_coder), allocator);
if (coder == NULL)
return LZMA_MEM_ERROR;
lz->coder = coder;
lz->code = &lzma2_encode;
lz->end = &lzma2_encoder_end;
lz->options_update = &lzma2_encoder_options_update;
lz->coder->lzma = NULL;
coder->lzma = NULL;
}
lz->coder->opt_cur = *(const lzma_options_lzma *)(options);
coder->opt_cur = *(const lzma_options_lzma *)(options);
lz->coder->sequence = SEQ_INIT;
lz->coder->need_properties = true;
lz->coder->need_state_reset = false;
lz->coder->need_dictionary_reset
= lz->coder->opt_cur.preset_dict == NULL
|| lz->coder->opt_cur.preset_dict_size == 0;
coder->sequence = SEQ_INIT;
coder->need_properties = true;
coder->need_state_reset = false;
coder->need_dictionary_reset
= coder->opt_cur.preset_dict == NULL
|| coder->opt_cur.preset_dict_size == 0;
// Initialize LZMA encoder
return_if_error(lzma_lzma_encoder_create(&lz->coder->lzma, allocator,
&lz->coder->opt_cur, lz_options));
return_if_error(lzma_lzma_encoder_create(&coder->lzma, allocator,
&coder->opt_cur, lz_options));
// Make sure that we will always have enough history available in
// case we need to use uncompressed chunks. They are used when the
@@ -349,7 +356,7 @@ lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
extern lzma_ret
lzma_lzma2_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lzma2_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return lzma_lz_encoder_init(
@@ -364,7 +371,7 @@ lzma_lzma2_encoder_memusage(const void *options)
if (lzma_mem == UINT64_MAX)
return UINT64_MAX;
return sizeof(lzma_coder) + lzma_mem;
return sizeof(lzma_lzma2_coder) + lzma_mem;
}
@@ -387,7 +394,17 @@ lzma_lzma2_props_encode(const void *options, uint8_t *out)
if (d == UINT32_MAX)
out[0] = 40;
else
out[0] = get_pos_slot(d + 1) - 24;
out[0] = get_dist_slot(d + 1) - 24;
return LZMA_OK;
}
extern uint64_t
lzma_lzma2_block_size(const void *options)
{
const lzma_options_lzma *const opt = options;
// Use at least 1 MiB to keep compression ratio better.
return my_max((uint64_t)(opt->dict_size) * 3, UINT64_C(1) << 20);
}

View File

@@ -31,11 +31,13 @@
extern lzma_ret lzma_lzma2_encoder_init(
lzma_next_coder *next, lzma_allocator *allocator,
lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern uint64_t lzma_lzma2_encoder_memusage(const void *options);
extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out);
extern uint64_t lzma_lzma2_block_size(const void *options);
#endif

View File

@@ -171,53 +171,54 @@ literal_init(probability (*probs)[LITERAL_CODER_SIZE],
// Match distance //
////////////////////
// Different set of probabilities is used for match distances that have very
// Different sets of probabilities are used for match distances that have very
// short match length: Lengths of 2, 3, and 4 bytes have a separate set of
// probabilities for each length. The matches with longer length use a shared
// set of probabilities.
#define LEN_TO_POS_STATES 4
#define DIST_STATES 4
// Macro to get the index of the appropriate probability array.
#define get_len_to_pos_state(len) \
((len) < LEN_TO_POS_STATES + MATCH_LEN_MIN \
#define get_dist_state(len) \
((len) < DIST_STATES + MATCH_LEN_MIN \
? (len) - MATCH_LEN_MIN \
: LEN_TO_POS_STATES - 1)
: DIST_STATES - 1)
// The highest two bits of a match distance (pos slot) are encoded using six
// bits. See fastpos.h for more explanation.
#define POS_SLOT_BITS 6
#define POS_SLOTS (1 << POS_SLOT_BITS)
// The highest two bits of a match distance (distance slot) are encoded
// using six bits. See fastpos.h for more explanation.
#define DIST_SLOT_BITS 6
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
// Match distances up to 127 are fully encoded using probabilities. Since
// the highest two bits (pos slot) are always encoded using six bits, the
// distances 0-3 don't need any additional bits to encode, since the pos
// slot itself is the same as the actual distance. START_POS_MODEL_INDEX
// indicates the first pos slot where at least one additional bit is needed.
#define START_POS_MODEL_INDEX 4
// the highest two bits (distance slot) are always encoded using six bits,
// the distances 0-3 don't need any additional bits to encode, since the
// distance slot itself is the same as the actual distance. DIST_MODEL_START
// indicates the first distance slot where at least one additional bit is
// needed.
#define DIST_MODEL_START 4
// Match distances greater than 127 are encoded in three pieces:
// - pos slot: the highest two bits
// - distance slot: the highest two bits
// - direct bits: 2-26 bits below the highest two bits
// - alignment bits: four lowest bits
//
// Direct bits don't use any probabilities.
//
// The pos slot value of 14 is for distances 128-191 (see the table in
// The distance slot value of 14 is for distances 128-191 (see the table in
// fastpos.h to understand why).
#define END_POS_MODEL_INDEX 14
#define DIST_MODEL_END 14
// Pos slots that indicate a distance <= 127.
#define FULL_DISTANCES_BITS (END_POS_MODEL_INDEX / 2)
// Distance slots that indicate a distance <= 127.
#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
// For match distances greater than 127, only the highest two bits and the
// lowest four bits (alignment) is encoded using probabilities.
#define ALIGN_BITS 4
#define ALIGN_TABLE_SIZE (1 << ALIGN_BITS)
#define ALIGN_MASK (ALIGN_TABLE_SIZE - 1)
#define ALIGN_SIZE (1 << ALIGN_BITS)
#define ALIGN_MASK (ALIGN_SIZE - 1)
// LZMA remembers the four most recent match distances. Reusing these distances
// tends to take less space than re-encoding the actual distance value.
#define REP_DISTANCES 4
#define REPS 4
#endif

View File

@@ -16,6 +16,12 @@
#include "lzma_decoder.h"
#include "range_decoder.h"
// The macros unroll loops with switch statements.
// Silence warnings about missing fall-through comments.
#if TUKLIB_GNUC_REQ(7, 0)
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
#ifdef HAVE_SMALL
@@ -161,7 +167,7 @@ typedef struct {
} lzma_length_decoder;
struct lzma_coder_s {
typedef struct {
///////////////////
// Probabilities //
///////////////////
@@ -193,15 +199,15 @@ struct lzma_coder_s {
/// Probability tree for the highest two bits of the match distance.
/// There is a separate probability tree for match lengths of
/// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
probability dist_slot[DIST_STATES][DIST_SLOTS];
/// Probability trees for additional bits for match distance when the
/// distance is in the range [4, 127].
probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
probability pos_special[FULL_DISTANCES - DIST_MODEL_END];
/// Probability tree for the lowest four bits of a match distance
/// that is equal to or greater than 128.
probability pos_align[ALIGN_TABLE_SIZE];
probability pos_align[ALIGN_SIZE];
/// Length of a normal match
lzma_length_decoder match_len_decoder;
@@ -245,8 +251,8 @@ struct lzma_coder_s {
SEQ_LITERAL_WRITE,
SEQ_IS_REP,
seq_len(SEQ_MATCH_LEN),
seq_6(SEQ_POS_SLOT),
SEQ_POS_MODEL,
seq_6(SEQ_DIST_SLOT),
SEQ_DIST_MODEL,
SEQ_DIRECT,
seq_4(SEQ_ALIGN),
SEQ_EOPM,
@@ -277,20 +283,26 @@ struct lzma_coder_s {
/// If decoding a literal: match byte.
/// If decoding a match: length of the match.
uint32_t len;
};
} lzma_lzma1_decoder;
static lzma_ret
lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
lzma_decode(void *coder_ptr, lzma_dict *restrict dictptr,
const uint8_t *restrict in,
size_t *restrict in_pos, size_t in_size)
{
lzma_lzma1_decoder *restrict coder = coder_ptr;
////////////////////
// Initialization //
////////////////////
if (!rc_read_init(&coder->rc, in, in_pos, in_size))
return LZMA_OK;
{
const lzma_ret ret = rc_read_init(
&coder->rc, in, in_pos, in_size);
if (ret != LZMA_STREAM_END)
return ret;
}
///////////////
// Variables //
@@ -502,28 +514,28 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
// Prepare to decode the highest two bits of the
// match distance.
probs = coder->pos_slot[get_len_to_pos_state(len)];
probs = coder->dist_slot[get_dist_state(len)];
symbol = 1;
#ifdef HAVE_SMALL
case SEQ_POS_SLOT:
case SEQ_DIST_SLOT:
do {
rc_bit(probs[symbol], , , SEQ_POS_SLOT);
} while (symbol < POS_SLOTS);
rc_bit(probs[symbol], , , SEQ_DIST_SLOT);
} while (symbol < DIST_SLOTS);
#else
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT0);
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT1);
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT2);
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT3);
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT4);
rc_bit_case(probs[symbol], , , SEQ_POS_SLOT5);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT0);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT1);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT2);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT3);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT4);
rc_bit_case(probs[symbol], , , SEQ_DIST_SLOT5);
#endif
// Get rid of the highest bit that was needed for
// indexing of the probability array.
symbol -= POS_SLOTS;
symbol -= DIST_SLOTS;
assert(symbol <= 63);
if (symbol < START_POS_MODEL_INDEX) {
if (symbol < DIST_MODEL_START) {
// Match distances [0, 3] have only two bits.
rep0 = symbol;
} else {
@@ -533,7 +545,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
assert(limit >= 1 && limit <= 30);
rep0 = 2 + (symbol & 1);
if (symbol < END_POS_MODEL_INDEX) {
if (symbol < DIST_MODEL_END) {
// Prepare to decode the low bits for
// a distance of [4, 127].
assert(limit <= 5);
@@ -553,12 +565,12 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
- symbol - 1;
symbol = 1;
offset = 0;
case SEQ_POS_MODEL:
case SEQ_DIST_MODEL:
#ifdef HAVE_SMALL
do {
rc_bit(probs[symbol], ,
rep0 += 1 << offset,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
} while (++offset < limit);
#else
switch (limit) {
@@ -566,25 +578,25 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
assert(offset == 0);
rc_bit(probs[symbol], ,
rep0 += 1,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
++offset;
--limit;
case 4:
rc_bit(probs[symbol], ,
rep0 += 1 << offset,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
++offset;
--limit;
case 3:
rc_bit(probs[symbol], ,
rep0 += 1 << offset,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
++offset;
--limit;
case 2:
rc_bit(probs[symbol], ,
rep0 += 1 << offset,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
++offset;
--limit;
case 1:
@@ -596,7 +608,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
// "symbol".
rc_bit_last(probs[symbol], ,
rep0 += 1 << offset,
SEQ_POS_MODEL);
SEQ_DIST_MODEL);
}
#endif
} else {
@@ -637,7 +649,7 @@ lzma_decode(lzma_coder *restrict coder, lzma_dict *restrict dictptr,
rc_bit(coder->pos_align[symbol], ,
rep0 += 4, SEQ_ALIGN2);
case SEQ_ALIGN3:
// Like in SEQ_POS_MODEL, we don't
// Like in SEQ_DIST_MODEL, we don't
// need "symbol" for anything else
// than indexing the probability array.
rc_bit_last(coder->pos_align[symbol], ,
@@ -836,23 +848,17 @@ out:
static void
lzma_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size)
{
lzma_lzma1_decoder *coder = coder_ptr;
coder->uncompressed_size = uncompressed_size;
}
/*
extern void
lzma_lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size)
{
// This is hack.
(*(lzma_coder **)(coder))->uncompressed_size = uncompressed_size;
}
*/
static void
lzma_decoder_reset(lzma_coder *coder, const void *opt)
lzma_decoder_reset(void *coder_ptr, const void *opt)
{
lzma_lzma1_decoder *coder = coder_ptr;
const lzma_options_lzma *options = opt;
// NOTE: We assume that lc/lp/pb are valid since they were
@@ -891,10 +897,10 @@ lzma_decoder_reset(lzma_coder *coder, const void *opt)
bit_reset(coder->is_rep2[i]);
}
for (uint32_t i = 0; i < LEN_TO_POS_STATES; ++i)
bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
for (uint32_t i = 0; i < DIST_STATES; ++i)
bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
for (uint32_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
for (uint32_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
bit_reset(coder->pos_special[i]);
bittree_reset(coder->pos_align, ALIGN_BITS);
@@ -933,11 +939,11 @@ lzma_decoder_reset(lzma_coder *coder, const void *opt)
extern lzma_ret
lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator,
lzma_lzma_decoder_create(lzma_lz_decoder *lz, const lzma_allocator *allocator,
const void *opt, lzma_lz_options *lz_options)
{
if (lz->coder == NULL) {
lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
lz->coder = lzma_alloc(sizeof(lzma_lzma1_decoder), allocator);
if (lz->coder == NULL)
return LZMA_MEM_ERROR;
@@ -961,7 +967,7 @@ lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator,
/// initialization (lzma_lzma_decoder_init() passes function pointer to
/// the LZ initialization).
static lzma_ret
lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
lzma_decoder_init(lzma_lz_decoder *lz, const lzma_allocator *allocator,
const void *options, lzma_lz_options *lz_options)
{
if (!is_lclppb_valid(options))
@@ -978,7 +984,7 @@ lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
extern lzma_ret
lzma_lzma_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lzma_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
// LZMA can only be the last filter in the chain. This is enforced
@@ -1010,7 +1016,8 @@ extern uint64_t
lzma_lzma_decoder_memusage_nocheck(const void *options)
{
const lzma_options_lzma *const opt = options;
return sizeof(lzma_coder) + lzma_lz_decoder_memusage(opt->dict_size);
return sizeof(lzma_lzma1_decoder)
+ lzma_lz_decoder_memusage(opt->dict_size);
}
@@ -1025,7 +1032,7 @@ lzma_lzma_decoder_memusage(const void *options)
extern lzma_ret
lzma_lzma_props_decode(void **options, lzma_allocator *allocator,
lzma_lzma_props_decode(void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
if (props_size != 5)

View File

@@ -19,12 +19,13 @@
/// Allocates and initializes LZMA decoder
extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern uint64_t lzma_lzma_decoder_memusage(const void *options);
extern lzma_ret lzma_lzma_props_decode(
void **options, lzma_allocator *allocator,
void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
@@ -40,7 +41,7 @@ extern bool lzma_lzma_lclppb_decode(
/// Allocate and setup function pointers only. This is used by LZMA1 and
/// LZMA2 decoders.
extern lzma_ret lzma_lzma_decoder_create(
lzma_lz_decoder *lz, lzma_allocator *allocator,
lzma_lz_decoder *lz, const lzma_allocator *allocator,
const void *opt, lzma_lz_options *lz_options);
/// Gets memory usage without validating lc/lp/pb. This is used by LZMA2

View File

@@ -43,7 +43,7 @@ literal_matched(lzma_range_encoder *rc, probability *subcoder,
static inline void
literal(lzma_coder *coder, lzma_mf *mf, uint32_t position)
literal(lzma_lzma1_encoder *coder, lzma_mf *mf, uint32_t position)
{
// Locate the literal byte to be encoded and the subcoder.
const uint8_t cur_byte = mf->buffer[
@@ -140,7 +140,7 @@ length(lzma_range_encoder *rc, lzma_length_encoder *lc,
///////////
static inline void
match(lzma_coder *coder, const uint32_t pos_state,
match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
const uint32_t distance, const uint32_t len)
{
update_match(coder->state);
@@ -148,28 +148,28 @@ match(lzma_coder *coder, const uint32_t pos_state,
length(&coder->rc, &coder->match_len_encoder, pos_state, len,
coder->fast_mode);
const uint32_t pos_slot = get_pos_slot(distance);
const uint32_t len_to_pos_state = get_len_to_pos_state(len);
rc_bittree(&coder->rc, coder->pos_slot[len_to_pos_state],
POS_SLOT_BITS, pos_slot);
const uint32_t dist_slot = get_dist_slot(distance);
const uint32_t dist_state = get_dist_state(len);
rc_bittree(&coder->rc, coder->dist_slot[dist_state],
DIST_SLOT_BITS, dist_slot);
if (pos_slot >= START_POS_MODEL_INDEX) {
const uint32_t footer_bits = (pos_slot >> 1) - 1;
const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
const uint32_t pos_reduced = distance - base;
if (dist_slot >= DIST_MODEL_START) {
const uint32_t footer_bits = (dist_slot >> 1) - 1;
const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
const uint32_t dist_reduced = distance - base;
if (pos_slot < END_POS_MODEL_INDEX) {
// Careful here: base - pos_slot - 1 can be -1, but
if (dist_slot < DIST_MODEL_END) {
// Careful here: base - dist_slot - 1 can be -1, but
// rc_bittree_reverse starts at probs[1], not probs[0].
rc_bittree_reverse(&coder->rc,
coder->pos_special + base - pos_slot - 1,
footer_bits, pos_reduced);
coder->dist_special + base - dist_slot - 1,
footer_bits, dist_reduced);
} else {
rc_direct(&coder->rc, pos_reduced >> ALIGN_BITS,
rc_direct(&coder->rc, dist_reduced >> ALIGN_BITS,
footer_bits - ALIGN_BITS);
rc_bittree_reverse(
&coder->rc, coder->pos_align,
ALIGN_BITS, pos_reduced & ALIGN_MASK);
&coder->rc, coder->dist_align,
ALIGN_BITS, dist_reduced & ALIGN_MASK);
++coder->align_price_count;
}
}
@@ -187,7 +187,7 @@ match(lzma_coder *coder, const uint32_t pos_state,
////////////////////
static inline void
rep_match(lzma_coder *coder, const uint32_t pos_state,
rep_match(lzma_lzma1_encoder *coder, const uint32_t pos_state,
const uint32_t rep, const uint32_t len)
{
if (rep == 0) {
@@ -231,7 +231,7 @@ rep_match(lzma_coder *coder, const uint32_t pos_state,
//////////
static void
encode_symbol(lzma_coder *coder, lzma_mf *mf,
encode_symbol(lzma_lzma1_encoder *coder, lzma_mf *mf,
uint32_t back, uint32_t len, uint32_t position)
{
const uint32_t pos_state = position & coder->pos_mask;
@@ -247,7 +247,7 @@ encode_symbol(lzma_coder *coder, lzma_mf *mf,
rc_bit(&coder->rc,
&coder->is_match[coder->state][pos_state], 1);
if (back < REP_DISTANCES) {
if (back < REPS) {
// It's a repeated match i.e. the same distance
// has been used earlier.
rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);
@@ -255,7 +255,7 @@ encode_symbol(lzma_coder *coder, lzma_mf *mf,
} else {
// Normal match
rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
match(coder, pos_state, back - REP_DISTANCES, len);
match(coder, pos_state, back - REPS, len);
}
}
@@ -265,7 +265,7 @@ encode_symbol(lzma_coder *coder, lzma_mf *mf,
static bool
encode_init(lzma_coder *coder, lzma_mf *mf)
encode_init(lzma_lzma1_encoder *coder, lzma_mf *mf)
{
assert(mf_position(mf) == 0);
@@ -293,7 +293,7 @@ encode_init(lzma_coder *coder, lzma_mf *mf)
static void
encode_eopm(lzma_coder *coder, uint32_t position)
encode_eopm(lzma_lzma1_encoder *coder, uint32_t position)
{
const uint32_t pos_state = position & coder->pos_mask;
rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);
@@ -309,7 +309,7 @@ encode_eopm(lzma_coder *coder, uint32_t position)
extern lzma_ret
lzma_lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma_lzma_encode(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size, uint32_t limit)
{
@@ -353,9 +353,9 @@ lzma_lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
// Get optimal match (repeat position and length).
// Value ranges for pos:
// - [0, REP_DISTANCES): repeated match
// - [REP_DISTANCES, UINT32_MAX):
// match at (pos - REP_DISTANCES)
// - [0, REPS): repeated match
// - [REPS, UINT32_MAX):
// match at (pos - REPS)
// - UINT32_MAX: not a match but a literal
// Value ranges for len:
// - [MATCH_LEN_MIN, MATCH_LEN_MAX]
@@ -402,7 +402,7 @@ lzma_lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
static lzma_ret
lzma_encode(lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma_encode(void *coder, lzma_mf *restrict mf,
uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size)
{
@@ -464,7 +464,7 @@ length_encoder_reset(lzma_length_encoder *lencoder,
bittree_reset(lencoder->high, LEN_HIGH_BITS);
if (!fast_mode)
for (size_t pos_state = 0; pos_state < num_pos_states;
for (uint32_t pos_state = 0; pos_state < num_pos_states;
++pos_state)
length_update_prices(lencoder, pos_state);
@@ -473,7 +473,8 @@ length_encoder_reset(lzma_length_encoder *lencoder,
extern lzma_ret
lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
lzma_lzma_encoder_reset(lzma_lzma1_encoder *coder,
const lzma_options_lzma *options)
{
if (!is_options_valid(options))
return LZMA_OPTIONS_ERROR;
@@ -487,7 +488,7 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
// State
coder->state = STATE_LIT_LIT;
for (size_t i = 0; i < REP_DISTANCES; ++i)
for (size_t i = 0; i < REPS; ++i)
coder->reps[i] = 0;
literal_init(coder->literal, options->lc, options->lp);
@@ -505,14 +506,14 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
bit_reset(coder->is_rep2[i]);
}
for (size_t i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
bit_reset(coder->pos_special[i]);
for (size_t i = 0; i < FULL_DISTANCES - DIST_MODEL_END; ++i)
bit_reset(coder->dist_special[i]);
// Bit tree encoders
for (size_t i = 0; i < LEN_TO_POS_STATES; ++i)
bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
for (size_t i = 0; i < DIST_STATES; ++i)
bittree_reset(coder->dist_slot[i], DIST_SLOT_BITS);
bittree_reset(coder->pos_align, ALIGN_BITS);
bittree_reset(coder->dist_align, ALIGN_BITS);
// Length encoders
length_encoder_reset(&coder->match_len_encoder,
@@ -545,17 +546,18 @@ lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
extern lzma_ret
lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator,
lzma_lzma_encoder_create(void **coder_ptr,
const lzma_allocator *allocator,
const lzma_options_lzma *options, lzma_lz_options *lz_options)
{
// Allocate lzma_coder if it wasn't already allocated.
// Allocate lzma_lzma1_encoder if it wasn't already allocated.
if (*coder_ptr == NULL) {
*coder_ptr = lzma_alloc(sizeof(lzma_coder), allocator);
*coder_ptr = lzma_alloc(sizeof(lzma_lzma1_encoder), allocator);
if (*coder_ptr == NULL)
return LZMA_MEM_ERROR;
}
lzma_coder *coder = *coder_ptr;
lzma_lzma1_encoder *coder = *coder_ptr;
// Set compression mode. We haven't validates the options yet,
// but it's OK here, since nothing bad happens with invalid
@@ -604,7 +606,7 @@ lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator,
static lzma_ret
lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
lzma_encoder_init(lzma_lz_encoder *lz, const lzma_allocator *allocator,
const void *options, lzma_lz_options *lz_options)
{
lz->code = &lzma_encode;
@@ -614,7 +616,7 @@ lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
extern lzma_ret
lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_lzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return lzma_lz_encoder_init(
@@ -635,7 +637,7 @@ lzma_lzma_encoder_memusage(const void *options)
if (lz_memusage == UINT64_MAX)
return UINT64_MAX;
return (uint64_t)(sizeof(lzma_coder)) + lz_memusage;
return (uint64_t)(sizeof(lzma_lzma1_encoder)) + lz_memusage;
}

View File

@@ -17,8 +17,12 @@
#include "common.h"
typedef struct lzma_lzma1_encoder_s lzma_lzma1_encoder;
extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern uint64_t lzma_lzma_encoder_memusage(const void *options);
@@ -35,16 +39,16 @@ extern bool lzma_lzma_lclppb_encode(
/// Initializes raw LZMA encoder; this is used by LZMA2.
extern lzma_ret lzma_lzma_encoder_create(
lzma_coder **coder_ptr, lzma_allocator *allocator,
void **coder_ptr, const lzma_allocator *allocator,
const lzma_options_lzma *options, lzma_lz_options *lz_options);
/// Resets an already initialized LZMA encoder; this is used by LZMA2.
extern lzma_ret lzma_lzma_encoder_reset(
lzma_coder *coder, const lzma_options_lzma *options);
lzma_lzma1_encoder *coder, const lzma_options_lzma *options);
extern lzma_ret lzma_lzma_encode(lzma_coder *restrict coder,
extern lzma_ret lzma_lzma_encode(lzma_lzma1_encoder *restrict coder,
lzma_mf *restrict mf, uint8_t *restrict out,
size_t *restrict out_pos, size_t out_size,
uint32_t read_limit);

View File

@@ -10,6 +10,7 @@
///////////////////////////////////////////////////////////////////////////////
#include "lzma_encoder_private.h"
#include "memcmplen.h"
#define change_pair(small_dist, big_dist) \
@@ -17,7 +18,8 @@
extern void
lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma_lzma_optimum_fast(lzma_lzma1_encoder *restrict coder,
lzma_mf *restrict mf,
uint32_t *restrict back_res, uint32_t *restrict len_res)
{
const uint32_t nice_len = mf->nice_len;
@@ -46,7 +48,7 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
uint32_t rep_len = 0;
uint32_t rep_index = 0;
for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
for (uint32_t i = 0; i < REPS; ++i) {
// Pointer to the beginning of the match candidate
const uint8_t *const buf_back = buf - coder->reps[i] - 1;
@@ -57,9 +59,8 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
// The first two bytes matched.
// Calculate the length of the match.
uint32_t len;
for (len = 2; len < buf_avail
&& buf[len] == buf_back[len]; ++len) ;
const uint32_t len = lzma_memcmplen(
buf, buf_back, 2, buf_avail);
// If we have found a repeated match that is at least
// nice_len long, return it immediately.
@@ -79,8 +80,7 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
// We didn't find a long enough repeated match. Encode it as a normal
// match if the match length is at least nice_len.
if (len_main >= nice_len) {
*back_res = coder->matches[matches_count - 1].dist
+ REP_DISTANCES;
*back_res = coder->matches[matches_count - 1].dist + REPS;
*len_res = len_main;
mf_skip(mf, len_main - 1);
return;
@@ -153,26 +153,17 @@ lzma_lzma_optimum_fast(lzma_coder *restrict coder, lzma_mf *restrict mf,
// the old buf pointer instead of recalculating it with mf_ptr().
++buf;
const uint32_t limit = len_main - 1;
const uint32_t limit = my_max(2, len_main - 1);
for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
const uint8_t *const buf_back = buf - coder->reps[i] - 1;
if (not_equal_16(buf, buf_back))
continue;
uint32_t len;
for (len = 2; len < limit
&& buf[len] == buf_back[len]; ++len) ;
if (len >= limit) {
for (uint32_t i = 0; i < REPS; ++i) {
if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) {
*back_res = UINT32_MAX;
*len_res = 1;
return;
}
}
*back_res = back_main + REP_DISTANCES;
*back_res = back_main + REPS;
*len_res = len_main;
mf_skip(mf, len_main - 2);
return;

View File

@@ -11,6 +11,7 @@
#include "lzma_encoder_private.h"
#include "fastpos.h"
#include "memcmplen.h"
////////////
@@ -18,7 +19,7 @@
////////////
static uint32_t
get_literal_price(const lzma_coder *const coder, const uint32_t pos,
get_literal_price(const lzma_lzma1_encoder *const coder, const uint32_t pos,
const uint32_t prev_byte, const bool match_mode,
uint32_t match_byte, uint32_t symbol)
{
@@ -64,7 +65,7 @@ get_len_price(const lzma_length_encoder *const lencoder,
static inline uint32_t
get_short_rep_price(const lzma_coder *const coder,
get_short_rep_price(const lzma_lzma1_encoder *const coder,
const lzma_lzma_state state, const uint32_t pos_state)
{
return rc_bit_0_price(coder->is_rep0[state])
@@ -73,7 +74,7 @@ get_short_rep_price(const lzma_coder *const coder,
static inline uint32_t
get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
get_pure_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
const lzma_lzma_state state, uint32_t pos_state)
{
uint32_t price;
@@ -98,7 +99,7 @@ get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
static inline uint32_t
get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
get_rep_price(const lzma_lzma1_encoder *const coder, const uint32_t rep_index,
const uint32_t len, const lzma_lzma_state state,
const uint32_t pos_state)
{
@@ -108,18 +109,18 @@ get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
static inline uint32_t
get_pos_len_price(const lzma_coder *const coder, const uint32_t pos,
get_dist_len_price(const lzma_lzma1_encoder *const coder, const uint32_t dist,
const uint32_t len, const uint32_t pos_state)
{
const uint32_t len_to_pos_state = get_len_to_pos_state(len);
const uint32_t dist_state = get_dist_state(len);
uint32_t price;
if (pos < FULL_DISTANCES) {
price = coder->distances_prices[len_to_pos_state][pos];
if (dist < FULL_DISTANCES) {
price = coder->dist_prices[dist_state][dist];
} else {
const uint32_t pos_slot = get_pos_slot_2(pos);
price = coder->pos_slot_prices[len_to_pos_state][pos_slot]
+ coder->align_prices[pos & ALIGN_MASK];
const uint32_t dist_slot = get_dist_slot_2(dist);
price = coder->dist_slot_prices[dist_state][dist_slot]
+ coder->align_prices[dist & ALIGN_MASK];
}
price += get_len_price(&coder->match_len_encoder, len, pos_state);
@@ -129,55 +130,53 @@ get_pos_len_price(const lzma_coder *const coder, const uint32_t pos,
static void
fill_distances_prices(lzma_coder *coder)
fill_dist_prices(lzma_lzma1_encoder *coder)
{
for (uint32_t len_to_pos_state = 0;
len_to_pos_state < LEN_TO_POS_STATES;
++len_to_pos_state) {
for (uint32_t dist_state = 0; dist_state < DIST_STATES; ++dist_state) {
uint32_t *const pos_slot_prices
= coder->pos_slot_prices[len_to_pos_state];
uint32_t *const dist_slot_prices
= coder->dist_slot_prices[dist_state];
// Price to encode the pos_slot.
for (uint32_t pos_slot = 0;
pos_slot < coder->dist_table_size; ++pos_slot)
pos_slot_prices[pos_slot] = rc_bittree_price(
coder->pos_slot[len_to_pos_state],
POS_SLOT_BITS, pos_slot);
// Price to encode the dist_slot.
for (uint32_t dist_slot = 0;
dist_slot < coder->dist_table_size; ++dist_slot)
dist_slot_prices[dist_slot] = rc_bittree_price(
coder->dist_slot[dist_state],
DIST_SLOT_BITS, dist_slot);
// For matches with distance >= FULL_DISTANCES, add the price
// of the direct bits part of the match distance. (Align bits
// are handled by fill_align_prices()).
for (uint32_t pos_slot = END_POS_MODEL_INDEX;
pos_slot < coder->dist_table_size; ++pos_slot)
pos_slot_prices[pos_slot] += rc_direct_price(
((pos_slot >> 1) - 1) - ALIGN_BITS);
for (uint32_t dist_slot = DIST_MODEL_END;
dist_slot < coder->dist_table_size;
++dist_slot)
dist_slot_prices[dist_slot] += rc_direct_price(
((dist_slot >> 1) - 1) - ALIGN_BITS);
// Distances in the range [0, 3] are fully encoded with
// pos_slot, so they are used for coder->distances_prices
// dist_slot, so they are used for coder->dist_prices
// as is.
for (uint32_t i = 0; i < START_POS_MODEL_INDEX; ++i)
coder->distances_prices[len_to_pos_state][i]
= pos_slot_prices[i];
for (uint32_t i = 0; i < DIST_MODEL_START; ++i)
coder->dist_prices[dist_state][i]
= dist_slot_prices[i];
}
// Distances in the range [4, 127] depend on pos_slot and pos_special.
// We do this in a loop separate from the above loop to avoid
// redundant calls to get_pos_slot().
for (uint32_t i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) {
const uint32_t pos_slot = get_pos_slot(i);
const uint32_t footer_bits = ((pos_slot >> 1) - 1);
const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
// Distances in the range [4, 127] depend on dist_slot and
// dist_special. We do this in a loop separate from the above
// loop to avoid redundant calls to get_dist_slot().
for (uint32_t i = DIST_MODEL_START; i < FULL_DISTANCES; ++i) {
const uint32_t dist_slot = get_dist_slot(i);
const uint32_t footer_bits = ((dist_slot >> 1) - 1);
const uint32_t base = (2 | (dist_slot & 1)) << footer_bits;
const uint32_t price = rc_bittree_reverse_price(
coder->pos_special + base - pos_slot - 1,
coder->dist_special + base - dist_slot - 1,
footer_bits, i - base);
for (uint32_t len_to_pos_state = 0;
len_to_pos_state < LEN_TO_POS_STATES;
++len_to_pos_state)
coder->distances_prices[len_to_pos_state][i]
= price + coder->pos_slot_prices[
len_to_pos_state][pos_slot];
for (uint32_t dist_state = 0; dist_state < DIST_STATES;
++dist_state)
coder->dist_prices[dist_state][i]
= price + coder->dist_slot_prices[
dist_state][dist_slot];
}
coder->match_price_count = 0;
@@ -186,11 +185,11 @@ fill_distances_prices(lzma_coder *coder)
static void
fill_align_prices(lzma_coder *coder)
fill_align_prices(lzma_lzma1_encoder *coder)
{
for (uint32_t i = 0; i < ALIGN_TABLE_SIZE; ++i)
for (uint32_t i = 0; i < ALIGN_SIZE; ++i)
coder->align_prices[i] = rc_bittree_reverse_price(
coder->pos_align, ALIGN_BITS, i);
coder->dist_align, ALIGN_BITS, i);
coder->align_price_count = 0;
return;
@@ -222,7 +221,7 @@ make_short_rep(lzma_optimal *optimal)
static void
backward(lzma_coder *restrict coder, uint32_t *restrict len_res,
backward(lzma_lzma1_encoder *restrict coder, uint32_t *restrict len_res,
uint32_t *restrict back_res, uint32_t cur)
{
coder->opts_end_index = cur;
@@ -270,7 +269,7 @@ backward(lzma_coder *restrict coder, uint32_t *restrict len_res,
//////////
static inline uint32_t
helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
helper1(lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
uint32_t *restrict back_res, uint32_t *restrict len_res,
uint32_t position)
{
@@ -296,10 +295,10 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
const uint8_t *const buf = mf_ptr(mf) - 1;
uint32_t rep_lens[REP_DISTANCES];
uint32_t rep_lens[REPS];
uint32_t rep_max_index = 0;
for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
for (uint32_t i = 0; i < REPS; ++i) {
const uint8_t *const buf_back = buf - coder->reps[i] - 1;
if (not_equal_16(buf, buf_back)) {
@@ -307,13 +306,9 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
continue;
}
uint32_t len_test;
for (len_test = 2; len_test < buf_avail
&& buf[len_test] == buf_back[len_test];
++len_test) ;
rep_lens[i] = lzma_memcmplen(buf, buf_back, 2, buf_avail);
rep_lens[i] = len_test;
if (len_test > rep_lens[rep_max_index])
if (rep_lens[i] > rep_lens[rep_max_index])
rep_max_index = i;
}
@@ -326,8 +321,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
if (len_main >= nice_len) {
*back_res = coder->matches[matches_count - 1].dist
+ REP_DISTANCES;
*back_res = coder->matches[matches_count - 1].dist + REPS;
*len_res = len_main;
mf_skip(mf, len_main - 1);
return UINT32_MAX;
@@ -381,7 +375,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
coder->opts[1].pos_prev = 0;
for (uint32_t i = 0; i < REP_DISTANCES; ++i)
for (uint32_t i = 0; i < REPS; ++i)
coder->opts[0].backs[i] = coder->reps[i];
uint32_t len = len_end;
@@ -390,7 +384,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
} while (--len >= 2);
for (uint32_t i = 0; i < REP_DISTANCES; ++i) {
for (uint32_t i = 0; i < REPS; ++i) {
uint32_t rep_len = rep_lens[i];
if (rep_len < 2)
continue;
@@ -426,14 +420,13 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
for(; ; ++len) {
const uint32_t dist = coder->matches[i].dist;
const uint32_t cur_and_len_price = normal_match_price
+ get_pos_len_price(coder,
+ get_dist_len_price(coder,
dist, len, pos_state);
if (cur_and_len_price < coder->opts[len].price) {
coder->opts[len].price = cur_and_len_price;
coder->opts[len].pos_prev = 0;
coder->opts[len].back_prev
= dist + REP_DISTANCES;
coder->opts[len].back_prev = dist + REPS;
coder->opts[len].prev_1_is_literal = false;
}
@@ -448,7 +441,7 @@ helper1(lzma_coder *restrict coder, lzma_mf *restrict mf,
static inline uint32_t
helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
helper2(lzma_lzma1_encoder *coder, uint32_t *reps, const uint8_t *buf,
uint32_t len_end, uint32_t position, const uint32_t cur,
const uint32_t nice_len, const uint32_t buf_avail_full)
{
@@ -463,7 +456,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
if (coder->opts[cur].prev_2) {
state = coder->opts[coder->opts[cur].pos_prev_2].state;
if (coder->opts[cur].back_prev_2 < REP_DISTANCES)
if (coder->opts[cur].back_prev_2 < REPS)
update_long_rep(state);
else
update_match(state);
@@ -492,33 +485,33 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
update_long_rep(state);
} else {
pos = coder->opts[cur].back_prev;
if (pos < REP_DISTANCES)
if (pos < REPS)
update_long_rep(state);
else
update_match(state);
}
if (pos < REP_DISTANCES) {
if (pos < REPS) {
reps[0] = coder->opts[pos_prev].backs[pos];
uint32_t i;
for (i = 1; i <= pos; ++i)
reps[i] = coder->opts[pos_prev].backs[i - 1];
for (; i < REP_DISTANCES; ++i)
for (; i < REPS; ++i)
reps[i] = coder->opts[pos_prev].backs[i];
} else {
reps[0] = pos - REP_DISTANCES;
reps[0] = pos - REPS;
for (uint32_t i = 1; i < REP_DISTANCES; ++i)
for (uint32_t i = 1; i < REPS; ++i)
reps[i] = coder->opts[pos_prev].backs[i - 1];
}
}
coder->opts[cur].state = state;
for (uint32_t i = 0; i < REP_DISTANCES; ++i)
for (uint32_t i = 0; i < REPS; ++i)
coder->opts[cur].backs[i] = reps[i];
const uint32_t cur_price = coder->opts[cur].price;
@@ -572,11 +565,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
const uint8_t *const buf_back = buf - reps[0] - 1;
const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
uint32_t len_test = 1;
while (len_test < limit && buf[len_test] == buf_back[len_test])
++len_test;
--len_test;
const uint32_t len_test = lzma_memcmplen(buf, buf_back, 1, limit) - 1;
if (len_test >= 2) {
lzma_lzma_state state_2 = state;
@@ -611,15 +600,12 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
uint32_t start_len = 2; // speed optimization
for (uint32_t rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) {
for (uint32_t rep_index = 0; rep_index < REPS; ++rep_index) {
const uint8_t *const buf_back = buf - reps[rep_index] - 1;
if (not_equal_16(buf, buf_back))
continue;
uint32_t len_test;
for (len_test = 2; len_test < buf_avail
&& buf[len_test] == buf_back[len_test];
++len_test) ;
uint32_t len_test = lzma_memcmplen(buf, buf_back, 2, buf_avail);
while (len_end < cur + len_test)
coder->opts[++len_end].price = RC_INFINITY_PRICE;
@@ -728,14 +714,14 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
for (uint32_t len_test = start_len; ; ++len_test) {
const uint32_t cur_back = coder->matches[i].dist;
uint32_t cur_and_len_price = normal_match_price
+ get_pos_len_price(coder,
+ get_dist_len_price(coder,
cur_back, len_test, pos_state);
if (cur_and_len_price < coder->opts[cur + len_test].price) {
coder->opts[cur + len_test].price = cur_and_len_price;
coder->opts[cur + len_test].pos_prev = cur;
coder->opts[cur + len_test].back_prev
= cur_back + REP_DISTANCES;
= cur_back + REPS;
coder->opts[cur + len_test].prev_1_is_literal = false;
}
@@ -795,7 +781,7 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
coder->opts[offset].prev_2 = true;
coder->opts[offset].pos_prev_2 = cur;
coder->opts[offset].back_prev_2
= cur_back + REP_DISTANCES;
= cur_back + REPS;
}
//}
}
@@ -811,7 +797,8 @@ helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
extern void
lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
lzma_mf *restrict mf,
uint32_t *restrict back_res, uint32_t *restrict len_res,
uint32_t position)
{
@@ -831,9 +818,9 @@ lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf,
// In liblzma they were moved into this single place.
if (mf->read_ahead == 0) {
if (coder->match_price_count >= (1 << 7))
fill_distances_prices(coder);
fill_dist_prices(coder);
if (coder->align_price_count >= ALIGN_TABLE_SIZE)
if (coder->align_price_count >= ALIGN_SIZE)
fill_align_prices(coder);
}
@@ -845,7 +832,7 @@ lzma_lzma_optimum_normal(lzma_coder *restrict coder, lzma_mf *restrict mf,
if (len_end == UINT32_MAX)
return;
uint32_t reps[REP_DISTANCES];
uint32_t reps[REPS];
memcpy(reps, coder->reps, sizeof(reps));
uint32_t cur;

View File

@@ -2,6 +2,7 @@
//
/// \file lzma_encoder_presets.c
/// \brief Encoder presets
/// \note xz needs this even when only decoding is enabled.
//
// Author: Lasse Collin
//

View File

@@ -64,12 +64,12 @@ typedef struct {
uint32_t pos_prev; // pos_next;
uint32_t back_prev;
uint32_t backs[REP_DISTANCES];
uint32_t backs[REPS];
} lzma_optimal;
struct lzma_coder_s {
struct lzma_lzma1_encoder_s {
/// Range encoder
lzma_range_encoder rc;
@@ -77,7 +77,7 @@ struct lzma_coder_s {
lzma_lzma_state state;
/// The four most recent match distances
uint32_t reps[REP_DISTANCES];
uint32_t reps[REPS];
/// Array of match candidates
lzma_match matches[MATCH_LEN_MAX + 1];
@@ -112,9 +112,9 @@ struct lzma_coder_s {
probability is_rep1[STATES];
probability is_rep2[STATES];
probability is_rep0_long[STATES][POS_STATES_MAX];
probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
probability pos_align[ALIGN_TABLE_SIZE];
probability dist_slot[DIST_STATES][DIST_SLOTS];
probability dist_special[FULL_DISTANCES - DIST_MODEL_END];
probability dist_align[ALIGN_SIZE];
// These are the same as in lzma_decoder.c except that the encoders
// include also price tables.
@@ -122,12 +122,12 @@ struct lzma_coder_s {
lzma_length_encoder rep_len_encoder;
// Price tables
uint32_t pos_slot_prices[LEN_TO_POS_STATES][POS_SLOTS];
uint32_t distances_prices[LEN_TO_POS_STATES][FULL_DISTANCES];
uint32_t dist_slot_prices[DIST_STATES][DIST_SLOTS];
uint32_t dist_prices[DIST_STATES][FULL_DISTANCES];
uint32_t dist_table_size;
uint32_t match_price_count;
uint32_t align_prices[ALIGN_TABLE_SIZE];
uint32_t align_prices[ALIGN_SIZE];
uint32_t align_price_count;
// Optimal
@@ -138,10 +138,10 @@ struct lzma_coder_s {
extern void lzma_lzma_optimum_fast(
lzma_coder *restrict coder, lzma_mf *restrict mf,
lzma_lzma1_encoder *restrict coder, lzma_mf *restrict mf,
uint32_t *restrict back_res, uint32_t *restrict len_res);
extern void lzma_lzma_optimum_normal(lzma_coder *restrict coder,
extern void lzma_lzma_optimum_normal(lzma_lzma1_encoder *restrict coder,
lzma_mf *restrict mf, uint32_t *restrict back_res,
uint32_t *restrict len_res, uint32_t position);

View File

@@ -25,20 +25,26 @@ typedef struct {
/// Reads the first five bytes to initialize the range decoder.
static inline bool
static inline lzma_ret
rc_read_init(lzma_range_decoder *rc, const uint8_t *restrict in,
size_t *restrict in_pos, size_t in_size)
{
while (rc->init_bytes_left > 0) {
if (*in_pos == in_size)
return false;
return LZMA_OK;
// The first byte is always 0x00. It could have been omitted
// in LZMA2 but it wasn't, so one byte is wasted in every
// LZMA2 chunk.
if (rc->init_bytes_left == 5 && in[*in_pos] != 0x00)
return LZMA_DATA_ERROR;
rc->code = (rc->code << 8) | in[*in_pos];
++*in_pos;
--rc->init_bytes_left;
}
return true;
return LZMA_STREAM_END;
}

View File

@@ -15,7 +15,7 @@
static size_t
arm_code(lzma_simple *simple lzma_attribute((__unused__)),
arm_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
@@ -45,7 +45,7 @@ arm_code(lzma_simple *simple lzma_attribute((__unused__)),
static lzma_ret
arm_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
arm_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
return lzma_simple_coder_init(next, allocator, filters,
@@ -54,7 +54,8 @@ arm_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_arm_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_simple_arm_encoder_init(lzma_next_coder *next,
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return arm_coder_init(next, allocator, filters, true);
@@ -62,7 +63,8 @@ lzma_simple_arm_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_arm_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_simple_arm_decoder_init(lzma_next_coder *next,
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return arm_coder_init(next, allocator, filters, false);

View File

@@ -15,7 +15,7 @@
static size_t
armthumb_code(lzma_simple *simple lzma_attribute((__unused__)),
armthumb_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
@@ -50,7 +50,7 @@ armthumb_code(lzma_simple *simple lzma_attribute((__unused__)),
static lzma_ret
armthumb_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
armthumb_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
return lzma_simple_coder_init(next, allocator, filters,
@@ -60,7 +60,8 @@ armthumb_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return armthumb_coder_init(next, allocator, filters, true);
}
@@ -68,7 +69,8 @@ lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
extern lzma_ret
lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return armthumb_coder_init(next, allocator, filters, false);
}

View File

@@ -15,7 +15,7 @@
static size_t
ia64_code(lzma_simple *simple lzma_attribute((__unused__)),
ia64_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
@@ -86,7 +86,7 @@ ia64_code(lzma_simple *simple lzma_attribute((__unused__)),
static lzma_ret
ia64_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
ia64_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
return lzma_simple_coder_init(next, allocator, filters,
@@ -96,7 +96,8 @@ ia64_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_ia64_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return ia64_coder_init(next, allocator, filters, true);
}
@@ -104,7 +105,8 @@ lzma_simple_ia64_encoder_init(lzma_next_coder *next,
extern lzma_ret
lzma_simple_ia64_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return ia64_coder_init(next, allocator, filters, false);
}

View File

@@ -15,7 +15,7 @@
static size_t
powerpc_code(lzma_simple *simple lzma_attribute((__unused__)),
powerpc_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
@@ -49,7 +49,7 @@ powerpc_code(lzma_simple *simple lzma_attribute((__unused__)),
static lzma_ret
powerpc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
powerpc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
return lzma_simple_coder_init(next, allocator, filters,
@@ -59,7 +59,8 @@ powerpc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return powerpc_coder_init(next, allocator, filters, true);
}
@@ -67,7 +68,8 @@ lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
extern lzma_ret
lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return powerpc_coder_init(next, allocator, filters, false);
}

View File

@@ -18,7 +18,7 @@
/// Copied or encodes/decodes more data to out[].
static lzma_ret
copy_or_code(lzma_coder *coder, lzma_allocator *allocator,
copy_or_code(lzma_simple_coder *coder, const 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)
@@ -55,7 +55,7 @@ copy_or_code(lzma_coder *coder, lzma_allocator *allocator,
static size_t
call_filter(lzma_coder *coder, uint8_t *buffer, size_t size)
call_filter(lzma_simple_coder *coder, uint8_t *buffer, size_t size)
{
const size_t filtered = coder->filter(coder->simple,
coder->now_pos, coder->is_encoder,
@@ -66,11 +66,13 @@ call_filter(lzma_coder *coder, uint8_t *buffer, size_t size)
static lzma_ret
simple_code(lzma_coder *coder, lzma_allocator *allocator,
simple_code(void *coder_ptr, const 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)
{
lzma_simple_coder *coder = coder_ptr;
// TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
// in cases when the filter is able to filter everything. With most
// simple filters it can be done at offset that is a multiple of 2,
@@ -198,8 +200,9 @@ simple_code(lzma_coder *coder, lzma_allocator *allocator,
static void
simple_coder_end(lzma_coder *coder, lzma_allocator *allocator)
simple_coder_end(void *coder_ptr, const lzma_allocator *allocator)
{
lzma_simple_coder *coder = coder_ptr;
lzma_next_end(&coder->next, allocator);
lzma_free(coder->simple, allocator);
lzma_free(coder, allocator);
@@ -208,10 +211,12 @@ simple_coder_end(lzma_coder *coder, lzma_allocator *allocator)
static lzma_ret
simple_coder_update(lzma_coder *coder, lzma_allocator *allocator,
simple_coder_update(void *coder_ptr, const lzma_allocator *allocator,
const lzma_filter *filters_null lzma_attribute((__unused__)),
const lzma_filter *reversed_filters)
{
lzma_simple_coder *coder = coder_ptr;
// No update support, just call the next filter in the chain.
return lzma_next_filter_update(
&coder->next, allocator, reversed_filters + 1);
@@ -219,59 +224,59 @@ simple_coder_update(lzma_coder *coder, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters,
size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
size_t (*filter)(void *simple, uint32_t now_pos,
bool is_encoder, uint8_t *buffer, size_t size),
size_t simple_size, size_t unfiltered_max,
uint32_t alignment, bool is_encoder)
{
// Allocate memory for the lzma_coder structure if needed.
if (next->coder == NULL) {
// Allocate memory for the lzma_simple_coder structure if needed.
lzma_simple_coder *coder = next->coder;
if (coder == NULL) {
// Here we allocate space also for the temporary buffer. We
// need twice the size of unfiltered_max, because then it
// is always possible to filter at least unfiltered_max bytes
// more data in coder->buffer[] if it can be filled completely.
next->coder = lzma_alloc(sizeof(lzma_coder)
coder = lzma_alloc(sizeof(lzma_simple_coder)
+ 2 * unfiltered_max, allocator);
if (next->coder == NULL)
if (coder == NULL)
return LZMA_MEM_ERROR;
next->coder = coder;
next->code = &simple_code;
next->end = &simple_coder_end;
next->update = &simple_coder_update;
next->coder->next = LZMA_NEXT_CODER_INIT;
next->coder->filter = filter;
next->coder->allocated = 2 * unfiltered_max;
coder->next = LZMA_NEXT_CODER_INIT;
coder->filter = filter;
coder->allocated = 2 * unfiltered_max;
// Allocate memory for filter-specific data structure.
if (simple_size > 0) {
next->coder->simple = lzma_alloc(
simple_size, allocator);
if (next->coder->simple == NULL)
coder->simple = lzma_alloc(simple_size, allocator);
if (coder->simple == NULL)
return LZMA_MEM_ERROR;
} else {
next->coder->simple = NULL;
coder->simple = NULL;
}
}
if (filters[0].options != NULL) {
const lzma_options_bcj *simple = filters[0].options;
next->coder->now_pos = simple->start_offset;
if (next->coder->now_pos & (alignment - 1))
coder->now_pos = simple->start_offset;
if (coder->now_pos & (alignment - 1))
return LZMA_OPTIONS_ERROR;
} else {
next->coder->now_pos = 0;
coder->now_pos = 0;
}
// Reset variables.
next->coder->is_encoder = is_encoder;
next->coder->end_was_reached = false;
next->coder->pos = 0;
next->coder->filtered = 0;
next->coder->size = 0;
coder->is_encoder = is_encoder;
coder->end_was_reached = false;
coder->pos = 0;
coder->filtered = 0;
coder->size = 0;
return lzma_next_filter_init(
&next->coder->next, allocator, filters + 1);
return lzma_next_filter_init(&coder->next, allocator, filters + 1);
}

View File

@@ -17,44 +17,56 @@
extern lzma_ret lzma_simple_x86_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_x86_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_arm_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters);
const lzma_allocator *allocator,
const lzma_filter_info *filters);
#endif

View File

@@ -14,7 +14,7 @@
extern lzma_ret
lzma_simple_props_decode(void **options, lzma_allocator *allocator,
lzma_simple_props_decode(void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size)
{
if (props_size == 0)

View File

@@ -16,7 +16,7 @@
#include "simple_coder.h"
extern lzma_ret lzma_simple_props_decode(
void **options, lzma_allocator *allocator,
void **options, const lzma_allocator *allocator,
const uint8_t *props, size_t props_size);
#endif

View File

@@ -16,9 +16,7 @@
#include "simple_coder.h"
typedef struct lzma_simple_s lzma_simple;
struct lzma_coder_s {
typedef struct {
/// Next filter in the chain
lzma_next_coder next;
@@ -33,12 +31,12 @@ struct lzma_coder_s {
/// Pointer to filter-specific function, which does
/// the actual filtering.
size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
size_t (*filter)(void *simple, uint32_t now_pos,
bool is_encoder, uint8_t *buffer, size_t size);
/// Pointer to filter-specific data, or NULL if filter doesn't need
/// any extra data.
lzma_simple *simple;
void *simple;
/// The lowest 32 bits of the current position in the data. Most
/// filters need this to do conversions between absolute and relative
@@ -62,12 +60,13 @@ struct lzma_coder_s {
/// Temporary buffer
uint8_t buffer[];
};
} lzma_simple_coder;
extern lzma_ret lzma_simple_coder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters,
size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
const lzma_allocator *allocator,
const lzma_filter_info *filters,
size_t (*filter)(void *simple, uint32_t now_pos,
bool is_encoder, uint8_t *buffer, size_t size),
size_t simple_size, size_t unfiltered_max,
uint32_t alignment, bool is_encoder);

View File

@@ -15,7 +15,7 @@
static size_t
sparc_code(lzma_simple *simple lzma_attribute((__unused__)),
sparc_code(void *simple lzma_attribute((__unused__)),
uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
@@ -57,7 +57,7 @@ sparc_code(lzma_simple *simple lzma_attribute((__unused__)),
static lzma_ret
sparc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
sparc_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
return lzma_simple_coder_init(next, allocator, filters,
@@ -67,7 +67,8 @@ sparc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_sparc_encoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return sparc_coder_init(next, allocator, filters, true);
}
@@ -75,7 +76,8 @@ lzma_simple_sparc_encoder_init(lzma_next_coder *next,
extern lzma_ret
lzma_simple_sparc_decoder_init(lzma_next_coder *next,
lzma_allocator *allocator, const lzma_filter_info *filters)
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return sparc_coder_init(next, allocator, filters, false);
}

View File

@@ -17,14 +17,14 @@
#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
struct lzma_simple_s {
typedef struct {
uint32_t prev_mask;
uint32_t prev_pos;
};
} lzma_simple_x86;
static size_t
x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder,
x86_code(void *simple_ptr, uint32_t now_pos, bool is_encoder,
uint8_t *buffer, size_t size)
{
static const bool MASK_TO_ALLOWED_STATUS[8]
@@ -33,6 +33,7 @@ x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder,
static const uint32_t MASK_TO_BIT_NUMBER[8]
= { 0, 1, 2, 2, 3, 3, 3, 3 };
lzma_simple_x86 *simple = simple_ptr;
uint32_t prev_mask = simple->prev_mask;
uint32_t prev_pos = simple->prev_pos;
@@ -123,15 +124,17 @@ x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder,
static lzma_ret
x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
x86_coder_init(lzma_next_coder *next, const lzma_allocator *allocator,
const lzma_filter_info *filters, bool is_encoder)
{
const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters,
&x86_code, sizeof(lzma_simple), 5, 1, is_encoder);
&x86_code, sizeof(lzma_simple_x86), 5, 1, is_encoder);
if (ret == LZMA_OK) {
next->coder->simple->prev_mask = 0;
next->coder->simple->prev_pos = (uint32_t)(-5);
lzma_simple_coder *coder = next->coder;
lzma_simple_x86 *simple = coder->simple;
simple->prev_mask = 0;
simple->prev_pos = (uint32_t)(-5);
}
return ret;
@@ -139,7 +142,8 @@ x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_simple_x86_encoder_init(lzma_next_coder *next,
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return x86_coder_init(next, allocator, filters, true);
@@ -147,7 +151,8 @@ lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
extern lzma_ret
lzma_simple_x86_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
lzma_simple_x86_decoder_init(lzma_next_coder *next,
const lzma_allocator *allocator,
const lzma_filter_info *filters)
{
return x86_coder_init(next, allocator, filters, false);