Path: blob/master/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c
3156 views
// SPDX-License-Identifier: 0BSD12///////////////////////////////////////////////////////////////////////////////3//4/// \file lzma_encoder_optimum_fast.c5//6// Author: Igor Pavlov7//8///////////////////////////////////////////////////////////////////////////////910#include "lzma_encoder_private.h"11#include "memcmplen.h"121314#define change_pair(small_dist, big_dist) \15(((big_dist) >> 7) > (small_dist))161718extern void19lzma_lzma_optimum_fast(lzma_lzma1_encoder *restrict coder,20lzma_mf *restrict mf,21uint32_t *restrict back_res, uint32_t *restrict len_res)22{23const uint32_t nice_len = mf->nice_len;2425uint32_t len_main;26uint32_t matches_count;27if (mf->read_ahead == 0) {28len_main = mf_find(mf, &matches_count, coder->matches);29} else {30assert(mf->read_ahead == 1);31len_main = coder->longest_match_length;32matches_count = coder->matches_count;33}3435const uint8_t *buf = mf_ptr(mf) - 1;36const uint32_t buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);3738if (buf_avail < 2) {39// There's not enough input left to encode a match.40*back_res = UINT32_MAX;41*len_res = 1;42return;43}4445// Look for repeated matches; scan the previous four match distances46uint32_t rep_len = 0;47uint32_t rep_index = 0;4849for (uint32_t i = 0; i < REPS; ++i) {50// Pointer to the beginning of the match candidate51const uint8_t *const buf_back = buf - coder->reps[i] - 1;5253// If the first two bytes (2 == MATCH_LEN_MIN) do not match,54// this rep is not useful.55if (not_equal_16(buf, buf_back))56continue;5758// The first two bytes matched.59// Calculate the length of the match.60const uint32_t len = lzma_memcmplen(61buf, buf_back, 2, buf_avail);6263// If we have found a repeated match that is at least64// nice_len long, return it immediately.65if (len >= nice_len) {66*back_res = i;67*len_res = len;68mf_skip(mf, len - 1);69return;70}7172if (len > rep_len) {73rep_index = i;74rep_len = len;75}76}7778// We didn't find a long enough repeated match. Encode it as a normal79// match if the match length is at least nice_len.80if (len_main >= nice_len) {81*back_res = coder->matches[matches_count - 1].dist + REPS;82*len_res = len_main;83mf_skip(mf, len_main - 1);84return;85}8687uint32_t back_main = 0;88if (len_main >= 2) {89back_main = coder->matches[matches_count - 1].dist;9091while (matches_count > 1 && len_main ==92coder->matches[matches_count - 2].len + 1) {93if (!change_pair(coder->matches[94matches_count - 2].dist,95back_main))96break;9798--matches_count;99len_main = coder->matches[matches_count - 1].len;100back_main = coder->matches[matches_count - 1].dist;101}102103if (len_main == 2 && back_main >= 0x80)104len_main = 1;105}106107if (rep_len >= 2) {108if (rep_len + 1 >= len_main109|| (rep_len + 2 >= len_main110&& back_main > (UINT32_C(1) << 9))111|| (rep_len + 3 >= len_main112&& back_main > (UINT32_C(1) << 15))) {113*back_res = rep_index;114*len_res = rep_len;115mf_skip(mf, rep_len - 1);116return;117}118}119120if (len_main < 2 || buf_avail <= 2) {121*back_res = UINT32_MAX;122*len_res = 1;123return;124}125126// Get the matches for the next byte. If we find a better match,127// the current byte is encoded as a literal.128coder->longest_match_length = mf_find(mf,129&coder->matches_count, coder->matches);130131if (coder->longest_match_length >= 2) {132const uint32_t new_dist = coder->matches[133coder->matches_count - 1].dist;134135if ((coder->longest_match_length >= len_main136&& new_dist < back_main)137|| (coder->longest_match_length == len_main + 1138&& !change_pair(back_main, new_dist))139|| (coder->longest_match_length > len_main + 1)140|| (coder->longest_match_length + 1 >= len_main141&& len_main >= 3142&& change_pair(new_dist, back_main))) {143*back_res = UINT32_MAX;144*len_res = 1;145return;146}147}148149// In contrast to LZMA SDK, dictionary could not have been moved150// between mf_find() calls, thus it is safe to just increment151// the old buf pointer instead of recalculating it with mf_ptr().152++buf;153154const uint32_t limit = my_max(2, len_main - 1);155156for (uint32_t i = 0; i < REPS; ++i) {157if (memcmp(buf, buf - coder->reps[i] - 1, limit) == 0) {158*back_res = UINT32_MAX;159*len_res = 1;160return;161}162}163164*back_res = back_main + REPS;165*len_res = len_main;166mf_skip(mf, len_main - 2);167return;168}169170171