From Jakub Zawadzki via bug #4289: (Fix for) Frame arrival times (pcap)
[obnox/wireshark/wip.git] / epan / tvbuff.c
index 19df4d86bfb74f457dceb152d78898752380c883..be7e32b14ffe2d949b2046709e89410a66a7c209 100644 (file)
@@ -3,21 +3,21 @@
  * Testy, Virtual(-izable) Buffer of guint8*'s
  *
  * "Testy" -- the buffer gets mad when an attempt to access data
- *             beyond the bounds of the buffer. An exception is thrown.
+ *             beyond the bounds of the buffer. An exception is thrown.
  *
  * "Virtual" -- the buffer can have its own data, can use a subset of
- *             the data of a backing tvbuff, or can be a composite of
- *             other tvbuffs.
+ *             the data of a backing tvbuff, or can be a composite of
+ *             other tvbuffs.
  *
- * $Id: tvbuff.c,v 1.51 2003/09/28 21:39:53 guy Exp $
+ * $Id$
  *
  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
  * Code to convert IEEE floating point formats to native floating point
  * derived from code Copyright (c) Ashok Narayanan, 2000
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
 
 #include <string.h>
 
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
 #include "pint.h"
 #include "tvbuff.h"
 #include "strutil.h"
+#include "emem.h"
+#include "proto.h"     /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
 
-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 guint8*
+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);
 
+#if GLIB_CHECK_VERSION(2,10,0)
+#else
 /* We dole out tvbuff's from this memchunk. */
-GMemChunk *tvbuff_mem_chunk = NULL;
+static GMemChunk *tvbuff_mem_chunk = NULL;
+#endif
 
 void
 tvbuff_init(void)
 {
+#if GLIB_CHECK_VERSION(2,10,0)
+#else
        if (!tvbuff_mem_chunk)
                tvbuff_mem_chunk = g_mem_chunk_create(tvbuff_t, 20, G_ALLOC_AND_FREE);
+#endif
 }
 
 void
 tvbuff_cleanup(void)
 {
+#if GLIB_CHECK_VERSION(2,10,0)
+#else
        if (tvbuff_mem_chunk)
                g_mem_chunk_destroy(tvbuff_mem_chunk);
 
        tvbuff_mem_chunk = NULL;
+#endif
 }
 
-
-
-
 static void
 tvb_init(tvbuff_t *tvb, tvbuff_type type)
 {
@@ -170,6 +121,10 @@ tvb_init(tvbuff_t *tvb, tvbuff_type type)
                        composite->start_offsets        = NULL;
                        composite->end_offsets          = NULL;
                        break;
+
+               default:
+                       DISSECTOR_ASSERT_NOT_REACHED();
+                       break;
        }
 }
 
@@ -179,22 +134,26 @@ tvb_new(tvbuff_type type)
 {
        tvbuff_t        *tvb;
 
+#if GLIB_CHECK_VERSION(2,10,0)
+       tvb = g_slice_new(tvbuff_t);
+#else
        tvb = g_chunk_new(tvbuff_t, tvbuff_mem_chunk);
-       g_assert(tvb);
+#endif
 
        tvb_init(tvb, type);
 
        return tvb;
 }
 
-/* We accept a void* instead of a field_info* to satisfy CLEANUP_POP */
-static void
-tvb_free_void(void *tvb)
+static tvbuff_t*
+tvb_new_with_subset(guint subset_tvb_offset, guint subset_tvb_length)
 {
-       tvb_free((tvbuff_t*)tvb);
-}
-
+       tvbuff_t *tvb = tvb_new(TVBUFF_SUBSET);
+       tvb->tvbuffs.subset.offset = subset_tvb_offset;
+       tvb->tvbuffs.subset.length = subset_tvb_length;
 
+       return tvb;
+}
 
 void
 tvb_free(tvbuff_t* tvb)
@@ -209,7 +168,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,12 +192,14 @@ tvb_free(tvbuff_t* tvb)
 
                        g_slist_free(composite->tvbs);
 
-                       if (composite->start_offsets)
-                               g_free(composite->start_offsets);
-                       if (composite->end_offsets)
-                               g_free(composite->end_offsets);
-                       if (tvb->real_data)
-                               g_free(tvb->real_data);
+                       g_free(composite->start_offsets);
+                       g_free(composite->end_offsets);
+                       if (tvb->real_data) {
+                               /*
+                                * XXX - do this with a union?
+                                */
+                               g_free((gpointer)tvb->real_data);
+                       }
 
                        break;
                }
@@ -244,7 +208,11 @@ tvb_free(tvbuff_t* tvb)
                        g_slist_free(tvb->used_in);
                }
 
+#if GLIB_CHECK_VERSION(2,10,0)
+               g_slice_free(tvbuff_t, tvb);
+#else
                g_chunk_free(tvb, tvbuff_mem_chunk);
+#endif
        }
 }
 
@@ -290,7 +258,8 @@ tvb_free_chain(tvbuff_t* tvb)
 void
 tvb_set_free_cb(tvbuff_t* tvb, tvbuff_free_cb_t func)
 {
-       g_assert(tvb->type == TVBUFF_REAL_DATA);
+       DISSECTOR_ASSERT(tvb);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_REAL_DATA);
        tvb->free_cb = func;
 }
 
@@ -304,26 +273,32 @@ add_to_used_in_list(tvbuff_t *tvb, tvbuff_t *used_in)
 void
 tvb_set_child_real_data_tvbuff(tvbuff_t* parent, tvbuff_t* child)
 {
-       g_assert(parent->initialized);
-       g_assert(child->initialized);
-       g_assert(child->type == TVBUFF_REAL_DATA);
+       DISSECTOR_ASSERT(parent && child);
+       DISSECTOR_ASSERT(parent->initialized);
+       DISSECTOR_ASSERT(child->initialized);
+       DISSECTOR_ASSERT(child->type == TVBUFF_REAL_DATA);
        add_to_used_in_list(parent, child);
 }
 
+static void
+tvb_set_real_data_no_exceptions(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
+{
+       tvb->real_data = data;
+       tvb->length = length;
+       tvb->reported_length = reported_length;
+       tvb->initialized = TRUE;
+}
+
 void
 tvb_set_real_data(tvbuff_t* tvb, const guint8* data, guint length, gint reported_length)
 {
-       g_assert(tvb->type == TVBUFF_REAL_DATA);
-       g_assert(!tvb->initialized);
+       DISSECTOR_ASSERT(tvb);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_REAL_DATA);
+       DISSECTOR_ASSERT(!tvb->initialized);
 
-       if (reported_length < -1) {
-               THROW(ReportedBoundsError);
-       }
+       THROW_ON(reported_length < -1, ReportedBoundsError);
 
-       tvb->real_data          = (gpointer) data;
-       tvb->length             = length;
-       tvb->reported_length    = reported_length;
-       tvb->initialized        = TRUE;
+       tvb_set_real_data_no_exceptions(tvb, data, length, reported_length);
 }
 
 tvbuff_t*
@@ -331,11 +306,11 @@ tvb_new_real_data(const guint8* data, guint length, gint reported_length)
 {
        tvbuff_t        *tvb;
 
-       tvb = tvb_new(TVBUFF_REAL_DATA);
+       THROW_ON(reported_length < -1, ReportedBoundsError);
 
-       CLEANUP_PUSH(tvb_free_void, tvb);
+       tvb = tvb_new(TVBUFF_REAL_DATA);
 
-       tvb_set_real_data(tvb, data, length, reported_length);
+       tvb_set_real_data_no_exceptions(tvb, data, length, reported_length);
 
        /*
         * This is the top-level real tvbuff for this data source,
@@ -343,7 +318,16 @@ tvb_new_real_data(const guint8* data, guint length, gint reported_length)
         */
        tvb->ds_tvb = tvb;
 
-       CLEANUP_POP;
+       return tvb;
+}
+
+tvbuff_t*
+tvb_new_child_real_data(tvbuff_t *parent, const guint8* data, guint length, gint reported_length)
+{
+       tvbuff_t *tvb = tvb_new_real_data(data, length, reported_length);
+       if (tvb) {
+               tvb_set_child_real_data_tvbuff (parent, tvb);
+       }
 
        return tvb;
 }
@@ -362,22 +346,22 @@ tvb_new_real_data(const guint8* data, guint length, gint reported_length)
  * that gets an exception, so the error is reported as an error in that
  * protocol rather than the containing protocol.  */
 static gboolean
-compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
+compute_offset_length(guint tvb_length, guint tvb_reported_length, gint offset, gint length,
                guint *offset_ptr, guint *length_ptr, int *exception)
 {
-       g_assert(offset_ptr);
-       g_assert(length_ptr);
+       DISSECTOR_ASSERT(offset_ptr);
+       DISSECTOR_ASSERT(length_ptr);
 
        /* Compute the offset */
        if (offset >= 0) {
                /* Positive offset - relative to the beginning of the packet. */
-               if ((guint) offset > tvb->reported_length) {
+               if ((guint) offset > tvb_reported_length) {
                        if (exception) {
                                *exception = ReportedBoundsError;
                        }
                        return FALSE;
                }
-               else if ((guint) offset > tvb->length) {
+               else if ((guint) offset > tvb_length) {
                        if (exception) {
                                *exception = BoundsError;
                        }
@@ -389,20 +373,20 @@ compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
        }
        else {
                /* Negative offset - relative to the end of the packet. */
-               if ((guint) -offset > tvb->reported_length) {
+               if ((guint) -offset > tvb_reported_length) {
                        if (exception) {
                                *exception = ReportedBoundsError;
                        }
                        return FALSE;
                }
-               else if ((guint) -offset > tvb->length) {
+               else if ((guint) -offset > tvb_length) {
                        if (exception) {
                                *exception = BoundsError;
                        }
                        return FALSE;
                }
                else {
-                       *offset_ptr = tvb->length + offset;
+                       *offset_ptr = tvb_length + offset;
                }
        }
 
@@ -415,7 +399,7 @@ compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
                return FALSE;
        }
        else if (length == -1) {
-               *length_ptr = tvb->length - *offset_ptr;
+               *length_ptr = tvb_length - *offset_ptr;
        }
        else {
                *length_ptr = length;
@@ -426,14 +410,12 @@ compute_offset_length(tvbuff_t *tvb, gint offset, gint length,
 
 
 static gboolean
-check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
+check_offset_length_no_exception(guint tvb_length, guint tvb_reported_length, gint offset, gint length,
                guint *offset_ptr, guint *length_ptr, int *exception)
 {
        guint   end_offset;
 
-       g_assert(tvb->initialized);
-
-       if (!compute_offset_length(tvb, offset, length, offset_ptr, length_ptr, exception)) {
+       if (!compute_offset_length(tvb_length, tvb_reported_length, offset, length, offset_ptr, length_ptr, exception)) {
                return FALSE;
        }
 
@@ -457,57 +439,41 @@ check_offset_length_no_exception(tvbuff_t *tvb, gint offset, gint length,
         * If not, return TRUE; otherwise, return FALSE and, if "exception"
         * is non-null, return the appropriate exception through it.
         */
-       if (end_offset <= tvb->length) {
+       if (end_offset <= tvb_length) {
                return TRUE;
        }
-       else if (end_offset <= tvb->reported_length) {
+       else if (end_offset <= tvb_reported_length) {
                if (exception) {
                        *exception = BoundsError;
                }
-               return FALSE;
        }
        else {
                if (exception) {
                        *exception = ReportedBoundsError;
                }
-               return FALSE;
        }
 
-       g_assert_not_reached();
+       return FALSE;
 }
 
 /* Checks (+/-) offset and length and throws an exception if
  * either is out of bounds. Sets integer ptrs to the new offset
  * and length. */
 static void
-check_offset_length(tvbuff_t *tvb, gint offset, gint length,
+check_offset_length(guint tvb_length, guint tvb_reported_length, gint offset, gint length,
                guint *offset_ptr, guint *length_ptr)
 {
        int exception = 0;
 
-       if (!check_offset_length_no_exception(tvb, offset, length, offset_ptr, length_ptr, &exception)) {
-               g_assert(exception > 0);
+       if (!check_offset_length_no_exception(tvb_length, tvb_reported_length, offset, length, offset_ptr, length_ptr, &exception)) {
+               DISSECTOR_ASSERT(exception > 0);
                THROW(exception);
        }
-       return;
 }
 
-
-void
-tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
-               gint backing_offset, gint backing_length, gint reported_length)
+static void
+tvb_set_subset_no_exceptions(tvbuff_t *tvb, tvbuff_t *backing, gint reported_length)
 {
-       g_assert(tvb->type == TVBUFF_SUBSET);
-       g_assert(!tvb->initialized);
-
-       if (reported_length < -1) {
-               THROW(ReportedBoundsError);
-       }
-
-       check_offset_length(backing, backing_offset, backing_length,
-                       &tvb->tvbuffs.subset.offset,
-                       &tvb->tvbuffs.subset.length);
-
        tvb->tvbuffs.subset.tvb         = backing;
        tvb->length                     = tvb->tvbuffs.subset.length;
 
@@ -527,17 +493,41 @@ tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
        }
 }
 
+void
+tvb_set_subset(tvbuff_t *tvb, tvbuff_t *backing,
+               gint backing_offset, gint backing_length, gint reported_length)
+{
+       DISSECTOR_ASSERT(tvb);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_SUBSET);
+       DISSECTOR_ASSERT(!tvb->initialized);
+
+       THROW_ON(reported_length < -1, ReportedBoundsError);
+
+       check_offset_length(backing->length, backing->reported_length, backing_offset, backing_length,
+                       &tvb->tvbuffs.subset.offset,
+                       &tvb->tvbuffs.subset.length);
+
+       tvb_set_subset_no_exceptions(tvb, backing, reported_length);
+}
 
 tvbuff_t*
 tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint reported_length)
 {
        tvbuff_t        *tvb;
+       guint           subset_tvb_offset;
+       guint           subset_tvb_length;
 
-       tvb = tvb_new(TVBUFF_SUBSET);
+       DISSECTOR_ASSERT(backing && backing->initialized);
 
-       CLEANUP_PUSH(tvb_free_void, tvb);
+       THROW_ON(reported_length < -1, ReportedBoundsError);
 
-       tvb_set_subset(tvb, backing, backing_offset, backing_length, reported_length);
+       check_offset_length(backing->length, backing->reported_length, backing_offset, backing_length,
+                       &subset_tvb_offset,
+                       &subset_tvb_length);
+
+       tvb = tvb_new_with_subset(subset_tvb_offset, subset_tvb_length);
+
+       tvb_set_subset_no_exceptions(tvb, backing, reported_length);
 
        /*
         * The top-level data source of this tvbuff is the top-level
@@ -545,7 +535,29 @@ tvb_new_subset(tvbuff_t *backing, gint backing_offset, gint backing_length, gint
         */
        tvb->ds_tvb = backing->ds_tvb;
 
-       CLEANUP_POP;
+       return tvb;
+}
+
+tvbuff_t*
+tvb_new_subset_remaining(tvbuff_t *backing, gint backing_offset)
+{
+       tvbuff_t        *tvb;
+       guint           subset_tvb_offset;
+       guint           subset_tvb_length;
+
+       check_offset_length(backing->length, backing->reported_length, backing_offset, -1 /* backing_length */,
+                       &subset_tvb_offset,
+                       &subset_tvb_length);
+
+       tvb = tvb_new_with_subset(subset_tvb_offset, subset_tvb_length);
+
+       tvb_set_subset_no_exceptions(tvb, backing, -1 /* reported_length */);
+
+       /*
+        * The top-level data source of this tvbuff is the top-level
+        * data source of its parent.
+        */
+       tvb->ds_tvb = backing->ds_tvb;
 
        return tvb;
 }
@@ -555,10 +567,11 @@ tvb_composite_append(tvbuff_t* tvb, tvbuff_t* member)
 {
        tvb_comp_t      *composite;
 
-       g_assert(!tvb->initialized);
+       DISSECTOR_ASSERT(tvb && !tvb->initialized);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE);
        composite = &tvb->tvbuffs.composite;
        composite->tvbs = g_slist_append( composite->tvbs, member );
-       add_to_used_in_list(member, tvb);
+       add_to_used_in_list(tvb, member);
 }
 
 void
@@ -566,10 +579,11 @@ tvb_composite_prepend(tvbuff_t* tvb, tvbuff_t* member)
 {
        tvb_comp_t      *composite;
 
-       g_assert(!tvb->initialized);
+       DISSECTOR_ASSERT(tvb && !tvb->initialized);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE);
        composite = &tvb->tvbuffs.composite;
        composite->tvbs = g_slist_prepend( composite->tvbs, member );
-       add_to_used_in_list(member, tvb);
+       add_to_used_in_list(tvb, member);
 }
 
 tvbuff_t*
@@ -587,8 +601,9 @@ tvb_composite_finalize(tvbuff_t* tvb)
        tvb_comp_t      *composite;
        int             i = 0;
 
-       g_assert(!tvb->initialized);
-       g_assert(tvb->length == 0);
+       DISSECTOR_ASSERT(tvb && !tvb->initialized);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE);
+       DISSECTOR_ASSERT(tvb->length == 0);
 
        composite = &tvb->tvbuffs.composite;
        num_members = g_slist_length(composite->tvbs);
@@ -597,7 +612,7 @@ tvb_composite_finalize(tvbuff_t* tvb)
        composite->end_offsets = g_new(guint, num_members);
 
        for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
-               g_assert((guint) i < num_members);
+               DISSECTOR_ASSERT((guint) i < num_members);
                member_tvb = slist->data;
                composite->start_offsets[i] = tvb->length;
                tvb->length += member_tvb->length;
@@ -613,7 +628,7 @@ tvb_composite_finalize(tvbuff_t* tvb)
 guint
 tvb_length(tvbuff_t* tvb)
 {
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        return tvb->length;
 }
@@ -623,9 +638,9 @@ tvb_length_remaining(tvbuff_t *tvb, gint offset)
 {
        guint   abs_offset, abs_length;
 
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
+       if (compute_offset_length(tvb->length, tvb->reported_length, offset, -1, &abs_offset, &abs_length, NULL)) {
                return abs_length;
        }
        else {
@@ -639,11 +654,22 @@ tvb_ensure_length_remaining(tvbuff_t *tvb, gint offset)
        guint   abs_offset, abs_length;
        int     exception;
 
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, &exception)) {
+       if (!compute_offset_length(tvb->length, tvb->reported_length, 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;
 }
 
@@ -657,9 +683,9 @@ tvb_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
 {
        guint           abs_offset, abs_length;
 
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       if (!compute_offset_length(tvb, offset, length, &abs_offset, &abs_length, NULL))
+       if (!compute_offset_length(tvb->length, tvb->reported_length, offset, length, &abs_offset, &abs_length, NULL))
                return FALSE;
 
        if (abs_offset + abs_length <= tvb->length) {
@@ -677,7 +703,7 @@ tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
 {
        guint           abs_offset, abs_length;
 
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        /*
         * -1 doesn't mean "until end of buffer", as that's pointless
@@ -692,7 +718,7 @@ tvb_ensure_bytes_exist(tvbuff_t *tvb, gint offset, gint length)
        if (length < 0) {
                THROW(ReportedBoundsError);
        }
-       check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
+       check_offset_length(tvb->length, tvb->reported_length, offset, length, &abs_offset, &abs_length);
 }
 
 gboolean
@@ -700,8 +726,8 @@ tvb_offset_exists(tvbuff_t *tvb, gint offset)
 {
        guint           abs_offset, abs_length;
 
-       g_assert(tvb->initialized);
-       if (!compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL))
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+       if (!compute_offset_length(tvb->length, tvb->reported_length, offset, -1, &abs_offset, &abs_length, NULL))
                return FALSE;
 
        if (abs_offset < tvb->length) {
@@ -715,7 +741,7 @@ tvb_offset_exists(tvbuff_t *tvb, gint offset)
 guint
 tvb_reported_length(tvbuff_t* tvb)
 {
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        return tvb->reported_length;
 }
@@ -725,9 +751,9 @@ tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
 {
        guint   abs_offset, abs_length;
 
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       if (compute_offset_length(tvb, offset, -1, &abs_offset, &abs_length, NULL)) {
+       if (compute_offset_length(tvb->length, tvb->reported_length, offset, -1, &abs_offset, &abs_length, NULL)) {
                if (tvb->reported_length >= abs_offset)
                        return tvb->reported_length - abs_offset;
                else
@@ -747,7 +773,7 @@ tvb_reported_length_remaining(tvbuff_t *tvb, gint offset)
 void
 tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
 {
-       g_assert(tvb->initialized);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        if (reported_length > tvb->reported_length)
                THROW(ReportedBoundsError);
@@ -758,7 +784,8 @@ tvb_set_reported_length(tvbuff_t* tvb, guint reported_length)
 }
 
 
-static guint8*
+#if 0
+static const guint8*
 first_real_data_ptr(tvbuff_t *tvb)
 {
        tvbuff_t        *member;
@@ -774,12 +801,13 @@ first_real_data_ptr(tvbuff_t *tvb)
                        return first_real_data_ptr(member);
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return NULL;
 }
+#endif
 
-static int
-offset_from_real_beginning(tvbuff_t *tvb, int counter)
+static guint
+offset_from_real_beginning(tvbuff_t *tvb, guint counter)
 {
        tvbuff_t        *member;
 
@@ -794,20 +822,17 @@ offset_from_real_beginning(tvbuff_t *tvb, int counter)
                        return offset_from_real_beginning(member, counter);
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return 0;
 }
 
-gint
-tvb_raw_offset(tvbuff_t *tvb)
+guint
+tvb_offset_from_real_beginning(tvbuff_t *tvb)
 {
-       if (tvb->raw_offset == -1) {
-               tvb->raw_offset = offset_from_real_beginning(tvb, 0);
-       }
-       return tvb->raw_offset;
+       return offset_from_real_beginning(tvb, 0);
 }
 
-static guint8*
+static const guint8*
 composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
                guint abs_length)
 {
@@ -817,7 +842,7 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
        guint           member_offset, member_length;
        GSList          *slist;
 
-       g_assert(tvb->type == TVBUFF_COMPOSITE);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE);
 
        /* Maybe the range specified by offset/length
         * is contiguous inside one of the member tvbuffs */
@@ -831,15 +856,15 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
                        break;
                }
        }
-       g_assert(member_tvb);
+       DISSECTOR_ASSERT(member_tvb);
 
-       if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
+       if (check_offset_length_no_exception(member_tvb->length, member_tvb->reported_length, 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);
+               DISSECTOR_ASSERT(!tvb->real_data);
                return ensure_contiguous_no_exception(member_tvb, member_offset, member_length, NULL);
        }
        else {
@@ -847,18 +872,18 @@ composite_ensure_contiguous_no_exception(tvbuff_t *tvb, guint abs_offset,
                return tvb->real_data + abs_offset;
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return NULL;
 }
 
-static guint8*
+static const guint8*
 ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
                int *exception)
 {
        guint   abs_offset, abs_length;
 
-       if (!check_offset_length_no_exception(tvb, offset, length,
-           &abs_offset, &abs_length, exception)) {
+       if (!check_offset_length_no_exception(tvb->length, tvb->reported_length, offset, length,
+               &abs_offset, &abs_length, exception)) {
                return NULL;
        }
 
@@ -872,7 +897,7 @@ ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
        else {
                switch(tvb->type) {
                        case TVBUFF_REAL_DATA:
-                               g_assert_not_reached();
+                               DISSECTOR_ASSERT_NOT_REACHED();
                        case TVBUFF_SUBSET:
                                return ensure_contiguous_no_exception(tvb->tvbuffs.subset.tvb,
                                                abs_offset - tvb->tvbuffs.subset.offset,
@@ -882,24 +907,53 @@ ensure_contiguous_no_exception(tvbuff_t *tvb, gint offset, gint length,
                }
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return NULL;
 }
 
-static guint8*
+static const guint8*
 ensure_contiguous(tvbuff_t *tvb, gint offset, gint length)
 {
        int exception;
-       guint8 *p;
+       const guint8 *p;
 
        p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
        if (p == NULL) {
-               g_assert(exception > 0);
+               DISSECTOR_ASSERT(exception > 0);
                THROW(exception);
        }
        return p;
 }
 
+static const guint8*
+fast_ensure_contiguous(tvbuff_t *tvb, gint offset, guint length)
+{
+       guint   end_offset;
+       guint   u_offset;
+
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+       /* We don't check for overflow in this fast path so we only handle simple types */
+       DISSECTOR_ASSERT(length <= 8);
+
+       if (offset < 0 || !tvb->real_data) {
+               return ensure_contiguous(tvb, offset, length);
+       }
+
+       u_offset = offset;
+       end_offset = u_offset + length;
+
+       if (end_offset <= tvb->length) {
+               return tvb->real_data + u_offset;
+       }
+
+       if (end_offset > tvb->reported_length) {
+               THROW(ReportedBoundsError);
+       }
+       THROW(BoundsError);
+       /* not reached */
+       return NULL;
+}
+
 static const guint8*
 guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
 {
@@ -916,11 +970,12 @@ guint8_find(const guint8* haystack, size_t haystacklen, guint8 needle)
 }
 
 static const guint8*
-guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
+guint8_pbrk(const guint8* haystack, size_t haystacklen, const guint8 *needles)
 {
        const guint8    *b;
        int             i;
-       guint8          item, *needlep, needle;
+       guint8          item, needle;
+       const guint8    *needlep;
 
        for (b = haystack, i = 0; (guint) i < haystacklen; i++, b++) {
                item = *b;
@@ -939,8 +994,8 @@ guint8_pbrk(const guint8* haystack, size_t haystacklen, guint8 *needles)
 
 /************** ACCESSORS **************/
 
-static guint8*
-composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_length)
+static void*
+composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, size_t abs_length)
 {
        guint           i, num_members;
        tvb_comp_t      *composite;
@@ -949,7 +1004,7 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_leng
        gboolean        retval;
        GSList          *slist;
 
-       g_assert(tvb->type == TVBUFF_COMPOSITE);
+       DISSECTOR_ASSERT(tvb->type == TVBUFF_COMPOSITE);
 
        /* Maybe the range specified by offset/length
         * is contiguous inside one of the member tvbuffs */
@@ -963,12 +1018,12 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_leng
                        break;
                }
        }
-       g_assert(member_tvb);
+       DISSECTOR_ASSERT(member_tvb);
 
-       if (check_offset_length_no_exception(member_tvb, abs_offset - composite->start_offsets[i],
-                               abs_length, &member_offset, &member_length, NULL)) {
+       if (check_offset_length_no_exception(member_tvb->length, member_tvb->reported_length, abs_offset - composite->start_offsets[i],
+                               (gint) abs_length, &member_offset, &member_length, NULL)) {
 
-               g_assert(!tvb->real_data);
+               DISSECTOR_ASSERT(!tvb->real_data);
                return tvb_memcpy(member_tvb, target, member_offset, member_length);
        }
        else {
@@ -977,9 +1032,9 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_leng
                 * then iterate across the other member tvb's, copying their portions
                 * until we have copied all data.
                 */
-               retval = compute_offset_length(member_tvb, abs_offset - composite->start_offsets[i], -1,
+               retval = compute_offset_length(member_tvb->length, member_tvb->reported_length, abs_offset - composite->start_offsets[i], -1,
                                &member_offset, &member_length, NULL);
-               g_assert(retval);
+               DISSECTOR_ASSERT(retval);
 
                tvb_memcpy(member_tvb, target, member_offset, member_length);
                abs_offset      += member_length;
@@ -993,25 +1048,38 @@ composite_memcpy(tvbuff_t *tvb, guint8* target, guint abs_offset, guint abs_leng
                return target;
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return NULL;
 }
 
-guint8*
-tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
+void*
+tvb_memcpy(tvbuff_t *tvb, void* target, gint offset, size_t length)
 {
        guint   abs_offset, abs_length;
 
-       g_assert(length >= -1);
-       check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       /*
+        * XXX - we should eliminate the "length = -1 means 'to the end
+        * of the tvbuff'" convention, and use other means to achieve
+        * that; this would let us eliminate a bunch of checks for
+        * negative lengths in cases where the protocol has a 32-bit
+        * length field.
+        *
+        * Allowing -1 but throwing an assertion on other negative
+        * lengths is a bit more work with the length being a size_t;
+        * instead, we check for a length <= 2^31-1.
+        */
+       DISSECTOR_ASSERT(length <= 0x7FFFFFFF);
+       check_offset_length(tvb->length, tvb->reported_length, offset, (gint) length, &abs_offset, &abs_length);
 
        if (tvb->real_data) {
-               return (guint8*) memcpy(target, tvb->real_data + abs_offset, abs_length);
+               return memcpy(target, tvb->real_data + abs_offset, abs_length);
        }
 
        switch(tvb->type) {
                case TVBUFF_REAL_DATA:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
 
                case TVBUFF_SUBSET:
                        return tvb_memcpy(tvb->tvbuffs.subset.tvb, target,
@@ -1022,7 +1090,7 @@ tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
                        return composite_memcpy(tvb, target, offset, length);
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return NULL;
 }
 
@@ -1037,18 +1105,50 @@ tvb_memcpy(tvbuff_t *tvb, guint8* target, gint offset, gint length)
  * 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)
+void*
+tvb_memdup(tvbuff_t *tvb, gint offset, size_t length)
 {
        guint   abs_offset, abs_length;
-       guint8  *duped;
+       void    *duped;
 
-       check_offset_length(tvb, offset, length, &abs_offset, &abs_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, (gint) length, &abs_offset, &abs_length);
 
        duped = g_malloc(abs_length);
        return tvb_memcpy(tvb, duped, abs_offset, abs_length);
 }
 
+/*
+ * XXX - this doesn't treat a length of -1 as an error.
+ * If it did, this could replace some code that calls
+ * "tvb_ensure_bytes_exist()" and then allocates a buffer and copies
+ * data to it.
+ *
+ * "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"?
+ *
+ * This function allocates memory from a buffer with packet lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts decoding the next packet.
+ * Do not use this function if you want the allocated memory to be persistent
+ * after the current packet has been dissected.
+ */
+void*
+ep_tvb_memdup(tvbuff_t *tvb, gint offset, size_t length)
+{
+       guint   abs_offset, abs_length;
+       void    *duped;
+
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, (gint) length, &abs_offset, &abs_length);
+
+       duped = ep_alloc(abs_length);
+       return tvb_memcpy(tvb, duped, abs_offset, abs_length);
+}
+
 
 
 const guint8*
@@ -1057,42 +1157,52 @@ tvb_get_ptr(tvbuff_t *tvb, gint offset, gint length)
        return ensure_contiguous(tvb, offset, length);
 }
 
+/* ---------------- */
 guint8
 tvb_get_guint8(tvbuff_t *tvb, gint offset)
 {
-       guint8* ptr;
+       const guint8* ptr;
 
-       ptr = ensure_contiguous(tvb, offset, sizeof(guint8));
+       ptr = fast_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));
+       ptr = fast_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);
+       ptr = fast_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));
+       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
        return pntohl(ptr);
 }
 
+guint64
+tvb_get_ntoh64(tvbuff_t *tvb, gint offset)
+{
+       const guint8* ptr;
+
+       ptr = fast_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.
@@ -1107,9 +1217,9 @@ tvb_get_ntohl(tvbuff_t *tvb, gint offset)
  * huge surprise).
  *
  * I don't know whether there are any other machines that
- * could run Ethereal and that don't use IEEE format.
+ * could run Wireshark and that don't use IEEE format.
  * As far as I know, all of the main commercial microprocessor
- * families on which OSes that support Ethereal can run
+ * families on which OSes that support Wireshark can run
  * use IEEE format (x86, 68k, SPARC, MIPS, PA-RISC, Alpha,
  * IA-64, and so on).
  */
@@ -1168,7 +1278,7 @@ get_ieee_float(guint32 w)
 #endif
 
        exponent = ((exponent >> IEEE_SP_MANTISSA_WIDTH) - IEEE_SP_BIAS) -
-           IEEE_SP_MANTISSA_WIDTH;
+               IEEE_SP_MANTISSA_WIDTH;
        mantissa |= IEEE_SP_IMPLIED_BIT;
 
        if (sign)
@@ -1229,7 +1339,7 @@ get_ieee_double(guint64 w)
 #endif
 
        exponent = ((exponent >> IEEE_DP_MANTISSA_WIDTH) - IEEE_DP_BIAS) -
-           IEEE_DP_MANTISSA_WIDTH;
+               IEEE_DP_MANTISSA_WIDTH;
        mantissa |= IEEE_DP_IMPLIED_BIT;
 
        if (sign)
@@ -1299,30 +1409,39 @@ 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));
+       ptr = fast_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);
+       ptr = fast_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));
+       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
        return pletohl(ptr);
 }
 
+guint64
+tvb_get_letoh64(tvbuff_t *tvb, gint offset)
+{
+       const guint8* ptr;
+
+       ptr = fast_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".
@@ -1380,6 +1499,290 @@ tvb_get_letohieee_double(tvbuff_t *tvb, int offset)
 #endif
 }
 
+/* Fetch an IPv4 address, in network byte order.
+ * We do *not* convert them to host byte order; we leave them in
+ * network byte order. */
+guint32
+tvb_get_ipv4(tvbuff_t *tvb, gint offset)
+{
+       const guint8* ptr;
+       guint32 addr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
+       memcpy(&addr, ptr, sizeof addr);
+       return addr;
+}
+
+/* Fetch an IPv6 address. */
+void
+tvb_get_ipv6(tvbuff_t *tvb, gint offset, struct e_in6_addr *addr)
+{
+       const guint8* ptr;
+
+       ptr = ensure_contiguous(tvb, offset, sizeof(*addr));
+       memcpy(addr, ptr, sizeof *addr);
+}
+
+/* Fetch a GUID. */
+void
+tvb_get_ntohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid)
+{
+       ensure_contiguous(tvb, offset, sizeof(*guid));
+       guid->data1 = tvb_get_ntohl(tvb, offset);
+       guid->data2 = tvb_get_ntohs(tvb, offset + 4);
+       guid->data3 = tvb_get_ntohs(tvb, offset + 6);
+       tvb_memcpy(tvb, guid->data4, offset + 8, sizeof guid->data4);
+}
+
+void
+tvb_get_letohguid(tvbuff_t *tvb, gint offset, e_guid_t *guid)
+{
+       ensure_contiguous(tvb, offset, sizeof(*guid));
+       guid->data1 = tvb_get_letohl(tvb, offset);
+       guid->data2 = tvb_get_letohs(tvb, offset + 4);
+       guid->data3 = tvb_get_letohs(tvb, offset + 6);
+       tvb_memcpy(tvb, guid->data4, offset + 8, sizeof guid->data4);
+}
+
+void
+tvb_get_guid(tvbuff_t *tvb, gint offset, e_guid_t *guid, gboolean little_endian)
+{
+       if (little_endian) {
+               tvb_get_letohguid(tvb, offset, guid);
+       } else {
+               tvb_get_ntohguid(tvb, offset, guid);
+       }
+}
+
+static const guint8 bit_mask8[] = {
+       0xff,
+       0x7f,
+       0x3f,
+       0x1f,
+       0x0f,
+       0x07,
+       0x03,
+       0x01
+};
+
+/* Bit offset mask for number of bits = 8 - 16 */
+static const guint16 bit_mask16[] = {
+       0xffff,
+       0x7fff,
+       0x3fff,
+       0x1fff,
+       0x0fff,
+       0x07ff,
+       0x03ff,
+       0x01ff
+};
+
+/* Get 1 - 8 bits */
+guint8
+tvb_get_bits8(tvbuff_t *tvb, gint bit_offset, gint no_of_bits)
+{
+       gint    offset;
+       guint16 value = 0;
+       guint8  tot_no_bits;
+
+       if (no_of_bits>8) {
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
+       /* Byte align offset */
+       offset = bit_offset>>3;
+
+       /* Find out which mask to use for the most significant octet
+        * by convering bit_offset into the offset into the first
+        * fetched octet.
+        */
+       bit_offset = bit_offset & 0x7;
+       tot_no_bits = bit_offset+no_of_bits;
+       if(tot_no_bits<=8){
+               /* Read one octet, mask off bit_offset bits and left shift out the unused bits */
+               value = tvb_get_guint8(tvb,offset) & bit_mask8[bit_offset];
+               value = value >> (8-tot_no_bits);
+       }else{
+               /* Read two octets, mask off bit_offset bits and left shift out the unused bits */
+               value = tvb_get_ntohs(tvb,offset) & bit_mask16[bit_offset];
+               value = value >> (16 - tot_no_bits);
+       }
+
+       return (guint8)value;
+}
+
+/* Get 9 - 16 bits */
+/* Bit offset mask for number of bits = 16 - 32 */
+static const guint32 bit_mask32[] = {
+       0xffffffff,
+       0x7fffffff,
+       0x3fffffff,
+       0x1fffffff,
+       0x0fffffff,
+       0x07ffffff,
+       0x03ffffff,
+       0x01ffffff
+};
+
+guint16
+tvb_get_bits16(tvbuff_t *tvb, gint bit_offset, gint no_of_bits,gboolean little_endian)
+{
+       gint    offset;
+       guint16 value = 0;
+       guint16 tempval = 0;
+       guint8  tot_no_bits;
+
+       if ((no_of_bits<=8)||(no_of_bits>16)) {
+               /* If bits <= 8 use tvb_get_bits8 */
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
+       if(little_endian){
+               DISSECTOR_ASSERT_NOT_REACHED();
+               /* This part is not implemented yet */
+       }
+
+       /* Byte align offset */
+       offset = bit_offset>>3;
+
+       /* Find out which mask to use for the most significant octet
+        * by convering bit_offset into the offset into the first
+        * fetched octet.
+        */
+       bit_offset = bit_offset & 0x7;
+       tot_no_bits = bit_offset+no_of_bits;
+       /* Read two octets and mask off bit_offset bits */
+       value = tvb_get_ntohs(tvb,offset) & bit_mask16[bit_offset];
+       if(tot_no_bits < 16){
+               /* Left shift out the unused bits */
+               value = value >> (16 - tot_no_bits);
+       }else if(tot_no_bits > 16){
+               /* Spans three octets, read next octet and shift as needed */
+               value = value << (tot_no_bits - 16);
+               tempval = tvb_get_guint8(tvb,offset+2);
+               tempval = tempval >> (24-tot_no_bits);
+               value = value | tempval;
+       }
+
+       return value;
+}
+
+/* Bit offset mask for number of bits = 32 - 64 */
+static const guint64 bit_mask64[] = {
+       G_GINT64_CONSTANT(0xffffffffffffffffU),
+       G_GINT64_CONSTANT(0x7fffffffffffffffU),
+       G_GINT64_CONSTANT(0x3fffffffffffffffU),
+       G_GINT64_CONSTANT(0x1fffffffffffffffU),
+       G_GINT64_CONSTANT(0x0fffffffffffffffU),
+       G_GINT64_CONSTANT(0x07ffffffffffffffU),
+       G_GINT64_CONSTANT(0x03ffffffffffffffU),
+       G_GINT64_CONSTANT(0x01ffffffffffffffU)
+};
+
+guint32
+tvb_get_bits32(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian)
+{
+       gint    offset;
+       guint32 value = 0;
+       guint32 tempval = 0;
+       guint8  tot_no_bits;
+
+       if ((no_of_bits<=16)||(no_of_bits>32)) {
+               /* If bits <= 16 use tvb_get_bits8 or tvb_get_bits16 */
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
+       if(little_endian){
+               DISSECTOR_ASSERT_NOT_REACHED();
+               /* This part is not implemented yet */
+       }
+
+       /* Byte align offset */
+       offset = bit_offset>>3;
+
+       /* Find out which mask to use for the most significant octet
+        * by convering bit_offset into the offset into the first
+        * fetched octet.
+        */
+       bit_offset = bit_offset & 0x7;
+       tot_no_bits = bit_offset+no_of_bits;
+       /* Read four octets and mask off bit_offset bits */
+       value = tvb_get_ntohl(tvb,offset) & bit_mask32[bit_offset];
+       if(tot_no_bits < 32){
+               /* Left shift out the unused bits */
+               value = value >> (32 - tot_no_bits);
+       }else if(tot_no_bits > 32){
+               /* Spans five octets, read next octet and shift as needed */
+               value = value << (tot_no_bits - 32);
+               tempval = tvb_get_guint8(tvb,offset+4);
+               tempval = tempval >> (40-tot_no_bits);
+               value = value | tempval;
+       }
+
+       return value;
+}
+
+guint64
+tvb_get_bits64(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian)
+{
+       gint    offset;
+       guint64 value = 0;
+       guint64 tempval = 0;
+       guint8  tot_no_bits;
+
+       if ((no_of_bits<=32)||(no_of_bits>64)) {
+               /* If bits <= 32 use tvb_get_bits8, tvb_get_bits16 or tvb_get_bits32 */
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
+       if(little_endian){
+               DISSECTOR_ASSERT_NOT_REACHED();
+               /* This part is not implemented yet */
+       }
+
+       /* Byte align offset */
+       offset = bit_offset>>3;
+
+       /* Find out which mask to use for the most significant octet
+        * by convering bit_offset into the offset into the first
+        * fetched octet.
+        */
+       bit_offset = bit_offset & 0x7;
+       tot_no_bits = bit_offset+no_of_bits;
+       /* Read eight octets and mask off bit_offset bits */
+       value = tvb_get_ntoh64(tvb,offset) & bit_mask64[bit_offset];
+       if (tot_no_bits < 64){
+               /* Left shift out the unused bits */
+               value = value >> (64 - tot_no_bits);
+       }else if (tot_no_bits > 64){
+               /* Spans nine octets, read next octet and shift as needed */
+               value = value << (tot_no_bits - 64);
+               tempval = tvb_get_guint8(tvb,offset+8);
+               tempval = tempval >> (72-tot_no_bits);
+               value = value | tempval;
+       }
+
+       return value;
+}
+
+guint32
+tvb_get_bits(tvbuff_t *tvb, gint bit_offset, gint no_of_bits, gboolean little_endian)
+{
+       /* This function can handle only up to 32 requested bits */
+       if (no_of_bits > 32)
+               DISSECTOR_ASSERT_NOT_REACHED();
+
+       if (no_of_bits == 0)
+               return 0;
+
+       /* Number of requested bits is in range [17, 32] */
+       if (no_of_bits > 16)
+               return tvb_get_bits32(tvb, bit_offset, no_of_bits, little_endian);
+
+       /* Number of requested bits is in range [9, 16] */
+       if (no_of_bits > 8)
+               return tvb_get_bits16(tvb, bit_offset, no_of_bits, little_endian);
+
+       /* Number of requested bits is in range [1, 8] */
+       return tvb_get_bits8(tvb, bit_offset, no_of_bits);
+}
+
 /* Find first occurence of needle in tvbuff, starting at offset. Searches
  * at most maxlength number of bytes; if maxlength is -1, searches to
  * end of tvbuff.
@@ -1395,7 +1798,9 @@ tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
        guint           tvbufflen;
        guint           limit;
 
-       check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, 0, &abs_offset, &junk_length);
 
        /* Only search to end of tvbuff, w/o throwing exception. */
        tvbufflen = tvb_length_remaining(tvb, abs_offset);
@@ -1421,13 +1826,13 @@ tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
                        return -1;
                }
                else {
-                       return result - tvb->real_data;
+                       return (gint) (result - tvb->real_data);
                }
        }
 
        switch(tvb->type) {
                case TVBUFF_REAL_DATA:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
 
                case TVBUFF_SUBSET:
                        return tvb_find_guint8(tvb->tvbuffs.subset.tvb,
@@ -1435,11 +1840,11 @@ tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
                                        limit, needle);
 
                case TVBUFF_COMPOSITE:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        /* XXX - return composite_find_guint8(tvb, offset, limit, needle); */
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return -1;
 }
 
@@ -1451,14 +1856,16 @@ tvb_find_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 needle)
  * in that case, -1 will be returned if the boundary is reached before
  * finding needle. */
 gint
-tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 *needles)
+tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, const guint8 *needles)
 {
        const guint8    *result;
        guint           abs_offset, junk_length;
        guint           tvbufflen;
        guint           limit;
 
-       check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, 0, &abs_offset, &junk_length);
 
        /* Only search to end of tvbuff, w/o throwing exception. */
        tvbufflen = tvb_length_remaining(tvb, abs_offset);
@@ -1484,13 +1891,13 @@ tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 *needles)
                        return -1;
                }
                else {
-                       return result - tvb->real_data;
+                       return (gint) (result - tvb->real_data);
                }
        }
 
        switch(tvb->type) {
                case TVBUFF_REAL_DATA:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
 
                case TVBUFF_SUBSET:
                        return tvb_pbrk_guint8(tvb->tvbuffs.subset.tvb,
@@ -1498,11 +1905,11 @@ tvb_pbrk_guint8(tvbuff_t *tvb, gint offset, gint maxlength, guint8 *needles)
                                        limit, needles);
 
                case TVBUFF_COMPOSITE:
-                       g_assert_not_reached();
+                       DISSECTOR_ASSERT_NOT_REACHED();
                        /* XXX - return composite_pbrk_guint8(tvb, offset, limit, needle); */
        }
 
