Qt: add initializers (CID 1162824).
[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 "wiretap/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                 /* XXX - report error! */
62                 switch (err) {
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 GPtrArray *buffer_cache = NULL;
73
74 static void
75 frame_cache(struct tvb_frame *frame_tvb)
76 {
77         struct wtap_pkthdr phdr; /* Packet header */
78
79         wtap_phdr_init(&phdr);
80
81         if (frame_tvb->buf == NULL) {
82                 if G_UNLIKELY(!buffer_cache) buffer_cache = g_ptr_array_sized_new(1024);
83
84                 if (buffer_cache->len > 0) {
85                         frame_tvb->buf = (struct Buffer *) g_ptr_array_remove_index(buffer_cache, buffer_cache->len - 1);
86                 } else {
87                         frame_tvb->buf = (struct Buffer *) g_malloc(sizeof(struct Buffer));
88                 }
89
90                 ws_buffer_init(frame_tvb->buf, frame_tvb->tvb.length + frame_tvb->offset);
91
92                 if (!frame_read(frame_tvb, &phdr, frame_tvb->buf))
93                         { /* TODO: THROW(???); */ }
94         }
95
96         frame_tvb->tvb.real_data = ws_buffer_start_ptr(frame_tvb->buf) + frame_tvb->offset;
97
98         wtap_phdr_cleanup(&phdr);
99 }
100
101 static void
102 frame_free(tvbuff_t *tvb)
103 {
104         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
105
106         if (frame_tvb->buf) {
107                 ws_buffer_free(frame_tvb->buf);
108                 g_ptr_array_add(buffer_cache, frame_tvb->buf);
109         }
110 }
111
112 static const guint8 *
113 frame_get_ptr(tvbuff_t *tvb, guint abs_offset, guint abs_length _U_)
114 {
115         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
116
117         frame_cache(frame_tvb);
118
119         return tvb->real_data + abs_offset;
120 }
121
122 static void *
123 frame_memcpy(tvbuff_t *tvb, void *target, guint abs_offset, guint abs_length)
124 {
125         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
126
127         frame_cache(frame_tvb);
128
129         return memcpy(target, tvb->real_data + abs_offset, abs_length);
130 }
131
132 static gint
133 frame_find_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, guint8 needle)
134 {
135         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
136         const guint8 *result;
137
138         frame_cache(frame_tvb);
139
140         result = (const guint8 *)memchr(tvb->real_data + abs_offset, needle, limit);
141         if (result)
142                 return (gint) (result - tvb->real_data);
143         else
144                 return -1;
145 }
146
147 static gint
148 frame_pbrk_guint8(tvbuff_t *tvb, guint abs_offset, guint limit, const ws_mempbrk_pattern* pattern, guchar *found_needle)
149 {
150         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
151
152         frame_cache(frame_tvb);
153
154         return tvb_ws_mempbrk_pattern_guint8(tvb, abs_offset, limit, pattern, found_needle);
155 }
156
157 static guint
158 frame_offset(const tvbuff_t *tvb _U_, const guint counter)
159 {
160         /* XXX: frame_tvb->offset */
161         return counter;
162 }
163
164 static tvbuff_t *frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length);
165
166 static const struct tvb_ops tvb_frame_ops = {
167         sizeof(struct tvb_frame), /* size */
168
169         frame_free,           /* free */
170         frame_offset,         /* offset */
171         frame_get_ptr,        /* get_ptr */
172         frame_memcpy,         /* memcpy */
173         frame_find_guint8,    /* find_guint8 */
174         frame_pbrk_guint8,    /* pbrk_guint8 */
175         frame_clone,          /* clone */
176 };
177
178 /* based on tvb_new_real_data() */
179 tvbuff_t *
180 frame_tvbuff_new(const frame_data *fd, const guint8 *buf)
181 {
182         struct tvb_frame *frame_tvb;
183         tvbuff_t *tvb;
184
185         tvb = tvb_new(&tvb_frame_ops);
186
187         /*
188          * XXX - currently, the length arguments in
189          * tvbuff structure are signed, but the captured
190          * and reported length values are unsigned; this means
191          * that length values > 2^31 - 1 will appear as
192          * negative lengths
193          *
194          * Captured length values that large will already
195          * have been filtered out by the Wiretap modules
196          * (the file will be reported as corrupted), to
197          * avoid trying to allocate large chunks of data.
198          *
199          * Reported length values will not have been
200          * filtered out, and should not be filtered out,
201          * as those lengths are not necessarily invalid.
202          *
203          * For now, we clip the reported length at G_MAXINT
204          *
205          * (XXX, is this still a problem?) There was an exception when we call
206          * tvb_new_real_data() now there's no one
207          */
208
209         tvb->real_data       = buf;
210         tvb->length          = fd->cap_len;
211         tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
212         tvb->initialized     = TRUE;
213
214         /*
215          * This is the top-level real tvbuff for this data source,
216          * so its data source tvbuff is itself.
217          */
218         tvb->ds_tvb = tvb;
219
220         frame_tvb = (struct tvb_frame *) tvb;
221
222         /* XXX, wtap_can_seek() */
223         if (cfile.wth && cfile.wth->random_fh
224 #ifdef WANT_PACKET_EDITOR
225                 && fd->file_off != -1 /* generic clone for modified packets */
226 #endif
227         ) {
228                 frame_tvb->wth = cfile.wth;
229                 frame_tvb->file_off = fd->file_off;
230                 frame_tvb->offset = 0;
231         } else
232                 frame_tvb->wth = NULL;
233
234         frame_tvb->buf = NULL;
235
236         return tvb;
237 }
238
239 tvbuff_t *
240 frame_tvbuff_new_buffer(const frame_data *fd, Buffer *buf)
241 {
242         return frame_tvbuff_new(fd, ws_buffer_start_ptr(buf));
243 }
244
245 static tvbuff_t *
246 frame_clone(tvbuff_t *tvb, guint abs_offset, guint abs_length)
247 {
248         struct tvb_frame *frame_tvb = (struct tvb_frame *) tvb;
249
250         tvbuff_t *cloned_tvb;
251         struct tvb_frame *cloned_frame_tvb;
252
253         /* file not seekable */
254         if (!frame_tvb->wth)
255                 return NULL;
256
257         abs_offset += frame_tvb->offset;
258
259         cloned_tvb = tvb_new(&tvb_frame_ops);
260
261         /* data will be read when needed */
262         cloned_tvb->real_data       = NULL;
263         cloned_tvb->length          = abs_length;
264         cloned_tvb->reported_length = abs_length; /* XXX? */
265         cloned_tvb->initialized     = TRUE;
266
267         /*
268          * This is the top-level real tvbuff for this data source,
269          * so its data source tvbuff is itself.
270          */
271         cloned_tvb->ds_tvb = cloned_tvb;
272
273         cloned_frame_tvb = (struct tvb_frame *) cloned_tvb;
274         cloned_frame_tvb->wth = frame_tvb->wth;
275         cloned_frame_tvb->file_off = frame_tvb->file_off;
276         cloned_frame_tvb->offset = abs_offset;
277         cloned_frame_tvb->buf = NULL;
278
279         return cloned_tvb;
280 }
281
282
283 /* based on tvb_new_real_data() */
284 tvbuff_t *
285 file_tvbuff_new(const frame_data *fd, const guint8 *buf)
286 {
287         struct tvb_frame *frame_tvb;
288         tvbuff_t *tvb;
289
290         tvb = tvb_new(&tvb_frame_ops);
291
292         /*
293          * XXX - currently, the length arguments in
294          * tvbuff structure are signed, but the captured
295          * and reported length values are unsigned; this means
296          * that length values > 2^31 - 1 will appear as
297          * negative lengths
298          *
299          * Captured length values that large will already
300          * have been filtered out by the Wiretap modules
301          * (the file will be reported as corrupted), to
302          * avoid trying to allocate large chunks of data.
303          *
304          * Reported length values will not have been
305          * filtered out, and should not be filtered out,
306          * as those lengths are not necessarily invalid.
307          *
308          * For now, we clip the reported length at G_MAXINT
309          *
310          * (XXX, is this still a problem?) There was an exception when we call
311          * tvb_new_real_data() now there's no one
312          */
313
314         tvb->real_data       = buf;
315         tvb->length          = fd->cap_len;
316         tvb->reported_length = fd->pkt_len > G_MAXINT ? G_MAXINT : fd->pkt_len;
317         tvb->initialized     = TRUE;
318
319         /*
320          * This is the top-level real tvbuff for this data source,
321          * so its data source tvbuff is itself.
322          */
323         tvb->ds_tvb = tvb;
324
325         frame_tvb = (struct tvb_frame *) tvb;
326
327         /* XXX, wtap_can_seek() */
328         if (cfile.wth && cfile.wth->random_fh
329 #ifdef WANT_PACKET_EDITOR
330                 && fd->file_off != -1 /* generic clone for modified packets */
331 #endif
332         ) {
333                 frame_tvb->wth = cfile.wth;
334                 frame_tvb->file_off = fd->file_off;
335                 frame_tvb->offset = 0;
336         } else
337                 frame_tvb->wth = NULL;
338
339         frame_tvb->buf = NULL;
340
341         return tvb;
342 }
343
344 tvbuff_t *
345 file_tvbuff_new_buffer(const frame_data *fd, Buffer *buf)
346 {
347         return frame_tvbuff_new(fd, ws_buffer_start_ptr(buf));
348 }
349
350 /*
351  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
352  *
353  * Local variables:
354  * c-basic-offset: 8
355  * tab-width: 8
356  * indent-tabs-mode: t
357  * End:
358  *
359  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
360  * :indentSize=8:tabSize=8:noTabs=false:
361  */