PA-PK-AS-REP-Win2k ::= PaPkAsRep
[metze/wireshark/wip.git] / epan / tvbuff.c
index 12d608a4e38922ed214b9f2a0db67feedae62cf6..c759b91a26fb3f282808386a70fca088508d0df3 100644 (file)
@@ -9,8 +9,6 @@
  *             the data of a backing tvbuff, or can be a composite of
  *             other tvbuffs.
  *
- * $Id$
- *
  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
  *
  * Code to convert IEEE floating point formats to native floating point
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include "config.h"
 
 #include <string.h>
+#include <stdio.h>
+#include <errno.h>
 
 #include "wsutil/pint.h"
 #include "wsutil/sign_ext.h"
 #include "wsutil/unicode-utils.h"
+#include "wsutil/nstime.h"
+#include "wsutil/time_util.h"
 #include "tvbuff.h"
 #include "tvbuff-int.h"
 #include "strutil.h"
 #include "proto.h"     /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
 #include "exceptions.h"
 
+/*
+ * Just make sure we include the prototype for strptime as well
+ * (needed for glibc 2.2) but make sure we do this only if not
+ * yet defined.
+ */
+#include <time.h>
+/*#ifndef HAVE_STRPTIME*/
+#ifndef strptime
+#include "wsutil/strptime.h"
+#endif
+ /*#endif*/
+
 static guint64
 _tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits);
 
+static inline gint
+_tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset);
+
+static inline const guint8*
+ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length);
+
+static inline guint8 *
+tvb_get_raw_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const gint length);
+
 tvbuff_t *
 tvb_new(const struct tvb_ops *ops)
 {
@@ -63,15 +74,16 @@ tvb_new(const struct tvb_ops *ops)
 
        tvb = (tvbuff_t *) g_slice_alloc(size);
 
-       tvb->next            = NULL;
-       tvb->ops             = ops;
-       tvb->initialized     = FALSE;
-       tvb->flags           = 0;
-       tvb->length          = 0;
-       tvb->reported_length = 0;
-       tvb->real_data       = NULL;
-       tvb->raw_offset      = -1;
-       tvb->ds_tvb          = NULL;
+       tvb->next                = NULL;
+       tvb->ops                 = ops;
+       tvb->initialized         = FALSE;
+       tvb->flags               = 0;
+       tvb->length              = 0;
+       tvb->reported_length     = 0;
+       tvb->contained_length    = 0;
+       tvb->real_data           = NULL;
+       tvb->raw_offset          = -1;
+       tvb->ds_tvb              = NULL;
 
        return tvb;
 }
@@ -149,25 +161,85 @@ tvb_add_to_chain(tvbuff_t *parent, tvbuff_t *child)
 static inline int
 validate_offset(const tvbuff_t *tvb, const guint abs_offset)
 {
-       if (G_LIKELY(abs_offset <= tvb->length))
+       if (G_LIKELY(abs_offset <= tvb->length)) {
+               /* It's OK. */
                return 0;
-       else if (abs_offset <= tvb->reported_length)
+       }
+
+       /*
+        * It's not OK, but why?  Which boundaries is it
+        * past?
+        */
+       if (abs_offset <= tvb->contained_length) {
+               /*
+                * It's past the captured length, but not past
+                * the reported end of any parent tvbuffs from
+                * which this is constructed, or the reported
+                * end of this tvbuff, so it's out of bounds
+                * solely because we're past the end of the
+                * captured data.
+                */
                return BoundsError;
-       else if (tvb->flags & TVBUFF_FRAGMENT)
+       }
+
+       /*
+        * There's some actual packet boundary, not just the
+        * artificial boundary imposed by packet slicing, that
+        * we're past.
+        */
+       if (abs_offset <= tvb->reported_length) {
+               /*
+                * We're within the bounds of what this tvbuff
+                * purportedly contains, based on some length
+                * value, but we're not within the bounds of
+                * something from which this tvbuff was
+                * extracted, so that length value ran past
+                * the end of some parent tvbuff.
+                */
+               return ContainedBoundsError;
+       }
+
+       /*
+        * OK, we're past the bounds of what this tvbuff
+        * purportedly contains.
+        */
+       if (tvb->flags & TVBUFF_FRAGMENT) {
+               /*
+                * This tvbuff is the first fragment of a larger
+                * packet that hasn't been reassembled, so we
+                * assume that's the source of the prblem - if
+                * we'd reassembled the packet, we wouldn't
+                * have gone past the end.
+                *
+                * That might not be true, but for at least
+                * some forms of reassembly, such as IP
+                * reassembly, you don't know how big the
+                * reassembled packet is unless you reassemble
+                * it, so, in those cases, we can't determine
+                * whether we would have gone past the end
+                * had we reassembled the packet.
+                */
                return FragmentBoundsError;
-       else
-               return ReportedBoundsError;
+       }
+
+       /*
+        * OK, it looks as if we ran past the claimed length
+        * of data.
+        */
+       return ReportedBoundsError;
 }
 
