aboutsummaryrefslogtreecommitdiff
path: root/inflate.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 /inflate.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 'inflate.c')
-rw-r--r--inflate.c27
1 files changed, 14 insertions, 13 deletions
diff --git a/inflate.c b/inflate.c
index 6b0ebbf..6832b8b 100644
--- a/inflate.c
+++ b/inflate.c
@@ -1232,7 +1232,7 @@ int flush;
1232 */ 1232 */
1233 inf_leave: 1233 inf_leave:
1234 RESTORE(); 1234 RESTORE();
1235 if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) 1235 if (state->wsize || (state->mode < BAD && out != strm->avail_out))
1236 if (updatewindow(strm, out)) { 1236 if (updatewindow(strm, out)) {
1237 state->mode = MEM; 1237 state->mode = MEM;
1238 return Z_MEM_ERROR; 1238 return Z_MEM_ERROR;
@@ -1274,6 +1274,9 @@ uInt dictLength;
1274{ 1274{
1275 struct inflate_state FAR *state; 1275 struct inflate_state FAR *state;
1276 unsigned long id; 1276 unsigned long id;
1277 unsigned char *next;
1278 unsigned avail;
1279 int ret;
1277 1280
1278 /* check state */ 1281 /* check state */
1279 if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; 1282 if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
@@ -1289,21 +1292,19 @@ uInt dictLength;
1289 return Z_DATA_ERROR; 1292 return Z_DATA_ERROR;
1290 } 1293 }
1291 1294
1292 /* copy dictionary to window */ 1295 /* copy dictionary to window using updatewindow(), which will amend the
1293 if (updatewindow(strm, strm->avail_out)) { 1296 existing dictionary if appropriate */
1297 next = strm->next_out;
1298 avail = strm->avail_out;
1299 strm->next_out = (Bytef *)dictionary + dictLength;
1300 strm->avail_out = 0;
1301 ret = updatewindow(strm, dictLength);
1302 strm->avail_out = avail;
1303 strm->next_out = next;
1304 if (ret) {
1294 state->mode = MEM; 1305 state->mode = MEM;
1295 return Z_MEM_ERROR; 1306 return Z_MEM_ERROR;
1296 } 1307 }
1297 if (dictLength > state->wsize) {
1298 zmemcpy(state->window, dictionary + dictLength - state->wsize,
1299 state->wsize);
1300 state->whave = state->wsize;
1301 }
1302 else {
1303 zmemcpy(state->window + state->wsize - dictLength, dictionary,
1304 dictLength);
1305 state->whave = dictLength;
1306 }
1307 state->havedict = 1; 1308 state->havedict = 1;
1308 Tracev((stderr, "inflate: dictionary set\n")); 1309 Tracev((stderr, "inflate: dictionary set\n"));
1309 return Z_OK; 1310 return Z_OK;