-       g_assert_not_reached();
+       DISSECTOR_ASSERT_NOT_REACHED();
        return -1;
 }
 
@@ -1517,7 +1924,9 @@ tvb_strsize(tvbuff_t *tvb, gint offset)
        guint   abs_offset, junk_length;
        gint    nul_offset;
 
-       check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, 0, &abs_offset, &junk_length);
        nul_offset = tvb_find_guint8(tvb, abs_offset, -1, 0);
        if (nul_offset == -1) {
                /*
@@ -1525,7 +1934,7 @@ tvb_strsize(tvbuff_t *tvb, gint offset)
                 * an exception.
                 *
                 * Did we hit the end of the captured data, or the end
-                * of the actual data?  If there's less captured data
+                * of the actual data?  If there's less captured data
                 * than actual data, we presumably hit the end of the
                 * captured data, otherwise we hit the end of the actual
                 * data.
@@ -1549,7 +1958,9 @@ tvb_strnlen(tvbuff_t *tvb, gint offset, guint maxlength)
        gint    result_offset;
        guint   abs_offset, junk_length;
 
-       check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       check_offset_length(tvb->length, tvb->reported_length, offset, 0, &abs_offset, &junk_length);
 
        result_offset = tvb_find_guint8(tvb, abs_offset, maxlength, 0);
 
@@ -1570,14 +1981,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_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.
@@ -1593,18 +2004,18 @@ tvb_strneql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
 }
 
 /*
- * Call strncasecmp after checking if enough chars left, returning 0 if
- * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
+ * Call g_ascii_strncasecmp after checking if enough chars left, returning
+ * 0 if 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_no_exception(tvb, offset, size, NULL);
 
        if (ptr) {
-               int cmp = strncasecmp(ptr, str, size);
+               int cmp = g_ascii_strncasecmp((const char *)ptr, str, size);
 
                /*
                 * Return 0 if equal, -1 otherwise.
@@ -1624,11 +2035,11 @@ tvb_strncaseeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
  * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
  */
 gint
-tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
+tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, size_t size)
 {
-       guint8 *ptr;
+       const guint8 *ptr;
 
-       ptr = ensure_contiguous_no_exception(tvb, offset, size, NULL);
+       ptr = ensure_contiguous_no_exception(tvb, offset, (gint) size, NULL);
 
        if (ptr) {
                int cmp = memcmp(ptr, str, size);
@@ -1646,10 +2057,10 @@ tvb_memeql(tvbuff_t *tvb, gint offset, const guint8 *str, gint size)
        }
 }
 