-static int
+static inline int
 compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
 {
        if (offset >= 0) {
                /* Positive offset - relative to the beginning of the packet. */
-               if ((guint) offset <= tvb->length) {
+               if (G_LIKELY((guint) offset <= tvb->length)) {
                        *offset_ptr = offset;
-               } else if ((guint) offset <= tvb->reported_length) {
+               } else if ((guint) offset <= tvb->contained_length) {
                        return BoundsError;
+               } else if ((guint) offset <= tvb->reported_length) {
+                       return ContainedBoundsError;
                } else if (tvb->flags & TVBUFF_FRAGMENT) {
                        return FragmentBoundsError;
                } else {
@@ -176,10 +248,12 @@ compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
        }
        else {
                /* Negative offset - relative to the end of the packet. */
-               if ((guint) -offset <= tvb->length) {
+               if (G_LIKELY((guint) -offset <= tvb->length)) {
                        *offset_ptr = tvb->length + offset;
-               } else if ((guint) -offset <= tvb->reported_length) {
+               } else if ((guint) -offset <= tvb->contained_length) {
                        return BoundsError;
+               } else if ((guint) -offset <= tvb->reported_length) {
+                       return ContainedBoundsError;
                } else if (tvb->flags & TVBUFF_FRAGMENT) {
                        return FragmentBoundsError;
                } else {
@@ -190,7 +264,7 @@ compute_offset(const tvbuff_t *tvb, const gint offset, guint *offset_ptr)
        return 0;
 }
 
-static int
+static inline int
 compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offset_ptr, guint *rem_len)
 {
        int exception;
@@ -205,8 +279,11 @@ compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offs
 /* Computes the absolute offset and length based on a possibly-negative offset
  * and a length that is possible -1 (which means "to the end of the data").
  * Returns integer indicating whether the offset is in bounds (0) or
- * not (exception number). The integer ptrs are modified with the new offset and length.
- * No exception is thrown.
+ * not (exception number). The integer ptrs are modified with the new offset,
+ * captured (available) length, and contained length (amount that's present
+ * in the parent tvbuff based on its reported length).
+ * No exception is thrown; on success, we return 0, otherwise we return an
+ * exception for the caller to throw if appropriate.
  *
  * XXX - we return success (0), if the offset is positive and right
  * after the end of the tvbuff (i.e., equal to the length).  We do this
@@ -215,13 +292,13 @@ compute_offset_and_remaining(const tvbuff_t *tvb, const gint offset, guint *offs
  * left for the next protocol - we want the next protocol to be the one
  * that gets an exception, so the error is reported as an error in that
  * protocol rather than the containing protocol.  */
-static int
+static inline int
 check_offset_length_no_exception(const tvbuff_t *tvb,
                                 const gint offset, gint const length_val,
                                 guint *offset_ptr, guint *length_ptr)
 {
        guint end_offset;
-       int exception;
+       int   exception;
 
        DISSECTOR_ASSERT(offset_ptr);
        DISSECTOR_ASSERT(length_ptr);
@@ -259,7 +336,7 @@ check_offset_length_no_exception(const tvbuff_t *tvb,
 /* 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
+static inline void
 check_offset_length(const tvbuff_t *tvb,
                    const gint offset, gint const length_val,
                    guint *offset_ptr, guint *length_ptr)
@@ -299,12 +376,14 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
        guint8        left, right, remaining_bits, *buf;
        const guint8 *data;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        byte_offset = bit_offset >> 3;
        left = bit_offset % 8; /* for left-shifting */
        right = 8 - left; /* for right-shifting */
 
        if (no_of_bits == -1) {
-               datalen = tvb_length_remaining(tvb, byte_offset);
+               datalen = _tvb_captured_length_remaining(tvb, byte_offset);
                remaining_bits = 0;
        } else {
                datalen = no_of_bits >> 3;
@@ -316,18 +395,18 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
 
        /* already aligned -> shortcut */
        if ((left == 0) && (remaining_bits == 0)) {
-               return tvb_new_subset(tvb, byte_offset, datalen, -1);
+               return tvb_new_subset_length_caplen(tvb, byte_offset, datalen, datalen);
        }
 
        DISSECTOR_ASSERT(datalen>0);
 
        /* if at least one trailing byte is available, we must use the content
-       * of that byte for the last shift (i.e. tvb_get_ptr() must use datalen + 1
-       * if non extra byte is available, the last shifted byte requires
-       * special treatment
-       */
-       if (tvb_length_remaining(tvb, byte_offset) > datalen) {
-               data = tvb_get_ptr(tvb, byte_offset, datalen + 1);
+       * of that byte for the last shift (i.e. tvb_get_ptr() must use datalen + 1
+       * if non extra byte is available, the last shifted byte requires
+       * special treatment
+       */
+       if (_tvb_captured_length_remaining(tvb, byte_offset) > datalen) {
+               data = ensure_contiguous(tvb, byte_offset, datalen + 1); /* tvb_get_ptr */
 
                /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */
                buf = (guint8 *)g_malloc(datalen);
@@ -336,7 +415,7 @@ tvb_new_octet_aligned(tvbuff_t *tvb, guint32 bit_offset, gint32 no_of_bits)
                for (i = 0; i < datalen; i++)
                        buf[i] = (data[i] << left) | (data[i+1] >> right);
        } else {
-               data = tvb_get_ptr(tvb, byte_offset, datalen);
+               data = ensure_contiguous(tvb, byte_offset, datalen); /* tvb_get_ptr() */
 
                /* Do this allocation AFTER tvb_get_ptr() (which could throw an exception) */
                buf = (guint8 *)g_malloc(datalen);
@@ -358,8 +437,11 @@ static tvbuff_t *
 tvb_generic_clone_offset_len(tvbuff_t *tvb, guint offset, guint len)
 {
        tvbuff_t *cloned_tvb;
+       guint8 *data;
 
-       guint8 *data = (guint8 *) g_malloc(len);
+       DISSECTOR_ASSERT(tvb_bytes_exist(tvb, offset, len));
+
+       data = (guint8 *) g_malloc(len);
 
        tvb_memcpy(tvb, data, offset, len);
 
@@ -390,18 +472,32 @@ tvb_clone(tvbuff_t *tvb)
 }
 
 guint
-tvb_length(const tvbuff_t *tvb)
+tvb_captured_length(const tvbuff_t *tvb)
 {
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        return tvb->length;
 }
 
+/* For tvbuff internal use */
+static inline gint
+_tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
+{
+       guint abs_offset = 0, rem_length;
+       int   exception;
+
+       exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
+       if (exception)
+               return 0;
+
+       return rem_length;
+}
+
 gint
-tvb_length_remaining(const tvbuff_t *tvb, const gint offset)
+tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset, rem_length;
-       int exception;
+       guint abs_offset = 0, rem_length;
+       int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -413,9 +509,9 @@ tvb_length_remaining(const tvbuff_t *tvb, const gint offset)
 }
 
 guint
-tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset)
+tvb_ensure_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset, rem_length;
+       guint abs_offset = 0, rem_length = 0;
        int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
@@ -430,14 +526,15 @@ tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset)
                 * There aren't any bytes available, so throw the appropriate
                 * exception.
                 */
-               if (abs_offset >= tvb->reported_length) {
-                       if (tvb->flags & TVBUFF_FRAGMENT) {
-                               THROW(FragmentBoundsError);
-                       } else {
-                               THROW(ReportedBoundsError);
-                       }
-               } else
+               if (abs_offset < tvb->contained_length) {
                        THROW(BoundsError);
+               } else if (abs_offset < tvb->reported_length) {
+                       THROW(ContainedBoundsError);
+               } else if (tvb->flags & TVBUFF_FRAGMENT) {
+                       THROW(FragmentBoundsError);
+               } else {
+                       THROW(ReportedBoundsError);
+               }
        }
        return rem_length;
 }
@@ -450,11 +547,18 @@ tvb_ensure_length_remaining(const tvbuff_t *tvb, const gint offset)
 gboolean
 tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length)
 {
-       guint abs_offset, abs_length;
-       int exception;
+       guint abs_offset = 0, abs_length;
+       int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
+       /*
+        * Negative lengths are not possible and indicate a bug (e.g. arithmetic
+        * error or an overly large value from packet data).
+        */
+       if (length < 0)
+               return FALSE;
+
        exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length);
        if (exception)
                return FALSE;
@@ -462,6 +566,24 @@ tvb_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length)
        return TRUE;
 }
 
+/* Validates that 'length' bytes, where 'length' is a 64-bit unsigned
+ * integer, are available starting from offset (pos/neg). Throws an
+ * exception if they aren't. */
+void
+tvb_ensure_bytes_exist64(const tvbuff_t *tvb, const gint offset, const guint64 length)
+{
+       /*
+        * Make sure the value fits in a signed integer; if not, assume
+        * that means that it's too big.
+        */
+       if (length > G_MAXINT) {
+               THROW(ReportedBoundsError);
+       }
+
+       /* OK, now cast it and try it with tvb_ensure_bytes_exist(). */
+       tvb_ensure_bytes_exist(tvb, offset, (gint)length);
+}
+
 /* Validates that 'length' bytes are available starting from
  * offset (pos/neg). Throws an exception if they aren't. */
 void
@@ -492,10 +614,12 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
 
        if (offset >= 0) {
                /* Positive offset - relative to the beginning of the packet. */
-               if ((guint) offset <= tvb->length) {
+               if (G_LIKELY((guint) offset <= tvb->length)) {
                        real_offset = offset;
-               } else if ((guint) offset <= tvb->reported_length) {
+               } else if ((guint) offset <= tvb->contained_length) {
                        THROW(BoundsError);
+               } else if ((guint) offset <= tvb->reported_length) {
+                       THROW(ContainedBoundsError);
                } else if (tvb->flags & TVBUFF_FRAGMENT) {
                        THROW(FragmentBoundsError);
                } else {
@@ -504,10 +628,12 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
        }
        else {
                /* Negative offset - relative to the end of the packet. */
-               if ((guint) -offset <= tvb->length) {
+               if (G_LIKELY((guint) -offset <= tvb->length)) {
                        real_offset = tvb->length + offset;
-               } else if ((guint) -offset <= tvb->reported_length) {
+               } else if ((guint) -offset <= tvb->contained_length) {
                        THROW(BoundsError);
+               } else if ((guint) -offset <= tvb->reported_length) {
+                       THROW(ContainedBoundsError);
                } else if (tvb->flags & TVBUFF_FRAGMENT) {
                        THROW(FragmentBoundsError);
                } else {
@@ -528,8 +654,10 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
 
        if (G_LIKELY(end_offset <= tvb->length))
                return;
-       else if (end_offset <= tvb->reported_length)
+       else if (end_offset <= tvb->contained_length)
                THROW(BoundsError);
+       else if (end_offset <= tvb->reported_length)
+               THROW(ContainedBoundsError);
        else if (tvb->flags & TVBUFF_FRAGMENT)
                THROW(FragmentBoundsError);
        else
@@ -539,8 +667,8 @@ tvb_ensure_bytes_exist(const tvbuff_t *tvb, const gint offset, const gint length
 gboolean
 tvb_offset_exists(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset;
-       int exception;
+       guint abs_offset = 0;
+       int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -570,8 +698,8 @@ tvb_reported_length(const tvbuff_t *tvb)
 gint
 tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset;
-       int exception;
+       guint abs_offset = 0;
+       int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -589,7 +717,7 @@ tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
  * whose headers contain an explicit length and where the calling
  * dissector's payload may include padding as well as the packet for
  * this protocol.
- * Also adjusts the data length. */
+ * Also adjusts the available and contained length. */
 void
 tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
 {
@@ -601,6 +729,8 @@ tvb_set_reported_length(tvbuff_t *tvb, const guint reported_length)
        tvb->reported_length = reported_length;
        if (reported_length < tvb->length)
                tvb->length = reported_length;
+       if (reported_length < tvb->contained_length)
+               tvb->contained_length = reported_length;
 }
 
 guint
@@ -619,11 +749,11 @@ tvb_offset_from_real_beginning(const tvbuff_t *tvb)
        return tvb_offset_from_real_beginning_counter(tvb, 0);
 }
 
-static const guint8*
+static inline const guint8*
 ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint length, int *pexception)
 {
-       guint abs_offset, abs_length;
-       int exception;
+       guint abs_offset = 0, abs_length = 0;
+       int   exception;
 
        exception = check_offset_length_no_exception(tvb, offset, length, &abs_offset, &abs_length);
        if (exception) {
@@ -632,6 +762,14 @@ ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint leng
                return NULL;
        }
 
+       /*
+        * Special case: if the caller (e.g. tvb_get_ptr) requested no data,
+        * then it is acceptable to have an empty tvb (!tvb->real_data).
+        */
+       if (length == 0) {
+               return NULL;
+       }
+
        /*
         * We know that all the data is present in the tvbuff, so
         * no exceptions should be thrown.
@@ -646,21 +784,21 @@ ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint leng
        return NULL;
 }
 
-static const guint8*
+static inline const guint8*
 ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length)
 {
        int           exception = 0;
        const guint8 *p;
 
        p = ensure_contiguous_no_exception(tvb, offset, length, &exception);
-       if (p == NULL) {
+       if (p == NULL && length != 0) {
                DISSECTOR_ASSERT(exception > 0);
                THROW(exception);
        }
        return p;
 }
 
-static const guint8*
+static inline const guint8*
 fast_ensure_contiguous(tvbuff_t *tvb, const gint offset, const guint length)
 {
        guint end_offset;
@@ -677,45 +815,21 @@ fast_ensure_contiguous(tvbuff_t *tvb, const gint offset, const guint length)
        u_offset = offset;
        end_offset = u_offset + length;
 
-       if (end_offset <= tvb->length) {
+       if (G_LIKELY(end_offset <= tvb->length)) {
                return tvb->real_data + u_offset;
+       } else if (end_offset <= tvb->contained_length) {
+               THROW(BoundsError);
+       } else if (end_offset <= tvb->reported_length) {
+               THROW(ContainedBoundsError);
+       } else if (tvb->flags & TVBUFF_FRAGMENT) {
+               THROW(FragmentBoundsError);
+       } else {
+               THROW(ReportedBoundsError);
        }
-
-       if (end_offset > tvb->reported_length) {
-               if (tvb->flags & TVBUFF_FRAGMENT) {
-                       THROW(FragmentBoundsError);
-               } else {
-                       THROW(ReportedBoundsError);
-               }
-               /* not reached */
-       }
-       THROW(BoundsError);
        /* not reached */
        return NULL;
 }
 
-static const guint8*
-guint8_pbrk(const guint8* haystack, size_t haystacklen, const guint8 *needles, guchar *found_needle)
-{
-       gchar         tmp[256] = { 0 };
-       const guint8 *haystack_end;
-
-       while (*needles)
-               tmp[*needles++] = 1;
-
-       haystack_end = haystack + haystacklen;
-       while (haystack < haystack_end) {
-               if (tmp[*haystack]) {
-                       if (found_needle)
-                               *found_needle = *haystack;
-                       return haystack;
-               }
-               haystack++;
-       }
-
-       return NULL;
-}
-
 
 
 /************** ACCESSORS **************/
@@ -723,7 +837,7 @@ guint8_pbrk(const guint8* haystack, size_t haystacklen, const guint8 *needles, g
 void *
 tvb_memcpy(tvbuff_t *tvb, void *target, const gint offset, size_t length)
 {
-       guint   abs_offset, abs_length;
+       guint   abs_offset = 0, abs_length = 0;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -748,9 +862,17 @@ tvb_memcpy(tvbuff_t *tvb, void *target, const gint offset, size_t length)
        if (tvb->ops->tvb_memcpy)
                return tvb->ops->tvb_memcpy(tvb, target, abs_offset, abs_length);
 
-       /* XXX, fallback to slower method */
-
-       DISSECTOR_ASSERT_NOT_REACHED();
+       /*
+        * If the length is 0, there's nothing to do.
+        * (tvb->real_data could be null if it's allocated with
+        * a size of length.)
+        */
+       if (length != 0) {
+               /*
+                * XXX, fallback to slower method
+                */
+               DISSECTOR_ASSERT_NOT_REACHED();
+       }
        return NULL;
 }
 
@@ -773,8 +895,8 @@ tvb_memcpy(tvbuff_t *tvb, void *target, const gint offset, size_t length)
 void *
 tvb_memdup(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, size_t length)
 {
-       guint   abs_offset, abs_length;
-       void    *duped;
+       guint  abs_offset = 0, abs_length = 0;
+       void  *duped;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -798,7 +920,16 @@ tvb_get_guint8(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint8));
+       ptr = fast_ensure_contiguous(tvb, offset, 1);
+       return *ptr;
+}
+
+gint8
+tvb_get_gint8(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 1);
        return *ptr;
 }
 
@@ -807,7 +938,16 @@ tvb_get_ntohs(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
+       ptr = fast_ensure_contiguous(tvb, offset, 2);
+       return pntoh16(ptr);
+}
+
+gint16
+tvb_get_ntohis(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 2);
        return pntoh16(ptr);
 }
 
@@ -820,12 +960,31 @@ tvb_get_ntoh24(tvbuff_t *tvb, const gint offset)
        return pntoh24(ptr);
 }
 
+gint32
+tvb_get_ntohi24(tvbuff_t *tvb, const gint offset)
+{
+       guint32 ret;
+
+       ret = ws_sign_ext32(tvb_get_ntoh24(tvb, offset), 24);
+
+       return (gint32)ret;
+}
+
 guint32
 tvb_get_ntohl(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
+       ptr = fast_ensure_contiguous(tvb, offset, 4);
+       return pntoh32(ptr);
+}
+
+gint32
+tvb_get_ntohil(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 4);
        return pntoh32(ptr);
 }
 
@@ -891,29 +1050,182 @@ tvb_get_ntoh64(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
+       ptr = fast_ensure_contiguous(tvb, offset, 8);
        return pntoh64(ptr);
 }
 
+gint64
+tvb_get_ntohi64(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 8);
+       return pntoh64(ptr);
+}
+
+guint16
+tvb_get_guint16(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohs(tvb, offset);
+       } else {
+               return tvb_get_ntohs(tvb, offset);
+       }
+}
+
+gint16
+tvb_get_gint16(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohis(tvb, offset);
+       } else {
+               return tvb_get_ntohis(tvb, offset);
+       }
+}
+
+guint32
+tvb_get_guint24(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letoh24(tvb, offset);
+       } else {
+               return tvb_get_ntoh24(tvb, offset);
+       }
+}
+
+gint32
+tvb_get_gint24(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohi24(tvb, offset);
+       } else {
+               return tvb_get_ntohi24(tvb, offset);
+       }
+}
+
+guint32
+tvb_get_guint32(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohl(tvb, offset);
+       } else {
+               return tvb_get_ntohl(tvb, offset);
+       }
+}
+
+gint32
+tvb_get_gint32(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohil(tvb, offset);
+       } else {
+               return tvb_get_ntohil(tvb, offset);
+       }
+}
+
+guint64
+tvb_get_guint40(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letoh40(tvb, offset);
+       } else {
+               return tvb_get_ntoh40(tvb, offset);
+       }
+}
+
+gint64
+tvb_get_gint40(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohi40(tvb, offset);
+       } else {
+               return tvb_get_ntohi40(tvb, offset);
+       }
+}
+
+guint64
+tvb_get_guint48(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letoh48(tvb, offset);
+       } else {
+               return tvb_get_ntoh48(tvb, offset);
+       }
+}
+
+gint64
+tvb_get_gint48(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohi48(tvb, offset);
+       } else {
+               return tvb_get_ntohi48(tvb, offset);
+       }
+}
+
+guint64
+tvb_get_guint56(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letoh56(tvb, offset);
+       } else {
+               return tvb_get_ntoh56(tvb, offset);
+       }
+}
+
+gint64
+tvb_get_gint56(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohi56(tvb, offset);
+       } else {
+               return tvb_get_ntohi56(tvb, offset);
+       }
+}
+
+guint64
+tvb_get_guint64(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letoh64(tvb, offset);
+       } else {
+               return tvb_get_ntoh64(tvb, offset);
+       }
+}
+
+gint64
+tvb_get_gint64(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohi64(tvb, offset);
+       } else {
+               return tvb_get_ntohi64(tvb, offset);
+       }
+}
+
+gfloat
+tvb_get_ieee_float(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohieee_float(tvb, offset);
+       } else {
+               return tvb_get_ntohieee_float(tvb, offset);
+       }
+}
+
+gdouble
+tvb_get_ieee_double(tvbuff_t *tvb, const gint offset, const guint encoding) {
+       if (encoding & ENC_LITTLE_ENDIAN) {
+               return tvb_get_letohieee_double(tvb, offset);
+       } else {
+               return tvb_get_ntohieee_double(tvb, offset);
+       }
+}
+
 /*
  * Stuff for IEEE float handling on platforms that don't have IEEE
  * format as the native floating-point format.
  *
  * For now, we treat only the VAX as such a platform.
  *
- * XXX - other non-IEEE boxes that can run UNIX include some Crays,
- * and possibly other machines.
- *
- * It appears that the official Linux port to System/390 and
- * zArchitecture uses IEEE format floating point (not a
- * huge surprise).
- *
- * I don't know whether there are any other machines that
- * 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 Wireshark can run
- * use IEEE format (x86, 68k, SPARC, MIPS, PA-RISC, Alpha,
- * IA-64, and so on).
+ * XXX - other non-IEEE boxes that can run UN*X include some Crays,
+ * and possibly other machines.  However, I don't know whether there
+ * are any other machines that could run Wireshark and that don't use
+ * IEEE format.  As far as I know, all of the main current and past
+ * commercial microprocessor families on which OSes that support
+ * Wireshark can run use IEEE format (x86, ARM, 68k, SPARC, MIPS,
+ * PA-RISC, Alpha, IA-64, and so on), and it appears that the official
+ * Linux port to System/390 and zArchitecture uses IEEE format floating-
+ * point rather than IBM hex floating-point (not a huge surprise), so
+ * I'm not sure that leaves any 32-bit or larger UN*X or Windows boxes,
+ * other than VAXes, that don't use IEEE format.  If you're not running
+ * UN*X or Windows, the floating-point format is probably going to be
+ * the least of your problems in a port.
  */
 
 #if defined(vax)
