Revert "Change exports from Q.932 to use VALS_WITH_TABLE in the same way as QSIG"
[metze/wireshark/wip.git] / epan / tvbuff_zlib.c
1 /* tvbuff_zlib.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
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.
13  *
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.
18  *
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.
22  */
23
24 #include <config.h>
25
26 #include <glib.h>
27
28 #include <string.h>
29
30 #ifdef HAVE_ZLIB
31 #define ZLIB_CONST
32 #include <zlib.h>
33 #endif
34
35 #include "tvbuff.h"
36 #ifdef TVB_Z_DEBUG
37 #include <wsutil/ws_printf.h> /* ws_debug_printf */
38 #endif
39
40 #ifdef HAVE_ZLIB
41 /*
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.
45  */
46 #define TVB_Z_MIN_BUFSIZ 32768
47 #define TVB_Z_MAX_BUFSIZ 1048576 * 10
48 /* #define TVB_Z_DEBUG 1 */
49 #undef TVB_Z_DEBUG
50
51 tvbuff_t *
52 tvb_uncompress(tvbuff_t *tvb, const int offset, int comprlen)
53 {
54         gint       err;
55         guint      bytes_out      = 0;
56         guint8    *compr;
57         guint8    *uncompr        = NULL;
58         tvbuff_t  *uncompr_tvb    = NULL;
59         z_streamp  strm;
60         Bytef     *strmbuf;
61         guint      inits_done     = 0;
62         gint       wbits          = MAX_WBITS;
63         guint8    *next;
64         guint      bufsiz;
65 #ifdef TVB_Z_DEBUG
66         guint      inflate_passes = 0;
67         guint      bytes_in       = tvb_captured_length_remaining(tvb, offset);
68 #endif
69
70         if (tvb == NULL) {
71                 return NULL;
72         }
73
74         compr = (guint8 *)tvb_memdup(NULL, tvb, offset, comprlen);
75         if (compr == NULL) {
76                 return NULL;
77         }
78
79         /*
80          * Assume that the uncompressed data is at least twice as big as
81          * the compressed size.
82          */
83         bufsiz = tvb_captured_length_remaining(tvb, offset) * 2;
84         bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ);
85
86 #ifdef TVB_Z_DEBUG
87         ws_debug_printf("bufsiz: %u bytes\n", bufsiz);
88 #endif
89
90         next = compr;
91
92         strm            = g_new0(z_stream, 1);
93         strm->next_in   = next;
94         strm->avail_in  = comprlen;
95
96         strmbuf         = (Bytef *)g_malloc0(bufsiz);
97         strm->next_out  = strmbuf;
98         strm->avail_out = bufsiz;
99
100         err = inflateInit2(strm, wbits);
101         inits_done = 1;
102         if (err != Z_OK) {
103                 inflateEnd(strm);
104                 g_free(strm);
105                 wmem_free(NULL, compr);
106                 g_free(strmbuf);
107                 return NULL;
108         }
109
110         while (1) {
111                 memset(strmbuf, '\0', bufsiz);
112                 strm->next_out  = strmbuf;
113                 strm->avail_out = bufsiz;
114
115                 err = inflate(strm, Z_SYNC_FLUSH);
116
117                 if (err == Z_OK || err == Z_STREAM_END) {
118                         guint bytes_pass = bufsiz - strm->avail_out;
119
120 #ifdef TVB_Z_DEBUG
121                         ++inflate_passes;
122 #endif
123
124                         if (uncompr == NULL) {
125                                 /*
126                                  * This is ugly workaround for bug #6480
127                                  * (https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6480)
128                                  *
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.
132                                  */
133                                 uncompr = (guint8 *)((bytes_pass || err != Z_STREAM_END) ?
134                                                 g_memdup(strmbuf, bytes_pass) :
135                                                 g_strdup(""));
136                         } else {
137                                 guint8 *new_data = (guint8 *)g_malloc0(bytes_out + bytes_pass);
138
139                                 memcpy(new_data, uncompr, bytes_out);
140                                 memcpy(new_data + bytes_out, strmbuf, bytes_pass);
141
142                                 g_free(uncompr);
143                                 uncompr = new_data;
144                         }
145
146                         bytes_out += bytes_pass;
147
148                         if (err == Z_STREAM_END) {
149                                 inflateEnd(strm);
150                                 g_free(strm);
151                                 g_free(strmbuf);
152                                 break;
153                         }
154                 } else if (err == Z_BUF_ERROR) {
155                         /*
156                          * It's possible that not enough frames were captured
157                          * to decompress this fully, so return what we've done
158                          * so far, if any.
159                          */
160                         inflateEnd(strm);
161                         g_free(strm);
162                         g_free(strmbuf);
163
164                         if (uncompr != NULL) {
165                                 break;
166                         } else {
167                                 wmem_free(NULL, compr);
168                                 return NULL;
169                         }
170
171                 } else if (err == Z_DATA_ERROR && inits_done == 1
172                         && uncompr == NULL && comprlen >= 2 &&
173                         (*compr  == 0x1f) && (*(compr + 1) == 0x8b)) {
174                         /*
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.
181                          */
182
183                         /*
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.
187                          */
188                         Bytef *c = compr + 2;
189                         Bytef  flags = 0;
190
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) {
195                                 inflateEnd(strm);
196                                 g_free(strm);
197                                 wmem_free(NULL, compr);
198                                 g_free(strmbuf);
199                                 return NULL;
200                         }
201
202                         c++;
203                         flags = *c;
204                         c++;
205
206                         /* Skip past the MTIME (4 bytes),
207                            XFL, and OS fields (1 byte each). */
208                         c += 6;
209
210                         if (flags & (1 << 2)) {
211                                 /* An Extra field is present. It
212                                    consists of 2 bytes xsize and xsize
213                                    bytes of data.
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. */
218                                 guint16 xsize = 0;
219
220                                 if (c-compr < comprlen) {
221                                         xsize += *c;
222                                         c++;
223                                 }
224                                 if (c-compr < comprlen) {
225                                         xsize += *c << 8;
226                                         c++;
227                                 }
228
229                                 c += xsize;
230                         }
231
232                         if (flags & (1 << 3)) {
233                                 /* A null terminated filename */
234
235                                 while ((c - compr) < comprlen && *c != '\0') {
236                                         c++;
237                                 }
238
239                                 c++;
240                         }
241
242                         if (flags & (1 << 4)) {
243                                 /* A null terminated comment */
244
245                                 while ((c - compr) < comprlen && *c != '\0') {
246                                         c++;
247                                 }
248
249                                 c++;
250                         }
251
252
253                         if (c - compr > comprlen) {
254                                 inflateEnd(strm);
255                                 g_free(strm);
256                                 wmem_free(NULL, compr);
257                                 g_free(strmbuf);
258                                 return NULL;
259                         }
260                         /* Drop gzip header */
261                         comprlen -= (int) (c - compr);
262                         next = c;
263
264                         inflateReset(strm);
265                         strm->next_in   = next;
266                         strm->avail_in  = comprlen;
267
268                         inflateEnd(strm);
269                         inflateInit2(strm, wbits);
270                         inits_done++;
271                 } else if (err == Z_DATA_ERROR && uncompr == NULL &&
272                         inits_done <= 3) {
273
274                         /*
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.
280                          */
281                         wbits = -MAX_WBITS;
282
283                         inflateReset(strm);
284
285                         strm->next_in   = next;
286                         strm->avail_in  = comprlen;
287
288                         inflateEnd(strm);
289                         memset(strmbuf, '\0', bufsiz);
290                         strm->next_out  = strmbuf;
291                         strm->avail_out = bufsiz;
292
293                         err = inflateInit2(strm, wbits);
294
295                         inits_done++;
296
297                         if (err != Z_OK) {
298                                 g_free(strm);
299                                 g_free(strmbuf);
300                                 wmem_free(NULL, compr);
301                                 g_free(uncompr);
302
303                                 return NULL;
304                         }
305                 } else {
306                         inflateEnd(strm);
307                         g_free(strm);
308                         g_free(strmbuf);
309
310                         if (uncompr == NULL) {
311                                 wmem_free(NULL, compr);
312                                 return NULL;
313                         }
314
315                         break;
316                 }
317         }
318
319 #ifdef TVB_Z_DEBUG
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);
322 #endif
323
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);
327         }
328         wmem_free(NULL, compr);
329         return uncompr_tvb;
330 }
331 #else
332 tvbuff_t *
333 tvb_uncompress(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_)
334 {
335         return NULL;
336 }
337 #endif
338
339 tvbuff_t *
340 tvb_child_uncompress(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
341 {
342         tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
343         if (new_tvb)
344                 tvb_set_child_real_data_tvbuff (parent, new_tvb);
345         return new_tvb;
346 }
347
348 /*
349  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
350  *
351  * Local variables:
352  * c-basic-offset: 8
353  * tab-width: 8
354  * indent-tabs-mode: t
355  * End:
356  *
357  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
358  * :indentSize=8:tabSize=8:noTabs=false:
359  */