ftypes: move set_value_floating into the union
[metze/wireshark/wip.git] / epan / ftypes / ftype-protocol.c
1 /*
2  * Wireshark - Network traffic analyzer
3  * By Gerald Combs <gerald@wireshark.org>
4  * Copyright 2001 Gerald Combs
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #include <ftypes-int.h>
24 #include <epan/to_str-int.h>
25 #include <string.h>
26
27 #include <epan/exceptions.h>
28
29 #define CMP_MATCHES cmp_matches
30
31 #define tvb_is_private  fvalue_gboolean1
32
33 static void
34 value_new(fvalue_t *fv)
35 {
36         fv->value.protocol.tvb = NULL;
37         fv->value.protocol.proto_string = NULL;
38         fv->tvb_is_private = FALSE;
39 }
40
41 static void
42 value_free(fvalue_t *fv)
43 {
44         if (fv->value.protocol.tvb && fv->tvb_is_private) {
45                 tvb_free_chain(fv->value.protocol.tvb);
46         }
47         g_free(fv->value.protocol.proto_string);
48 }
49
50 static void
51 value_set(fvalue_t *fv, tvbuff_t *value, const gchar *name)
52 {
53         /* Free up the old value, if we have one */
54         value_free(fv);
55
56         fv->value.protocol.tvb = value;
57         fv->value.protocol.proto_string = g_strdup(name);
58 }
59
60 static void
61 free_tvb_data(void *data)
62 {
63         g_free(data);
64 }
65
66 static gboolean
67 val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
68 {
69         tvbuff_t *new_tvb;
70         guint8 *private_data;
71
72         /* Free up the old value, if we have one */
73         value_free(fv);
74
75         /* Make a tvbuff from the string. We can drop the
76          * terminating NUL. */
77         private_data = (guint8 *)g_memdup(s, (guint)strlen(s));
78         new_tvb = tvb_new_real_data(private_data,
79                         (guint)strlen(s), (gint)strlen(s));
80
81         /* Let the tvbuff know how to delete the data. */
82         tvb_set_free_cb(new_tvb, free_tvb_data);
83
84         /* And let us know that we need to free the tvbuff */
85         fv->tvb_is_private = TRUE;
86         fv->value.protocol.tvb = new_tvb;
87         fv->value.protocol.proto_string = g_strdup(s);
88         return TRUE;
89 }
90
91 static gboolean
92 val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
93 {
94         fvalue_t *fv_bytes;
95         tvbuff_t *new_tvb;
96         guint8 *private_data;
97
98         /* Free up the old value, if we have one */
99         value_free(fv);
100
101         /* Does this look like a byte string? */
102         fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL);
103         if (fv_bytes) {
104                 /* Make a tvbuff from the bytes */
105                 private_data = (guint8 *)g_memdup(fv_bytes->value.bytes->data,
106                                 fv_bytes->value.bytes->len);
107                 new_tvb = tvb_new_real_data(private_data,
108                                 fv_bytes->value.bytes->len,
109                                 fv_bytes->value.bytes->len);
110
111                 /* Let the tvbuff know how to delete the data. */
112                 tvb_set_free_cb(new_tvb, free_tvb_data);
113
114                 /* And let us know that we need to free the tvbuff */
115                 fv->tvb_is_private = TRUE;
116                 fv->value.protocol.tvb = new_tvb;
117                 return TRUE;
118         }
119
120         /* Treat it as a string. */
121         return val_from_string(fv, s, err_msg);
122 }
123
124 static int
125 val_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
126 {
127         volatile guint length = 0;
128
129         if (rtype != FTREPR_DFILTER) return -1;
130
131         TRY {
132                 /* 3 bytes for each byte of the byte "NN:" minus 1 byte
133                  * as there's no trailing ":". */
134                 length = tvb_captured_length(fv->value.protocol.tvb) * 3 - 1;
135         }
136         CATCH_ALL {
137                 /* nothing */
138         }
139         ENDTRY;
140
141         return (int) length;
142 }
143
144 static void
145 val_to_repr(fvalue_t *fv, ftrepr_t rtype, int field_display _U_, char * volatile buf, unsigned int size _U_)
146 {
147         guint length;
148
149         g_assert(rtype == FTREPR_DFILTER);
150
151         TRY {
152                 length = tvb_captured_length(fv->value.protocol.tvb);
153
154                 if (length)
155                         buf = bytes_to_hexstr_punct(buf, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':');
156                 *buf = '\0';
157         }
158         CATCH_ALL {
159                 /* nothing */
160         }
161         ENDTRY;
162 }
163
164 static gpointer
165 value_get(fvalue_t *fv)
166 {
167         return fv->value.protocol.tvb;
168 }
169
170 static guint
171 len(fvalue_t *fv)
172 {
173         volatile guint length = 0;
174
175         TRY {
176                 if (fv->value.protocol.tvb)
177                         length = tvb_captured_length(fv->value.protocol.tvb);
178         }
179         CATCH_ALL {
180                 /* nothing */
181         }
182         ENDTRY;
183
184         return length;
185 }
186
187 static void
188 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
189 {
190         const guint8* data;
191
192         if (fv->value.protocol.tvb) {
193                 TRY {
194                         data = tvb_get_ptr(fv->value.protocol.tvb, offset, length);
195                         g_byte_array_append(bytes, data, length);
196                 }
197                 CATCH_ALL {
198                         /* nothing */
199                 }
200                 ENDTRY;
201
202         }
203 }
204
205 static gboolean
206 cmp_eq(const fvalue_t *fv_a, const fvalue_t *fv_b)
207 {
208         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
209         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
210         volatile gboolean       eq = FALSE;
211
212         TRY {
213                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
214                         guint   a_len = tvb_captured_length(a->tvb);
215
216                         if (a_len == tvb_captured_length(b->tvb))
217                                 eq = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) == 0);
218                 } else {
219                         eq = (strcmp(a->proto_string, b->proto_string) == 0);
220                 }
221         }
222         CATCH_ALL {
223                 /* nothing */
224         }
225         ENDTRY;
226
227         return eq;
228 }
229
230 static gboolean
231 cmp_ne(const fvalue_t *fv_a, const fvalue_t *fv_b)
232 {
233         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
234         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
235         volatile gboolean       ne = TRUE;
236
237         TRY {
238                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
239                         guint   a_len = tvb_captured_length(a->tvb);
240
241                         if (a_len == tvb_captured_length(b->tvb))
242                                 ne = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) != 0);
243                 } else {
244                         ne = (strcmp(a->proto_string, b->proto_string) != 0);
245                 }
246         }
247         CATCH_ALL {
248                 /* nothing */
249         }
250         ENDTRY;
251
252         return ne;
253 }
254
255 static gboolean
256 cmp_gt(const fvalue_t *fv_a, const fvalue_t *fv_b)
257 {
258         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
259         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
260         volatile gboolean       gt = FALSE;
261
262         TRY {
263                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
264                         guint   a_len = tvb_captured_length(a->tvb);
265                         guint   b_len = tvb_captured_length(b->tvb);
266
267                         if (a_len > b_len) {
268                                 gt = TRUE;
269                         } else if (a_len == b_len) {
270                                 gt = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) > 0);
271                         }
272                 } else {
273                         return (strcmp(a->proto_string, b->proto_string) > 0);
274                 }
275         }
276         CATCH_ALL {
277                 /* nothing */
278         }
279         ENDTRY;
280
281         return gt;
282 }
283
284 static gboolean
285 cmp_ge(const fvalue_t *fv_a, const fvalue_t *fv_b)
286 {
287         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
288         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
289         volatile gboolean       ge = FALSE;
290
291         TRY {
292                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
293                         guint   a_len = tvb_captured_length(a->tvb);
294                         guint   b_len = tvb_captured_length(b->tvb);
295
296                         if (a_len > b_len) {
297                                 ge = TRUE;
298                         } else if (a_len == b_len) {
299                                 ge = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) >= 0);
300                         }
301                 } else {
302                         return (strcmp(a->proto_string, b->proto_string) >= 0);
303                 }
304         }
305         CATCH_ALL {
306                 /* nothing */
307         }
308         ENDTRY;
309
310         return ge;
311 }
312
313 static gboolean
314 cmp_lt(const fvalue_t *fv_a, const fvalue_t *fv_b)
315 {
316         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
317         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
318         volatile gboolean       lt = FALSE;
319
320         TRY {
321                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
322                         guint   a_len = tvb_captured_length(a->tvb);
323                         guint   b_len = tvb_captured_length(b->tvb);
324
325                         if (a_len < b_len) {
326                                 lt = TRUE;
327                         } else if (a_len == b_len) {
328                                 lt = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) < 0);
329                         }
330                 } else {
331                         return (strcmp(a->proto_string, b->proto_string) < 0);
332                 }
333         }
334         CATCH_ALL {
335                 /* nothing */
336         }
337         ENDTRY;
338
339         return lt;
340 }
341
342 static gboolean
343 cmp_le(const fvalue_t *fv_a, const fvalue_t *fv_b)
344 {
345         const protocol_value_t  *a = (const protocol_value_t *)&fv_a->value.protocol;
346         const protocol_value_t  *b = (const protocol_value_t *)&fv_b->value.protocol;
347         volatile gboolean       le = FALSE;
348
349         TRY {
350                 if ((a->tvb != NULL) && (b->tvb != NULL)) {
351                         guint   a_len = tvb_captured_length(a->tvb);
352                         guint   b_len = tvb_captured_length(b->tvb);
353
354                         if (a_len < b_len) {
355                                 le = TRUE;
356                         } else if (a_len == b_len) {
357                                 le = (memcmp(tvb_get_ptr(a->tvb, 0, a_len), tvb_get_ptr(b->tvb, 0, a_len), a_len) <= 0);
358                         }
359                 } else {
360                         return (strcmp(a->proto_string, b->proto_string) <= 0);
361                 }
362         }
363         CATCH_ALL {
364                 /* nothing */
365         }
366         ENDTRY;
367
368         return le;
369 }
370
371 static gboolean
372 cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b)
373 {
374         volatile gboolean contains = FALSE;
375
376         TRY {
377                 /* First see if tvb exists for both sides */
378                 if ((fv_a->value.protocol.tvb != NULL) && (fv_b->value.protocol.tvb != NULL)) {
379                         if (tvb_find_tvb(fv_a->value.protocol.tvb, fv_b->value.protocol.tvb, 0) > -1) {
380                                 contains = TRUE;
381                         }
382                 } else {
383                         /* Otherwise just compare strings */
384                         if ((strlen(fv_b->value.protocol.proto_string) != 0) &&
385                                 strstr(fv_a->value.protocol.proto_string, fv_b->value.protocol.proto_string)) {
386                                 contains = TRUE;
387                         }
388                 }
389         }
390         CATCH_ALL {
391                 /* nothing */
392         }
393         ENDTRY;
394
395         return contains;
396 }
397
398 static gboolean
399 cmp_matches(const fvalue_t *fv_a, const fvalue_t *fv_b)
400 {
401         const protocol_value_t *a = (const protocol_value_t *)&fv_a->value.protocol;
402         GRegex *regex = fv_b->value.re;
403         volatile gboolean rc = FALSE;
404         const char *data = NULL; /* tvb data */
405         guint32 tvb_len; /* tvb length */
406
407         /* fv_b is always a FT_PCRE, otherwise the dfilter semcheck() would have
408          * warned us. For the same reason (and because we're using g_malloc()),
409          * fv_b->value.re is not NULL.
410          */
411         if (strcmp(fv_b->ftype->name, "FT_PCRE") != 0) {
412                 return FALSE;
413         }
414         if (! regex) {
415                 return FALSE;
416         }
417         TRY {
418                 if (a->tvb != NULL) {
419                         tvb_len = tvb_captured_length(a->tvb);
420                         data = (const char *)tvb_get_ptr(a->tvb, 0, tvb_len);
421                         rc = g_regex_match_full(
422                                 regex,          /* Compiled PCRE */
423                                 data,           /* The data to check for the pattern... */
424                                 tvb_len,        /* ... and its length */
425                                 0,              /* Start offset within data */
426                                 (GRegexMatchFlags)0,            /* GRegexMatchFlags */
427                                 NULL,           /* We are not interested in the match information */
428                                 NULL            /* We don't want error information */
429                                 );
430                         /* NOTE - DO NOT g_free(data) */
431                 } else {
432                         rc = g_regex_match_full(
433                         regex,          /* Compiled PCRE */
434                         a->proto_string,                /* The data to check for the pattern... */
435                         (int)strlen(a->proto_string),   /* ... and its length */
436                         0,              /* Start offset within data */
437                         (GRegexMatchFlags)0,            /* GRegexMatchFlags */
438                         NULL,           /* We are not interested in the match information */
439                         NULL            /* We don't want error information */
440                         );
441                 }
442         }
443         CATCH_ALL {
444                 return FALSE;
445         }
446         ENDTRY;
447         return rc;
448 }
449
450 void
451 ftype_register_tvbuff(void)
452 {
453
454         static ftype_t protocol_type = {
455                 FT_PROTOCOL,                    /* ftype */
456                 "FT_PROTOCOL",                  /* name */
457                 "Protocol",                     /* pretty_name */
458                 0,                              /* wire_size */
459                 value_new,                      /* new_value */
460                 value_free,                     /* free_value */
461                 val_from_unparsed,              /* val_from_unparsed */
462                 val_from_string,                /* val_from_string */
463                 val_to_repr,                    /* val_to_string_repr */
464                 val_repr_len,                   /* len_string_repr */
465
466                 { .set_value_protocol = value_set },    /* union set_value */
467
468
469                 value_get,                      /* get_value */
470                 NULL,                           /* get_value_uinteger */
471                 NULL,                           /* get_value_sinteger */
472                 NULL,                           /* get_value_uinteger64 */
473                 NULL,                           /* get_value_sinteger64 */
474                 NULL,                           /* get_value_floating */
475
476                 cmp_eq,
477                 cmp_ne,
478                 cmp_gt,
479                 cmp_ge,
480                 cmp_lt,
481                 cmp_le,
482                 NULL,                           /* cmp_bitwise_and */
483                 cmp_contains,
484                 CMP_MATCHES,
485
486                 len,
487                 slice,
488
489         };
490
491
492         ftype_register(FT_PROTOCOL, &protocol_type);
493 }
494
495 /*
496  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
497  *
498  * Local variables:
499  * c-basic-offset: 8
500  * tab-width: 8
501  * indent-tabs-mode: t
502  * End:
503  *
504  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
505  * :indentSize=8:tabSize=8:noTabs=false:
506  */