@@ -1056,7 +1368,7 @@ tvb_get_ntohieee_float(tvbuff_t *tvb, const int offset)
        return get_ieee_float(tvb_get_ntohl(tvb, offset));
 #else
        union {
-               gfloat f;
+               gfloat  f;
                guint32 w;
        } ieee_fp_union;
 
@@ -1084,7 +1396,7 @@ tvb_get_ntohieee_double(tvbuff_t *tvb, const int offset)
        } ieee_fp_union;
 #endif
 
-#ifdef WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
        ieee_fp_union.w[0] = tvb_get_ntohl(tvb, offset);
        ieee_fp_union.w[1] = tvb_get_ntohl(tvb, offset+4);
 #else
@@ -1103,7 +1415,16 @@ tvb_get_letohs(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint16));
+       ptr = fast_ensure_contiguous(tvb, offset, 2);
+       return pletoh16(ptr);
+}
+
+gint16
+tvb_get_letohis(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 2);
        return pletoh16(ptr);
 }
 
@@ -1116,22 +1437,41 @@ tvb_get_letoh24(tvbuff_t *tvb, const gint offset)
        return pletoh24(ptr);
 }
 
+gint32
+tvb_get_letohi24(tvbuff_t *tvb, const gint offset)
+{
+       guint32 ret;
+
+       ret = ws_sign_ext32(tvb_get_letoh24(tvb, offset), 24);
+
+       return (gint32)ret;
+}
+
 guint32
 tvb_get_letohl(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint32));
+       ptr = fast_ensure_contiguous(tvb, offset, 4);
        return pletoh32(ptr);
 }
 
-guint64
-tvb_get_letoh40(tvbuff_t *tvb, const gint offset)
+gint32
+tvb_get_letohil(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, 5);
-       return pletoh40(ptr);
+       ptr = fast_ensure_contiguous(tvb, offset, 4);
+       return pletoh32(ptr);
+}
+
+guint64
+tvb_get_letoh40(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 5);
+       return pletoh40(ptr);
 }
 
 gint64
@@ -1187,7 +1527,16 @@ tvb_get_letoh64(tvbuff_t *tvb, const gint offset)
 {
        const guint8 *ptr;
 
-       ptr = fast_ensure_contiguous(tvb, offset, sizeof(guint64));
+       ptr = fast_ensure_contiguous(tvb, offset, 8);
+       return pletoh64(ptr);
+}
+
+gint64
+tvb_get_letohi64(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 8);
        return pletoh64(ptr);
 }
 
@@ -1234,7 +1583,7 @@ tvb_get_letohieee_double(tvbuff_t *tvb, const int offset)
        } ieee_fp_union;
 #endif
 
-#ifdef WORDS_BIGENDIAN
+#if G_BYTE_ORDER == G_BIG_ENDIAN
        ieee_fp_union.w[0] = tvb_get_letohl(tvb, offset+4);
        ieee_fp_union.w[1] = tvb_get_letohl(tvb, offset);
 #else
@@ -1248,6 +1597,252 @@ tvb_get_letohieee_double(tvbuff_t *tvb, const int offset)
 #endif
 }
 
+static inline void
+validate_single_byte_ascii_encoding(const guint encoding)
+{
+       const guint enc = encoding & ~ENC_STR_MASK;
+
+       switch (enc) {
+           case ENC_UTF_16:
+           case ENC_UCS_2:
+           case ENC_UCS_4:
+           case ENC_3GPP_TS_23_038_7BITS:
+           case ENC_EBCDIC:
+               REPORT_DISSECTOR_BUG("Invalid string encoding type passed to tvb_get_string_XXX");
+               break;
+           default:
+               break;
+       }
+       /* make sure something valid was set */
+       if (enc == 0)
+           REPORT_DISSECTOR_BUG("No string encoding type passed to tvb_get_string_XXX");
+}
+
+GByteArray*
+tvb_get_string_bytes(tvbuff_t *tvb, const gint offset, const gint length,
+                    const guint encoding, GByteArray *bytes, gint *endoff)
+{
+       const gchar *ptr    = (gchar*) tvb_get_raw_string(wmem_packet_scope(), tvb, offset, length);
+       const gchar *begin  = ptr;
+       const gchar *end    = NULL;
+       GByteArray  *retval = NULL;
+
+       errno = EDOM;
+
+       validate_single_byte_ascii_encoding(encoding);
+
+       if (endoff) *endoff = 0;
+
+       while (*begin == ' ') begin++;
+
+       if (*begin && bytes) {
+               if (hex_str_to_bytes_encoding(begin, bytes, &end, encoding, FALSE)) {
+                       if (bytes->len > 0) {
+                               if (endoff) *endoff = offset + (gint)(end - ptr);
+                               errno = 0;
+                               retval = bytes;
+                       }
+               }
+       }
+
+       return retval;
+}
+
+/* support hex-encoded time values? */
+nstime_t*
+tvb_get_string_time(tvbuff_t *tvb, const gint offset, const gint length,
+                   const guint encoding, nstime_t *ns, gint *endoff)
+{
+       const gchar *begin     = (gchar*) tvb_get_raw_string(wmem_packet_scope(), tvb, offset, length);
+       const gchar *ptr       = begin;
+       const gchar *end       = NULL;
+       struct tm    tm;
+       nstime_t*    retval    = NULL;
+       char         sign      = '+';
+       int          off_hr    = 0;
+       int          off_min   = 0;
+       int          num_chars = 0;
+       gboolean     matched   = FALSE;
+
+       errno = EDOM;
+
+       validate_single_byte_ascii_encoding(encoding);
+
+       DISSECTOR_ASSERT(ns);
+
+       memset(&tm, 0, sizeof(tm));
+       tm.tm_isdst = -1;
+       ns->secs    = 0;
+       ns->nsecs   = 0;
+
+       while (*ptr == ' ') ptr++;
+
+       if (*ptr) {
+               /* note: sscanf is known to be inconsistent across platforms with respect
+                  to whether a %n is counted as a return value or not, so we have to use
+                  '>=' a lot */
+               if ((encoding & ENC_ISO_8601_DATE_TIME) == ENC_ISO_8601_DATE_TIME) {
+                       /* TODO: using sscanf this many times is probably slow; might want
+                          to parse it by hand in the future */
+                       /* 2014-04-07T05:41:56+00:00 */
+                       if (sscanf(ptr, "%d-%d-%d%*c%d:%d:%d%c%d:%d%n",
+                           &tm.tm_year,
+                           &tm.tm_mon,
+                           &tm.tm_mday,
+                           &tm.tm_hour,
+                           &tm.tm_min,
+                           &tm.tm_sec,
+                           &sign,
+                           &off_hr,
+                           &off_min,
+                           &num_chars) >= 9)
+                       {
+                               matched = TRUE;
+                       }
+                       /* no seconds is ok */
+                       else if (sscanf(ptr, "%d-%d-%d%*c%d:%d%c%d:%d%n",
+                           &tm.tm_year,
+                           &tm.tm_mon,
+                           &tm.tm_mday,
+                           &tm.tm_hour,
+                           &tm.tm_min,
+                           &sign,
+                           &off_hr,
+                           &off_min,
+                           &num_chars) >= 8)
+                       {
+                               matched = TRUE;
+                       }
+                       /* 2007-04-05T14:30:56Z */
+                       else if (sscanf(ptr, "%d-%d-%d%*c%d:%d:%dZ%n",
+                           &tm.tm_year,
+                           &tm.tm_mon,
+                           &tm.tm_mday,
+                           &tm.tm_hour,
+                           &tm.tm_min,
+                           &tm.tm_sec,
+                           &num_chars) >= 6)
+                       {
+                               matched = TRUE;
+                               off_hr = 0;
+                               off_min = 0;
+                       }
+                       /* 2007-04-05T14:30Z no seconds is ok */
+                       else if (sscanf(ptr, "%d-%d-%d%*c%d:%dZ%n",
+                           &tm.tm_year,
+                           &tm.tm_mon,
+                           &tm.tm_mday,
+                           &tm.tm_hour,
+                           &tm.tm_min,
+                           &num_chars) >= 5)
+                       {
+                               matched = TRUE;
+                               off_hr = 0;
+                               off_min = 0;
+                       }
+
+                       if (matched) {
+                               errno = 0;
+                               end = ptr + num_chars;
+                               tm.tm_mon--;
+                               if (tm.tm_year > 1900) tm.tm_year -= 1900;
+                               if (sign == '-') off_hr = -off_hr;
+                       }
+               }
+               else if (encoding & ENC_ISO_8601_DATE) {
+                       /* 2014-04-07 */
+                       if (sscanf(ptr, "%d-%d-%d%n",
+                           &tm.tm_year,
+                           &tm.tm_mon,
+                           &tm.tm_mday,
+                           &num_chars) >= 3)
+                       {
+                               errno = 0;
+                               end = ptr + num_chars;
+                               tm.tm_mon--;
+                               if (tm.tm_year > 1900) tm.tm_year -= 1900;
+                       }
+               }
+               else if (encoding & ENC_ISO_8601_TIME) {
+                       /* 2014-04-07 */
+                       if (sscanf(ptr, "%d:%d:%d%n",
+                           &tm.tm_hour,
+                           &tm.tm_min,
+                           &tm.tm_sec,
+                           &num_chars) >= 2)
+                       {
+                               /* what should we do about day/month/year? */
+                               /* setting it to "now" for now */
+                               time_t time_now = time(NULL);
+                               struct tm *tm_now = gmtime(&time_now);
+                               if (tm_now != NULL) {
+                                       tm.tm_year = tm_now->tm_year;
+                                       tm.tm_mon  = tm_now->tm_mon;
+                                       tm.tm_mday = tm_now->tm_mday;
+                               } else {
+                                       /* The second before the Epoch */
+                                       tm.tm_year = 69;
+                                       tm.tm_mon = 12;
+                                       tm.tm_mday = 31;
+                               }
+                               end = ptr + num_chars;
+                               errno = 0;
+
+                       }
+               }
+               else if (encoding & ENC_RFC_822 || encoding & ENC_RFC_1123) {
+                       if (encoding & ENC_RFC_822) {
+                               /* this will unfortunately match ENC_RFC_1123 style
+                                  strings too, partially - probably need to do this the long way */
+                               end = strptime(ptr, "%a, %d %b %y %H:%M:%S", &tm);
+                               if (!end) end = strptime(ptr, "%a, %d %b %y %H:%M", &tm);
+                               if (!end) end = strptime(ptr, "%d %b %y %H:%M:%S", &tm);
+                               if (!end) end = strptime(ptr, "%d %b %y %H:%M", &tm);
+                       }
+                       else if (encoding & ENC_RFC_1123) {
+                               end = strptime(ptr, "%a, %d %b %Y %H:%M:%S", &tm);
+                               if (!end) end = strptime(ptr, "%a, %d %b %Y %H:%M", &tm);
+                               if (!end) end = strptime(ptr, "%d %b %Y %H:%M:%S", &tm);
+                               if (!end) end = strptime(ptr, "%d %b %Y %H:%M", &tm);
+                       }
+                       if (end) {
+                               errno = 0;
+                               if (*end == ' ') end++;
+                               if (g_ascii_strncasecmp(end, "UT", 2) == 0)
+                               {
+                                       end += 2;
+                               }
+                               else if (g_ascii_strncasecmp(end, "GMT", 3) == 0)
+                               {
+                                       end += 3;
+                               }
+                               else if (sscanf(end, "%c%2d%2d%n",
+                                   &sign,
+                                   &off_hr,
+                                   &off_min,
+                                   &num_chars) < 3)
+                               {
+                                       errno = ERANGE;
+                               }
+                               if (sign == '-') off_hr = -off_hr;
+                       }
+               }
+       }
+
+       if (errno == 0) {
+               ns->secs = mktime_utc (&tm);
+               if (off_hr > 0)
+                       ns->secs += (off_hr * 3600) + (off_min * 60);
+               else if (off_hr < 0)
+                       ns->secs -= ((-off_hr) * 3600) + (off_min * 60);
+               retval = ns;
+               if (endoff)
+                   *endoff = (gint)(offset + (end - begin));
+       }
+
+       return retval;
+}
+
 /* Fetch an IPv4 address, in network byte order.
  * We do *not* convert them to host byte order; we leave them in
  * network byte order. */
