LZMA2 decoder cleanups. Make it require new LZMA properties

also in the first LZMA chunk after a dictionary reset in
uncompressed chunk.
This commit is contained in:
Lasse Collin 2008-12-01 22:50:28 +02:00
parent 656ec87882
commit cd70801520
1 changed files with 41 additions and 54 deletions

View File

@ -70,76 +70,63 @@ lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict,
// at least one byte of input. // at least one byte of input.
while (*in_pos < in_size || coder->sequence == SEQ_LZMA) while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
switch (coder->sequence) { switch (coder->sequence) {
case SEQ_CONTROL: case SEQ_CONTROL: {
if (in[*in_pos] & 0x80) { const uint32_t control = in[*in_pos];
// Get the highest five bits of uncompressed size. ++*in_pos;
coder->uncompressed_size
= (uint32_t)(in[*in_pos] & 0x1F) << 16; // Dictionary reset implies that next LZMA chunk has to set
// new properties.
if (control >= 0xE0 || control == 1) {
dict_reset(dict);
coder->need_dictionary_reset = false;
coder->need_properties = true;
} else if (coder->need_dictionary_reset) {
return LZMA_DATA_ERROR;
}
if (control >= 0x80) {
// LZMA chunk. The highest five bits of the
// uncompressed size are taken from the control byte.
coder->uncompressed_size = (control & 0x1F) << 16;
coder->sequence = SEQ_UNCOMPRESSED_1; coder->sequence = SEQ_UNCOMPRESSED_1;
// See if we need to reset dictionary or state. // See if there are new properties or if we need to
switch ((in[(*in_pos)++] >> 5) & 3) { // reset the state.
case 3: if (control >= 0xC0) {
dict_reset(dict); // When there are new properties, state reset
coder->need_dictionary_reset = false; // is done at SEQ_PROPERTIES.
// Fall through
case 2:
if (coder->need_dictionary_reset)
return LZMA_DATA_ERROR;
coder->need_properties = false; coder->need_properties = false;
coder->next_sequence = SEQ_PROPERTIES; coder->next_sequence = SEQ_PROPERTIES;
break;
case 1: } else if (coder->need_properties) {
if (coder->need_properties) return LZMA_DATA_ERROR;
return LZMA_DATA_ERROR;
coder->lzma.reset(coder->lzma.coder,
&coder->options);
} else {
coder->next_sequence = SEQ_LZMA; coder->next_sequence = SEQ_LZMA;
break;
case 0: // If only state reset is wanted with old
if (coder->need_properties) // properties, do the resetting here for
return LZMA_DATA_ERROR; // simplicity.
if (control >= 0xA0)
coder->next_sequence = SEQ_LZMA; coder->lzma.reset(coder->lzma.coder,
break; &coder->options);
} }
} else { } else {
switch (in[(*in_pos)++]) { // End marker
case 0: if (control == 0x00)
// End of payload marker
return LZMA_STREAM_END; return LZMA_STREAM_END;
case 1: // Invalid control values
// Dictionary reset if (control > 2)
dict_reset(dict);
coder->need_dictionary_reset = false;
// Fall through
case 2:
if (coder->need_dictionary_reset)
return LZMA_DATA_ERROR;
// Uncompressed chunk; we need to read total
// size first.
coder->sequence = SEQ_COMPRESSED_0;
coder->next_sequence = SEQ_COPY;
break;
default:
return LZMA_DATA_ERROR; return LZMA_DATA_ERROR;
}
// It's uncompressed chunk
coder->sequence = SEQ_COMPRESSED_0;
coder->next_sequence = SEQ_COPY;
} }
break; break;
}
case SEQ_UNCOMPRESSED_1: case SEQ_UNCOMPRESSED_1:
coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8; coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;