PA-PK-AS-REP-Win2k ::= PaPkAsRep
[metze/wireshark/wip.git] / epan / tvbuff.c
index af7a6e7bf01aee0ee69fcd10efb67cf11db3d07a..c759b91a26fb3f282808386a70fca088508d0df3 100644 (file)
  * 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"
@@ -86,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;
 }
@@ -172,14 +161,72 @@ 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 inline int
@@ -187,10 +234,12 @@ 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 {
@@ -199,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 {
@@ -228,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
@@ -429,7 +483,7 @@ tvb_captured_length(const tvbuff_t *tvb)
 static inline gint
 _tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset, rem_length;
+       guint abs_offset = 0, rem_length;
        int   exception;
 
        exception = compute_offset_and_remaining(tvb, offset, &abs_offset, &rem_length);
@@ -442,7 +496,7 @@ _tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
 gint
 tvb_captured_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset, rem_length;
+       guint abs_offset = 0, rem_length;
        int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
@@ -472,14 +526,15 @@ tvb_ensure_captured_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;
 }
@@ -492,11 +547,18 @@ tvb_ensure_captured_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;
+       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;
@@ -552,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 {
@@ -564,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 {
@@ -588,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
@@ -599,7 +667,7 @@ 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;
+       guint abs_offset = 0;
        int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
@@ -630,7 +698,7 @@ tvb_reported_length(const tvbuff_t *tvb)
 gint
 tvb_reported_length_remaining(const tvbuff_t *tvb, const gint offset)
 {
-       guint abs_offset;
+       guint abs_offset = 0;
        int   exception;
 
        DISSECTOR_ASSERT(tvb && tvb->initialized);
@@ -649,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)
 {
@@ -661,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
@@ -692,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.
@@ -713,7 +791,7 @@ ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length)
        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);
        }
@@ -737,19 +815,17 @@ 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;
 }
@@ -844,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;
 }
 
@@ -853,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);
 }
 
@@ -866,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);
 }
 
@@ -937,7 +1050,16 @@ 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);
 }
 
@@ -950,6 +1072,15 @@ tvb_get_guint16(tvbuff_t *tvb, const gint offset, const guint encoding) {
        }
 }
 
+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) {
@@ -959,6 +1090,15 @@ tvb_get_guint24(tvbuff_t *tvb, const gint offset, const guint encoding) {
        }
 }
 
+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) {
@@ -968,6 +1108,15 @@ tvb_get_guint32(tvbuff_t *tvb, const gint offset, const guint encoding) {
        }
 }
 
+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) {
@@ -1031,6 +1180,15 @@ tvb_get_guint64(tvbuff_t *tvb, const gint offset, const guint encoding) {
        }
 }
 
+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) {
@@ -1055,19 +1213,19 @@ tvb_get_ieee_double(tvbuff_t *tvb, const gint offset, const guint encoding) {
  *
  * 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)
@@ -1238,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
@@ -1257,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);
 }
 
@@ -1270,12 +1437,31 @@ 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);
+}
+
+gint32
+tvb_get_letohil(tvbuff_t *tvb, const gint offset)
+{
+       const guint8 *ptr;
+
+       ptr = fast_ensure_contiguous(tvb, offset, 4);
        return pletoh32(ptr);
 }
 
@@ -1341,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);
 }
 
@@ -1388,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
@@ -1664,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;
 
@@ -2023,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;
@@ -3464,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);
 }
 
@@ -3648,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
  *