FIXUP: WIP: verification_trailer
[wireshark-wip.git] / epan / tvbuff_composite.c
blobe9be61e20bb1ae7f6c4c444f862ec7a0dce2f76b
1 /* tvbuff_composite.c
3 * $Id$
5 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "config.h"
28 #include <epan/emem.h>
30 #include "tvbuff.h"
31 #include "tvbuff-int.h"
32 #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
34 typedef struct {
35 GSList *tvbs;
37 /* Used for quick testing to see if this
38 * is the tvbuff that a COMPOSITE is
39 * interested in. */
40 guint *start_offsets;
41 guint *end_offsets;
43 } tvb_comp_t;
45 struct tvb_composite {
46 struct tvbuff tvb;
48 tvb_comp_t composite;
51 static void
52 composite_free(tvbuff_t *tvb)
54 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
55 tvb_comp_t *composite = &composite_tvb->composite;
57 g_slist_free(composite->tvbs);
59 g_free(composite->start_offsets);
60 g_free(composite->end_offsets);
61 if (tvb->real_data) {
63 * XXX - do this with a union?
65 g_free((gpointer)tvb->real_data);
69 static guint
70 composite_offset(const tvbuff_t *tvb, const guint counter)
72 const struct tvb_composite *composite_tvb = (const struct tvb_composite *) tvb;
73 const tvbuff_t *member = (const tvbuff_t *)composite_tvb->composite.tvbs->data;
75 return tvb_offset_from_real_beginning_counter(member, counter);
78 static const guint8*
79 composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
81 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
82 guint i, num_members;
83 tvb_comp_t *composite;
84 tvbuff_t *member_tvb = NULL;
85 guint member_offset;
86 GSList *slist;
88 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
90 /* Maybe the range specified by offset/length
91 * is contiguous inside one of the member tvbuffs */
92 composite = &composite_tvb->composite;
93 num_members = g_slist_length(composite->tvbs);
95 for (i = 0; i < num_members; i++) {
96 if (abs_offset <= composite->end_offsets[i]) {
97 slist = g_slist_nth(composite->tvbs, i);
98 member_tvb = (tvbuff_t *)slist->data;
99 break;
103 /* special case */
104 if (!member_tvb) {
105 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
106 return "";
109 member_offset = abs_offset - composite->start_offsets[i];
111 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
113 * The range is, in fact, contiguous within member_tvb.
115 DISSECTOR_ASSERT(!tvb->real_data);
116 return tvb_get_ptr(member_tvb, member_offset, abs_length);
118 else {
119 tvb->real_data = (guint8 *)tvb_memdup(NULL, tvb, 0, -1);
120 return tvb->real_data + abs_offset;
123 DISSECTOR_ASSERT_NOT_REACHED();
126 static void *
127 composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_length)
129 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
130 guint8 *target = (guint8 *) _target;
132 guint i, num_members;
133 tvb_comp_t *composite;
134 tvbuff_t *member_tvb = NULL;
135 guint member_offset, member_length;
136 GSList *slist;
138 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
140 /* Maybe the range specified by offset/length
141 * is contiguous inside one of the member tvbuffs */
142 composite = &composite_tvb->composite;
143 num_members = g_slist_length(composite->tvbs);
145 for (i = 0; i < num_members; i++) {
146 if (abs_offset <= composite->end_offsets[i]) {
147 slist = g_slist_nth(composite->tvbs, i);
148 member_tvb = (tvbuff_t *)slist->data;
149 break;
153 /* special case */
154 if (!member_tvb) {
155 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
156 return target;
159 member_offset = abs_offset - composite->start_offsets[i];
161 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
162 DISSECTOR_ASSERT(!tvb->real_data);
163 return tvb_memcpy(member_tvb, target, member_offset, abs_length);
165 else {
166 /* The requested data is non-contiguous inside
167 * the member tvb. We have to memcpy() the part that's in the member tvb,
168 * then iterate across the other member tvb's, copying their portions
169 * until we have copied all data.
171 member_length = tvb_length_remaining(member_tvb, member_offset);
173 /* composite_memcpy() can't handle a member_length of zero. */
174 DISSECTOR_ASSERT(member_length > 0);
176 tvb_memcpy(member_tvb, target, member_offset, member_length);
177 abs_offset += member_length;
178 abs_length -= member_length;
180 /* Recurse */
181 if (abs_length > 0) {
182 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
185 return target;
188 DISSECTOR_ASSERT_NOT_REACHED();
191 static const struct tvb_ops tvb_composite_ops = {
192 sizeof(struct tvb_composite), /* size */
194 composite_free, /* free */
195 composite_offset, /* offset */
196 composite_get_ptr, /* get_ptr */
197 composite_memcpy, /* memcpy */
198 NULL, /* find_guint8 XXX */
199 NULL, /* pbrk_guint8 XXX */
200 NULL, /* clone */
204 * Composite tvb
206 * 1. A composite tvb is automatically chained to its first member when the
207 * tvb is finalized.
208 * This means that composite tvb members must all be in the same chain.
209 * ToDo: enforce this: By searching the chain?
211 tvbuff_t *
212 tvb_new_composite(void)
214 tvbuff_t *tvb = tvb_new(&tvb_composite_ops);
215 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
216 tvb_comp_t *composite = &composite_tvb->composite;
218 composite->tvbs = NULL;
219 composite->start_offsets = NULL;
220 composite->end_offsets = NULL;
222 return tvb;
225 void
226 tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
228 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
229 tvb_comp_t *composite;
231 DISSECTOR_ASSERT(tvb && !tvb->initialized);
232 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
234 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
235 * and anyway it makes no sense.
237 DISSECTOR_ASSERT(member->length);
239 composite = &composite_tvb->composite;
240 composite->tvbs = g_slist_append(composite->tvbs, member);
243 void
244 tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
246 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
247 tvb_comp_t *composite;
249 DISSECTOR_ASSERT(tvb && !tvb->initialized);
250 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
252 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
253 * and anyway it makes no sense.
255 DISSECTOR_ASSERT(member->length);
257 composite = &composite_tvb->composite;
258 composite->tvbs = g_slist_prepend(composite->tvbs, member);
261 void
262 tvb_composite_finalize(tvbuff_t *tvb)
264 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
265 GSList *slist;
266 guint num_members;
267 tvbuff_t *member_tvb;
268 tvb_comp_t *composite;
269 int i = 0;
271 DISSECTOR_ASSERT(tvb && !tvb->initialized);
272 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
273 DISSECTOR_ASSERT(tvb->length == 0);
274 DISSECTOR_ASSERT(tvb->reported_length == 0);
276 composite = &composite_tvb->composite;
277 num_members = g_slist_length(composite->tvbs);
279 /* Dissectors should not create composite TVBs if they're not going to
280 * put at least one TVB in them.
281 * (Without this check--or something similar--we'll seg-fault below.)
283 DISSECTOR_ASSERT(num_members);
285 composite->start_offsets = g_new(guint, num_members);
286 composite->end_offsets = g_new(guint, num_members);
288 for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
289 DISSECTOR_ASSERT((guint) i < num_members);
290 member_tvb = (tvbuff_t *)slist->data;
291 composite->start_offsets[i] = tvb->length;
292 tvb->length += member_tvb->length;
293 tvb->reported_length += member_tvb->reported_length;
294 composite->end_offsets[i] = tvb->length - 1;
295 i++;
297 tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
298 tvb->initialized = TRUE;