3 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #include <wsutil/ws_printf.h> /* ws_debug_printf */
42 * Uncompresses a zlib compressed packet inside a message of tvb at offset with
43 * length comprlen. Returns an uncompressed tvbuffer if uncompression
44 * succeeded or NULL if uncompression failed.
46 #define TVB_Z_MIN_BUFSIZ 32768
47 #define TVB_Z_MAX_BUFSIZ 1048576 * 10
48 /* #define TVB_Z_DEBUG 1 */
52 tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen)
57 guint8 *uncompr = NULL;
58 tvbuff_t *uncompr_tvb = NULL;
62 gint wbits = MAX_WBITS;
66 guint inflate_passes = 0;
67 guint bytes_in = tvb_captured_length_remaining(tvb, offset);
74 compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen);
80 * Assume that the uncompressed data is at least twice as big as
81 * the compressed size.
83 bufsiz = tvb_captured_length_remaining(tvb, offset) * 2;
84 bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ);
87 ws_debug_printf("bufsiz: %u bytes\n", bufsiz);
92 strm = g_new0(z_stream, 1);
94 strm->avail_in = comprlen;
96 strmbuf = (Bytef *)g_malloc0(bufsiz);
97 strm->next_out = strmbuf;
98 strm->avail_out = bufsiz;
100 err = inflateInit2(strm, wbits);
105 wmem_free(NULL, compr);
111 memset(strmbuf, '\0', bufsiz);
112 strm->next_out = strmbuf;
113 strm->avail_out = bufsiz;
115 err = inflate(strm, Z_SYNC_FLUSH);
117 if (err == Z_OK || err == Z_STREAM_END) {
118 guint bytes_pass = bufsiz - strm->avail_out;
124 if (uncompr == NULL) {
126 * This is ugly workaround for bug #6480
127 * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480)
129 * g_memdup(..., 0) returns NULL (g_malloc(0) also)
130 * when uncompr is NULL logic below doesn't create tvb
131 * which is later interpreted as decompression failed.
133 uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ?
134 g_memdup(strmbuf, bytes_pass) :
137 guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass);
139 memcpy(new_data, uncompr, bytes_out);
140 memcpy(new_data + bytes_out, strmbuf, bytes_pass);
146 bytes_out += bytes_pass;
148 if (err == Z_STREAM_END) {
154 } else if (err == Z_BUF_ERROR) {
156 * It's possible that not enough frames were captured
157 * to decompress this fully, so return what we've done
164 if (uncompr != NULL) {
167 wmem_free(NULL, compr);
171 } else if (err == Z_DATA_ERROR && inits_done == 1
172 && uncompr == NULL && comprlen >= 2 &&
173 (*compr == 0x1f) && (*(compr + 1) == 0x8b)) {
175 * inflate() is supposed to handle both gzip and deflate
176 * streams automatically, but in reality it doesn't
177 * seem to handle either (at least not within the
178 * context of an HTTP response.) We have to try
179 * several tweaks, depending on the type of data and
180 * version of the library installed.
184 * Gzip file format. Skip past the header, since the
185 * fix to make it work (setting windowBits to 31)
186 * doesn't work with all versions of the library.
188 Bytef *c = compr + 2;
191 /* we read two bytes already (0x1f, 0x8b) and
192 need at least Z_DEFLATED, 1 byte flags, 4
193 bytes MTIME, 1 byte XFL, 1 byte OS */
194 if (comprlen < 10 || *c != Z_DEFLATED) {
197 wmem_free(NULL, compr);
206 /* Skip past the MTIME (4 bytes),
207 XFL, and OS fields (1 byte each). */
210 if (flags & (1 << 2)) {
211 /* An Extra field is present. It
212 consists of 2 bytes xsize and xsize
214 Read byte-by-byte (least significant
215 byte first) to make sure we abort
216 cleanly when the xsize is truncated
217 after the first byte. */
220 if (c-compr < comprlen) {
224 if (c-compr < comprlen) {
232 if (flags & (1 << 3)) {
233 /* A null terminated filename */
235 while ((c - compr) < comprlen && *c != '\0') {
242 if (flags & (1 << 4)) {
243 /* A null terminated comment */
245 while ((c - compr) < comprlen && *c != '\0') {
253 if (c - compr > comprlen) {
256 wmem_free(NULL, compr);
260 /* Drop gzip header */
261 comprlen -= (int) (c - compr);
265 strm->next_in = next;
266 strm->avail_in = comprlen;
269 inflateInit2(strm, wbits);
271 } else if (err == Z_DATA_ERROR && uncompr == NULL &&
275 * Re-init the stream with a negative
276 * MAX_WBITS. This is necessary due to
277 * some servers (Apache) not sending
278 * the deflate header with the
279 * content-encoded response.
285 strm->next_in = next;
286 strm->avail_in = comprlen;
289 memset(strmbuf, '\0', bufsiz);
290 strm->next_out = strmbuf;
291 strm->avail_out = bufsiz;
293 err = inflateInit2(strm, wbits);
300 wmem_free(NULL, compr);
310 if (uncompr == NULL) {
311 wmem_free(NULL, compr);
320 ws_debug_printf("inflate() total passes: %u\n", inflate_passes);
321 ws_debug_printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out);
324 if (uncompr != NULL) {
325 uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out, bytes_out);
326 tvb_set_free_cb(uncompr_tvb, g_free);
328 wmem_free(NULL, compr);
333 tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_)
340 tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
342 tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
344 tvb_set_child_real_data_tvbuff (parent, new_tvb);
349 * Editor modelines - http://www.wireshark.org/tools/modelines.html
354 * indent-tabs-mode: t
357 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
358 * :indentSize=8:tabSize=8:noTabs=false: