1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "config.h"
10
11 #include <stdio.h>
12 #include <ftypes-int.h>
13 #include <string.h>
14
15 #define CMP_MATCHES cmp_matches
16
17 #include <strutil.h>
18 #include <wsutil/ws_assert.h>
19
20 static void
string_fvalue_new(fvalue_t * fv)21 string_fvalue_new(fvalue_t *fv)
22 {
23 fv->value.string = NULL;
24 }
25
26 static void
string_fvalue_free(fvalue_t * fv)27 string_fvalue_free(fvalue_t *fv)
28 {
29 g_free(fv->value.string);
30 }
31
32 static void
string_fvalue_set_string(fvalue_t * fv,const gchar * value)33 string_fvalue_set_string(fvalue_t *fv, const gchar *value)
34 {
35 DISSECTOR_ASSERT(value != NULL);
36
37 /* Free up the old value, if we have one */
38 string_fvalue_free(fv);
39
40 fv->value.string = (gchar *)g_strdup(value);
41 }
42
43 static int
string_repr_len(fvalue_t * fv,ftrepr_t rtype,int field_display _U_)44 string_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display _U_)
45 {
46 switch (rtype) {
47 case FTREPR_DISPLAY:
48 return (int)strlen(fv->value.string);
49
50 case FTREPR_DFILTER:
51 return escape_string_len(fv->value.string);
52 }
53 ws_assert_not_reached();
54 return -1;
55 }
56
57 static void
string_to_repr(fvalue_t * fv,ftrepr_t rtype,int field_display _U_,char * buf,unsigned int size)58 string_to_repr(fvalue_t *fv, ftrepr_t rtype, int field_display _U_, char *buf, unsigned int size)
59 {
60 switch (rtype) {
61 case FTREPR_DISPLAY:
62 (void) g_strlcpy(buf, fv->value.string, size);
63 return;
64
65 case FTREPR_DFILTER:
66 escape_string(buf, fv->value.string);
67 return;
68 }
69 ws_assert_not_reached();
70 }
71
72
73 static gpointer
value_get(fvalue_t * fv)74 value_get(fvalue_t *fv)
75 {
76 return fv->value.string;
77 }
78
79 static gboolean
val_from_string(fvalue_t * fv,const char * s,gchar ** err_msg _U_)80 val_from_string(fvalue_t *fv, const char *s, gchar **err_msg _U_)
81 {
82 /* Free up the old value, if we have one */
83 string_fvalue_free(fv);
84
85 fv->value.string = g_strdup(s);
86 return TRUE;
87 }
88
89 static gboolean
val_from_unparsed(fvalue_t * fv,const char * s,gboolean allow_partial_value _U_,gchar ** err_msg)90 val_from_unparsed(fvalue_t *fv, const char *s, gboolean allow_partial_value _U_, gchar **err_msg)
91 {
92 fvalue_t *fv_bytes;
93
94 /* Does this look like a byte-string? */
95 fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL);
96 if (fv_bytes) {
97 /* Free up the old value, if we have one */
98 string_fvalue_free(fv);
99
100 /* Copy the bytes over to a string and terminate it
101 * with a NUL. XXX - what if the user embeds a NUL
102 * in the middle of the byte string? */
103 int num_bytes = fv_bytes->value.bytes->len;
104
105 fv->value.string = (gchar *)g_malloc(num_bytes + 1);
106 memcpy(fv->value.string, fv_bytes->value.bytes->data, num_bytes);
107 fv->value.string[num_bytes] = '\0';
108
109 FVALUE_FREE(fv_bytes);
110 return TRUE;
111 } else {
112 /* Just turn it into a string */
113 return val_from_string(fv, s, err_msg);
114 }
115 }
116
117 static guint
len(fvalue_t * fv)118 len(fvalue_t *fv)
119 {
120 return (guint)strlen(fv->value.string);
121 }
122
123 static void
slice(fvalue_t * fv,GByteArray * bytes,guint offset,guint length)124 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
125 {
126 guint8* data;
127
128 data = fv->value.ustring + offset;
129
130 g_byte_array_append(bytes, data, length);
131 }
132
133
134 static gboolean
cmp_eq(const fvalue_t * a,const fvalue_t * b)135 cmp_eq(const fvalue_t *a, const fvalue_t *b)
136 {
137 return (strcmp(a->value.string, b->value.string) == 0);
138 }
139
140 static gboolean
cmp_ne(const fvalue_t * a,const fvalue_t * b)141 cmp_ne(const fvalue_t *a, const fvalue_t *b)
142 {
143 return (strcmp(a->value.string, b->value.string) != 0);
144 }
145
146 static gboolean
cmp_gt(const fvalue_t * a,const fvalue_t * b)147 cmp_gt(const fvalue_t *a, const fvalue_t *b)
148 {
149 return (strcmp(a->value.string, b->value.string) > 0);
150 }
151
152 static gboolean
cmp_ge(const fvalue_t * a,const fvalue_t * b)153 cmp_ge(const fvalue_t *a, const fvalue_t *b)
154 {
155 return (strcmp(a->value.string, b->value.string) >= 0);
156 }
157
158 static gboolean
cmp_lt(const fvalue_t * a,const fvalue_t * b)159 cmp_lt(const fvalue_t *a, const fvalue_t *b)
160 {
161 return (strcmp(a->value.string, b->value.string) < 0);
162 }
163
164 static gboolean
cmp_le(const fvalue_t * a,const fvalue_t * b)165 cmp_le(const fvalue_t *a, const fvalue_t *b)
166 {
167 return (strcmp(a->value.string, b->value.string) <= 0);
168 }
169
170 static gboolean
cmp_contains(const fvalue_t * fv_a,const fvalue_t * fv_b)171 cmp_contains(const fvalue_t *fv_a, const fvalue_t *fv_b)
172 {
173 /* According to
174 * http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html
175 * strstr() returns a non-NULL value if needle is an empty
176 * string. We don't that behavior for cmp_contains. */
177 if (strlen(fv_b->value.string) == 0) {
178 return FALSE;
179 }
180
181 if (strstr(fv_a->value.string, fv_b->value.string)) {
182 return TRUE;
183 }
184 else {
185 return FALSE;
186 }
187 }
188
189 static gboolean
cmp_matches(const fvalue_t * fv,const GRegex * regex)190 cmp_matches(const fvalue_t *fv, const GRegex *regex)
191 {
192 char *str = fv->value.string;
193
194 if (! regex) {
195 return FALSE;
196 }
197 return g_regex_match_full(
198 regex, /* Compiled PCRE */
199 str, /* The data to check for the pattern... */
200 (int)strlen(str), /* ... and its length */
201 0, /* Start offset within data */
202 (GRegexMatchFlags)0, /* GRegexMatchFlags */
203 NULL, /* We are not interested in the match information */
204 NULL /* We don't want error information */
205 );
206 }
207
208 void
ftype_register_string(void)209 ftype_register_string(void)
210 {
211
212 static ftype_t string_type = {
213 FT_STRING, /* ftype */
214 "FT_STRING", /* name */
215 "Character string", /* pretty_name */
216 0, /* wire_size */
217 string_fvalue_new, /* new_value */
218 string_fvalue_free, /* free_value */
219 val_from_unparsed, /* val_from_unparsed */
220 val_from_string, /* val_from_string */
221 string_to_repr, /* val_to_string_repr */
222 string_repr_len, /* len_string_repr */
223
224 { .set_value_string = string_fvalue_set_string }, /* union set_value */
225 { .get_value_ptr = value_get }, /* union get_value */
226
227 cmp_eq,
228 cmp_ne,
229 cmp_gt,
230 cmp_ge,
231 cmp_lt,
232 cmp_le,
233 NULL, /* cmp_bitwise_and */
234 cmp_contains,
235 CMP_MATCHES,
236
237 len,
238 slice,
239 };
240 static ftype_t stringz_type = {
241 FT_STRINGZ, /* ftype */
242 "FT_STRINGZ", /* name */
243 "Character string", /* pretty name */
244 0, /* wire_size */
245 string_fvalue_new, /* new_value */
246 string_fvalue_free, /* free_value */
247 val_from_unparsed, /* val_from_unparsed */
248 val_from_string, /* val_from_string */
249 string_to_repr, /* val_to_string_repr */
250 string_repr_len, /* len_string_repr */
251
252 { .set_value_string = string_fvalue_set_string }, /* union set_value */
253 { .get_value_ptr = value_get }, /* union get_value */
254
255 cmp_eq,
256 cmp_ne,
257 cmp_gt,
258 cmp_ge,
259 cmp_lt,
260 cmp_le,
261 NULL, /* cmp_bitwise_and */
262 cmp_contains, /* cmp_contains */
263 CMP_MATCHES,
264
265 len,
266 slice,
267 };
268 static ftype_t uint_string_type = {
269 FT_UINT_STRING, /* ftype */
270 "FT_UINT_STRING", /* name */
271 "Character string", /* pretty_name */
272 0, /* wire_size */
273 string_fvalue_new, /* new_value */
274 string_fvalue_free, /* free_value */
275 val_from_unparsed, /* val_from_unparsed */
276 val_from_string, /* val_from_string */
277 string_to_repr, /* val_to_string_repr */
278 string_repr_len, /* len_string_repr */
279
280 { .set_value_string = string_fvalue_set_string }, /* union set_value */
281 { .get_value_ptr = value_get }, /* union get_value */
282
283 cmp_eq,
284 cmp_ne,
285 cmp_gt,
286 cmp_ge,
287 cmp_lt,
288 cmp_le,
289 NULL, /* cmp_bitwise_and */
290 cmp_contains, /* cmp_contains */
291 CMP_MATCHES,
292
293 len,
294 slice,
295 };
296 static ftype_t stringzpad_type = {
297 FT_STRINGZPAD, /* ftype */
298 "FT_STRINGZPAD", /* name */
299 "Character string", /* pretty name */
300 0, /* wire_size */
301 string_fvalue_new, /* new_value */
302 string_fvalue_free, /* free_value */
303 val_from_unparsed, /* val_from_unparsed */
304 val_from_string, /* val_from_string */
305 string_to_repr, /* val_to_string_repr */
306 string_repr_len, /* len_string_repr */
307
308 { .set_value_string = string_fvalue_set_string }, /* union set_value */
309 { .get_value_ptr = value_get }, /* union get_value */
310
311 cmp_eq,
312 cmp_ne,
313 cmp_gt,
314 cmp_ge,
315 cmp_lt,
316 cmp_le,
317 NULL, /* cmp_bitwise_and */
318 cmp_contains, /* cmp_contains */
319 CMP_MATCHES,
320
321 len,
322 slice,
323 };
324 static ftype_t stringztrunc_type = {
325 FT_STRINGZTRUNC, /* ftype */
326 "FT_STRINGZTRUNC", /* name */
327 "Character string", /* pretty name */
328 0, /* wire_size */
329 string_fvalue_new, /* new_value */
330 string_fvalue_free, /* free_value */
331 val_from_unparsed, /* val_from_unparsed */
332 val_from_string, /* val_from_string */
333 string_to_repr, /* val_to_string_repr */
334 string_repr_len, /* len_string_repr */
335
336 { .set_value_string = string_fvalue_set_string }, /* union set_value */
337 { .get_value_ptr = value_get }, /* union get_value */
338
339 cmp_eq,
340 cmp_ne,
341 cmp_gt,
342 cmp_ge,
343 cmp_lt,
344 cmp_le,
345 NULL, /* cmp_bitwise_and */
346 cmp_contains, /* cmp_contains */
347 CMP_MATCHES,
348
349 len,
350 slice,
351 };
352
353 ftype_register(FT_STRING, &string_type);
354 ftype_register(FT_STRINGZ, &stringz_type);
355 ftype_register(FT_UINT_STRING, &uint_string_type);
356 ftype_register(FT_STRINGZPAD, &stringzpad_type);
357 ftype_register(FT_STRINGZTRUNC, &stringztrunc_type);
358 }
359
360 /*
361 * Editor modelines - https://www.wireshark.org/tools/modelines.html
362 *
363 * Local variables:
364 * c-basic-offset: 8
365 * tab-width: 8
366 * indent-tabs-mode: t
367 * End:
368 *
369 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
370 * :indentSize=8:tabSize=8:noTabs=false:
371 */
372