liblzma: Allow nice_len 2 and 3 even if match finder requires 3 or 4.

That is, if the specified nice_len is smaller than the minimum
of the match finder, silently use the match finder's minimum value
instead of reporting an error. The old behavior is annoying to users
and it complicates xz options handling too.
This commit is contained in:
Lasse Collin 2022-11-24 23:23:55 +02:00
parent 93439cfafe
commit 3be88ae071
3 changed files with 26 additions and 8 deletions

View File

@ -293,11 +293,15 @@ lz_encoder_prepare(lzma_mf *mf, const lzma_allocator *allocator,
return true; return true;
} }
// Calculate the sizes of mf->hash and mf->son and check that // Calculate the sizes of mf->hash and mf->son.
// nice_len is big enough for the selected match finder. //
const uint32_t hash_bytes = lz_options->match_finder & 0x0F; // NOTE: Since 5.3.5beta the LZMA encoder ensures that nice_len
if (hash_bytes > mf->nice_len) // is big enough for the selected match finder. This makes it
return true; // easier for applications as nice_len = 2 will always be accepted
// even though the effective value can be slightly bigger.
const uint32_t hash_bytes
= mf_get_hash_bytes(lz_options->match_finder);
assert(hash_bytes <= mf->nice_len);
const bool is_bt = (lz_options->match_finder & 0x10) != 0; const bool is_bt = (lz_options->match_finder & 0x10) != 0;
uint32_t hs; uint32_t hs;

View File

@ -220,6 +220,15 @@ typedef struct {
// are called `read ahead'. // are called `read ahead'.
/// Get how many bytes the match finder hashes in its initial step.
/// This is also the minimum nice_len value with the match finder.
static inline uint32_t
mf_get_hash_bytes(lzma_match_finder match_finder)
{
return (uint32_t)match_finder & 0x0F;
}
/// Get pointer to the first byte not ran through the match finder /// Get pointer to the first byte not ran through the match finder
static inline const uint8_t * static inline const uint8_t *
mf_ptr(const lzma_mf *mf) mf_ptr(const lzma_mf *mf)

View File

@ -492,7 +492,8 @@ set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)
lz_options->dict_size = options->dict_size; lz_options->dict_size = options->dict_size;
lz_options->after_size = LOOP_INPUT_MAX; lz_options->after_size = LOOP_INPUT_MAX;
lz_options->match_len_max = MATCH_LEN_MAX; lz_options->match_len_max = MATCH_LEN_MAX;
lz_options->nice_len = options->nice_len; lz_options->nice_len = my_max(mf_get_hash_bytes(options->mf),
options->nice_len);
lz_options->match_finder = options->mf; lz_options->match_finder = options->mf;
lz_options->depth = options->depth; lz_options->depth = options->depth;
lz_options->preset_dict = options->preset_dict; lz_options->preset_dict = options->preset_dict;
@ -643,10 +644,14 @@ lzma_lzma_encoder_create(void **coder_ptr,
coder->dist_table_size = log_size * 2; coder->dist_table_size = log_size * 2;
// Length encoders' price table size // Length encoders' price table size
const uint32_t nice_len = my_max(
mf_get_hash_bytes(options->mf),
options->nice_len);
coder->match_len_encoder.table_size coder->match_len_encoder.table_size
= options->nice_len + 1 - MATCH_LEN_MIN; = nice_len + 1 - MATCH_LEN_MIN;
coder->rep_len_encoder.table_size coder->rep_len_encoder.table_size
= options->nice_len + 1 - MATCH_LEN_MIN; = nice_len + 1 - MATCH_LEN_MIN;
break; break;
} }