3 * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "tvbuff-int.h"
28 #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
33 /* Used for quick testing to see if this
34 * is the tvbuff that a COMPOSITE is
41 struct tvb_composite {
48 composite_free(tvbuff_t *tvb)
50 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
51 tvb_comp_t *composite = &composite_tvb->composite;
53 g_slist_free(composite->tvbs);
55 g_free(composite->start_offsets);
56 g_free(composite->end_offsets);
59 * XXX - do this with a union?
61 g_free((gpointer)tvb->real_data);
66 composite_offset(const tvbuff_t *tvb, const guint counter)
68 const struct tvb_composite *composite_tvb = (const struct tvb_composite *) tvb;
69 const tvbuff_t *member = (const tvbuff_t *)composite_tvb->composite.tvbs->data;
71 return tvb_offset_from_real_beginning_counter(member, counter);
75 composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
77 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
79 tvb_comp_t *composite;
80 tvbuff_t *member_tvb = NULL;
84 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
86 /* Maybe the range specified by offset/length
87 * is contiguous inside one of the member tvbuffs */
88 composite = &composite_tvb->composite;
89 num_members = g_slist_length(composite->tvbs);
91 for (i = 0; i < num_members; i++) {
92 if (abs_offset <= composite->end_offsets[i]) {
93 slist = g_slist_nth(composite->tvbs, i);
94 member_tvb = (tvbuff_t *)slist->data;
101 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
105 member_offset = abs_offset - composite->start_offsets[i];
107 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
109 * The range is, in fact, contiguous within member_tvb.
111 DISSECTOR_ASSERT(!tvb->real_data);
112 return tvb_get_ptr(member_tvb, member_offset, abs_length);
115 tvb->real_data = (guint8 *)tvb_memdup(NULL, tvb, 0, -1);
116 return tvb->real_data + abs_offset;
119 DISSECTOR_ASSERT_NOT_REACHED();
123 composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_length)
125 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
126 guint8 *target = (guint8 *) _target;
128 guint i, num_members;
129 tvb_comp_t *composite;
130 tvbuff_t *member_tvb = NULL;
131 guint member_offset, member_length;
134 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
136 /* Maybe the range specified by offset/length
137 * is contiguous inside one of the member tvbuffs */
138 composite = &composite_tvb->composite;
139 num_members = g_slist_length(composite->tvbs);
141 for (i = 0; i < num_members; i++) {
142 if (abs_offset <= composite->end_offsets[i]) {
143 slist = g_slist_nth(composite->tvbs, i);
144 member_tvb = (tvbuff_t *)slist->data;
151 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
155 member_offset = abs_offset - composite->start_offsets[i];
157 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
158 DISSECTOR_ASSERT(!tvb->real_data);
159 return tvb_memcpy(member_tvb, target, member_offset, abs_length);
162 /* The requested data is non-contiguous inside
163 * the member tvb. We have to memcpy() the part that's in the member tvb,
164 * then iterate across the other member tvb's, copying their portions
165 * until we have copied all data.
167 member_length = tvb_captured_length_remaining(member_tvb, member_offset);
169 /* composite_memcpy() can't handle a member_length of zero. */
170 DISSECTOR_ASSERT(member_length > 0);
172 tvb_memcpy(member_tvb, target, member_offset, member_length);
173 abs_offset += member_length;
174 abs_length -= member_length;
177 if (abs_length > 0) {
178 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
184 DISSECTOR_ASSERT_NOT_REACHED();
187 static const struct tvb_ops tvb_composite_ops = {
188 sizeof(struct tvb_composite), /* size */
190 composite_free, /* free */
191 composite_offset, /* offset */
192 composite_get_ptr, /* get_ptr */
193 composite_memcpy, /* memcpy */
194 NULL, /* find_guint8 XXX */
195 NULL, /* pbrk_guint8 XXX */
202 * 1. A composite tvb is automatically chained to its first member when the
204 * This means that composite tvb members must all be in the same chain.
205 * ToDo: enforce this: By searching the chain?
208 tvb_new_composite(void)
210 tvbuff_t *tvb = tvb_new(&tvb_composite_ops);
211 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
212 tvb_comp_t *composite = &composite_tvb->composite;
214 composite->tvbs = NULL;
215 composite->start_offsets = NULL;
216 composite->end_offsets = NULL;
222 tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
224 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
225 tvb_comp_t *composite;
227 DISSECTOR_ASSERT(tvb && !tvb->initialized);
228 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
230 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
231 * and anyway it makes no sense.
233 DISSECTOR_ASSERT(member->length);
235 composite = &composite_tvb->composite;
236 composite->tvbs = g_slist_append(composite->tvbs, member);
240 tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
242 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
243 tvb_comp_t *composite;
245 DISSECTOR_ASSERT(tvb && !tvb->initialized);
246 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
248 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
249 * and anyway it makes no sense.
251 DISSECTOR_ASSERT(member->length);
253 composite = &composite_tvb->composite;
254 composite->tvbs = g_slist_prepend(composite->tvbs, member);
258 tvb_composite_finalize(tvbuff_t *tvb)
260 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
263 tvbuff_t *member_tvb;
264 tvb_comp_t *composite;
267 DISSECTOR_ASSERT(tvb && !tvb->initialized);
268 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
269 DISSECTOR_ASSERT(tvb->length == 0);
270 DISSECTOR_ASSERT(tvb->reported_length == 0);
272 composite = &composite_tvb->composite;
273 num_members = g_slist_length(composite->tvbs);
275 /* Dissectors should not create composite TVBs if they're not going to
276 * put at least one TVB in them.
277 * (Without this check--or something similar--we'll seg-fault below.)
279 DISSECTOR_ASSERT(num_members);
281 composite->start_offsets = g_new(guint, num_members);
282 composite->end_offsets = g_new(guint, num_members);
284 for (slist = composite->tvbs; slist != NULL; slist = slist->next) {
285 DISSECTOR_ASSERT((guint) i < num_members);
286 member_tvb = (tvbuff_t *)slist->data;
287 composite->start_offsets[i] = tvb->length;
288 tvb->length += member_tvb->length;
289 tvb->reported_length += member_tvb->reported_length;
290 composite->end_offsets[i] = tvb->length - 1;
294 DISSECTOR_ASSERT(composite->tvbs);
296 tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
297 tvb->initialized = TRUE;
301 * Editor modelines - http://www.wireshark.org/tools/modelines.html
306 * indent-tabs-mode: t
309 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
310 * :indentSize=8:tabSize=8:noTabs=false: