1 /* value_string.c 2 * Routines for value_strings 3 * 4 * Wireshark - Network traffic analyzer 5 * By Gerald Combs <gerald@wireshark.org> 6 * Copyright 1998 Gerald Combs 7 * 8 * SPDX-License-Identifier: GPL-2.0-or-later 9 */ 10 11 #include "config.h" 12 #define WS_LOG_DOMAIN LOG_DOMAIN_EPAN 13 14 #include <stdio.h> 15 #include <string.h> 16 17 #include <epan/wmem_scopes.h> 18 #include "proto.h" 19 #include "to_str.h" 20 #include "value_string.h" 21 #include <wsutil/ws_assert.h> 22 23 #include <wsutil/wslog.h> 24 25 /* REGULAR VALUE STRING */ 26 27 /* Tries to match val against each element in the value_string array vs. 28 Returns the associated string ptr on a match. 29 Formats val with fmt, and returns the resulting string, on failure. */ 30 const gchar * 31 val_to_str(const guint32 val, const value_string *vs, const char *fmt) 32 { 33 const gchar *ret; 34 35 DISSECTOR_ASSERT(fmt != NULL); 36 37 ret = try_val_to_str(val, vs); 38 if (ret != NULL) 39 return ret; 40 41 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 42 } 43 44 gchar * 45 val_to_str_wmem(wmem_allocator_t *scope, const guint32 val, const value_string *vs, const char *fmt) 46 { 47 const gchar *ret; 48 49 DISSECTOR_ASSERT(fmt != NULL); 50 51 ret = try_val_to_str(val, vs); 52 if (ret != NULL) 53 return wmem_strdup(scope, ret); 54 55 return wmem_strdup_printf(scope, fmt, val); 56 } 57 58 /* Tries to match val against each element in the value_string array vs. 59 Returns the associated string ptr on a match. 60 Returns 'unknown_str', on failure. */ 61 const gchar * 62 val_to_str_const(const guint32 val, const value_string *vs, 63 const char *unknown_str) 64 { 65 const gchar *ret; 66 67 DISSECTOR_ASSERT(unknown_str != NULL); 68 69 ret = try_val_to_str(val, vs); 70 if (ret != NULL) 71 return ret; 72 73 return unknown_str; 74 } 75 76 /* Tries to match val against each element in the value_string array vs. 77 Returns the associated string ptr, and sets "*idx" to the index in 78 that table, on a match, and returns NULL, and sets "*idx" to -1, 79 on failure. */ 80 const gchar * 81 try_val_to_str_idx(const guint32 val, const value_string *vs, gint *idx) 82 { 83 gint i = 0; 84 85 DISSECTOR_ASSERT(idx != NULL); 86 87 if(vs) { 88 while (vs[i].strptr) { 89 if (vs[i].value == val) { 90 *idx = i; 91 return(vs[i].strptr); 92 } 93 i++; 94 } 95 } 96 97 *idx = -1; 98 return NULL; 99 } 100 101 /* Like try_val_to_str_idx(), but doesn't return the index. */ 102 const gchar * 103 try_val_to_str(const guint32 val, const value_string *vs) 104 { 105 gint ignore_me; 106 return try_val_to_str_idx(val, vs, &ignore_me); 107 } 108 109 /* 64-BIT VALUE STRING */ 110 111 const gchar * 112 val64_to_str(const guint64 val, const val64_string *vs, const char *fmt) 113 { 114 const gchar *ret; 115 116 DISSECTOR_ASSERT(fmt != NULL); 117 118 ret = try_val64_to_str(val, vs); 119 if (ret != NULL) 120 return ret; 121 122 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 123 } 124 125 const gchar * 126 val64_to_str_const(const guint64 val, const val64_string *vs, 127 const char *unknown_str) 128 { 129 const gchar *ret; 130 131 DISSECTOR_ASSERT(unknown_str != NULL); 132 133 ret = try_val64_to_str(val, vs); 134 if (ret != NULL) 135 return ret; 136 137 return unknown_str; 138 } 139 140 const gchar * 141 try_val64_to_str_idx(const guint64 val, const val64_string *vs, gint *idx) 142 { 143 gint i = 0; 144 145 DISSECTOR_ASSERT(idx != NULL); 146 147 if(vs) { 148 while (vs[i].strptr) { 149 if (vs[i].value == val) { 150 *idx = i; 151 return(vs[i].strptr); 152 } 153 i++; 154 } 155 } 156 157 *idx = -1; 158 return NULL; 159 } 160 161 const gchar * 162 try_val64_to_str(const guint64 val, const val64_string *vs) 163 { 164 gint ignore_me; 165 return try_val64_to_str_idx(val, vs, &ignore_me); 166 } 167 168 /* REVERSE VALUE STRING */ 169 170 /* We use the same struct as for regular value strings, but we look up strings 171 * and return values instead */ 172 173 /* Like val_to_str except backwards */ 174 guint32 175 str_to_val(const gchar *val, const value_string *vs, const guint32 err_val) 176 { 177 gint i; 178 179 i = str_to_val_idx(val, vs); 180 181 if (i >= 0) { 182 return vs[i].value; 183 } 184 185 return err_val; 186 } 187 188 /* Find the index of a string in a value_string, or -1 when not present */ 189 gint 190 str_to_val_idx(const gchar *val, const value_string *vs) 191 { 192 gint i = 0; 193 194 if(vs) { 195 196 while (vs[i].strptr) { 197 198 if (strcmp(vs[i].strptr, val) == 0) { 199 return i; 200 } 201 202 i++; 203 } 204 205 } 206 207 return -1; 208 } 209 210 /* EXTENDED VALUE STRING */ 211 212 /* Extended value strings allow fast(er) value_string array lookups by 213 * using (if possible) direct access or a binary search of the array. 214 * 215 * If the values in the value_string array are a contiguous range of values 216 * from min to max, the value will be used as as a direct index into the array. 217 * 218 * If the values in the array are not contiguous (ie: there are "gaps"), 219 * but are in assending order a binary search will be used. 220 * 221 * If direct access or binary search cannot be used, then a linear search 222 * is used and a warning is emitted. 223 * 224 * Note that the value_string array used with VALUE_STRING_EXT_INIT 225 * *must* be terminated with {0, NULL}). 226 * 227 * Extended value strings are defined at compile time as follows: 228 * static const value_string vs[] = { {value1, "string1"}, 229 * {value2, "string2"}, 230 * ..., 231 * {0, NULL}}; 232 * static value_string_ext vse = VALUE_STRING_EXT_INIT(vs); 233 * 234 * Extended value strings can be created at runtime by calling 235 * value_string_ext_new(<ptr to value_string array>, 236 * <total number of entries in the value_string_array>, 237 * <value_string_name>); 238 * Note: The <total number of entries in the value_string_array> should include 239 * the {0, NULL} entry. 240 */ 241 242 /* Create a value_string_ext given a ptr to a value_string array and the total 243 * number of entries. Note that the total number of entries should include the 244 * required {0, NULL} terminating entry of the array. 245 * Returns a pointer to an epan-scoped'd and initialized value_string_ext 246 * struct. */ 247 value_string_ext * 248 value_string_ext_new(const value_string *vs, guint vs_tot_num_entries, 249 const gchar *vs_name) 250 { 251 value_string_ext *vse; 252 253 DISSECTOR_ASSERT (vs_name != NULL); 254 DISSECTOR_ASSERT (vs_tot_num_entries > 0); 255 /* Null-terminated value-string ? */ 256 DISSECTOR_ASSERT (vs[vs_tot_num_entries-1].strptr == NULL); 257 258 vse = wmem_new(wmem_epan_scope(), value_string_ext); 259 vse->_vs_p = vs; 260 vse->_vs_num_entries = vs_tot_num_entries - 1; 261 /* We set our 'match' function to the init function, which finishes by 262 * setting the match function properly and then calling it. This is a 263 * simple way to do lazy initialization of extended value strings. 264 * The init function also sets up _vs_first_value for us. */ 265 vse->_vs_first_value = 0; 266 vse->_vs_match2 = _try_val_to_str_ext_init; 267 vse->_vs_name = vs_name; 268 269 return vse; 270 } 271 272 void 273 value_string_ext_free(value_string_ext *vse) 274 { 275 wmem_free(wmem_epan_scope(), vse); 276 } 277 278 /* Like try_val_to_str for extended value strings */ 279 const gchar * 280 try_val_to_str_ext(const guint32 val, value_string_ext *vse) 281 { 282 if (vse) { 283 const value_string *vs = vse->_vs_match2(val, vse); 284 285 if (vs) { 286 return vs->strptr; 287 } 288 } 289 290 return NULL; 291 } 292 293 /* Like try_val_to_str_idx for extended value strings */ 294 const gchar * 295 try_val_to_str_idx_ext(const guint32 val, value_string_ext *vse, gint *idx) 296 { 297 if (vse) { 298 const value_string *vs = vse->_vs_match2(val, vse); 299 if (vs) { 300 *idx = (gint) (vs - vse->_vs_p); 301 return vs->strptr; 302 } 303 } 304 *idx = -1; 305 return NULL; 306 } 307 308 /* Like val_to_str for extended value strings */ 309 const gchar * 310 val_to_str_ext(const guint32 val, value_string_ext *vse, const char *fmt) 311 { 312 const gchar *ret; 313 314 DISSECTOR_ASSERT(fmt != NULL); 315 316 ret = try_val_to_str_ext(val, vse); 317 if (ret != NULL) 318 return ret; 319 320 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 321 } 322 323 gchar * 324 val_to_str_ext_wmem(wmem_allocator_t *scope, const guint32 val, value_string_ext *vse, const char *fmt) 325 { 326 const gchar *ret; 327 328 DISSECTOR_ASSERT(fmt != NULL); 329 330 ret = try_val_to_str_ext(val, vse); 331 if (ret != NULL) 332 return wmem_strdup(scope, ret); 333 334 return wmem_strdup_printf(scope, fmt, val); 335 } 336 337 /* Like val_to_str_const for extended value strings */ 338 const gchar * 339 val_to_str_ext_const(const guint32 val, value_string_ext *vse, 340 const char *unknown_str) 341 { 342 const gchar *ret; 343 344 DISSECTOR_ASSERT(unknown_str != NULL); 345 346 ret = try_val_to_str_ext(val, vse); 347 if (ret != NULL) 348 return ret; 349 350 return unknown_str; 351 } 352 353 /* Fallback linear matching algorithm for extended value strings */ 354 static const value_string * 355 _try_val_to_str_linear(const guint32 val, value_string_ext *vse) 356 { 357 const value_string *vs_p = vse->_vs_p; 358 guint i; 359 for (i=0; i<vse->_vs_num_entries; i++) { 360 if (vs_p[i].value == val) 361 return &(vs_p[i]); 362 } 363 return NULL; 364 } 365 366 /* Constant-time matching algorithm for contiguous extended value strings */ 367 static const value_string * 368 _try_val_to_str_index(const guint32 val, value_string_ext *vse) 369 { 370 guint32 i; 371 372 i = val - vse->_vs_first_value; 373 if (i < vse->_vs_num_entries) { 374 ws_assert (val == vse->_vs_p[i].value); 375 return &(vse->_vs_p[i]); 376 } 377 return NULL; 378 } 379 380 /* log(n)-time matching algorithm for sorted extended value strings */ 381 static const value_string * 382 _try_val_to_str_bsearch(const guint32 val, value_string_ext *vse) 383 { 384 guint low, i, max; 385 guint32 item; 386 387 for (low = 0, max = vse->_vs_num_entries; low < max; ) { 388 i = (low + max) / 2; 389 item = vse->_vs_p[i].value; 390 391 if (val < item) 392 max = i; 393 else if (val > item) 394 low = i + 1; 395 else 396 return &(vse->_vs_p[i]); 397 } 398 return NULL; 399 } 400 401 /* Initializes an extended value string. Behaves like a match function to 402 * permit lazy initialization of extended value strings. 403 * - Goes through the value_string array to determine the fastest possible 404 * access method. 405 * - Verifies that the value_string contains no NULL string pointers. 406 * - Verifies that the value_string is terminated by {0, NULL} 407 */ 408 const value_string * 409 _try_val_to_str_ext_init(const guint32 val, value_string_ext *vse) 410 { 411 const value_string *vs_p = vse->_vs_p; 412 const guint vs_num_entries = vse->_vs_num_entries; 413 414 /* The matching algorithm used: 415 * VS_SEARCH - slow sequential search (as in a normal value string) 416 * VS_BIN_TREE - log(n)-time binary search, the values must be sorted 417 * VS_INDEX - constant-time index lookup, the values must be contiguous 418 */ 419 enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX; 420 421 /* Note: The value_string 'value' is *unsigned*, but we do a little magic 422 * to help with value strings that have negative values. 423 * 424 * { -3, -2, -1, 0, 1, 2 } 425 * will be treated as "ascending ordered" (although it isn't technically), 426 * thus allowing constant-time index search 427 * 428 * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } 429 * will both be considered as "out-of-order with gaps", thus falling 430 * back to the slow linear search 431 * 432 * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } 433 * will be considered "ascending ordered with gaps" thus allowing 434 * a log(n)-time 'binary' search 435 * 436 * If you're confused, think of how negative values are represented, or 437 * google two's complement. 438 */ 439 440 guint32 prev_value; 441 guint32 first_value; 442 guint i; 443 444 DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) && 445 (vs_p[vs_num_entries].strptr == NULL)); 446 447 vse->_vs_first_value = vs_p[0].value; 448 first_value = vs_p[0].value; 449 prev_value = first_value; 450 451 for (i = 0; i < vs_num_entries; i++) { 452 DISSECTOR_ASSERT(vs_p[i].strptr != NULL); 453 if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { 454 type = VS_BIN_TREE; 455 } 456 /* XXX: Should check for dups ?? */ 457 if (type == VS_BIN_TREE) { 458 if (prev_value > vs_p[i].value) { 459 ws_warning("Extended value string '%s' forced to fall back to linear search:\n" 460 " entry %u, value %u [%#x] < previous entry, value %u [%#x]", 461 vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value); 462 type = VS_SEARCH; 463 break; 464 } 465 if (first_value > vs_p[i].value) { 466 ws_warning("Extended value string '%s' forced to fall back to linear search:\n" 467 " entry %u, value %u [%#x] < first entry, value %u [%#x]", 468 vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value); 469 type = VS_SEARCH; 470 break; 471 } 472 } 473 474 prev_value = vs_p[i].value; 475 } 476 477 switch (type) { 478 case VS_SEARCH: 479 vse->_vs_match2 = _try_val_to_str_linear; 480 break; 481 case VS_BIN_TREE: 482 vse->_vs_match2 = _try_val_to_str_bsearch; 483 break; 484 case VS_INDEX: 485 vse->_vs_match2 = _try_val_to_str_index; 486 break; 487 default: 488 ws_assert_not_reached(); 489 break; 490 } 491 492 return vse->_vs_match2(val, vse); 493 } 494 495 /* EXTENDED 64-BIT VALUE STRING */ 496 497 /* Extended value strings allow fast(er) val64_string array lookups by 498 * using (if possible) direct access or a binary search of the array. 499 * 500 * If the values in the val64_string array are a contiguous range of values 501 * from min to max, the value will be used as as a direct index into the array. 502 * 503 * If the values in the array are not contiguous (ie: there are "gaps"), 504 * but are in assending order a binary search will be used. 505 * 506 * If direct access or binary search cannot be used, then a linear search 507 * is used and a warning is emitted. 508 * 509 * Note that the val64_string array used with VAL64_STRING_EXT_INIT 510 * *must* be terminated with {0, NULL}). 511 * 512 * Extended value strings are defined at compile time as follows: 513 * static const val64_string vs[] = { {value1, "string1"}, 514 * {value2, "string2"}, 515 * ..., 516 * {0, NULL}}; 517 * static val64_string_ext vse = VAL64_STRING_EXT_INIT(vs); 518 * 519 * Extended value strings can be created at runtime by calling 520 * val64_string_ext_new(<ptr to val64_string array>, 521 * <total number of entries in the val64_string_array>, 522 * <val64_string_name>); 523 * Note: The <total number of entries in the val64_string_array> should include 524 * the {0, NULL} entry. 525 */ 526 527 /* Create a val64_string_ext given a ptr to a val64_string array and the total 528 * number of entries. Note that the total number of entries should include the 529 * required {0, NULL} terminating entry of the array. 530 * Returns a pointer to an epan-scoped'd and initialized val64_string_ext 531 * struct. */ 532 val64_string_ext * 533 val64_string_ext_new(const val64_string *vs, guint vs_tot_num_entries, 534 const gchar *vs_name) 535 { 536 val64_string_ext *vse; 537 538 DISSECTOR_ASSERT (vs_name != NULL); 539 DISSECTOR_ASSERT (vs_tot_num_entries > 0); 540 /* Null-terminated value-string ? */ 541 DISSECTOR_ASSERT (vs[vs_tot_num_entries-1].strptr == NULL); 542 543 vse = wmem_new(wmem_epan_scope(), val64_string_ext); 544 vse->_vs_p = vs; 545 vse->_vs_num_entries = vs_tot_num_entries - 1; 546 /* We set our 'match' function to the init function, which finishes by 547 * setting the match function properly and then calling it. This is a 548 * simple way to do lazy initialization of extended value strings. 549 * The init function also sets up _vs_first_value for us. */ 550 vse->_vs_first_value = 0; 551 vse->_vs_match2 = _try_val64_to_str_ext_init; 552 vse->_vs_name = vs_name; 553 554 return vse; 555 } 556 557 void 558 val64_string_ext_free(val64_string_ext *vse) 559 { 560 wmem_free(wmem_epan_scope(), vse); 561 } 562 563 /* Like try_val_to_str for extended value strings */ 564 const gchar * 565 try_val64_to_str_ext(const guint64 val, val64_string_ext *vse) 566 { 567 if (vse) { 568 const val64_string *vs = vse->_vs_match2(val, vse); 569 570 if (vs) { 571 return vs->strptr; 572 } 573 } 574 575 return NULL; 576 } 577 578 /* Like try_val_to_str_idx for extended value strings */ 579 const gchar * 580 try_val64_to_str_idx_ext(const guint64 val, val64_string_ext *vse, gint *idx) 581 { 582 if (vse) { 583 const val64_string *vs = vse->_vs_match2(val, vse); 584 if (vs) { 585 *idx = (gint) (vs - vse->_vs_p); 586 return vs->strptr; 587 } 588 } 589 *idx = -1; 590 return NULL; 591 } 592 593 /* Like val_to_str for extended value strings */ 594 const gchar * 595 val64_to_str_ext(const guint64 val, val64_string_ext *vse, const char *fmt) 596 { 597 const gchar *ret; 598 599 DISSECTOR_ASSERT(fmt != NULL); 600 601 ret = try_val64_to_str_ext(val, vse); 602 if (ret != NULL) 603 return ret; 604 605 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 606 } 607 608 gchar * 609 val64_to_str_ext_wmem(wmem_allocator_t *scope, const guint64 val, val64_string_ext *vse, const char *fmt) 610 { 611 const gchar *ret; 612 613 DISSECTOR_ASSERT(fmt != NULL); 614 615 ret = try_val64_to_str_ext(val, vse); 616 if (ret != NULL) 617 return wmem_strdup(scope, ret); 618 619 return wmem_strdup_printf(scope, fmt, val); 620 } 621 622 /* Like val_to_str_const for extended value strings */ 623 const gchar * 624 val64_to_str_ext_const(const guint64 val, val64_string_ext *vse, 625 const char *unknown_str) 626 { 627 const gchar *ret; 628 629 DISSECTOR_ASSERT(unknown_str != NULL); 630 631 ret = try_val64_to_str_ext(val, vse); 632 if (ret != NULL) 633 return ret; 634 635 return unknown_str; 636 } 637 638 /* Fallback linear matching algorithm for extended value strings */ 639 static const val64_string * 640 _try_val64_to_str_linear(const guint64 val, val64_string_ext *vse) 641 { 642 const val64_string *vs_p = vse->_vs_p; 643 guint i; 644 for (i=0; i<vse->_vs_num_entries; i++) { 645 if (vs_p[i].value == val) 646 return &(vs_p[i]); 647 } 648 return NULL; 649 } 650 651 /* Constant-time matching algorithm for contiguous extended value strings */ 652 static const val64_string * 653 _try_val64_to_str_index(const guint64 val, val64_string_ext *vse) 654 { 655 guint64 i; 656 657 i = val - vse->_vs_first_value; 658 if (i < vse->_vs_num_entries) { 659 ws_assert (val == vse->_vs_p[i].value); 660 return &(vse->_vs_p[i]); 661 } 662 return NULL; 663 } 664 665 /* log(n)-time matching algorithm for sorted extended value strings */ 666 static const val64_string * 667 _try_val64_to_str_bsearch(const guint64 val, val64_string_ext *vse) 668 { 669 guint low, i, max; 670 guint64 item; 671 672 for (low = 0, max = vse->_vs_num_entries; low < max; ) { 673 i = (low + max) / 2; 674 item = vse->_vs_p[i].value; 675 676 if (val < item) 677 max = i; 678 else if (val > item) 679 low = i + 1; 680 else 681 return &(vse->_vs_p[i]); 682 } 683 return NULL; 684 } 685 686 /* Initializes an extended value string. Behaves like a match function to 687 * permit lazy initialization of extended value strings. 688 * - Goes through the val64_string array to determine the fastest possible 689 * access method. 690 * - Verifies that the val64_string contains no NULL string pointers. 691 * - Verifies that the val64_string is terminated by {0, NULL} 692 */ 693 const val64_string * 694 _try_val64_to_str_ext_init(const guint64 val, val64_string_ext *vse) 695 { 696 const val64_string *vs_p = vse->_vs_p; 697 const guint vs_num_entries = vse->_vs_num_entries; 698 699 /* The matching algorithm used: 700 * VS_SEARCH - slow sequential search (as in a normal value string) 701 * VS_BIN_TREE - log(n)-time binary search, the values must be sorted 702 * VS_INDEX - constant-time index lookup, the values must be contiguous 703 */ 704 enum { VS_SEARCH, VS_BIN_TREE, VS_INDEX } type = VS_INDEX; 705 706 /* Note: The val64_string 'value' is *unsigned*, but we do a little magic 707 * to help with value strings that have negative values. 708 * 709 * { -3, -2, -1, 0, 1, 2 } 710 * will be treated as "ascending ordered" (although it isn't technically), 711 * thus allowing constant-time index search 712 * 713 * { -3, -2, 0, 1, 2 } and { -3, -2, -1, 0, 2 } 714 * will both be considered as "out-of-order with gaps", thus falling 715 * back to the slow linear search 716 * 717 * { 0, 1, 2, -3, -2 } and { 0, 2, -3, -2, -1 } 718 * will be considered "ascending ordered with gaps" thus allowing 719 * a log(n)-time 'binary' search 720 * 721 * If you're confused, think of how negative values are represented, or 722 * google two's complement. 723 */ 724 725 guint64 prev_value; 726 guint64 first_value; 727 guint i; 728 729 DISSECTOR_ASSERT((vs_p[vs_num_entries].value == 0) && 730 (vs_p[vs_num_entries].strptr == NULL)); 731 732 vse->_vs_first_value = vs_p[0].value; 733 first_value = vs_p[0].value; 734 prev_value = first_value; 735 736 for (i = 0; i < vs_num_entries; i++) { 737 DISSECTOR_ASSERT(vs_p[i].strptr != NULL); 738 if ((type == VS_INDEX) && (vs_p[i].value != (i + first_value))) { 739 type = VS_BIN_TREE; 740 } 741 /* XXX: Should check for dups ?? */ 742 if (type == VS_BIN_TREE) { 743 if (prev_value > vs_p[i].value) { 744 ws_warning("Extended value string '%s' forced to fall back to linear search:\n" 745 " entry %u, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x] < previous entry, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x]", 746 vse->_vs_name, i, vs_p[i].value, vs_p[i].value, prev_value, prev_value); 747 type = VS_SEARCH; 748 break; 749 } 750 if (first_value > vs_p[i].value) { 751 ws_warning("Extended value string '%s' forced to fall back to linear search:\n" 752 " entry %u, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x] < first entry, value %" G_GINT64_MODIFIER "u [%#" G_GINT64_MODIFIER "x]", 753 vse->_vs_name, i, vs_p[i].value, vs_p[i].value, first_value, first_value); 754 type = VS_SEARCH; 755 break; 756 } 757 } 758 759 prev_value = vs_p[i].value; 760 } 761 762 switch (type) { 763 case VS_SEARCH: 764 vse->_vs_match2 = _try_val64_to_str_linear; 765 break; 766 case VS_BIN_TREE: 767 vse->_vs_match2 = _try_val64_to_str_bsearch; 768 break; 769 case VS_INDEX: 770 vse->_vs_match2 = _try_val64_to_str_index; 771 break; 772 default: 773 ws_assert_not_reached(); 774 break; 775 } 776 777 return vse->_vs_match2(val, vse); 778 } 779 780 /* STRING TO STRING MATCHING */ 781 782 /* string_string is like value_string except the values being matched are 783 * also strings (instead of unsigned integers) */ 784 785 /* Like val_to_str except for string_string */ 786 const gchar * 787 str_to_str(const gchar *val, const string_string *vs, const char *fmt) 788 { 789 const gchar *ret; 790 791 DISSECTOR_ASSERT(fmt != NULL); 792 793 ret = try_str_to_str(val, vs); 794 if (ret != NULL) 795 return ret; 796 797 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 798 } 799 800 /* Like try_val_to_str_idx except for string_string */ 801 const gchar * 802 try_str_to_str_idx(const gchar *val, const string_string *vs, gint *idx) 803 { 804 gint i = 0; 805 806 if(vs) { 807 while (vs[i].strptr) { 808 if (!strcmp(vs[i].value,val)) { 809 *idx = i; 810 return(vs[i].strptr); 811 } 812 i++; 813 } 814 } 815 816 *idx = -1; 817 return NULL; 818 } 819 820 /* Like try_val_to_str except for string_string */ 821 const gchar * 822 try_str_to_str(const gchar *val, const string_string *vs) 823 { 824 gint ignore_me; 825 return try_str_to_str_idx(val, vs, &ignore_me); 826 } 827 828 /* RANGE TO STRING MATCHING */ 829 830 /* range_string is like value_string except the values being matched are 831 * integer ranges (for example, 0-10, 11-19, etc.) instead of single values. */ 832 833 /* Like val_to_str except for range_string */ 834 const gchar * 835 rval_to_str(const guint32 val, const range_string *rs, const char *fmt) 836 { 837 const gchar *ret = NULL; 838 839 DISSECTOR_ASSERT(fmt != NULL); 840 841 ret = try_rval_to_str(val, rs); 842 if(ret != NULL) 843 return ret; 844 845 return wmem_strdup_printf(wmem_packet_scope(), fmt, val); 846 } 847 848 /* Like val_to_str_const except for range_string */ 849 const gchar * 850 rval_to_str_const(const guint32 val, const range_string *rs, 851 const char *unknown_str) 852 { 853 const gchar *ret = NULL; 854 855 DISSECTOR_ASSERT(unknown_str != NULL); 856 857 ret = try_rval_to_str(val, rs); 858 if(ret != NULL) 859 return ret; 860 861 return unknown_str; 862 } 863 864 /* Like try_val_to_str_idx except for range_string */ 865 const gchar * 866 try_rval_to_str_idx(const guint32 val, const range_string *rs, gint *idx) 867 { 868 gint i = 0; 869 870 if(rs) { 871 while(rs[i].strptr) { 872 if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) { 873 *idx = i; 874 return (rs[i].strptr); 875 } 876 i++; 877 } 878 } 879 880 *idx = -1; 881 return NULL; 882 } 883 884 /* Like try_val_to_str except for range_string */ 885 const gchar * 886 try_rval_to_str(const guint32 val, const range_string *rs) 887 { 888 gint ignore_me = 0; 889 return try_rval_to_str_idx(val, rs, &ignore_me); 890 } 891 892 /* Like try_val_to_str_idx except for range_string */ 893 const gchar * 894 try_rval64_to_str_idx(const guint64 val, const range_string *rs, gint *idx) 895 { 896 gint i = 0; 897 898 if(rs) { 899 while(rs[i].strptr) { 900 if( (val >= rs[i].value_min) && (val <= rs[i].value_max) ) { 901 *idx = i; 902 return (rs[i].strptr); 903 } 904 i++; 905 } 906 } 907 908 *idx = -1; 909 return NULL; 910 } 911 912 /* Like try_val64_to_str except for range_string */ 913 const gchar * 914 try_rval64_to_str(const guint64 val, const range_string *rs) 915 { 916 gint ignore_me = 0; 917 return try_rval64_to_str_idx(val, rs, &ignore_me); 918 } 919 920 921 /* BYTE BUFFER TO STRING MATCHING */ 922 923 /* Like val_to_str except for bytes_string */ 924 const gchar * 925 bytesval_to_str(const guint8 *val, const size_t val_len, const bytes_string *bs, const char *fmt) 926 { 927 const gchar *ret; 928 929 DISSECTOR_ASSERT(fmt != NULL); 930 931 ret = try_bytesval_to_str(val, val_len, bs); 932 if (ret != NULL) 933 return ret; 934 935 /* 936 * XXX should this use bytes_to_str as format parameter for consistency? 937 * Though for bytes I guess most of the time you want to show "Unknown" 938 * anyway rather than "Unknown (\x13\x37...)" 939 */ 940 return wmem_strdup(wmem_packet_scope(), fmt); 941 } 942 943 /* Like try_val_to_str except for bytes_string */ 944 const gchar * 945 try_bytesval_to_str(const guint8 *val, const size_t val_len, const bytes_string *bs) 946 { 947 guint i = 0; 948 949 if (bs) { 950 while (bs[i].strptr) { 951 if (bs[i].value_length == val_len && !memcmp(bs[i].value, val, val_len)) { 952 return bs[i].strptr; 953 } 954 i++; 955 } 956 } 957 958 return NULL; 959 } 960 961 /* Like val_to_str, but tries to find a prefix (instead of an exact) match 962 of any prefix from the bytes_string array bs against the haystack. */ 963 const gchar * 964 bytesprefix_to_str(const guint8 *haystack, const size_t haystack_len, const bytes_string *bs, const char *fmt) 965 { 966 const gchar *ret; 967 968 DISSECTOR_ASSERT(fmt != NULL); 969 970 ret = try_bytesprefix_to_str(haystack, haystack_len, bs); 971 if (ret != NULL) 972 return ret; 973 974 /* XXX See note at bytesval_to_str. */ 975 return wmem_strdup(wmem_packet_scope(), fmt); 976 } 977 978 /* Like try_val_to_str, but tries to find a prefix (instead of an exact) match 979 of any prefix from the bytes_string array bs against the haystack. */ 980 const gchar * 981 try_bytesprefix_to_str(const guint8 *haystack, const size_t haystack_len, const bytes_string *bs) 982 { 983 guint i = 0; 984 985 if (bs) { 986 while (bs[i].strptr) { 987 if (haystack_len >= bs[i].value_length && 988 !memcmp(bs[i].value, haystack, bs[i].value_length)) { 989 return bs[i].strptr; 990 } 991 i++; 992 } 993 } 994 995 return NULL; 996 } 997 998 /* MISC */ 999 1000 /* Functions for use by proto_registrar_dump_values(), see proto.c */ 1001 1002 gboolean 1003 value_string_ext_validate(const value_string_ext *vse) 1004 { 1005 if (vse == NULL) 1006 return FALSE; 1007 #ifndef _WIN32 /* doesn't work on Windows for refs from another DLL ?? */ 1008 if ((vse->_vs_match2 != _try_val_to_str_ext_init) && 1009 (vse->_vs_match2 != _try_val_to_str_linear) && 1010 (vse->_vs_match2 != _try_val_to_str_bsearch) && 1011 (vse->_vs_match2 != _try_val_to_str_index)) 1012 return FALSE; 1013 #endif 1014 return TRUE; 1015 } 1016 1017 const gchar * 1018 value_string_ext_match_type_str(const value_string_ext *vse) 1019 { 1020 if (vse->_vs_match2 == _try_val_to_str_ext_init) 1021 return "[Not Initialized]"; 1022 if (vse->_vs_match2 == _try_val_to_str_linear) 1023 return "[Linear Search]"; 1024 if (vse->_vs_match2 == _try_val_to_str_bsearch) 1025 return "[Binary Search]"; 1026 if (vse->_vs_match2 == _try_val_to_str_index) 1027 return "[Direct (indexed) Access]"; 1028 return "[Invalid]"; 1029 } 1030 1031 gboolean 1032 val64_string_ext_validate(const val64_string_ext *vse) 1033 { 1034 if (vse == NULL) 1035 return FALSE; 1036 #ifndef _WIN32 /* doesn't work on Windows for refs from another DLL ?? */ 1037 if ((vse->_vs_match2 != _try_val64_to_str_ext_init) && 1038 (vse->_vs_match2 != _try_val64_to_str_linear) && 1039 (vse->_vs_match2 != _try_val64_to_str_bsearch) && 1040 (vse->_vs_match2 != _try_val64_to_str_index)) 1041 return FALSE; 1042 #endif 1043 return TRUE; 1044 } 1045 1046 const gchar * 1047 val64_string_ext_match_type_str(const val64_string_ext *vse) 1048 { 1049 if (vse->_vs_match2 == _try_val64_to_str_ext_init) 1050 return "[Not Initialized]"; 1051 if (vse->_vs_match2 == _try_val64_to_str_linear) 1052 return "[Linear Search]"; 1053 if (vse->_vs_match2 == _try_val64_to_str_bsearch) 1054 return "[Binary Search]"; 1055 if (vse->_vs_match2 == _try_val64_to_str_index) 1056 return "[Direct (indexed) Access]"; 1057 return "[Invalid]"; 1058 } 1059 1060 /* 1061 * Editor modelines - https://www.wireshark.org/tools/modelines.html 1062 * 1063 * Local variables: 1064 * c-basic-offset: 4 1065 * tab-width: 8 1066 * indent-tabs-mode: nil 1067 * End: 1068 * 1069 * vi: set shiftwidth=4 tabstop=8 expandtab: 1070 * :indentSize=4:tabSize=8:noTabs=true: 1071 */ 1072