Add "tvb_get_ntoh64()" and "tvb_get_letoh64()" routines to fetch 64-bit
[obnox/wireshark/wip.git] / epan / tvbuff.c
index 443287342ad1df51fe6382f9a67246ad90bc3d8d..eee139ff5493328cc25e2a51996949d3b56c89b1 100644 (file)
@@ -9,7 +9,7 @@
  *             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. */
@@ -183,15 +130,6 @@ tvb_new(tvbuff_type type)
        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)
 {
@@ -205,7 +143,10 @@ 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;
 
@@ -230,8 +171,12 @@ tvb_free(tvbuff_t* tvb)
                                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;
                }
@@ -316,7 +261,7 @@ tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported
                THROW(ReportedBoundsError);
        }
 
-       tvb->real_data          = (gpointer) data;
+       tvb->real_data          = data;
        tvb->length             = length;
        tvb->reported_length    = reported_length;
        tvb->initialized        = TRUE;
@@ -325,11 +270,18 @@ tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported
 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);
 
@@ -339,7 +291,8 @@ tvb_new_real_data(const guint8* data, guint length, gint 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;
 }
@@ -404,6 +357,10 @@ compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
 
        /* Compute the length */
        if (length < -1) {
+               if (exception) {
+                       /* XXX - ReportedBoundsError? */
+                       *exception = BoundsError;
+               }
                return FALSE;
        }
        else if (length == -1) {
@@ -477,10 +434,6 @@ check_offset_length(tvbuff_t *tvb, gint offset, gint length,
 {
        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);
@@ -527,11 +480,18 @@ tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
 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);
 
@@ -541,7 +501,8 @@ tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint
         */
        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;
 }
@@ -640,6 +601,17 @@ tvb_ensure_length_remaining(tvbuff_t *tvb, gint offset)
        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;
 }
 
@@ -754,7 +726,7 @@ tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
 }
 
 
-static guint8*
+static const guint8*
 first_real_data_ptr(tvbuff_t *tvb)
 {
        tvbuff_t        *member;
@@ -774,7 +746,7 @@ first_real_data_ptr(tvbuff_t *tvb)
        return NULL;
 }
 
-static int
+int
 offset_from_real_beginning(tvbuff_t *tvb, int counter)
 {
        tvbuff_t        *member;
@@ -794,17 +766,9 @@ offset_from_real_beginning(tvbuff_t *tvb, int counter)
        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;
@@ -831,8 +795,11 @@ composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
        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);
@@ -843,13 +810,21 @@ composite_ensure_contiguous(tvbuff_t *tvb, guint abs_offset, guint abs_length)
        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;
        }
@@ -858,11 +833,11 @@ ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
                        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);
                }
        }
 
@@ -870,6 +845,20 @@ ensure_contiguous(tvbuff_t *tvb, gint offset, gint 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)
 {
@@ -1003,10 +992,9 @@ tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
  * "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)
@@ -1031,7 +1019,7 @@ tvb_get_ptr(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;
@@ -1040,7 +1028,7 @@ tvb_get_guint8(tvbuff_t *tvb, gint offset)
 guint16
 tvb_get_ntohs(tvbuff_t *tvb, gint offset)
 {
-       guint8* ptr;
+       const guint8* ptr;
 
        ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
        return pntohs(ptr);
@@ -1049,7 +1037,7 @@ tvb_get_ntohs(tvbuff_t *tvb, gint offset)
 guint32
 tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
 {
-       guint8* ptr;
+       const guint8* ptr;
 
        ptr = ensure_contiguous(tvb, offset, 3);
        return pntoh24(ptr);
@@ -1058,12 +1046,21 @@ tvb_get_ntoh24(tvbuff_t *tvb, gint offset)
 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.
@@ -1270,7 +1267,7 @@ tvb_get_ntohieee_double(tvbuff_t *tvb, int offset)
 guint16
 tvb_get_letohs(tvbuff_t *tvb, gint offset)
 {
-       guint8* ptr;
+       const guint8* ptr;
 
        ptr = ensure_contiguous(tvb, offset, sizeof(guint16));
        return pletohs(ptr);
@@ -1279,7 +1276,7 @@ tvb_get_letohs(tvbuff_t *tvb, gint offset)
 guint32
 tvb_get_letoh24(tvbuff_t *tvb, gint offset)
 {
-       guint8* ptr;
+       const guint8* ptr;
 
        ptr = ensure_contiguous(tvb, offset, 3);
        return pletoh24(ptr);
@@ -1288,12 +1285,21 @@ tvb_get_letoh24(tvbuff_t *tvb, gint offset)
 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".
@@ -1541,14 +1547,14 @@ tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
  * 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.
@@ -1568,14 +1574,14 @@ tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
  * 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.
@@ -1597,9 +1603,9 @@ tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
 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);
@@ -1652,10 +1658,10 @@ tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
  * 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) {
@@ -1669,12 +1675,81 @@ tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
 
 }
 
+/*
+ * 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
@@ -1696,10 +1771,11 @@ _tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer,
 
        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;
@@ -1779,8 +1855,6 @@ tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
 /* 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)
@@ -1789,10 +1863,6 @@ 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;
@@ -1840,7 +1910,7 @@ tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
        /*
         * 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.
@@ -1969,7 +2039,7 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                         * 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) {
                        /*
@@ -2068,8 +2138,328 @@ tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
        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
+