a2df4a3f76
Revert commit 82c51a8a (liblzma: Disable XL compiler optimizations in one source to avoid crash, 2015-04-02) and instead add a compiler flag to disable optimizations in every source of liblzma. Somehow the XL compiler optimizations create incorrect behavior in liblzma and lead to crashes or truncated output during compression.
926 lines
23 KiB
C
926 lines
23 KiB
C
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
/// \file lzma_encoder_optimum_normal.c
|
|
//
|
|
// Author: Igor Pavlov
|
|
//
|
|
// This file has been put into the public domain.
|
|
// You can do whatever you want with this file.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "lzma_encoder_private.h"
|
|
#include "fastpos.h"
|
|
|
|
|
|
////////////
|
|
// Prices //
|
|
////////////
|
|
|
|
static uint32_t
|
|
get_literal_price(const lzma_coder *const coder, const uint32_t pos,
|
|
const uint32_t prev_byte, const bool match_mode,
|
|
uint32_t match_byte, uint32_t symbol)
|
|
{
|
|
const probability *const subcoder = literal_subcoder(coder->literal,
|
|
coder->literal_context_bits, coder->literal_pos_mask,
|
|
pos, prev_byte);
|
|
|
|
uint32_t price = 0;
|
|
|
|
if (!match_mode) {
|
|
price = rc_bittree_price(subcoder, 8, symbol);
|
|
} else {
|
|
uint32_t offset = 0x100;
|
|
symbol += UINT32_C(1) << 8;
|
|
|
|
do {
|
|
uint32_t match_bit;
|
|
uint32_t subcoder_index;
|
|
uint32_t bit;
|
|
|
|
match_byte <<= 1;
|
|
|
|
match_bit = match_byte & offset;
|
|
subcoder_index = offset + match_bit + (symbol >> 8);
|
|
bit = (symbol >> 7) & 1;
|
|
price += rc_bit_price(subcoder[subcoder_index], bit);
|
|
|
|
symbol <<= 1;
|
|
offset &= ~(match_byte ^ symbol);
|
|
|
|
} while (symbol < (UINT32_C(1) << 16));
|
|
}
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_len_price(const lzma_length_encoder *const lencoder,
|
|
const uint32_t len, const uint32_t pos_state)
|
|
{
|
|
// NOTE: Unlike the other price tables, length prices are updated
|
|
// in lzma_encoder.c
|
|
return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_short_rep_price(const lzma_coder *const coder,
|
|
const lzma_lzma_state state, const uint32_t pos_state)
|
|
{
|
|
return rc_bit_0_price(coder->is_rep0[state])
|
|
+ rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
|
|
const lzma_lzma_state state, uint32_t pos_state)
|
|
{
|
|
uint32_t price;
|
|
|
|
if (rep_index == 0) {
|
|
price = rc_bit_0_price(coder->is_rep0[state]);
|
|
price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
|
|
} else {
|
|
price = rc_bit_1_price(coder->is_rep0[state]);
|
|
|
|
if (rep_index == 1) {
|
|
price += rc_bit_0_price(coder->is_rep1[state]);
|
|
} else {
|
|
price += rc_bit_1_price(coder->is_rep1[state]);
|
|
price += rc_bit_price(coder->is_rep2[state],
|
|
rep_index - 2);
|
|
}
|
|
}
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
|
|
const uint32_t len, const lzma_lzma_state state,
|
|
const uint32_t pos_state)
|
|
{
|
|
return get_len_price(&coder->rep_len_encoder, len, pos_state)
|
|
+ get_pure_rep_price(coder, rep_index, state, pos_state);
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
get_pos_len_price(const lzma_coder *const coder, const uint32_t pos,
|
|
const uint32_t len, const uint32_t pos_state)
|
|
{
|
|
const uint32_t len_to_pos_state = get_len_to_pos_state(len);
|
|
uint32_t price;
|
|
|
|
if (pos < FULL_DISTANCES) {
|
|
price = coder->distances_prices[len_to_pos_state][pos];
|
|
} else {
|
|
const uint32_t pos_slot = get_pos_slot_2(pos);
|
|
price = coder->pos_slot_prices[len_to_pos_state][pos_slot]
|
|
+ coder->align_prices[pos & ALIGN_MASK];
|
|
}
|
|
|
|
price += get_len_price(&coder->match_len_encoder, len, pos_state);
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
static void
|
|
fill_distances_prices(lzma_coder *coder)
|
|
{
|
|
uint32_t len_to_pos_state;
|
|
uint32_t pos_slot;
|
|
uint32_t i;
|
|
|
|
for (len_to_pos_state = 0;
|
|
len_to_pos_state < LEN_TO_POS_STATES;
|
|
++len_to_pos_state) {
|
|
|
|
uint32_t *const pos_slot_prices
|
|
= coder->pos_slot_prices[len_to_pos_state];
|
|
|
|
// Price to encode the pos_slot.
|
|
for (pos_slot = 0;
|
|
pos_slot < coder->dist_table_size; ++pos_slot)
|
|
pos_slot_prices[pos_slot] = rc_bittree_price(
|
|
coder->pos_slot[len_to_pos_state],
|
|
POS_SLOT_BITS, pos_slot);
|
|
|
|
// For matches with distance >= FULL_DISTANCES, add the price
|
|
// of the direct bits part of the match distance. (Align bits
|
|
// are handled by fill_align_prices()).
|
|
for (pos_slot = END_POS_MODEL_INDEX;
|
|
pos_slot < coder->dist_table_size; ++pos_slot)
|
|
pos_slot_prices[pos_slot] += rc_direct_price(
|
|
((pos_slot >> 1) - 1) - ALIGN_BITS);
|
|
|
|
// Distances in the range [0, 3] are fully encoded with
|
|
// pos_slot, so they are used for coder->distances_prices
|
|
// as is.
|
|
for (i = 0; i < START_POS_MODEL_INDEX; ++i)
|
|
coder->distances_prices[len_to_pos_state][i]
|
|
= pos_slot_prices[i];
|
|
}
|
|
|
|
// Distances in the range [4, 127] depend on pos_slot and pos_special.
|
|
// We do this in a loop separate from the above loop to avoid
|
|
// redundant calls to get_pos_slot().
|
|
for (i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) {
|
|
const uint32_t pos_slot = get_pos_slot(i);
|
|
const uint32_t footer_bits = ((pos_slot >> 1) - 1);
|
|
const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
|
|
const uint32_t price = rc_bittree_reverse_price(
|
|
coder->pos_special + base - pos_slot - 1,
|
|
footer_bits, i - base);
|
|
|
|
for (len_to_pos_state = 0;
|
|
len_to_pos_state < LEN_TO_POS_STATES;
|
|
++len_to_pos_state)
|
|
coder->distances_prices[len_to_pos_state][i]
|
|
= price + coder->pos_slot_prices[
|
|
len_to_pos_state][pos_slot];
|
|
}
|
|
|
|
coder->match_price_count = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
static void
|
|
fill_align_prices(lzma_coder *coder)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < ALIGN_TABLE_SIZE; ++i)
|
|
coder->align_prices[i] = rc_bittree_reverse_price(
|
|
coder->pos_align, ALIGN_BITS, i);
|
|
|
|
coder->align_price_count = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
/////////////
|
|
// Optimal //
|
|
/////////////
|
|
|
|
static inline void
|
|
make_literal(lzma_optimal *optimal)
|
|
{
|
|
optimal->back_prev = UINT32_MAX;
|
|
optimal->prev_1_is_literal = false;
|
|
}
|
|
|
|
|
|
static inline void
|
|
make_short_rep(lzma_optimal *optimal)
|
|
{
|
|
optimal->back_prev = 0;
|
|
optimal->prev_1_is_literal = false;
|
|
}
|
|
|
|
|
|
#define is_short_rep(optimal) \
|
|
((optimal).back_prev == 0)
|
|
|
|
|
|
static void
|
|
backward(lzma_coder *LZMA_RESTRICT coder, uint32_t *LZMA_RESTRICT len_res,
|
|
uint32_t *LZMA_RESTRICT back_res, uint32_t cur)
|
|
{
|
|
uint32_t pos_mem = coder->opts[cur].pos_prev;
|
|
uint32_t back_mem = coder->opts[cur].back_prev;
|
|
|
|
coder->opts_end_index = cur;
|
|
|
|
do {
|
|
const uint32_t pos_prev = pos_mem;
|
|
const uint32_t back_cur = back_mem;
|
|
|
|
if (coder->opts[cur].prev_1_is_literal) {
|
|
make_literal(&coder->opts[pos_mem]);
|
|
coder->opts[pos_mem].pos_prev = pos_mem - 1;
|
|
|
|
if (coder->opts[cur].prev_2) {
|
|
coder->opts[pos_mem - 1].prev_1_is_literal
|
|
= false;
|
|
coder->opts[pos_mem - 1].pos_prev
|
|
= coder->opts[cur].pos_prev_2;
|
|
coder->opts[pos_mem - 1].back_prev
|
|
= coder->opts[cur].back_prev_2;
|
|
}
|
|
}
|
|
|
|
back_mem = coder->opts[pos_prev].back_prev;
|
|
pos_mem = coder->opts[pos_prev].pos_prev;
|
|
|
|
coder->opts[pos_prev].back_prev = back_cur;
|
|
coder->opts[pos_prev].pos_prev = cur;
|
|
cur = pos_prev;
|
|
|
|
} while (cur != 0);
|
|
|
|
coder->opts_current_index = coder->opts[0].pos_prev;
|
|
*len_res = coder->opts[0].pos_prev;
|
|
*back_res = coder->opts[0].back_prev;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//////////
|
|
// Main //
|
|
//////////
|
|
|
|
static inline uint32_t
|
|
helper1(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
|
|
uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res,
|
|
uint32_t position)
|
|
{
|
|
uint32_t buf_avail;
|
|
const uint8_t *buf;
|
|
uint32_t rep_lens[REP_DISTANCES];
|
|
uint32_t rep_max_index = 0;
|
|
uint32_t i;
|
|
|
|
uint8_t current_byte;
|
|
uint8_t match_byte;
|
|
|
|
uint32_t pos_state;
|
|
uint32_t match_price;
|
|
uint32_t rep_match_price;
|
|
uint32_t len_end;
|
|
uint32_t len;
|
|
|
|
uint32_t normal_match_price;
|
|
|
|
const uint32_t nice_len = mf->nice_len;
|
|
|
|
uint32_t len_main;
|
|
uint32_t matches_count;
|
|
|
|
if (mf->read_ahead == 0) {
|
|
len_main = mf_find(mf, &matches_count, coder->matches);
|
|
} else {
|
|
assert(mf->read_ahead == 1);
|
|
len_main = coder->longest_match_length;
|
|
matches_count = coder->matches_count;
|
|
}
|
|
|
|
buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
|
|
if (buf_avail < 2) {
|
|
*back_res = UINT32_MAX;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
buf = mf_ptr(mf) - 1;
|
|
|
|
for (i = 0; i < REP_DISTANCES; ++i) {
|
|
uint32_t len_test;
|
|
|
|
const uint8_t *const buf_back = buf - coder->reps[i] - 1;
|
|
|
|
if (not_equal_16(buf, buf_back)) {
|
|
rep_lens[i] = 0;
|
|
continue;
|
|
}
|
|
|
|
for (len_test = 2; len_test < buf_avail
|
|
&& buf[len_test] == buf_back[len_test];
|
|
++len_test) ;
|
|
|
|
rep_lens[i] = len_test;
|
|
if (len_test > rep_lens[rep_max_index])
|
|
rep_max_index = i;
|
|
}
|
|
|
|
if (rep_lens[rep_max_index] >= nice_len) {
|
|
*back_res = rep_max_index;
|
|
*len_res = rep_lens[rep_max_index];
|
|
mf_skip(mf, *len_res - 1);
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
|
|
if (len_main >= nice_len) {
|
|
*back_res = coder->matches[matches_count - 1].dist
|
|
+ REP_DISTANCES;
|
|
*len_res = len_main;
|
|
mf_skip(mf, len_main - 1);
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
current_byte = *buf;
|
|
match_byte = *(buf - coder->reps[0] - 1);
|
|
|
|
if (len_main < 2 && current_byte != match_byte
|
|
&& rep_lens[rep_max_index] < 2) {
|
|
*back_res = UINT32_MAX;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
coder->opts[0].state = coder->state;
|
|
|
|
pos_state = position & coder->pos_mask;
|
|
|
|
coder->opts[1].price = rc_bit_0_price(
|
|
coder->is_match[coder->state][pos_state])
|
|
+ get_literal_price(coder, position, buf[-1],
|
|
!is_literal_state(coder->state),
|
|
match_byte, current_byte);
|
|
|
|
make_literal(&coder->opts[1]);
|
|
|
|
match_price = rc_bit_1_price(
|
|
coder->is_match[coder->state][pos_state]);
|
|
rep_match_price = match_price
|
|
+ rc_bit_1_price(coder->is_rep[coder->state]);
|
|
|
|
if (match_byte == current_byte) {
|
|
const uint32_t short_rep_price = rep_match_price
|
|
+ get_short_rep_price(
|
|
coder, coder->state, pos_state);
|
|
|
|
if (short_rep_price < coder->opts[1].price) {
|
|
coder->opts[1].price = short_rep_price;
|
|
make_short_rep(&coder->opts[1]);
|
|
}
|
|
}
|
|
|
|
len_end = my_max(len_main, rep_lens[rep_max_index]);
|
|
|
|
if (len_end < 2) {
|
|
*back_res = coder->opts[1].back_prev;
|
|
*len_res = 1;
|
|
return UINT32_MAX;
|
|
}
|
|
|
|
coder->opts[1].pos_prev = 0;
|
|
|
|
for (i = 0; i < REP_DISTANCES; ++i)
|
|
coder->opts[0].backs[i] = coder->reps[i];
|
|
|
|
len = len_end;
|
|
do {
|
|
coder->opts[len].price = RC_INFINITY_PRICE;
|
|
} while (--len >= 2);
|
|
|
|
|
|
for (i = 0; i < REP_DISTANCES; ++i) {
|
|
uint32_t price;
|
|
|
|
uint32_t rep_len = rep_lens[i];
|
|
if (rep_len < 2)
|
|
continue;
|
|
|
|
price = rep_match_price + get_pure_rep_price(
|
|
coder, i, coder->state, pos_state);
|
|
|
|
do {
|
|
const uint32_t cur_and_len_price = price
|
|
+ get_len_price(
|
|
&coder->rep_len_encoder,
|
|
rep_len, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[rep_len].price) {
|
|
coder->opts[rep_len].price = cur_and_len_price;
|
|
coder->opts[rep_len].pos_prev = 0;
|
|
coder->opts[rep_len].back_prev = i;
|
|
coder->opts[rep_len].prev_1_is_literal = false;
|
|
}
|
|
} while (--rep_len >= 2);
|
|
}
|
|
|
|
|
|
normal_match_price = match_price
|
|
+ rc_bit_0_price(coder->is_rep[coder->state]);
|
|
|
|
len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
|
|
if (len <= len_main) {
|
|
uint32_t i = 0;
|
|
while (len > coder->matches[i].len)
|
|
++i;
|
|
|
|
for(; ; ++len) {
|
|
const uint32_t dist = coder->matches[i].dist;
|
|
const uint32_t cur_and_len_price = normal_match_price
|
|
+ get_pos_len_price(coder,
|
|
dist, len, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[len].price) {
|
|
coder->opts[len].price = cur_and_len_price;
|
|
coder->opts[len].pos_prev = 0;
|
|
coder->opts[len].back_prev
|
|
= dist + REP_DISTANCES;
|
|
coder->opts[len].prev_1_is_literal = false;
|
|
}
|
|
|
|
if (len == coder->matches[i].len)
|
|
if (++i == matches_count)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return len_end;
|
|
}
|
|
|
|
|
|
static inline uint32_t
|
|
helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
|
|
uint32_t len_end, uint32_t position, const uint32_t cur,
|
|
const uint32_t nice_len, const uint32_t buf_avail_full)
|
|
{
|
|
uint32_t matches_count = coder->matches_count;
|
|
uint32_t new_len = coder->longest_match_length;
|
|
uint32_t pos_prev = coder->opts[cur].pos_prev;
|
|
lzma_lzma_state state;
|
|
uint32_t buf_avail;
|
|
uint32_t rep_index;
|
|
uint32_t i;
|
|
|
|
uint32_t cur_price;
|
|
uint8_t current_byte;
|
|
uint8_t match_byte;
|
|
uint32_t pos_state;
|
|
uint32_t cur_and_1_price;
|
|
bool next_is_literal = false;
|
|
uint32_t match_price;
|
|
uint32_t rep_match_price;
|
|
uint32_t start_len = 2;
|
|
|
|
if (coder->opts[cur].prev_1_is_literal) {
|
|
--pos_prev;
|
|
|
|
if (coder->opts[cur].prev_2) {
|
|
state = coder->opts[coder->opts[cur].pos_prev_2].state;
|
|
|
|
if (coder->opts[cur].back_prev_2 < REP_DISTANCES)
|
|
update_long_rep(state);
|
|
else
|
|
update_match(state);
|
|
|
|
} else {
|
|
state = coder->opts[pos_prev].state;
|
|
}
|
|
|
|
update_literal(state);
|
|
|
|
} else {
|
|
state = coder->opts[pos_prev].state;
|
|
}
|
|
|
|
if (pos_prev == cur - 1) {
|
|
if (is_short_rep(coder->opts[cur]))
|
|
update_short_rep(state);
|
|
else
|
|
update_literal(state);
|
|
} else {
|
|
uint32_t pos;
|
|
if (coder->opts[cur].prev_1_is_literal
|
|
&& coder->opts[cur].prev_2) {
|
|
pos_prev = coder->opts[cur].pos_prev_2;
|
|
pos = coder->opts[cur].back_prev_2;
|
|
update_long_rep(state);
|
|
} else {
|
|
pos = coder->opts[cur].back_prev;
|
|
if (pos < REP_DISTANCES)
|
|
update_long_rep(state);
|
|
else
|
|
update_match(state);
|
|
}
|
|
|
|
if (pos < REP_DISTANCES) {
|
|
uint32_t i;
|
|
|
|
reps[0] = coder->opts[pos_prev].backs[pos];
|
|
|
|
for (i = 1; i <= pos; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i - 1];
|
|
|
|
for (; i < REP_DISTANCES; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i];
|
|
|
|
} else {
|
|
reps[0] = pos - REP_DISTANCES;
|
|
|
|
for (i = 1; i < REP_DISTANCES; ++i)
|
|
reps[i] = coder->opts[pos_prev].backs[i - 1];
|
|
}
|
|
}
|
|
|
|
coder->opts[cur].state = state;
|
|
|
|
for (i = 0; i < REP_DISTANCES; ++i)
|
|
coder->opts[cur].backs[i] = reps[i];
|
|
|
|
cur_price = coder->opts[cur].price;
|
|
|
|
current_byte = *buf;
|
|
match_byte = *(buf - reps[0] - 1);
|
|
|
|
pos_state = position & coder->pos_mask;
|
|
|
|
cur_and_1_price = cur_price
|
|
+ rc_bit_0_price(coder->is_match[state][pos_state])
|
|
+ get_literal_price(coder, position, buf[-1],
|
|
!is_literal_state(state), match_byte, current_byte);
|
|
|
|
if (cur_and_1_price < coder->opts[cur + 1].price) {
|
|
coder->opts[cur + 1].price = cur_and_1_price;
|
|
coder->opts[cur + 1].pos_prev = cur;
|
|
make_literal(&coder->opts[cur + 1]);
|
|
next_is_literal = true;
|
|
}
|
|
|
|
match_price = cur_price
|
|
+ rc_bit_1_price(coder->is_match[state][pos_state]);
|
|
rep_match_price = match_price
|
|
+ rc_bit_1_price(coder->is_rep[state]);
|
|
|
|
if (match_byte == current_byte
|
|
&& !(coder->opts[cur + 1].pos_prev < cur
|
|
&& coder->opts[cur + 1].back_prev == 0)) {
|
|
|
|
const uint32_t short_rep_price = rep_match_price
|
|
+ get_short_rep_price(coder, state, pos_state);
|
|
|
|
if (short_rep_price <= coder->opts[cur + 1].price) {
|
|
coder->opts[cur + 1].price = short_rep_price;
|
|
coder->opts[cur + 1].pos_prev = cur;
|
|
make_short_rep(&coder->opts[cur + 1]);
|
|
next_is_literal = true;
|
|
}
|
|
}
|
|
|
|
if (buf_avail_full < 2)
|
|
return len_end;
|
|
|
|
buf_avail = my_min(buf_avail_full, nice_len);
|
|
|
|
if (!next_is_literal && match_byte != current_byte) { // speed optimization
|
|
// try literal + rep0
|
|
const uint8_t *const buf_back = buf - reps[0] - 1;
|
|
const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
|
|
|
|
uint32_t len_test = 1;
|
|
while (len_test < limit && buf[len_test] == buf_back[len_test])
|
|
++len_test;
|
|
|
|
--len_test;
|
|
|
|
if (len_test >= 2) {
|
|
uint32_t pos_state_next;
|
|
uint32_t next_rep_match_price;
|
|
uint32_t offset;
|
|
uint32_t cur_and_len_price;
|
|
|
|
lzma_lzma_state state_2 = state;
|
|
update_literal(state_2);
|
|
|
|
pos_state_next = (position + 1) & coder->pos_mask;
|
|
next_rep_match_price = cur_and_1_price
|
|
+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
//for (; len_test >= 2; --len_test) {
|
|
offset = cur + 1 + len_test;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = false;
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
for (rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) {
|
|
uint32_t len_test, len_test_2, len_test_temp;
|
|
uint32_t price, limit;
|
|
|
|
const uint8_t *const buf_back = buf - reps[rep_index] - 1;
|
|
if (not_equal_16(buf, buf_back))
|
|
continue;
|
|
|
|
for (len_test = 2; len_test < buf_avail
|
|
&& buf[len_test] == buf_back[len_test];
|
|
++len_test) ;
|
|
|
|
while (len_end < cur + len_test)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
len_test_temp = len_test;
|
|
price = rep_match_price + get_pure_rep_price(
|
|
coder, rep_index, state, pos_state);
|
|
|
|
do {
|
|
const uint32_t cur_and_len_price = price
|
|
+ get_len_price(&coder->rep_len_encoder,
|
|
len_test, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[cur + len_test].price) {
|
|
coder->opts[cur + len_test].price = cur_and_len_price;
|
|
coder->opts[cur + len_test].pos_prev = cur;
|
|
coder->opts[cur + len_test].back_prev = rep_index;
|
|
coder->opts[cur + len_test].prev_1_is_literal = false;
|
|
}
|
|
} while (--len_test >= 2);
|
|
|
|
len_test = len_test_temp;
|
|
|
|
if (rep_index == 0)
|
|
start_len = len_test + 1;
|
|
|
|
|
|
len_test_2 = len_test + 1;
|
|
limit = my_min(buf_avail_full,
|
|
len_test_2 + nice_len);
|
|
for (; len_test_2 < limit
|
|
&& buf[len_test_2] == buf_back[len_test_2];
|
|
++len_test_2) ;
|
|
|
|
len_test_2 -= len_test + 1;
|
|
|
|
if (len_test_2 >= 2) {
|
|
uint32_t pos_state_next;
|
|
uint32_t cur_and_len_literal_price;
|
|
uint32_t next_rep_match_price;
|
|
uint32_t offset;
|
|
uint32_t cur_and_len_price;
|
|
|
|
lzma_lzma_state state_2 = state;
|
|
update_long_rep(state_2);
|
|
|
|
pos_state_next = (position + len_test) & coder->pos_mask;
|
|
|
|
cur_and_len_literal_price = price
|
|
+ get_len_price(&coder->rep_len_encoder,
|
|
len_test, pos_state)
|
|
+ rc_bit_0_price(coder->is_match[state_2][pos_state_next])
|
|
+ get_literal_price(coder, position + len_test,
|
|
buf[len_test - 1], true,
|
|
buf_back[len_test], buf[len_test]);
|
|
|
|
update_literal(state_2);
|
|
|
|
pos_state_next = (position + len_test + 1) & coder->pos_mask;
|
|
|
|
next_rep_match_price = cur_and_len_literal_price
|
|
+ rc_bit_1_price(coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
//for(; len_test_2 >= 2; len_test_2--) {
|
|
offset = cur + len_test + 1 + len_test_2;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test_2,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + len_test + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = true;
|
|
coder->opts[offset].pos_prev_2 = cur;
|
|
coder->opts[offset].back_prev_2 = rep_index;
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
|
|
//for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
|
|
if (new_len > buf_avail) {
|
|
new_len = buf_avail;
|
|
|
|
matches_count = 0;
|
|
while (new_len > coder->matches[matches_count].len)
|
|
++matches_count;
|
|
|
|
coder->matches[matches_count++].len = new_len;
|
|
}
|
|
|
|
|
|
if (new_len >= start_len) {
|
|
uint32_t len_test;
|
|
uint32_t i = 0;
|
|
|
|
const uint32_t normal_match_price = match_price
|
|
+ rc_bit_0_price(coder->is_rep[state]);
|
|
|
|
while (len_end < cur + new_len)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
while (start_len > coder->matches[i].len)
|
|
++i;
|
|
|
|
for (len_test = start_len; ; ++len_test) {
|
|
const uint32_t cur_back = coder->matches[i].dist;
|
|
uint32_t cur_and_len_price = normal_match_price
|
|
+ get_pos_len_price(coder,
|
|
cur_back, len_test, pos_state);
|
|
|
|
if (cur_and_len_price < coder->opts[cur + len_test].price) {
|
|
coder->opts[cur + len_test].price = cur_and_len_price;
|
|
coder->opts[cur + len_test].pos_prev = cur;
|
|
coder->opts[cur + len_test].back_prev
|
|
= cur_back + REP_DISTANCES;
|
|
coder->opts[cur + len_test].prev_1_is_literal = false;
|
|
}
|
|
|
|
if (len_test == coder->matches[i].len) {
|
|
// Try Match + Literal + Rep0
|
|
const uint8_t *const buf_back = buf - cur_back - 1;
|
|
uint32_t len_test_2 = len_test + 1;
|
|
const uint32_t limit = my_min(buf_avail_full,
|
|
len_test_2 + nice_len);
|
|
|
|
for (; len_test_2 < limit &&
|
|
buf[len_test_2] == buf_back[len_test_2];
|
|
++len_test_2) ;
|
|
|
|
len_test_2 -= len_test + 1;
|
|
|
|
if (len_test_2 >= 2) {
|
|
uint32_t pos_state_next;
|
|
uint32_t cur_and_len_literal_price;
|
|
uint32_t next_rep_match_price;
|
|
uint32_t offset;
|
|
|
|
lzma_lzma_state state_2 = state;
|
|
update_match(state_2);
|
|
pos_state_next = (position + len_test) & coder->pos_mask;
|
|
|
|
cur_and_len_literal_price = cur_and_len_price
|
|
+ rc_bit_0_price(
|
|
coder->is_match[state_2][pos_state_next])
|
|
+ get_literal_price(coder,
|
|
position + len_test,
|
|
buf[len_test - 1],
|
|
true,
|
|
buf_back[len_test],
|
|
buf[len_test]);
|
|
|
|
update_literal(state_2);
|
|
pos_state_next = (pos_state_next + 1) & coder->pos_mask;
|
|
|
|
next_rep_match_price
|
|
= cur_and_len_literal_price
|
|
+ rc_bit_1_price(
|
|
coder->is_match[state_2][pos_state_next])
|
|
+ rc_bit_1_price(coder->is_rep[state_2]);
|
|
|
|
// for(; len_test_2 >= 2; --len_test_2) {
|
|
offset = cur + len_test + 1 + len_test_2;
|
|
|
|
while (len_end < offset)
|
|
coder->opts[++len_end].price = RC_INFINITY_PRICE;
|
|
|
|
cur_and_len_price = next_rep_match_price
|
|
+ get_rep_price(coder, 0, len_test_2,
|
|
state_2, pos_state_next);
|
|
|
|
if (cur_and_len_price < coder->opts[offset].price) {
|
|
coder->opts[offset].price = cur_and_len_price;
|
|
coder->opts[offset].pos_prev = cur + len_test + 1;
|
|
coder->opts[offset].back_prev = 0;
|
|
coder->opts[offset].prev_1_is_literal = true;
|
|
coder->opts[offset].prev_2 = true;
|
|
coder->opts[offset].pos_prev_2 = cur;
|
|
coder->opts[offset].back_prev_2
|
|
= cur_back + REP_DISTANCES;
|
|
}
|
|
//}
|
|
}
|
|
|
|
if (++i == matches_count)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return len_end;
|
|
}
|
|
|
|
|
|
extern void
|
|
lzma_lzma_optimum_normal(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
|
|
uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res,
|
|
uint32_t position)
|
|
{
|
|
uint32_t reps[REP_DISTANCES];
|
|
uint32_t len_end;
|
|
uint32_t cur;
|
|
|
|
// If we have symbols pending, return the next pending symbol.
|
|
if (coder->opts_end_index != coder->opts_current_index) {
|
|
assert(mf->read_ahead > 0);
|
|
*len_res = coder->opts[coder->opts_current_index].pos_prev
|
|
- coder->opts_current_index;
|
|
*back_res = coder->opts[coder->opts_current_index].back_prev;
|
|
coder->opts_current_index = coder->opts[
|
|
coder->opts_current_index].pos_prev;
|
|
return;
|
|
}
|
|
|
|
// Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
|
|
// this was done in both initialization function and in the main loop.
|
|
// In liblzma they were moved into this single place.
|
|
if (mf->read_ahead == 0) {
|
|
if (coder->match_price_count >= (1 << 7))
|
|
fill_distances_prices(coder);
|
|
|
|
if (coder->align_price_count >= ALIGN_TABLE_SIZE)
|
|
fill_align_prices(coder);
|
|
}
|
|
|
|
// TODO: This needs quite a bit of cleaning still. But splitting
|
|
// the original function into two pieces makes it at least a little
|
|
// more readable, since those two parts don't share many variables.
|
|
|
|
len_end = helper1(coder, mf, back_res, len_res, position);
|
|
if (len_end == UINT32_MAX)
|
|
return;
|
|
|
|
|
|
memcpy(reps, coder->reps, sizeof(reps));
|
|
|
|
for (cur = 1; cur < len_end; ++cur) {
|
|
assert(cur < OPTS);
|
|
|
|
coder->longest_match_length = mf_find(
|
|
mf, &coder->matches_count, coder->matches);
|
|
|
|
if (coder->longest_match_length >= mf->nice_len)
|
|
break;
|
|
|
|
len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
|
|
position + cur, cur, mf->nice_len,
|
|
my_min(mf_avail(mf) + 1, OPTS - 1 - cur));
|
|
}
|
|
|
|
backward(coder, len_res, back_res, cur);
|
|
return;
|
|
}
|