-/* Convert a string from Unicode to ASCII.  At the moment we fake it by
- * assuming all characters are ASCII  )-:  The caller must free the
- * result returned.  The len parameter is the number of guint16's to
- * convert from Unicode. */
+/* Convert a string from Unicode to ASCII.     At the moment we fake it by
+ * replacing all non-ASCII characters with a '.' )-:  The caller must
+ * free the result returned.  The len parameter is the number of guint16's
+ * to convert from Unicode. */
 char *
 tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
 {
@@ -1668,7 +2079,7 @@ tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
        for (i = 0; i < len; i++) {
                character = little_endian ? tvb_get_letohs(tvb, offset)
                                          : tvb_get_ntohs(tvb, offset);
-               buffer[i] = character & 0xff;
+               buffer[i] = character < 256 ? character : '.';
                offset += 2;
        }
 
@@ -1677,24 +2088,125 @@ tvb_fake_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
        return buffer;
 }
 
-/*
- * Format the data in the tvb from offset for length ...
+/* Convert a string from Unicode to ASCII.     At the moment we fake it by
+ * replacing all non-ASCII characters with a '.' )-:   The len parameter is
+ * the number of guint16's to convert from Unicode.
+ *
+ * This function allocates memory from a buffer with packet lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts decoding the next packet.
  */
