more decompress
[wireshark-sm.git] / epan / uat.c
blob10e0ac16e5df2d692848e9a6838175f3af5ba760
1 /*
2 * uat.c
4 * User Accessible Tables
5 * Maintain an array of user accessible data structures
7 * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 2001 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <stdarg.h>
23 #include <glib.h>
25 #include <wsutil/file_util.h>
26 #include <wsutil/str_util.h>
27 #include <wsutil/report_message.h>
28 #include <wsutil/ws_assert.h>
30 #include <wsutil/filesystem.h>
31 #include <epan/packet.h>
32 #include <epan/range.h>
34 #include "uat-int.h"
37 * XXX Files are encoded as ASCII. We might want to encode them as UTF8
38 * instead.
41 static GPtrArray* all_uats;
43 uat_t* uat_new(const char* name,
44 size_t size,
45 const char* filename,
46 bool from_profile,
47 void* data_ptr,
48 unsigned* numitems_ptr,
49 unsigned flags,
50 const char* help,
51 uat_copy_cb_t copy_cb,
52 uat_update_cb_t update_cb,
53 uat_free_cb_t free_cb,
54 uat_post_update_cb_t post_update_cb,
55 uat_reset_cb_t reset_cb,
56 uat_field_t* flds_array) {
57 /* Create new uat */
58 uat_t* uat = g_new(uat_t, 1);
59 unsigned i;
61 /* Add to global array of uats */
62 if (!all_uats)
63 all_uats = g_ptr_array_new();
65 g_ptr_array_add(all_uats,uat);
67 /* Check params */
68 ws_assert(name && size && filename && data_ptr && numitems_ptr);
70 /* Set uat values from inputs */
71 uat->name = g_strdup(name);
72 uat->record_size = size;
73 uat->filename = g_strdup(filename);
74 uat->from_profile = from_profile;
75 /* Callers of uat_new() pass in (void*) for data_ptr, because
76 * that is the "universal" pointer type that can be cast to
77 * anything. However, for our purposes, we want a (void**).
78 * So, we cast (void*) data_ptr to (void**) here. That keeps
79 * gcc -fstrict-aliasing from complaining. */
80 uat->user_ptr = (void**) data_ptr;
81 uat->nrows_p = numitems_ptr;
82 uat->copy_cb = copy_cb;
83 uat->update_cb = update_cb;
84 uat->free_cb = free_cb;
85 uat->post_update_cb = post_update_cb;
86 uat->reset_cb = reset_cb;
87 uat->fields = flds_array;
88 uat->default_values = NULL;
89 uat->user_data = g_array_new(false,false,(unsigned)uat->record_size);
90 uat->raw_data = g_array_new(false,false,(unsigned)uat->record_size);
91 uat->valid_data = g_array_new(false,false,sizeof(bool));
92 uat->changed = false;
93 uat->loaded = false;
94 uat->rep = NULL;
95 uat->free_rep = NULL;
96 uat->help = g_strdup(help);
97 uat->flags = flags;
99 for (i=0;flds_array[i].title;i++) {
100 fld_data_t* f = g_new(fld_data_t, 1);
102 f->colnum = i+1;
103 f->rep = NULL;
104 f->free_rep = NULL;
106 flds_array[i].priv = f;
109 uat->ncols = i;
111 *((void**)data_ptr) = NULL;
112 *numitems_ptr = 0;
114 return uat;
117 void* uat_add_record(uat_t* uat, const void* data, bool valid_rec) {
118 void* rec;
119 bool* valid;
121 uat_insert_record_idx(uat, uat->raw_data->len, data);
123 if (valid_rec) {
124 /* Add a "known good" record to the list to be used by the dissector */
125 g_array_append_vals (uat->user_data, data, 1);
127 rec = UAT_USER_INDEX_PTR(uat, uat->user_data->len - 1);
129 if (uat->copy_cb) {
130 uat->copy_cb(rec, data, (unsigned int) uat->record_size);
133 UAT_UPDATE(uat);
135 valid = &g_array_index(uat->valid_data, bool, uat->valid_data->len-1);
136 *valid = valid_rec;
137 } else {
138 rec = NULL;
141 return rec;
144 /* Updates the validity of a record. */
145 void uat_update_record(uat_t *uat, const void *record, bool valid_rec) {
146 unsigned pos;
147 bool *valid;
149 /* Locate internal UAT data pointer. */
150 for (pos = 0; pos < uat->raw_data->len; pos++) {
151 if (UAT_INDEX_PTR(uat, pos) == record) {
152 break;
155 if (pos == uat->raw_data->len) {
156 /* Data is not within list?! */
157 ws_assert_not_reached();
160 valid = &g_array_index(uat->valid_data, bool, pos);
161 *valid = valid_rec;
164 void uat_swap(uat_t* uat, unsigned a, unsigned b) {
165 size_t s = uat->record_size;
166 void* tmp;
167 bool tmp_bool;
169 ws_assert( a < uat->raw_data->len && b < uat->raw_data->len );
171 if (a == b) return;
173 tmp = g_malloc(s);
174 memcpy(tmp, UAT_INDEX_PTR(uat,a), s);
175 memcpy(UAT_INDEX_PTR(uat,a), UAT_INDEX_PTR(uat,b), s);
176 memcpy(UAT_INDEX_PTR(uat,b), tmp, s);
177 g_free(tmp);
179 tmp_bool = *(bool*)(uat->valid_data->data + (sizeof(bool) * (a)));
180 *(bool*)(uat->valid_data->data + (sizeof(bool) * (a))) = *(bool*)(uat->valid_data->data + (sizeof(bool) * (b)));
181 *(bool*)(uat->valid_data->data + (sizeof(bool) * (b))) = tmp_bool;
186 void uat_insert_record_idx(uat_t* uat, unsigned idx, const void *src_record) {
187 /* Allow insert before an existing item or append after the last item. */
188 ws_assert( idx <= uat->raw_data->len );
190 /* Store a copy of the record and invoke copy_cb to clone pointers too. */
191 g_array_insert_vals(uat->raw_data, idx, src_record, 1);
192 void *rec = UAT_INDEX_PTR(uat, idx);
193 if (uat->copy_cb) {
194 uat->copy_cb(rec, src_record, (unsigned int) uat->record_size);
195 } else {
196 memcpy(rec, src_record, (unsigned int) uat->record_size);
199 /* Initially assume that the record is invalid, it is not copied to the
200 * user-visible records list. */
201 bool valid_rec = false;
202 g_array_insert_val(uat->valid_data, idx, valid_rec);
205 void uat_remove_record_idx(uat_t* uat, unsigned idx) {
207 ws_assert( idx < uat->raw_data->len );
209 if (uat->free_cb) {
210 uat->free_cb(UAT_INDEX_PTR(uat,idx));
213 g_array_remove_index(uat->raw_data, idx);
214 g_array_remove_index(uat->valid_data, idx);
217 void uat_remove_record_range(uat_t* uat, unsigned idx, unsigned count) {
219 ws_assert( idx + count <= uat->raw_data->len );
221 if (count == 0) {
222 return;
225 if (uat->free_cb) {
226 for (unsigned i = 0; i < count; i++) {
227 uat->free_cb(UAT_INDEX_PTR(uat, idx + i));
231 g_array_remove_range(uat->raw_data, idx, count);
232 g_array_remove_range(uat->valid_data, idx, count);
235 void uat_move_index(uat_t * uat, unsigned old_idx, unsigned new_idx)
237 unsigned dir = 1;
238 unsigned start = old_idx;
239 if ( old_idx > new_idx )
240 dir = -1;
242 while ( start != new_idx )
244 uat_swap(uat, start, start + dir);
245 start += dir;
249 /* The returned filename was g_malloc()'d so the caller must free it */
250 char* uat_get_actual_filename(uat_t* uat, bool for_writing) {
251 char *pers_fname = NULL;
253 pers_fname = get_persconffile_path(uat->filename, uat->from_profile);
254 if ((! for_writing ) && (! file_exists(pers_fname) )) {
255 char* data_fname = get_datafile_path(uat->filename);
257 if (file_exists(data_fname)) {
258 g_free(pers_fname);
259 return data_fname;
262 g_free(data_fname);
263 g_free(pers_fname);
264 return NULL;
267 return pers_fname;
270 uat_t* uat_get_table_by_name(const char* name) {
271 unsigned i;
273 for (i=0; i < all_uats->len; i++) {
274 uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
275 if ( g_str_equal(u->name,name) ) {
276 return (u);
280 return NULL;
283 void uat_set_default_values(uat_t *uat_in, const char *default_values[])
285 uat_in->default_values = default_values;
288 char *uat_fld_tostr(void *rec, uat_field_t *f) {
289 unsigned len;
290 char *ptr;
291 char *out;
293 f->cb.tostr(rec, &ptr, &len, f->cbdata.tostr, f->fld_data);
295 switch(f->mode) {
296 case PT_TXTMOD_NONE:
297 case PT_TXTMOD_ENUM:
298 case PT_TXTMOD_BOOL:
299 case PT_TXTMOD_FILENAME:
300 case PT_TXTMOD_DIRECTORYNAME:
301 case PT_TXTMOD_DISPLAY_FILTER:
302 case PT_TXTMOD_PROTO_FIELD:
303 case PT_TXTMOD_COLOR:
304 case PT_TXTMOD_STRING:
305 case PT_TXTMOD_DISSECTOR:
306 out = g_strndup(ptr, len);
307 break;
308 case PT_TXTMOD_HEXBYTES: {
309 GString *s = g_string_sized_new( len*2 + 1 );
310 unsigned i;
312 for (i=0; i<len;i++) g_string_append_printf(s, "%.2X", ((const uint8_t*)ptr)[i]);
314 out = g_string_free(s, FALSE);
315 break;
317 default:
318 ws_assert_not_reached();
319 out = NULL;
320 break;
323 g_free(ptr);
324 return out;
327 static void putfld(FILE* fp, void* rec, uat_field_t* f) {
328 unsigned fld_len;
329 char* fld_ptr;
331 f->cb.tostr(rec,&fld_ptr,&fld_len,f->cbdata.tostr,f->fld_data);
333 switch(f->mode){
334 case PT_TXTMOD_NONE:
335 case PT_TXTMOD_ENUM:
336 case PT_TXTMOD_FILENAME:
337 case PT_TXTMOD_DIRECTORYNAME:
338 case PT_TXTMOD_DISPLAY_FILTER:
339 case PT_TXTMOD_PROTO_FIELD:
340 case PT_TXTMOD_COLOR:
341 case PT_TXTMOD_STRING:
342 case PT_TXTMOD_DISSECTOR:
344 unsigned i;
346 putc('"',fp);
348 for(i=0;i<fld_len;i++) {
349 char c = fld_ptr[i];
351 if (c == '"' || c == '\\' || ! g_ascii_isprint((unsigned char)c) ) {
352 fprintf(fp,"\\x%02x", (unsigned char) c);
353 } else {
354 putc(c,fp);
358 putc('"',fp);
359 break;
361 case PT_TXTMOD_HEXBYTES: {
362 unsigned i;
364 for(i=0;i<fld_len;i++) {
365 fprintf(fp,"%02x", (unsigned char)fld_ptr[i]);
368 break;
370 case PT_TXTMOD_BOOL: {
371 fprintf(fp,"\"%s\"", fld_ptr);
372 break;
374 default:
375 ws_assert_not_reached();
378 g_free(fld_ptr);
381 bool uat_save(uat_t* uat, char** error) {
382 unsigned i;
383 char* fname = uat_get_actual_filename(uat,true);
384 FILE* fp;
386 if (! fname ) return false;
388 fp = ws_fopen(fname,"w");
390 if (!fp && errno == ENOENT) {
391 /* Parent directory does not exist, try creating first */
392 char *pf_dir_path = NULL;
393 if (create_persconffile_dir(&pf_dir_path) != 0) {
394 *error = ws_strdup_printf("uat_save: error creating '%s'", pf_dir_path);
395 g_free (pf_dir_path);
396 return false;
398 fp = ws_fopen(fname,"w");
401 if (!fp) {
402 *error = ws_strdup_printf("uat_save: error opening '%s': %s",fname,g_strerror(errno));
403 g_free(fname);
404 return false;
407 *error = NULL;
408 g_free(fname);
410 /* Ensure raw_data is synced with user_data and all "good" entries have been accounted for */
412 /* Start by clearing current user_data */
413 for ( i = 0 ; i < uat->user_data->len ; i++ ) {
414 if (uat->free_cb) {
415 uat->free_cb(UAT_USER_INDEX_PTR(uat,i));
418 g_array_set_size(uat->user_data,0);
420 *((uat)->user_ptr) = NULL;
421 *((uat)->nrows_p) = 0;
423 /* Now copy "good" raw_data entries to user_data */
424 for ( i = 0 ; i < uat->raw_data->len ; i++ ) {
425 void *rec = UAT_INDEX_PTR(uat, i);
426 bool valid = g_array_index(uat->valid_data, bool, i);
427 if (valid) {
428 g_array_append_vals(uat->user_data, rec, 1);
429 if (uat->copy_cb) {
430 uat->copy_cb(UAT_USER_INDEX_PTR(uat, uat->user_data->len - 1),
431 rec, (unsigned int) uat->record_size);
434 UAT_UPDATE(uat);
439 fprintf(fp,"# This file is automatically generated. BE CAREFUL MODIFYING.\n");
440 fprintf(fp,"# You can add (but not modify or delete) records with the command line option:\n");
441 #ifdef _WIN32
442 /* Powershell 7.3 has UN*X-like treatment of double quotes inside quotes.
443 * Since it's not shipped with Windows, assume someone using PS 7.3 or
444 * later knows how to quote with it.
446 fprintf(fp,"# -o \"uat:%s:", uat->filename);
447 #else
448 fprintf(fp,"# -o 'uat:%s:", uat->filename);
449 #endif
450 for (i = 0; i < uat->ncols; ++i) {
451 uat_field_t *field = &uat->fields[i];
452 switch(field->mode) {
453 case PT_TXTMOD_HEXBYTES:
454 fprintf(fp, "%s", field->name);
455 break;
456 default:
457 #ifdef _WIN32
458 fprintf(fp, "\\\"%s\\\"", field->name);
459 #else
460 fprintf(fp, "\"%s\"", field->name);
461 #endif
463 #ifdef _WIN32
464 fputs((i == uat->ncols - 1) ? "\"\n" : "," ,fp);
465 #else
466 fputs((i == uat->ncols - 1) ? "'\n" : "," ,fp);
467 #endif
470 fprintf(fp,"#");
471 for (i = 0; i < uat->ncols; ++i) {
472 uat_field_t *field = &uat->fields[i];
473 switch(field->mode) {
474 case PT_TXTMOD_HEXBYTES:
475 fprintf(fp, "%s", field->title);
476 break;
477 default:
478 fprintf(fp, "\"%s\"", field->title);
480 fputs((i == uat->ncols - 1) ? "\n" : "," ,fp);
483 for ( i = 0 ; i < uat->user_data->len ; i++ ) {
484 void* rec = uat->user_data->data + (uat->record_size * i);
485 uat_field_t* f;
486 unsigned j;
488 f = uat->fields;
491 for( j=0 ; j < uat->ncols ; j++ ) {
492 putfld(fp, rec, &(f[j]));
493 fputs((j == uat->ncols - 1) ? "\n" : "," ,fp);
498 fclose(fp);
500 uat->changed = false;
502 return true;
505 uat_t *uat_find(char *name) {
506 unsigned i;
508 for (i=0; i < all_uats->len; i++) {
509 uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
511 if (strcmp(u->name, name) == 0 || strcmp(u->filename, name) == 0) {
512 return u;
515 return NULL;
518 void uat_clear(uat_t* uat) {
519 unsigned i;
521 for ( i = 0 ; i < uat->user_data->len ; i++ ) {
522 if (uat->free_cb) {
523 uat->free_cb(UAT_USER_INDEX_PTR(uat,i));
527 for ( i = 0 ; i < uat->raw_data->len ; i++ ) {
528 if (uat->free_cb) {
529 uat->free_cb(UAT_INDEX_PTR(uat,i));
533 g_array_set_size(uat->raw_data,0);
534 g_array_set_size(uat->user_data,0);
535 g_array_set_size(uat->valid_data,0);
537 *((uat)->user_ptr) = NULL;
538 *((uat)->nrows_p) = 0;
540 if (uat->reset_cb) {
541 uat->reset_cb();
545 void uat_unload_all(void) {
546 unsigned i;
548 for (i=0; i < all_uats->len; i++) {
549 uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
550 /* Do not unload if not in profile */
551 if (u->from_profile) {
552 uat_clear(u);
553 u->loaded = false;
558 static void free_uat(uat_t *uat)
560 unsigned j;
562 uat_clear(uat);
563 g_free(uat->help);
564 g_free(uat->name);
565 g_free(uat->filename);
566 g_array_free(uat->user_data, true);
567 g_array_free(uat->raw_data, true);
568 g_array_free(uat->valid_data, true);
569 for (j = 0; uat->fields[j].title; j++)
570 g_free(uat->fields[j].priv);
571 g_free(uat);
574 void uat_cleanup(void) {
575 unsigned i;
576 uat_t* uat;
578 for (i = 0; i < all_uats->len; i++) {
579 uat = (uat_t *)g_ptr_array_index(all_uats, i);
580 free_uat(uat);
583 g_ptr_array_free(all_uats,true);
586 void uat_destroy(uat_t *uat)
588 g_ptr_array_remove(all_uats, uat);
589 free_uat(uat);
592 void uat_foreach_table(uat_cb_t cb,void* user_data) {
593 unsigned i;
595 for (i=0; i < all_uats->len; i++)
596 cb(g_ptr_array_index(all_uats,i), user_data);
600 void uat_load_all(void) {
601 unsigned i;
602 char* err;
604 for (i=0; i < all_uats->len; i++) {
605 uat_t* u = (uat_t *)g_ptr_array_index(all_uats,i);
607 if (!u->loaded) {
608 err = NULL;
609 if (!uat_load(u, NULL, &err)) {
610 report_failure("Error loading table '%s': %s",u->name,err);
611 g_free(err);
618 bool uat_fld_chk_str(void* u1 _U_, const char* strptr, unsigned len _U_, const void* u2 _U_, const void* u3 _U_, char** err) {
619 if (strptr == NULL) {
620 *err = g_strdup("NULL pointer");
621 return false;
624 *err = NULL;
625 return true;
628 bool uat_fld_chk_oid(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
629 unsigned int i;
630 *err = NULL;
632 if (strptr == NULL) {
633 *err = g_strdup("NULL pointer");
634 return false;
637 if (len == 0) {
638 *err = g_strdup("Empty OID");
639 return false;
642 for(i = 0; i < len; i++)
643 if(!(g_ascii_isdigit(strptr[i]) || strptr[i] == '.')) {
644 *err = g_strdup("Only digits [0-9] and \".\" allowed in an OID");
645 return false;
648 if(strptr[len-1] == '.') {
649 *err = g_strdup("OIDs must not be terminated with a \".\"");
650 return false;
653 if(!((*strptr == '0' || *strptr == '1' || *strptr =='2') && (len > 1 && strptr[1] == '.'))) {
654 *err = g_strdup("OIDs must start with \"0.\" (ITU-T assigned), \"1.\" (ISO assigned) or \"2.\" (joint ISO/ITU-T assigned)");
655 return false;
658 /* should also check that the second arc is in the range 0-39 */
660 return *err == NULL;
663 bool uat_fld_chk_proto(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
664 if (len) {
665 char* name = g_strndup(strptr,len);
666 g_strstrip(name);
668 if (find_dissector(name)) {
669 *err = NULL;
670 g_free(name);
671 return true;
672 } else {
673 *err = g_strdup("dissector not found");
674 g_free(name);
675 return false;
677 } else {
678 *err = NULL;
679 return true;
683 static bool uat_fld_chk_num_check_result(bool result, const char* strn, char** err) {
684 if (result && ((*strn != '\0') && (*strn != ' '))) {
685 /* string valid, but followed by something other than a space */
686 result = false;
687 errno = EINVAL;
689 if (!result) {
690 switch (errno) {
692 case EINVAL:
693 *err = g_strdup("Invalid value");
694 break;
696 case ERANGE:
697 *err = g_strdup("Value too large");
698 break;
700 default:
701 *err = g_strdup(g_strerror(errno));
702 break;
706 return result;
709 static bool uat_fld_chk_num(int base, const char* strptr, unsigned len, char** err) {
710 if (len > 0) {
711 char* str = g_strndup(strptr, len);
712 const char* strn;
713 bool result;
714 uint32_t value;
716 result = ws_basestrtou32(str, &strn, &value, base);
717 result = uat_fld_chk_num_check_result(result, strn, err);
718 g_free(str);
719 return result;
722 *err = NULL;
723 return true;
726 static bool uat_fld_chk_num64(int base, const char* strptr, unsigned len, char** err) {
727 if (len > 0) {
728 char* str = g_strndup(strptr, len);
729 const char* strn;
730 bool result;
731 uint64_t value64;
733 result = ws_basestrtou64(str, &strn, &value64, base);
734 result = uat_fld_chk_num_check_result(result, strn, err);
735 g_free(str);
736 return result;
739 *err = NULL;
740 return true;
743 bool uat_fld_chk_num_dec(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
744 return uat_fld_chk_num(10, strptr, len, err);
747 bool uat_fld_chk_num_hex(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
748 return uat_fld_chk_num(16, strptr, len, err);
751 bool uat_fld_chk_num_dec64(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
752 return uat_fld_chk_num64(10, strptr, len, err);
755 bool uat_fld_chk_num_hex64(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
756 return uat_fld_chk_num64(16, strptr, len, err);
759 bool uat_fld_chk_num_signed_dec(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
760 if (len > 0) {
761 char* str = g_strndup(strptr,len);
762 const char* strn;
763 bool result;
764 int32_t value;
766 result = ws_strtoi32(str, &strn, &value);
767 result = uat_fld_chk_num_check_result(result, strn, err);
768 g_free(str);
770 return result;
773 *err = NULL;
774 return true;
777 bool uat_fld_chk_num_signed_dec64(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
778 if (len > 0) {
779 char* str = g_strndup(strptr, len);
780 const char* strn;
781 bool result;
782 int64_t value;
784 result = ws_strtoi64(str, &strn, &value);
785 result = uat_fld_chk_num_check_result(result, strn, err);
786 g_free(str);
788 return result;
791 *err = NULL;
792 return true;
795 bool uat_fld_chk_bool(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err)
797 char* str = g_strndup(strptr,len);
799 if ((g_strcmp0(str, "TRUE") == 0) ||
800 (g_strcmp0(str, "FALSE") == 0)) {
801 *err = NULL;
802 g_free(str);
803 return true;
806 *err = ws_strdup_printf("invalid value: %s (must be true or false)", str);
807 g_free(str);
808 return false;
812 bool uat_fld_chk_enum(void* u1 _U_, const char* strptr, unsigned len, const void* v, const void* u3 _U_, char** err) {
813 char* str = g_strndup(strptr,len);
814 unsigned i;
815 const value_string* vs = (const value_string *)v;
817 for(i=0;vs[i].strptr;i++) {
818 if (g_strcmp0(vs[i].strptr,str) == 0) {
819 *err = NULL;
820 g_free(str);
821 return true;
825 *err = ws_strdup_printf("invalid value: %s",str);
826 g_free(str);
827 return false;
830 bool uat_fld_chk_range(void* u1 _U_, const char* strptr, unsigned len, const void* v _U_, const void* u3, char** err) {
831 char* str = g_strndup(strptr,len);
832 range_t* r = NULL;
833 convert_ret_t ret = range_convert_str(NULL, &r, str,GPOINTER_TO_UINT(u3));
834 bool ret_value = false;
836 switch ( ret ) {
837 case CVT_NO_ERROR:
838 *err = NULL;
839 ret_value = true;
840 break;
841 case CVT_SYNTAX_ERROR:
842 *err = ws_strdup_printf("syntax error in range: %s",str);
843 ret_value = false;
844 break;
845 case CVT_NUMBER_TOO_BIG:
846 *err = ws_strdup_printf("value too large in range: '%s' (max = %u)",str,GPOINTER_TO_UINT(u3));
847 ret_value = false;
848 break;
849 default:
850 *err = g_strdup("Unable to convert range. Please report this to wireshark-dev@wireshark.org");
851 ret_value = false;
852 break;
855 g_free(str);
856 wmem_free(NULL, r);
857 return ret_value;
860 bool uat_fld_chk_color(void* u1 _U_, const char* strptr, unsigned len, const void* v _U_, const void* u3 _U_, char** err) {
862 if ((len != 7) || (*strptr != '#')) {
863 *err = g_strdup("Color must be of the format #RRGGBB");
864 return false;
867 /* Color is just # followed by hex string, so use hex verification */
868 return uat_fld_chk_num(16, strptr + 1, len - 1, err);
871 char* uat_unbinstring(const char* si, unsigned in_len, unsigned* len_p) {
872 uint8_t* buf;
873 unsigned len = in_len/2;
874 int i = 0;
875 int d0, d1;
877 if (in_len%2) {
878 return NULL;
881 buf= (uint8_t *)g_malloc0(len+1);
882 if (len_p) *len_p = len;
884 while(in_len) {
885 d1 = ws_xton(*(si++));
886 d0 = ws_xton(*(si++));
888 buf[i++] = (d1 * 16) + d0;
890 in_len -= 2;
893 return (char*)buf;
896 char* uat_unesc(const char* si, unsigned in_len, unsigned* len_p) {
897 char* buf = (char *)g_malloc0(in_len+1);
898 char* p = buf;
899 unsigned len = 0;
900 const char* s;
901 const char* in_end = si+in_len;
903 for (s = si; s < in_end; s++) {
904 switch(*s) {
905 case '\\':
906 switch(*(++s)) {
907 case 'a': *(p++) = '\a'; len++; break;
908 case 'b': *(p++) = '\b'; len++; break;
909 case 'e': *(p++) = '\033' /* '\e' is non ANSI-C */; len++; break;
910 case 'f': *(p++) = '\f'; len++; break;
911 case 'n': *(p++) = '\n'; len++; break;
912 case 'r': *(p++) = '\r'; len++; break;
913 case 't': *(p++) = '\t'; len++; break;
914 case 'v': *(p++) = '\v'; len++; break;
916 case '0':
917 case '1':
918 case '2':
919 case '3':
920 case '4':
921 case '5':
922 case '6':
923 case '7':
925 int c0 = 0;
926 int c1 = 0;
927 int c2 = 0;
928 int c = 0;
930 c0 = (*s) - '0';
932 if ( s[1] >= '0' && s[1] <= '7' ) {
933 c1 = c0;
934 c0 = (*++s) - '0';
936 if ( s[1] >= '0' && s[1] <= '7' ) {
937 c2 = c1;
938 c1 = c0;
939 c0 = (*++s) - '0';
942 c = (64 * c2) + (8 * c1) + c0;
943 *(p++) = (char) (c > 255 ? 255 : c);
944 len++;
945 break;
948 case 'x':
950 char c1 = *(s+1);
951 char c0 = *(s+2);
953 if (g_ascii_isxdigit(c1) && g_ascii_isxdigit(c0)) {
954 *(p++) = (ws_xton(c1) * 0x10) + ws_xton(c0);
955 s += 2;
956 } else {
957 *(p++) = *s;
959 len++;
960 break;
962 default:
963 *p++ = *s;
964 break;
966 break;
967 default:
968 *(p++) = *s;
969 len++;
970 break;
974 if (len_p) *len_p = len;
975 return buf;
978 char* uat_undquote(const char* si, unsigned in_len, unsigned* len_p) {
979 return uat_unesc(si+1,in_len-2,len_p);
983 char* uat_esc(const char* buf, unsigned len) {
984 const uint8_t* end = ((const uint8_t*)buf)+len;
985 char* out = (char *)g_malloc0((4*len)+1);
986 const uint8_t* b;
987 char* s = out;
989 for (b = (const uint8_t *)buf; b < end; b++) {
990 if (*b == '"' || *b == '\\' || ! g_ascii_isprint(*b) ) {
991 snprintf(s,5,"\\x%02x",((unsigned)*b));
992 s+=4;
993 } else {
994 *(s++) = (*b);
998 return out;
1002 bool uat_fld_chk_str_isprint(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
1003 unsigned i;
1005 for (i = 0; i < len; i++) {
1006 char c = strptr[i];
1007 if (! g_ascii_isprint(c)) {
1008 *err = ws_strdup_printf("invalid char pos=%d value=%02x", i, (unsigned char) c);
1009 return false;
1012 *err = NULL;
1013 return true;
1016 bool uat_fld_chk_str_isalpha(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
1017 unsigned i;
1019 for (i = 0; i < len; i++) {
1020 char c = strptr[i];
1021 if (! g_ascii_isalpha(c)) {
1022 *err = ws_strdup_printf("invalid char pos=%d value=%02x", i, (unsigned char) c);
1023 return false;
1026 *err = NULL;
1027 return true;
1030 bool uat_fld_chk_str_isalnum(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
1031 unsigned i;
1033 for (i = 0; i < len; i++) {
1034 char c = strptr[i];
1035 if (! g_ascii_isalnum(c)) {
1036 *err = ws_strdup_printf("invalid char pos=%d value=%02x", i, (unsigned char) c);
1037 return false;
1040 *err = NULL;
1041 return true;
1044 bool uat_fld_chk_str_isdigit(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
1045 unsigned i;
1047 for (i = 0; i < len; i++) {
1048 char c = strptr[i];
1049 if (! g_ascii_isdigit(c)) {
1050 *err = ws_strdup_printf("invalid char pos=%d value=%02x", i, (unsigned char) c);
1051 return false;
1054 *err = NULL;
1055 return true;
1058 bool uat_fld_chk_str_isxdigit(void* u1 _U_, const char* strptr, unsigned len, const void* u2 _U_, const void* u3 _U_, char** err) {
1059 unsigned i;
1061 for (i = 0; i < len; i++) {
1062 char c = strptr[i];
1063 if (! g_ascii_isxdigit(c)) {
1064 *err = ws_strdup_printf("invalid char pos=%d value=%02x", i, (unsigned char) c);
1065 return false;
1068 *err = NULL;
1069 return true;
1074 * Editor modelines
1076 * Local Variables:
1077 * c-basic-offset: 4
1078 * tab-width: 8
1079 * indent-tabs-mode: nil
1080 * End:
1082 * ex: set shiftwidth=4 tabstop=8 expandtab:
1083 * :indentSize=4:tabSize=8:noTabs=true: