ftypes: move set_value_sinteger into the union
[metze/wireshark/wip.git] / epan / ftypes / ftype-pcre.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 /* Perl-Compatible Regular Expression (PCRE) internal field type.
22  * Used with the "matches" dfilter operator, allowing efficient
23  * compilation and studying of a PCRE pattern in dfilters.
24  */
25
26 #include "config.h"
27
28 #include <ftypes-int.h>
29
30 #include <glib.h>
31 #include <string.h>
32
33 static void
34 gregex_fvalue_new(fvalue_t *fv)
35 {
36     fv->value.re = NULL;
37 }
38
39 static void
40 gregex_fvalue_free(fvalue_t *fv)
41 {
42     if (fv->value.re) {
43         g_regex_unref(fv->value.re);
44         fv->value.re = NULL;
45     }
46 }
47
48 /* Determines whether pattern needs to match raw byte sequences */
49 static gboolean
50 raw_flag_needed(const gchar *pattern)
51 {
52     gboolean found = FALSE;
53     const gchar *s = pattern;
54     size_t i, len;
55
56     /* find any character whose hex value is two letters */
57     len = strlen(s);
58     for (i = 0; i < len; i++) {
59         /* Upper and lower-nibble must be >= 0xA */
60         if ((guchar)(s[i] & 0xF0) >= 0xA0 &&
61             (guchar)(s[i] & 0x0F) >= 0x0A)
62         {
63             found = TRUE;
64             break;
65         }
66     }
67     return found;
68 }
69
70 /* Generate a FT_PCRE from a parsed string pattern.
71  * On failure, if err_msg is non-null, set *err_msg to point to a
72  * g_malloc()ed error message. */
73 static gboolean
74 val_from_string(fvalue_t *fv, const char *pattern, gchar **err_msg)
75 {
76     GError *regex_error = NULL;
77     GRegexCompileFlags cflags = G_REGEX_OPTIMIZE;
78
79     /* Set RAW flag only if pattern requires matching raw byte
80        sequences. Otherwise, omit it so that GRegex treats its
81        input as UTF8-encoded string. */
82     if (raw_flag_needed(pattern)) {
83         cflags = (GRegexCompileFlags)(G_REGEX_OPTIMIZE | G_REGEX_RAW);
84     }
85
86     /* Free up the old value, if we have one */
87     gregex_fvalue_free(fv);
88
89     fv->value.re = g_regex_new(
90             pattern,            /* pattern */
91             cflags,             /* Compile options */
92             (GRegexMatchFlags)0,                  /* Match options */
93             &regex_error        /* Compile / study errors */
94             );
95
96     if (regex_error) {
97         if (err_msg) {
98             *err_msg = g_strdup(regex_error->message);
99         }
100         g_error_free(regex_error);
101         if (fv->value.re) {
102             g_regex_unref(fv->value.re);
103         }
104         return FALSE;
105     }
106     return TRUE;
107 }
108
109 /* Generate a FT_PCRE from an unparsed string pattern.
110  * On failure, if err_msg is non-null, set *err_msg to point to a
111  * g_malloc()ed error message. */
112 static gboolean
113 val_from_unparsed(fvalue_t *fv, const char *pattern, gboolean allow_partial_value, gchar **err_msg)
114 {
115     g_assert(! allow_partial_value);
116
117     return val_from_string(fv, pattern, err_msg);
118 }
119
120 static int
121 gregex_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
122 {
123     g_assert(rtype == FTREPR_DFILTER);
124     return (int)strlen(g_regex_get_pattern(fv->value.re));
125 }
126
127 static void
128 gregex_to_repr(fvalue_t *fv, ftrepr_t rtype, int field_display _U_, char *buf, unsigned int size)
129 {
130     g_assert(rtype == FTREPR_DFILTER);
131     g_strlcpy(buf, g_regex_get_pattern(fv->value.re), size);
132 }
133
134 /* BEHOLD - value contains the string representation of the regular expression,
135  * and we want to store the compiled PCRE RE object into the value. */
136 static void
137 gregex_fvalue_set(fvalue_t *fv, const char *value)
138 {
139     g_assert(value != NULL);
140     /* Free up the old value, if we have one */
141     gregex_fvalue_free(fv);
142     val_from_unparsed(fv, value, FALSE, NULL);
143 }
144
145 static gpointer
146 gregex_fvalue_get(fvalue_t *fv)
147 {
148     return fv->value.re;
149 }
150
151 void
152 ftype_register_pcre(void)
153 {
154     static ftype_t pcre_type = {
155         FT_PCRE,            /* ftype */
156         "FT_PCRE",          /* name */
157         "Compiled Perl-Compatible Regular Expression (GRegex) object", /* pretty_name */
158         0,                  /* wire_size */
159         gregex_fvalue_new,  /* new_value */
160         gregex_fvalue_free, /* free_value */
161         val_from_unparsed,  /* val_from_unparsed */
162         val_from_string,    /* val_from_string */
163         gregex_to_repr,     /* val_to_string_repr */
164         gregex_repr_len,    /* len_string_repr */
165
166         { .set_value_string = gregex_fvalue_set }, /* union set_value */
167
168         NULL,               /* set_value_uinteger64 */
169         NULL,               /* set_value_sinteger64 */
170         NULL,               /* set_value_floating */
171
172         gregex_fvalue_get,  /* get_value */
173         NULL,               /* get_value_uinteger */
174         NULL,               /* get_value_sinteger */
175         NULL,               /* get_value_uinteger64 */
176         NULL,               /* get_value_sinteger64 */
177         NULL,               /* get_value_floating */
178
179         NULL,               /* cmp_eq */
180         NULL,               /* cmp_ne */
181         NULL,               /* cmp_gt */
182         NULL,               /* cmp_ge */
183         NULL,               /* cmp_lt */
184         NULL,               /* cmp_le */
185         NULL,               /* cmp_bitwise_and */
186         NULL,               /* cmp_contains */
187         NULL,               /* cmp_matches */
188
189         NULL,               /* len */
190         NULL,               /* slice */
191     };
192     ftype_register(FT_PCRE, &pcre_type);
193 }
194
195 /*
196  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
197  *
198  * Local variables:
199  * c-basic-offset: 4
200  * tab-width: 8
201  * indent-tabs-mode: nil
202  * End:
203  *
204  * vi: set shiftwidth=4 tabstop=8 expandtab:
205  * :indentSize=4:tabSize=8:noTabs=true:
206  */