+char *
+tvb_get_ephemeral_faked_unicode(tvbuff_t *tvb, int offset, int len, gboolean little_endian)
+{
+       char *buffer;
+       int i;
+       guint16 character;
 
-guint8 *
+       /* Make sure we have enough data before allocating the buffer,
+          so we don't blow up if the length is huge. */
+       tvb_ensure_bytes_exist(tvb, offset, 2*len);
+
+       /* We know we won't throw an exception, so we don't have to worry
+          about leaking this buffer. */
+       buffer = ep_alloc(len + 1);
+
+       for (i = 0; i < len; i++) {
+               character = little_endian ? tvb_get_letohs(tvb, offset)
+                                         : tvb_get_ntohs(tvb, offset);
+               buffer[i] = character < 256 ? character : '.';
+               offset += 2;
+       }
+
+       buffer[len] = 0;
+
+       return buffer;
+}
+
+/*
+ * Format the data in the tvb from offset for length ...
+ */
+
+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) {
-
     len = tvb_length_remaining(tvb, offset);
     ptr = ensure_contiguous(tvb, offset, len);
-
   }
 
   return format_text(ptr, len);
+}
+
+/*
+ * Format the data in the tvb from offset for length ...
+ */
+
+gchar *
+tvb_format_text_wsp(tvbuff_t *tvb, gint offset, gint size)
+{
+  const guint8 *ptr;
+  gint len = size;
+
+  if ((ptr = ensure_contiguous(tvb, offset, size)) == NULL) {
+
+       len = tvb_length_remaining(tvb, offset);
+       ptr = ensure_contiguous(tvb, offset, len);
+
+  }
+
+  return format_text_wsp(ptr, len);
+
+}
+
+/*
+ * 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);
+
+}
+
+/*
+ * Like "tvb_format_text_wsp()", but for null-padded strings; don't show
+ * the null padding characters as "\000".
+ */
+gchar *
+tvb_format_stringzpad_wsp(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_wsp(ptr, stringlen);
 
 }
 
