#if 0 (with XXX comment) use of try_conversion(); Also: do misc cosmetic changes.
[metze/wireshark/wip.git] / frame_tvbuff.c
1 /* frame_tvbuff.c
2  * Implements a tvbuff for frame
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <glib.h>
26
27 #include <epan/packet.h>
28 #include <epan/tvbuff-int.h>
29 #include <epan/tvbuff.h>
30
31 #include "frame_tvbuff.h"
32 #include "globals.h"
33
34 #include "wtap-int.h" /* for ->random_fh */
35
36 struct tvb_frame {
37         struct tvbuff tvb;
38
39         Buffer *buf;         /* Packet data */
40
41         wtap *wth;           /**< Wiretap session */
42         gint64 file_off;     /**< File offset */
43
44         guint offset;
45 };
46
47 static gboolean
48 frame_read(struct tvb_frame *frame_tvb, struct wtap_pkthdr *phdr, Buffer *buf)
49 {
50         int    err;
51         gchar *err_info;
52
53         /* sanity check, capture file was closed? */
54         if (cfile.wth != frame_tvb->wth)
55                 return FALSE;
56
57         /* XXX, what if phdr->caplen isn't equal to
58          * frame_tvb->tvb.length + frame_tvb->offset?
59          */
60         if (!wtap_seek_read(frame_tvb->wth, frame_tvb->file_off, phdr, buf, &err, &err_info)) {
61                 switch (err) {
62                         case WTAP_ERR_UNSUPPORTED_ENCAP:
63                         case WTAP_ERR_BAD_FILE:
64                                 g_free(err_info);
65                                 break;
66                 }
67                 return FALSE;
68         }
69         return TRUE;
70 }
71
72 static void
73 frame_cache(struct tvb_frame *frame_tvb)
74 {
75         struct wtap_pkthdr phdr; /* Packet header */
76
77         if (frame_tvb->buf == NULL) {
78                 frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
79
80                 /* XXX, register frame_tvb to some list which frees from time to time not used buffers :] */
81                 buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
82
83                 if (!frame_read(frame_tvb, &phdr, frame_tvb->buf))
84                         { /* TODO: THROW(???); */ }
85         }
86
87         frame_tvb->tvb.real_data = buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
88 }
89
90 static void
91 frame_free(tvbuff_t *tvb)
92 {
93         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
94
95         if (frame_tvb->buf) {
96                 buffer_free(frame_tvb->buf);
97
98                 g_free(frame_tvb->buf);
99         }
100 }
101
102 static const guint8 *
103 frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_)
104 {
105         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
106
107         frame_cache(frame_tvb);
108
109         return tvb->real_data + abs_offset;
110 }
111
112 static void *
113 frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
114 {
115         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
116
117         frame_cache(frame_tvb);
118
119         return memcpy(target, tvb->real_data + abs_offset, abs_length);
120 }
121
122 static gint
123 frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
124 {
125         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
126         const guint8 *result;
127
128         frame_cache(frame_tvb);
129
130         result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
131         if (result)
132                 return (gint) (result - tvb->real_data);
133         else
134                 return -1;
135 }
136
137 static gint
138 frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const guint8 *needles, guchar *found_needle)
139 {
140         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
141
142         frame_cache(frame_tvb);
143
144         return tvb_pbrk_guint8(tvb, abs_offset, limit, needles, found_needle);
145 }
146
147 static guint
148 frame_offset(const tvbuff_t *tvb _U_, const guint counter)
149 {
150         /* XXX: frame_tvb->offset */
151         return counter;
152 }
153
154 static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length);
155
156 static const struct tvb_ops tvb_frame_ops = {
157         sizeof(struct tvb_frame), /* size */
158
159         frame_free,           /* free */
160         frame_offset,         /* offset */
161         frame_get_ptr,        /* get_ptr */
162         frame_memcpy,         /* memcpy */
163         frame_find_guint8,    /* find_guint8 */
164         frame_pbrk_guint8,    /* pbrk_guint8 */
165         frame_clone,          /* clone */
166 };
167
168 /* based on tvb_new_real_data() */
169 tvbuff_t *
170 frame_tvbuff_new(const frame_data *fd, const guint8 *buf)
171 {
172         struct tvb_frame *frame_tvb;
173         tvbuff_t *tvb;
174
175         tvb = tvb_new(&tvb_frame_ops);
176
177         /*
178          * XXX - currently, the length arguments in
179          * tvbuff structure are signed, but the captured
180          * and reported length values are unsigned; this means
181          * that length values > 2^31 - 1 will appear as
182          * negative lengths
183          *
184          * Captured length values that large will already
185          * have been filtered out by the Wiretap modules
186          * (the file will be reported as corrupted), to
187          * avoid trying to allocate large chunks of data.
188          *
189          * Reported length values will not have been
190          * filtered out, and should not be filtered out,
191          * as those lengths are not necessarily invalid.
192          *
193          * For now, we clip the reported length at G_MAXINT
194          *
195          * (XXX, is this still a problem?) There was an exception when we call
196          * tvb_new_real_data() now there's no one
197          */
198
199         tvb->real_data       = buf;
200         tvb->length          = fd->cap_len;
201         tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
202         tvb->initialized     = TRUE;
203
204         /*
205          * This is the top-level real tvbuff for this data source,
206          * so its data source tvbuff is itself.
207          */
208         tvb->ds_tvb = tvb;
209
210         frame_tvb = (struct tvb_frame *) tvb;
211
212         /* XXX, wtap_can_seek() */
213         if (cfile.wth && cfile.wth->random_fh
214 #ifdef WANT_PACKET_EDITOR
215                 && fd->file_off != -1 /* generic clone for modified packets */
216 #endif
217         ) {
218                 frame_tvb->wth = cfile.wth;
219                 frame_tvb->file_off = fd->file_off;
220                 frame_tvb->offset = 0;
221         } else
222                 frame_tvb->wth = NULL;
223
224         frame_tvb->buf = NULL;
225
226         return tvb;
227 }
228
229 tvbuff_t *
230 frame_tvbuff_new_buffer(const frame_data *fd, Buffer *buf)
231 {
232         return frame_tvbuff_new(fd, buffer_start_ptr(buf));
233 }
234
235 static tvbuff_t *
236 frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
237 {
238         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
239
240         tvbuff_t *cloned_tvb;
241         struct tvb_frame *cloned_frame_tvb;
242
243         /* file not seekable */
244         if (!frame_tvb->wth)
245                 return NULL;
246
247         abs_offset += frame_tvb->offset;
248
249         cloned_tvb = tvb_new(&tvb_frame_ops);
250
251         /* data will be read when needed */
252         cloned_tvb->real_data       = NULL;
253         cloned_tvb->length          = abs_length;
254         cloned_tvb->reported_length = abs_length; /* XXX? */
255         cloned_tvb->initialized     = TRUE;
256
257         /*
258          * This is the top-level real tvbuff for this data source,
259          * so its data source tvbuff is itself.
260          */
261         cloned_tvb->ds_tvb = cloned_tvb;
262
263         cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
264         cloned_frame_tvb->wth = frame_tvb->wth;
265         cloned_frame_tvb->file_off = frame_tvb->file_off;
266         cloned_frame_tvb->offset = abs_offset;
267         cloned_frame_tvb->buf = NULL;
268
269         return cloned_tvb;
270 }
271
272
273 /* based on tvb_new_real_data() */
274 tvbuff_t *
275 file_tvbuff_new(const frame_data *fd, const guint8 *buf)
276 {
277         struct tvb_frame *frame_tvb;
278         tvbuff_t *tvb;
279
280         tvb = tvb_new(&tvb_frame_ops);
281
282         /*
283          * XXX - currently, the length arguments in
284          * tvbuff structure are signed, but the captured
285          * and reported length values are unsigned; this means
286          * that length values > 2^31 - 1 will appear as
287          * negative lengths
288          *
289          * Captured length values that large will already
290          * have been filtered out by the Wiretap modules
291          * (the file will be reported as corrupted), to
292          * avoid trying to allocate large chunks of data.
293          *
294          * Reported length values will not have been
295          * filtered out, and should not be filtered out,
296          * as those lengths are not necessarily invalid.
297          *
298          * For now, we clip the reported length at G_MAXINT
299          *
300          * (XXX, is this still a problem?) There was an exception when we call
301          * tvb_new_real_data() now there's no one
302          */
303
304         tvb->real_data       = buf;
305         tvb->length          = fd->cap_len;
306         tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
307         tvb->initialized     = TRUE;
308
309         /*
310          * This is the top-level real tvbuff for this data source,
311          * so its data source tvbuff is itself.
312          */
313         tvb->ds_tvb = tvb;
314
315         frame_tvb = (struct tvb_frame *) tvb;
316
317         /* XXX, wtap_can_seek() */
318         if (cfile.wth && cfile.wth->random_fh
319 #ifdef WANT_PACKET_EDITOR
320                 && fd->file_off != -1 /* generic clone for modified packets */
321 #endif
322         ) {
323                 frame_tvb->wth = cfile.wth;
324                 frame_tvb->file_off = fd->file_off;
325                 frame_tvb->offset = 0;
326         } else
327                 frame_tvb->wth = NULL;
328
329         frame_tvb->buf = NULL;
330
331         return tvb;
332 }
333
334 tvbuff_t *
335 file_tvbuff_new_buffer(const frame_data *fd, Buffer *buf)
336 {
337         return frame_tvbuff_new(fd, buffer_start_ptr(buf));
338 }