From 9d519b5659aa8c0c4aa984bc6169909eb31be7d6 Mon Sep 17 00:00:00 2001 From: Jakub Zawadzki Date: Wed, 31 Jul 2013 19:58:13 +0000 Subject: Move composite tvbuff to seperate file (with some subtle changes). svn path=/trunk/; revision=51071 --- epan/tvbuff_composite.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 epan/tvbuff_composite.c (limited to 'epan/tvbuff_composite.c') 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 + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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; +} -- cgit v1.2.3