15a645f22SBen Gras ///////////////////////////////////////////////////////////////////////////////
25a645f22SBen Gras //
35a645f22SBen Gras /// \file lz_encoder_mf.c
45a645f22SBen Gras /// \brief Match finders
55a645f22SBen Gras ///
65a645f22SBen Gras // Authors: Igor Pavlov
75a645f22SBen Gras // Lasse Collin
85a645f22SBen Gras //
95a645f22SBen Gras // This file has been put into the public domain.
105a645f22SBen Gras // You can do whatever you want with this file.
115a645f22SBen Gras //
125a645f22SBen Gras ///////////////////////////////////////////////////////////////////////////////
135a645f22SBen Gras
145a645f22SBen Gras #include "lz_encoder.h"
155a645f22SBen Gras #include "lz_encoder_hash.h"
16*0a6a1f1dSLionel Sambuc #include "memcmplen.h"
175a645f22SBen Gras
185a645f22SBen Gras
195a645f22SBen Gras /// \brief Find matches starting from the current byte
205a645f22SBen Gras ///
215a645f22SBen Gras /// \return The length of the longest match found
225a645f22SBen Gras extern uint32_t
lzma_mf_find(lzma_mf * mf,uint32_t * count_ptr,lzma_match * matches)235a645f22SBen Gras lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
245a645f22SBen Gras {
255a645f22SBen Gras // Call the match finder. It returns the number of length-distance
265a645f22SBen Gras // pairs found.
275a645f22SBen Gras // FIXME: Minimum count is zero, what _exactly_ is the maximum?
285a645f22SBen Gras const uint32_t count = mf->find(mf, matches);
295a645f22SBen Gras
305a645f22SBen Gras // Length of the longest match; assume that no matches were found
315a645f22SBen Gras // and thus the maximum length is zero.
325a645f22SBen Gras uint32_t len_best = 0;
335a645f22SBen Gras
345a645f22SBen Gras if (count > 0) {
355a645f22SBen Gras #ifndef NDEBUG
365a645f22SBen Gras // Validate the matches.
375a645f22SBen Gras for (uint32_t i = 0; i < count; ++i) {
385a645f22SBen Gras assert(matches[i].len <= mf->nice_len);
395a645f22SBen Gras assert(matches[i].dist < mf->read_pos);
405a645f22SBen Gras assert(memcmp(mf_ptr(mf) - 1,
415a645f22SBen Gras mf_ptr(mf) - matches[i].dist - 2,
425a645f22SBen Gras matches[i].len) == 0);
435a645f22SBen Gras }
445a645f22SBen Gras #endif
455a645f22SBen Gras
465a645f22SBen Gras // The last used element in the array contains
475a645f22SBen Gras // the longest match.
485a645f22SBen Gras len_best = matches[count - 1].len;
495a645f22SBen Gras
505a645f22SBen Gras // If a match of maximum search length was found, try to
515a645f22SBen Gras // extend the match to maximum possible length.
525a645f22SBen Gras if (len_best == mf->nice_len) {
535a645f22SBen Gras // The limit for the match length is either the
545a645f22SBen Gras // maximum match length supported by the LZ-based
555a645f22SBen Gras // encoder or the number of bytes left in the
565a645f22SBen Gras // dictionary, whichever is smaller.
575a645f22SBen Gras uint32_t limit = mf_avail(mf) + 1;
585a645f22SBen Gras if (limit > mf->match_len_max)
595a645f22SBen Gras limit = mf->match_len_max;
605a645f22SBen Gras
615a645f22SBen Gras // Pointer to the byte we just ran through
625a645f22SBen Gras // the match finder.
635a645f22SBen Gras const uint8_t *p1 = mf_ptr(mf) - 1;
645a645f22SBen Gras
655a645f22SBen Gras // Pointer to the beginning of the match. We need -1
665a645f22SBen Gras // here because the match distances are zero based.
675a645f22SBen Gras const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
685a645f22SBen Gras
69*0a6a1f1dSLionel Sambuc len_best = lzma_memcmplen(p1, p2, len_best, limit);
705a645f22SBen Gras }
715a645f22SBen Gras }
725a645f22SBen Gras
735a645f22SBen Gras *count_ptr = count;
745a645f22SBen Gras
755a645f22SBen Gras // Finally update the read position to indicate that match finder was
765a645f22SBen Gras // run for this dictionary offset.
775a645f22SBen Gras ++mf->read_ahead;
785a645f22SBen Gras
795a645f22SBen Gras return len_best;
805a645f22SBen Gras }
815a645f22SBen Gras
825a645f22SBen Gras
835a645f22SBen Gras /// Hash value to indicate unused element in the hash. Since we start the
845a645f22SBen Gras /// positions from dict_size + 1, zero is always too far to qualify
855a645f22SBen Gras /// as usable match position.
865a645f22SBen Gras #define EMPTY_HASH_VALUE 0
875a645f22SBen Gras
885a645f22SBen Gras
895a645f22SBen Gras /// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
905a645f22SBen Gras /// reaches MUST_NORMALIZE_POS.
915a645f22SBen Gras #define MUST_NORMALIZE_POS UINT32_MAX
925a645f22SBen Gras
935a645f22SBen Gras
945a645f22SBen Gras /// \brief Normalizes hash values
955a645f22SBen Gras ///
965a645f22SBen Gras /// The hash arrays store positions of match candidates. The positions are
975a645f22SBen Gras /// relative to an arbitrary offset that is not the same as the absolute
985a645f22SBen Gras /// offset in the input stream. The relative position of the current byte
995a645f22SBen Gras /// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
1005a645f22SBen Gras /// the differences of the current read position and the position found from
1015a645f22SBen Gras /// the hash.
1025a645f22SBen Gras ///
1035a645f22SBen Gras /// To prevent integer overflows of the offsets stored in the hash arrays,
1045a645f22SBen Gras /// we need to "normalize" the stored values now and then. During the
1055a645f22SBen Gras /// normalization, we drop values that indicate distance greater than the
1065a645f22SBen Gras /// dictionary size, thus making space for new values.
1075a645f22SBen Gras static void
normalize(lzma_mf * mf)1085a645f22SBen Gras normalize(lzma_mf *mf)
1095a645f22SBen Gras {
1105a645f22SBen Gras assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
1115a645f22SBen Gras
1125a645f22SBen Gras // In future we may not want to touch the lowest bits, because there
1135a645f22SBen Gras // may be match finders that use larger resolution than one byte.
1145a645f22SBen Gras const uint32_t subvalue
1155a645f22SBen Gras = (MUST_NORMALIZE_POS - mf->cyclic_size);
1165a645f22SBen Gras // & (~(UINT32_C(1) << 10) - 1);
1175a645f22SBen Gras
118*0a6a1f1dSLionel Sambuc for (uint32_t i = 0; i < mf->hash_count; ++i) {
1195a645f22SBen Gras // If the distance is greater than the dictionary size,
1205a645f22SBen Gras // we can simply mark the hash element as empty.
121*0a6a1f1dSLionel Sambuc if (mf->hash[i] <= subvalue)
122*0a6a1f1dSLionel Sambuc mf->hash[i] = EMPTY_HASH_VALUE;
1235a645f22SBen Gras else
124*0a6a1f1dSLionel Sambuc mf->hash[i] -= subvalue;
125*0a6a1f1dSLionel Sambuc }
126*0a6a1f1dSLionel Sambuc
127*0a6a1f1dSLionel Sambuc for (uint32_t i = 0; i < mf->sons_count; ++i) {
128*0a6a1f1dSLionel Sambuc // Do the same for mf->son.
129*0a6a1f1dSLionel Sambuc //
130*0a6a1f1dSLionel Sambuc // NOTE: There may be uninitialized elements in mf->son.
131*0a6a1f1dSLionel Sambuc // Valgrind may complain that the "if" below depends on
132*0a6a1f1dSLionel Sambuc // an uninitialized value. In this case it is safe to ignore
133*0a6a1f1dSLionel Sambuc // the warning. See also the comments in lz_encoder_init()
134*0a6a1f1dSLionel Sambuc // in lz_encoder.c.
135*0a6a1f1dSLionel Sambuc if (mf->son[i] <= subvalue)
136*0a6a1f1dSLionel Sambuc mf->son[i] = EMPTY_HASH_VALUE;
137*0a6a1f1dSLionel Sambuc else
138*0a6a1f1dSLionel Sambuc mf->son[i] -= subvalue;
1395a645f22SBen Gras }
1405a645f22SBen Gras
1415a645f22SBen Gras // Update offset to match the new locations.
1425a645f22SBen Gras mf->offset -= subvalue;
1435a645f22SBen Gras
1445a645f22SBen Gras return;
1455a645f22SBen Gras }
1465a645f22SBen Gras
1475a645f22SBen Gras
1485a645f22SBen Gras /// Mark the current byte as processed from point of view of the match finder.
1495a645f22SBen Gras static void
move_pos(lzma_mf * mf)1505a645f22SBen Gras move_pos(lzma_mf *mf)
1515a645f22SBen Gras {
1525a645f22SBen Gras if (++mf->cyclic_pos == mf->cyclic_size)
1535a645f22SBen Gras mf->cyclic_pos = 0;
1545a645f22SBen Gras
1555a645f22SBen Gras ++mf->read_pos;
1565a645f22SBen Gras assert(mf->read_pos <= mf->write_pos);
1575a645f22SBen Gras
1585a645f22SBen Gras if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
1595a645f22SBen Gras normalize(mf);
1605a645f22SBen Gras }
1615a645f22SBen Gras
1625a645f22SBen Gras
1635a645f22SBen Gras /// When flushing, we cannot run the match finder unless there is nice_len
1645a645f22SBen Gras /// bytes available in the dictionary. Instead, we skip running the match
1655a645f22SBen Gras /// finder (indicating that no match was found), and count how many bytes we
1665a645f22SBen Gras /// have ignored this way.
1675a645f22SBen Gras ///
1685a645f22SBen Gras /// When new data is given after the flushing was completed, the match finder
1695a645f22SBen Gras /// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
1705a645f22SBen Gras /// the missed bytes are added to the hash using the match finder's skip
1715a645f22SBen Gras /// function (with small amount of input, it may start using mf->pending
1725a645f22SBen Gras /// again if flushing).
1735a645f22SBen Gras ///
1745a645f22SBen Gras /// Due to this rewinding, we don't touch cyclic_pos or test for
1755a645f22SBen Gras /// normalization. It will be done when the match finder's skip function
1765a645f22SBen Gras /// catches up after a flush.
1775a645f22SBen Gras static void
move_pending(lzma_mf * mf)1785a645f22SBen Gras move_pending(lzma_mf *mf)
1795a645f22SBen Gras {
1805a645f22SBen Gras ++mf->read_pos;
1815a645f22SBen Gras assert(mf->read_pos <= mf->write_pos);
1825a645f22SBen Gras ++mf->pending;
1835a645f22SBen Gras }
1845a645f22SBen Gras
1855a645f22SBen Gras
1865a645f22SBen Gras /// Calculate len_limit and determine if there is enough input to run
1875a645f22SBen Gras /// the actual match finder code. Sets up "cur" and "pos". This macro
1885a645f22SBen Gras /// is used by all find functions and binary tree skip functions. Hash
1895a645f22SBen Gras /// chain skip function doesn't need len_limit so a simpler code is used
1905a645f22SBen Gras /// in them.
1915a645f22SBen Gras #define header(is_bt, len_min, ret_op) \
1925a645f22SBen Gras uint32_t len_limit = mf_avail(mf); \
1935a645f22SBen Gras if (mf->nice_len <= len_limit) { \
1945a645f22SBen Gras len_limit = mf->nice_len; \
1955a645f22SBen Gras } else if (len_limit < (len_min) \
1965a645f22SBen Gras || (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
1975a645f22SBen Gras assert(mf->action != LZMA_RUN); \
1985a645f22SBen Gras move_pending(mf); \
1995a645f22SBen Gras ret_op; \
2005a645f22SBen Gras } \
2015a645f22SBen Gras const uint8_t *cur = mf_ptr(mf); \
2025a645f22SBen Gras const uint32_t pos = mf->read_pos + mf->offset
2035a645f22SBen Gras
2045a645f22SBen Gras
2055a645f22SBen Gras /// Header for find functions. "return 0" indicates that zero matches
2065a645f22SBen Gras /// were found.
2075a645f22SBen Gras #define header_find(is_bt, len_min) \
2085a645f22SBen Gras header(is_bt, len_min, return 0); \
2095a645f22SBen Gras uint32_t matches_count = 0
2105a645f22SBen Gras
2115a645f22SBen Gras
2125a645f22SBen Gras /// Header for a loop in a skip function. "continue" tells to skip the rest
2135a645f22SBen Gras /// of the code in the loop.
2145a645f22SBen Gras #define header_skip(is_bt, len_min) \
2155a645f22SBen Gras header(is_bt, len_min, continue)
2165a645f22SBen Gras
2175a645f22SBen Gras
2185a645f22SBen Gras /// Calls hc_find_func() or bt_find_func() and calculates the total number
2195a645f22SBen Gras /// of matches found. Updates the dictionary position and returns the number
2205a645f22SBen Gras /// of matches found.
2215a645f22SBen Gras #define call_find(func, len_best) \
2225a645f22SBen Gras do { \
2235a645f22SBen Gras matches_count = func(len_limit, pos, cur, cur_match, mf->depth, \
2245a645f22SBen Gras mf->son, mf->cyclic_pos, mf->cyclic_size, \
2255a645f22SBen Gras matches + matches_count, len_best) \
2265a645f22SBen Gras - matches; \
2275a645f22SBen Gras move_pos(mf); \
2285a645f22SBen Gras return matches_count; \
2295a645f22SBen Gras } while (0)
2305a645f22SBen Gras
2315a645f22SBen Gras
2325a645f22SBen Gras ////////////////
2335a645f22SBen Gras // Hash Chain //
2345a645f22SBen Gras ////////////////
2355a645f22SBen Gras
2365a645f22SBen Gras #if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
2375a645f22SBen Gras ///
2385a645f22SBen Gras ///
2395a645f22SBen Gras /// \param len_limit Don't look for matches longer than len_limit.
2405a645f22SBen Gras /// \param pos lzma_mf.read_pos + lzma_mf.offset
2415a645f22SBen Gras /// \param cur Pointer to current byte (mf_ptr(mf))
2425a645f22SBen Gras /// \param cur_match Start position of the current match candidate
2435a645f22SBen Gras /// \param depth Maximum length of the hash chain
2445a645f22SBen Gras /// \param son lzma_mf.son (contains the hash chain)
2455a645f22SBen Gras /// \param cyclic_pos
2465a645f22SBen Gras /// \param cyclic_size
2475a645f22SBen Gras /// \param matches Array to hold the matches.
2485a645f22SBen Gras /// \param len_best The length of the longest match found so far.
2495a645f22SBen Gras 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)2505a645f22SBen Gras hc_find_func(
2515a645f22SBen Gras const uint32_t len_limit,
2525a645f22SBen Gras const uint32_t pos,
2535a645f22SBen Gras const uint8_t *const cur,
2545a645f22SBen Gras uint32_t cur_match,
2555a645f22SBen Gras uint32_t depth,
2565a645f22SBen Gras uint32_t *const son,
2575a645f22SBen Gras const uint32_t cyclic_pos,
2585a645f22SBen Gras const uint32_t cyclic_size,
2595a645f22SBen Gras lzma_match *matches,
2605a645f22SBen Gras uint32_t len_best)
2615a645f22SBen Gras {
2625a645f22SBen Gras son[cyclic_pos] = cur_match;
2635a645f22SBen Gras
2645a645f22SBen Gras while (true) {
2655a645f22SBen Gras const uint32_t delta = pos - cur_match;
2665a645f22SBen Gras if (depth-- == 0 || delta >= cyclic_size)
2675a645f22SBen Gras return matches;
2685a645f22SBen Gras
2695a645f22SBen Gras const uint8_t *const pb = cur - delta;
2705a645f22SBen Gras cur_match = son[cyclic_pos - delta
2715a645f22SBen Gras + (delta > cyclic_pos ? cyclic_size : 0)];
2725a645f22SBen Gras
2735a645f22SBen Gras if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
274*0a6a1f1dSLionel Sambuc uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit);
2755a645f22SBen Gras
2765a645f22SBen Gras if (len_best < len) {
2775a645f22SBen Gras len_best = len;
2785a645f22SBen Gras matches->len = len;
2795a645f22SBen Gras matches->dist = delta - 1;
2805a645f22SBen Gras ++matches;
2815a645f22SBen Gras
2825a645f22SBen Gras if (len == len_limit)
2835a645f22SBen Gras return matches;
2845a645f22SBen Gras }
2855a645f22SBen Gras }
2865a645f22SBen Gras }
2875a645f22SBen Gras }
2885a645f22SBen Gras
2895a645f22SBen Gras
2905a645f22SBen Gras #define hc_find(len_best) \
2915a645f22SBen Gras call_find(hc_find_func, len_best)
2925a645f22SBen Gras
2935a645f22SBen Gras
2945a645f22SBen Gras #define hc_skip() \
2955a645f22SBen Gras do { \
2965a645f22SBen Gras mf->son[mf->cyclic_pos] = cur_match; \
2975a645f22SBen Gras move_pos(mf); \
2985a645f22SBen Gras } while (0)
2995a645f22SBen Gras
3005a645f22SBen Gras #endif
3015a645f22SBen Gras
3025a645f22SBen Gras
3035a645f22SBen Gras #ifdef HAVE_MF_HC3
3045a645f22SBen Gras extern uint32_t
lzma_mf_hc3_find(lzma_mf * mf,lzma_match * matches)3055a645f22SBen Gras lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
3065a645f22SBen Gras {
3075a645f22SBen Gras header_find(false, 3);
3085a645f22SBen Gras
3095a645f22SBen Gras hash_3_calc();
3105a645f22SBen Gras
3115a645f22SBen Gras const uint32_t delta2 = pos - mf->hash[hash_2_value];
3125a645f22SBen Gras const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
3135a645f22SBen Gras
3145a645f22SBen Gras mf->hash[hash_2_value] = pos;
3155a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
3165a645f22SBen Gras
3175a645f22SBen Gras uint32_t len_best = 2;
3185a645f22SBen Gras
3195a645f22SBen Gras if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
320*0a6a1f1dSLionel Sambuc len_best = lzma_memcmplen(cur - delta2, cur,
321*0a6a1f1dSLionel Sambuc len_best, len_limit);
3225a645f22SBen Gras
3235a645f22SBen Gras matches[0].len = len_best;
3245a645f22SBen Gras matches[0].dist = delta2 - 1;
3255a645f22SBen Gras matches_count = 1;
3265a645f22SBen Gras
3275a645f22SBen Gras if (len_best == len_limit) {
3285a645f22SBen Gras hc_skip();
3295a645f22SBen Gras return 1; // matches_count
3305a645f22SBen Gras }
3315a645f22SBen Gras }
3325a645f22SBen Gras
3335a645f22SBen Gras hc_find(len_best);
3345a645f22SBen Gras }
3355a645f22SBen Gras
3365a645f22SBen Gras
3375a645f22SBen Gras extern void
lzma_mf_hc3_skip(lzma_mf * mf,uint32_t amount)3385a645f22SBen Gras lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
3395a645f22SBen Gras {
3405a645f22SBen Gras do {
3415a645f22SBen Gras if (mf_avail(mf) < 3) {
3425a645f22SBen Gras move_pending(mf);
3435a645f22SBen Gras continue;
3445a645f22SBen Gras }
3455a645f22SBen Gras
3465a645f22SBen Gras const uint8_t *cur = mf_ptr(mf);
3475a645f22SBen Gras const uint32_t pos = mf->read_pos + mf->offset;
3485a645f22SBen Gras
3495a645f22SBen Gras hash_3_calc();
3505a645f22SBen Gras
3515a645f22SBen Gras const uint32_t cur_match
3525a645f22SBen Gras = mf->hash[FIX_3_HASH_SIZE + hash_value];
3535a645f22SBen Gras
3545a645f22SBen Gras mf->hash[hash_2_value] = pos;
3555a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
3565a645f22SBen Gras
3575a645f22SBen Gras hc_skip();
3585a645f22SBen Gras
3595a645f22SBen Gras } while (--amount != 0);
3605a645f22SBen Gras }
3615a645f22SBen Gras #endif
3625a645f22SBen Gras
3635a645f22SBen Gras
3645a645f22SBen Gras #ifdef HAVE_MF_HC4
3655a645f22SBen Gras extern uint32_t
lzma_mf_hc4_find(lzma_mf * mf,lzma_match * matches)3665a645f22SBen Gras lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
3675a645f22SBen Gras {
3685a645f22SBen Gras header_find(false, 4);
3695a645f22SBen Gras
3705a645f22SBen Gras hash_4_calc();
3715a645f22SBen Gras
3725a645f22SBen Gras uint32_t delta2 = pos - mf->hash[hash_2_value];
3735a645f22SBen Gras const uint32_t delta3
3745a645f22SBen Gras = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
3755a645f22SBen Gras const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
3765a645f22SBen Gras
3775a645f22SBen Gras mf->hash[hash_2_value ] = pos;
3785a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
3795a645f22SBen Gras mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
3805a645f22SBen Gras
3815a645f22SBen Gras uint32_t len_best = 1;
3825a645f22SBen Gras
3835a645f22SBen Gras if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
3845a645f22SBen Gras len_best = 2;
3855a645f22SBen Gras matches[0].len = 2;
3865a645f22SBen Gras matches[0].dist = delta2 - 1;
3875a645f22SBen Gras matches_count = 1;
3885a645f22SBen Gras }
3895a645f22SBen Gras
3905a645f22SBen Gras if (delta2 != delta3 && delta3 < mf->cyclic_size
3915a645f22SBen Gras && *(cur - delta3) == *cur) {
3925a645f22SBen Gras len_best = 3;
3935a645f22SBen Gras matches[matches_count++].dist = delta3 - 1;
3945a645f22SBen Gras delta2 = delta3;
3955a645f22SBen Gras }
3965a645f22SBen Gras
3975a645f22SBen Gras if (matches_count != 0) {
398*0a6a1f1dSLionel Sambuc len_best = lzma_memcmplen(cur - delta2, cur,
399*0a6a1f1dSLionel Sambuc len_best, len_limit);
4005a645f22SBen Gras
4015a645f22SBen Gras matches[matches_count - 1].len = len_best;
4025a645f22SBen Gras
4035a645f22SBen Gras if (len_best == len_limit) {
4045a645f22SBen Gras hc_skip();
4055a645f22SBen Gras return matches_count;
4065a645f22SBen Gras }
4075a645f22SBen Gras }
4085a645f22SBen Gras
4095a645f22SBen Gras if (len_best < 3)
4105a645f22SBen Gras len_best = 3;
4115a645f22SBen Gras
4125a645f22SBen Gras hc_find(len_best);
4135a645f22SBen Gras }
4145a645f22SBen Gras
4155a645f22SBen Gras
4165a645f22SBen Gras extern void
lzma_mf_hc4_skip(lzma_mf * mf,uint32_t amount)4175a645f22SBen Gras lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
4185a645f22SBen Gras {
4195a645f22SBen Gras do {
4205a645f22SBen Gras if (mf_avail(mf) < 4) {
4215a645f22SBen Gras move_pending(mf);
4225a645f22SBen Gras continue;
4235a645f22SBen Gras }
4245a645f22SBen Gras
4255a645f22SBen Gras const uint8_t *cur = mf_ptr(mf);
4265a645f22SBen Gras const uint32_t pos = mf->read_pos + mf->offset;
4275a645f22SBen Gras
4285a645f22SBen Gras hash_4_calc();
4295a645f22SBen Gras
4305a645f22SBen Gras const uint32_t cur_match
4315a645f22SBen Gras = mf->hash[FIX_4_HASH_SIZE + hash_value];
4325a645f22SBen Gras
4335a645f22SBen Gras mf->hash[hash_2_value] = pos;
4345a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
4355a645f22SBen Gras mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
4365a645f22SBen Gras
4375a645f22SBen Gras hc_skip();
4385a645f22SBen Gras
4395a645f22SBen Gras } while (--amount != 0);
4405a645f22SBen Gras }
4415a645f22SBen Gras #endif
4425a645f22SBen Gras
4435a645f22SBen Gras
4445a645f22SBen Gras /////////////////
4455a645f22SBen Gras // Binary Tree //
4465a645f22SBen Gras /////////////////
4475a645f22SBen Gras
4485a645f22SBen Gras #if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
4495a645f22SBen Gras 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)4505a645f22SBen Gras bt_find_func(
4515a645f22SBen Gras const uint32_t len_limit,
4525a645f22SBen Gras const uint32_t pos,
4535a645f22SBen Gras const uint8_t *const cur,
4545a645f22SBen Gras uint32_t cur_match,
4555a645f22SBen Gras uint32_t depth,
4565a645f22SBen Gras uint32_t *const son,
4575a645f22SBen Gras const uint32_t cyclic_pos,
4585a645f22SBen Gras const uint32_t cyclic_size,
4595a645f22SBen Gras lzma_match *matches,
4605a645f22SBen Gras uint32_t len_best)
4615a645f22SBen Gras {
4625a645f22SBen Gras uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
4635a645f22SBen Gras uint32_t *ptr1 = son + (cyclic_pos << 1);
4645a645f22SBen Gras
4655a645f22SBen Gras uint32_t len0 = 0;
4665a645f22SBen Gras uint32_t len1 = 0;
4675a645f22SBen Gras
4685a645f22SBen Gras while (true) {
4695a645f22SBen Gras const uint32_t delta = pos - cur_match;
4705a645f22SBen Gras if (depth-- == 0 || delta >= cyclic_size) {
4715a645f22SBen Gras *ptr0 = EMPTY_HASH_VALUE;
4725a645f22SBen Gras *ptr1 = EMPTY_HASH_VALUE;
4735a645f22SBen Gras return matches;
4745a645f22SBen Gras }
4755a645f22SBen Gras
4765a645f22SBen Gras uint32_t *const pair = son + ((cyclic_pos - delta
4775a645f22SBen Gras + (delta > cyclic_pos ? cyclic_size : 0))
4785a645f22SBen Gras << 1);
4795a645f22SBen Gras
4805a645f22SBen Gras const uint8_t *const pb = cur - delta;
4815a645f22SBen Gras uint32_t len = my_min(len0, len1);
4825a645f22SBen Gras
4835a645f22SBen Gras if (pb[len] == cur[len]) {
484*0a6a1f1dSLionel Sambuc len = lzma_memcmplen(pb, cur, len + 1, len_limit);
4855a645f22SBen Gras
4865a645f22SBen Gras if (len_best < len) {
4875a645f22SBen Gras len_best = len;
4885a645f22SBen Gras matches->len = len;
4895a645f22SBen Gras matches->dist = delta - 1;
4905a645f22SBen Gras ++matches;
4915a645f22SBen Gras
4925a645f22SBen Gras if (len == len_limit) {
4935a645f22SBen Gras *ptr1 = pair[0];
4945a645f22SBen Gras *ptr0 = pair[1];
4955a645f22SBen Gras return matches;
4965a645f22SBen Gras }
4975a645f22SBen Gras }
4985a645f22SBen Gras }
4995a645f22SBen Gras
5005a645f22SBen Gras if (pb[len] < cur[len]) {
5015a645f22SBen Gras *ptr1 = cur_match;
5025a645f22SBen Gras ptr1 = pair + 1;
5035a645f22SBen Gras cur_match = *ptr1;
5045a645f22SBen Gras len1 = len;
5055a645f22SBen Gras } else {
5065a645f22SBen Gras *ptr0 = cur_match;
5075a645f22SBen Gras ptr0 = pair;
5085a645f22SBen Gras cur_match = *ptr0;
5095a645f22SBen Gras len0 = len;
5105a645f22SBen Gras }
5115a645f22SBen Gras }
5125a645f22SBen Gras }
5135a645f22SBen Gras
5145a645f22SBen Gras
5155a645f22SBen Gras 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)5165a645f22SBen Gras bt_skip_func(
5175a645f22SBen Gras const uint32_t len_limit,
5185a645f22SBen Gras const uint32_t pos,
5195a645f22SBen Gras const uint8_t *const cur,
5205a645f22SBen Gras uint32_t cur_match,
5215a645f22SBen Gras uint32_t depth,
5225a645f22SBen Gras uint32_t *const son,
5235a645f22SBen Gras const uint32_t cyclic_pos,
5245a645f22SBen Gras const uint32_t cyclic_size)
5255a645f22SBen Gras {
5265a645f22SBen Gras uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
5275a645f22SBen Gras uint32_t *ptr1 = son + (cyclic_pos << 1);
5285a645f22SBen Gras
5295a645f22SBen Gras uint32_t len0 = 0;
5305a645f22SBen Gras uint32_t len1 = 0;
5315a645f22SBen Gras
5325a645f22SBen Gras while (true) {
5335a645f22SBen Gras const uint32_t delta = pos - cur_match;
5345a645f22SBen Gras if (depth-- == 0 || delta >= cyclic_size) {
5355a645f22SBen Gras *ptr0 = EMPTY_HASH_VALUE;
5365a645f22SBen Gras *ptr1 = EMPTY_HASH_VALUE;
5375a645f22SBen Gras return;
5385a645f22SBen Gras }
5395a645f22SBen Gras
5405a645f22SBen Gras uint32_t *pair = son + ((cyclic_pos - delta
5415a645f22SBen Gras + (delta > cyclic_pos ? cyclic_size : 0))
5425a645f22SBen Gras << 1);
5435a645f22SBen Gras const uint8_t *pb = cur - delta;
5445a645f22SBen Gras uint32_t len = my_min(len0, len1);
5455a645f22SBen Gras
5465a645f22SBen Gras if (pb[len] == cur[len]) {
547*0a6a1f1dSLionel Sambuc len = lzma_memcmplen(pb, cur, len + 1, len_limit);
5485a645f22SBen Gras
5495a645f22SBen Gras if (len == len_limit) {
5505a645f22SBen Gras *ptr1 = pair[0];
5515a645f22SBen Gras *ptr0 = pair[1];
5525a645f22SBen Gras return;
5535a645f22SBen Gras }
5545a645f22SBen Gras }
5555a645f22SBen Gras
5565a645f22SBen Gras if (pb[len] < cur[len]) {
5575a645f22SBen Gras *ptr1 = cur_match;
5585a645f22SBen Gras ptr1 = pair + 1;
5595a645f22SBen Gras cur_match = *ptr1;
5605a645f22SBen Gras len1 = len;
5615a645f22SBen Gras } else {
5625a645f22SBen Gras *ptr0 = cur_match;
5635a645f22SBen Gras ptr0 = pair;
5645a645f22SBen Gras cur_match = *ptr0;
5655a645f22SBen Gras len0 = len;
5665a645f22SBen Gras }
5675a645f22SBen Gras }
5685a645f22SBen Gras }
5695a645f22SBen Gras
5705a645f22SBen Gras
5715a645f22SBen Gras #define bt_find(len_best) \
5725a645f22SBen Gras call_find(bt_find_func, len_best)
5735a645f22SBen Gras
5745a645f22SBen Gras #define bt_skip() \
5755a645f22SBen Gras do { \
5765a645f22SBen Gras bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
5775a645f22SBen Gras mf->son, mf->cyclic_pos, \
5785a645f22SBen Gras mf->cyclic_size); \
5795a645f22SBen Gras move_pos(mf); \
5805a645f22SBen Gras } while (0)
5815a645f22SBen Gras
5825a645f22SBen Gras #endif
5835a645f22SBen Gras
5845a645f22SBen Gras
5855a645f22SBen Gras #ifdef HAVE_MF_BT2
5865a645f22SBen Gras extern uint32_t
lzma_mf_bt2_find(lzma_mf * mf,lzma_match * matches)5875a645f22SBen Gras lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
5885a645f22SBen Gras {
5895a645f22SBen Gras header_find(true, 2);
5905a645f22SBen Gras
5915a645f22SBen Gras hash_2_calc();
5925a645f22SBen Gras
5935a645f22SBen Gras const uint32_t cur_match = mf->hash[hash_value];
5945a645f22SBen Gras mf->hash[hash_value] = pos;
5955a645f22SBen Gras
5965a645f22SBen Gras bt_find(1);
5975a645f22SBen Gras }
5985a645f22SBen Gras
5995a645f22SBen Gras
6005a645f22SBen Gras extern void
lzma_mf_bt2_skip(lzma_mf * mf,uint32_t amount)6015a645f22SBen Gras lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
6025a645f22SBen Gras {
6035a645f22SBen Gras do {
6045a645f22SBen Gras header_skip(true, 2);
6055a645f22SBen Gras
6065a645f22SBen Gras hash_2_calc();
6075a645f22SBen Gras
6085a645f22SBen Gras const uint32_t cur_match = mf->hash[hash_value];
6095a645f22SBen Gras mf->hash[hash_value] = pos;
6105a645f22SBen Gras
6115a645f22SBen Gras bt_skip();
6125a645f22SBen Gras
6135a645f22SBen Gras } while (--amount != 0);
6145a645f22SBen Gras }
6155a645f22SBen Gras #endif
6165a645f22SBen Gras
6175a645f22SBen Gras
6185a645f22SBen Gras #ifdef HAVE_MF_BT3
6195a645f22SBen Gras extern uint32_t
lzma_mf_bt3_find(lzma_mf * mf,lzma_match * matches)6205a645f22SBen Gras lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
6215a645f22SBen Gras {
6225a645f22SBen Gras header_find(true, 3);
6235a645f22SBen Gras
6245a645f22SBen Gras hash_3_calc();
6255a645f22SBen Gras
6265a645f22SBen Gras const uint32_t delta2 = pos - mf->hash[hash_2_value];
6275a645f22SBen Gras const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
6285a645f22SBen Gras
6295a645f22SBen Gras mf->hash[hash_2_value] = pos;
6305a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
6315a645f22SBen Gras
6325a645f22SBen Gras uint32_t len_best = 2;
6335a645f22SBen Gras
6345a645f22SBen Gras if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
635*0a6a1f1dSLionel Sambuc len_best = lzma_memcmplen(
636*0a6a1f1dSLionel Sambuc cur, cur - delta2, len_best, len_limit);
6375a645f22SBen Gras
6385a645f22SBen Gras matches[0].len = len_best;
6395a645f22SBen Gras matches[0].dist = delta2 - 1;
6405a645f22SBen Gras matches_count = 1;
6415a645f22SBen Gras
6425a645f22SBen Gras if (len_best == len_limit) {
6435a645f22SBen Gras bt_skip();
6445a645f22SBen Gras return 1; // matches_count
6455a645f22SBen Gras }
6465a645f22SBen Gras }
6475a645f22SBen Gras
6485a645f22SBen Gras bt_find(len_best);
6495a645f22SBen Gras }
6505a645f22SBen Gras
6515a645f22SBen Gras
6525a645f22SBen Gras extern void
lzma_mf_bt3_skip(lzma_mf * mf,uint32_t amount)6535a645f22SBen Gras lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
6545a645f22SBen Gras {
6555a645f22SBen Gras do {
6565a645f22SBen Gras header_skip(true, 3);
6575a645f22SBen Gras
6585a645f22SBen Gras hash_3_calc();
6595a645f22SBen Gras
6605a645f22SBen Gras const uint32_t cur_match
6615a645f22SBen Gras = mf->hash[FIX_3_HASH_SIZE + hash_value];
6625a645f22SBen Gras
6635a645f22SBen Gras mf->hash[hash_2_value] = pos;
6645a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
6655a645f22SBen Gras
6665a645f22SBen Gras bt_skip();
6675a645f22SBen Gras
6685a645f22SBen Gras } while (--amount != 0);
6695a645f22SBen Gras }
6705a645f22SBen Gras #endif
6715a645f22SBen Gras
6725a645f22SBen Gras
6735a645f22SBen Gras #ifdef HAVE_MF_BT4
6745a645f22SBen Gras extern uint32_t
lzma_mf_bt4_find(lzma_mf * mf,lzma_match * matches)6755a645f22SBen Gras lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
6765a645f22SBen Gras {
6775a645f22SBen Gras header_find(true, 4);
6785a645f22SBen Gras
6795a645f22SBen Gras hash_4_calc();
6805a645f22SBen Gras
6815a645f22SBen Gras uint32_t delta2 = pos - mf->hash[hash_2_value];
6825a645f22SBen Gras const uint32_t delta3
6835a645f22SBen Gras = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
6845a645f22SBen Gras const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
6855a645f22SBen Gras
6865a645f22SBen Gras mf->hash[hash_2_value] = pos;
6875a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
6885a645f22SBen Gras mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
6895a645f22SBen Gras
6905a645f22SBen Gras uint32_t len_best = 1;
6915a645f22SBen Gras
6925a645f22SBen Gras if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
6935a645f22SBen Gras len_best = 2;
6945a645f22SBen Gras matches[0].len = 2;
6955a645f22SBen Gras matches[0].dist = delta2 - 1;
6965a645f22SBen Gras matches_count = 1;
6975a645f22SBen Gras }
6985a645f22SBen Gras
6995a645f22SBen Gras if (delta2 != delta3 && delta3 < mf->cyclic_size
7005a645f22SBen Gras && *(cur - delta3) == *cur) {
7015a645f22SBen Gras len_best = 3;
7025a645f22SBen Gras matches[matches_count++].dist = delta3 - 1;
7035a645f22SBen Gras delta2 = delta3;
7045a645f22SBen Gras }
7055a645f22SBen Gras
7065a645f22SBen Gras if (matches_count != 0) {
707*0a6a1f1dSLionel Sambuc len_best = lzma_memcmplen(
708*0a6a1f1dSLionel Sambuc cur, cur - delta2, len_best, len_limit);
7095a645f22SBen Gras
7105a645f22SBen Gras matches[matches_count - 1].len = len_best;
7115a645f22SBen Gras
7125a645f22SBen Gras if (len_best == len_limit) {
7135a645f22SBen Gras bt_skip();
7145a645f22SBen Gras return matches_count;
7155a645f22SBen Gras }
7165a645f22SBen Gras }
7175a645f22SBen Gras
7185a645f22SBen Gras if (len_best < 3)
7195a645f22SBen Gras len_best = 3;
7205a645f22SBen Gras
7215a645f22SBen Gras bt_find(len_best);
7225a645f22SBen Gras }
7235a645f22SBen Gras
7245a645f22SBen Gras
7255a645f22SBen Gras extern void
lzma_mf_bt4_skip(lzma_mf * mf,uint32_t amount)7265a645f22SBen Gras lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
7275a645f22SBen Gras {
7285a645f22SBen Gras do {
7295a645f22SBen Gras header_skip(true, 4);
7305a645f22SBen Gras
7315a645f22SBen Gras hash_4_calc();
7325a645f22SBen Gras
7335a645f22SBen Gras const uint32_t cur_match
7345a645f22SBen Gras = mf->hash[FIX_4_HASH_SIZE + hash_value];
7355a645f22SBen Gras
7365a645f22SBen Gras mf->hash[hash_2_value] = pos;
7375a645f22SBen Gras mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
7385a645f22SBen Gras mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
7395a645f22SBen Gras
7405a645f22SBen Gras bt_skip();
7415a645f22SBen Gras
7425a645f22SBen Gras } while (--amount != 0);
7435a645f22SBen Gras }
7445a645f22SBen Gras #endif
745