update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / epan / tvbuff_composite.c
blobe483d6ba590970a268958d0c3c4865931fd3228f
1 /* tvbuff_composite.c
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 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #include "tvbuff.h"
15 #include "tvbuff-int.h"
16 #include "proto.h" /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
18 typedef struct {
19 GQueue *tvbs;
21 /* Used for quick testing to see if this
22 * is the tvbuff that a COMPOSITE is
23 * interested in. */
24 unsigned *start_offsets;
25 unsigned *end_offsets;
27 } tvb_comp_t;
29 struct tvb_composite {
30 struct tvbuff tvb;
32 tvb_comp_t composite;
35 static void
36 composite_free(tvbuff_t *tvb)
38 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
39 tvb_comp_t *composite = &composite_tvb->composite;
41 g_queue_free(composite->tvbs);
43 g_free(composite->start_offsets);
44 g_free(composite->end_offsets);
45 g_free((void *)tvb->real_data);
48 static unsigned
49 composite_offset(const tvbuff_t *tvb _U_, const unsigned counter)
51 return counter;
54 static const uint8_t*
55 composite_get_ptr(tvbuff_t *tvb, unsigned abs_offset, unsigned abs_length)
57 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
58 unsigned i;
59 tvb_comp_t *composite;
60 tvbuff_t *member_tvb = NULL;
61 unsigned member_offset;
63 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
65 /* Maybe the range specified by offset/length
66 * is contiguous inside one of the member tvbuffs */
67 composite = &composite_tvb->composite;
68 GList *item = (GList*)composite->tvbs->head;
71 for (i = 0; i < g_queue_get_length(composite->tvbs); i++, item=item->next) {
72 if (abs_offset <= composite->end_offsets[i]) {
73 member_tvb = (tvbuff_t *)item->data;
74 break;
78 /* special case */
79 if (!member_tvb) {
80 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
81 return "";
84 member_offset = abs_offset - composite->start_offsets[i];
86 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
88 * The range is, in fact, contiguous within member_tvb.
90 DISSECTOR_ASSERT(!tvb->real_data);
91 return tvb_get_ptr(member_tvb, member_offset, abs_length);
93 else {
94 /* Use a temporary variable as tvb_memcpy is also checking tvb->real_data pointer */
95 void *real_data = g_malloc(tvb->length);
96 tvb_memcpy(tvb, real_data, 0, tvb->length);
97 tvb->real_data = (const uint8_t *)real_data;
98 return tvb->real_data + abs_offset;
101 DISSECTOR_ASSERT_NOT_REACHED();
104 static void *
105 composite_memcpy(tvbuff_t *tvb, void* _target, unsigned abs_offset, unsigned abs_length)
107 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
108 uint8_t *target = (uint8_t *) _target;
110 unsigned i;
111 tvb_comp_t *composite;
112 tvbuff_t *member_tvb = NULL;
113 unsigned member_offset, member_length;
115 /* DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops); */
117 /* Maybe the range specified by offset/length
118 * is contiguous inside one of the member tvbuffs */
119 composite = &composite_tvb->composite;
121 GList *item = (GList*)composite->tvbs->head;
122 for (i = 0; i < g_queue_get_length(composite->tvbs); i++, item=item->next) {
123 if (abs_offset <= composite->end_offsets[i]) {
124 member_tvb = (tvbuff_t *)item->data;
125 break;
129 /* special case */
130 if (!member_tvb) {
131 DISSECTOR_ASSERT(abs_offset == tvb->length && abs_length == 0);
132 return target;
135 member_offset = abs_offset - composite->start_offsets[i];
137 if (tvb_bytes_exist(member_tvb, member_offset, abs_length)) {
138 DISSECTOR_ASSERT(!tvb->real_data);
139 return tvb_memcpy(member_tvb, target, member_offset, abs_length);
141 else {
142 /* The requested data is non-contiguous inside
143 * the member tvb. We have to memcpy() the part that's in the member tvb,
144 * then iterate across the other member tvb's, copying their portions
145 * until we have copied all data.
147 member_length = tvb_captured_length_remaining(member_tvb, member_offset);
149 /* composite_memcpy() can't handle a member_length of zero. */
150 DISSECTOR_ASSERT(member_length > 0);
152 tvb_memcpy(member_tvb, target, member_offset, member_length);
153 abs_offset += member_length;
154 abs_length -= member_length;
156 /* Recurse */
157 if (abs_length > 0) {
158 composite_memcpy(tvb, target + member_length, abs_offset, abs_length);
161 return target;
164 DISSECTOR_ASSERT_NOT_REACHED();
167 static const struct tvb_ops tvb_composite_ops = {
168 sizeof(struct tvb_composite), /* size */
170 composite_free, /* free */
171 composite_offset, /* offset */
172 composite_get_ptr, /* get_ptr */
173 composite_memcpy, /* memcpy */
174 NULL, /* find_uint8 XXX */
175 NULL, /* pbrk_uint8 XXX */
176 NULL, /* clone */
180 * Composite tvb
182 * A composite TVB references the concatenation of one or more TVBs, each of
183 * them MUST be part of the same chain (the same memory "scope"). The
184 * caller of tvb_new_composite MUST immediately call tvb_composite_append or
185 * tvb_composite_prepend to ensure that the composite TVB is properly freed as
186 * needed.
188 * Failure to satisfy the same chain requirement can result in memory-safety
189 * issues such as use-after-free or double-free.
191 tvbuff_t *
192 tvb_new_composite(void)
194 tvbuff_t *tvb = tvb_new(&tvb_composite_ops);
195 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
196 tvb_comp_t *composite = &composite_tvb->composite;
198 composite->tvbs = g_queue_new();
199 composite->start_offsets = NULL;
200 composite->end_offsets = NULL;
202 return tvb;
205 void
206 tvb_composite_append(tvbuff_t *tvb, tvbuff_t *member)
208 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
209 tvb_comp_t *composite;
211 DISSECTOR_ASSERT(tvb && !tvb->initialized);
212 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
214 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
215 * and anyway it makes no sense.
217 if (member && member->length) {
218 composite = &composite_tvb->composite;
219 g_queue_push_tail(composite->tvbs, member);
221 /* Attach the composite TVB to the first TVB only. */
222 if (g_queue_get_length(composite->tvbs) == 1) {
223 tvb_add_to_chain((tvbuff_t *)g_queue_peek_head(composite->tvbs), tvb);
228 void
229 tvb_composite_prepend(tvbuff_t *tvb, tvbuff_t *member)
231 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
232 tvb_comp_t *composite;
234 DISSECTOR_ASSERT(tvb && !tvb->initialized);
235 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
237 /* Don't allow zero-length TVBs: composite_memcpy() can't handle them
238 * and anyway it makes no sense.
240 if (member && member->length) {
241 composite = &composite_tvb->composite;
242 g_queue_push_head(composite->tvbs, member);
244 /* Attach the composite TVB to the first TVB only. */
245 if (g_queue_get_length(composite->tvbs) == 1) {
246 tvb_add_to_chain((tvbuff_t *)g_queue_peek_head(composite->tvbs), tvb);
251 void
252 tvb_composite_finalize(tvbuff_t *tvb)
254 struct tvb_composite *composite_tvb = (struct tvb_composite *) tvb;
256 unsigned num_members;
257 tvbuff_t *member_tvb;
258 tvb_comp_t *composite;
259 unsigned i;
261 DISSECTOR_ASSERT(tvb && !tvb->initialized);
262 DISSECTOR_ASSERT(tvb->ops == &tvb_composite_ops);
263 DISSECTOR_ASSERT(tvb->length == 0);
264 DISSECTOR_ASSERT(tvb->reported_length == 0);
265 DISSECTOR_ASSERT(tvb->contained_length == 0);
267 composite = &composite_tvb->composite;
269 num_members = g_queue_get_length(composite->tvbs);
271 /* Dissectors should not create composite TVBs if they're not going to
272 * put at least one TVB in them.
273 * (Without this check--or something similar--we'll seg-fault below.)
275 DISSECTOR_ASSERT(num_members);
277 composite->start_offsets = g_new(unsigned, num_members);
278 composite->end_offsets = g_new(unsigned, num_members);
280 GList *item = (GList*)composite->tvbs->head;
281 for (i=0; i < num_members; i++, item=item->next) {
282 member_tvb = (tvbuff_t *)item->data;
283 composite->start_offsets[i] = tvb->length;
284 tvb->length += member_tvb->length;
285 tvb->reported_length += member_tvb->reported_length;
286 tvb->contained_length += member_tvb->contained_length;
287 composite->end_offsets[i] = tvb->length - 1;
290 tvb->initialized = true;
291 tvb->ds_tvb = tvb;
295 * Editor modelines - https://www.wireshark.org/tools/modelines.html
297 * Local variables:
298 * c-basic-offset: 8
299 * tab-width: 8
300 * indent-tabs-mode: t
301 * End:
303 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
304 * :indentSize=8:tabSize=8:noTabs=false: