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.
28 #include <epan/emem.h>
31 #include "tvbuff-int.h"
32 #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
37 /* Used for quick testing to see if this
38 * is the tvbuff that a COMPOSITE is
45 struct tvb_composite
{
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
);
63 * XXX - do this with a union?
65 g_free((gpointer
)tvb
->real_data
);
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
);
79 composite_get_ptr(tvbuff_t
*tvb
, guint abs_offset
, guint abs_length
)
81 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
83 tvb_comp_t
*composite
;
84 tvbuff_t
*member_tvb
= NULL
;
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
;
105 DISSECTOR_ASSERT(abs_offset
== tvb
->length
&& abs_length
== 0);
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
);
119 tvb
->real_data
= (guint8
*)tvb_memdup(NULL
, tvb
, 0, -1);
120 return tvb
->real_data
+ abs_offset
;
123 DISSECTOR_ASSERT_NOT_REACHED();
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
;
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
;
155 DISSECTOR_ASSERT(abs_offset
== tvb
->length
&& abs_length
== 0);
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
);
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
;
181 if (abs_length
> 0) {
182 composite_memcpy(tvb
, target
+ member_length
, abs_offset
, abs_length
);
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 */
206 * 1. A composite tvb is automatically chained to its first member when the
208 * This means that composite tvb members must all be in the same chain.
209 * ToDo: enforce this: By searching the chain?
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
;
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
);
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
);
262 tvb_composite_finalize(tvbuff_t
*tvb
)
264 struct tvb_composite
*composite_tvb
= (struct tvb_composite
*) tvb
;
267 tvbuff_t
*member_tvb
;
268 tvb_comp_t
*composite
;
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;
297 tvb_add_to_chain((tvbuff_t
*)composite
->tvbs
->data
, tvb
); /* chain composite tvb to first member */
298 tvb
->initialized
= TRUE
;