lz_encoder.c   lz_encoder.c 
skipping to change at line 23 skipping to change at line 23
#include "lz_encoder.h" #include "lz_encoder.h"
#include "lz_encoder_hash.h" #include "lz_encoder_hash.h"
// See lz_encoder_hash.h. This is a bit hackish but avoids making // See lz_encoder_hash.h. This is a bit hackish but avoids making
// endianness a conditional in makefiles. // endianness a conditional in makefiles.
#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL) #if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
# include "lz_encoder_hash_table.h" # include "lz_encoder_hash_table.h"
#endif #endif
#include "memcmplen.h"
struct lzma_coder_s { struct lzma_coder_s {
/// LZ-based encoder e.g. LZMA /// LZ-based encoder e.g. LZMA
lzma_lz_encoder lz; lzma_lz_encoder lz;
/// History buffer and match finder /// History buffer and match finder
lzma_mf mf; lzma_mf mf;
/// Next coder in the chain /// Next coder in the chain
lzma_next_coder next; lzma_next_coder next;
}; };
skipping to change at line 76 skipping to change at line 78
/// \brief Tries to fill the input window (mf->buffer) /// \brief Tries to fill the input window (mf->buffer)
/// ///
/// If we are the last encoder in the chain, our input data is in in[]. /// If we are the last encoder in the chain, our input data is in in[].
/// Otherwise we call the next filter in the chain to process in[] and /// Otherwise we call the next filter in the chain to process in[] and
/// write its output to mf->buffer. /// write its output to mf->buffer.
/// ///
/// This function must not be called once it has returned LZMA_STREAM_END. /// This function must not be called once it has returned LZMA_STREAM_END.
/// ///
static lzma_ret static lzma_ret
fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in fill_window(lzma_coder *coder, const lzma_allocator *allocator,
, const uint8_t *in, size_t *in_pos, size_t in_size,
size_t *in_pos, size_t in_size, lzma_action action) lzma_action action)
{ {
assert(coder->mf.read_pos <= coder->mf.write_pos); assert(coder->mf.read_pos <= coder->mf.write_pos);
// Move the sliding window if needed. // Move the sliding window if needed.
if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after ) if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after )
move_window(&coder->mf); move_window(&coder->mf);
// Maybe this is ugly, but lzma_mf uses uint32_t for most things // Maybe this is ugly, but lzma_mf uses uint32_t for most things
// (which I find cleanest), but we need size_t here when filling // (which I find cleanest), but we need size_t here when filling
// the history window. // the history window.
skipping to change at line 147 skipping to change at line 150
// Call the skip function directly instead of using // Call the skip function directly instead of using
// mf_skip(), since we don't want to touch mf->read_ahead. // mf_skip(), since we don't want to touch mf->read_ahead.
coder->mf.skip(&coder->mf, pending); coder->mf.skip(&coder->mf, pending);
} }
return ret; return ret;
} }
static lzma_ret static lzma_ret
lz_encode(lzma_coder *coder, lzma_allocator *allocator, lz_encode(lzma_coder *coder, const lzma_allocator *allocator,
const uint8_t *restrict in, size_t *restrict in_pos, const uint8_t *restrict in, size_t *restrict in_pos,
size_t in_size, size_t in_size,
uint8_t *restrict out, size_t *restrict out_pos, uint8_t *restrict out, size_t *restrict out_pos,
size_t out_size, lzma_action action) size_t out_size, lzma_action action)
{ {
while (*out_pos < out_size while (*out_pos < out_size
&& (*in_pos < in_size || action != LZMA_RUN)) { && (*in_pos < in_size || action != LZMA_RUN)) {
// Read more data to coder->mf.buffer if needed. // Read more data to coder->mf.buffer if needed.
if (coder->mf.action == LZMA_RUN && coder->mf.read_pos if (coder->mf.action == LZMA_RUN && coder->mf.read_pos
>= coder->mf.read_limit) >= coder->mf.read_limit)
skipping to change at line 177 skipping to change at line 180
// an error occurred. // an error occurred.
coder->mf.action = LZMA_RUN; coder->mf.action = LZMA_RUN;
return ret; return ret;
} }
} }
return LZMA_OK; return LZMA_OK;
} }
static bool 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) const lzma_lz_options *lz_options)
{ {
// For now, the dictionary size is limited to 1.5 GiB. This may grow // For now, the dictionary size is limited to 1.5 GiB. This may grow
// in the future if needed, but it needs a little more work than jus t // in the future if needed, but it needs a little more work than jus t
// changing this check. // changing this check.
if (lz_options->dict_size < LZMA_DICT_SIZE_MIN if (lz_options->dict_size < LZMA_DICT_SIZE_MIN
|| lz_options->dict_size || lz_options->dict_size
> (UINT32_C(1) << 30) + (UINT32_C(1) << 29) > (UINT32_C(1) << 30) + (UINT32_C(1) << 29)
|| lz_options->nice_len > lz_options->match_len_max) || lz_options->nice_len > lz_options->match_len_max)
return true; return true;
skipping to change at line 323 skipping to change at line 326
if (hash_bytes > 2) if (hash_bytes > 2)
hs += HASH_2_SIZE; hs += HASH_2_SIZE;
if (hash_bytes > 3) if (hash_bytes > 3)
hs += HASH_3_SIZE; hs += HASH_3_SIZE;
/* /*
No match finder uses this at the moment. No match finder uses this at the moment.
if (mf->hash_bytes > 4) if (mf->hash_bytes > 4)
hs += HASH_4_SIZE; hs += HASH_4_SIZE;
*/ */
// If the above code calculating hs is modified, make sure that const uint32_t old_hash_count = mf->hash_count;
// this assertion stays valid (UINT32_MAX / 5 is not strictly the const uint32_t old_sons_count = mf->sons_count;
// exact limit). If it doesn't, you need to calculate that mf->hash_count = hs;
// 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;
mf->sons_count = mf->cyclic_size; mf->sons_count = mf->cyclic_size;
if (is_bt) if (is_bt)
mf->sons_count *= 2; 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 // Deallocate the old hash array if it exists and has different size
// than what is needed now. // 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); lzma_free(mf->hash, allocator);
mf->hash = NULL; mf->hash = NULL;
lzma_free(mf->son, allocator);
mf->son = NULL;
} }
// Maximum number of match finder cycles // Maximum number of match finder cycles
mf->depth = lz_options->depth; mf->depth = lz_options->depth;
if (mf->depth == 0) { if (mf->depth == 0) {
if (is_bt) if (is_bt)
mf->depth = 16 + mf->nice_len / 2; mf->depth = 16 + mf->nice_len / 2;
else else
mf->depth = 4 + mf->nice_len / 4; mf->depth = 4 + mf->nice_len / 4;
} }
return false; return false;
} }
static bool 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) const lzma_lz_options *lz_options)
{ {
// Allocate the history buffer. // Allocate the history buffer.
if (mf->buffer == NULL) { 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) if (mf->buffer == NULL)
return true; 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 // Use cyclic_size as initial mf->offset. This allows
// avoiding a few branches in the match finders. The downside is // avoiding a few branches in the match finders. The downside is
// that match finder needs to be normalized more often, which may // that match finder needs to be normalized more often, which may
// hurt performance with huge dictionaries. // hurt performance with huge dictionaries.
mf->offset = mf->cyclic_size; mf->offset = mf->cyclic_size;
mf->read_pos = 0; mf->read_pos = 0;
mf->read_ahead = 0; mf->read_ahead = 0;
mf->read_limit = 0; mf->read_limit = 0;
mf->write_pos = 0; mf->write_pos = 0;
mf->pending = 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 #if UINT32_MAX >= SIZE_MAX / 4
// Check for integer overflow. (Huge dictionaries are not // Check for integer overflow. (Huge dictionaries are not
// possible on 32-bit CPU.) // 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; return true;
#endif #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) { 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);
mf->son = lzma_alloc(mf->sons_count * sizeof(uint32_t),
allocator); allocator);
if (mf->hash == NULL)
return true;
}
mf->son = mf->hash + mf->hash_size_sum; if (mf->hash == NULL || mf->son == NULL) {
mf->cyclic_pos = 0; lzma_free(mf->hash, allocator);
mf->hash = NULL;
lzma_free(mf->son, allocator);
mf->son = NULL;
// Initialize the hash table. Since EMPTY_HASH_VALUE is zero, we return true;
// can use memset(). }
} else {
/* /*
for (uint32_t i = 0; i < hash_size_sum; ++i) for (uint32_t i = 0; i < mf->hash_count; ++i)
mf->hash[i] = EMPTY_HASH_VALUE; mf->hash[i] = EMPTY_HASH_VALUE;
*/ */
memzero(mf->hash, (size_t)(mf->hash_size_sum) * sizeof(uint32_t)); memzero(mf->hash, mf->hash_count * sizeof(uint32_t));
}
// We don't need to initialize mf->son, but not doing that will mf->cyclic_pos = 0;
// make Valgrind complain in normalization (see normalize() in
// lz_encoder_mf.c).
//
// Skipping this initialization is *very* good when big dictionary i
s
// 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. // Handle preset dictionary.
if (lz_options->preset_dict != NULL if (lz_options->preset_dict != NULL
&& lz_options->preset_dict_size > 0) { && lz_options->preset_dict_size > 0) {
// If the preset dictionary is bigger than the actual // If the preset dictionary is bigger than the actual
// dictionary, use only the tail. // dictionary, use only the tail.
mf->write_pos = my_min(lz_options->preset_dict_size, mf->siz e); mf->write_pos = my_min(lz_options->preset_dict_size, mf->siz e);
memcpy(mf->buffer, lz_options->preset_dict memcpy(mf->buffer, lz_options->preset_dict
+ lz_options->preset_dict_size - mf->write_p os, + lz_options->preset_dict_size - mf->write_p os,
mf->write_pos); mf->write_pos);
skipping to change at line 441 skipping to change at line 455
return false; return false;
} }
extern uint64_t extern uint64_t
lzma_lz_encoder_memusage(const lzma_lz_options *lz_options) lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
{ {
// Old buffers must not exist when calling lz_encoder_prepare(). // Old buffers must not exist when calling lz_encoder_prepare().
lzma_mf mf = { lzma_mf mf = {
.buffer = NULL, .buffer = NULL,
.hash = NULL, .hash = NULL,
.hash_size_sum = 0, .son = NULL,
.hash_count = 0,
.sons_count = 0, .sons_count = 0,
}; };
// Setup the size information into mf. // Setup the size information into mf.
if (lz_encoder_prepare(&mf, NULL, lz_options)) if (lz_encoder_prepare(&mf, NULL, lz_options))
return UINT64_MAX; return UINT64_MAX;
// Calculate the memory usage. // Calculate the memory usage.
return (uint64_t)(mf.hash_size_sum + mf.sons_count) return ((uint64_t)(mf.hash_count) + mf.sons_count) * sizeof(uint32_t
* sizeof(uint32_t) )
+ (uint64_t)(mf.size) + sizeof(lzma_coder); + mf.size + sizeof(lzma_coder);
} }
static void static void
lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator) lz_encoder_end(lzma_coder *coder, const lzma_allocator *allocator)
{ {
lzma_next_end(&coder->next, allocator); lzma_next_end(&coder->next, allocator);
lzma_free(coder->mf.son, allocator);
lzma_free(coder->mf.hash, allocator); lzma_free(coder->mf.hash, allocator);
lzma_free(coder->mf.buffer, allocator); lzma_free(coder->mf.buffer, allocator);
if (coder->lz.end != NULL) if (coder->lz.end != NULL)
coder->lz.end(coder->lz.coder, allocator); coder->lz.end(coder->lz.coder, allocator);
else else
lzma_free(coder->lz.coder, allocator); lzma_free(coder->lz.coder, allocator);
lzma_free(coder, allocator); lzma_free(coder, allocator);
return; return;
} }
static lzma_ret static lzma_ret
lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator, lz_encoder_update(lzma_coder *coder, const lzma_allocator *allocator,
const lzma_filter *filters_null lzma_attribute((__unused__)) , const lzma_filter *filters_null lzma_attribute((__unused__)) ,
const lzma_filter *reversed_filters) const lzma_filter *reversed_filters)
{ {
if (coder->lz.options_update == NULL) if (coder->lz.options_update == NULL)
return LZMA_PROG_ERROR; return LZMA_PROG_ERROR;
return_if_error(coder->lz.options_update( return_if_error(coder->lz.options_update(
coder->lz.coder, reversed_filters)); coder->lz.coder, reversed_filters));
return lzma_next_filter_update( return lzma_next_filter_update(
&coder->next, allocator, reversed_filters + 1); &coder->next, allocator, reversed_filters + 1);
} }
extern lzma_ret 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, const lzma_filter_info *filters,
lzma_ret (*lz_init)(lzma_lz_encoder *lz, 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)) lzma_lz_options *lz_options))
{ {
#ifdef HAVE_SMALL #ifdef HAVE_SMALL
// We need that the CRC32 table has been initialized. // We need that the CRC32 table has been initialized.
lzma_crc32_init(); lzma_crc32_init();
#endif #endif
// Allocate and initialize the base data structure. // Allocate and initialize the base data structure.
if (next->coder == NULL) { if (next->coder == NULL) {
next->coder = lzma_alloc(sizeof(lzma_coder), allocator); next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
skipping to change at line 515 skipping to change at line 530
next->code = &lz_encode; next->code = &lz_encode;
next->end = &lz_encoder_end; next->end = &lz_encoder_end;
next->update = &lz_encoder_update; next->update = &lz_encoder_update;
next->coder->lz.coder = NULL; next->coder->lz.coder = NULL;
next->coder->lz.code = NULL; next->coder->lz.code = NULL;
next->coder->lz.end = NULL; next->coder->lz.end = NULL;
next->coder->mf.buffer = NULL; next->coder->mf.buffer = NULL;
next->coder->mf.hash = NULL; next->coder->mf.hash = NULL;
next->coder->mf.hash_size_sum = 0; next->coder->mf.son = NULL;
next->coder->mf.hash_count = 0;
next->coder->mf.sons_count = 0; next->coder->mf.sons_count = 0;
next->coder->next = LZMA_NEXT_CODER_INIT; next->coder->next = LZMA_NEXT_CODER_INIT;
} }
// Initialize the LZ-based encoder. // Initialize the LZ-based encoder.
lzma_lz_options lz_options; lzma_lz_options lz_options;
return_if_error(lz_init(&next->coder->lz, allocator, return_if_error(lz_init(&next->coder->lz, allocator,
filters[0].options, &lz_options)); filters[0].options, &lz_options));
 End of changes. 29 change blocks. 
52 lines changed or deleted 68 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/