Fix LZMA_SYNC_FLUSH handling in LZ and LZMA encoders.
That code is now almost completely in LZ coder, where it can be shared with other LZ77-based algorithms in future.
This commit is contained in:
parent
079c4f7fc2
commit
ab5feaf1fc
|
@ -141,7 +141,7 @@ lzma_lz_encoder_reset(lzma_lz_encoder *lz, lzma_allocator *allocator,
|
||||||
const uint8_t *preset_dictionary,
|
const uint8_t *preset_dictionary,
|
||||||
size_t preset_dictionary_size)
|
size_t preset_dictionary_size)
|
||||||
{
|
{
|
||||||
lz->sequence = SEQ_RUN;
|
lz->sequence = SEQ_START;
|
||||||
lz->uncompressed_size = uncompressed_size;
|
lz->uncompressed_size = uncompressed_size;
|
||||||
lz->temp_size = 0;
|
lz->temp_size = 0;
|
||||||
|
|
||||||
|
@ -477,24 +477,42 @@ lzma_lz_encode(lzma_coder *coder, lzma_allocator *allocator,
|
||||||
coder->lz.temp_size = 0;
|
coder->lz.temp_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coder->lz.sequence == SEQ_FLUSH_END) {
|
switch (coder->lz.sequence) {
|
||||||
|
case SEQ_START:
|
||||||
|
assert(coder->lz.read_pos == coder->lz.write_pos);
|
||||||
|
|
||||||
|
// If there is no new input data and LZMA_SYNC_FLUSH is used
|
||||||
|
// immediatelly after previous LZMA_SYNC_FLUSH finished or
|
||||||
|
// at the very beginning of the input stream, we return
|
||||||
|
// LZMA_STREAM_END immediatelly. Writing a flush marker
|
||||||
|
// to the very beginning of the stream or right after previous
|
||||||
|
// flush marker is not allowed by the LZMA stream format.
|
||||||
|
if (*in_pos == in_size && action == LZMA_SYNC_FLUSH)
|
||||||
|
return LZMA_STREAM_END;
|
||||||
|
|
||||||
|
coder->lz.sequence = SEQ_RUN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEQ_FLUSH_END:
|
||||||
// During an earlier call to this function, flushing was
|
// During an earlier call to this function, flushing was
|
||||||
// otherwise finished except some data was left pending
|
// otherwise finished except some data was left pending
|
||||||
// in coder->lz.buffer. Now we have copied all that data
|
// in coder->lz.buffer. Now we have copied all that data
|
||||||
// to the output buffer and can return LZMA_STREAM_END.
|
// to the output buffer and can return LZMA_STREAM_END.
|
||||||
coder->lz.sequence = SEQ_RUN;
|
coder->lz.sequence = SEQ_START;
|
||||||
assert(action == LZMA_SYNC_FLUSH);
|
assert(action == LZMA_SYNC_FLUSH);
|
||||||
return LZMA_STREAM_END;
|
return LZMA_STREAM_END;
|
||||||
}
|
|
||||||
|
|
||||||
if (coder->lz.sequence == SEQ_END) {
|
case SEQ_END:
|
||||||
// This is like the above flushing case, but for finishing
|
// This is like the above flushing case, but for finishing
|
||||||
// the encoding.
|
// the encoding.
|
||||||
//
|
//
|
||||||
// NOTE: action is not necesarily LZMA_FINISH; it can
|
// NOTE: action is not necesarily LZMA_FINISH; it can
|
||||||
// be LZMA_SYNC_FLUSH too in case it is used at the
|
// be LZMA_RUN or LZMA_SYNC_FLUSH too in case it is used
|
||||||
// end of the stream with known Uncompressed Size.
|
// at the end of the stream with known Uncompressed Size.
|
||||||
return action != LZMA_RUN ? LZMA_STREAM_END : LZMA_OK;
|
return action != LZMA_RUN ? LZMA_STREAM_END : LZMA_OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*out_pos < out_size
|
while (*out_pos < out_size
|
||||||
|
@ -511,7 +529,7 @@ lzma_lz_encode(lzma_coder *coder, lzma_allocator *allocator,
|
||||||
assert(action == LZMA_SYNC_FLUSH);
|
assert(action == LZMA_SYNC_FLUSH);
|
||||||
if (coder->lz.temp_size == 0) {
|
if (coder->lz.temp_size == 0) {
|
||||||
// Flushing was finished successfully.
|
// Flushing was finished successfully.
|
||||||
coder->lz.sequence = SEQ_RUN;
|
coder->lz.sequence = SEQ_START;
|
||||||
} else {
|
} else {
|
||||||
// Flushing was otherwise finished,
|
// Flushing was otherwise finished,
|
||||||
// except that some data was left
|
// except that some data was left
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
typedef struct lzma_lz_encoder_s lzma_lz_encoder;
|
typedef struct lzma_lz_encoder_s lzma_lz_encoder;
|
||||||
struct lzma_lz_encoder_s {
|
struct lzma_lz_encoder_s {
|
||||||
enum {
|
enum {
|
||||||
|
SEQ_START,
|
||||||
SEQ_RUN,
|
SEQ_RUN,
|
||||||
SEQ_FLUSH,
|
SEQ_FLUSH,
|
||||||
SEQ_FLUSH_END,
|
SEQ_FLUSH_END,
|
||||||
|
|
|
@ -157,31 +157,8 @@ lzma_lzma_encode(lzma_coder *coder, uint8_t *restrict out,
|
||||||
// Initialize the stream if no data has been encoded yet.
|
// Initialize the stream if no data has been encoded yet.
|
||||||
if (!coder->is_initialized) {
|
if (!coder->is_initialized) {
|
||||||
if (coder->lz.read_pos == coder->lz.read_limit) {
|
if (coder->lz.read_pos == coder->lz.read_limit) {
|
||||||
switch (coder->lz.sequence) {
|
assert(coder->lz.write_pos == coder->lz.read_pos);
|
||||||
case SEQ_RUN:
|
assert(coder->lz.sequence == SEQ_FINISH);
|
||||||
// Cannot initialize, because there is
|
|
||||||
// no input data.
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case SEQ_FLUSH:
|
|
||||||
// Nothing to flush. There cannot be a flush
|
|
||||||
// marker when no data has been processed
|
|
||||||
// yet (file format doesn't allow it, and
|
|
||||||
// it would be just waste of space).
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SEQ_FINISH:
|
|
||||||
// We are encoding an empty file. No need
|
|
||||||
// to initialize the encoder.
|
|
||||||
assert(coder->lz.write_pos == coder->lz.read_pos);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// We never get here.
|
|
||||||
assert(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Do the actual initialization.
|
// Do the actual initialization.
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
|
Loading…
Reference in New Issue