@@ -1264,7 +1859,7 @@ tvb_get_ipv4(tvbuff_t *tvb, const gint offset)
 
 /* Fetch an IPv6 address. */
 void
-tvb_get_ipv6(tvbuff_t *tvb, const gint offset, struct e_in6_addr *addr)
+tvb_get_ipv6(tvbuff_t *tvb, const gint offset, ws_in6_addr *addr)
 {
        const guint8 *ptr;
 
@@ -1299,12 +1894,12 @@ tvb_get_letohguid(tvbuff_t *tvb, const gint offset, e_guid_t *guid)
  * NOTE: to support code written when proto_tree_add_item() took a
  * gboolean as its last argument, with FALSE meaning "big-endian"
  * and TRUE meaning "little-endian", we treat any non-zero value of
- * "representation" as meaning "little-endian".
+ * "encoding" as meaning "little-endian".
  */
 void
-tvb_get_guid(tvbuff_t *tvb, const gint offset, e_guid_t *guid, const guint representation)
+tvb_get_guid(tvbuff_t *tvb, const gint offset, e_guid_t *guid, const guint encoding)
 {
-       if (representation) {
+       if (encoding) {
                tvb_get_letohguid(tvb, offset, guid);
        } else {
                tvb_get_ntohguid(tvb, offset, guid);
@@ -1363,8 +1958,8 @@ static guint64
 _tvb_get_bits64(tvbuff_t *tvb, guint bit_offset, const gint total_no_of_bits)
 {
        guint64 value;
-       guint octet_offset = bit_offset >> 3;
-       guint8 required_bits_in_first_octet = 8 - (bit_offset % 8);
+       guint   octet_offset = bit_offset >> 3;
+       guint8  required_bits_in_first_octet = 8 - (bit_offset % 8);
 
        if(required_bits_in_first_octet > total_no_of_bits)
        {
@@ -1446,7 +2041,7 @@ tvb_find_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 nee
        const guint8 *ptr;
        const guint8 *result;
 
-       ptr = tvb_get_ptr(tvb, abs_offset, limit);
+       ptr = ensure_contiguous(tvb, abs_offset, limit); /* tvb_get_ptr() */
 
        result = (const guint8 *) memchr(ptr, needle, limit);
        if (!result)
@@ -1466,28 +2061,21 @@ gint
 tvb_find_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 needle)
 {
        const guint8 *result;
-       guint         abs_offset;
-       guint         tvbufflen;
-       guint         limit;
+       guint         abs_offset = 0;
+       guint         limit = 0;
+       int           exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen);
+       exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &limit);
+       if (exception)
+               THROW(exception);
 
        /* Only search to end of tvbuff, w/o throwing exception. */
-       if (maxlength == -1) {
-               /* No maximum length specified; search to end of tvbuff. */
-               limit = tvbufflen;
-       }
-       else if (tvbufflen < (guint) maxlength) {
-               /* Maximum length goes past end of tvbuff; search to end
-                  of tvbuff. */
-               limit = tvbufflen;
-       }
-       else {
+       if (maxlength >= 0 && limit > (guint) maxlength) {
                /* Maximum length doesn't go past end of tvbuff; search
                   to that value. */
-               limit = maxlength;
+               limit = (guint) maxlength;
        }
 
        /* If we have real data, perform our search now. */
@@ -1507,22 +2095,65 @@ tvb_find_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
        return tvb_find_guint8_generic(tvb, offset, limit, needle);
 }
 
-static gint
-tvb_pbrk_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
+/* Same as tvb_find_guint8() with 16bit needle. */
+gint
+tvb_find_guint16(tvbuff_t *tvb, const gint offset, const gint maxlength,
+                const guint16 needle)
+{
+       const guint8 needle1 = ((needle & 0xFF00) >> 8);
+       const guint8 needle2 = ((needle & 0x00FF) >> 0);
+       gint searched_bytes = 0;
+       gint pos = offset;
+
+       do {
+               gint offset1 =
+                       tvb_find_guint8(tvb, pos, maxlength - searched_bytes, needle1);
+               gint offset2 = -1;
+
+               if (offset1 == -1) {
+                       return -1;
+               }
+
+               searched_bytes = offset - pos + 1;
+
+               if ((maxlength != -1) && (searched_bytes >= maxlength)) {
+                       return -1;
+               }
+
+               offset2 = tvb_find_guint8(tvb, offset1 + 1, 1, needle2);
+
+               searched_bytes += 1;
+
+               if (offset2 != -1) {
+                       if ((maxlength != -1) && (searched_bytes > maxlength)) {
+                               return -1;
+                       }
+                       return offset1;
+               }
+
+               pos = offset1 + 1;
+       } while (searched_bytes < maxlength);
+
+       return -1;
+}
+
+static inline gint
+tvb_ws_mempbrk_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
 {
        const guint8 *ptr;
        const guint8 *result;
 
-       ptr = tvb_get_ptr(tvb, abs_offset, limit);
+       ptr = ensure_contiguous(tvb, abs_offset, limit); /* tvb_get_ptr */
 
-       result = guint8_pbrk(ptr, limit, needles, found_needle);
+       result = ws_mempbrk_exec(ptr, limit, pattern, found_needle);
        if (!result)
                return -1;
 
        return (gint) ((result - ptr) + abs_offset);
 }
 
-/* Find first occurrence of any of the needles in tvbuff, starting at offset.
+
+/* Find first occurrence of any of the pattern chars in tvbuff, starting at offset.
  * Searches at most maxlength number of bytes; if maxlength is -1, searches
  * to end of tvbuff.
  * Returns the offset of the found needle, or -1 if not found.
@@ -1530,28 +2161,22 @@ tvb_pbrk_guint8_generic(tvbuff_t *tvb, guint abs_offset, guint limit, const guin
  * in that case, -1 will be returned if the boundary is reached before
  * finding needle. */
 gint
-tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const guint8 *needles, guchar *found_needle)
+tvb_ws_mempbrk_pattern_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength,
+                       const ws_mempbrk_pattern* pattern, guchar *found_needle)
 {
        const guint8 *result;
-       guint         abs_offset;
-       guint         tvbufflen;
-       guint         limit;
+       guint         abs_offset = 0;
+       guint         limit = 0;
+       int           exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       check_offset_length(tvb, offset, -1, &abs_offset, &tvbufflen);
+       exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &limit);
+       if (exception)
+               THROW(exception);
 
        /* Only search to end of tvbuff, w/o throwing exception. */
-       if (maxlength == -1) {
-               /* No maximum length specified; search to end of tvbuff. */
-               limit = tvbufflen;
-       }
-       else if (tvbufflen < (guint) maxlength) {
-               /* Maximum length goes past end of tvbuff; search to end
-                  of tvbuff. */
-               limit = tvbufflen;
-       }
-       else {
+       if (limit > (guint) maxlength) {
                /* Maximum length doesn't go past end of tvbuff; search
                   to that value. */
                limit = maxlength;
@@ -1559,7 +2184,7 @@ tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
 
        /* If we have real data, perform our search now. */
        if (tvb->real_data) {
-               result = guint8_pbrk(tvb->real_data + abs_offset, limit, needles, found_needle);
+               result = ws_mempbrk_exec(tvb->real_data + abs_offset, limit, pattern, found_needle);
                if (result == NULL) {
                        return -1;
                }
@@ -1568,10 +2193,10 @@ tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
                }
        }
 
-       if (tvb->ops->tvb_pbrk_guint8)
-               return tvb->ops->tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle);
+       if (tvb->ops->tvb_ws_mempbrk_pattern_guint8)
+               return tvb->ops->tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle);
 
-       return tvb_pbrk_guint8_generic(tvb, abs_offset, limit, needles, found_needle);
+       return tvb_ws_mempbrk_guint8_generic(tvb, abs_offset, limit, pattern, found_needle);
 }
 
 /* Find size of stringz (NUL-terminated string) by looking for terminating
@@ -1582,7 +2207,7 @@ tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
 guint
 tvb_strsize(tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset, junk_length;
+       guint abs_offset = 0, junk_length;
        gint  nul_offset;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
@@ -1593,21 +2218,15 @@ tvb_strsize(tvbuff_t *tvb, const gint offset)
                /*
                 * OK, we hit the end of the tvbuff, so we should throw
                 * an exception.
-                *
-                * Did we hit the end of the captured data, or the end
-                * 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.
                 */
-               if (tvb->length < tvb->reported_length) {
+               if (tvb->length < tvb->contained_length) {
                        THROW(BoundsError);
+               } else if (tvb->length < tvb->reported_length) {
+                       THROW(ContainedBoundsError);
+               } else if (tvb->flags & TVBUFF_FRAGMENT) {
+                       THROW(FragmentBoundsError);
                } else {
-                       if (tvb->flags & TVBUFF_FRAGMENT) {
-                               THROW(FragmentBoundsError);
-                       } else {
-                               THROW(ReportedBoundsError);
-                       }
+                       THROW(ReportedBoundsError);
                }
        }
        return (nul_offset - abs_offset) + 1;
@@ -1640,7 +2259,7 @@ gint
 tvb_strnlen(tvbuff_t *tvb, const gint offset, const guint maxlength)
 {
        gint  result_offset;
-       guint abs_offset, junk_length;
+       guint abs_offset = 0, junk_length;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
 
@@ -1715,8 +2334,9 @@ tvb_strncaseeql(tvbuff_t *tvb, const gint offset, const gchar *str, const size_t
 }
 
 /*
- * Call memcmp after checking if enough chars left, returning 0 if
- * it returns 0 (meaning "equal") and -1 otherwise, otherwise return -1.
+ * Check that the tvbuff contains at least size bytes, starting at
+ * offset, and that those bytes are equal to str. Return 0 for success
+ * and -1 for error. This function does not throw an exception.
  */
 gint
 tvb_memeql(tvbuff_t *tvb, const gint offset, const guint8 *str, size_t size)
@@ -1741,45 +2361,9 @@ tvb_memeql(tvbuff_t *tvb, const gint offset, const guint8 *str, size_t size)
        }
 }
 
-/* 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.
- *
- * If scope is set to NULL, returned buffer is allocated by g_malloc()
- * and must be g_free by the caller. Otherwise memory is automatically
- * freed when the scope lifetime is reached.
- */
-/* XXX: This has been replaced by tvb_get_string() */
-char *
-tvb_get_faked_unicode(wmem_allocator_t *scope, tvbuff_t *tvb, int offset,
-                     const int len, const gboolean little_endian)
-{
-       char    *buffer;
-       int      i;
-       guint16  character;
-
-       /* 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 = (char *)wmem_alloc(scope, 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 ...
+/**
+ * Format the data in the tvb from offset for size.  Returned string is
+ * wmem packet_scoped so call must be in that scope.
  */
 gchar *
 tvb_format_text(tvbuff_t *tvb, const gint offset, const gint size)
@@ -1790,14 +2374,14 @@ tvb_format_text(tvbuff_t *tvb, const gint offset, const gint size)
        len = (size > 0) ? size : 0;
 
        ptr = ensure_contiguous(tvb, offset, size);
-       return format_text(ptr, len);
+       return format_text(wmem_packet_scope(), ptr, len);
 }
 
 /*
  * Format the data in the tvb from offset for length ...
  */
 gchar *
-tvb_format_text_wsp(tvbuff_t *tvb, const gint offset, const gint size)
+tvb_format_text_wsp(wmem_allocator_t* allocator, tvbuff_t *tvb, const gint offset, const gint size)
 {
        const guint8 *ptr;
        gint          len;
@@ -1805,12 +2389,13 @@ tvb_format_text_wsp(tvbuff_t *tvb, const gint offset, const gint size)
        len = (size > 0) ? size : 0;
 
        ptr = ensure_contiguous(tvb, offset, size);
-       return format_text_wsp(ptr, len);
+       return format_text_wsp(allocator, ptr, len);
 }
 
-/*
+/**
  * Like "tvb_format_text()", but for null-padded strings; don't show
- * the null padding characters as "\000".
+ * the null padding characters as "\000".  Returned string is wmem packet_scoped
+ * so call must be in that scope.
  */
 gchar *
 tvb_format_stringzpad(tvbuff_t *tvb, const gint offset, const gint size)
@@ -1824,7 +2409,7 @@ tvb_format_stringzpad(tvbuff_t *tvb, const gint offset, const gint size)
        ptr = ensure_contiguous(tvb, offset, size);
        for (p = ptr, stringlen = 0; stringlen < len && *p != '\0'; p++, stringlen++)
                ;
