summaryrefslogtreecommitdiffstats
path: root/epan/tvbuff_subset.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/tvbuff_subset.c')
-rw-r--r--epan/tvbuff_subset.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/epan/tvbuff_subset.c b/epan/tvbuff_subset.c
new file mode 100644
index 00000000..839facc3
--- /dev/null
+++ b/epan/tvbuff_subset.c
@@ -0,0 +1,289 @@
+/* tvbuff_subset.c
+ *
+ * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+
+#include "tvbuff.h"
+#include "tvbuff-int.h"
+#include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
+#include "exceptions.h"
+
+typedef struct {
+ /** The backing tvbuff_t */
+ struct tvbuff *tvb;
+
+ /** The offset of 'tvb' to which I'm privy */
+ guint offset;
+ /** The length of 'tvb' to which I'm privy */
+ guint length;
+
+} tvb_backing_t;
+
+struct tvb_subset {
+ struct tvbuff tvb;
+
+ tvb_backing_t 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;
+ gint result;
+
+ result = tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
+ if (result == -1)
+ return result;
+
+ /*
+ * Make the result relative to the beginning of the tvbuff we
+ * were handed, *not* relative to the beginning of its parent
+ * tvbuff.
+ */
+ return result - subset_tvb->subset.offset;
+}
+
+static gint
+subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+ gint result;
+
+ result = tvb_ws_mempbrk_pattern_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, pattern, found_needle);
+ if (result == -1)
+ return result;
+
+ /*
+ * Make the result relative to the beginning of the tvbuff we
+ * were handed, *not* relative to the beginning of its parent
+ * tvbuff.
+ */
+ return result - subset_tvb->subset.offset;
+}
+
+static tvbuff_t *
+subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
+
+ return tvb_clone_offset_len(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
+}
+
+static const struct tvb_ops tvb_subset_ops = {
+ sizeof(struct tvb_subset), /* 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 guint 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;
+ /*
+ * The contained length must not exceed what remains in the
+ * backing tvbuff.
+ */
+ tvb->contained_length = MIN(reported_length, backing->contained_length - subset_tvb_offset);
+ tvb->flags = backing->flags;
+
+ tvb->reported_length = reported_length;
+ tvb->initialized = TRUE;
+
+ /* 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_length_caplen(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;
+ guint actual_reported_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);
+
+ if (reported_length == -1)
+ actual_reported_length = backing->reported_length - subset_tvb_offset;
+ else
+ actual_reported_length = (guint)reported_length;
+
+ /*
+ * Cut the captured length short, so it doesn't go past the subset's
+ * reported length.
+ */
+ if (subset_tvb_length > actual_reported_length)
+ subset_tvb_length = actual_reported_length;
+
+ tvb = tvb_new_with_subset(backing, actual_reported_length,
+ subset_tvb_offset, subset_tvb_length);
+
+ tvb_add_to_chain(backing, tvb);
+
+ return tvb;
+}
+
+tvbuff_t *
+tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint reported_length)
+{
+ gint captured_length;
+ gint actual_reported_length;
+ tvbuff_t *tvb;
+ guint subset_tvb_offset;
+ guint subset_tvb_length;
+
+ DISSECTOR_ASSERT(backing && backing->initialized);
+
+ THROW_ON(reported_length < -1, ReportedBoundsError);
+
+ if (reported_length == -1)
+ actual_reported_length = backing->reported_length;
+ else
+ actual_reported_length = reported_length;
+
+ /*
+ * Cut the captured length short, so it doesn't go past the subset's
+ * reported length.
+ */
+ captured_length = tvb_captured_length_remaining(backing, backing_offset);
+ THROW_ON(captured_length < 0, BoundsError);
+ if (captured_length > actual_reported_length)
+ captured_length = actual_reported_length;
+
+ tvb_check_offset_length(backing, backing_offset, captured_length,
+ &subset_tvb_offset,
+ &subset_tvb_length);
+
+ /*
+ * If the requested reported length is "to the end of the buffer",
+ * subtract the offset from the total length. We do this now, because
+ * the user might have passed in a negative offset.
+ */
+ if (reported_length == -1) {
+ THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
+ actual_reported_length -= subset_tvb_offset;
+ }
+
+ tvb = tvb_new_with_subset(backing, (guint)actual_reported_length,
+ subset_tvb_offset, subset_tvb_length);
+
+ tvb_add_to_chain(backing, tvb);
+
+ 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;
+ guint reported_length;
+
+ tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
+ &subset_tvb_offset,
+ &subset_tvb_length);
+
+ THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
+ reported_length = backing->reported_length - subset_tvb_offset;
+
+ tvb = tvb_new_with_subset(backing, reported_length,
+ subset_tvb_offset, subset_tvb_length);
+
+ tvb_add_to_chain(backing, tvb);
+
+ return tvb;
+}
+
+tvbuff_t *
+tvb_new_proxy(tvbuff_t *backing)
+{
+ tvbuff_t *tvb;
+
+ if (backing)
+ tvb = tvb_new_with_subset(backing, backing->reported_length, 0, backing->length);
+ else
+ tvb = tvb_new_real_data(NULL, 0, 0);
+
+ tvb->ds_tvb = tvb;
+
+ return tvb;
+}
+
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * End:
+ *
+ * vi: set shiftwidth=8 tabstop=8 noexpandtab:
+ * :indentSize=8:tabSize=8:noTabs=false:
+ */