@@ -1709,12 +2221,75 @@ tvb_format_text(tvbuff_t *tvb, gint offset, gint size)
 guint8 *
 tvb_get_string(tvbuff_t *tvb, gint offset, gint length)
 {
-       guint8 *ptr, *strbuf;
+       const guint8 *ptr;
+       guint8 *strbuf = NULL;
+
+       tvb_ensure_bytes_exist(tvb, offset, length);
 
        ptr = ensure_contiguous(tvb, offset, length);
        strbuf = g_malloc(length + 1);
-       if (length != 0)
+       if (length != 0) {
+               memcpy(strbuf, ptr, length);
+       }
+       strbuf[length] = '\0';
+       return strbuf;
+}
+/*
+ * 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.
+ *
+ * This function allocates memory from a buffer with packet lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts decoding the next packet.
+ * Do not use this function if you want the allocated memory to be persistent
+ * after the current packet has been dissected.
+ */
+guint8 *
+tvb_get_ephemeral_string(tvbuff_t *tvb, gint offset, gint length)
+{
+       const guint8 *ptr;
+       guint8 *strbuf = NULL;
+
+       tvb_ensure_bytes_exist(tvb, offset, length);
+
+       ptr = ensure_contiguous(tvb, offset, length);
+       strbuf = ep_alloc(length + 1);
+       if (length != 0) {
+               memcpy(strbuf, ptr, length);
+       }
+       strbuf[length] = '\0';
+       return strbuf;
+}
+
+/*
+ * 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.
+ *
+ * This function allocates memory from a buffer with capture session lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts or opens a new capture.
+ */
+guint8 *
+tvb_get_seasonal_string(tvbuff_t *tvb, gint offset, gint length)
+{
+       const guint8 *ptr;
+       guint8 *strbuf = NULL;
+
+       tvb_ensure_bytes_exist(tvb, offset, length);
+
+       ptr = ensure_contiguous(tvb, offset, length);
+       strbuf = se_alloc(length + 1);
+       if (length != 0) {
                memcpy(strbuf, ptr, length);
+       }
        strbuf[length] = '\0';
        return strbuf;
 }
