Witness: enum witness_interface_state
[metze/wireshark/wip.git] / epan / uat.c
1 /*
2  *  uat.c
3  *
4  * $Id$
5  *
6  *  User Accessible Tables
7  *  Mantain an array of user accessible data strucures
8  *
9  * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 2001 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  */
29 #include "config.h"
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37
38 #include <glib.h>
39
40 #include <wsutil/file_util.h>
41 #include <wsutil/str_util.h>
42 #include <wsutil/report_err.h>
43
44 #include <epan/emem.h>
45 #include <wsutil/filesystem.h>
46 #include <epan/packet.h>
47 #include <epan/range.h>
48
49 #include "uat-int.h"
50
51 static GPtrArray* all_uats = NULL;
52
53 void uat_init(void) {
54     all_uats = g_ptr_array_new();
55 }
56
57 uat_t* uat_new(const char* name,
58                size_t size,
59                const char* filename,
60                gboolean from_profile,
61                void** data_ptr,
62                guint* numitems_ptr,
63                guint flags,
64                const char* help,
65                uat_copy_cb_t copy_cb,
66                uat_update_cb_t update_cb,
67                uat_free_cb_t free_cb,
68                uat_post_update_cb_t post_update_cb,
69                uat_field_t* flds_array) {
70     /* Create new uat */
71     uat_t* uat = (uat_t *)g_malloc(sizeof(uat_t));
72     guint i;
73
74     /* Add to global array of uats */
75     if (!all_uats)
76         all_uats = g_ptr_array_new();
77
78     g_ptr_array_add(all_uats,uat);
79
80     /* Check params */
81     g_assert(name && size && filename && data_ptr && numitems_ptr);
82
83     /* Set uat values from inputs */
84     uat->name = g_strdup(name);
85     uat->record_size = size;
86     uat->filename = g_strdup(filename);
87     uat->from_profile = from_profile;
88     uat->user_ptr = data_ptr;
89     uat->nrows_p = numitems_ptr;
90     uat->copy_cb = copy_cb;
91     uat->update_cb = update_cb;
92     uat->free_cb = free_cb;
93     uat->post_update_cb = post_update_cb;
94     uat->fields = flds_array;
95     uat->user_data = g_array_new(FALSE,FALSE,(guint)uat->record_size);
96     uat->raw_data = g_array_new(FALSE,FALSE,(guint)uat->record_size);
97     uat->valid_data = g_array_new(FALSE,FALSE,sizeof(gboolean));
98     uat->changed = FALSE;
99     uat->loaded = FALSE;
100     uat->from_global = FALSE;
101     uat->rep = NULL;
102     uat->free_rep = NULL;
103     uat->help = help;
104     uat->flags = flags;
105
106     for (i=0;flds_array[i].title;i++) {
107         fld_data_t* f = (fld_data_t *)g_malloc(sizeof(fld_data_t));
108
109         f->colnum = i+1;
110         f->rep = NULL;
111         f->free_rep = NULL;
112
113         flds_array[i].priv = f;
114     }
115
116     uat->ncols = i;
117
118     *data_ptr = NULL;
119     *numitems_ptr = 0;
120
121     return uat;
122 }
123
124 void* uat_add_record(uat_t* uat, const void* data, gboolean valid_rec) {
125     void* rec;
126     gboolean* valid;
127
128     /* Save a copy of the raw (possibly that may contain invalid field values) data */
129     g_array_append_vals (uat->raw_data, data, 1);
130
131     rec = uat->raw_data->data + (uat->record_size * (uat->raw_data->len-1));
132
133     if (uat->copy_cb) {
134         uat->copy_cb(rec, data, (unsigned int) uat->record_size);
135     }
136
137     if (valid_rec) {
138         /* Add a "known good" record to the list to be used by the dissector */
139         g_array_append_vals (uat->user_data, data, 1);
140
141         rec = uat->user_data->data + (uat->record_size * (uat->user_data->len-1));
142
143         if (uat->copy_cb) {
144             uat->copy_cb(rec, data, (unsigned int) uat->record_size);
145         }
146
147         UAT_UPDATE(uat);
148     } else {
149         rec = NULL;
150     }
151
152     g_array_append_vals (uat->valid_data, &valid_rec, 1);
153     valid = (gboolean*)(uat->valid_data->data + (sizeof(gboolean) * (uat->valid_data->len-1)));
154     *valid = valid_rec;
155
156     return rec;
157 }
158
159 void uat_swap(uat_t* uat, guint a, guint b) {
160     size_t s = uat->record_size;
161     void* tmp = ep_alloc(s);
162     gboolean tmp_bool;
163
164     g_assert( a < uat->raw_data->len && b < uat->raw_data->len );
165
166     if (a == b) return;
167
168     memcpy(tmp, UAT_INDEX_PTR(uat,a), s);
169     memcpy(UAT_INDEX_PTR(uat,a), UAT_INDEX_PTR(uat,b), s);
170     memcpy(UAT_INDEX_PTR(uat,b), tmp, s);
171
172     tmp_bool = *(gboolean*)(uat->valid_data->data + (sizeof(gboolean) * (a)));
173     *(gboolean*)(uat->valid_data->data + (sizeof(gboolean) * (a))) = *(gboolean*)(uat->valid_data->data + (sizeof(gboolean) * (b)));
174     *(gboolean*)(uat->valid_data->data + (sizeof(gboolean) * (b))) = tmp_bool;
175
176
177 }
178
179 void uat_remove_record_idx(uat_t* uat, guint idx) {
180
181     g_assert( idx < uat->raw_data->len );
182
183     if (uat->free_cb) {
184         uat->free_cb(UAT_INDEX_PTR(uat,idx));
185     }
186
187     g_array_remove_index(uat->raw_data, idx);
188     g_array_remove_index(uat->valid_data, idx);
189 }
190
191 /* The returned filename was g_malloc()'d so the caller must free it */
192 gchar* uat_get_actual_filename(uat_t* uat, gboolean for_writing) {
193     gchar *pers_fname = NULL;
194
195     if (! uat->from_global) {
196         pers_fname =  get_persconffile_path(uat->filename, uat->from_profile);
197     }
198
199     if ((! for_writing ) && (! file_exists(pers_fname) )) {
200         gchar* data_fname = get_datafile_path(uat->filename);
201
202         if (file_exists(data_fname)) {
203             g_free(pers_fname);
204             return data_fname;
205         }
206
207         g_free(data_fname);
208         g_free(pers_fname);
209         return NULL;
210     }
211
212     return pers_fname;
213 }
214
215 uat_t* uat_get_table_by_name(const char* name) {
216     guint i;
217
218     for (i=0; i < all_uats->len; i++) {
219         uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
220         if ( g_str_equal(u->name,name) ) {
221             return (u);
222         }
223     }
224
225     return NULL;
226 }
227
228 static void putfld(FILE* fp, void* rec, uat_field_t* f) {
229     guint fld_len;
230     const char* fld_ptr;
231
232     f->cb.tostr(rec,&fld_ptr,&fld_len,f->cbdata.tostr,f->fld_data);
233
234     switch(f->mode){
235         case PT_TXTMOD_NONE:
236         case PT_TXTMOD_ENUM:
237         case PT_TXTMOD_FILENAME:
238         case PT_TXTMOD_DIRECTORYNAME:
239         case PT_TXTMOD_STRING: {
240             guint i;
241
242             putc('"',fp);
243
244             for(i=0;i<fld_len;i++) {
245                 char c = fld_ptr[i];
246
247                 if (c == '"' || c == '\\' || ! isprint((guchar)c) ) {
248                     fprintf(fp,"\\x%.2x",c);
249                 } else {
250                     putc(c,fp);
251                 }
252             }
253
254             putc('"',fp);
255             return;
256         }
257         case PT_TXTMOD_HEXBYTES: {
258             guint i;
259
260             for(i=0;i<fld_len;i++) {
261                 fprintf(fp,"%.2x",((const guint8*)fld_ptr)[i]);
262             }
263
264             return;
265         }
266         default:
267             g_assert_not_reached();
268     }
269 }
270
271 gboolean uat_save(uat_t* uat, const char** error) {
272     guint i;
273     gchar* fname = uat_get_actual_filename(uat,TRUE);
274     FILE* fp;
275
276     if (! fname ) return FALSE;
277
278     fp = ws_fopen(fname,"w");
279
280     if (!fp && errno == ENOENT) {
281         /* Parent directory does not exist, try creating first */
282         gchar *pf_dir_path = NULL;
283         if (create_persconffile_dir(&pf_dir_path) != 0) {
284             *error = ep_strdup_printf("uat_save: error creating '%s'", pf_dir_path);
285             g_free (pf_dir_path);
286             return FALSE;
287         }
288         fp = ws_fopen(fname,"w");
289     }
290
291     if (!fp) {
292         *error = ep_strdup_printf("uat_save: error opening '%s': %s",fname,g_strerror(errno));
293         return FALSE;
294     }
295
296     *error = NULL;
297     g_free (fname);
298
299     /* Ensure raw_data is synced with user_data and all "good" entries have been accounted for */
300
301     /* Start by clearing current user_data */
302     for ( i = 0 ; i < uat->user_data->len ; i++ ) {
303         if (uat->free_cb) {
304             uat->free_cb(UAT_USER_INDEX_PTR(uat,i));
305         }
306     }
307     g_array_set_size(uat->user_data,0);
308
309     *((uat)->user_ptr) = NULL;
310     *((uat)->nrows_p) = 0;
311
312     /* Now copy "good" raw_data entries to user_data */
313     for ( i = 0 ; i < uat->raw_data->len ; i++ ) {
314         void* rec = uat->raw_data->data + (uat->record_size * i);
315         gboolean* valid = (gboolean*)(uat->valid_data->data + sizeof(gboolean)*i);
316         if (*valid) {
317             g_array_append_vals(uat->user_data, rec, 1);
318             if (uat->copy_cb) {
319                 uat->copy_cb(UAT_USER_INDEX_PTR(uat,i), rec, (unsigned int) uat->record_size);
320             }
321
322             UAT_UPDATE(uat);
323         }
324     }
325
326
327     fprintf(fp,"# This file is automatically generated, DO NOT MODIFY.\n");
328
329     for ( i = 0 ; i < uat->user_data->len ; i++ ) {
330         void* rec = uat->user_data->data + (uat->record_size * i);
331         uat_field_t* f;
332         guint j;
333
334         f = uat->fields;
335
336
337         for( j=0 ; j < uat->ncols ; j++ ) {
338             putfld(fp, rec, &(f[j]));
339             fputs((j == uat->ncols - 1) ? "\n" : "," ,fp);
340         }
341
342     }
343
344     fclose(fp);
345
346     uat->changed = FALSE;
347
348     return TRUE;
349 }
350
351 void uat_destroy(uat_t* uat) {
352     /* XXX still missing a destructor */
353     g_ptr_array_remove(all_uats,uat);
354
355 }
356
357 uat_t *uat_find(gchar *name) {
358     guint i;
359
360     for (i=0; i < all_uats->len; i++) {
361         uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
362
363         if (strcmp(u->name, name) == 0 || strcmp(u->filename, name) == 0) {
364             return u;
365         }
366     }
367     return NULL;
368 }
369
370 void uat_clear(uat_t* uat) {
371     guint i;
372
373     for ( i = 0 ; i < uat->user_data->len ; i++ ) {
374         if (uat->free_cb) {
375             uat->free_cb(UAT_USER_INDEX_PTR(uat,i));
376         }
377     }
378
379     for ( i = 0 ; i < uat->raw_data->len ; i++ ) {
380         if (uat->free_cb) {
381             uat->free_cb(UAT_INDEX_PTR(uat,i));
382         }
383     }
384
385     g_array_set_size(uat->raw_data,0);
386     g_array_set_size(uat->user_data,0);
387     g_array_set_size(uat->valid_data,0);
388
389     *((uat)->user_ptr) = NULL;
390     *((uat)->nrows_p) = 0;
391 }
392
393 void* uat_dup(uat_t* uat, guint* len_p) {
394     guint size = (guint) (uat->record_size * uat->user_data->len);
395     *len_p = size;
396     return size ? g_memdup(uat->user_data->data,size) : NULL ;
397 }
398
399 void* uat_se_dup(uat_t* uat, guint* len_p) {
400     guint size = (guint) (uat->record_size * uat->user_data->len);
401     *len_p = (guint) size;
402     return size ? se_memdup(uat->user_data->data,size) : NULL ;
403 }
404
405 void uat_unload_all(void) {
406     guint i;
407
408     for (i=0; i < all_uats->len; i++) {
409         uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
410         /* Do not unload if not in profile */
411         if (u->from_profile) {
412             uat_clear(u);
413             u->loaded = FALSE;
414         }
415     }
416 }
417
418 #if 0
419 static void uat_cleanup(void) {
420     while( all_uats->len ) {
421         uat_destroy((uat_t*)all_uats->pdata);
422     }
423
424     g_ptr_array_free(all_uats,TRUE);
425 }
426 #endif
427
428 void uat_foreach_table(uat_cb_t cb,void* user_data) {
429     guint i;
430
431     for (i=0; i < all_uats->len; i++)
432         cb(g_ptr_array_index(all_uats,i), user_data);
433
434 }
435
436
437 void uat_load_all(void) {
438     guint i;
439     const gchar* err;
440
441     for (i=0; i < all_uats->len; i++) {
442         uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
443         err = NULL;
444
445         if (!u->loaded)
446             uat_load(u, &err);
447
448         if (err) {
449             report_failure("Error loading table '%s': %s",u->name,err);
450         }
451     }
452 }
453
454
455 gboolean uat_fld_chk_str(void* u1 _U_, const char* strptr, guint len _U_, const void* u2 _U_, const void* u3 _U_, const char** err) {
456     if (strptr == NULL) {
457         *err = "NULL pointer";
458         return FALSE;
459     }
460
461     *err = NULL;
462     return TRUE;
463 }
464
465 gboolean uat_fld_chk_oid(void* u1 _U_, const char* strptr, guint len, const void* u2 _U_, const void* u3 _U_, const char** err) {
466   unsigned int i;
467     *err = NULL;
468
469     if (strptr == NULL) {
470       *err = "NULL pointer";
471       return FALSE;
472     }
473
474     for(i = 0; i < len; i++)
475       if(!(isdigit(strptr[i]) || strptr[i] == '.')) {
476         *err = "Only digits [0-9] and \".\" allowed in an OID";
477         break;
478       }
479
480     if(strptr[len-1] == '.')
481       *err = "OIDs must not be terminated with a \".\"";
482
483     if(!((*strptr == '0' || *strptr == '1' || *strptr =='2') && (len > 1 && strptr[1] == '.')))
484       *err = "OIDs must start with \"0.\" (ITU-T assigned), \"1.\" (ISO assigned) or \"2.\" (joint ISO/ITU-T assigned)";
485
486     /* should also check that the second arc is in the range 0-39 */
487
488     return *err == NULL;
489 }
490
491 gboolean uat_fld_chk_proto(void* u1 _U_, const char* strptr, guint len, const void* u2 _U_, const void* u3 _U_, const char** err) {
492     if (len) {
493         char* name = ep_strndup(strptr,len);
494         ascii_strdown_inplace(name);
495         g_strchug(name);
496
497         if (find_dissector(name)) {
498             *err = NULL;
499             return TRUE;
500         } else {
501             *err = "dissector not found";
502             return FALSE;
503         }
504     } else {
505         *err = NULL;
506         return TRUE;
507     }
508 }
509
510 gboolean uat_fld_chk_num_dec(void* u1 _U_, const char* strptr, guint len, const void* u2 _U_, const void* u3 _U_, const char** err) {
511     if (len > 0) {
512         char* str = ep_strndup(strptr,len);
513         long i = strtol(str,&str,10);
514
515         if ( ( i == 0) && (errno == ERANGE || errno == EINVAL) ) {
516             *err = g_strerror(errno);
517             return FALSE;
518         }
519     }
520
521     *err = NULL;
522     return TRUE;
523 }
524
525 gboolean uat_fld_chk_num_hex(void* u1 _U_, const char* strptr, guint len, const void* u2 _U_, const void* u3 _U_, const char** err) {
526     if (len > 0) {
527         char* str = ep_strndup(strptr,len);
528         long i = strtol(str,&str,16);
529
530         if ( ( i == 0) && (errno == ERANGE || errno == EINVAL) ) {
531             *err = g_strerror(errno);
532             return FALSE;
533         }
534     }
535
536     *err = NULL;
537     return TRUE;
538 }
539
540 gboolean uat_fld_chk_enum(void* u1 _U_, const char* strptr, guint len, const void* v, const void* u3 _U_, const char** err) {
541     char* str = ep_strndup(strptr,len);
542     guint i;
543     const value_string* vs = (const value_string *)v;
544
545     for(i=0;vs[i].strptr;i++) {
546         if (g_str_equal(vs[i].strptr,str)) {
547             *err = NULL;
548             return TRUE;
549         }
550     }
551
552     *err = ep_strdup_printf("invalid value: %s",str);
553     return FALSE;
554 }
555
556 gboolean uat_fld_chk_range(void* u1 _U_, const char* strptr, guint len, const void* v _U_, const void* u3, const char** err) {
557     char* str = ep_strndup(strptr,len);
558     range_t* r = NULL;
559     convert_ret_t ret = range_convert_str(&r, str,GPOINTER_TO_UINT(u3));
560
561     switch (  ret ) {
562         case CVT_NO_ERROR:
563             *err = NULL;
564             return TRUE;
565         case CVT_SYNTAX_ERROR:
566             *err = ep_strdup_printf("syntax error in range: %s",str);
567             return FALSE;
568         case CVT_NUMBER_TOO_BIG:
569             *err = ep_strdup_printf("value too large in range: '%s' (max = %u)",str,GPOINTER_TO_UINT(u3));
570             return FALSE;
571         default:
572             *err = "This should not happen, it is a bug in wireshark! please report to wireshark-dev@wireshark.org";
573             return FALSE;
574     }
575 }
576
577 char* uat_unbinstring(const char* si, guint in_len, guint* len_p) {
578     guint8* buf;
579     guint len = in_len/2;
580     int i = 0;
581     int d0, d1;
582
583     if (in_len%2) {
584         return NULL;
585     }
586
587     buf= (guint8 *)g_malloc0(len+1);
588     if (len_p) *len_p = len;
589
590     while(in_len) {
591         d1 = ws_xton(*(si++));
592         d0 = ws_xton(*(si++));
593
594         buf[i++] = (d1 * 16) + d0;
595
596         in_len -= 2;
597     }
598
599     return (char*)buf;
600 }
601
602 char* uat_unesc(const char* si, guint in_len, guint* len_p) {
603     char* buf = (char *)g_malloc0(in_len+1);
604     char* p = buf;
605     guint len = 0;
606     const char* s;
607     const char* in_end = si+in_len;
608
609     for (s = (const char *)si; s < in_end; s++) {
610         switch(*s) {
611             case '\\':
612                 switch(*(++s)) {
613                     case 'a': *(p++) = '\a'; len++; break;
614                     case 'b': *(p++) = '\b'; len++; break;
615                     case 'e': *(p++) = '\033' /* '\e' is non ANSI-C */; len++; break;
616                     case 'f': *(p++) = '\f'; len++; break;
617                     case 'n': *(p++) = '\n'; len++; break;
618                     case 'r': *(p++) = '\r'; len++; break;
619                     case 't': *(p++) = '\t'; len++; break;
620                     case 'v': *(p++) = '\v'; len++; break;
621
622                     case '0':
623                     case '1':
624                     case '2':
625                     case '3':
626                     case '4':
627                     case '5':
628                     case '6':
629                     case '7':
630                     {
631                         int c0 = 0;
632                         int c1 = 0;
633                         int c2 = 0;
634                         int c = 0;
635
636                         c0 = (*s) - '0';
637
638                         if ( s[1] >= '0' && s[1] <= '7' ) {
639                             c1 = c0;
640                             c0 = (*++s) - '0';
641
642                             if ( s[1] >= '0' && s[1] <= '7' ) {
643                                 c2 = c1;
644                                 c1 = c0;
645                                 c0 = (*++s) - '0';
646                             }
647                         }
648                         c = (64 * c2) + (8 * c1) + c0;
649                         *(p++) = (char) (c > 255 ? 255 : c);
650                         len++;
651                         break;
652                     }
653
654                     case 'x':
655                     {
656                         char c1 = *(s+1);
657                         char c0 = *(s+2);
658
659                         if (isxdigit((guchar)c1) && isxdigit((guchar)c0)) {
660                             *(p++) = (ws_xton(c1) * 0x10) + ws_xton(c0);
661                             s += 2;
662                         } else {
663                             *(p++) = *s;
664                         }
665                         len++;
666                         break;
667                     }
668                     default:
669                         *p++ = *s;
670                         break;
671                 }
672                 break;
673             default:
674                 *(p++) = *s;
675                 len++;
676                 break;
677         }
678     }
679
680     if (len_p) *len_p = len;
681     return buf;
682 }
683
684 char* uat_undquote(const char* si, guint in_len, guint* len_p) {
685     return uat_unesc(si+1,in_len-2,len_p);
686 }
687
688
689 char* uat_esc(const char* buf, guint len) {
690     const guint8* end = ((const guint8*)buf)+len;
691     char* out = (char *)ep_alloc0((4*len)+1);
692     const guint8* b;
693     char* s = out;
694
695     for (b = (const guint8 *)buf; b < end; b++) {
696         if (isprint(*b) ) {
697             *(s++) = (*b);
698         } else {
699             g_snprintf(s,5,"\\x%.2x",((guint)*b));
700             s+=4;
701         }
702     }
703
704     return out;
705
706 }
707
708 CHK_STR_IS_DEF(isprint)
709 CHK_STR_IS_DEF(isalpha)
710 CHK_STR_IS_DEF(isalnum)
711 CHK_STR_IS_DEF(isdigit)
712 CHK_STR_IS_DEF(isxdigit)
713
714 /*
715  * Editor modelines
716  *
717  * Local Variables:
718  * c-basic-offset: 4
719  * tab-width: 8
720  * indent-tabs-mode: nil
721  * End:
722  *
723  * ex: set shiftwidth=4 tabstop=8 expandtab:
724  * :indentSize=4:tabSize=8:noTabs=true:
725  */