more decompress
[wireshark-sm.git] / epan / tvbuff_subset.c
blob5e31cc8b52497256b7361991937d0528b8f2b551
1 /* tvbuff_subset.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? */
17 #include "exceptions.h"
19 typedef struct {
20 /** The backing tvbuff_t */
21 struct tvbuff *tvb;
23 /** The offset of 'tvb' to which I'm privy */
24 unsigned offset;
25 /** The length of 'tvb' to which I'm privy */
26 unsigned length;
28 } tvb_backing_t;
30 struct tvb_subset {
31 struct tvbuff tvb;
33 tvb_backing_t subset;
36 static unsigned
37 subset_offset(const tvbuff_t *tvb, const unsigned counter)
39 const struct tvb_subset *subset_tvb = (const struct tvb_subset *) tvb;
40 const tvbuff_t *member = subset_tvb->subset.tvb;
42 return tvb_offset_from_real_beginning_counter(member, counter + subset_tvb->subset.offset);
45 static void *
46 subset_memcpy(tvbuff_t *tvb, void *target, unsigned abs_offset, unsigned abs_length)
48 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
50 return tvb_memcpy(subset_tvb->subset.tvb, target, subset_tvb->subset.offset + abs_offset, abs_length);
53 static const uint8_t *
54 subset_get_ptr(tvbuff_t *tvb, unsigned abs_offset, unsigned abs_length)
56 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
58 return tvb_get_ptr(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
61 static int
62 subset_find_uint8(tvbuff_t *tvb, unsigned abs_offset, unsigned limit, uint8_t needle)
64 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
65 int result;
67 result = tvb_find_uint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
68 if (result == -1)
69 return result;
72 * Make the result relative to the beginning of the tvbuff we
73 * were handed, *not* relative to the beginning of its parent
74 * tvbuff.
76 return result - subset_tvb->subset.offset;
79 static int
80 subset_pbrk_uint8(tvbuff_t *tvb, unsigned abs_offset, unsigned limit, const ws_mempbrk_pattern* pattern, unsigned char *found_needle)
82 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
83 int result;
85 result = tvb_ws_mempbrk_pattern_uint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, pattern, found_needle);
86 if (result == -1)
87 return result;
90 * Make the result relative to the beginning of the tvbuff we
91 * were handed, *not* relative to the beginning of its parent
92 * tvbuff.
94 return result - subset_tvb->subset.offset;
97 static tvbuff_t *
98 subset_clone(tvbuff_t *tvb, unsigned abs_offset, unsigned abs_length)
100 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
102 return tvb_clone_offset_len(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
105 static const struct tvb_ops tvb_subset_ops = {
106 sizeof(struct tvb_subset), /* size */
108 NULL, /* free */
109 subset_offset, /* offset */
110 subset_get_ptr, /* get_ptr */
111 subset_memcpy, /* memcpy */
112 subset_find_uint8, /* find_uint8 */
113 subset_pbrk_uint8, /* pbrk_uint8 */
114 subset_clone, /* clone */
117 static tvbuff_t *
118 tvb_new_with_subset(tvbuff_t *backing, const unsigned reported_length,
119 const unsigned subset_tvb_offset, const unsigned subset_tvb_length)
121 tvbuff_t *tvb = tvb_new(&tvb_subset_ops);
122 struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
124 subset_tvb->subset.offset = subset_tvb_offset;
125 subset_tvb->subset.length = subset_tvb_length;
127 subset_tvb->subset.tvb = backing;
128 tvb->length = subset_tvb_length;
130 * The contained length must not exceed what remains in the
131 * backing tvbuff.
133 tvb->contained_length = MIN(reported_length, backing->contained_length - subset_tvb_offset);
134 tvb->flags = backing->flags;
136 tvb->reported_length = reported_length;
137 tvb->initialized = true;
139 /* Optimization. If the backing buffer has a pointer to contiguous, real data,
140 * then we can point directly to our starting offset in that buffer */
141 if (backing->real_data != NULL) {
142 tvb->real_data = backing->real_data + subset_tvb_offset;
146 * The top-level data source of this tvbuff is the top-level
147 * data source of its parent.
149 tvb->ds_tvb = backing->ds_tvb;
151 return tvb;
154 tvbuff_t *
155 tvb_new_subset_length_caplen(tvbuff_t *backing, const int backing_offset, const int backing_length, const int reported_length)
157 tvbuff_t *tvb;
158 unsigned subset_tvb_offset;
159 unsigned subset_tvb_length;
160 unsigned actual_reported_length;
162 DISSECTOR_ASSERT(backing && backing->initialized);
164 THROW_ON(reported_length < -1, ReportedBoundsError);
166 tvb_check_offset_length(backing, backing_offset, backing_length,
167 &subset_tvb_offset,
168 &subset_tvb_length);
170 if (reported_length == -1)
171 actual_reported_length = backing->reported_length - subset_tvb_offset;
172 else
173 actual_reported_length = (unsigned)reported_length;
176 * Cut the captured length short, so it doesn't go past the subset's
177 * reported length.
179 if (subset_tvb_length > actual_reported_length)
180 subset_tvb_length = actual_reported_length;
182 tvb = tvb_new_with_subset(backing, actual_reported_length,
183 subset_tvb_offset, subset_tvb_length);
185 tvb_add_to_chain(backing, tvb);
187 return tvb;
190 tvbuff_t *
191 tvb_new_subset_length(tvbuff_t *backing, const int backing_offset, const int reported_length)
193 int captured_length;
194 int actual_reported_length;
195 tvbuff_t *tvb;
196 unsigned subset_tvb_offset;
197 unsigned subset_tvb_length;
199 DISSECTOR_ASSERT(backing && backing->initialized);
201 THROW_ON(reported_length < -1, ReportedBoundsError);
203 if (reported_length == -1)
204 actual_reported_length = backing->reported_length;
205 else
206 actual_reported_length = reported_length;
209 * Cut the captured length short, so it doesn't go past the subset's
210 * reported length.
212 captured_length = tvb_captured_length_remaining(backing, backing_offset);
213 THROW_ON(captured_length < 0, BoundsError);
214 if (captured_length > actual_reported_length)
215 captured_length = actual_reported_length;
217 tvb_check_offset_length(backing, backing_offset, captured_length,
218 &subset_tvb_offset,
219 &subset_tvb_length);
222 * If the requested reported length is "to the end of the buffer",
223 * subtract the offset from the total length. We do this now, because
224 * the user might have passed in a negative offset.
226 if (reported_length == -1) {
227 THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
228 actual_reported_length -= subset_tvb_offset;
231 tvb = tvb_new_with_subset(backing, (unsigned)actual_reported_length,
232 subset_tvb_offset, subset_tvb_length);
234 tvb_add_to_chain(backing, tvb);
236 return tvb;
239 tvbuff_t *
240 tvb_new_subset_remaining(tvbuff_t *backing, const int backing_offset)
242 tvbuff_t *tvb;
243 unsigned subset_tvb_offset;
244 unsigned subset_tvb_length;
245 unsigned reported_length;
247 tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
248 &subset_tvb_offset,
249 &subset_tvb_length);
251 THROW_ON(backing->reported_length < subset_tvb_offset, ReportedBoundsError);
252 reported_length = backing->reported_length - subset_tvb_offset;
254 tvb = tvb_new_with_subset(backing, reported_length,
255 subset_tvb_offset, subset_tvb_length);
257 tvb_add_to_chain(backing, tvb);
259 return tvb;
262 tvbuff_t *
263 tvb_new_proxy(tvbuff_t *backing)
265 tvbuff_t *tvb;
267 if (backing)
268 tvb = tvb_new_with_subset(backing, backing->reported_length, 0, backing->length);
269 else
270 tvb = tvb_new_real_data(NULL, 0, 0);
272 tvb->ds_tvb = tvb;
274 return tvb;
279 * Editor modelines - https://www.wireshark.org/tools/modelines.html
281 * Local variables:
282 * c-basic-offset: 8
283 * tab-width: 8
284 * indent-tabs-mode: t
285 * End:
287 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
288 * :indentSize=8:tabSize=8:noTabs=false: