Insert the first two strings in the hash table after a flush.

This allows deflate to generate the same output when continuing after
a Z_SYNC_FLUSH vs. using deflateSetDictionary() after a Z_FULL_FLUSH
or a deflateReset().  It also slightly improves compression when
flushing by providing two more strings to possibly match at the start
of the new block.
This commit is contained in:
Mark Adler 2012-01-13 23:54:40 -06:00
parent 0b828b4aa6
commit 4f5779a8e7
2 changed files with 22 additions and 3 deletions

View File

@ -349,6 +349,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
CLEAR_HASH(s); CLEAR_HASH(s);
s->strstart = 0; s->strstart = 0;
s->block_start = 0L; s->block_start = 0L;
s->insert = 0;
} }
dictionary += dictLength - s->w_size; /* use the tail */ dictionary += dictLength - s->w_size; /* use the tail */
dictLength = s->w_size; dictLength = s->w_size;
@ -377,6 +378,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
} }
s->strstart += s->lookahead; s->strstart += s->lookahead;
s->block_start = (long)s->strstart; s->block_start = (long)s->strstart;
s->insert = s->lookahead;
s->lookahead = 0; s->lookahead = 0;
s->match_length = s->prev_length = MIN_MATCH-1; s->match_length = s->prev_length = MIN_MATCH-1;
s->match_available = 0; s->match_available = 0;
@ -929,6 +931,7 @@ int ZEXPORT deflate (strm, flush)
if (s->lookahead == 0) { if (s->lookahead == 0) {
s->strstart = 0; s->strstart = 0;
s->block_start = 0L; s->block_start = 0L;
s->insert = 0;
} }
} }
} }
@ -1115,6 +1118,7 @@ local void lm_init (s)
s->strstart = 0; s->strstart = 0;
s->block_start = 0L; s->block_start = 0L;
s->lookahead = 0; s->lookahead = 0;
s->insert = 0;
s->match_length = s->prev_length = MIN_MATCH-1; s->match_length = s->prev_length = MIN_MATCH-1;
s->match_available = 0; s->match_available = 0;
s->ins_h = 0; s->ins_h = 0;
@ -1462,12 +1466,24 @@ local void fill_window(s)
s->lookahead += n; s->lookahead += n;
/* Initialize the hash value now that we have some input: */ /* Initialize the hash value now that we have some input: */
if (s->lookahead >= MIN_MATCH) { if (s->lookahead + s->insert >= MIN_MATCH) {
s->ins_h = s->window[s->strstart]; uInt str = s->strstart - s->insert;
UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); s->ins_h = s->window[str];
UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
#if MIN_MATCH != 3 #if MIN_MATCH != 3
Call UPDATE_HASH() MIN_MATCH-3 more times Call UPDATE_HASH() MIN_MATCH-3 more times
#endif #endif
while (s->insert) {
UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
#ifndef FASTEST
s->prev[str & s->w_mask] = s->head[s->ins_h];
#endif
s->head[s->ins_h] = (Pos)str;
str++;
s->insert--;
if (s->lookahead + s->insert < MIN_MATCH)
break;
}
} }
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
* but this is not important since only literal bytes will be emitted. * but this is not important since only literal bytes will be emitted.
@ -1692,6 +1708,7 @@ local block_state deflate_fast(s, flush)
} }
if (bflush) FLUSH_BLOCK(s, 0); if (bflush) FLUSH_BLOCK(s, 0);
} }
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
if (flush == Z_FINISH) { if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1); FLUSH_BLOCK(s, 1);
return finish_done; return finish_done;
@ -1822,6 +1839,7 @@ local block_state deflate_slow(s, flush)
_tr_tally_lit(s, s->window[s->strstart-1], bflush); _tr_tally_lit(s, s->window[s->strstart-1], bflush);
s->match_available = 0; s->match_available = 0;
} }
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
if (flush == Z_FINISH) { if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1); FLUSH_BLOCK(s, 1);
return finish_done; return finish_done;

View File

@ -247,6 +247,7 @@ typedef struct internal_state {
ulg opt_len; /* bit length of current block with optimal trees */ ulg opt_len; /* bit length of current block with optimal trees */
ulg static_len; /* bit length of current block with static trees */ ulg static_len; /* bit length of current block with static trees */
uInt matches; /* number of string matches in current block */ uInt matches; /* number of string matches in current block */
uInt insert; /* bytes at end of window left to insert */
#ifdef DEBUG #ifdef DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg compressed_len; /* total bit length of compressed file mod 2^32 */