diff options
| author | Simon Tatham <anakin@pobox.com> | 2012-06-01 19:37:14 +0000 |
|---|---|---|
| committer | Simon Tatham <anakin@pobox.com> | 2012-06-01 19:37:14 +0000 |
| commit | ea4654d03324dd4feba49d616cbf13b4d6b808c6 (patch) | |
| tree | ca37d46073194792bb211aaab70ca89282bc3125 | |
| parent | 7c09a2ba4b42aa86785e788a5c72cc1e628d7d9a (diff) | |
| download | halibut-ea4654d03324dd4feba49d616cbf13b4d6b808c6.zip halibut-ea4654d03324dd4feba49d616cbf13b4d6b808c6.tar.gz halibut-ea4654d03324dd4feba49d616cbf13b4d6b808c6.tar.bz2 halibut-ea4654d03324dd4feba49d616cbf13b4d6b808c6.tar.xz | |
Make the Deflate decoder correctly handle the special case of a
dynamic block in which the backward-distances Huffman table contains
no entries at all. (In this situation it's impossible to use the
distance table, and therefore the block must contain nothing but
Huffman-coded literals.)
[originally from svn r9550]
| -rw-r--r-- | deflate.c | 30 | ||||
| -rw-r--r-- | deflate.h | 1 |
2 files changed, 24 insertions, 7 deletions
@@ -2297,14 +2297,25 @@ int deflate_decompress_data(deflate_decompress_ctx *dctx, &error); if (!dctx->currlentable) goto finished; /* error code set up by mktable */ - dctx->currdisttable = mktable(dctx->lengths + dctx->hlit, - dctx->hdist, + if (dctx->hdist == 1 && dctx->lengths[dctx->hlit] == 0) { + /* + * Special case: if the code length list for the + * backward-distance table contains a single zero + * entry, it means this block will never encode a + * backward distance at all (i.e. it's all + * literals). + */ + dctx->currdisttable = NULL; + } else { + dctx->currdisttable = mktable(dctx->lengths + dctx->hlit, + dctx->hdist, #ifdef ANALYSIS - "distance", + "distance", #endif - &error); - if (!dctx->currdisttable) - goto finished; /* error code set up by mktable */ + &error); + if (!dctx->currdisttable) + goto finished; /* error code set up by mktable */ + } freetable(&dctx->lenlentable); dctx->lenlentable = NULL; dctx->state = INBLK; @@ -2374,7 +2385,8 @@ int deflate_decompress_data(deflate_decompress_ctx *dctx, freetable(&dctx->currlentable); dctx->currlentable = NULL; } - if (dctx->currdisttable != dctx->staticdisttable) { + if (dctx->currdisttable && + dctx->currdisttable != dctx->staticdisttable) { freetable(&dctx->currdisttable); dctx->currdisttable = NULL; } @@ -2396,6 +2408,10 @@ int deflate_decompress_data(deflate_decompress_ctx *dctx, dctx->state = GOTLEN; break; case GOTLEN: + if (!dctx->currdisttable) { + error = DEFLATE_ERR_NODISTTABLE; + goto finished; + } code = huflookup(&dctx->bits, &dctx->nbits, dctx->currdisttable); debug(("recv: dist %d\n", code)); if (code == -1) @@ -151,6 +151,7 @@ int deflate_decompress_data(deflate_decompress_ctx *ctx, A(DEFLATE_ERR_SMALL_HUFTABLE, "under-committed Huffman code space"), \ A(DEFLATE_ERR_LARGE_HUFTABLE, "over-committed Huffman code space"), \ A(DEFLATE_ERR_UNCOMP_HDR, "wrongly formatted header in uncompressed block"), \ + A(DEFLATE_ERR_NODISTTABLE, "backward copy encoded in block without distances table"), \ A(DEFLATE_ERR_CHECKSUM, "incorrect data checksum"), \ A(DEFLATE_ERR_INLEN, "incorrect data length"), \ A(DEFLATE_ERR_UNEXPECTED_EOF, "unexpected end of data") |