aboutsummaryrefslogtreecommitdiff
path: root/deflate.c
diff options
context:
space:
mode:
authorMark Adler <madler@alumni.caltech.edu>2011-12-07 23:57:37 -0800
committerMark Adler <madler@alumni.caltech.edu>2011-12-08 00:13:52 -0800
commitafe7cf78d51b819dcdc5b0f4cb85a25a52a9fcd0 (patch)
tree24c9db96071504cd7beb1d1800dbb265c736070f /deflate.c
parentfbac04f666339eef3678e4eb81b25ae69bfcbd81 (diff)
downloadzlib-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.c90
1 files changed, 63 insertions, 27 deletions
diff --git a/deflate.c b/deflate.c
index 4b8e91b..096207d 100644
--- a/deflate.c
+++ b/deflate.c
@@ -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/* ========================================================================= */
362int ZEXPORT deflateReset (strm) 387int 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/* ========================================================================= */
422int 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/* ========================================================================= */
398int ZEXPORT deflateSetHeader (strm, head) 434int ZEXPORT deflateSetHeader (strm, head)
399 z_streamp strm; 435 z_streamp strm;
400 gz_headerp head; 436 gz_headerp head;