-       return format_text(ptr, stringlen);
+       return format_text(wmem_packet_scope(), ptr, stringlen);
 }
 
 /*
@@ -1832,7 +2417,7 @@ tvb_format_stringzpad(tvbuff_t *tvb, const gint offset, const gint size)
  * the null padding characters as "\000".
  */
 gchar *
-tvb_format_stringzpad_wsp(tvbuff_t *tvb, const gint offset, const gint size)
+tvb_format_stringzpad_wsp(wmem_allocator_t* allocator, tvbuff_t *tvb, const gint offset, const gint size)
 {
        const guint8 *ptr, *p;
        gint          len;
@@ -1843,27 +2428,54 @@ tvb_format_stringzpad_wsp(tvbuff_t *tvb, const gint offset, const gint size)
        ptr = ensure_contiguous(tvb, offset, size);
        for (p = ptr, stringlen = 0; stringlen < len && *p != '\0'; p++, stringlen++)
                ;
-       return format_text_wsp(ptr, stringlen);
+       return format_text_wsp(allocator, ptr, stringlen);
 }
 
 /* Unicode REPLACEMENT CHARACTER */
 #define UNREPL 0x00FFFD
 
 /*
- * 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.
+ * All string functions below take a scope as an argument.
+ *
+ *
  * If scope is NULL, memory is allocated with g_malloc() and user must
  * explicitly free it with g_free().
  * If scope is not NULL, memory is allocated with the corresponding pool
  * lifetime.
- * Throws an exception if the tvbuff ends before the string does.
+ *
+ * All functions throw an exception if the tvbuff ends before the string
+ * does.
  */
-guint8 *
-tvb_get_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const gint length)
+
+/*
+ * Given a wmem scope, tvbuff, an offset, and a length, treat the string
+ * of bytes referred to by the tvbuff, offset, and length as an ASCII string,
+ * with all bytes with the high-order bit set being invalid, and return a
+ * pointer to a UTF-8 string, allocated using the wmem scope.
+ *
+ * Octets with the highest bit set will be converted to the Unicode
+ * REPLACEMENT CHARACTER.
+ */
+static guint8 *
+tvb_get_ascii_string(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length)
 {
-       guint8       *strbuf;
+       const guint8  *ptr;
+
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_ascii_string(scope, ptr, length);
+}
+
+/*
+ * Given a wmem scope, a tvbuff, an offset, and a length, treat the string
+ * of bytes referred to by the tvbuff, the offset. and the length as a UTF-8
+ * string, and return a pointer to that string, allocated using the wmem scope.
+ *
+ * XXX - should map invalid UTF-8 sequences to UNREPL.
+ */
+static guint8 *
+tvb_get_utf_8_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const gint length)
+{
+       guint8 *strbuf;
 
        tvb_ensure_bytes_exist(tvb, offset, length); /* make sure length = -1 fails */
        strbuf = (guint8 *)wmem_alloc(scope, length + 1);
@@ -1872,449 +2484,199 @@ tvb_get_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const
        return strbuf;
 }
 
-static guint8 *
-tvb_get_string_8859_1(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length)
+/*
+ * Given a wmem scope, tvbuff, an offset, and a length, treat the string
+ * of bytes referred to by the tvbuff, the offset, and the length as a
+ * raw string, and return a pointer to that string, allocated using the
+ * wmem scope. This means a null is appended at the end, but no replacement
+ * checking is done otherwise. Currently tvb_get_utf_8_string() does not
+ * replace either, but it might in the future.
+ *
+ * Also, this one allows a length of -1 to mean get all, but does not
+ * allow a negative offset.
+ */
+static inline guint8 *
+tvb_get_raw_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const gint length)
 {
-       wmem_strbuf_t *str;
+       guint8 *strbuf;
+       gint    abs_length = length;
 
-       str = wmem_strbuf_new(scope, "");
+       DISSECTOR_ASSERT(offset     >=  0);
+       DISSECTOR_ASSERT(abs_length >= -1);
 
-       while (length > 0) {
-               guint8 ch = tvb_get_guint8(tvb, offset);
-
-               if (ch < 0x80)
-                       wmem_strbuf_append_c(str, ch);
-               else {
-                       /*
-                        * Note: we assume here that the code points
-                        * 0x80-0x9F are used for C1 control characters,
-                        * and thus have the same value as the corresponding
-                        * Unicode code points.
-                        */
-                       wmem_strbuf_append_unichar(str, ch);
-               }
-               offset++;
-               length--;
-       }
+       if (abs_length < 0)
+               abs_length = tvb->length - offset;
 
-       /* XXX, discarding constiness, should we have some function which "take-over" strbuf->str (like when strbuf is no longer needed) */
-       return (guint8 *) wmem_strbuf_get_str(str);
+       tvb_ensure_bytes_exist(tvb, offset, abs_length);
+       strbuf = (guint8 *)wmem_alloc(scope, abs_length + 1);
+       tvb_memcpy(tvb, strbuf, offset, abs_length);
+       strbuf[abs_length] = '\0';
+       return strbuf;
 }
 
 /*
- * Given a string encoded using octet per character, with octets with
- * the high-order bit clear being ASCII, and a translation table that
- * maps values for other octets to 2-byte Unicode Basic Multilingual
- * Plane characters (including REPLACEMENT CHARACTER), return a UTF-8
- * string with the same characters.
+ * Given a wmem scope, a tvbuff, an offset, and a length, treat the string
+ * of bytes referred to by the tvbuff, the offset, and the length as an
+ * ISO 8859/1 string, and return a pointer to a UTF-8 string, allocated
+ * using the wmem scope.
  */
 static guint8 *
-tvb_get_string_unichar2(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length, const gunichar2 table[0x80])
+tvb_get_string_8859_1(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length)
 {
-       wmem_strbuf_t *str;
-
-       str = wmem_strbuf_new(scope, "");
+       const guint8  *ptr;
 
-       while (length > 0) {
-               guint8 ch = tvb_get_guint8(tvb, offset);
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_8859_1_string(scope, ptr, length);
+}
 
-               if (ch < 0x80)
-                       wmem_strbuf_append_c(str, ch);
-               else
-                       wmem_strbuf_append_unichar(str, table[ch-0x80]);
-               offset++;
-               length--;
-       }
+/*
+ * Given a wmem scope, a tvbuff, an offset, a length, and a translation
+ * table, treat the string of bytes referred to by the tvbuff, the offset,
+ * and the length as a string encoded using one octet per character, with
+ * octets with the high-order bit clear being ASCII and octets with the
+ * high-order bit set being mapped by the translation table to 2-byte
+ * Unicode Basic Multilingual Plane characters (including REPLACEMENT
+ * CHARACTER), and return a pointer to a UTF-8 string, allocated with the
+ * wmem scope.
+ */
+static guint8 *
+tvb_get_string_unichar2(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length, const gunichar2 table[0x80])
+{
+       const guint8  *ptr;
 
-       /* XXX, discarding constiness, should we have some function which "take-over" strbuf->str (like when strbuf is no longer needed) */
-       return (guint8 *) wmem_strbuf_get_str(str);
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_unichar2_string(scope, ptr, length, table);
 }
 
 /*
- * Given a UCS-2 encoded string containing characters from the
- * Basic Multilingual Plane (plane 0) of Unicode, return a UTF-8
- * string with the same characters.
- *
- * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN
+ * Given a wmem scope, a tvbuff, an offset, a length, and an encoding
+ * giving the byte order, treat the string of bytes referred to by the
+ * tvbuff, the offset, and the length as a UCS-2 encoded string in
+ * the byte order in question, containing characters from the Basic
+ * Multilingual Plane (plane 0) of Unicode, and return a pointer to a
+ * UTF-8 string, allocated with the wmem scope.
  *
- * Specify length in bytes
+ * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN.
  *
- * If scope is NULL, memory is allocated with g_malloc() and user must
- * explicitly free it with g_free().
- * If scope is not NULL, memory is allocated with the corresponding pool
- * lifetime.
+ * Specify length in bytes.
  *
  * XXX - should map lead and trail surrogate values to REPLACEMENT
  * CHARACTERs (0xFFFD)?
  * XXX - if there are an odd number of bytes, should put a
  * REPLACEMENT CHARACTER at the end.
  */
-static wmem_strbuf_t *
-tvb_extract_ucs_2_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
-{
-       gunichar2      uchar;
-       gint           i;       /* Byte counter for tvbuff */
-       wmem_strbuf_t *strbuf;
-
-       strbuf = wmem_strbuf_new(scope, NULL);
-
-       for(i = 0; i + 1 < length; i += 2) {
-               if (encoding == ENC_BIG_ENDIAN)
-                       uchar = tvb_get_ntohs(tvb, offset + i);
-               else
-                       uchar = tvb_get_letohs(tvb, offset + i);
-
-               wmem_strbuf_append_unichar(strbuf, uchar);
-       }
-
-       /*
-        * XXX - if i < length, this means we were handed an odd
-        * number of bytes, so we're not a valid UCS-2 string.
-        */
-       return strbuf;
-}
-
-static gchar *
+static guint8 *
 tvb_get_ucs_2_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
 {
-       wmem_strbuf_t *strbuf;
+       const guint8  *ptr;
 
-       tvb_ensure_bytes_exist(tvb, offset, length);
-       strbuf = tvb_extract_ucs_2_string(scope, tvb, offset, length, encoding);
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_ucs_2_string(scope, ptr, length, encoding);
 }
 
 /*
- * Given a UTF-16 encoded Unicode string, return a UTF-8 string with the
- * same characters.
+ * Given a wmem scope, a tvbuff, an offset, a length, and an encoding
+ * giving the byte order, treat the string of bytes referred to by the
+ * tvbuff, the offset, and the length as a UTF-16 encoded string in
+ * the byte order in question, and return a pointer to a UTF-8 string,
+ * allocated with the wmem scope.
  *
- * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN
+ * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN.
  *
- * Specify length in bytes
- *
- * If scope is NULL, memory is allocated with g_malloc() and user must
- * explicitly free it with g_free().
- * If scope is not NULL, memory is allocated with the corresponding pool
- * lifetime.
+ * Specify length in bytes.
  *
  * XXX - should map surrogate errors to REPLACEMENT CHARACTERs (0xFFFD).
  * XXX - should map code points > 10FFFF to REPLACEMENT CHARACTERs.
  * XXX - if there are an odd number of bytes, should put a
  * REPLACEMENT CHARACTER at the end.
  */
-
-static wmem_strbuf_t *
-tvb_extract_utf_16_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint size, const guint encoding)
-{
-       wmem_strbuf_t *strbuf;
-       gunichar2      uchar2, lead_surrogate;
-       gunichar       uchar;
-       gint           i;       /* Byte counter for tvbuff */
-
-       strbuf = wmem_strbuf_new(scope, NULL);
-
-       for(i = 0; i + 1 < size; i += 2) {
-               if (encoding == ENC_BIG_ENDIAN)
-                       uchar2 = tvb_get_ntohs(tvb, offset + i);
-               else
-                       uchar2 = tvb_get_letohs(tvb, offset + i);
-
-               if (IS_LEAD_SURROGATE(uchar2)) {
-                       /*
-                        * Lead surrogate.  Must be followed by
-                        * a trail surrogate.
-                        */
-                       i += 2;
-                       if (i + 1 >= size) {
-                               /*
-                                * Oops, string ends with a lead surrogate.
-                                * Ignore this for now.
-                                * XXX - insert "substitute" character?
-                                * Report the error in some other
-                                * fashion?
-                                */
-                               break;
-                       }
-                       lead_surrogate = uchar2;
-                       if (encoding == ENC_BIG_ENDIAN)
-                               uchar2 = tvb_get_ntohs(tvb, offset + i);
-                       else
-                               uchar2 = tvb_get_letohs(tvb, offset + i);
-                       if (IS_TRAIL_SURROGATE(uchar2)) {
-                               /* Trail surrogate. */
-                               uchar = SURROGATE_VALUE(lead_surrogate, uchar2);
-                               wmem_strbuf_append_unichar(strbuf, uchar);
-                       } else {
-                               /*
-                                * Not a trail surrogate.
-                                * Ignore the entire pair. 
-                                * XXX - insert "substitute" character?
-                                * Report the error in some other
-                                * fashion?
-                                */
-                                ;
-                       }
-               } else {
-                       if (IS_TRAIL_SURROGATE(uchar2)) {
-                               /*
-                                * Trail surrogate without a preceding
-                                * lead surrogate.  Ignore it.
-                                * XXX - insert "substitute" character?
-                                * Report the error in some other
-                                * fashion?
-                                */
-                               ;
-                       } else {
-                               /*
-                                * Non-surrogate; just append it.
-                                */
-                               wmem_strbuf_append_unichar(strbuf, uchar2);
-                       }
-               }
-       }
-
-       /*
-        * XXX - if i < length, this means we were handed an odd
-        * number of bytes, so we're not a valid UTF-16 string.
-        */
-       return strbuf;
-}
-
-static gchar *
+static guint8 *
 tvb_get_utf_16_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
 {
-       wmem_strbuf_t *strbuf;
+       const guint8  *ptr;
 
-       tvb_ensure_bytes_exist(tvb, offset, length);
-       strbuf = tvb_extract_utf_16_string(scope, tvb, offset, length, encoding);
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_utf_16_string(scope, ptr, length, encoding);
 }
 
 /*
- * Given a UCS-4-encoded Unicode string, return a UTF-8 string with the
- * same characters.
+ * Given a wmem scope, a tvbuff, an offset, a length, and an encoding
+ * giving the byte order, treat the string of bytes referred to by the
+ * tvbuff, the offset, and the length as a UCS-4 encoded string in
+ * the byte order in question, and return a pointer to a UTF-8 string,
+ * allocated with the wmem scope.
  *
  * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN
  *
  * Specify length in bytes
  *
- * If scope is NULL, memory is allocated with g_malloc() and user must
- * explicitly free it with g_free().
- * If scope is not NULL, memory is allocated with the corresponding pool
- * lifetime.
- *
  * XXX - should map lead and trail surrogate values to a "substitute"
  * UTF-8 character?
  * XXX - should map code points > 10FFFF to REPLACEMENT CHARACTERs.
  * XXX - if the number of bytes isn't a multiple of 4, should put a
  * REPLACEMENT CHARACTER at the end.
  */
