6 * User Accessible Tables
7 * Mantain an array of user accessible data strucures
9 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 2001 Gerald Combs
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.
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.
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.
40 #include <wsutil/file_util.h>
41 #include <wsutil/str_util.h>
42 #include <wsutil/report_err.h>
44 #include <epan/emem.h>
45 #include <epan/filesystem.h>
46 #include <epan/packet.h>
47 #include <epan/range.h>
51 static GPtrArray
* all_uats
= NULL
;
54 all_uats
= g_ptr_array_new();
57 uat_t
* uat_new(const char* name
,
60 gboolean from_profile
,
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
) {
71 uat_t
* uat
= (uat_t
*)g_malloc(sizeof(uat_t
));
74 /* Add to global array of uats */
76 all_uats
= g_ptr_array_new();
78 g_ptr_array_add(all_uats
,uat
);
81 g_assert(name
&& size
&& filename
&& data_ptr
&& numitems_ptr
);
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
));
100 uat
->from_global
= FALSE
;
102 uat
->free_rep
= NULL
;
106 for (i
=0;flds_array
[i
].title
;i
++) {
107 fld_data_t
* f
= (fld_data_t
*)g_malloc(sizeof(fld_data_t
));
113 flds_array
[i
].priv
= f
;
124 void* uat_add_record(uat_t
* uat
, const void* data
, gboolean valid_rec
) {
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);
131 rec
= uat
->raw_data
->data
+ (uat
->record_size
* (uat
->raw_data
->len
-1));
134 uat
->copy_cb(rec
, data
, (unsigned int) uat
->record_size
);
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);
141 rec
= uat
->user_data
->data
+ (uat
->record_size
* (uat
->user_data
->len
-1));
144 uat
->copy_cb(rec
, data
, (unsigned int) uat
->record_size
);
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)));
159 void uat_swap(uat_t
* uat
, guint a
, guint b
) {
160 size_t s
= uat
->record_size
;
161 void* tmp
= ep_alloc(s
);
164 g_assert( a
< uat
->raw_data
->len
&& b
< uat
->raw_data
->len
);
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
);
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
;
179 void uat_remove_record_idx(uat_t
* uat
, guint idx
) {
181 g_assert( idx
< uat
->raw_data
->len
);
184 uat
->free_cb(UAT_INDEX_PTR(uat
,idx
));
187 g_array_remove_index(uat
->raw_data
, idx
);
188 g_array_remove_index(uat
->valid_data
, idx
);
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
;
195 if (! uat
->from_global
) {
196 pers_fname
= get_persconffile_path(uat
->filename
, uat
->from_profile
);
199 if ((! for_writing
) && (! file_exists(pers_fname
) )) {
200 gchar
* data_fname
= get_datafile_path(uat
->filename
);
202 if (file_exists(data_fname
)) {
215 uat_t
* uat_get_table_by_name(const char* name
) {
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
) ) {
228 static void putfld(FILE* fp
, void* rec
, uat_field_t
* f
) {
232 f
->cb
.tostr(rec
,&fld_ptr
,&fld_len
,f
->cbdata
.tostr
,f
->fld_data
);
236 case PT_TXTMOD_FILENAME
:
237 case PT_TXTMOD_DIRECTORYNAME
:
238 case PT_TXTMOD_STRING
: {
243 for(i
=0;i
<fld_len
;i
++) {
246 if (c
== '"' || c
== '\\' || ! isprint((guchar
)c
) ) {
247 fprintf(fp
,"\\x%.2x",c
);
256 case PT_TXTMOD_HEXBYTES
: {
259 for(i
=0;i
<fld_len
;i
++) {
260 fprintf(fp
,"%.2x",((guint8
*)fld_ptr
)[i
]);
266 g_assert_not_reached();
270 gboolean
uat_save(uat_t
* uat
, const char** error
) {
272 gchar
* fname
= uat_get_actual_filename(uat
,TRUE
);
275 if (! fname
) return FALSE
;
277 fp
= ws_fopen(fname
,"w");
279 if (!fp
&& errno
== ENOENT
) {
280 /* Parent directory does not exist, try creating first */
281 gchar
*pf_dir_path
= NULL
;
282 if (create_persconffile_dir(&pf_dir_path
) != 0) {
283 *error
= ep_strdup_printf("uat_save: error creating '%s'", pf_dir_path
);
284 g_free (pf_dir_path
);
287 fp
= ws_fopen(fname
,"w");
291 *error
= ep_strdup_printf("uat_save: error opening '%s': %s",fname
,g_strerror(errno
));
298 /* Ensure raw_data is synced with user_data and all "good" entries have been accounted for */
300 /* Start by clearing current user_data */
301 for ( i
= 0 ; i
< uat
->user_data
->len
; i
++ ) {
303 uat
->free_cb(UAT_USER_INDEX_PTR(uat
,i
));
306 g_array_set_size(uat
->user_data
,0);
308 *((uat
)->user_ptr
) = NULL
;
309 *((uat
)->nrows_p
) = 0;
311 /* Now copy "good" raw_data entries to user_data */
312 for ( i
= 0 ; i
< uat
->raw_data
->len
; i
++ ) {
313 void* rec
= uat
->raw_data
->data
+ (uat
->record_size
* i
);
314 gboolean
* valid
= (gboolean
*)(uat
->valid_data
->data
+ sizeof(gboolean
)*i
);
316 g_array_append_vals(uat
->user_data
, rec
, 1);
318 uat
->copy_cb(UAT_USER_INDEX_PTR(uat
,i
), rec
, (unsigned int) uat
->record_size
);
326 fprintf(fp
,"# This file is automatically generated, DO NOT MODIFY.\n");
328 for ( i
= 0 ; i
< uat
->user_data
->len
; i
++ ) {
329 void* rec
= uat
->user_data
->data
+ (uat
->record_size
* i
);
336 for( j
=0 ; j
< uat
->ncols
; j
++ ) {
337 putfld(fp
, rec
, &(f
[j
]));
338 fputs((j
== uat
->ncols
- 1) ? "\n" : "," ,fp
);
345 uat
->changed
= FALSE
;
350 void uat_destroy(uat_t
* uat
) {
351 /* XXX still missing a destructor */
352 g_ptr_array_remove(all_uats
,uat
);
356 uat_t
*uat_find(gchar
*name
) {
359 for (i
=0; i
< all_uats
->len
; i
++) {
360 uat_t
* u
= (uat_t
*)g_ptr_array_index(all_uats
,i
);
362 if (strcmp(u
->name
, name
) == 0 || strcmp(u
->filename
, name
) == 0) {
369 void uat_clear(uat_t
* uat
) {
372 for ( i
= 0 ; i
< uat
->user_data
->len
; i
++ ) {
374 uat
->free_cb(UAT_USER_INDEX_PTR(uat
,i
));
378 for ( i
= 0 ; i
< uat
->raw_data
->len
; i
++ ) {
380 uat
->free_cb(UAT_INDEX_PTR(uat
,i
));
384 g_array_set_size(uat
->raw_data
,0);
385 g_array_set_size(uat
->user_data
,0);
386 g_array_set_size(uat
->valid_data
,0);
388 *((uat
)->user_ptr
) = NULL
;
389 *((uat
)->nrows_p
) = 0;
392 void* uat_dup(uat_t
* uat
, guint
* len_p
) {
393 guint size
= (guint
) (uat
->record_size
* uat
->user_data
->len
);
395 return size
? g_memdup(uat
->user_data
->data
,size
) : NULL
;
398 void* uat_se_dup(uat_t
* uat
, guint
* len_p
) {
399 guint size
= (guint
) (uat
->record_size
* uat
->user_data
->len
);
400 *len_p
= (guint
) size
;
401 return size
? se_memdup(uat
->user_data
->data
,size
) : NULL
;
404 void uat_unload_all(void) {
407 for (i
=0; i
< all_uats
->len
; i
++) {
408 uat_t
* u
= (uat_t
*)g_ptr_array_index(all_uats
,i
);
409 /* Do not unload if not in profile */
410 if (u
->from_profile
) {
417 void uat_cleanup(void) {
418 while( all_uats
->len
) {
419 uat_destroy((uat_t
*)all_uats
->pdata
);
422 g_ptr_array_free(all_uats
,TRUE
);
426 void uat_foreach_table(uat_cb_t cb
,void* user_data
) {
429 for (i
=0; i
< all_uats
->len
; i
++)
430 cb(g_ptr_array_index(all_uats
,i
), user_data
);
435 void uat_load_all(void) {
439 for (i
=0; i
< all_uats
->len
; i
++) {
440 uat_t
* u
= (uat_t
*)g_ptr_array_index(all_uats
,i
);
447 report_failure("Error loading table '%s': %s",u
->name
,err
);
453 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
) {
454 if (strptr
== NULL
) {
455 *err
= "NULL pointer";
463 gboolean
uat_fld_chk_oid(void* u1 _U_
, const char* strptr
, guint len
, const void* u2 _U_
, const void* u3 _U_
, const char** err
) {
467 if (strptr
== NULL
) {
468 *err
= "NULL pointer";
472 for(i
= 0; i
< len
; i
++)
473 if(!(isdigit(strptr
[i
]) || strptr
[i
] == '.')) {
474 *err
= "Only digits [0-9] and \".\" allowed in an OID";
478 if(strptr
[len
-1] == '.')
479 *err
= "OIDs must not be terminated with a \".\"";
481 if(!((*strptr
== '0' || *strptr
== '1' || *strptr
=='2') && (len
> 1 && strptr
[1] == '.')))
482 *err
= "OIDs must start with \"0.\" (ITU-T assigned), \"1.\" (ISO assigned) or \"2.\" (joint ISO/ITU-T assigned)";
484 /* should also check that the second arc is in the range 0-39 */
489 gboolean
uat_fld_chk_proto(void* u1 _U_
, const char* strptr
, guint len
, const void* u2 _U_
, const void* u3 _U_
, const char** err
) {
491 char* name
= ep_strndup(strptr
,len
);
492 ascii_strdown_inplace(name
);
495 if (find_dissector(name
)) {
499 *err
= "dissector not found";
508 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
) {
510 char* str
= ep_strndup(strptr
,len
);
511 long i
= strtol(str
,&str
,10);
513 if ( ( i
== 0) && (errno
== ERANGE
|| errno
== EINVAL
) ) {
514 *err
= g_strerror(errno
);
523 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
) {
525 char* str
= ep_strndup(strptr
,len
);
526 long i
= strtol(str
,&str
,16);
528 if ( ( i
== 0) && (errno
== ERANGE
|| errno
== EINVAL
) ) {
529 *err
= g_strerror(errno
);
538 gboolean
uat_fld_chk_enum(void* u1 _U_
, const char* strptr
, guint len
, const void* v
, const void* u3 _U_
, const char** err
) {
539 char* str
= ep_strndup(strptr
,len
);
541 const value_string
* vs
= (const value_string
*)v
;
543 for(i
=0;vs
[i
].strptr
;i
++) {
544 if (g_str_equal(vs
[i
].strptr
,str
)) {
550 *err
= ep_strdup_printf("invalid value: %s",str
);
554 gboolean
uat_fld_chk_range(void* u1 _U_
, const char* strptr
, guint len
, const void* v _U_
, const void* u3
, const char** err
) {
555 char* str
= ep_strndup(strptr
,len
);
557 convert_ret_t ret
= range_convert_str(&r
, str
,GPOINTER_TO_UINT(u3
));
563 case CVT_SYNTAX_ERROR
:
564 *err
= ep_strdup_printf("syntax error in range: %s",str
);
566 case CVT_NUMBER_TOO_BIG
:
567 *err
= ep_strdup_printf("value too large in range: '%s' (max = %u)",str
,GPOINTER_TO_UINT(u3
));
570 *err
= "This should not happen, it is a bug in wireshark! please report to wireshark-dev@wireshark.org";
575 static int xton(char d
) {
587 case 'a': case 'A': return 10;
588 case 'b': case 'B': return 11;
589 case 'c': case 'C': return 12;
590 case 'd': case 'D': return 13;
591 case 'e': case 'E': return 14;
592 case 'f': case 'F': return 15;
597 char* uat_unbinstring(const char* si
, guint in_len
, guint
* len_p
) {
599 guint len
= in_len
/2;
607 buf
= (guint8
*)g_malloc0(len
+1);
608 if (len_p
) *len_p
= len
;
614 buf
[i
++] = (d1
* 16) + d0
;
622 char* uat_unesc(const char* si
, guint in_len
, guint
* len_p
) {
623 char* buf
= (char *)g_malloc0(in_len
+1);
627 const char* in_end
= si
+in_len
;
629 for (s
= (const char *)si
; s
< in_end
; s
++) {
633 case 'a': *(p
++) = '\a'; len
++; break;
634 case 'b': *(p
++) = '\b'; len
++; break;
635 case 'e': *(p
++) = '\033' /* '\e' is non ANSI-C */; len
++; break;
636 case 'f': *(p
++) = '\f'; len
++; break;
637 case 'n': *(p
++) = '\n'; len
++; break;
638 case 'r': *(p
++) = '\r'; len
++; break;
639 case 't': *(p
++) = '\t'; len
++; break;
640 case 'v': *(p
++) = '\v'; len
++; break;
658 if ( s
[1] >= '0' && s
[1] <= '7' ) {
662 if ( s
[1] >= '0' && s
[1] <= '7' ) {
668 c
= (64 * c2
) + (8 * c1
) + c0
;
669 *(p
++) = (char) (c
> 255 ? 255 : c
);
679 if (isxdigit((guchar
)c1
) && isxdigit((guchar
)c0
)) {
680 *(p
++) = (xton(c1
) * 0x10) + xton(c0
);
700 if (len_p
) *len_p
= len
;
704 char* uat_undquote(const char* si
, guint in_len
, guint
* len_p
) {
705 return uat_unesc(si
+1,in_len
-2,len_p
);
709 char* uat_esc(const char* buf
, guint len
) {
710 const guint8
* end
= ((guint8
*)buf
)+len
;
711 char* out
= (char *)ep_alloc0((4*len
)+1);
715 for (b
= (guint8
*)buf
; b
< end
; b
++) {
719 g_snprintf(s
,5,"\\x%.2x",((guint
)*b
));
728 CHK_STR_IS_DEF(isprint
)
729 CHK_STR_IS_DEF(isalpha
)
730 CHK_STR_IS_DEF(isalnum
)
731 CHK_STR_IS_DEF(isdigit
)
732 CHK_STR_IS_DEF(isxdigit
)
740 * indent-tabs-mode: nil
743 * ex: set shiftwidth=4 tabstop=8 expandtab:
744 * :indentSize=4:tabSize=8:noTabs=true: