]> git.lizzy.rs Git - zlib.git/commitdiff
Enable dictionary setting in middle of stream, and keeping the dictionary.
authorMark Adler <madler@alumni.caltech.edu>
Thu, 8 Dec 2011 07:57:37 +0000 (23:57 -0800)
committerMark Adler <madler@alumni.caltech.edu>
Thu, 8 Dec 2011 08:13:52 +0000 (00:13 -0800)
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.

12 files changed:
as400/bndsrc
as400/zlib.inc
contrib/vstudio/vc10/zlibvc.def
contrib/vstudio/vc9/zlibvc.def
deflate.c
inflate.c
win32/zlib.def
zconf.h
zconf.h.cmakein
zconf.h.in
zlib.h
zlib.map

index 036cd63ab3231bf5dcbeb9634b746ace45a023cb..3e26283debdf07ef837f1f3ec48bbf4ec70d48c7 100644 (file)
@@ -33,6 +33,7 @@ STRPGMEXP PGMLVL(*CURRENT) SIGNATURE('ZLIB')
   EXPORT SYMBOL("deflateSetDictionary")
   EXPORT SYMBOL("deflateCopy")
   EXPORT SYMBOL("deflateReset")
+  EXPORT SYMBOL("deflateResetKeep")
   EXPORT SYMBOL("deflateParams")
   EXPORT SYMBOL("deflatePending")
   EXPORT SYMBOL("deflatePrime")
index 976dca2a65f34521957a26d1d121f7caf6e01a0c..f0915c8206e997b90e798f2d209666a0c13ed814 100644 (file)
       *
      D inflateResetKeep...
      D                 PR            10I 0 extproc('inflateResetKeep')          End and init. stream
+     D  strm                               like(z_stream)                       Expansion stream
+      *
+     D deflateResetKeep...
+     D                 PR            10I 0 extproc('deflateResetKeep')          End and init. stream
      D  strm                               like(z_stream)                       Expansion stream
       *
      D gzflags         PR            10U 0 extproc('gzflags')
index d6ab1c1b0243349225115fb14f77b9397e22f1a2..5521885454a1b9a05abe6e2e3852a18075374d58 100644 (file)
@@ -133,3 +133,4 @@ EXPORTS
         gzgetc_                                 @30\r
         gzflags                                 @162\r
         inflateResetKeep                        @163\r
+       deflateResetKeep                        @164
index d6ab1c1b0243349225115fb14f77b9397e22f1a2..5521885454a1b9a05abe6e2e3852a18075374d58 100644 (file)
@@ -133,3 +133,4 @@ EXPORTS
         gzgetc_                                 @30\r
         gzflags                                 @162\r
         inflateResetKeep                        @163\r
