| 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/ | ||||