@@ -1724,7 +2299,7 @@ tvb_get_string(tvbuff_t *tvb, gint offset, gint length)
  * 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
+ * and return a pointer to the string. Also return the length of the
  * string (including the terminating null) through a pointer.
  */
 guint8 *
@@ -1736,7 +2311,61 @@ tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
        size = tvb_strsize(tvb, offset);
        strptr = g_malloc(size);
        tvb_memcpy(tvb, strptr, offset, size);
-       *lengthp = size;
+       if (lengthp)
+               *lengthp = size;
+       return strptr;
+}
+/*
+ * 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.
+ *
+ * This function allocates memory from a buffer with packet lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts decoding the next packet.
+ * Do not use this function if you want the allocated memory to be persistent
+ * after the current packet has been dissected.
+ */
+guint8 *
+tvb_get_ephemeral_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
+{
+       guint size;
+       guint8 *strptr;
+
+       size = tvb_strsize(tvb, offset);
+       strptr = ep_alloc(size);
+       tvb_memcpy(tvb, strptr, offset, size);
+       if (lengthp)
+               *lengthp = size;
+       return strptr;
+}
+
+/*
+ * 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.
+ *
+ * This function allocates memory from a buffer with capture session lifetime.
+ * You do not have to free this buffer, it will be automatically freed
+ * when wireshark starts or opens a new capture.
+ */
+guint8 *
+tvb_get_seasonal_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
+{
+       guint size;
+       guint8 *strptr;
+
+       size = tvb_strsize(tvb, offset);
+       strptr = se_alloc(size);
+       tvb_memcpy(tvb, strptr, offset, size);
+       if (lengthp)
+               *lengthp = size;
        return strptr;
 }
 
@@ -1744,7 +2373,7 @@ tvb_get_stringz(tvbuff_t *tvb, gint offset, gint *lengthp)
  * 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().
+ * In this way, it acts like g_snprintf().
  *
  * bufsize MUST be greater than 0.
  *
@@ -1767,10 +2396,10 @@ _tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer,
        gint    limit, len;
        gboolean decreased_max = FALSE;
 
-       check_offset_length(tvb, offset, 0, &abs_offset, &junk_length);
+       check_offset_length(tvb->length, tvb->reported_length, offset, 0, &abs_offset, &junk_length);
 
        /* There must at least be room for the terminating NUL. */