+       deflateResetKeep                        @164
index 4b8e91bb9017c9e6ce8f08abf16bd8572110da52..096207d6c3dc5e5e712d4d1505c07b5da1e45983 100644 (file)
--- a/deflate.c
+++ b/deflate.c
@@ -323,43 +323,68 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
     uInt  dictLength;
 {
     deflate_state *s;
-    uInt length = dictLength;
-    uInt n;
-    IPos hash_head = 0;
+    uInt str, n;
+    int wrap;
+    unsigned avail;
+    unsigned char *next;
 
-    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
-        strm->state->wrap == 2 ||
-        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
         return Z_STREAM_ERROR;
-
     s = strm->state;
-    if (s->wrap)
-        strm->adler = adler32(strm->adler, dictionary, dictLength);
+    wrap = s->wrap;
+    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+        return Z_STREAM_ERROR;
 
-    if (length < MIN_MATCH) return Z_OK;
-    if (length > s->w_size) {
-        length = s->w_size;
-        dictionary += dictLength - length; /* use the tail of the dictionary */
+    /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+    if (wrap == 1)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */
+
+    /* if dictionary would fill window, just replace the history */
+    if (dictLength >= s->w_size) {
+        if (wrap == 0) {            /* already empty otherwise */
+            CLEAR_HASH(s);
+            s->strstart = 0;
+            s->block_start = 0L;
+        }
+        dictionary += dictLength - s->w_size;  /* use the tail */
+        dictLength = s->w_size;
     }
-    zmemcpy(s->window, dictionary, length);
-    s->strstart = length;
-    s->block_start = (long)length;
 
-    /* Insert all strings in the hash table (except for the last two bytes).
-     * s->lookahead stays null, so s->ins_h will be recomputed at the next
-     * call of fill_window.
-     */
-    s->ins_h = s->window[0];
-    UPDATE_HASH(s, s->ins_h, s->window[1]);
-    for (n = 0; n <= length - MIN_MATCH; n++) {
-        INSERT_STRING(s, n, hash_head);
+    /* insert dictionary into window and hash */
+    avail = strm->avail_in;
+    next = strm->next_in;
+    strm->avail_in = dictLength;
+    strm->next_in = (Bytef *)dictionary;
+    fill_window(s);
+    while (s->lookahead >= MIN_MATCH) {
+        str = s->strstart;
+        n = s->lookahead - (MIN_MATCH-1);
+        do {
+            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++;
+        } while (--n);
+        s->strstart = str;
+        s->lookahead = MIN_MATCH-1;
+        fill_window(s);
     }
-    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    s->strstart += s->lookahead;
+    s->block_start = (long)s->strstart;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    strm->next_in = next;
+    strm->avail_in = avail;
+    s->wrap = wrap;
     return Z_OK;
 }
 
 /* ========================================================================= */
-int ZEXPORT deflateReset (strm)
+int ZEXPORT deflateResetKeep (strm)
     z_streamp strm;
 {
     deflate_state *s;
@@ -389,11 +414,22 @@ int ZEXPORT deflateReset (strm)
     s->last_flush = Z_NO_FLUSH;
 
     _tr_init(s);
-    lm_init(s);
 
     return Z_OK;
 }
 
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    int ret;
+
+    ret = deflateResetKeep(strm);
+    if (ret == Z_OK)
+        lm_init(strm->state);
+    return ret;
+}
+
 /* ========================================================================= */
 int ZEXPORT deflateSetHeader (strm, head)
     z_streamp strm;
index 6b0ebbfbcd9434b447d970a989b7c599a553ca68..6832b8b746e6e43e2a69a6f0229618955646cdf3 100644 (file)
--- a/inflate.c
+++ b/inflate.c
@@ -1232,7 +1232,7 @@ int flush;
      */
   inf_leave:
     RESTORE();
-    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+    if (state->wsize || (state->mode < BAD && out != strm->avail_out))
         if (updatewindow(strm, out)) {
             state->mode = MEM;
             return Z_MEM_ERROR;
@@ -1274,6 +1274,9 @@ uInt dictLength;
 {
     struct inflate_state FAR *state;
     unsigned long id;
+    unsigned char *next;
+    unsigned avail;
+    int ret;
 
     /* check state */
     if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
@@ -1289,21 +1292,19 @@ uInt dictLength;
             return Z_DATA_ERROR;
     }
 
-    /* copy dictionary to window */
-    if (updatewindow(strm, strm->avail_out)) {
+    /* copy dictionary to window using updatewindow(), which will amend the
+       existing dictionary if appropriate */
+    next = strm->next_out;
+    avail = strm->avail_out;
+    strm->next_out = (Bytef *)dictionary + dictLength;
+    strm->avail_out = 0;
+    ret = updatewindow(strm, dictLength);
+    strm->avail_out = avail;
+    strm->next_out = next;
+    if (ret) {
         state->mode = MEM;
         return Z_MEM_ERROR;
     }
-    if (dictLength > state->wsize) {
-        zmemcpy(state->window, dictionary + dictLength - state->wsize,
-                state->wsize);
-        state->whave = state->wsize;
-    }
-    else {
-        zmemcpy(state->window + state->wsize - dictLength, dictionary,
-                dictLength);
-        state->whave = dictLength;
-    }
     state->havedict = 1;
     Tracev((stderr, "inflate:   dictionary set\n"));
     return Z_OK;
index c420d8b9117fdd49d637c522ec498e4fbeaced89..21bff1f8a8d1b3ab239b5501447c58e85b01e2b8 100644 (file)
@@ -78,5 +78,6 @@ EXPORTS
     get_crc_table
     inflateUndermine
     inflateResetKeep
+    deflateResetKeep
     gzgetc_
     gzflags
diff --git a/zconf.h b/zconf.h
index 84ffb32ba16b559f8338265bf9c13039c80d1f92..51c80ac144306f547ae7d10a02f9dc41d67572a0 100644 (file)
--- a/zconf.h
+++ b/zconf.h
@@ -46,6 +46,7 @@
 #  define deflatePending        z_deflatePending
 #  define deflatePrime          z_deflatePrime
 #  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
 #  define deflateSetDictionary  z_deflateSetDictionary
 #  define deflateSetHeader      z_deflateSetHeader
 #  define deflateTune           z_deflateTune
index b2d78b3a70a51de8f3d044c85059c5cb228d4526..3ea5531d5573d00511c4829fd76839c016ca3b00 100644 (file)
@@ -48,6 +48,7 @@
 #  define deflatePending        z_deflatePending
 #  define deflatePrime          z_deflatePrime
 #  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
 #  define deflateSetDictionary  z_deflateSetDictionary
 #  define deflateSetHeader      z_deflateSetHeader
 #  define deflateTune           z_deflateTune
index 84ffb32ba16b559f8338265bf9c13039c80d1f92..51c80ac144306f547ae7d10a02f9dc41d67572a0 100644 (file)
@@ -46,6 +46,7 @@
 #  define deflatePending        z_deflatePending
 #  define deflatePrime          z_deflatePrime
 #  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
 #  define deflateSetDictionary  z_deflateSetDictionary
 #  define deflateSetHeader      z_deflateSetHeader
 #  define deflateTune           z_deflateTune
diff --git a/zlib.h b/zlib.h
index 3121b0a7381e68e6d90e8f0bd11a22ef9d44ae76..3669f2e27cced6657f4f153141ca99ef46d3ce55 100644 (file)
--- a/zlib.h
+++ b/zlib.h
@@ -581,10 +581,15 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
                                              uInt  dictLength));
 /*
      Initializes the compression dictionary from the given byte sequence
-   without producing any compressed output.  This function must be called
-   immediately after deflateInit, deflateInit2 or deflateReset, before any call
-   of deflate.  The compressor and decompressor must use exactly the same
-   dictionary (see inflateSetDictionary).
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
 
      The dictionary should consist of strings (byte sequences) that are likely
    to be encountered later in the data to be compressed, with the most commonly
@@ -611,8 +616,8 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
      deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
    parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
    inconsistent (for example if deflate has already been called for this stream
-   or if the compression method is bsort).  deflateSetDictionary does not
-   perform any compression: this will be done by deflate().
+   or if not at a block boundary for raw deflate).  deflateSetDictionary does
+   not perform any compression: this will be done by deflate().
 */
 
 ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
@@ -810,10 +815,11 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
    if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
    can be determined from the adler32 value returned by that call of inflate.
    The compressor and decompressor must use exactly the same dictionary (see
-   deflateSetDictionary).  For raw inflate, this function can be called
-   immediately after inflateInit2() or inflateReset() and before any call of
-   inflate() to set the dictionary.  The application must insure that the
-   dictionary that was used for compression is provided.
+   deflateSetDictionary).  For raw inflate, this function can be called at any
+   time to set the dictionary.  If the provided dictionary is smaller than the
+   window and there is already data in the window, then the provided dictionary
+   will amend what's there.  The application must insure that the dictionary
+   that was used for compression is provided.
 
      inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
    parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
@@ -1694,6 +1700,7 @@ ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
 ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
 ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
 ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
 #ifndef Z_SOLO
   ZEXTERN unsigned long  ZEXPORT gzflags          OF((void));
 #endif
index dd27591bb8402da861413414f8205a4b86be531e..80c4774ffa294b6bb8ce964096c701aeb4b9fe46 100644 (file)
--- a/zlib.map
+++ b/zlib.map
@@ -76,3 +76,7 @@ ZLIB_1.2.5.2 {
     gzgetc_;
     inflateResetKeep;
 } ZLIB_1.2.5.1;
+
+ZLIB_1.2.5.3 {
+    deflateResetKeep;
+} ZLIB_1.2.5.2;