8e4a7050597cc690aa19c1d9023091b0b775f510
[obnox/wireshark/wip.git] / epan / ftypes / ftype-tvbuff.c
1 /*
2  * $Id$
3  *
4  * Ethereal - Network traffic analyzer
5  * By Gerald Combs <gerald@ethereal.com>
6  * Copyright 2001 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <ftypes-int.h>
28 #include <string.h>
29
30 #ifdef HAVE_LIBPCRE
31 #include <pcre.h>
32 #define CMP_MATCHES cmp_matches
33 #else
34 #define CMP_MATCHES NULL
35 #endif
36
37 #define tvb_is_private  fvalue_gboolean1
38
39 static void
40 value_new(fvalue_t *fv)
41 {
42         fv->value.tvb = NULL;
43         fv->tvb_is_private = FALSE;
44 }
45
46 static void
47 value_free(fvalue_t *fv)
48 {
49         if (fv->value.tvb && fv->tvb_is_private) {
50                 tvb_free_chain(fv->value.tvb);
51         }
52 }
53
54 static void
55 value_set(fvalue_t *fv, gpointer value, gboolean already_copied)
56 {
57         g_assert(already_copied);
58
59         /* Free up the old value, if we have one */
60         value_free(fv);
61
62         fv->value.tvb = value;
63 }
64
65 static void
66 free_tvb_data(void *data)
67 {
68         g_free(data);
69 }
70
71 static gboolean
72 val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_)
73 {
74         tvbuff_t *new_tvb;
75         guint8 *private_data;
76
77         /* Free up the old value, if we have one */
78         value_free(fv);
79
80         /* Make a tvbuff from the string. We can drop the
81          * terminating NUL. */
82         private_data = g_memdup(s, strlen(s)); 
83         new_tvb = tvb_new_real_data(private_data, 
84                         strlen(s), strlen(s));
85
86         /* Let the tvbuff know how to delete the data. */
87         tvb_set_free_cb(new_tvb, free_tvb_data);
88
89         /* And let us know that we need to free the tvbuff */
90         fv->tvb_is_private = TRUE;
91         fv->value.tvb = new_tvb;
92         return TRUE;
93 }
94
95 static gboolean
96 val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
97 {
98         fvalue_t *fv_bytes;
99         tvbuff_t *new_tvb;
100         guint8 *private_data;
101
102         /* Free up the old value, if we have one */
103         value_free(fv);
104
105         /* Does this look like a byte string? */
106         fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL);
107         if (fv_bytes) {
108                 /* Make a tvbuff from the bytes */
109                 private_data = g_memdup(fv_bytes->value.bytes->data,
110                                 fv_bytes->value.bytes->len);
111                 new_tvb = tvb_new_real_data(private_data, 
112                                 fv_bytes->value.bytes->len,
113                                 fv_bytes->value.bytes->len);
114
115                 /* Let the tvbuff know how to delete the data. */
116                 tvb_set_free_cb(new_tvb, free_tvb_data);
117
118                 /* And let us know that we need to free the tvbuff */
119                 fv->tvb_is_private = TRUE;
120                 fv->value.tvb = new_tvb;
121                 return TRUE;
122         }
123         else {
124                 /* Treat it as a string. */
125                 return val_from_string(fv, s, logfunc);
126         }
127         g_assert_not_reached();
128 }
129
130 static int
131 val_repr_len(fvalue_t *fv, ftrepr_t rtype)
132 {
133         guint length;
134
135         g_assert(rtype == FTREPR_DFILTER);
136         length = tvb_length(fv->value.tvb);
137         /* 3 bytes for each byte of the byte "NN:" minus 1 byte
138          * as there's no trailing ":". */
139         return length * 3 - 1;
140 }
141
142 static void
143 val_to_repr(fvalue_t *fv, ftrepr_t rtype, char *buf)
144 {
145         guint length;
146         const guint8 *c;
147         char *write_cursor;
148         unsigned int i;
149
150         g_assert(rtype == FTREPR_DFILTER);
151         length = tvb_length(fv->value.tvb);
152         c = tvb_get_ptr(fv->value.tvb, 0, length);
153         write_cursor = buf;
154
155         for (i = 0; i < length; i++) {
156                 if (i == 0) {
157                         sprintf(write_cursor, "%02x", *c++);
158                         write_cursor += 2;
159                 }
160                 else {
161                         sprintf(write_cursor, ":%02x", *c++);
162                         write_cursor += 3;
163                 }
164         }
165 }
166
167 static gpointer
168 value_get(fvalue_t *fv)
169 {
170         return fv->value.tvb;
171 }
172
173 static guint
174 len(fvalue_t *fv)
175 {
176         if (fv->value.tvb)
177                 return tvb_length(fv->value.tvb);
178         else
179                 return 0;
180 }
181
182 static void
183 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
184 {
185         const guint8* data;
186
187         if (fv->value.tvb) {
188                 TRY {
189                         data = tvb_get_ptr(fv->value.tvb, offset, length);
190                         g_byte_array_append(bytes, data, length);
191                 }
192                 CATCH_ALL {
193                         /* nothing */
194                 }
195                 ENDTRY;
196
197         }
198 }
199
200 static gboolean
201 cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b)
202 {
203         if (tvb_find_tvb(fv_a->value.tvb, fv_b->value.tvb, 0) > -1) {
204                 return TRUE;
205         }
206         else {
207                 return FALSE;
208         }
209 }
210
211 #ifdef HAVE_LIBPCRE
212 static gboolean
213 cmp_matches(fvalue_t *fv_a, fvalue_t *fv_b)
214 {
215         tvbuff_t *tvb = fv_a->value.tvb;
216         pcre_tuple_t *pcre = fv_b->value.re;
217         int options = 0;
218         volatile int rc = 1;
219         const char *data = NULL; /* tvb data */
220         guint32 tvb_len; /* tvb length */
221
222         /* fv_b is always a FT_PCRE, otherwise the dfilter semcheck() would have
223          * warned us. For the same reason (and because we're using g_malloc()),
224          * fv_b->value.re is not NULL.
225          */
226         if (strcmp(fv_b->ftype->name, "FT_PCRE") != 0) {
227                 return FALSE;
228         }
229         if (! pcre) {
230                 return FALSE;
231         }
232         TRY {
233                 tvb_len = tvb_length(tvb);
234                 data = (const char *)tvb_get_ptr(tvb, 0, tvb_len);
235                 rc = pcre_exec(
236                         pcre->re,       /* Compiled PCRE */
237                         pcre->ex,       /* PCRE extra from pcre_study() */
238                         data,           /* The data to check for the pattern... */
239                         tvb_len,        /* ... and its length */
240                         0,              /* Start offset within data */
241                         options,        /* PCRE options */
242                         NULL,           /* We are not interested in the matched string */
243                         0               /* of the pattern; only in success or failure. */
244                         );
245                 /* NOTE - DO NOT g_free(data) */
246         }
247         CATCH_ALL {
248                 return FALSE;
249         }
250         ENDTRY;
251         if (rc == 0) {
252                 return TRUE;
253         }
254         return FALSE;
255 }
256 #endif
257
258 void
259 ftype_register_tvbuff(void)
260 {
261
262         static ftype_t protocol_type = {
263                 FT_PROTOCOL,                    /* ftype */
264                 "FT_PROTOCOL",                  /* name */
265                 "protocol",                     /* pretty_name */
266                 0,                              /* wire_size */
267                 value_new,                      /* new_value */
268                 value_free,                     /* free_value */
269                 val_from_unparsed,              /* val_from_unparsed */
270                 val_from_string,                /* val_from_string */
271                 val_to_repr,                    /* val_to_string_repr */
272                 val_repr_len,                   /* len_string_repr */
273
274                 value_set,                      /* set_value */
275                 NULL,                           /* set_value_integer */
276                 NULL,                           /* set_value_integer64 */
277                 NULL,                           /* set_value_floating */
278
279                 value_get,                      /* get_value */
280                 NULL,                           /* get_value_integer */
281                 NULL,                           /* get_value_integer64 */
282                 NULL,                           /* get_value_floating */
283
284
285                 /* TODO - tvb's *can* do 'eq', etc. */
286
287                 NULL,                           /* cmp_eq */
288                 NULL,                           /* cmp_ne */
289                 NULL,                           /* cmp_gt */
290                 NULL,                           /* cmp_ge */
291                 NULL,                           /* cmp_lt */
292                 NULL,                           /* cmp_le */
293                 NULL,                           /* cmp_bitwise_and */
294                 cmp_contains,
295                 CMP_MATCHES,
296
297                 len,
298                 slice,
299
300         };
301
302
303         ftype_register(FT_PROTOCOL, &protocol_type);
304 }