-       g_assert(bufsize != 0);
+       DISSECTOR_ASSERT(bufsize != 0);
 
        /* If there's no room for anything else, just return the NUL. */
        if (bufsize == 1) {
@@ -1791,13 +2420,13 @@ _tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer,
        /* This should not happen because check_offset_length() would
         * have already thrown an exception if 'offset' were out-of-bounds.
         */
-       g_assert(len != -1);
+       DISSECTOR_ASSERT(len != -1);
 
        /*
         * If we've been passed a negative number, bufsize will
         * be huge.
         */
-       g_assert(bufsize <= G_MAXINT);
+       DISSECTOR_ASSERT(bufsize <= G_MAXINT);
 
        if ((guint)len < bufsize) {
                limit = len;
@@ -1833,7 +2462,7 @@ _tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer,
  * 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().
+ * In this way, it acts like g_snprintf().
  *
  * 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
@@ -1847,6 +2476,8 @@ tvb_get_nstringz(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
 {
        gint bytes_copied;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        return _tvb_get_nstringz(tvb, offset, bufsize, buffer, &bytes_copied);
 }
 
@@ -1859,6 +2490,8 @@ tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
 {
        gint    len, bytes_copied;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        len = _tvb_get_nstringz(tvb, offset, bufsize, buffer, &bytes_copied);
 
        if (len == -1) {
@@ -1887,11 +2520,11 @@ tvb_get_nstringz0(tvbuff_t *tvb, gint offset, guint bufsize, guint8* buffer)
  *
  * Set "*next_offset" to the offset of the character past the line
  * terminator, or past the end of the buffer if we don't find a line
- * terminator.  (It's not set if we return -1.)
+ * terminator. (It's not set if we return -1.)
  */
 gint
 tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
-    gboolean desegment)
+       gboolean desegment)
 {
        gint eob_offset;
        gint eol_offset;
@@ -1908,7 +2541,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, (const guint8 *)"\r\n");
        if (eol_offset == -1) {
                /*
                 * No CR or LF - line is presumably continued in next packet.
@@ -1925,7 +2558,8 @@ tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
                         * Pretend the line runs to the end of the tvbuff.
                         */
                        linelen = eob_offset - offset;
-                       *next_offset = eob_offset;
+                       if (next_offset)
+                               *next_offset = eob_offset;
                }
        } else {
                /*
@@ -1979,7 +2613,8 @@ tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
                 * character in the line, skipping over the last character
                 * in the line terminator.
                 */
-               *next_offset = eol_offset + 1;
+               if (next_offset)
+                       *next_offset = eol_offset + 1;
        }
        return linelen;
 }
@@ -2004,7 +2639,7 @@ tvb_find_line_end(tvbuff_t *tvb, gint offset, int len, gint *next_offset,
  */
 gint
 tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
-    gint *next_offset)
+       gint *next_offset)
 {
        gint cur_offset, char_offset;
        gboolean is_quoted;
@@ -2023,7 +2658,7 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
        cur_offset = offset;
        is_quoted = FALSE;
        for (;;) {
-               /*
+                       /*
                 * Is this part of the string quoted?
                 */
                if (is_quoted) {
@@ -2031,13 +2666,13 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                         * Yes - look only for the terminating quote.
                         */
                        char_offset = tvb_find_guint8(tvb, cur_offset, len,
-                           '"');
+                               '"');
                } else {
                        /*
                         * Look either for a CR, an LF, or a '"'.
                         */
                        char_offset = tvb_pbrk_guint8(tvb, cur_offset, len,
-                           "\r\n\"");
+                               (const guint8 *)"\r\n\"");
                }
                if (char_offset == -1) {
                        /*
@@ -2046,7 +2681,8 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                         * We pretend the line runs to the end of the tvbuff.
                         */
                        linelen = eob_offset - offset;
-                       *next_offset = eob_offset;
+                       if (next_offset)
+                               *next_offset = eob_offset;
                        break;
                }
 
@@ -2087,8 +2723,8 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                                         * Yes; is it followed by an LF?
                                         */
                                        if (char_offset + 1 < eob_offset &&
-                                           tvb_get_guint8(tvb, char_offset + 1)
-                                             == '\n') {
+                                               tvb_get_guint8(tvb, char_offset + 1)
+                                                 == '\n') {
                                                /*
                                                 * Yes; skip over the CR.
                                                 */
@@ -2102,7 +2738,8 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                                 * over the last character in the line
                                 * terminator, and quit.
                                 */
-                               *next_offset = char_offset + 1;
+                               if (next_offset)
+                                       *next_offset = char_offset + 1;
                                break;
                        }
                }
@@ -2119,27 +2756,87 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, gint offset, int len,
                         * We pretend the line runs to the end of the tvbuff.
                         */
                        linelen = eob_offset - offset;
-                       *next_offset = eob_offset;
+                       if (next_offset)
+                               *next_offset = eob_offset;
                        break;
                }
        }
        return linelen;
 }
 
+/*
+ * Copied from the mgcp dissector. (This function should be moved to /epan )
+ * tvb_skip_wsp - Returns the position in tvb of the first non-whitespace
+ *                               character following offset or offset + maxlength -1 whichever
+ *                               is smaller.
+ *
+ * Parameters:
+ * tvb - The tvbuff in which we are skipping whitespace.
+ * offset - The offset in tvb from which we begin trying to skip whitespace.
+ * maxlength - The maximum distance from offset that we may try to skip
+ * whitespace.
+ *
+ * Returns: The position in tvb of the first non-whitespace
+ *                     character following offset or offset + maxlength -1 whichever
+ *                     is smaller.
+ */
+gint tvb_skip_wsp(tvbuff_t* tvb, gint offset, gint maxlength)
+{
+       gint counter = offset;
+       gint end = offset + maxlength,tvb_len;
+       guint8 tempchar;
+
+       /* Get the length remaining */
+       tvb_len = tvb_length(tvb);
+       end = offset + maxlength;
+       if (end >= tvb_len)
+       {
+               end = tvb_len;
+       }
+
+       /* Skip past spaces, tabs, CRs and LFs until run out or meet something else */
+       for (counter = offset;
+                counter < end &&
+                 ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
+                 tempchar == '\t' || tempchar == '\r' || tempchar == '\n');
+                counter++);
+
+       return (counter);
+}
+
+gint tvb_skip_wsp_return(tvbuff_t* tvb, gint offset){
+       gint counter = offset;
+       gint end;
+       guint8 tempchar;
+       end = 0;
+
+       for(counter = offset; counter > end &&
+               ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
+               tempchar == '\t' || tempchar == '\n' || tempchar == '\r'); counter--);
+       counter++;
+       return (counter);
+}
+
+
 /*
  * Format a bunch of data from a tvbuff as bytes, returning a pointer
- * to the string with the formatted data.
+ * to the string with the formatted data, with "punct" as a byte
+ * separator.
  */
 gchar *
-tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
+tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, gchar punct)
 {
-       return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
+       return bytes_to_str_punct(tvb_get_ptr(tvb, offset, len), len, punct);
 }
 
-tvbuff_t *
-tvb_get_ds_tvb(tvbuff_t *tvb)
+/*
+ * Format a bunch of data from a tvbuff as bytes, returning a pointer
+ * to the string with the formatted data.
+ */
+gchar *
+tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len)
 {
-       return tvb->ds_tvb;
+       return bytes_to_str(tvb_get_ptr(tvb, offset, len), len);
 }
 
 /* Find a needle tvbuff within a haystack tvbuff. */
@@ -2152,6 +2849,8 @@ tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset)
        const guint     needle_len = needle_tvb->length;
        const guint8    *location;
 
+       DISSECTOR_ASSERT(haystack_tvb && haystack_tvb->initialized);
+
        if (haystack_tvb->length < 1 || needle_tvb->length < 1) {
                return -1;
        }
@@ -2160,18 +2859,294 @@ tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset)
        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,
+       check_offset_length(haystack_tvb->length, haystack_tvb->reported_length, 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 (gint) (location - haystack_data);
        }
 
        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;
+       }
+
+       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;
+       bufsiz = CLAMP(bufsiz, TVB_Z_MIN_BUFSIZ, TVB_Z_MAX_BUFSIZ);
+
+#ifdef TVB_Z_DEBUG
+       printf("bufsiz: %u bytes\n", bufsiz);
+#endif
+
+       next = compr;
+
+       strm = g_new0(z_stream, 1);
+       strm->next_in = next;
+       strm->avail_in = comprlen;
+
+       strmbuf = g_malloc0(bufsiz);
+       strm->next_out = strmbuf;
+       strm->avail_out = bufsiz;
+
+       err = inflateInit2(strm, wbits);
+       inits_done = 1;
+       if (err != Z_OK) {
+               inflateEnd(strm);
+               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);
+
+                               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.
+                        */
+                       inflateEnd(strm);
+                       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 {
+                               inflateEnd(strm);
+                               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 - compr) < comprlen && *c != '\0') {
+                                       c++;
+                               }
+
+                               c++;
+                       }
+
+                       if (flags & (1 << 4)) {
+                               /* A null terminated comment */
+
+                               while ((c - compr) < comprlen && *c != '\0') {
+                                       c++;
+                               }
+
+                               c++;
+                       }
+
+
+                       inflateReset(strm);
+                       next = c;
+                       strm->next_in = next;
+                       if (c - compr > comprlen) {
+                               inflateEnd(strm);
+                               g_free(strm);
+                               g_free(compr);
+                               g_free(strmbuf);
+                               return NULL;
+                       }
+                       comprlen -= (int) (c - compr);
+
+                       inflateEnd(strm);
+                       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;
+
+                       inflateEnd(strm);
+                       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 {
+                       inflateEnd(strm);
+                       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_uncompress(tvbuff_t *tvb _U_, int offset _U_, int comprlen _U_)
+{
+       return NULL;
+}
+#endif
+
+tvbuff_t* tvb_child_uncompress(tvbuff_t *parent _U_, tvbuff_t *tvb, int offset, int comprlen)
+{
+       tvbuff_t *new_tvb = tvb_uncompress(tvb, offset, comprlen);
+       if (new_tvb)
+               tvb_set_child_real_data_tvbuff (parent, new_tvb);
+       return new_tvb;
+}
+