-static wmem_strbuf_t *
-tvb_extract_ucs_4_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
-{
-       gunichar       uchar;
-       gint           i;       /* Byte counter for tvbuff */
-       wmem_strbuf_t *strbuf;
-
-       strbuf = wmem_strbuf_new(scope, NULL);
-
-       for(i = 0; i + 3 < length; i += 4) {
-               if (encoding == ENC_BIG_ENDIAN)
-                       uchar = tvb_get_ntohl(tvb, offset + i);
-               else
-                       uchar = tvb_get_letohl(tvb, offset + i);
-
-               wmem_strbuf_append_unichar(strbuf, uchar);
-       }
-
-       /*
-        * XXX - if i < length, this means we were handed a number
-        * of bytes that's not a multiple of 4, so we're not a valid
-        * UCS-4 string.
-        */
-       return strbuf;
-}
-
 static gchar *
 tvb_get_ucs_4_string(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint length, const guint encoding)
 {
-       wmem_strbuf_t *strbuf;
-
-       tvb_ensure_bytes_exist(tvb, offset, length);
-       strbuf = tvb_extract_ucs_4_string(scope, tvb, offset, length, encoding);
-       return (gchar*)wmem_strbuf_get_str(strbuf);
-}
-
-/*
- * FROM GNOKII
- * gsm-encoding.c
- * gsm-sms.c
- */
-#define GN_BYTE_MASK ((1 << bits) - 1)
-
-#define GN_CHAR_ALPHABET_SIZE 128
-
-#define GN_CHAR_ESCAPE 0x1b
-
-static const gunichar gsm_default_alphabet[GN_CHAR_ALPHABET_SIZE] = {
-
-    /* ETSI GSM 03.38, version 6.0.1, section 6.2.1; Default alphabet */
-
-    '@',   0xa3,  '$',   0xa5,  0xe8,  0xe9,  0xf9,  0xec,
-    0xf2,  0xc7,  '\n',  0xd8,  0xf8,  '\r',  0xc5,  0xe5,
-    0x394, '_',   0x3a6, 0x393, 0x39b, 0x3a9, 0x3a0, 0x3a8,
-    0x3a3, 0x398, 0x39e, 0xa0,  0xc6,  0xe6,  0xdf,  0xc9,
-    ' ',   '!',   '\"',  '#',   0xa4,  '%',   '&',   '\'',
-    '(',   ')',   '*',   '+',   ',',   '-',   '.',   '/',
-    '0',   '1',   '2',   '3',   '4',   '5',   '6',   '7',
-    '8',   '9',   ':',   ';',   '<',   '=',   '>',   '?',
-    0xa1,  'A',   'B',   'C',   'D',   'E',   'F',   'G',
-    'H',   'I',   'J',   'K',   'L',   'M',   'N',   'O',
-    'P',   'Q',   'R',   'S',   'T',   'U',   'V',   'W',
-    'X',   'Y',   'Z',   0xc4,  0xd6,  0xd1,  0xdc,  0xa7,
-    0xbf,  'a',   'b',   'c',   'd',   'e',   'f',   'g',
-    'h',   'i',   'j',   'k',   'l',   'm',   'n',   'o',
-    'p',   'q',   'r',   's',   't',   'u',   'v',   'w',
-    'x',   'y',   'z',   0xe4,  0xf6,  0xf1,  0xfc,  0xe0
-};
-
-static gboolean
-char_is_escape(unsigned char value)
-{
-    return (value == GN_CHAR_ESCAPE);
-}
+       const guint8 *ptr;
 
-static gunichar
-char_def_alphabet_ext_decode(unsigned char value)
-{
-    switch (value)
-    {
-    case 0x0a: return 0x0c; /* form feed */
-    case 0x14: return '^';
-    case 0x28: return '{';
-    case 0x29: return '}';
-    case 0x2f: return '\\';
-    case 0x3c: return '[';
-    case 0x3d: return '~';
-    case 0x3e: return ']';
-    case 0x40: return '|';
-    case 0x65: return 0x20ac; /* euro */
-    default: return UNREPL; /* invalid character */
-    }
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_ucs_4_string(scope, ptr, length, encoding);
 }
 
-static gunichar
-char_def_alphabet_decode(unsigned char value)
+gchar *
+tvb_get_ts_23_038_7bits_string(wmem_allocator_t *scope, tvbuff_t *tvb,
+       const gint bit_offset, gint no_of_chars)
 {
-    if (value < GN_CHAR_ALPHABET_SIZE)
-    {
-        return gsm_default_alphabet[value];
-    }
-    else
-    {
-        return UNREPL;
-    }
-}
+       gint           in_offset = bit_offset >> 3; /* Current pointer to the input buffer */
+       gint           length = ((no_of_chars + 1) * 7 + (bit_offset & 0x07)) >> 3;
+       const guint8  *ptr;
 
-static gboolean
-handle_ts_23_038_char(wmem_strbuf_t *strbuf, guint8 code_point,
-    gboolean saw_escape)
-{
-       gunichar       uchar;
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-       if (char_is_escape(code_point)) {
-               /*
-                * XXX - if saw_escape is TRUE here, then this is
-                * the case where we escape to "another extension table",
-                * but TS 128 038 V11.0 doesn't specify such an extension
-                * table.
-                */
-               saw_escape = TRUE;
-       } else {
-               /*
-                * Have we seen an escape?
-                */
-               if (saw_escape) {
-                       saw_escape = FALSE;
-                       uchar = char_def_alphabet_ext_decode(code_point);
-               } else {
-                       uchar = char_def_alphabet_decode(code_point);
-               }
-               wmem_strbuf_append_unichar(strbuf, uchar);
-       }
-       return saw_escape;
+       ptr = ensure_contiguous(tvb, in_offset, length);
+       return get_ts_23_038_7bits_string(scope, ptr, bit_offset, no_of_chars);
 }
 
 gchar *
-tvb_get_ts_23_038_7bits_string(wmem_allocator_t *scope, tvbuff_t *tvb,
+tvb_get_ascii_7bits_string(wmem_allocator_t *scope, tvbuff_t *tvb,
        const gint bit_offset, gint no_of_chars)
 {
-       wmem_strbuf_t *strbuf;
-       gint           char_count;                  /* character counter for tvbuff */
        gint           in_offset = bit_offset >> 3; /* Current pointer to the input buffer */
-       guint8         in_byte, out_byte, rest = 0x00;
-       gboolean       saw_escape = FALSE;
-       int            bits;
+       gint           length = ((no_of_chars + 1) * 7 + (bit_offset & 0x07)) >> 3;
+       const guint8  *ptr;
 
-       bits = bit_offset & 0x07;
-       if (!bits) {
-               bits = 7;
-       }
-
-       tvb_ensure_bytes_exist(tvb, in_offset, ((no_of_chars + 1) * 7 + (bit_offset & 0x07)) >> 3);
-       strbuf = wmem_strbuf_new(scope, NULL);
-       for(char_count = 0; char_count < no_of_chars;) {
-               /* Get the next byte from the string. */
-               in_byte = tvb_get_guint8(tvb, in_offset);
-               in_offset++;
-
-               /*
-                * Combine the bits we've accumulated with bits from
-                * that byte to make a 7-bit code point.
-                */
-               out_byte = ((in_byte & GN_BYTE_MASK) << (7 - bits)) | rest;
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
-               /*
-                * Leftover bits used in that code point.
-                */
-               rest = in_byte >> bits;
+       ptr = ensure_contiguous(tvb, in_offset, length);
+       return get_ascii_7bits_string(scope, ptr, bit_offset, no_of_chars);
+}
 
-               /*
-                * If we don't start from 0th bit, we shouldn't go to the
-                * next char. Under *out_num we have now 0 and under Rest -
-                * _first_ part of the char.
-                */
-               if (char_count || (bits == 7)) {
-                       saw_escape = handle_ts_23_038_char(strbuf, out_byte,
-                           saw_escape);
-                       char_count++;
-               }
+/*
+ * Given a wmem scope, a tvbuff, an offset, a length, and a translation
+ * table, treat the string of bytes referred to by the tvbuff, the offset,
+ * and the length as a string encoded using one octet per character, with
+ * octets being mapped by the translation table to 2-byte Unicode Basic
+ * Multilingual Plane characters (including REPLACEMENT CHARACTER), and
+ * return a pointer to a UTF-8 string, allocated with the wmem scope.
+ */
+static guint8 *
+tvb_get_nonascii_unichar2_string(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length, const gunichar2 table[256])
+{
+       const guint8  *ptr;
 
-               /*
-                * After reading 7 octets we have read 7 full characters
-                * but we have 7 bits as well. This is the next character.
-                */
-               if ((bits == 1) && (char_count < no_of_chars)) {
-                       saw_escape = handle_ts_23_038_char(strbuf, rest,
-                           saw_escape);
-                       char_count++;
-                       bits = 7;
-                       rest = 0x00;
-               } else
-                       bits--;
-       }
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_nonascii_unichar2_string(scope, ptr, length, table);
+}
 
-       if (saw_escape) {
-               /*
-                * Escape not followed by anything.
-                *
-                * XXX - for now, show the escape as a REPLACEMENT
-                * CHARACTER.
-                */
-               wmem_strbuf_append_unichar(strbuf, UNREPL);
-       }
+static guint8 *
+tvb_get_t61_string(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint length)
+{
+       const guint8  *ptr;
 
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+       ptr = ensure_contiguous(tvb, offset, length);
+       return get_t61_string(scope, ptr, length);
 }
 
 /*
@@ -2323,20 +2685,19 @@ tvb_get_ts_23_038_7bits_string(wmem_allocator_t *scope, tvbuff_t *tvb,
  * at that offset, plus a trailing '\0', copy into the buffer the
  * string as converted from the appropriate encoding to UTF-8, and
  * return a pointer to the string.
- *
- * Throws an exception if the tvbuff ends before the string does.
- *
- * If scope is NULL, memory is allocated with g_malloc() and user must
- * explicitly free it with g_free().
- * If scope is not NULL, memory is allocated with the corresponding pool
- * lifetime.
  */
 guint8 *
 tvb_get_string_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
                             const gint length, const guint encoding)
 {
-       const guint8 *ptr;
-       guint8       *strbuf;
+       guint8 *strptr;
+
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       /* make sure length = -1 fails */
+       if (length < 0) {
+               THROW(ReportedBoundsError);
+       }
 
        switch (encoding & ENC_CHARENCODING_MASK) {
 
@@ -2350,11 +2711,8 @@ tvb_get_string_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
                 * was a gboolean for the byte order, not an
                 * encoding value, and passed non-zero values
                 * other than TRUE to mean "little-endian".
-                *
-                * XXX - should map all octets with the 8th bit
-                * set REPLACEMENT CHARACTERs.
                 */
-               strbuf = tvb_get_string(scope, tvb, offset, length);
+               strptr = tvb_get_ascii_string(scope, tvb, offset, length);
                break;
 
        case ENC_UTF_8:
@@ -2363,24 +2721,22 @@ tvb_get_string_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
                 * points to a "substitute" UTF-8 character?
                 * XXX - should map code points > 10FFFF to REPLACEMENT
                 * CHARACTERs.
-                * XXX - should map invalid UTF-8 sequences to
-                * REPLACEMENT CHARACTERs.
                 */
-               strbuf = tvb_get_string(scope, tvb, offset, length);
+               strptr = tvb_get_utf_8_string(scope, tvb, offset, length);
                break;
 
        case ENC_UTF_16:
-               strbuf = tvb_get_utf_16_string(scope, tvb, offset, length,
+               strptr = tvb_get_utf_16_string(scope, tvb, offset, length,
                    encoding & ENC_LITTLE_ENDIAN);
                break;
 
        case ENC_UCS_2:
-               strbuf = tvb_get_ucs_2_string(scope, tvb, offset, length,
+               strptr = tvb_get_ucs_2_string(scope, tvb, offset, length,
                    encoding & ENC_LITTLE_ENDIAN);
                break;
 
        case ENC_UCS_4:
-               strbuf = tvb_get_ucs_4_string(scope, tvb, offset, length,
+               strptr = tvb_get_ucs_4_string(scope, tvb, offset, length,
                    encoding & ENC_LITTLE_ENDIAN);
                break;
 
@@ -2390,111 +2746,159 @@ tvb_get_string_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
                 * to the equivalent Unicode code point value, so
                 * no translation table is needed.
                 */
-               strbuf = tvb_get_string_8859_1(scope, tvb, offset, length);
+               strptr = tvb_get_string_8859_1(scope, tvb, offset, length);
                break;
 
        case ENC_ISO_8859_2:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_2);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_2);
                break;
 
        case ENC_ISO_8859_3:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_3);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_3);
                break;
 
        case ENC_ISO_8859_4:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_4);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_4);
                break;
 
        case ENC_ISO_8859_5:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_5);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_5);
                break;
 
        case ENC_ISO_8859_6:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_6);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_6);
                break;
 
        case ENC_ISO_8859_7:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_7);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_7);
                break;
 
        case ENC_ISO_8859_8:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_8);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_8);
                break;
 
        case ENC_ISO_8859_9:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_9);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_9);
                break;
 
        case ENC_ISO_8859_10:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_10);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_10);
                break;
 
        case ENC_ISO_8859_11:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_11);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_11);
                break;
 
        case ENC_ISO_8859_13:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_13);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_13);
                break;
 
        case ENC_ISO_8859_14:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_14);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_14);
                break;
 
        case ENC_ISO_8859_15:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_15);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_15);
                break;
 
        case ENC_ISO_8859_16:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_16);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_iso_8859_16);
                break;
 
        case ENC_WINDOWS_1250:
