aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/CMakeLists.txt2
-rw-r--r--epan/Makefile.common2
-rw-r--r--epan/tvbuff-int.h12
-rw-r--r--epan/tvbuff.c263
-rw-r--r--epan/tvbuff_real.c120
-rw-r--r--epan/tvbuff_subset.c200
6 files changed, 340 insertions, 259 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt
index 4720fc8eba..0c1c6d369e 100644
--- a/epan/CMakeLists.txt
+++ b/epan/CMakeLists.txt
@@ -1498,6 +1498,8 @@ set(LIBWIRESHARK_FILES
to_str.c
tvbparse.c
tvbuff.c
+ tvbuff_real.c
+ tvbuff_subset.c
uat.c
value_string.c
xdlc.c
diff --git a/epan/Makefile.common b/epan/Makefile.common
index 441bc8174b..df016301f5 100644
--- a/epan/Makefile.common
+++ b/epan/Makefile.common
@@ -98,6 +98,8 @@ LIBWIRESHARK_SRC = \
tfs.c \
to_str.c \
tvbparse.c \
+ tvbuff_real.c \
+ tvbuff_subset.c \
tvbuff.c \
uat.c \
value_string.c \
diff --git a/epan/tvbuff-int.h b/epan/tvbuff-int.h
index d8d4cba314..3609a39606 100644
--- a/epan/tvbuff-int.h
+++ b/epan/tvbuff-int.h
@@ -97,13 +97,6 @@ struct tvbuff {
gint raw_offset;
};
-struct tvb_real {
- struct tvbuff tvb;
-
- /** Func to call when actually freed */
- tvbuff_free_cb_t free_cb;
-};
-
struct tvb_subset {
struct tvbuff tvb;
@@ -118,4 +111,9 @@ struct tvb_composite {
WS_DLL_PUBLIC tvbuff_t *tvb_new(const struct tvb_ops *ops);
+void tvb_add_to_chain(tvbuff_t *parent, tvbuff_t *child);
+
+guint tvb_offset_from_real_beginning_counter(const tvbuff_t *tvb, const guint counter);
+
+void tvb_check_offset_length(const tvbuff_t *tvb, const gint offset, gint const length_val, guint *offset_ptr, guint *length_ptr);
#endif
diff --git a/epan/tvbuff.c b/epan/tvbuff.c
index 6de6b7df35..b99e467891 100644
--- a/epan/tvbuff.c
+++ b/epan/tvbuff.c
@@ -51,8 +51,6 @@
#include "charsets.h"
#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
-static inline const struct tvb_ops *get_tvb_real_ops(void);
-static inline const struct tvb_ops *get_tvb_subset_ops(void);
static inline const struct tvb_ops *get_tvb_composite_ops(void);
static const guint8*
@@ -87,19 +85,6 @@ tvb_new(const struct tvb_ops *ops)
}
static void
-real_free(tvbuff_t *tvb)
-{
- struct tvb_real *real_tvb = (struct tvb_real *) tvb;
-
- if (real_tvb->free_cb) {
- /*
- * XXX - do this with a union?
- */
- real_tvb->free_cb((gpointer)tvb->real_data);
- }
-}
-
-static void
composite_free(tvbuff_t *tvb)
{
struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
@@ -158,17 +143,7 @@ tvb_free_chain(tvbuff_t *tvb)
}
void
-tvb_set_free_cb(tvbuff_t *tvb, const tvbuff_free_cb_t func)
-{
- struct tvb_real *real_tvb = (struct tvb_real *) tvb;
-
- DISSECTOR_ASSERT(tvb);
- DISSECTOR_ASSERT(tvb->ops == get_tvb_real_ops());
- real_tvb->free_cb = func;
-}
-
-static void
-add_to_chain(tvbuff_t *parent, tvbuff_t *child)
+tvb_add_to_chain(tvbuff_t *parent, tvbuff_t *child)
{
DISSECTOR_ASSERT(parent && child);
DISSECTOR_ASSERT(!child->next && !child->previous);
@@ -179,43 +154,6 @@ add_to_chain(tvbuff_t *parent, tvbuff_t *child)
parent->next = child;
}
-void
-tvb_set_child_real_data_tvbuff(tvbuff_t *parent, tvbuff_t *child)
-{
- DISSECTOR_ASSERT(parent && child);
- DISSECTOR_ASSERT(parent->initialized);
- DISSECTOR_ASSERT(child->initialized);
- DISSECTOR_ASSERT(child->ops == get_tvb_real_ops());
- add_to_chain(parent, child);
-}
-
-tvbuff_t *
-tvb_new_real_data(const guint8* data, const guint length, const gint reported_length)
-{
- tvbuff_t *tvb;
- struct tvb_real *real_tvb;
-
- THROW_ON(reported_length < -1, ReportedBoundsError);
-
- tvb = tvb_new(get_tvb_real_ops());
-
- tvb->real_data = data;
- tvb->length = length;
- tvb->reported_length = reported_length;
- tvb->initialized = TRUE;
-
- /*
- * This is the top-level real tvbuff for this data source,
- * so its data source tvbuff is itself.
- */
- tvb->ds_tvb = tvb;
-
- real_tvb = (struct tvb_real *) tvb;
- real_tvb->free_cb = NULL;
-
- return tvb;
-}
-
tvbuff_t *
tvb_new_child_real_data(tvbuff_t *parent, const guint8* data, const guint length, const gint reported_length)
{
@@ -349,110 +287,12 @@ check_offset_length(const tvbuff_t *tvb,
THROW(exception);
}
-static tvbuff_t *
-tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
- const guint subset_tvb_offset, const guint subset_tvb_length)
-{
- tvbuff_t *tvb = tvb_new(get_tvb_subset_ops());
- struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
-
- subset_tvb->subset.offset = subset_tvb_offset;
- subset_tvb->subset.length = subset_tvb_length;
-
- subset_tvb->subset.tvb = backing;
- tvb->length = subset_tvb_length;
- tvb->flags = backing->flags;
-
- if (reported_length == -1) {
- tvb->reported_length = backing->reported_length - subset_tvb_offset;
- }
- else {
- tvb->reported_length = reported_length;
- }
- tvb->initialized = TRUE;
- add_to_chain(backing, tvb);
-
- /* Optimization. If the backing buffer has a pointer to contiguous, real data,
- * then we can point directly to our starting offset in that buffer */
- if (backing->real_data != NULL) {
- tvb->real_data = backing->real_data + subset_tvb_offset;
- }
-
- /*
- * The top-level data source of this tvbuff is the top-level
- * data source of its parent.
- */
- tvb->ds_tvb = backing->ds_tvb;
-
- return tvb;
-}
-
-tvbuff_t *
-tvb_new_subset(tvbuff_t *backing, const gint backing_offset, const gint backing_length, const gint reported_length)
-{
- tvbuff_t *tvb;
- guint subset_tvb_offset;
- guint subset_tvb_length;
-
- DISSECTOR_ASSERT(backing && backing->initialized);
-
- THROW_ON(reported_length < -1, ReportedBoundsError);
-
- check_offset_length(backing, backing_offset, backing_length,
- &subset_tvb_offset,
- &subset_tvb_length);
-
- tvb = tvb_new_with_subset(backing, reported_length,
- subset_tvb_offset, subset_tvb_length);
-
- return tvb;
-}
-
-tvbuff_t *
-tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint backing_length)
-{
- gint captured_length;
- tvbuff_t *tvb;
- guint subset_tvb_offset;
- guint subset_tvb_length;
-
- DISSECTOR_ASSERT(backing && backing->initialized);
-
- THROW_ON(backing_length < 0, ReportedBoundsError);
-
- /*
- * Give the next dissector only captured_length bytes.
- */
- captured_length = tvb_length_remaining(backing, backing_offset);
- THROW_ON(captured_length < 0, BoundsError);
- if (captured_length > backing_length)
- captured_length = backing_length;
-
- check_offset_length(backing, backing_offset, captured_length,
- &subset_tvb_offset,
- &subset_tvb_length);
-
- tvb = tvb_new_with_subset(backing, backing_length,
- subset_tvb_offset, subset_tvb_length);
-
- return tvb;
-}
-
-tvbuff_t *
-tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset)
+void
+tvb_check_offset_length(const tvbuff_t *tvb,
+ const gint offset, gint const length_val,
+ guint *offset_ptr, guint *length_ptr)
{
- tvbuff_t *tvb;
- guint subset_tvb_offset;
- guint subset_tvb_length;
-
- check_offset_length(backing, backing_offset, -1 /* backing_length */,
- &subset_tvb_offset,
- &subset_tvb_length);
-
- tvb = tvb_new_with_subset(backing, -1 /* reported_length */,
- subset_tvb_offset, subset_tvb_length);
-
- return tvb;
+ check_offset_length(tvb, offset, length_val, offset_ptr, length_ptr);
}
static const unsigned char left_aligned_bitmask[] = {
@@ -625,7 +465,7 @@ tvb_composite_finalize(tvbuff_t *tvb)
composite->end_offsets[i] = tvb->length - 1;
i++;
}
- add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
+ tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
tvb->initialized = TRUE;
}
@@ -849,8 +689,8 @@ first_real_data_ptr(tvbuff_t *tvb)
}
#endif
-static guint
-offset_from_real_beginning(const tvbuff_t *tvb, const guint counter)
+guint
+tvb_offset_from_real_beginning_counter(const tvbuff_t *tvb, const guint counter)
{
if (tvb->ops->tvb_offset)
return tvb->ops->tvb_offset(tvb, counter);
@@ -860,33 +700,18 @@ offset_from_real_beginning(const tvbuff_t *tvb, const guint counter)
}
static guint
-real_offset(const tvbuff_t *tvb _U_, const guint counter)
-{
- return counter;
-}
-
-static guint
-subset_offset(const tvbuff_t *tvb, const guint counter)
-{
- const struct tvb_subset *subset_tvb = (const struct tvb_subset *) tvb;
- const tvbuff_t *member = subset_tvb->subset.tvb;
-
- return offset_from_real_beginning(member, counter + subset_tvb->subset.offset);
-}
-
-static guint
composite_offset(const tvbuff_t *tvb, const guint counter)
{
const struct tvb_composite *composite_tvb = (const struct tvb_composite *) tvb;
const tvbuff_t *member = (const tvbuff_t *)composite_tvb->composite.tvbs->data;
- return offset_from_real_beginning(member, counter);
+ return tvb_offset_from_real_beginning_counter(member, counter);
}
guint
tvb_offset_from_real_beginning(const tvbuff_t *tvb)
{
- return offset_from_real_beginning(tvb, 0);
+ return tvb_offset_from_real_beginning_counter(tvb, 0);
}
static const guint8*
@@ -963,14 +788,6 @@ ensure_contiguous_no_exception(tvbuff_t *tvb, const gint offset, const gint leng
return NULL;
}
-static const guint8 *
-subset_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
-{
- struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
-
- return ensure_contiguous_no_exception(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length, NULL);
-}
-
static const guint8*
ensure_contiguous(tvbuff_t *tvb, const gint offset, const gint length)
{
@@ -1109,14 +926,6 @@ composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, size_t abs_leng
DISSECTOR_ASSERT_NOT_REACHED();
}
-static void *
-subset_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
-{
- struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
-
- return tvb_memcpy(subset_tvb->subset.tvb, target, subset_tvb->subset.offset + abs_offset, abs_length);
-}
-
void *
tvb_memcpy(tvbuff_t *tvb, void *target, const gint offset, size_t length)
{
@@ -1962,14 +1771,6 @@ tvb_find_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
return -1;
}
-static gint
-subset_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
-{
- struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
-
- return tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
-}
-
/* Find first occurrence of any of the needles in tvbuff, starting at offset.
* Searches at most maxlength number of bytes; if maxlength is -1, searches
* to end of tvbuff.
@@ -2025,20 +1826,6 @@ tvb_pbrk_guint8(tvbuff_t *tvb, const gint offset, const gint maxlength, const gu
return -1;
}
-static gint
-subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
-{
- struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
-
- return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle);
-}
-
-static tvbuff_t *
-subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
-{
- return tvb_clone_offset_len(tvb, abs_offset, abs_length);
-}
-
/* Find size of stringz (NUL-terminated string) by looking for terminating
* NUL. The size of the string includes the terminating NUL.
*
@@ -3672,36 +3459,8 @@ tvb_get_ds_tvb(tvbuff_t *tvb)
return(tvb->ds_tvb);
}
-static gsize real_sizeof(void) { return sizeof(struct tvb_real); }
-static gsize subset_sizeof(void) { return sizeof(struct tvb_subset); }
static gsize composite_sizeof(void) { return sizeof(struct tvb_composite); }
-static const struct tvb_ops tvb_real_ops = {
- real_sizeof, /* size */
- real_free, /* free */
- real_offset, /* offset */
- NULL, /* get_ptr */
- NULL, /* memcpy */
- NULL, /* find_guint8 */
- NULL, /* pbrk_guint8 */
- NULL, /* clone */
-};
-
-static inline const struct tvb_ops *get_tvb_real_ops(void) { return &tvb_real_ops; }
-
-static const struct tvb_ops tvb_subset_ops = {
- subset_sizeof, /* size */
- NULL, /* free */
- subset_offset, /* offset */
- subset_get_ptr, /* get_ptr */
- subset_memcpy, /* memcpy */
- subset_find_guint8, /* find_guint8 */
- subset_pbrk_guint8, /* pbrk_guint8 */
- subset_clone, /* clone */
-};
-
-static inline const struct tvb_ops *get_tvb_subset_ops(void) { return &tvb_subset_ops; }
-
static const struct tvb_ops tvb_composite_ops = {
composite_sizeof, /* size */
composite_free, /* free */
diff --git a/epan/tvbuff_real.c b/epan/tvbuff_real.c
new file mode 100644
index 0000000000..c1014eddbf
--- /dev/null
+++ b/epan/tvbuff_real.c
@@ -0,0 +1,120 @@
+/* tvbuff_real.c
+ *
+ * $Id$
+ *
+ * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * 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.
+ */
+
+#include "config.h"
+
+#include "tvbuff.h"
+#include "tvbuff-int.h"
+#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
+
+struct tvb_real {
+ struct tvbuff tvb;
+
+ /** Func to call when actually freed */
+ tvbuff_free_cb_t free_cb;
+};
+
+static gsize
+real_sizeof(void)
+{
+ return sizeof(struct tvb_real);
+}
+
+static void
+real_free(tvbuff_t *tvb)
+{
+ struct tvb_real *real_tvb = (struct tvb_real *) tvb;
+
+ if (real_tvb->free_cb) {
+ /*
+ * XXX - do this with a union?
+ */
+ real_tvb->free_cb((gpointer)tvb->real_data);
+ }
+}
+
+static guint
+real_offset(const tvbuff_t *tvb _U_, const guint counter)
+{
+ return counter;
+}
+
+static const struct tvb_ops tvb_real_ops = {
+ real_sizeof, /* size */
+ real_free, /* free */
+ real_offset, /* offset */
+ NULL, /* get_ptr */
+ NULL, /* memcpy */
+ NULL, /* find_guint8 */
+ NULL, /* pbrk_guint8 */
+ NULL, /* clone */
+};
+
+tvbuff_t *
+tvb_new_real_data(const guint8* data, const guint length, const gint reported_length)
+{
+ tvbuff_t *tvb;
+ struct tvb_real *real_tvb;
+
+ THROW_ON(reported_length < -1, ReportedBoundsError);
+
+ tvb = tvb_new(&tvb_real_ops);
+
+ tvb->real_data = data;
+ tvb->length = length;
+ tvb->reported_length = reported_length;
+ tvb->initialized = TRUE;
+
+ /*
+ * This is the top-level real tvbuff for this data source,
+ * so its data source tvbuff is itself.
+ */
+ tvb->ds_tvb = tvb;
+
+ real_tvb = (struct tvb_real *) tvb;
+ real_tvb->free_cb = NULL;
+
+ return tvb;
+}
+
+void
+tvb_set_free_cb(tvbuff_t *tvb, const tvbuff_free_cb_t func)
+{
+ struct tvb_real *real_tvb = (struct tvb_real *) tvb;
+
+ DISSECTOR_ASSERT(tvb);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_real_ops);
+ real_tvb->free_cb = func;
+}
+
+void
+tvb_set_child_real_data_tvbuff(tvbuff_t *parent, tvbuff_t *child)
+{
+ DISSECTOR_ASSERT(parent && child);
+ DISSECTOR_ASSERT(parent->initialized);
+ DISSECTOR_ASSERT(child->initialized);
+ DISSECTOR_ASSERT(child->ops == &tvb_real_ops);
+ tvb_add_to_chain(parent, child);
+}
diff --git a/epan/tvbuff_subset.c b/epan/tvbuff_subset.c
new file mode 100644
index 0000000000..1dcdecdd6a
--- /dev/null
+++ b/epan/tvbuff_subset.c
@@ -0,0 +1,200 @@
+/* tvbuff_real.c
+ *
+ * $Id$
+ *
+ * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * 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.
+ */
+
+#include "config.h"
+
+#include "tvbuff.h"
+#include "tvbuff-int.h"
+#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
+
+static gsize
+subset_sizeof(void)
+{
+ return sizeof(struct tvb_subset);
+}
+
+static guint
+subset_offset(const tvbuff_t *tvb, const guint counter)
+{
+ const struct tvb_subset *subset_tvb = (const struct tvb_subset *) tvb;
+ const tvbuff_t *member = subset_tvb->subset.tvb;
+
+ return tvb_offset_from_real_beginning_counter(member, counter + subset_tvb->subset.offset);
+}
+
+static void *
+subset_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ return tvb_memcpy(subset_tvb->subset.tvb, target, subset_tvb->subset.offset + abs_offset, abs_length);
+}
+
+static const guint8 *
+subset_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ return tvb_get_ptr(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
+}
+
+static gint
+subset_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ return tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
+}
+
+static gint
+subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle);
+}
+
+static tvbuff_t *
+subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ return tvb_clone_offset_len(tvb, abs_offset, abs_length);
+}
+
+static const struct tvb_ops tvb_subset_ops = {
+ subset_sizeof, /* size */
+ NULL, /* free */
+ subset_offset, /* offset */
+ subset_get_ptr, /* get_ptr */
+ subset_memcpy, /* memcpy */
+ subset_find_guint8, /* find_guint8 */
+ subset_pbrk_guint8, /* pbrk_guint8 */
+ subset_clone, /* clone */
+};
+
+static tvbuff_t *
+tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
+ const guint subset_tvb_offset, const guint subset_tvb_length)
+{
+ tvbuff_t *tvb = tvb_new(&tvb_subset_ops);
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ subset_tvb->subset.offset = subset_tvb_offset;
+ subset_tvb->subset.length = subset_tvb_length;
+
+ subset_tvb->subset.tvb = backing;
+ tvb->length = subset_tvb_length;
+ tvb->flags = backing->flags;
+
+ if (reported_length == -1) {
+ tvb->reported_length = backing->reported_length - subset_tvb_offset;
+ }
+ else {
+ tvb->reported_length = reported_length;
+ }
+ tvb->initialized = TRUE;
+ tvb_add_to_chain(backing, tvb);
+
+ /* Optimization. If the backing buffer has a pointer to contiguous, real data,
+ * then we can point directly to our starting offset in that buffer */
+ if (backing->real_data != NULL) {
+ tvb->real_data = backing->real_data + subset_tvb_offset;
+ }
+
+ /*
+ * The top-level data source of this tvbuff is the top-level
+ * data source of its parent.
+ */
+ tvb->ds_tvb = backing->ds_tvb;
+
+ return tvb;
+}
+
+tvbuff_t *
+tvb_new_subset(tvbuff_t *backing, const gint backing_offset, const gint backing_length, const gint reported_length)
+{
+ tvbuff_t *tvb;
+ guint subset_tvb_offset;
+ guint subset_tvb_length;
+
+ DISSECTOR_ASSERT(backing && backing->initialized);
+
+ THROW_ON(reported_length < -1, ReportedBoundsError);
+
+ tvb_check_offset_length(backing, backing_offset, backing_length,
+ &subset_tvb_offset,
+ &subset_tvb_length);
+
+ tvb = tvb_new_with_subset(backing, reported_length,
+ subset_tvb_offset, subset_tvb_length);
+
+ return tvb;
+}
+
+tvbuff_t *
+tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint backing_length)
+{
+ gint captured_length;
+ tvbuff_t *tvb;
+ guint subset_tvb_offset;
+ guint subset_tvb_length;
+
+ DISSECTOR_ASSERT(backing && backing->initialized);
+
+ THROW_ON(backing_length < 0, ReportedBoundsError);
+
+ /*
+ * Give the next dissector only captured_length bytes.
+ */
+ captured_length = tvb_length_remaining(backing, backing_offset);
+ THROW_ON(captured_length < 0, BoundsError);
+ if (captured_length > backing_length)
+ captured_length = backing_length;
+
+ tvb_check_offset_length(backing, backing_offset, captured_length,
+ &subset_tvb_offset,
+ &subset_tvb_length);
+
+ tvb = tvb_new_with_subset(backing, backing_length,
+ subset_tvb_offset, subset_tvb_length);
+
+ return tvb;
+}
+
+tvbuff_t *
+tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset)
+{
+ tvbuff_t *tvb;
+ guint subset_tvb_offset;
+ guint subset_tvb_length;
+
+ tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
+ &subset_tvb_offset,
+ &subset_tvb_length);
+
+ tvb = tvb_new_with_subset(backing, -1 /* reported_length */,
+ subset_tvb_offset, subset_tvb_length);
+
+ return tvb;
+}