Return ByteArray as "value" for FieldInfo's with type FT_NONE (which has data).
[metze/wireshark/wip.git] / epan / tvbuff_subset.c
1 /* tvbuff_real.c
2  *
3  * $Id$
4  *
5  * Copyright (c) 2000 by Gilbert Ramirez <gram@alumni.rice.edu>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
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.
15  *
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.
20  *
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.
24  */
25
26 #include "config.h"
27
28 #include "tvbuff.h"
29 #include "tvbuff-int.h"
30 #include "proto.h"      /* XXX - only used for DISSECTOR_ASSERT, probably a new header file? */
31
32 typedef struct {
33         /** The backing tvbuff_t */
34         struct tvbuff   *tvb;
35
36         /** The offset of 'tvb' to which I'm privy */
37         guint           offset;
38         /** The length of 'tvb' to which I'm privy */
39         guint           length;
40
41 } tvb_backing_t;
42
43 struct tvb_subset {
44         struct tvbuff tvb;
45
46         tvb_backing_t   subset;
47 };
48
49 static guint
50 subset_offset(const tvbuff_t *tvb, const guint counter)
51 {
52         const struct tvb_subset *subset_tvb = (const struct tvb_subset *) tvb;
53         const tvbuff_t *member = subset_tvb->subset.tvb;
54
55         return tvb_offset_from_real_beginning_counter(member, counter + subset_tvb->subset.offset);
56 }
57
58 static void *
59 subset_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
60 {
61         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
62
63         return tvb_memcpy(subset_tvb->subset.tvb, target, subset_tvb->subset.offset + abs_offset, abs_length);
64 }
65
66 static const guint8 *
67 subset_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length)
68 {
69         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
70
71         return tvb_get_ptr(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
72 }
73
74 static gint
75 subset_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
76 {
77         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
78
79         return tvb_find_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needle);
80 }
81
82 static gint
83 subset_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
84 {
85         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
86
87         return tvb_pbrk_guint8(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, limit, needles, found_needle);
88 }
89
90 static tvbuff_t *
91 subset_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
92 {
93         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
94
95         return tvb_clone_offset_len(subset_tvb->subset.tvb, subset_tvb->subset.offset + abs_offset, abs_length);
96 }
97
98 static const struct tvb_ops tvb_subset_ops = {
99         sizeof(struct tvb_subset), /* size */
100
101         NULL,                 /* free */
102         subset_offset,        /* offset */
103         subset_get_ptr,       /* get_ptr */
104         subset_memcpy,        /* memcpy */
105         subset_find_guint8,   /* find_guint8 */
106         subset_pbrk_guint8,   /* pbrk_guint8 */
107         subset_clone,         /* clone */
108 };
109
110 static tvbuff_t *
111 tvb_new_with_subset(tvbuff_t *backing, const gint reported_length,
112     const guint subset_tvb_offset, const guint subset_tvb_length)
113 {
114         tvbuff_t *tvb = tvb_new(&tvb_subset_ops);
115         struct tvb_subset *subset_tvb = (struct tvb_subset *) tvb;
116
117         subset_tvb->subset.offset = subset_tvb_offset;
118         subset_tvb->subset.length = subset_tvb_length;
119
120         subset_tvb->subset.tvb       = backing;
121         tvb->length                  = subset_tvb_length;
122         tvb->flags                   = backing->flags;
123
124         if (reported_length == -1) {
125                 tvb->reported_length = backing->reported_length - subset_tvb_offset;
126         }
127         else {
128                 tvb->reported_length = reported_length;
129         }
130         tvb->initialized             = TRUE;
131
132         /* Optimization. If the backing buffer has a pointer to contiguous, real data,
133          * then we can point directly to our starting offset in that buffer */
134         if (backing->real_data != NULL) {
135                 tvb->real_data = backing->real_data + subset_tvb_offset;
136         }
137
138         /*
139          * The top-level data source of this tvbuff is the top-level
140          * data source of its parent.
141          */
142         tvb->ds_tvb = backing->ds_tvb;
143
144         return tvb;
145 }
146
147 tvbuff_t *
148 tvb_new_subset(tvbuff_t *backing, const gint backing_offset, const gint backing_length, const gint reported_length)
149 {
150         tvbuff_t *tvb;
151         guint     subset_tvb_offset;
152         guint     subset_tvb_length;
153
154         DISSECTOR_ASSERT(backing && backing->initialized);
155
156         THROW_ON(reported_length < -1, ReportedBoundsError);
157
158         tvb_check_offset_length(backing, backing_offset, backing_length,
159                                 &subset_tvb_offset,
160                                 &subset_tvb_length);
161
162         tvb = tvb_new_with_subset(backing, reported_length,
163             subset_tvb_offset, subset_tvb_length);
164
165         tvb_add_to_chain(backing, tvb);
166
167         return tvb;
168 }
169
170 tvbuff_t *
171 tvb_new_subset_length(tvbuff_t *backing, const gint backing_offset, const gint backing_length)
172 {
173         gint      captured_length;
174         tvbuff_t *tvb;
175         guint     subset_tvb_offset;
176         guint     subset_tvb_length;
177
178         DISSECTOR_ASSERT(backing && backing->initialized);
179
180         THROW_ON(backing_length < 0, ReportedBoundsError);
181
182         /*
183          * Give the next dissector only captured_length bytes.
184          */
185         captured_length = tvb_length_remaining(backing, backing_offset);
186         THROW_ON(captured_length < 0, BoundsError);
187         if (captured_length > backing_length)
188                 captured_length = backing_length;
189
190         tvb_check_offset_length(backing, backing_offset, captured_length,
191                                 &subset_tvb_offset,
192                                 &subset_tvb_length);
193
194         tvb = tvb_new_with_subset(backing, backing_length,
195             subset_tvb_offset, subset_tvb_length);
196
197         tvb_add_to_chain(backing, tvb);
198
199         return tvb;
200 }
201
202 tvbuff_t *
203 tvb_new_subset_remaining(tvbuff_t *backing, const gint backing_offset)
204 {
205         tvbuff_t *tvb;
206         guint     subset_tvb_offset;
207         guint     subset_tvb_length;
208
209         tvb_check_offset_length(backing, backing_offset, -1 /* backing_length */,
210                                 &subset_tvb_offset,
211                                 &subset_tvb_length);
212
213         tvb = tvb_new_with_subset(backing, -1 /* reported_length */,
214             subset_tvb_offset, subset_tvb_length);
215
216         tvb_add_to_chain(backing, tvb);
217
218         return tvb;
219 }
220
221 tvbuff_t *
222 tvb_new_proxy(tvbuff_t *backing)
223 {
224         tvbuff_t *tvb;
225         
226         if (backing)
227                 tvb = tvb_new_with_subset(backing, backing->reported_length, 0, backing->length);
228         else
229                 tvb = tvb_new_real_data(NULL, 0, 0);
230
231         tvb->ds_tvb = tvb;
232
233         return tvb;
234 }