diff options
author | Mark Adler <madler@alumni.caltech.edu> | 2011-12-07 23:57:37 -0800 |
---|---|---|
committer | Mark Adler <madler@alumni.caltech.edu> | 2011-12-08 00:13:52 -0800 |
commit | afe7cf78d51b819dcdc5b0f4cb85a25a52a9fcd0 (patch) | |
tree | 24c9db96071504cd7beb1d1800dbb265c736070f /deflate.c | |
parent | fbac04f666339eef3678e4eb81b25ae69bfcbd81 (diff) | |
download | zlib-afe7cf78d51b819dcdc5b0f4cb85a25a52a9fcd0.tar.gz zlib-afe7cf78d51b819dcdc5b0f4cb85a25a52a9fcd0.tar.bz2 zlib-afe7cf78d51b819dcdc5b0f4cb85a25a52a9fcd0.zip |
Enable dictionary setting in middle of stream, and keeping the dictionary.
This patch adds the deflateResetKeep() function to retain the sliding
window for the next deflate operation, and fixes an inflateResetKeep()
problem that came from inflate() not updating the window when the
stream completed. This enables constructing and decompressing a series
of concatenated deflate streams where each can depend on the history of
uncompressed data that precedes it.
This generalizes deflateSetDictionary() and inflateSetDictionary() to
permit setting the dictionary in the middle of a stream for raw deflate
and inflate. This in combination with the Keep functions enables a
scheme for updating files block by block with the transmission of
compressed data, where blocks are sent with deflateResetKeep() to
retain history for better compression, and deflateSetDictionary() is
used for blocks already present at the receiver to skip compression but
insert that data in the history, again for better compression. The
corresponding inflate calls are done on the receiver side.
Diffstat (limited to 'deflate.c')
-rw-r--r-- | deflate.c | 90 |
1 files changed, 63 insertions, 27 deletions
@@ -323,43 +323,68 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) | |||
323 | uInt dictLength; | 323 | uInt dictLength; |
324 | { | 324 | { |
325 | deflate_state *s; | 325 | deflate_state *s; |
326 | uInt length = dictLength; | 326 | uInt str, n; |
327 | uInt n; | 327 | int wrap; |
328 | IPos hash_head = 0; | 328 | unsigned avail; |
329 | unsigned char *next; | ||
329 | 330 | ||
330 | if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || | 331 | if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) |
331 | strm->state->wrap == 2 || | ||
332 | (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) | ||
333 | return Z_STREAM_ERROR; | 332 | return Z_STREAM_ERROR; |
334 | |||
335 | s = strm->state; | 333 | s = strm->state; |
336 | if (s->wrap) | 334 | wrap = s->wrap; |
337 | strm->adler = adler32(strm->adler, dictionary, dictLength); | 335 | if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) |
336 | return Z_STREAM_ERROR; | ||
338 | 337 | ||
339 | if (length < MIN_MATCH) return Z_OK; | 338 | /* when using zlib wrappers, compute Adler-32 for provided dictionary */ |
340 | if (length > s->w_size) { | 339 | if (wrap == 1) |
341 | length = s->w_size; | 340 | strm->adler = adler32(strm->adler, dictionary, dictLength); |
342 | dictionary += dictLength - length; /* use the tail of the dictionary */ | 341 | s->wrap = 0; /* avoid computing Adler-32 in read_buf */ |
342 | |||
343 | /* if dictionary would fill window, just replace the history */ | ||
344 | if (dictLength >= s->w_size) { | ||
345 | if (wrap == 0) { /* already empty otherwise */ | ||
346 | CLEAR_HASH(s); | ||
347 | s->strstart = 0; | ||
348 | s->block_start = 0L; | ||
349 | } | ||
350 | dictionary += dictLength - s->w_size; /* use the tail */ | ||
351 | dictLength = s->w_size; | ||
343 | } | 352 | } |
344 | zmemcpy(s->window, dictionary, length); | ||
345 | s->strstart = length; | ||
346 | s->block_start = (long)length; | ||
347 | 353 | ||
348 | /* Insert all strings in the hash table (except for the last two bytes). | 354 | /* insert dictionary into window and hash */ |
349 | * s->lookahead stays null, so s->ins_h will be recomputed at the next | 355 | avail = strm->avail_in; |
350 | * call of fill_window. | 356 | next = strm->next_in; |
351 | */ | 357 | strm->avail_in = dictLength; |
352 | s->ins_h = s->window[0]; | 358 | strm->next_in = (Bytef *)dictionary; |
353 | UPDATE_HASH(s, s->ins_h, s->window[1]); | 359 | fill_window(s); |
354 | for (n = 0; n <= length - MIN_MATCH; n++) { | 360 | while (s->lookahead >= MIN_MATCH) { |
355 | INSERT_STRING(s, n, hash_head); | 361 | str = s->strstart; |
362 | n = s->lookahead - (MIN_MATCH-1); | ||
363 | do { | ||
364 | UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); | ||
365 | #ifndef FASTEST | ||
366 | s->prev[str & s->w_mask] = s->head[s->ins_h]; | ||
367 | #endif | ||
368 | s->head[s->ins_h] = (Pos)str; | ||
369 | str++; | ||
370 | } while (--n); | ||
371 | s->strstart = str; | ||
372 | s->lookahead = MIN_MATCH-1; | ||
373 | fill_window(s); | ||
356 | } | 374 | } |
357 | if (hash_head) hash_head = 0; /* to make compiler happy */ | 375 | s->strstart += s->lookahead; |
376 | s->block_start = (long)s->strstart; | ||
377 | s->lookahead = 0; | ||
378 | s->match_length = s->prev_length = MIN_MATCH-1; | ||
379 | s->match_available = 0; | ||
380 | strm->next_in = next; | ||
381 | strm->avail_in = avail; | ||
382 | s->wrap = wrap; | ||
358 | return Z_OK; | 383 | return Z_OK; |
359 | } | 384 | } |
360 | 385 | ||
361 | /* ========================================================================= */ | 386 | /* ========================================================================= */ |
362 | int ZEXPORT deflateReset (strm) | 387 | int ZEXPORT deflateResetKeep (strm) |
363 | z_streamp strm; | 388 | z_streamp strm; |
364 | { | 389 | { |
365 | deflate_state *s; | 390 | deflate_state *s; |
@@ -389,12 +414,23 @@ int ZEXPORT deflateReset (strm) | |||
389 | s->last_flush = Z_NO_FLUSH; | 414 | s->last_flush = Z_NO_FLUSH; |
390 | 415 | ||
391 | _tr_init(s); | 416 | _tr_init(s); |
392 | lm_init(s); | ||
393 | 417 | ||
394 | return Z_OK; | 418 | return Z_OK; |
395 | } | 419 | } |
396 | 420 | ||
397 | /* ========================================================================= */ | 421 | /* ========================================================================= */ |
422 | int ZEXPORT deflateReset (strm) | ||
423 | z_streamp strm; | ||
424 | { | ||
425 | int ret; | ||
426 | |||
427 | ret = deflateResetKeep(strm); | ||
428 | if (ret == Z_OK) | ||
429 | lm_init(strm->state); | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | /* ========================================================================= */ | ||
398 | int ZEXPORT deflateSetHeader (strm, head) | 434 | int ZEXPORT deflateSetHeader (strm, head) |
399 | z_streamp strm; | 435 | z_streamp strm; |
400 | gz_headerp head; | 436 | gz_headerp head; |