From Pekka Pietikainen <pp@ee.oulu.fi>, add a byte to the hex[]
[metze/wireshark/wip.git] / epan / ftypes / ftype-string.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 #include <ctype.h>
38
39 static void
40 string_fvalue_new(fvalue_t *fv)
41 {
42         fv->value.string = NULL;
43 }
44
45 static void
46 string_fvalue_free(fvalue_t *fv)
47 {
48         if (fv->value.string) {
49                 g_free(fv->value.string);
50         }
51 }
52
53 static void
54 string_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
55 {
56         g_assert(value != NULL);
57
58         /* Free up the old value, if we have one */
59         string_fvalue_free(fv);
60
61         if (already_copied) {
62                 fv->value.string = value;
63         }
64         else {
65                 fv->value.string = g_strdup(value);
66         }
67 }
68
69 static int
70 string_repr_len(fvalue_t *fv, ftrepr_t rtype)
71 {
72         gchar *p, c;
73         int repr_len;
74
75         switch (rtype) {
76                 case FTREPR_DISPLAY:
77                         return strlen(fv->value.string);
78                 case FTREPR_DFILTER:
79                         repr_len = 0;
80                         for (p = fv->value.string; (c = *p) != '\0'; p++) {
81                                 /* Backslashes and double-quotes must
82                                  * be escaped */
83                                 if (c == '\\' || c == '"') {
84                                         repr_len += 2;
85                                 }
86                                 /* Values that can't nicely be represented
87                                  * in ASCII need to be escaped. */
88                                 else if (!isprint((unsigned char)c)) {
89                                         /* c --> \xNN */
90                                         repr_len += 4;
91                                 }
92                                 /* Other characters are just passed through. */
93                                 else {
94                                         repr_len++;
95                                 }
96                         }
97                         return repr_len + 2;    /* string plus leading and trailing quotes */
98         }
99         g_assert_not_reached();
100         return -1;
101 }
102
103 static void
104 string_to_repr(fvalue_t *fv, ftrepr_t rtype, char *buf)
105 {
106         gchar *p, c;
107         char *bufp;
108         char hex[3];
109
110         if (rtype == FTREPR_DFILTER) {
111                 bufp = buf;
112                 *bufp++ = '"';
113                 for (p = fv->value.string; (c = *p) != '\0'; p++) {
114                         /* Backslashes and double-quotes must
115                          * be escaped. */
116                         if (c == '\\' || c == '"') {
117                                 *bufp++ = '\\';
118                                 *bufp++ = c;
119                         }
120                         /* Values that can't nicely be represented
121                          * in ASCII need to be escaped. */
122                         else if (!isprint((unsigned char)c)) {
123                                 /* c --> \xNN */
124                                 sprintf(hex, "%02x", (unsigned char) c);
125                                 *bufp++ = '\\';
126                                 *bufp++ = 'x';
127                                 *bufp++ = hex[0];
128                                 *bufp++ = hex[1];
129                         }
130                         /* Other characters are just passed through. */
131                         else {
132                                 *bufp++ = c;
133                         }
134                 }
135                 *bufp++ = '"';
136                 *bufp = '\0';
137         }
138         else {
139                 strcpy(buf, fv->value.string);
140         }
141 }
142
143
144 static gpointer
145 value_get(fvalue_t *fv)
146 {
147         return fv->value.string;
148 }
149
150 static gboolean
151 val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_)
152 {
153         /* Free up the old value, if we have one */
154         string_fvalue_free(fv);
155
156         fv->value.string = g_strdup(s);
157         return TRUE;
158 }
159
160 static gboolean
161 val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc)
162 {
163         fvalue_t *fv_bytes;
164
165         /* Free up the old value, if we have one */
166         string_fvalue_free(fv);
167
168         /* Does this look like a byte-string? */
169         fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL);
170         if (fv_bytes) {
171                 /* Copy the bytes over to a string and terminate it
172                  * with a NUL. XXX - what if the user embeds a NUL
173                  * in the middle of the byte string? */
174                 int num_bytes = fv_bytes->value.bytes->len;
175
176                 fv->value.string = g_malloc(num_bytes + 1);
177                 memcpy(fv->value.string, fv_bytes->value.bytes->data, num_bytes);
178                 fv->value.string[num_bytes] = '\0';
179
180                 FVALUE_FREE(fv_bytes);
181                 return TRUE;
182         }
183         else {
184                 /* Just turn it into a string */
185                 return val_from_string(fv, s, logfunc);
186         }
187         g_assert_not_reached();
188 }
189
190 static guint
191 len(fvalue_t *fv)
192 {
193         return strlen(fv->value.string);
194 }
195
196 static void
197 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
198 {
199         guint8* data;
200
201         data = fv->value.ustring + offset;
202
203         g_byte_array_append(bytes, data, length);
204 }
205
206
207 static gboolean
208 cmp_eq(fvalue_t *a, fvalue_t *b)
209 {
210         return (strcmp(a->value.string, b->value.string) == 0);
211 }
212
213 static gboolean
214 cmp_ne(fvalue_t *a, fvalue_t *b)
215 {
216         return (strcmp(a->value.string, b->value.string) != 0);
217 }
218
219 static gboolean
220 cmp_gt(fvalue_t *a, fvalue_t *b)
221 {
222         return (strcmp(a->value.string, b->value.string) > 0);
223 }
224
225 static gboolean
226 cmp_ge(fvalue_t *a, fvalue_t *b)
227 {
228         return (strcmp(a->value.string, b->value.string) >= 0);
229 }
230
231 static gboolean
232 cmp_lt(fvalue_t *a, fvalue_t *b)
233 {
234         return (strcmp(a->value.string, b->value.string) < 0);
235 }
236
237 static gboolean
238 cmp_le(fvalue_t *a, fvalue_t *b)
239 {
240         return (strcmp(a->value.string, b->value.string) <= 0);
241 }
242
243 static gboolean
244 cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b)
245 {
246         /* According to
247         * http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html
248         * strstr() returns a non-NULL value if needle is an empty
249         * string. We don't that behavior for cmp_contains. */
250         if (strlen(fv_b->value.string) == 0) {
251                 return FALSE;
252         }
253
254         if (strstr(fv_a->value.string, fv_b->value.string)) {
255                 return TRUE;
256         }
257         else {
258                 return FALSE;
259         }
260 }
261
262 #ifdef HAVE_LIBPCRE
263 static gboolean
264 cmp_matches(fvalue_t *fv_a, fvalue_t *fv_b)
265 {
266         char *str = fv_a->value.string;
267         pcre_tuple_t *pcre = fv_b->value.re;
268         int options = 0;
269         int rc;
270
271         /* fv_b is always a FT_PCRE, otherwise the dfilter semcheck() would have
272          * warned us. For the same reason (and because we're using g_malloc()),
273          * fv_b->value.re is not NULL.
274          */
275         if (strcmp(fv_b->ftype->name, "FT_PCRE") != 0) {
276                 return FALSE;
277         }
278         if (! pcre) {
279                 return FALSE;
280         }
281         rc = pcre_exec(
282                         pcre->re,       /* Compiled PCRE */
283                         pcre->ex,       /* PCRE extra from pcre_study() */
284                         str,                            /* The data to check for the pattern... */
285                         (int)strlen(str),       /* ... and its length */
286                         0,                      /* Start offset within data */
287                         options,        /* PCRE options */
288                         NULL,           /* We are not interested in the matched string */
289                         0                       /* of the pattern; only in success or failure. */
290                         );
291         if (rc == 0) {
292                 return TRUE;
293         }
294         return FALSE;
295 }
296 #endif
297
298 void
299 ftype_register_string(void)
300 {
301
302         static ftype_t string_type = {
303                 "FT_STRING",                    /* name */
304                 "character string",             /* pretty_name */
305                 0,                              /* wire_size */
306                 string_fvalue_new,              /* new_value */
307                 string_fvalue_free,             /* free_value */
308                 val_from_unparsed,              /* val_from_unparsed */
309                 val_from_string,                /* val_from_string */
310                 string_to_repr,                 /* val_to_string_repr */
311                 string_repr_len,                /* len_string_repr */
312
313                 string_fvalue_set,              /* set_value */
314                 NULL,                           /* set_value_integer */
315                 NULL,                           /* set_value_integer64 */
316                 NULL,                           /* set_value_floating */
317
318                 value_get,                      /* get_value */
319                 NULL,                           /* get_value_integer */
320                 NULL,                           /* get_value_integer64 */
321                 NULL,                           /* get_value_floating */
322
323                 cmp_eq,
324                 cmp_ne,
325                 cmp_gt,
326                 cmp_ge,
327                 cmp_lt,
328                 cmp_le,
329                 NULL,                           /* cmp_bitwise_and */
330                 cmp_contains,
331                 CMP_MATCHES,
332
333                 len,
334                 slice,
335         };
336         static ftype_t stringz_type = {
337                 "FT_STRINGZ",                   /* name */
338                 "character string",             /* pretty name */
339                 0,                              /* wire_size */
340                 string_fvalue_new,              /* new_value */
341                 string_fvalue_free,             /* free_value */
342                 val_from_unparsed,              /* val_from_unparsed */
343                 val_from_string,                /* val_from_string */
344                 NULL,                           /* val_to_string_repr */
345                 NULL,                           /* len_string_repr */
346
347                 string_fvalue_set,              /* set_value */
348                 NULL,                           /* set_value_integer */
349                 NULL,                           /* set_value_integer64 */
350                 NULL,                           /* set_value_floating */
351
352                 value_get,                      /* get_value */
353                 NULL,                           /* get_value_integer */
354                 NULL,                           /* get_value_integer64 */
355                 NULL,                           /* get_value_floating */
356
357                 cmp_eq,
358                 cmp_ne,
359                 cmp_gt,
360                 cmp_ge,
361                 cmp_lt,
362                 cmp_le,
363                 NULL,                           /* cmp_bitwise_and */
364                 cmp_contains,                   /* cmp_contains */
365                 CMP_MATCHES,
366
367                 len,
368                 slice,
369         };
370         static ftype_t uint_string_type = {
371                 "FT_UINT_STRING",               /* name */
372                 "character string",             /* pretty_name */
373                 0,                              /* wire_size */
374                 string_fvalue_new,              /* new_value */
375                 string_fvalue_free,             /* free_value */
376                 val_from_unparsed,              /* val_from_unparsed */
377                 val_from_string,                /* val_from_string */
378                 NULL,                           /* val_to_string_repr */
379                 NULL,                           /* len_string_repr */
380
381                 string_fvalue_set,              /* set_value */
382                 NULL,                           /* set_value_integer */
383                 NULL,                           /* set_value_integer64 */
384                 NULL,                           /* set_value_floating */
385
386                 value_get,                      /* get_value */
387                 NULL,                           /* get_value_integer */
388                 NULL,                           /* get_value_integer64 */
389                 NULL,                           /* get_value_floating */
390
391                 cmp_eq,
392                 cmp_ne,
393                 cmp_gt,
394                 cmp_ge,
395                 cmp_lt,
396                 cmp_le,
397                 NULL,                           /* cmp_bitwise_and */
398                 cmp_contains,                   /* cmp_contains */
399                 CMP_MATCHES,
400
401                 len,
402                 slice,
403         };
404
405         ftype_register(FT_STRING, &string_type);
406         ftype_register(FT_STRINGZ, &stringz_type);
407         ftype_register(FT_UINT_STRING, &uint_string_type);
408 }