63c73275013b1fee92021ea139c5f06b4dde93fb
[obnox/wireshark/wip.git] / epan / ftypes / ftype-bytes.c
1 /* 
2  * $Id: ftype-bytes.c,v 1.8 2001/11/22 03:07:07 hagbard Exp $
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 #include <ctype.h>
30 #include "resolv.h"
31 #include "int-64bit.h"
32
33 #define ETHER_LEN       6
34 #define IPv6_LEN        16
35 #define U64_LEN         8
36
37 static void
38 bytes_fvalue_new(fvalue_t *fv)
39 {
40         fv->value.bytes = NULL;
41 }
42
43 void
44 bytes_fvalue_free(fvalue_t *fv)
45 {
46         if (fv->value.bytes) {
47                 g_byte_array_free(fv->value.bytes, TRUE);
48                 fv->value.bytes=NULL;
49         }
50 }
51
52
53 static void
54 bytes_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
55 {
56         g_assert(already_copied);
57         fv->value.bytes = value;
58 }
59
60 static void
61 common_fvalue_set(fvalue_t *fv, guint8* data, guint len)
62 {
63         fv->value.bytes = g_byte_array_new();
64         g_byte_array_append(fv->value.bytes, data, len);
65 }
66
67 static void
68 ether_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
69 {
70         g_assert(!already_copied);
71         common_fvalue_set(fv, value, ETHER_LEN);
72 }
73
74 static void
75 ipv6_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
76 {
77         g_assert(!already_copied);
78         common_fvalue_set(fv, value, IPv6_LEN);
79 }
80
81 static void
82 u64_fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied)
83 {
84         g_assert(!already_copied);
85         common_fvalue_set(fv, value, U64_LEN);
86 }
87
88 static gpointer
89 value_get(fvalue_t *fv)
90 {
91         return fv->value.bytes->data;
92 }
93
94 static gboolean
95 is_byte_sep(guint8 c)
96 {
97         return (c == '-' || c == ':' || c == '.');
98 }
99         
100 static gboolean
101 val_from_string(fvalue_t *fv, char *s, LogFunc log)
102 {
103         GByteArray      *bytes;
104         guint8          val;
105         guchar          *p, *q, *punct;
106         char            two_digits[3];
107         char            one_digit[2];
108         gboolean        fail = FALSE;
109
110         bytes = g_byte_array_new();
111
112         p = (guchar *)s;
113         while (*p) {
114                 q = p+1;
115                 if (*q && isxdigit(*p) && isxdigit(*q)) {
116                         two_digits[0] = *p;
117                         two_digits[1] = *q;
118                         two_digits[2] = '\0';
119
120                         /*
121                          * Two or more hex digits in a row.
122                          * "strtoul()" will succeed, as it'll see at
123                          * least one hex digit.
124                          */
125                         val = (guint8) strtoul(two_digits, NULL, 16);
126                         g_byte_array_append(bytes, &val, 1);
127                         punct = q + 1;
128                         if (*punct) {
129                                 /*
130                                  * Make sure the character after
131                                  * the second hex digit is a byte
132                                  * separator, i.e. that we don't have
133                                  * more than two hex digits, or a
134                                  * bogus character.
135                                  */
136                                 if (is_byte_sep(*punct)) {
137                                         p = punct + 1;
138                                         continue;
139                                 }
140                                 else {
141                                         fail = TRUE;
142                                         break;
143                                 }
144                         }
145                         else {
146                                 p = punct;
147                                 continue;
148                         }
149                 }
150                 else if (*q && isxdigit(*p) && is_byte_sep(*q)) {
151                         one_digit[0] = *p;
152                         one_digit[1] = '\0';
153
154                         /*
155                          * Only one hex digit.
156                          * "strtoul()" will succeed, as it'll see that
157                          * hex digit.
158                          */
159                         val = (guint8) strtoul(one_digit, NULL, 16);
160                         g_byte_array_append(bytes, &val, 1);
161                         p = q + 1;
162                         continue;
163                 }
164                 else if (!*q && isxdigit(*p)) {
165                         one_digit[0] = *p;
166                         one_digit[1] = '\0';
167
168                         /*
169                          * Only one hex digit.
170                          * "strtoul()" will succeed, as it'll see that
171                          * hex digit.
172                          */
173                         val = (guint8) strtoul(one_digit, NULL, 16);
174                         g_byte_array_append(bytes, &val, 1);
175                         p = q;
176                         continue;
177                 }
178                 else {
179                         fail = TRUE;
180                         break;
181                 }
182         }
183
184         if (fail) {
185                 if (log != NULL)
186                         log("\"%s\" is not a valid byte string.", s);
187                 g_byte_array_free(bytes, TRUE);
188                 return FALSE;
189         }
190
191         fv->value.bytes = bytes;
192
193
194         return TRUE;
195 }
196
197 static gboolean
198 ether_from_string(fvalue_t *fv, char *s, LogFunc log)
199 {
200         guint8  *mac;
201
202         /*
203          * Don't log a message if this fails; we'll try looking it
204          * up as an Ethernet host name if it does, and if that fails,
205          * we'll log a message.
206          */
207         if (val_from_string(fv, s, NULL)) {
208                 return TRUE;
209         }
210
211         mac = get_ether_addr(s);
212         if (!mac) {
213                 log("\"%s\" is not a valid hostname or Ethernet address.", s);
214                 return FALSE;
215         }
216
217         ether_fvalue_set(fv, mac, FALSE);
218         return TRUE;
219 }
220
221 static gboolean
222 ipv6_from_string(fvalue_t *fv, char *s, LogFunc log)
223 {
224         guint8  buffer[16];
225
226         if (!get_host_ipaddr6(s, (struct e_in6_addr*)buffer)) {
227                 log("\"%s\" is not a valid hostname or IPv6 address.", s);
228                 return FALSE;
229         }
230
231         ipv6_fvalue_set(fv, buffer, FALSE);
232         return TRUE;
233 }
234
235 static gboolean
236 u64_from_string(fvalue_t *fv, char *s, LogFunc log)
237 {
238         guint8  buffer[8];
239
240         if (atou64(s, buffer) == NULL) {
241                 log("\"%s\" is not a valid integer", s);
242                 return FALSE;
243         }
244
245         u64_fvalue_set(fv, buffer, FALSE);
246         return TRUE;
247 }
248
249 static gboolean
250 i64_from_string(fvalue_t *fv, char *s, LogFunc log)
251 {
252         guint8  buffer[8];
253
254         if (atoi64(s, buffer) == NULL) {
255                 log("\"%s\" is not a valid integer", s);
256                 return FALSE;
257         }
258
259         u64_fvalue_set(fv, buffer, FALSE);
260         return TRUE;
261 }
262
263 static guint
264 len(fvalue_t *fv)
265 {
266         return fv->value.bytes->len;
267 }
268
269 static void
270 slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length)
271 {
272         guint8* data;
273
274         data = fv->value.bytes->data + offset;
275
276         g_byte_array_append(bytes, data, length);
277 }
278
279
280 static gboolean
281 cmp_eq(fvalue_t *fv_a, fvalue_t *fv_b)
282 {
283         GByteArray      *a = fv_a->value.bytes;
284         GByteArray      *b = fv_b->value.bytes;
285
286         if (a->len != b->len) {
287                 return FALSE;
288         }
289
290         return (memcmp(a->data, b->data, a->len) == 0);
291 }
292
293
294 static gboolean
295 cmp_ne(fvalue_t *fv_a, fvalue_t *fv_b)
296 {
297         GByteArray      *a = fv_a->value.bytes;
298         GByteArray      *b = fv_b->value.bytes;
299
300         if (a->len != b->len) {
301                 return FALSE;
302         }
303
304         return (memcmp(a->data, b->data, a->len) != 0);
305 }
306
307
308 static gboolean
309 cmp_gt(fvalue_t *fv_a, fvalue_t *fv_b)
310 {
311         GByteArray      *a = fv_a->value.bytes;
312         GByteArray      *b = fv_b->value.bytes;
313
314         if (a->len > b->len) {
315                 return TRUE;
316         }
317
318         if (a->len < b->len) {
319                 return FALSE;
320         }
321         
322         return (memcmp(a->data, b->data, a->len) > 0);
323 }
324
325 static gboolean
326 cmp_ge(fvalue_t *fv_a, fvalue_t *fv_b)
327 {
328         GByteArray      *a = fv_a->value.bytes;
329         GByteArray      *b = fv_b->value.bytes;
330
331         if (a->len > b->len) {
332                 return TRUE;
333         }
334
335         if (a->len < b->len) {
336                 return FALSE;
337         }
338         
339         return (memcmp(a->data, b->data, a->len) >= 0);
340 }
341
342 static gboolean
343 cmp_lt(fvalue_t *fv_a, fvalue_t *fv_b)
344 {
345         GByteArray      *a = fv_a->value.bytes;
346         GByteArray      *b = fv_b->value.bytes;
347
348         if (a->len < b->len) {
349                 return TRUE;
350         }
351
352         if (a->len > b->len) {
353                 return FALSE;
354         }
355         
356         return (memcmp(a->data, b->data, a->len) < 0);
357 }
358
359 static gboolean
360 cmp_le(fvalue_t *fv_a, fvalue_t *fv_b)
361 {
362         GByteArray      *a = fv_a->value.bytes;
363         GByteArray      *b = fv_b->value.bytes;
364
365         if (a->len < b->len) {
366                 return TRUE;
367         }
368
369         if (a->len > b->len) {
370                 return FALSE;
371         }
372         
373         return (memcmp(a->data, b->data, a->len) <= 0);
374 }
375
376 static gboolean
377 cmp_gt_i64(fvalue_t *fv_a, fvalue_t *fv_b)
378 {
379         GByteArray      *a = fv_a->value.bytes;
380         GByteArray      *b = fv_b->value.bytes;
381
382         if (a->len > b->len) {
383                 return TRUE;
384         }
385
386         if (a->len < b->len) {
387                 return FALSE;
388         }
389         
390         if ((a->data[0] & 0x80) == 0) {
391                 /*
392                  * "a" is positive.
393                  */
394                 if (b->data[0] & 0x80) {
395                         /*
396                          * "b" is negative, so a > b.
397                          */
398                         return TRUE;
399                 }
400         } else {
401                 /*
402                  * "a" is negative.
403                  */
404                 if ((b->data[0] & 0x80) == 0) {
405                         /*
406                          * "b" is positive, so a < b.
407                          */
408                         return FALSE;
409                 }
410         }
411
412         /*
413          * "a" and "b" have the same sign, so "memcmp()" should
414          * give the right answer.
415          */
416         return (memcmp(a->data, b->data, a->len) > 0);
417 }
418
419 static gboolean
420 cmp_ge_i64(fvalue_t *fv_a, fvalue_t *fv_b)
421 {
422         GByteArray      *a = fv_a->value.bytes;
423         GByteArray      *b = fv_b->value.bytes;
424
425         if (a->len > b->len) {
426                 return TRUE;
427         }
428
429         if (a->len < b->len) {
430                 return FALSE;
431         }
432         
433         if ((a->data[0] & 0x80) == 0) {
434                 /*
435                  * "a" is positive.
436                  */
437                 if (b->data[0] & 0x80) {
438                         /*
439                          * "b" is negative, so a > b.
440                          */
441                         return TRUE;
442                 }
443         } else {
444                 /*
445                  * "a" is negative.
446                  */
447                 if ((b->data[0] & 0x80) == 0) {
448                         /*
449                          * "b" is positive, so a < b.
450                          */
451                         return FALSE;
452                 }
453         }
454
455         /*
456          * "a" and "b" have the same sign, so "memcmp()" should
457          * give the right answer.
458          */
459         return (memcmp(a->data, b->data, a->len) >= 0);
460 }
461
462 static gboolean
463 cmp_lt_i64(fvalue_t *fv_a, fvalue_t *fv_b)
464 {
465         GByteArray      *a = fv_a->value.bytes;
466         GByteArray      *b = fv_b->value.bytes;
467
468         if (a->len < b->len) {
469                 return TRUE;
470         }
471
472         if (a->len > b->len) {
473                 return FALSE;
474         }
475         
476         if (a->data[0] & 0x80) {
477                 /*
478                  * "a" is negative.
479                  */
480                 if ((b->data[0] & 0x80) == 0) {
481                         /*
482                          * "b" is positive, so a < b.
483                          */
484                         return TRUE;
485                 }
486         } else {
487                 /*
488                  * "a" is positive.
489                  */
490                 if (b->data[0] & 0x80) {
491                         /*
492                          * "b" is negative, so a > b.
493                          */
494                         return FALSE;
495                 }
496         }
497
498         /*
499          * "a" and "b" have the same sign, so "memcmp()" should
500          * give the right answer.
501          */
502         return (memcmp(a->data, b->data, a->len) < 0);
503 }
504
505 static gboolean
506 cmp_le_i64(fvalue_t *fv_a, fvalue_t *fv_b)
507 {
508         GByteArray      *a = fv_a->value.bytes;
509         GByteArray      *b = fv_b->value.bytes;
510
511         if (a->len < b->len) {
512                 return TRUE;
513         }
514
515         if (a->len > b->len) {
516                 return FALSE;
517         }
518         
519         if (a->data[0] & 0x80) {
520                 /*
521                  * "a" is negative.
522                  */
523                 if ((b->data[0] & 0x80) == 0) {
524                         /*
525                          * "b" is positive, so a < b.
526                          */
527                         return TRUE;
528                 }
529         } else {
530                 /*
531                  * "a" is positive.
532                  */
533                 if (b->data[0] & 0x80) {
534                         /*
535                          * "b" is negative, so a > b.
536                          */
537                         return FALSE;
538                 }
539         }
540
541         /*
542          * "a" and "b" have the same sign, so "memcmp()" should
543          * give the right answer.
544          */
545         return (memcmp(a->data, b->data, a->len) <= 0);
546 }
547
548 void
549 ftype_register_bytes(void)
550 {
551
552         static ftype_t bytes_type = {
553                 "FT_BYTES",
554                 "sequence of bytes",
555                 0,
556                 bytes_fvalue_new,
557                 bytes_fvalue_free,
558                 val_from_string,
559
560                 bytes_fvalue_set,
561                 NULL,
562                 NULL,
563
564                 value_get,
565                 NULL,
566                 NULL,
567
568                 cmp_eq,
569                 cmp_ne,
570                 cmp_gt,
571                 cmp_ge,
572                 cmp_lt,
573                 cmp_le,
574
575                 len,
576                 slice,
577         };
578
579         static ftype_t ether_type = {
580                 "FT_ETHER",
581                 "Ethernet or other MAC address",
582                 ETHER_LEN,
583                 bytes_fvalue_new,
584                 bytes_fvalue_free,
585                 ether_from_string,
586
587                 ether_fvalue_set,
588                 NULL,
589                 NULL,
590
591                 value_get,
592                 NULL,
593                 NULL,
594
595                 cmp_eq,
596                 cmp_ne,
597                 cmp_gt,
598                 cmp_ge,
599                 cmp_lt,
600                 cmp_le,
601
602                 len,
603                 slice,
604         };
605
606         static ftype_t ipv6_type = {
607                 "FT_IPv6",
608                 "IPv6 address",
609                 IPv6_LEN,
610                 bytes_fvalue_new,
611                 bytes_fvalue_free,
612                 ipv6_from_string,
613
614                 ipv6_fvalue_set,
615                 NULL,
616                 NULL,
617
618                 value_get,
619                 NULL,
620                 NULL,
621
622                 cmp_eq,
623                 cmp_ne,
624                 cmp_gt,
625                 cmp_ge,
626                 cmp_lt,
627                 cmp_le,
628
629                 len,
630                 slice,
631         };
632
633         static ftype_t u64_type = {
634                 "FT_UINT64",
635                 "Unsigned 64-bit integer",
636                 U64_LEN,
637                 bytes_fvalue_new,
638                 bytes_fvalue_free,
639                 u64_from_string,
640
641                 u64_fvalue_set,
642                 NULL,
643                 NULL,
644
645                 value_get,
646                 NULL,
647                 NULL,
648
649                 cmp_eq,
650                 cmp_ne,
651                 cmp_gt,
652                 cmp_ge,
653                 cmp_lt,
654                 cmp_le,
655
656                 len,
657                 slice,
658         };
659
660         static ftype_t i64_type = {
661                 "FT_INT64",
662                 "Signed 64-bit integer",
663                 U64_LEN,
664                 bytes_fvalue_new,
665                 bytes_fvalue_free,
666                 i64_from_string,
667
668                 u64_fvalue_set,
669                 NULL,
670                 NULL,
671
672                 value_get,
673                 NULL,
674                 NULL,
675
676                 cmp_eq,
677                 cmp_ne,
678                 cmp_gt_i64,
679                 cmp_ge_i64,
680                 cmp_lt_i64,
681                 cmp_le_i64,
682
683                 len,
684                 slice,
685         };
686
687         ftype_register(FT_BYTES, &bytes_type);
688         ftype_register(FT_ETHER, &ether_type);
689         ftype_register(FT_IPv6, &ipv6_type);
690         ftype_register(FT_UINT64, &u64_type);
691         ftype_register(FT_INT64, &i64_type);
692 }