RTPS: Adding position in the batch to the rtps_dissector_data
[metze/wireshark/wip.git] / epan / tvbuff_composite.c
1 /* tvbuff_composite.c
2  *
3  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
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.
13  *
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.
18  *
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.
22  */
23
24 #include "config.h"
25
26 #include "tvbuff.h"
27 #include "tvbuff-int.h"
28 #include "proto.h"      /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
29
30 typedef struct {
31         GSList          *tvbs;
32
33         /* Used for quick testing to see if this
34          * is the tvbuff that a COMPOSITE is
35          * interested in. */
36         guint           *start_offsets;
37         guint           *end_offsets;
38
39 } tvb_comp_t;
40
41 struct tvb_composite {
42         struct tvbuff tvb;
43
44         tvb_comp_t      composite;
45 };
46
47 static void
48 composite_free(tvbuff_t *tvb)
49 {
50         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
51         tvb_comp_t *composite = &composite_tvb->composite;
52
53         g_slist_free(composite->tvbs);
54
55         g_free(composite->start_offsets);
56         g_free(composite->end_offsets);
57         if (tvb->real_data) {
58                 /*
59                  * XXX - do this with a union?
60                  */
61                 g_free((gpointer)tvb->real_data);
62         }
63 }
64
65 static guint
66 composite_offset(const tvbuff_t *tvb, const guint counter)
67 {
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;
70
71         return tvb_offset_from_real_beginning_counter(member, counter);
72 }
73
74 static const guint8*
75 composite_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
76 {
77         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
78         guint       i, num_members;
79         tvb_comp_t *composite;
80         tvbuff_t   *member_tvb = NULL;
81         guint       member_offset;
82         GSList     *slist;
83
84         /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
85
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);
90
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;
95                         break;
96                 }
97         }
98
99         /* special case */
100         if (!member_tvb) {
101                 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
102                 return "";
103         }
104
105         member_offset = abs_offset - composite->start_offsets[i];
106
107         if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
108                 /*
109                  * The range is, in fact, contiguous within member_tvb.
110                  */
111                 DISSECTOR_ASSERT(!tvb->real_data);
112                 return tvb_get_ptr(member_tvb, member_offset, abs_length);
113         }
114         else {
115                 tvb->real_data = (guint8 *)tvb_memdup(NULL, tvb, 0, -1);
116                 return tvb->real_data + abs_offset;
117         }
118
119         DISSECTOR_ASSERT_NOT_REACHED();
120 }
121
122 static void *
123 composite_memcpy(tvbuff_t *tvb, void* _target, guint abs_offset, guint abs_length)
124 {
125         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
126         guint8 *target = (guint8 *) _target;
127
128         guint       i, num_members;
129         tvb_comp_t *composite;
130         tvbuff_t   *member_tvb = NULL;
131         guint       member_offset, member_length;
132         GSList     *slist;
133
134         /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
135
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);
140
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;
145                         break;
146                 }
147         }
148
149         /* special case */
150         if (!member_tvb) {
151                 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
152                 return target;
153         }
154
155         member_offset = abs_offset - composite->start_offsets[i];
156
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);
160         }
161         else {
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.
166                  */
167                 member_length = tvb_captured_length_remaining(member_tvb, member_offset);
168
169                 /* composite_memcpy() can't handle a member_length of zero. */
170                 DISSECTOR_ASSERT(member_length > 0);
171
172                 tvb_memcpy(member_tvb, target, member_offset, member_length);
173                 abs_offset      += member_length;
174                 abs_length      -= member_length;
175
176                 /* Recurse */
177                 if (abs_length > 0) {
178                         composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
179                 }
180
181                 return target;
182         }
183
184         DISSECTOR_ASSERT_NOT_REACHED();
185 }
186
187 static const struct tvb_ops tvb_composite_ops = {
188         sizeof(struct tvb_composite), /* size */
189
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 */
196         NULL,                 /* clone */
197 };
198
199 /*
200  * Composite tvb
201  *
202  *   1. A composite tvb is automatically chained to its first member when the
203  *      tvb is finalized.
204  *      This means that composite tvb members must all be in the same chain.
205  *      ToDo: enforce this: By searching the chain?
206  */
207 tvbuff_t *
208 tvb_new_composite(void)
209 {
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;
213
214         composite->tvbs          = NULL;
215         composite->start_offsets = NULL;
216         composite->end_offsets   = NULL;
217
218         return tvb;
219 }
220
221 void
222 tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
223 {
224         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
225         tvb_comp_t *composite;
226
227         DISSECTOR_ASSERT(tvb && !tvb->initialized);
228         DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
229
230         /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
231          * and anyway it makes no sense.
232          */
233         DISSECTOR_ASSERT(member->length);
234
235         composite       = &composite_tvb->composite;
236         composite->tvbs = g_slist_append(composite->tvbs, member);
237 }
238
239 void
240 tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
241 {
242         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
243         tvb_comp_t *composite;
244
245         DISSECTOR_ASSERT(tvb && !tvb->initialized);
246         DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
247
248         /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
249          * and anyway it makes no sense.
250          */
251         DISSECTOR_ASSERT(member->length);
252
253         composite       = &composite_tvb->composite;
254         composite->tvbs = g_slist_prepend(composite->tvbs, member);
255 }
256
257 void
258 tvb_composite_finalize(tvbuff_t *tvb)
259 {
260         struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
261         GSList     *slist;
262         guint       num_members;
263         tvbuff_t   *member_tvb;
264         tvb_comp_t *composite;
265         int         i = 0;
266
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);
271
272         composite   = &composite_tvb->composite;
273         num_members = g_slist_length(composite->tvbs);
274
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.)
278          */
279         DISSECTOR_ASSERT(num_members);
280
281         composite->start_offsets = g_new(guint, num_members);
282         composite->end_offsets = g_new(guint, num_members);
283
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;
291                 i++;
292         }
293
294         DISSECTOR_ASSERT(composite->tvbs);
295
296         tvb_add_to_chain((tvbuff_t *)composite->tvbs->data, tvb); /* chain composite tvb to first member */
297         tvb->initialized = TRUE;
298 }
299
300 /*
301  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
302  *
303  * Local variables:
304  * c-basic-offset: 8
305  * tab-width: 8
306  * indent-tabs-mode: t
307  * End:
308  *
309  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
310  * :indentSize=8:tabSize=8:noTabs=false:
311  */