-               strbuf = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_cp1250);
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_cp1250);
+               break;
+
+       case ENC_MAC_ROMAN:
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_mac_roman);
+               break;
+
+       case ENC_CP437:
+               strptr = tvb_get_string_unichar2(scope, tvb, offset, length, charset_table_cp437);
                break;
 
        case ENC_3GPP_TS_23_038_7BITS:
                {
-                       gint bit_offset = offset << 3;
+                       gint bit_offset  = offset << 3;
                        gint no_of_chars = (length << 3) / 7;
-                       strbuf = tvb_get_ts_23_038_7bits_string(scope, tvb, bit_offset, no_of_chars);
+                       strptr = tvb_get_ts_23_038_7bits_string(scope, tvb, bit_offset, no_of_chars);
+               }
+               break;
+
+       case ENC_ASCII_7BITS:
+               {
+                       gint bit_offset  = offset << 3;
+                       gint no_of_chars = (length << 3) / 7;
+                       strptr = tvb_get_ascii_7bits_string(scope, tvb, bit_offset, no_of_chars);
                }
                break;
 
        case ENC_EBCDIC:
                /*
-                * XXX - do the copy and conversion in one pass.
-                *
-                * XXX - multiple "dialects" of EBCDIC?
+                * "Common" EBCDIC, covering all characters with the
+                * same code point in all Roman-alphabet EBCDIC code
+                * pages.
                 */
-               tvb_ensure_bytes_exist(tvb, offset, length); /* make sure length = -1 fails */
-               strbuf = (guint8 *)wmem_alloc(scope, length + 1);
-               if (length != 0) {
-                       ptr = ensure_contiguous(tvb, offset, length);
-                       memcpy(strbuf, ptr, length);
-                       EBCDIC_to_ASCII(strbuf, length);
-               }
-               strbuf[length] = '\0';
+               strptr = tvb_get_nonascii_unichar2_string(scope, tvb, offset, length, charset_table_ebcdic);
+               break;
+
+       case ENC_EBCDIC_CP037:
+               /*
+                * EBCDIC code page 037.
+                */
+               strptr = tvb_get_nonascii_unichar2_string(scope, tvb, offset, length, charset_table_ebcdic_cp037);
+               break;
+
+       case ENC_T61:
+               strptr = tvb_get_t61_string(scope, tvb, offset, length);
                break;
        }
-       return strbuf;
+       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 is like tvb_get_string_enc(), except that it handles null-padded
+ * strings.
  *
- * If scope is NULL, memory is allocated with g_malloc() and user must
- * explicitly free it with g_free().
- * If scope is not NULL, memory is allocated with the corresponding pool
- * lifetime.
+ * Currently, string values are stored as UTF-8 null-terminated strings,
+ * so nothing needs to be done differently for null-padded strings; we
+ * could save a little memory by not storing the null padding.
+ *
+ * If we ever store string values differently, in a fashion that doesn't
+ * involve null termination, that might change.
  */
 guint8 *
-tvb_get_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp)
+tvb_get_stringzpad(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
+                  const gint length, const guint encoding)
+{
+       return tvb_get_string_enc(scope, tvb, offset, length, encoding);
+}
+
+/*
+ * These routines are like the above routines, except that they handle
+ * null-terminated strings.  They find the length of that string (and
+ * throw an exception if the tvbuff ends before we find the null), and
+ * also return through a pointer the length of the string, in bytes,
+ * including the terminating null (the terminating null being 2 bytes
+ * for UCS-2 and UTF-16, 4 bytes for UCS-4, and 1 byte for other
+ * encodings).
+ */
+static guint8 *
+tvb_get_ascii_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint *lengthp)
+{
+       guint          size;
+       const guint8  *ptr;
+
+       size = tvb_strsize(tvb, offset);
+       ptr  = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
+       if (lengthp)
+               *lengthp = size;
+       return get_ascii_string(scope, ptr, size);
+}
+
+static guint8 *
+tvb_get_utf_8_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp)
 {
        guint   size;
        guint8 *strptr;
@@ -2511,22 +2915,28 @@ static guint8 *
 tvb_get_stringz_8859_1(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint *lengthp)
 {
        guint size;
+       const guint8  *ptr;
 
-       /* XXX, convertion between signed/unsigned integer */
-       *lengthp = size = tvb_strsize(tvb, offset);
-
-       return tvb_get_string_8859_1(scope, tvb, offset, size);
+       size = tvb_strsize(tvb, offset);
+       ptr = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
+       if (lengthp)
+               *lengthp = size;
+       return get_8859_1_string(scope, ptr, size);
 }
 
 static guint8 *
 tvb_get_stringz_unichar2(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint *lengthp, const gunichar2 table[0x80])
 {
        guint size;
+       const guint8  *ptr;
 
-       /* XXX, convertion between signed/unsigned integer */
-       *lengthp = size = tvb_strsize(tvb, offset);
-
-       return tvb_get_string_unichar2(scope, tvb, offset, size, table);
+       size = tvb_strsize(tvb, offset);
+       ptr = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
+       if (lengthp)
+               *lengthp = size;
+       return get_unichar2_string(scope, ptr, size, table);
 }
 
 /*
@@ -2540,7 +2950,7 @@ tvb_get_stringz_unichar2(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gi
  * As long as we aren't using composite TVBs, this saves the cycles used
  * (often unnecessariliy) in allocating a buffer and copying the string into
  * it.  (If we do start using composite TVBs, we may want to replace this
- * function with the _ephemeral versoin.)
+ * function with the _ephemeral version.)
  */
 const guint8 *
 tvb_get_const_stringz(tvbuff_t *tvb, const gint offset, gint *lengthp)
@@ -2555,71 +2965,40 @@ tvb_get_const_stringz(tvbuff_t *tvb, const gint offset, gint *lengthp)
        return strptr;
 }
 
-/*
- * Version of tvb_get_stringz() that handles the Basic Multilingual Plane
- * (plane 0) of Unicode, with each code point encoded in 16 bits.
- *
- * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN.
- *
- * Returns an allocated UTF-8 string and updates lengthp pointer with
- * length of string (in bytes), including the terminating (2-byte) NUL.
- */
 static gchar *
 tvb_get_ucs_2_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp, const guint encoding)
 {
        gint           size;    /* Number of bytes in string */
-       wmem_strbuf_t *strbuf;
+       const guint8  *ptr;
 
        size = tvb_unicode_strsize(tvb, offset);
-
-       strbuf = tvb_extract_ucs_2_string(scope, tvb, offset, size, encoding);
-
+       ptr = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
        if (lengthp)
                *lengthp = size;
-
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+       return get_ucs_2_string(scope, ptr, size, encoding);
 }
 
-/*
- * Version of tvb_get_stringz() that handles UTF-16.
- *
- * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN.
- *
- * Returns an allocated UTF-8 string and updates lengthp pointer with
- * length of string (in bytes), including the terminating (2-byte) NUL.
- */
 static gchar *
 tvb_get_utf_16_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp, const guint encoding)
 {
        gint           size;
-       wmem_strbuf_t *strbuf;
+       const guint8  *ptr;
 
        size = tvb_unicode_strsize(tvb, offset);
-
-       strbuf = tvb_extract_utf_16_string(scope, tvb, offset, size, encoding);
-
+       ptr = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
        if (lengthp)
                *lengthp = size;
-
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+       return get_utf_16_string(scope, ptr, size, encoding);
 }
 
-/*
- * Version of tvb_get_stringz() that handles UCS-4.
- *
- * Encoding parameter should be ENC_BIG_ENDIAN or ENC_LITTLE_ENDIAN.
- *
- * Returns an allocated UTF-8 string and updates lengthp pointer with
- * length of string (in bytes), including the terminating (4-byte) NUL.
- */
 static gchar *
 tvb_get_ucs_4_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp, const guint encoding)
 {
+       gint           size;
        gunichar       uchar;
-       gint           size;    /* Number of bytes in string */
-       wmem_strbuf_t *strbuf;
-
-       DISSECTOR_ASSERT(tvb && tvb->initialized);
+       const guint8  *ptr;
 
        size = 0;
        do {
@@ -2628,20 +3007,48 @@ tvb_get_ucs_4_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset,
                size += 4;
        } while(uchar != 0);
 
-       strbuf = tvb_extract_ucs_4_string(scope, tvb, offset, size, encoding);
+       ptr = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
+       if (lengthp)
+               *lengthp = size;
+       return get_ucs_4_string(scope, ptr, size, encoding);
+}
 
+static guint8 *
+tvb_get_nonascii_unichar2_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint *lengthp, const gunichar2 table[256])
+{
+       guint          size;
+       const guint8  *ptr;
+
+       size = tvb_strsize(tvb, offset);
+       ptr  = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
        if (lengthp)
-               *lengthp = size; /* Number of *bytes* processed */
+               *lengthp = size;
+       return get_nonascii_unichar2_string(scope, ptr, size, table);
+}
 
-       return (gchar*)wmem_strbuf_get_str(strbuf);
+static guint8 *
+tvb_get_t61_stringz(wmem_allocator_t *scope, tvbuff_t *tvb, gint offset, gint *lengthp)
+{
+       guint          size;
+       const guint8  *ptr;
+
+       size = tvb_strsize(tvb, offset);
+       ptr  = ensure_contiguous(tvb, offset, size);
+       /* XXX, conversion between signed/unsigned integer */
+       if (lengthp)
+               *lengthp = size;
+       return get_t61_string(scope, ptr, size);
 }
 
 guint8 *
 tvb_get_stringz_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, gint *lengthp, const guint encoding)
 {
-       guint   size;
        guint8 *strptr;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        switch (encoding & ENC_CHARENCODING_MASK) {
 
        case ENC_ASCII:
@@ -2654,19 +3061,18 @@ tvb_get_stringz_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, g
                 * was a gboolean for the byte order, not an
                 * encoding value, and passed non-zero values
                 * other than TRUE to mean "little-endian".
-                *
-                * XXX - should map all octets with the 8th bit
-                * not set to a "substitute" UTF-8 character.
                 */
-               strptr = tvb_get_stringz(scope, tvb, offset, lengthp);
+               strptr = tvb_get_ascii_stringz(scope, tvb, offset, lengthp);
                break;
 
        case ENC_UTF_8:
                /*
                 * XXX - should map all invalid UTF-8 sequences
                 * to a "substitute" UTF-8 character.
+                * XXX - should map code points > 10FFFF to REPLACEMENT
+                * CHARACTERs.
                 */
-               strptr = tvb_get_stringz(scope, tvb, offset, lengthp);
+               strptr = tvb_get_utf_8_stringz(scope, tvb, offset, lengthp);
                break;
 
        case ENC_UTF_16:
@@ -2753,22 +3159,40 @@ tvb_get_stringz_enc(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, g
                strptr = tvb_get_stringz_unichar2(scope, tvb, offset, lengthp, charset_table_cp1250);
                break;
 
+       case ENC_MAC_ROMAN:
+               strptr = tvb_get_stringz_unichar2(scope, tvb, offset, lengthp, charset_table_mac_roman);
+               break;
+
+       case ENC_CP437:
+               strptr = tvb_get_stringz_unichar2(scope, tvb, offset, lengthp, charset_table_cp437);
+               break;
+
        case ENC_3GPP_TS_23_038_7BITS:
                REPORT_DISSECTOR_BUG("TS 23.038 7bits has no null character and doesn't support null-terminated strings");
                break;
 
+       case ENC_ASCII_7BITS:
+               REPORT_DISSECTOR_BUG("tvb_get_stringz_enc function with ENC_ASCII_7BITS not implemented yet");
+               break;
+
        case ENC_EBCDIC:
                /*
-                * XXX - do the copy and conversion in one pass.
-                *
-                * XXX - multiple "dialects" of EBCDIC?
+                * "Common" EBCDIC, covering all characters with the
+                * same code point in all Roman-alphabet EBCDIC code
+                * pages.
+                */
+               strptr = tvb_get_nonascii_unichar2_stringz(scope, tvb, offset, lengthp, charset_table_ebcdic);
+               break;
+
+       case ENC_EBCDIC_CP037:
+               /*
+                * EBCDIC code page 037.
                 */
-               size = tvb_strsize(tvb, offset);
-               strptr = (guint8 *)wmem_alloc(scope, size);
-               tvb_memcpy(tvb, strptr, offset, size);
-               EBCDIC_to_ASCII(strptr, size);
-               if (lengthp)
-                       *lengthp = size;
+               strptr = tvb_get_nonascii_unichar2_stringz(scope, tvb, offset, lengthp, charset_table_ebcdic_cp037);
+               break;
+
+       case ENC_T61:
+               strptr = tvb_get_t61_stringz(scope, tvb, offset, lengthp);
                break;
        }
 
@@ -2797,8 +3221,8 @@ static gint
 _tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8* buffer, gint *bytes_copied)
 {
        gint     stringlen;
-       guint    abs_offset;
-       gint     limit, len;
+       guint    abs_offset = 0;
+       gint     limit, len = 0;
        gboolean decreased_max = FALSE;
 
        /* Only read to end of tvbuff, w/o throwing exception. */
@@ -2875,7 +3299,7 @@ _tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8*
  * at the correct spot, terminating the string.
  */
 gint
-tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8buffer)
+tvb_get_nstringz(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8 *buffer)
 {
        gint bytes_copied;
 
@@ -2906,6 +3330,8 @@ tvb_get_nstringz0(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8*
        }
 }
 
+
+static ws_mempbrk_pattern pbrk_crlf;
 /*
  * Given a tvbuff, an offset into the tvbuff, and a length that starts
  * at that offset (which may be -1 for "all the way to the end of the
@@ -2916,10 +3342,10 @@ tvb_get_nstringz0(tvbuff_t *tvb, const gint offset, const guint bufsize, guint8*
  * Return the length of the line (not counting the line terminator at
  * the end), or, if we don't find a line terminator:
  *
- *     if "deseg" is true, return -1;
+ * if "desegment" is true, return -1;
  *
- *     if "deseg" is false, return the amount of data remaining in
- *     the buffer.
+ * if "desegment" is false, return the amount of data remaining in
+ * the 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
@@ -2932,19 +3358,26 @@ tvb_find_line_end(tvbuff_t *tvb, const gint offset, int len, gint *next_offset,
        gint   eol_offset;
        int    linelen;
        guchar found_needle = 0;
+       static gboolean compiled = FALSE;
+
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       if (len == -1) {
+               len = _tvb_captured_length_remaining(tvb, offset);
+               /* if offset is past the end of the tvbuff, len is now 0 */
+       }
 
-       if (len == -1)
-               len = tvb_length_remaining(tvb, offset);
-       /*
-        * XXX - what if "len" is still -1, meaning "offset is past the
-        * end of the tvbuff"?
-        */
        eob_offset = offset + len;
 
+       if (!compiled) {
+               ws_mempbrk_compile(&pbrk_crlf, "\r\n");
+               compiled = TRUE;
+       }
+
        /*
         * Look either for a CR or an LF.
         */
-       eol_offset = tvb_pbrk_guint8(tvb, offset, len, "\r\n", &found_needle);
+       eol_offset = tvb_ws_mempbrk_pattern_guint8(tvb, offset, len, &pbrk_crlf, &found_needle);
        if (eol_offset == -1) {
                /*
                 * No CR or LF - line is presumably continued in next packet.
@@ -3022,6 +3455,7 @@ tvb_find_line_end(tvbuff_t *tvb, const gint offset, int len, gint *next_offset,
        return linelen;
 }
 
+static ws_mempbrk_pattern pbrk_crlf_dquote;
 /*
  * Given a tvbuff, an offset into the tvbuff, and a length that starts
  * at that offset (which may be -1 for "all the way to the end of the
@@ -3048,9 +3482,18 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, const gint offset, int len, gint *next
        guchar   c = 0;
        gint     eob_offset;
        int      linelen;
+       static gboolean compiled = FALSE;
+
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
 
        if (len == -1)
-               len = tvb_length_remaining(tvb, offset);
+               len = _tvb_captured_length_remaining(tvb, offset);
+
+       if (!compiled) {
+               ws_mempbrk_compile(&pbrk_crlf_dquote, "\r\n\"");
+               compiled = TRUE;
+       }
+
        /*
         * XXX - what if "len" is still -1, meaning "offset is past the
         * end of the tvbuff"?
@@ -3073,7 +3516,7 @@ tvb_find_line_end_unquoted(tvbuff_t *tvb, const gint offset, int len, gint *next
                        /*
                         * Look either for a CR, an LF, or a '"'.
                         */
-                       char_offset = tvb_pbrk_guint8(tvb, cur_offset, len, "\r\n\"", &c);
+                       char_offset = tvb_ws_mempbrk_pattern_guint8(tvb, cur_offset, len, &pbrk_crlf_dquote, &c);
                }
                if (char_offset == -1) {
                        /*
@@ -3187,8 +3630,12 @@ tvb_skip_wsp(tvbuff_t *tvb, const gint offset, const gint maxlength)
        gint   end, tvb_len;
        guint8 tempchar;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        /* Get the length remaining */
-       tvb_len = tvb_length(tvb);
+       /*tvb_len = tvb_captured_length(tvb);*/
+       tvb_len = tvb->length;
+
        end     = offset + maxlength;
        if (end >= tvb_len)
        {
@@ -3206,14 +3653,18 @@ tvb_skip_wsp(tvbuff_t *tvb, const gint offset, const gint maxlength)
 }
 
 gint
-tvb_skip_wsp_return(tvbuff_t *tvb, const gint offset) {
+tvb_skip_wsp_return(tvbuff_t *tvb, const gint offset)
+{
        gint   counter = offset;
        guint8 tempchar;
 
-       for(counter = offset; counter > 0 &&
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
+       for (counter = offset; counter > 0 &&
                ((tempchar = tvb_get_guint8(tvb,counter)) == ' ' ||
                tempchar == '\t' || tempchar == '\n' || tempchar == '\r'); counter--);
        counter++;
+
        return (counter);
 }
 
@@ -3222,8 +3673,12 @@ tvb_skip_guint8(tvbuff_t *tvb, int offset, const int maxlength, const guint8 ch)
 {
        int end, tvb_len;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        /* Get the length remaining */
-       tvb_len = tvb_length(tvb);
+       /*tvb_len = tvb_captured_length(tvb);*/
+       tvb_len = tvb->length;
+
        end     = offset + maxlength;
        if (end >= tvb_len)
                end = tvb_len;
@@ -3245,9 +3700,9 @@ tvb_skip_guint8(tvbuff_t *tvb, int offset, const int maxlength, const guint8 ch)
  * separator.
  */
 gchar *
-tvb_bytes_to_ep_str_punct(tvbuff_t *tvb, const gint offset, const gint len, const gchar punct)
+tvb_bytes_to_str_punct(wmem_allocator_t *scope, tvbuff_t *tvb, const gint offset, const gint len, const gchar punct)
 {
-       return bytes_to_ep_str_punct(ensure_contiguous(tvb, offset, len), len, punct);
+       return bytestring_to_str(scope, ensure_contiguous(tvb, offset, len), len, punct);
 }
 
 
@@ -3260,14 +3715,14 @@ tvb_bytes_to_ep_str_punct(tvbuff_t *tvb, const gint offset, const gint len, cons
  * A pointer to the packet scope allocated string will be returned.
  * Note a tvbuff content of 0xf is considered a 'filler' and will end the conversion.
  */
-static dgt_set_t Dgt1_9_bcd = {
+static const dgt_set_t Dgt1_9_bcd = {
        {
                /*  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e  f*/
                '0','1','2','3','4','5','6','7','8','9','?','?','?','?','?','?'
        }
 };
 const gchar *
-tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len, dgt_set_t *dgt, gboolean skip_first)
+tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len, const dgt_set_t *dgt, gboolean skip_first)
 {
        int     length;
        guint8  octet;
@@ -3275,11 +3730,14 @@ tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len,
        char   *digit_str;
        gint    t_offset = offset;
 
+       DISSECTOR_ASSERT(tvb && tvb->initialized);
+
        if (!dgt)
                dgt = &Dgt1_9_bcd;
 
        if (len == -1) {
-               length = tvb_length(tvb);
+               /*length = tvb_captured_length(tvb);*/
+               length = tvb->length;
                if (length < offset) {
                        return "";
                }
@@ -3302,8 +3760,15 @@ tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len,
                 */
                octet = octet >> 4;
 
-               if (octet == 0x0f)      /* odd number bytes - hit filler */
+               if (t_offset == length - 1 && octet == 0x0f) {
+                       /*
+                        * This is the last octet, and the low-order
+                        * nibble is 0xf, so we have an odd number of
+                        * digits, and this is a filler digit.  Ignore
+                        * it.
+                        */
                        break;
+               }
 
                digit_str[i] = dgt->out[octet & 0x0f];
                i++;
@@ -3319,17 +3784,17 @@ tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len,
  * Format a bunch of data from a tvbuff as bytes, returning a pointer
  * to the string with the formatted data.
  */
-gchar *
-tvb_bytes_to_ep_str(tvbuff_t *tvb, const gint offset, const gint len)
+gchar *tvb_bytes_to_str(wmem_allocator_t *allocator, tvbuff_t *tvb,
+    const gint offset, const gint len)
 {
-       return bytes_to_ep_str(ensure_contiguous(tvb, offset, len), len);
+       return bytes_to_str(allocator, ensure_contiguous(tvb, offset, len), len);
 }
 
 /* Find a needle tvbuff within a haystack tvbuff. */
 gint
 tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, const gint haystack_offset)
 {
-       guint         haystack_abs_offset, haystack_abs_length;
+       guint         haystack_abs_offset = 0, haystack_abs_length = 0;
        const guint8 *haystack_data;
        const guint8 *needle_data;
        const guint   needle_len = needle_tvb->length;
@@ -3376,6 +3841,51 @@ tvb_get_ds_tvb(tvbuff_t *tvb)
        return(tvb->ds_tvb);
 }
 
+guint
+tvb_get_varint(tvbuff_t *tvb, guint offset, guint maxlen, guint64 *value, const guint encoding)
+{
+       *value = 0;
+
+       if (encoding & ENC_VARINT_PROTOBUF) {
+               guint i;
+               guint64 b; /* current byte */
+
+               for (i = 0; ((i < FT_VARINT_MAX_LEN) && (i < maxlen)); ++i) {
+                       b = tvb_get_guint8(tvb, offset++);
+                       *value |= ((b & 0x7F) << (i * 7)); /* add lower 7 bits to val */
+
+                       if (b < 0x80) {
+                               /* end successfully becauseof last byte's msb(most significant bit) is zero */
+                               return i + 1;
+                       }
+               }
+       } else if (encoding & ENC_VARINT_QUIC) {
+
+               /* calculate variable length */
+               *value = tvb_get_guint8(tvb, offset);
+               switch((*value) >> 6) {
+               case 0: /* 0b00 => 1 byte length (6 bits Usable) */
+                       (*value) &= 0x3F;
+                       return 1;
+               case 1: /* 0b01 => 2 bytes length (14 bits Usable) */
+                       *value = tvb_get_ntohs(tvb, offset) & 0x3FFF;
+                       return 2;
+               case 2: /* 0b10 => 4 bytes length (30 bits Usable) */
+                       *value = tvb_get_ntohl(tvb, offset) & 0x3FFFFFFF;
+                       return 4;
+               case 3: /* 0b11 => 8 bytes length (62 bits Usable) */
+                       *value = tvb_get_ntoh64(tvb, offset) & G_GUINT64_CONSTANT(0x3FFFFFFFFFFFFFFF);
+                       return 8;
+               default: /* No Possible */
+                       g_assert_not_reached();
+                       break;
+               }
+
+       }
+
+       return 0; /* 10 bytes scanned, but no bytes' msb is zero */
+}
+
 /*
  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
  *