| Index: xz/src/liblzma/lz/lz_encoder_mf.c
|
| ===================================================================
|
| --- xz/src/liblzma/lz/lz_encoder_mf.c (revision 0)
|
| +++ xz/src/liblzma/lz/lz_encoder_mf.c (revision 0)
|
| @@ -0,0 +1,753 @@
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +//
|
| +/// \file lz_encoder_mf.c
|
| +/// \brief Match finders
|
| +///
|
| +// Authors: Igor Pavlov
|
| +// Lasse Collin
|
| +//
|
| +// This file has been put into the public domain.
|
| +// You can do whatever you want with this file.
|
| +//
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +#include "lz_encoder.h"
|
| +#include "lz_encoder_hash.h"
|
| +
|
| +
|
| +/// \brief Find matches starting from the current byte
|
| +///
|
| +/// \return The length of the longest match found
|
| +extern uint32_t
|
| +lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
|
| +{
|
| + // Call the match finder. It returns the number of length-distance
|
| + // pairs found.
|
| + // FIXME: Minimum count is zero, what _exactly_ is the maximum?
|
| + const uint32_t count = mf->find(mf, matches);
|
| +
|
| + // Length of the longest match; assume that no matches were found
|
| + // and thus the maximum length is zero.
|
| + uint32_t len_best = 0;
|
| +
|
| + if (count > 0) {
|
| +#ifndef NDEBUG
|
| + // Validate the matches.
|
| + for (uint32_t i = 0; i < count; ++i) {
|
| + assert(matches[i].len <= mf->nice_len);
|
| + assert(matches[i].dist < mf->read_pos);
|
| + assert(memcmp(mf_ptr(mf) - 1,
|
| + mf_ptr(mf) - matches[i].dist - 2,
|
| + matches[i].len) == 0);
|
| + }
|
| +#endif
|
| +
|
| + // The last used element in the array contains
|
| + // the longest match.
|
| + len_best = matches[count - 1].len;
|
| +
|
| + // If a match of maximum search length was found, try to
|
| + // extend the match to maximum possible length.
|
| + if (len_best == mf->nice_len) {
|
| + // The limit for the match length is either the
|
| + // maximum match length supported by the LZ-based
|
| + // encoder or the number of bytes left in the
|
| + // dictionary, whichever is smaller.
|
| + uint32_t limit = mf_avail(mf) + 1;
|
| + if (limit > mf->match_len_max)
|
| + limit = mf->match_len_max;
|
| +
|
| + // Pointer to the byte we just ran through
|
| + // the match finder.
|
| + const uint8_t *p1 = mf_ptr(mf) - 1;
|
| +
|
| + // Pointer to the beginning of the match. We need -1
|
| + // 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;
|
| + }
|
| + }
|
| +
|
| + *count_ptr = count;
|
| +
|
| + // Finally update the read position to indicate that match finder was
|
| + // run for this dictionary offset.
|
| + ++mf->read_ahead;
|
| +
|
| + return len_best;
|
| +}
|
| +
|
| +
|
| +/// Hash value to indicate unused element in the hash. Since we start the
|
| +/// positions from dict_size + 1, zero is always too far to qualify
|
| +/// as usable match position.
|
| +#define EMPTY_HASH_VALUE 0
|
| +
|
| +
|
| +/// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
|
| +/// reaches MUST_NORMALIZE_POS.
|
| +#define MUST_NORMALIZE_POS UINT32_MAX
|
| +
|
| +
|
| +/// \brief Normalizes hash values
|
| +///
|
| +/// The hash arrays store positions of match candidates. The positions are
|
| +/// relative to an arbitrary offset that is not the same as the absolute
|
| +/// offset in the input stream. The relative position of the current byte
|
| +/// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
|
| +/// the differences of the current read position and the position found from
|
| +/// the hash.
|
| +///
|
| +/// To prevent integer overflows of the offsets stored in the hash arrays,
|
| +/// we need to "normalize" the stored values now and then. During the
|
| +/// normalization, we drop values that indicate distance greater than the
|
| +/// dictionary size, thus making space for new values.
|
| +static void
|
| +normalize(lzma_mf *mf)
|
| +{
|
| + assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
|
| +
|
| + // In future we may not want to touch the lowest bits, because there
|
| + // may be match finders that use larger resolution than one byte.
|
| + const uint32_t subvalue
|
| + = (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) {
|
| + // 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;
|
| + else
|
| + hash[i] -= subvalue;
|
| + }
|
| +
|
| + // Update offset to match the new locations.
|
| + mf->offset -= subvalue;
|
| +
|
| + return;
|
| +}
|
| +
|
| +
|
| +/// Mark the current byte as processed from point of view of the match finder.
|
| +static void
|
| +move_pos(lzma_mf *mf)
|
| +{
|
| + if (++mf->cyclic_pos == mf->cyclic_size)
|
| + mf->cyclic_pos = 0;
|
| +
|
| + ++mf->read_pos;
|
| + assert(mf->read_pos <= mf->write_pos);
|
| +
|
| + if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
|
| + normalize(mf);
|
| +}
|
| +
|
| +
|
| +/// When flushing, we cannot run the match finder unless there is nice_len
|
| +/// bytes available in the dictionary. Instead, we skip running the match
|
| +/// finder (indicating that no match was found), and count how many bytes we
|
| +/// have ignored this way.
|
| +///
|
| +/// When new data is given after the flushing was completed, the match finder
|
| +/// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
|
| +/// the missed bytes are added to the hash using the match finder's skip
|
| +/// function (with small amount of input, it may start using mf->pending
|
| +/// again if flushing).
|
| +///
|
| +/// Due to this rewinding, we don't touch cyclic_pos or test for
|
| +/// normalization. It will be done when the match finder's skip function
|
| +/// catches up after a flush.
|
| +static void
|
| +move_pending(lzma_mf *mf)
|
| +{
|
| + ++mf->read_pos;
|
| + assert(mf->read_pos <= mf->write_pos);
|
| + ++mf->pending;
|
| +}
|
| +
|
| +
|
| +/// Calculate len_limit and determine if there is enough input to run
|
| +/// the actual match finder code. Sets up "cur" and "pos". This macro
|
| +/// is used by all find functions and binary tree skip functions. Hash
|
| +/// chain skip function doesn't need len_limit so a simpler code is used
|
| +/// in them.
|
| +#define header(is_bt, len_min, ret_op) \
|
| + uint32_t len_limit = mf_avail(mf); \
|
| + if (mf->nice_len <= len_limit) { \
|
| + len_limit = mf->nice_len; \
|
| + } else if (len_limit < (len_min) \
|
| + || (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
|
| + assert(mf->action != LZMA_RUN); \
|
| + move_pending(mf); \
|
| + ret_op; \
|
| + } \
|
| + const uint8_t *cur = mf_ptr(mf); \
|
| + const uint32_t pos = mf->read_pos + mf->offset
|
| +
|
| +
|
| +/// Header for find functions. "return 0" indicates that zero matches
|
| +/// were found.
|
| +#define header_find(is_bt, len_min) \
|
| + header(is_bt, len_min, return 0); \
|
| + uint32_t matches_count = 0
|
| +
|
| +
|
| +/// Header for a loop in a skip function. "continue" tells to skip the rest
|
| +/// of the code in the loop.
|
| +#define header_skip(is_bt, len_min) \
|
| + header(is_bt, len_min, continue)
|
| +
|
| +
|
| +/// Calls hc_find_func() or bt_find_func() and calculates the total number
|
| +/// of matches found. Updates the dictionary position and returns the number
|
| +/// of matches found.
|
| +#define call_find(func, len_best) \
|
| +do { \
|
| + matches_count = func(len_limit, pos, cur, cur_match, mf->depth, \
|
| + mf->son, mf->cyclic_pos, mf->cyclic_size, \
|
| + matches + matches_count, len_best) \
|
| + - matches; \
|
| + move_pos(mf); \
|
| + return matches_count; \
|
| +} while (0)
|
| +
|
| +
|
| +////////////////
|
| +// Hash Chain //
|
| +////////////////
|
| +
|
| +#if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
|
| +///
|
| +///
|
| +/// \param len_limit Don't look for matches longer than len_limit.
|
| +/// \param pos lzma_mf.read_pos + lzma_mf.offset
|
| +/// \param cur Pointer to current byte (mf_ptr(mf))
|
| +/// \param cur_match Start position of the current match candidate
|
| +/// \param depth Maximum length of the hash chain
|
| +/// \param son lzma_mf.son (contains the hash chain)
|
| +/// \param cyclic_pos
|
| +/// \param cyclic_size
|
| +/// \param matches Array to hold the matches.
|
| +/// \param len_best The length of the longest match found so far.
|
| +static lzma_match *
|
| +hc_find_func(
|
| + const uint32_t len_limit,
|
| + const uint32_t pos,
|
| + const uint8_t *const cur,
|
| + uint32_t cur_match,
|
| + uint32_t depth,
|
| + uint32_t *const son,
|
| + const uint32_t cyclic_pos,
|
| + const uint32_t cyclic_size,
|
| + lzma_match *matches,
|
| + uint32_t len_best)
|
| +{
|
| + son[cyclic_pos] = cur_match;
|
| +
|
| + while (true) {
|
| + const uint32_t delta = pos - cur_match;
|
| + if (depth-- == 0 || delta >= cyclic_size)
|
| + return matches;
|
| +
|
| + const uint8_t *const pb = cur - delta;
|
| + cur_match = son[cyclic_pos - delta
|
| + + (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;
|
| +
|
| + if (len_best < len) {
|
| + len_best = len;
|
| + matches->len = len;
|
| + matches->dist = delta - 1;
|
| + ++matches;
|
| +
|
| + if (len == len_limit)
|
| + return matches;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +#define hc_find(len_best) \
|
| + call_find(hc_find_func, len_best)
|
| +
|
| +
|
| +#define hc_skip() \
|
| +do { \
|
| + mf->son[mf->cyclic_pos] = cur_match; \
|
| + move_pos(mf); \
|
| +} while (0)
|
| +
|
| +#endif
|
| +
|
| +
|
| +#ifdef HAVE_MF_HC3
|
| +extern uint32_t
|
| +lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
|
| +{
|
| + header_find(false, 3);
|
| +
|
| + hash_3_calc();
|
| +
|
| + const uint32_t delta2 = pos - mf->hash[hash_2_value];
|
| + const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
|
| +
|
| + 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;
|
| +
|
| + matches[0].len = len_best;
|
| + matches[0].dist = delta2 - 1;
|
| + matches_count = 1;
|
| +
|
| + if (len_best == len_limit) {
|
| + hc_skip();
|
| + return 1; // matches_count
|
| + }
|
| + }
|
| +
|
| + hc_find(len_best);
|
| +}
|
| +
|
| +
|
| +extern void
|
| +lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
|
| +{
|
| + do {
|
| + if (mf_avail(mf) < 3) {
|
| + move_pending(mf);
|
| + continue;
|
| + }
|
| +
|
| + const uint8_t *cur = mf_ptr(mf);
|
| + const uint32_t pos = mf->read_pos + mf->offset;
|
| +
|
| + hash_3_calc();
|
| +
|
| + const uint32_t cur_match
|
| + = mf->hash[FIX_3_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
|
| +
|
| + hc_skip();
|
| +
|
| + } while (--amount != 0);
|
| +}
|
| +#endif
|
| +
|
| +
|
| +#ifdef HAVE_MF_HC4
|
| +extern uint32_t
|
| +lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
|
| +{
|
| + header_find(false, 4);
|
| +
|
| + hash_4_calc();
|
| +
|
| + uint32_t delta2 = pos - mf->hash[hash_2_value];
|
| + const uint32_t delta3
|
| + = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
|
| + const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value ] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
|
| + mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
|
| +
|
| + uint32_t len_best = 1;
|
| +
|
| + if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
|
| + len_best = 2;
|
| + matches[0].len = 2;
|
| + matches[0].dist = delta2 - 1;
|
| + matches_count = 1;
|
| + }
|
| +
|
| + if (delta2 != delta3 && delta3 < mf->cyclic_size
|
| + && *(cur - delta3) == *cur) {
|
| + len_best = 3;
|
| + matches[matches_count++].dist = delta3 - 1;
|
| + delta2 = delta3;
|
| + }
|
| +
|
| + if (matches_count != 0) {
|
| + for ( ; len_best != len_limit; ++len_best)
|
| + if (*(cur + len_best - delta2) != cur[len_best])
|
| + break;
|
| +
|
| + matches[matches_count - 1].len = len_best;
|
| +
|
| + if (len_best == len_limit) {
|
| + hc_skip();
|
| + return matches_count;
|
| + }
|
| + }
|
| +
|
| + if (len_best < 3)
|
| + len_best = 3;
|
| +
|
| + hc_find(len_best);
|
| +}
|
| +
|
| +
|
| +extern void
|
| +lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
|
| +{
|
| + do {
|
| + if (mf_avail(mf) < 4) {
|
| + move_pending(mf);
|
| + continue;
|
| + }
|
| +
|
| + const uint8_t *cur = mf_ptr(mf);
|
| + const uint32_t pos = mf->read_pos + mf->offset;
|
| +
|
| + hash_4_calc();
|
| +
|
| + const uint32_t cur_match
|
| + = mf->hash[FIX_4_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
|
| + mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
|
| +
|
| + hc_skip();
|
| +
|
| + } while (--amount != 0);
|
| +}
|
| +#endif
|
| +
|
| +
|
| +/////////////////
|
| +// Binary Tree //
|
| +/////////////////
|
| +
|
| +#if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
|
| +static lzma_match *
|
| +bt_find_func(
|
| + const uint32_t len_limit,
|
| + const uint32_t pos,
|
| + const uint8_t *const cur,
|
| + uint32_t cur_match,
|
| + uint32_t depth,
|
| + uint32_t *const son,
|
| + const uint32_t cyclic_pos,
|
| + const uint32_t cyclic_size,
|
| + lzma_match *matches,
|
| + uint32_t len_best)
|
| +{
|
| + uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
|
| + uint32_t *ptr1 = son + (cyclic_pos << 1);
|
| +
|
| + uint32_t len0 = 0;
|
| + uint32_t len1 = 0;
|
| +
|
| + while (true) {
|
| + const uint32_t delta = pos - cur_match;
|
| + if (depth-- == 0 || delta >= cyclic_size) {
|
| + *ptr0 = EMPTY_HASH_VALUE;
|
| + *ptr1 = EMPTY_HASH_VALUE;
|
| + return matches;
|
| + }
|
| +
|
| + uint32_t *const pair = son + ((cyclic_pos - delta
|
| + + (delta > cyclic_pos ? cyclic_size : 0))
|
| + << 1);
|
| +
|
| + const uint8_t *const pb = cur - delta;
|
| + uint32_t len = my_min(len0, len1);
|
| +
|
| + if (pb[len] == cur[len]) {
|
| + while (++len != len_limit)
|
| + if (pb[len] != cur[len])
|
| + break;
|
| +
|
| + if (len_best < len) {
|
| + len_best = len;
|
| + matches->len = len;
|
| + matches->dist = delta - 1;
|
| + ++matches;
|
| +
|
| + if (len == len_limit) {
|
| + *ptr1 = pair[0];
|
| + *ptr0 = pair[1];
|
| + return matches;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (pb[len] < cur[len]) {
|
| + *ptr1 = cur_match;
|
| + ptr1 = pair + 1;
|
| + cur_match = *ptr1;
|
| + len1 = len;
|
| + } else {
|
| + *ptr0 = cur_match;
|
| + ptr0 = pair;
|
| + cur_match = *ptr0;
|
| + len0 = len;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +static void
|
| +bt_skip_func(
|
| + const uint32_t len_limit,
|
| + const uint32_t pos,
|
| + const uint8_t *const cur,
|
| + uint32_t cur_match,
|
| + uint32_t depth,
|
| + uint32_t *const son,
|
| + const uint32_t cyclic_pos,
|
| + const uint32_t cyclic_size)
|
| +{
|
| + uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
|
| + uint32_t *ptr1 = son + (cyclic_pos << 1);
|
| +
|
| + uint32_t len0 = 0;
|
| + uint32_t len1 = 0;
|
| +
|
| + while (true) {
|
| + const uint32_t delta = pos - cur_match;
|
| + if (depth-- == 0 || delta >= cyclic_size) {
|
| + *ptr0 = EMPTY_HASH_VALUE;
|
| + *ptr1 = EMPTY_HASH_VALUE;
|
| + return;
|
| + }
|
| +
|
| + uint32_t *pair = son + ((cyclic_pos - delta
|
| + + (delta > cyclic_pos ? cyclic_size : 0))
|
| + << 1);
|
| + const uint8_t *pb = cur - delta;
|
| + uint32_t len = my_min(len0, len1);
|
| +
|
| + if (pb[len] == cur[len]) {
|
| + while (++len != len_limit)
|
| + if (pb[len] != cur[len])
|
| + break;
|
| +
|
| + if (len == len_limit) {
|
| + *ptr1 = pair[0];
|
| + *ptr0 = pair[1];
|
| + return;
|
| + }
|
| + }
|
| +
|
| + if (pb[len] < cur[len]) {
|
| + *ptr1 = cur_match;
|
| + ptr1 = pair + 1;
|
| + cur_match = *ptr1;
|
| + len1 = len;
|
| + } else {
|
| + *ptr0 = cur_match;
|
| + ptr0 = pair;
|
| + cur_match = *ptr0;
|
| + len0 = len;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +#define bt_find(len_best) \
|
| + call_find(bt_find_func, len_best)
|
| +
|
| +#define bt_skip() \
|
| +do { \
|
| + bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
|
| + mf->son, mf->cyclic_pos, \
|
| + mf->cyclic_size); \
|
| + move_pos(mf); \
|
| +} while (0)
|
| +
|
| +#endif
|
| +
|
| +
|
| +#ifdef HAVE_MF_BT2
|
| +extern uint32_t
|
| +lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
|
| +{
|
| + header_find(true, 2);
|
| +
|
| + hash_2_calc();
|
| +
|
| + const uint32_t cur_match = mf->hash[hash_value];
|
| + mf->hash[hash_value] = pos;
|
| +
|
| + bt_find(1);
|
| +}
|
| +
|
| +
|
| +extern void
|
| +lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
|
| +{
|
| + do {
|
| + header_skip(true, 2);
|
| +
|
| + hash_2_calc();
|
| +
|
| + const uint32_t cur_match = mf->hash[hash_value];
|
| + mf->hash[hash_value] = pos;
|
| +
|
| + bt_skip();
|
| +
|
| + } while (--amount != 0);
|
| +}
|
| +#endif
|
| +
|
| +
|
| +#ifdef HAVE_MF_BT3
|
| +extern uint32_t
|
| +lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
|
| +{
|
| + header_find(true, 3);
|
| +
|
| + hash_3_calc();
|
| +
|
| + const uint32_t delta2 = pos - mf->hash[hash_2_value];
|
| + const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
|
| +
|
| + 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;
|
| +
|
| + matches[0].len = len_best;
|
| + matches[0].dist = delta2 - 1;
|
| + matches_count = 1;
|
| +
|
| + if (len_best == len_limit) {
|
| + bt_skip();
|
| + return 1; // matches_count
|
| + }
|
| + }
|
| +
|
| + bt_find(len_best);
|
| +}
|
| +
|
| +
|
| +extern void
|
| +lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
|
| +{
|
| + do {
|
| + header_skip(true, 3);
|
| +
|
| + hash_3_calc();
|
| +
|
| + const uint32_t cur_match
|
| + = mf->hash[FIX_3_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
|
| +
|
| + bt_skip();
|
| +
|
| + } while (--amount != 0);
|
| +}
|
| +#endif
|
| +
|
| +
|
| +#ifdef HAVE_MF_BT4
|
| +extern uint32_t
|
| +lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
|
| +{
|
| + header_find(true, 4);
|
| +
|
| + hash_4_calc();
|
| +
|
| + uint32_t delta2 = pos - mf->hash[hash_2_value];
|
| + const uint32_t delta3
|
| + = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
|
| + const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
|
| + mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
|
| +
|
| + uint32_t len_best = 1;
|
| +
|
| + if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
|
| + len_best = 2;
|
| + matches[0].len = 2;
|
| + matches[0].dist = delta2 - 1;
|
| + matches_count = 1;
|
| + }
|
| +
|
| + if (delta2 != delta3 && delta3 < mf->cyclic_size
|
| + && *(cur - delta3) == *cur) {
|
| + len_best = 3;
|
| + matches[matches_count++].dist = delta3 - 1;
|
| + delta2 = delta3;
|
| + }
|
| +
|
| + if (matches_count != 0) {
|
| + for ( ; len_best != len_limit; ++len_best)
|
| + if (*(cur + len_best - delta2) != cur[len_best])
|
| + break;
|
| +
|
| + matches[matches_count - 1].len = len_best;
|
| +
|
| + if (len_best == len_limit) {
|
| + bt_skip();
|
| + return matches_count;
|
| + }
|
| + }
|
| +
|
| + if (len_best < 3)
|
| + len_best = 3;
|
| +
|
| + bt_find(len_best);
|
| +}
|
| +
|
| +
|
| +extern void
|
| +lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
|
| +{
|
| + do {
|
| + header_skip(true, 4);
|
| +
|
| + hash_4_calc();
|
| +
|
| + const uint32_t cur_match
|
| + = mf->hash[FIX_4_HASH_SIZE + hash_value];
|
| +
|
| + mf->hash[hash_2_value] = pos;
|
| + mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
|
| + mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
|
| +
|
| + bt_skip();
|
| +
|
| + } while (--amount != 0);
|
| +}
|
| +#endif
|
|
|
| Property changes on: xz/src/liblzma/lz/lz_encoder_mf.c
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|