aboutsummaryrefslogtreecommitdiffstats
path: root/epan/tvbuff_composite.c
diff options
context:
space:
mode:
authorJakub Zawadzki <darkjames-ws@darkjames.pl>2013-07-31 19:58:13 +0000
committerJakub Zawadzki <darkjames-ws@darkjames.pl>2013-07-31 19:58:13 +0000
commit9d519b5659aa8c0c4aa984bc6169909eb31be7d6 (patch)
treebbc5aa35d69f68abeb608f7bb08aed6ca74fac47 /epan/tvbuff_composite.c
parenta9b8779fb92525eeeca8afb8a13c86f613d05ef5 (diff)
Move composite tvbuff to seperate file (with some subtle changes).
svn path=/trunk/; revision=51071
Diffstat (limited to 'epan/tvbuff_composite.c')
-rw-r--r--epan/tvbuff_composite.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/epan/tvbuff_composite.c b/epan/tvbuff_composite.c
new file mode 100644
index 0000000000..8ec3cc12dc
--- /dev/null
+++ b/epan/tvbuff_composite.c
@@ -0,0 +1,275 @@
+/* tvbuff_composite.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
+composite_sizeof(void)
+{
+ return sizeof(struct tvb_composite);
+}
+
+static void
+composite_free(tvbuff_t *tvb)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite = &composite_tvb->composite;
+
+ g_slist_free(composite->tvbs);
+
+ g_free(composite->start_offsets);
+ g_free(composite->end_offsets);
+ if (tvb->real_data) {
+ /*
+ * XXX - do this with a union?
+ */
+ g_free((gpointer)tvb->real_data);
+ }
+}
+
+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 tvb_offset_from_real_beginning_counter(member, counter);
+}
+
+static const guint8*
+composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ guint i, num_members;
+ tvb_comp_t *composite;
+ tvbuff_t *member_tvb = NULL;
+ guint member_offset;
+ GSList *slist;
+
+ /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
+
+ /* Maybe the range specified by offset/length
+ * is contiguous inside one of the member tvbuffs */
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ for (i = 0; i < num_members; i++) {
+ if (abs_offset <= composite->end_offsets[i]) {
+ slist = g_slist_nth(composite->tvbs, i);
+ member_tvb = (tvbuff_t *)slist->data;
+ break;
+ }
+ }
+ DISSECTOR_ASSERT(member_tvb);
+
+ member_offset = abs_offset - composite->start_offsets[i];
+
+ if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
+ /*
+ * The range is, in fact, contiguous within member_tvb.
+ */
+ DISSECTOR_ASSERT(!tvb->real_data);
+ return tvb_get_ptr(member_tvb, member_offset, abs_length);
+ }
+ else {
+ tvb->real_data = (guint8 *)tvb_memdup(tvb, 0, -1);
+ return tvb->real_data + abs_offset;
+ }
+
+ DISSECTOR_ASSERT_NOT_REACHED();
+}
+
+static void *
+composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_length)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ guint8 *target = (guint8 *) _target;
+
+ guint i, num_members;
+ tvb_comp_t *composite;
+ tvbuff_t *member_tvb = NULL;
+ guint member_offset, member_length;
+ GSList *slist;
+
+ /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
+
+ /* Maybe the range specified by offset/length
+ * is contiguous inside one of the member tvbuffs */
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ for (i = 0; i < num_members; i++) {
+ if (abs_offset <= composite->end_offsets[i]) {
+ slist = g_slist_nth(composite->tvbs, i);
+ member_tvb = (tvbuff_t *)slist->data;
+ break;
+ }
+ }
+ DISSECTOR_ASSERT(member_tvb);
+
+ member_offset = abs_offset - composite->start_offsets[i];
+
+ if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
+ DISSECTOR_ASSERT(!tvb->real_data);
+ return tvb_memcpy(member_tvb, target, member_offset, abs_length);
+ }
+ else {
+ /* The requested data is non-contiguous inside
+ * the member tvb. We have to memcpy() the part that's in the member tvb,
+ * then iterate across the other member tvb's, copying their portions
+ * until we have copied all data.
+ */
+ member_length = tvb_length_remaining(member_tvb, member_offset);
+
+ /* composite_memcpy() can't handle a member_length of zero. */
+ DISSECTOR_ASSERT(member_length > 0);
+
+ tvb_memcpy(member_tvb, target, member_offset, member_length);
+ abs_offset += member_length;
+ abs_length -= member_length;
+
+ /* Recurse */
+ if (abs_length > 0) {
+ composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
+ }
+
+ return target;
+ }
+
+ DISSECTOR_ASSERT_NOT_REACHED();
+}
+
+static const struct tvb_ops tvb_composite_ops = {
+ composite_sizeof, /* size */
+ composite_free, /* free */
+ composite_offset, /* offset */
+ composite_get_ptr, /* get_ptr */
+ composite_memcpy, /* memcpy */
+ NULL, /* find_guint8 XXX */
+ NULL, /* pbrk_guint8 XXX */
+ NULL, /* clone */
+};
+
+/*
+ * Composite tvb
+ *
+ * 1. A composite tvb is automatically chained to its first member when the
+ * tvb is finalized.
+ * This means that composite tvb members must all be in the same chain.
+ * ToDo: enforce this: By searching the chain?
+ */
+tvbuff_t *
+tvb_new_composite(void)
+{
+ tvbuff_t *tvb = tvb_new(&tvb_composite_ops);
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite = &composite_tvb->composite;
+
+ composite->tvbs = NULL;
+ composite->start_offsets = NULL;
+ composite->end_offsets = NULL;
+
+ return tvb;
+}
+
+void
+tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+
+ /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
+ * and anyway it makes no sense.
+ */
+ DISSECTOR_ASSERT(member->length);
+
+ composite = &composite_tvb->composite;
+ composite->tvbs = g_slist_append(composite->tvbs, member);
+}
+
+void
+tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ tvb_comp_t *composite;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+
+ /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
+ * and anyway it makes no sense.
+ */
+ DISSECTOR_ASSERT(member->length);
+
+ composite = &composite_tvb->composite;
+ composite->tvbs = g_slist_prepend(composite->tvbs, member);
+}
+
+void
+tvb_composite_finalize(tvbuff_t *tvb)
+{
+ struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
+ GSList *slist;
+ guint num_members;
+ tvbuff_t *member_tvb;
+ tvb_comp_t *composite;
+ int i = 0;
+
+ DISSECTOR_ASSERT(tvb && !tvb->initialized);
+ DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
+ DISSECTOR_ASSERT(tvb->length == 0);
+ DISSECTOR_ASSERT(tvb->reported_length == 0);
+
+ composite = &composite_tvb->composite;
+ num_members = g_slist_length(composite->tvbs);
+
+ /* Dissectors should not create composite TVBs if they're not going to
+ * put at least one TVB in them.
+ * (Without this check--or something similar--we'll seg-fault below.)
+ */
+ DISSECTOR_ASSERT(num_members);
+
+ composite->start_offsets = g_new(guint, num_members);
+ composite->end_offsets = g_new(guint, num_members);
+
+ for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
+ DISSECTOR_ASSERT((guint) i < num_members);
+ member_tvb = (tvbuff_t *)slist->data;
+ composite->start_offsets[i] = tvb->length;
+ tvb->length += member_tvb->length;
+ tvb->reported_length += member_tvb->reported_length;
+ composite->end_offsets[i] = tvb->length - 1;
+ i++;
+ }
+ tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
+ tvb->initialized = TRUE;
+}