/epan/tvbuff_composite.c
C | 297 lines | 179 code | 52 blank | 66 comment | 28 complexity | 59181ae187b678c06b1f8cf098f74358 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
- /* 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? */
- typedef struct {
- GSList *tvbs;
- /* Used for quick testing to see if this
- * is the tvbuff that a COMPOSITE is
- * interested in. */
- guint *start_offsets;
- guint *end_offsets;
- } tvb_comp_t;
- struct tvb_composite {
- struct tvbuff tvb;
- tvb_comp_t 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;
- }
- }
- /* special case */
- if (!member_tvb) {
- DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
- return "";
- }
- 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;
- }
- }
- /* special case */
- if (!member_tvb) {
- DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
- return target;
- }
- 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 = {
- sizeof(struct tvb_composite), /* 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;
- }