* the data of a backing tvbuff, or can be a composite of
* other tvbuffs.
*
- * $Id: tvbuff.c,v 1.45 2003/06/04 21:45:49 guy Exp $
+ * $Id$
*
* Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
*
#include <string.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
#include "pint.h"
#include "tvbuff.h"
#include "strutil.h"
-typedef struct {
- /* The backing tvbuff_t */
- tvbuff_t *tvb;
-
- /* The offset/length of 'tvb' to which I'm privy */
- guint offset;
- guint length;
-
-} tvb_backing_t;
-
-typedef struct {
- GSList *tvbs;
-
- /* Used for quick testing to see if this
- * is the tvbuff that a COMPOSITE is
- * interested in. */
- guint *start_offsets;
- guint *end_offsets;
-
-} tvb_comp_t;
-
-struct tvbuff {
- /* Record-keeping */
- tvbuff_type type;
- gboolean initialized;
- guint usage_count;
- tvbuff_t* ds_tvb; /* data source top-level tvbuff */
-
- /* The tvbuffs in which this tvbuff is a member
- * (that is, a backing tvbuff for a TVBUFF_SUBSET
- * or a member for a TVB_COMPOSITE) */
- GSList *used_in;
-
- /* TVBUFF_SUBSET and TVBUFF_COMPOSITE keep track
- * of the other tvbuff's they use */
- union {
- tvb_backing_t subset;
- tvb_comp_t composite;
- } tvbuffs;
-
- /* We're either a TVBUFF_REAL_DATA or a
- * TVBUFF_SUBSET that has a backing buffer that
- * has real_data != NULL, or a TVBUFF_COMPOSITE
- * which has flattened its data due to a call
- * to tvb_get_ptr().
- */
- guint8 *real_data;
-
- /* Length of virtual buffer (and/or real_data). */
- guint length;
-
- /* Reported length. */
- guint reported_length;
-
- /* Offset from beginning of first TVBUFF_REAL. */
- gint raw_offset;
-
- /* Func to call when actually freed */
- tvbuff_free_cb_t free_cb;
-};
+static const guint8*
+ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
+ int *exception);
-static guint8*
+static const guint8*
ensure_contiguous(tvbuff_t *tvb, gint offset, gint length);
/* We dole out tvbuff's from this memchunk. */
return tvb;
}
-/* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
-static void
-tvb_free_void(void *tvb)
-{
- tvb_free((tvbuff_t*)tvb);
-}
-
-
-
void
tvb_free(tvbuff_t* tvb)
{
switch (tvb->type) {
case TVBUFF_REAL_DATA:
if (tvb->free_cb) {
- tvb->free_cb(tvb->real_data);
+ /*
+ * XXX - do this with a union?
+ */
+ tvb->free_cb((gpointer)tvb->real_data);
}
break;
g_free(composite->start_offsets);
if (composite->end_offsets)
g_free(composite->end_offsets);
- if (tvb->real_data)
- g_free(tvb->real_data);
+ if (tvb->real_data) {
+ /*
+ * XXX - do this with a union?
+ */
+ g_free((gpointer)tvb->real_data);
+ }
break;
}
THROW(ReportedBoundsError);
}
- tvb->real_data = (gpointer) data;
+ tvb->real_data = data;
tvb->length = length;
tvb->reported_length = reported_length;
tvb->initialized = TRUE;
tvbuff_t*
tvb_new_real_data(const guint8* data, guint length, gint reported_length)
{
+ static tvbuff_t *last_tvb=NULL;
tvbuff_t *tvb;
tvb = tvb_new(TVBUFF_REAL_DATA);
- CLEANUP_PUSH(tvb_free_void, tvb);
+ if(last_tvb){
+ tvb_free(last_tvb);
+ }
+ /* remember this tvb in case we throw an exception and
+ * lose the pointer to it.
+ */
+ last_tvb=tvb;
tvb_set_real_data(tvb, data, length, reported_length);
*/
tvb->ds_tvb = tvb;
- CLEANUP_POP;
+ /* ok no exception so we dont need to remember it any longer */
+ last_tvb=NULL;
return tvb;
}
/* Compute the length */
if (length < -1) {
+ if (exception) {
+ /* XXX - ReportedBoundsError? */
+ *exception = BoundsError;
+ }
return FALSE;
}
else if (length == -1) {
{
int exception = 0;
- if (length < -1) {
- THROW(BoundsError);
- }
-
if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
g_assert(exception > 0);
THROW(exception);
tvbuff_t*
tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
{
+ static tvbuff_t *last_tvb=NULL;
tvbuff_t *tvb;
tvb = tvb_new(TVBUFF_SUBSET);
- CLEANUP_PUSH(tvb_free_void, tvb);
+ if(last_tvb){
+ tvb_free(last_tvb);
+ }
+ /* remember this tvb in case we throw an exception and
+ * lose the pointer to it.
+ */
+ last_tvb=tvb;
tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
*/
tvb->ds_tvb = backing->ds_tvb;
- CLEANUP_POP;
+ /* ok no exception so we dont need to remember it any longer */
+ last_tvb=NULL;
return tvb;
}
if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, &exception)) {
THROW(exception);
}
+ if (abs_length == 0) {
+ /*
+ * This routine ensures there's at least one byte available.
+ * There aren't any bytes available, so throw the appropriate
+ * exception.
+ */
+ if (abs_offset >= tvb->reported_length)
+ THROW(ReportedBoundsError);
+ else
+ THROW(BoundsError);
+ }
return abs_length;
}
}
-static guint8*
+static const guint8*
first_real_data_ptr(tvbuff_t *tvb)
{
tvbuff_t *member;
return NULL;
}
-static int
+int
offset_from_real_beginning(tvbuff_t *tvb, int counter)
{
tvbuff_t *member;
return 0;
}
-gint
-tvb_raw_offset(tvbuff_t *tvb)
-{
- if (tvb->raw_offset == -1) {
- tvb->raw_offset = offset_from_real_beginning(tvb, 0);
- }
- return tvb->raw_offset;
-}
-
-static guint8*
-composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+static const guint8*
+composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
+ guint abs_length)
{
guint i, num_members;
tvb_comp_t *composite;
if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
abs_length, &member_offset, &member_length, NULL)) {
+ /*
+ * The range is, in fact, contiguous within member_tvb.
+ */
g_assert(!tvb->real_data);
- return ensure_contiguous(member_tvb, member_offset, member_length);
+ return ensure_contiguous_no_exception(member_tvb, member_offset, member_length, NULL);
}
else {
tvb->real_data = tvb_memdup(tvb, 0, -1);
return NULL;
}
-static guint8*
-ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
+static const guint8*
+ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
+ int *exception)
{
guint abs_offset, abs_length;
- check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
+ if (!check_offset_length_no_exception(tvb, offset, length,
+ &abs_offset, &abs_length, exception)) {
+ return NULL;
+ }
+ /*
+ * We know that all the data is present in the tvbuff, so
+ * no exceptions should be thrown.
+ */
if (tvb->real_data) {
return tvb->real_data + abs_offset;
}
case TVBUFF_REAL_DATA:
g_assert_not_reached();
case TVBUFF_SUBSET:
- return ensure_contiguous(tvb->tvbuffs.subset.tvb,
+ return ensure_contiguous_no_exception(tvb->tvbuffs.subset.tvb,
abs_offset - tvb->tvbuffs.subset.offset,
- abs_length);
+ abs_length, NULL);
case TVBUFF_COMPOSITE:
- return composite_ensure_contiguous(tvb, abs_offset, abs_length);
+ return composite_ensure_contiguous_no_exception(tvb, abs_offset, abs_length);
}
}
return NULL;
}
+static const guint8*
+ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
+{
+ int exception;
+ const guint8 *p;
+
+ p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
+ if (p == NULL) {
+ g_assert(exception > 0);
+ THROW(exception);
+ }
+ return p;
+}
+
static const guint8*
guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
{
* "tvb_ensure_bytes_exist()" and then allocates a buffer and copies
* data to it.
*
- * Does anything depend on this routine treating -1 as meaning "to the
- * end of the buffer"? If so, perhaps we need two routines, one that
- * treats -1 as such, and one that checks for -1 and then calls this
- * routine.
+ * "composite_ensure_contiguous_no_exception()" depends on -1 not being
+ * an error; does anything else depend on this routine treating -1 as
+ * meaning "to the end of the buffer"?
*/
guint8*
tvb_memdup(tvbuff_t *tvb, gint offset, gint length)
guint8
tvb_get_guint8(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
return *ptr;
guint16
tvb_get_ntohs(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
return pntohs(ptr);
guint32
tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, 3);
return pntoh24(ptr);
guint32
tvb_get_ntohl(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
return pntohl(ptr);
}
+guint64
+tvb_get_ntoh64(tvbuff_t *tvb, gint offset)
+{
+ const guint8* ptr;
+
+ ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
+ return pntoh64(ptr);
+}
+
/*
* Stuff for IEEE float handling on platforms that don't have IEEE
* format as the native floating-point format.
guint16
tvb_get_letohs(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
return pletohs(ptr);
guint32
tvb_get_letoh24(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, 3);
return pletoh24(ptr);
guint32
tvb_get_letohl(tvbuff_t *tvb, gint offset)
{
- guint8* ptr;
+ const guint8* ptr;
ptr = ensure_contiguous(tvb, offset, sizeof(guint32));
return pletohl(ptr);
}
+guint64
+tvb_get_letoh64(tvbuff_t *tvb, gint offset)
+{
+ const guint8* ptr;
+
+ ptr = ensure_contiguous(tvb, offset, sizeof(guint64));
+ return pletoh64(ptr);
+}
+
/*
* Fetches an IEEE single-precision floating-point number, in
* little-endian form, and returns a "float".
* it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
*/
gint
-tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
+tvb_strneql(tvbuff_t *tvb, gint offset, const gchar *str, gint size)
{
- guint8 *ptr;
+ const guint8 *ptr;
- ptr = ensure_contiguous(tvb, offset, size);
+ ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
if (ptr) {
- int cmp = strncmp(ptr, str, size);
+ int cmp = strncmp((const char *)ptr, str, size);
/*
* Return 0 if equal, -1 otherwise.
* it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
*/
gint
-tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
+tvb_strncaseeql(tvbuff_t *tvb, gint offset, const gchar *str, gint size)
{
- guint8 *ptr;
+ const guint8 *ptr;
- ptr = ensure_contiguous(tvb, offset, size);
+ ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
if (ptr) {
- int cmp = strncasecmp(ptr, str, size);
+ int cmp = strncasecmp((const char *)ptr, str, size);
/*
* Return 0 if equal, -1 otherwise.
gint
tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
{
- guint8 *ptr;
+ const guint8 *ptr;
- ptr = ensure_contiguous(tvb, offset, size);
+ ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
if (ptr) {
int cmp = memcmp(ptr, str, size);
* Format the data in the tvb from offset for length ...
*/
-guint8 *
+gchar *
tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
{
- guint8 *ptr;
+ const guint8 *ptr;
gint len = size;
if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
}
+/*
+ * Like "tvb_format_text()", but for null-padded strings; don't show
+ * the null padding characters as "\000".
+ */
+gchar *
+tvb_format_stringzpad(tvbuff_t *tvb, gint offset, gint size)
+{
+ const guint8 *ptr, *p;
+ gint len = size;
+ gint stringlen;
+
+ if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
+
+ len = tvb_length_remaining(tvb, offset);
+ ptr = ensure_contiguous(tvb, offset, len);
+
+ }
+
+ for (p = ptr, stringlen = 0; stringlen < len && *p != '\0'; p++, stringlen++)
+ ;
+ return format_text(ptr, stringlen);
+
+}
+
+/*
+ * Given a tvbuff, an offset, and a length, allocate a buffer big enough
+ * to hold a non-null-terminated string of that length at that offset,
+ * plus a trailing '\0', copy the string into it, and return a pointer
+ * to the string.
+ *
+ * Throws an exception if the tvbuff ends before the string does.
+ */
+guint8 *
+tvb_get_string(tvbuff_t *tvb, gint offset, gint length)
+{
+ const guint8 *ptr;
+ guint8 *strbuf;
+
+ ptr = ensure_contiguous(tvb, offset, length);
+ strbuf = g_malloc(length + 1);
+ if (length != 0)
+ memcpy(strbuf, ptr, length);
+ strbuf[length] = '\0';
+ return strbuf;
+}
+
+/*
+ * Given a tvbuff and an offset, with the offset assumed to refer to
+ * a null-terminated string, find the length of that string (and throw
+ * an exception if the tvbuff ends before we find the null), allocate
+ * a buffer big enough to hold the string, copy the string into it,
+ * and return a pointer to the string. Also return the length of the
+ * string (including the terminating null) through a pointer.
+ */
+guint8 *
+tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
+{
+ guint size;
+ guint8 *strptr;
+
+ size = tvb_strsize(tvb, offset);
+ strptr = g_malloc(size);
+ tvb_memcpy(tvb, strptr, offset, size);
+ *lengthp = size;
+ return strptr;
+}
+
/* Looks for a stringz (NUL-terminated string) in tvbuff and copies
* no more than bufsize number of bytes, including terminating NUL, to buffer.
* Returns length of string (not including terminating NUL), or -1 if the string was
* truncated in the buffer due to not having reached the terminating NUL.
* In this way, it acts like snprintf().
*
+ * bufsize MUST be greater than 0.
+ *
* When processing a packet where the remaining number of bytes is less
* than bufsize, an exception is not thrown if the end of the packet
* is reached before the NUL is found. If no NUL is found before reaching
check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
- if (bufsize == 0) {
- *bytes_copied = 0;
- return -1;
- } else if (bufsize == 1) {
+ /* There must at least be room for the terminating NUL. */
+ g_assert(bufsize != 0);
+
+ /* If there's no room for anything else, just return the NUL. */
+ if (bufsize == 1) {
buffer[0] = 0;
*bytes_copied = 1;
return 0;
/* Like tvb_get_nstringz(), but never returns -1. The string is guaranteed to
* have a terminating NUL. If the string was truncated when copied into buffer,
* a NUL is placed at the end of buffer to terminate it.
- *
- * bufsize MUST be greater than 0.
*/
gint
tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
len = _tvb_get_nstringz(tvb, offset, bufsize, buffer, &bytes_copied);
- if (len == 0) {
- THROW(BoundsError);
- }
-
if (len == -1) {
buffer[bufsize - 1] = 0;
return bytes_copied - 1;
/*
* Look either for a CR or an LF.
*/
- eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n");
+ eol_offset = tvb_pbrk_guint8(tvb, offset, len, (guint8 *)"\r\n");
if (eol_offset == -1) {
/*
* No CR or LF - line is presumably continued in next packet.
* Look either for a CR, an LF, or a '"'.
*/
char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
- "\r\n\"");
+ (guint8 *)"\r\n\"");
}
if (char_offset == -1) {
/*
return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
}
+/* Find a needle tvbuff within a haystack tvbuff. */
+gint
+tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset)
+{
+ guint haystack_abs_offset, haystack_abs_length;
+ const guint8 *haystack_data;
+ const guint8 *needle_data;
+ const guint needle_len = needle_tvb->length;
+ const guint8 *location;
+
+ if (haystack_tvb->length < 1 || needle_tvb->length < 1) {
+ return -1;
+ }
+
+ /* Get pointers to the tvbuffs' data. */
+ haystack_data = tvb_get_ptr(haystack_tvb, 0, -1);
+ needle_data = tvb_get_ptr(needle_tvb, 0, -1);
+
+ check_offset_length(haystack_tvb, haystack_offset, -1,
+ &haystack_abs_offset, &haystack_abs_length);
+
+ location = epan_memmem(haystack_data + haystack_abs_offset, haystack_abs_length,
+ needle_data, needle_len);
+
+ if (location) {
+ return location - haystack_data;
+ }
+ else {
+ return -1;
+ }
+
+ return -1;
+}
+
+#ifdef HAVE_LIBZ
+/*
+ * Uncompresses a zlib compressed packet inside a message of tvb at offset with
+ * length comprlen. Returns an uncompressed tvbuffer if uncompression
+ * succeeded or NULL if uncompression failed.
+ */
+#define TVB_Z_MIN_BUFSIZ 32768
+#define TVB_Z_MAX_BUFSIZ 1048576 * 10
+/* #define TVB_Z_DEBUG 1 */
+#undef TVB_Z_DEBUG
+
+tvbuff_t *
+tvb_uncompress(tvbuff_t *tvb, int offset, int comprlen)
+{
+
+
+ gint err = Z_OK;
+ guint bytes_out = 0;
+ guint8 *compr = NULL;
+ guint8 *uncompr = NULL;
+ tvbuff_t *uncompr_tvb = NULL;
+ z_streamp strm = NULL;
+ Bytef *strmbuf = NULL;
+ guint inits_done = 0;
+ gint wbits = MAX_WBITS;
+ guint8 *next = NULL;
+ guint bufsiz = TVB_Z_MIN_BUFSIZ;
+#ifdef TVB_Z_DEBUG
+ guint inflate_passes = 0;
+ guint bytes_in = tvb_length_remaining(tvb, offset);
+#endif
+
+ if (tvb == NULL) {
+ return NULL;
+ }
+
+ strm = g_malloc0(sizeof(z_stream));
+
+ if (strm == NULL) {
+ return NULL;
+ }
+
+ compr = tvb_memdup(tvb, offset, comprlen);
+
+ if (!compr) {
+ return NULL;
+ }
+
+ /*
+ * Assume that the uncompressed data is at least twice as big as
+ * the compressed size.
+ */
+ bufsiz = tvb_length_remaining(tvb, offset) * 2;
+
+ if (bufsiz < TVB_Z_MIN_BUFSIZ) {
+ bufsiz = TVB_Z_MIN_BUFSIZ;
+ } else if (bufsiz > TVB_Z_MAX_BUFSIZ) {
+ bufsiz = TVB_Z_MIN_BUFSIZ;
+ }
+
+#ifdef TVB_Z_DEBUG
+ printf("bufsiz: %u bytes\n", bufsiz);
+#endif
+
+ next = compr;
+
+ strm->next_in = next;
+ strm->avail_in = comprlen;
+
+
+ strmbuf = g_malloc0(bufsiz);
+
+ if(strmbuf == NULL) {
+ g_free(compr);
+ return NULL;
+ }
+
+ strm->next_out = strmbuf;
+ strm->avail_out = bufsiz;
+
+ err = inflateInit2(strm, wbits);
+ inits_done = 1;
+ if (err != Z_OK) {
+ g_free(strm);
+ g_free(compr);
+ g_free(strmbuf);
+ return NULL;
+ }
+
+ while (1) {
+ memset(strmbuf, '\0', bufsiz);
+ strm->next_out = strmbuf;
+ strm->avail_out = bufsiz;
+
+ err = inflate(strm, Z_SYNC_FLUSH);
+
+ if (err == Z_OK || err == Z_STREAM_END) {
+ guint bytes_pass = bufsiz - strm->avail_out;
+
+#ifdef TVB_Z_DEBUG
+ ++inflate_passes;
+#endif
+
+ if (uncompr == NULL) {
+ uncompr = g_memdup(strmbuf, bytes_pass);
+ } else {
+ guint8 *new_data = g_malloc0(bytes_out +
+ bytes_pass);
+
+ if (new_data == NULL) {
+ g_free(strm);
+ g_free(strmbuf);
+ g_free(compr);
+
+ if (uncompr != NULL) {
+ g_free(uncompr);
+ }
+
+ return NULL;
+ }
+
+ g_memmove(new_data, uncompr, bytes_out);
+ g_memmove((new_data + bytes_out), strmbuf,
+ bytes_pass);
+
+ g_free(uncompr);
+ uncompr = new_data;
+ }
+
+ bytes_out += bytes_pass;
+
+ if ( err == Z_STREAM_END) {
+ inflateEnd(strm);
+ g_free(strm);
+ g_free(strmbuf);
+ break;
+ }
+ } else if (err == Z_BUF_ERROR) {
+ /*
+ * It's possible that not enough frames were captured
+ * to decompress this fully, so return what we've done
+ * so far, if any.
+ */
+
+ g_free(strm);
+ g_free(strmbuf);
+
+ if (uncompr != NULL) {
+ break;
+ } else {
+ g_free(compr);
+ return NULL;
+ }
+
+ } else if (err == Z_DATA_ERROR && inits_done == 1
+ && uncompr == NULL && (*compr == 0x1f) &&
+ (*(compr + 1) == 0x8b)) {
+ /*
+ * inflate() is supposed to handle both gzip and deflate
+ * streams automatically, but in reality it doesn't
+ * seem to handle either (at least not within the
+ * context of an HTTP response.) We have to try
+ * several tweaks, depending on the type of data and
+ * version of the library installed.
+ */
+
+ /*
+ * Gzip file format. Skip past the header, since the
+ * fix to make it work (setting windowBits to 31)
+ * doesn't work with all versions of the library.
+ */
+ Bytef *c = compr + 2;
+ Bytef flags = 0;
+
+ if (*c == Z_DEFLATED) {
+ c++;
+ } else {
+ g_free(strm);
+ g_free(compr);
+ g_free(strmbuf);
+ return NULL;
+ }
+
+ flags = *c;
+
+ /* Skip past the MTIME, XFL, and OS fields. */
+ c += 7;
+
+ if (flags & (1 << 2)) {
+ /* An Extra field is present. */
+ gint xsize = (gint)(*c |
+ (*(c + 1) << 8));
+
+ c += xsize;
+ }
+
+ if (flags & (1 << 3)) {
+ /* A null terminated filename */
+
+ while (*c != '\0') {
+ c++;
+ }
+
+ c++;
+ }
+
+ if (flags & (1 << 4)) {
+ /* A null terminated comment */
+
+ while (*c != '\0') {
+ c++;
+ }
+
+ c++;
+ }
+
+
+ inflateReset(strm);
+ next = c;
+ strm->next_in = next;
+ comprlen -= (c - compr);
+
+ err = inflateInit2(strm, wbits);
+ inits_done++;
+ } else if (err == Z_DATA_ERROR && uncompr == NULL &&
+ inits_done <= 3) {
+
+ /*
+ * Re-init the stream with a negative
+ * MAX_WBITS. This is necessary due to
+ * some servers (Apache) not sending
+ * the deflate header with the
+ * content-encoded response.
+ */
+ wbits = -MAX_WBITS;
+
+ inflateReset(strm);
+
+ strm->next_in = next;
+ strm->avail_in = comprlen;
+
+ memset(strmbuf, '\0', bufsiz);
+ strm->next_out = strmbuf;
+ strm->avail_out = bufsiz;
+
+ err = inflateInit2(strm, wbits);
+
+ inits_done++;
+
+ if (err != Z_OK) {
+ g_free(strm);
+ g_free(strmbuf);
+ g_free(compr);
+ g_free(uncompr);
+
+ return NULL;
+ }
+ } else {
+ g_free(strm);
+ g_free(strmbuf);
+ g_free(compr);
+
+ if (uncompr == NULL) {
+ return NULL;
+ }
+
+ break;
+ }
+ }
+
+#ifdef TVB_Z_DEBUG
+ printf("inflate() total passes: %u\n", inflate_passes);
+ printf("bytes in: %u\nbytes out: %u\n\n", bytes_in, bytes_out);
+#endif
+
+ if (uncompr != NULL) {
+ uncompr_tvb = tvb_new_real_data((guint8*) uncompr, bytes_out,
+ bytes_out);
+ tvb_set_free_cb(uncompr_tvb, g_free);
+ }
+ g_free(compr);
+ return uncompr_tvb;
+}
+#else
tvbuff_t *
-tvb_get_ds_tvb(tvbuff_t *tvb)
+tvb_uncompress(tvbuff_t *tvb _U_, int offset _U_, int comprlen _U_)
{
- return tvb->ds_tvb;
+ return NULL;
}
+#endif
+