1 /* 2 * Wireshark - Network traffic analyzer 3 * By Gerald Combs <gerald@wireshark.org> 4 * Copyright 2001 Gerald Combs 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "config.h" 10 11 #include <ftypes-int.h> 12 #include <glib.h> 13 14 #include "ftypes.h" 15 #include <wsutil/ws_assert.h> 16 17 /* Keep track of ftype_t's via their ftenum number */ 18 static ftype_t* type_list[FT_NUM_TYPES]; 19 20 /* Initialize the ftype module. */ 21 void 22 ftypes_initialize(void) 23 { 24 ftype_register_bytes(); 25 ftype_register_double(); 26 ftype_register_ieee_11073_float(); 27 ftype_register_integers(); 28 ftype_register_ipv4(); 29 ftype_register_ipv6(); 30 ftype_register_guid(); 31 ftype_register_none(); 32 ftype_register_string(); 33 ftype_register_time(); 34 ftype_register_tvbuff(); 35 } 36 37 /* Each ftype_t is registered via this function */ 38 void 39 ftype_register(enum ftenum ftype, ftype_t *ft) 40 { 41 /* Check input */ 42 ws_assert(ftype < FT_NUM_TYPES); 43 ws_assert(ftype == ft->ftype); 44 45 /* Don't re-register. */ 46 ws_assert(type_list[ftype] == NULL); 47 48 type_list[ftype] = ft; 49 } 50 51 /* Given an ftenum number, return an ftype_t* */ 52 #define FTYPE_LOOKUP(ftype, result) \ 53 /* Check input */ \ 54 ws_assert(ftype < FT_NUM_TYPES); \ 55 result = type_list[ftype]; 56 57 58 59 /* from README.dissector: 60 Note that the formats used must all belong to the same list as defined below: 61 - FT_INT8, FT_INT16, FT_INT24 and FT_INT32 62 - FT_UINT8, FT_UINT16, FT_UINT24, FT_UINT32, FT_IPXNET and FT_FRAMENUM 63 - FT_UINT64 and FT_EUI64 64 - FT_STRING, FT_STRINGZ and FT_UINT_STRING 65 - FT_FLOAT and FT_DOUBLE 66 - FT_BYTES, FT_UINT_BYTES, FT_AX25, FT_ETHER, FT_VINES, FT_OID and FT_REL_OID 67 - FT_ABSOLUTE_TIME and FT_RELATIVE_TIME 68 */ 69 static enum ftenum 70 same_ftype(const enum ftenum ftype) 71 { 72 switch (ftype) { 73 case FT_INT8: 74 case FT_INT16: 75 case FT_INT24: 76 case FT_INT32: 77 return FT_INT32; 78 79 case FT_UINT8: 80 case FT_UINT16: 81 case FT_UINT24: 82 case FT_UINT32: 83 return FT_UINT32; 84 85 case FT_INT40: 86 case FT_INT48: 87 case FT_INT56: 88 case FT_INT64: 89 return FT_INT64; 90 91 case FT_UINT40: 92 case FT_UINT48: 93 case FT_UINT56: 94 case FT_UINT64: 95 return FT_UINT64; 96 97 case FT_STRING: 98 case FT_STRINGZ: 99 case FT_UINT_STRING: 100 return FT_STRING; 101 102 case FT_FLOAT: 103 case FT_DOUBLE: 104 return FT_DOUBLE; 105 106 case FT_BYTES: 107 case FT_UINT_BYTES: 108 return FT_BYTES; 109 110 case FT_OID: 111 case FT_REL_OID: 112 return FT_OID; 113 114 /* XXX: the folowing are unique for now */ 115 case FT_IPv4: 116 case FT_IPv6: 117 118 /* everything else is unique */ 119 default: 120 return ftype; 121 } 122 } 123 124 /* given two types, are they similar - for example can two 125 * duplicate fields be registered of these two types. */ 126 gboolean 127 ftype_similar_types(const enum ftenum ftype_a, const enum ftenum ftype_b) 128 { 129 return (same_ftype(ftype_a) == same_ftype(ftype_b)); 130 } 131 132 /* Returns a string representing the name of the type. Useful 133 * for glossary production. */ 134 const char* 135 ftype_name(enum ftenum ftype) 136 { 137 ftype_t *ft; 138 139 FTYPE_LOOKUP(ftype, ft); 140 return ft->name; 141 } 142 143 const char* 144 ftype_pretty_name(enum ftenum ftype) 145 { 146 ftype_t *ft; 147 148 FTYPE_LOOKUP(ftype, ft); 149 return ft->pretty_name; 150 } 151 152 int 153 ftype_length(enum ftenum ftype) 154 { 155 ftype_t *ft; 156 157 FTYPE_LOOKUP(ftype, ft); 158 return ft->wire_size; 159 } 160 161 gboolean 162 ftype_can_slice(enum ftenum ftype) 163 { 164 ftype_t *ft; 165 166 FTYPE_LOOKUP(ftype, ft); 167 return ft->slice ? TRUE : FALSE; 168 } 169 170 gboolean 171 ftype_can_eq(enum ftenum ftype) 172 { 173 ftype_t *ft; 174 175 FTYPE_LOOKUP(ftype, ft); 176 return ft->cmp_eq ? TRUE : FALSE; 177 } 178 179 gboolean 180 ftype_can_ne(enum ftenum ftype) 181 { 182 ftype_t *ft; 183 184 FTYPE_LOOKUP(ftype, ft); 185 return ft->cmp_ne ? TRUE : FALSE; 186 } 187 188 gboolean 189 ftype_can_gt(enum ftenum ftype) 190 { 191 ftype_t *ft; 192 193 FTYPE_LOOKUP(ftype, ft); 194 return ft->cmp_gt ? TRUE : FALSE; 195 } 196 197 gboolean 198 ftype_can_ge(enum ftenum ftype) 199 { 200 ftype_t *ft; 201 202 FTYPE_LOOKUP(ftype, ft); 203 return ft->cmp_ge ? TRUE : FALSE; 204 } 205 206 gboolean 207 ftype_can_lt(enum ftenum ftype) 208 { 209 ftype_t *ft; 210 211 FTYPE_LOOKUP(ftype, ft); 212 return ft->cmp_lt ? TRUE : FALSE; 213 } 214 215 gboolean 216 ftype_can_le(enum ftenum ftype) 217 { 218 ftype_t *ft; 219 220 FTYPE_LOOKUP(ftype, ft); 221 return ft->cmp_le ? TRUE : FALSE; 222 } 223 224 gboolean 225 ftype_can_bitwise_and(enum ftenum ftype) 226 { 227 ftype_t *ft; 228 229 FTYPE_LOOKUP(ftype, ft); 230 return ft->cmp_bitwise_and ? TRUE : FALSE; 231 } 232 233 gboolean 234 ftype_can_contains(enum ftenum ftype) 235 { 236 ftype_t *ft; 237 238 FTYPE_LOOKUP(ftype, ft); 239 return ft->cmp_contains ? TRUE : FALSE; 240 } 241 242 gboolean 243 ftype_can_matches(enum ftenum ftype) 244 { 245 ftype_t *ft; 246 247 FTYPE_LOOKUP(ftype, ft); 248 return ft->cmp_matches ? TRUE : FALSE; 249 } 250 251 /* ---------------------------------------------------------- */ 252 253 /* Allocate and initialize an fvalue_t, given an ftype */ 254 fvalue_t* 255 fvalue_new(ftenum_t ftype) 256 { 257 fvalue_t *fv; 258 ftype_t *ft; 259 FvalueNewFunc new_value; 260 261 fv = g_slice_new(fvalue_t); 262 263 FTYPE_LOOKUP(ftype, ft); 264 fv->ftype = ft; 265 266 new_value = ft->new_value; 267 if (new_value) { 268 new_value(fv); 269 } 270 271 return fv; 272 } 273 274 void 275 fvalue_init(fvalue_t *fv, ftenum_t ftype) 276 { 277 ftype_t *ft; 278 FvalueNewFunc new_value; 279 280 FTYPE_LOOKUP(ftype, ft); 281 fv->ftype = ft; 282 283 new_value = ft->new_value; 284 if (new_value) { 285 new_value(fv); 286 } 287 } 288 289 fvalue_t* 290 fvalue_from_unparsed(ftenum_t ftype, const char *s, gboolean allow_partial_value, gchar **err_msg) 291 { 292 fvalue_t *fv; 293 294 fv = fvalue_new(ftype); 295 if (fv->ftype->val_from_unparsed) { 296 if (fv->ftype->val_from_unparsed(fv, s, allow_partial_value, err_msg)) { 297 /* Success */ 298 if (err_msg != NULL) 299 *err_msg = NULL; 300 return fv; 301 } 302 } 303 else { 304 if (err_msg != NULL) { 305 *err_msg = g_strdup_printf("\"%s\" cannot be converted to %s.", 306 s, ftype_pretty_name(ftype)); 307 } 308 } 309 FVALUE_FREE(fv); 310 return NULL; 311 } 312 313 fvalue_t* 314 fvalue_from_string(ftenum_t ftype, const char *s, gchar **err_msg) 315 { 316 fvalue_t *fv; 317 318 fv = fvalue_new(ftype); 319 if (fv->ftype->val_from_string) { 320 if (fv->ftype->val_from_string(fv, s, err_msg)) { 321 /* Success */ 322 if (err_msg != NULL) 323 *err_msg = NULL; 324 return fv; 325 } 326 } 327 else { 328 if (err_msg != NULL) { 329 *err_msg = g_strdup_printf("\"%s\" cannot be converted to %s.", 330 s, ftype_pretty_name(ftype)); 331 } 332 } 333 FVALUE_FREE(fv); 334 return NULL; 335 } 336 337 ftenum_t 338 fvalue_type_ftenum(fvalue_t *fv) 339 { 340 return fv->ftype->ftype; 341 } 342 343 const char* 344 fvalue_type_name(fvalue_t *fv) 345 { 346 return fv->ftype->name; 347 } 348 349 350 guint 351 fvalue_length(fvalue_t *fv) 352 { 353 if (fv->ftype->len) 354 return fv->ftype->len(fv); 355 else 356 return fv->ftype->wire_size; 357 } 358 359 int 360 fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype, int field_display) 361 { 362 ws_assert(fv->ftype->len_string_repr); 363 return fv->ftype->len_string_repr(fv, rtype, field_display); 364 } 365 366 char * 367 fvalue_to_string_repr(wmem_allocator_t *scope, fvalue_t *fv, ftrepr_t rtype, int field_display) 368 { 369 char *buf; 370 int len; 371 if (fv->ftype->val_to_string_repr == NULL) { 372 /* no value-to-string-representation function, so the value cannot be represented */ 373 return NULL; 374 } 375 376 if ((len = fvalue_string_repr_len(fv, rtype, field_display)) >= 0) { 377 buf = (char *)wmem_alloc0(scope, len + 1); 378 } else { 379 /* the value cannot be represented in the given representation type (rtype) */ 380 return NULL; 381 } 382 383 fv->ftype->val_to_string_repr(fv, rtype, field_display, buf, (unsigned int)len+1); 384 return buf; 385 } 386 387 typedef struct { 388 fvalue_t *fv; 389 GByteArray *bytes; 390 gboolean slice_failure; 391 } slice_data_t; 392 393 static void 394 slice_func(gpointer data, gpointer user_data) 395 { 396 drange_node *drnode = (drange_node *)data; 397 slice_data_t *slice_data = (slice_data_t *)user_data; 398 gint start_offset; 399 gint length = 0; 400 gint end_offset = 0; 401 guint field_length; 402 fvalue_t *fv; 403 drange_node_end_t ending; 404 405 if (slice_data->slice_failure) { 406 return; 407 } 408 409 start_offset = drange_node_get_start_offset(drnode); 410 ending = drange_node_get_ending(drnode); 411 412 fv = slice_data->fv; 413 field_length = fvalue_length(fv); 414 415 /* Check for negative start */ 416 if (start_offset < 0) { 417 start_offset = field_length + start_offset; 418 if (start_offset < 0) { 419 slice_data->slice_failure = TRUE; 420 return; 421 } 422 } 423 424 /* Check the end type and set the length */ 425 426 if (ending == DRANGE_NODE_END_T_TO_THE_END) { 427 length = field_length - start_offset; 428 if (length <= 0) { 429 slice_data->slice_failure = TRUE; 430 return; 431 } 432 } 433 else if (ending == DRANGE_NODE_END_T_LENGTH) { 434 length = drange_node_get_length(drnode); 435 if (start_offset + length > (int) field_length) { 436 slice_data->slice_failure = TRUE; 437 return; 438 } 439 } 440 else if (ending == DRANGE_NODE_END_T_OFFSET) { 441 end_offset = drange_node_get_end_offset(drnode); 442 if (end_offset < 0) { 443 end_offset = field_length + end_offset; 444 if (end_offset < start_offset) { 445 slice_data->slice_failure = TRUE; 446 return; 447 } 448 } else if (end_offset >= (int) field_length) { 449 slice_data->slice_failure = TRUE; 450 return; 451 } 452 length = end_offset - start_offset + 1; 453 } 454 else { 455 ws_assert_not_reached(); 456 } 457 458 ws_assert(start_offset >=0 && length > 0); 459 fv->ftype->slice(fv, slice_data->bytes, start_offset, length); 460 } 461 462 463 /* Returns a new FT_BYTES fvalue_t* if possible, otherwise NULL */ 464 fvalue_t* 465 fvalue_slice(fvalue_t *fv, drange_t *d_range) 466 { 467 slice_data_t slice_data; 468 fvalue_t *new_fv; 469 470 slice_data.fv = fv; 471 slice_data.bytes = g_byte_array_new(); 472 slice_data.slice_failure = FALSE; 473 474 /* XXX - We could make some optimizations here based on 475 * drange_has_total_length() and 476 * drange_get_max_offset(). 477 */ 478 479 drange_foreach_drange_node(d_range, slice_func, &slice_data); 480 481 new_fv = fvalue_new(FT_BYTES); 482 fvalue_set_byte_array(new_fv, slice_data.bytes); 483 return new_fv; 484 } 485 486 487 void 488 fvalue_set_byte_array(fvalue_t *fv, GByteArray *value) 489 { 490 ws_assert(fv->ftype->ftype == FT_BYTES || 491 fv->ftype->ftype == FT_UINT_BYTES || 492 fv->ftype->ftype == FT_OID || 493 fv->ftype->ftype == FT_REL_OID || 494 fv->ftype->ftype == FT_SYSTEM_ID); 495 ws_assert(fv->ftype->set_value.set_value_byte_array); 496 fv->ftype->set_value.set_value_byte_array(fv, value); 497 } 498 499 void 500 fvalue_set_bytes(fvalue_t *fv, const guint8 *value) 501 { 502 ws_assert(fv->ftype->ftype == FT_AX25 || 503 fv->ftype->ftype == FT_VINES || 504 fv->ftype->ftype == FT_ETHER || 505 fv->ftype->ftype == FT_FCWWN || 506 fv->ftype->ftype == FT_IPv6); 507 ws_assert(fv->ftype->set_value.set_value_bytes); 508 fv->ftype->set_value.set_value_bytes(fv, value); 509 } 510 511 void 512 fvalue_set_guid(fvalue_t *fv, const e_guid_t *value) 513 { 514 ws_assert(fv->ftype->ftype == FT_GUID); 515 ws_assert(fv->ftype->set_value.set_value_guid); 516 fv->ftype->set_value.set_value_guid(fv, value); 517 } 518 519 void 520 fvalue_set_time(fvalue_t *fv, const nstime_t *value) 521 { 522 ws_assert(IS_FT_TIME(fv->ftype->ftype)); 523 ws_assert(fv->ftype->set_value.set_value_time); 524 fv->ftype->set_value.set_value_time(fv, value); 525 } 526 527 void 528 fvalue_set_string(fvalue_t *fv, const gchar *value) 529 { 530 ws_assert(IS_FT_STRING(fv->ftype->ftype) || 531 fv->ftype->ftype == FT_UINT_STRING); 532 ws_assert(fv->ftype->set_value.set_value_string); 533 fv->ftype->set_value.set_value_string(fv, value); 534 } 535 536 void 537 fvalue_set_protocol(fvalue_t *fv, tvbuff_t *value, const gchar *name) 538 { 539 ws_assert(fv->ftype->ftype == FT_PROTOCOL); 540 ws_assert(fv->ftype->set_value.set_value_protocol); 541 fv->ftype->set_value.set_value_protocol(fv, value, name); 542 } 543 544 void 545 fvalue_set_uinteger(fvalue_t *fv, guint32 value) 546 { 547 ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT || 548 fv->ftype->ftype == FT_IEEE_11073_FLOAT || 549 fv->ftype->ftype == FT_CHAR || 550 fv->ftype->ftype == FT_UINT8 || 551 fv->ftype->ftype == FT_UINT16 || 552 fv->ftype->ftype == FT_UINT24 || 553 fv->ftype->ftype == FT_UINT32 || 554 fv->ftype->ftype == FT_IPXNET || 555 fv->ftype->ftype == FT_FRAMENUM || 556 fv->ftype->ftype == FT_IPv4); 557 ws_assert(fv->ftype->set_value.set_value_uinteger); 558 fv->ftype->set_value.set_value_uinteger(fv, value); 559 } 560 561 void 562 fvalue_set_sinteger(fvalue_t *fv, gint32 value) 563 { 564 ws_assert(fv->ftype->ftype == FT_INT8 || 565 fv->ftype->ftype == FT_INT16 || 566 fv->ftype->ftype == FT_INT24 || 567 fv->ftype->ftype == FT_INT32); 568 ws_assert(fv->ftype->set_value.set_value_sinteger); 569 fv->ftype->set_value.set_value_sinteger(fv, value); 570 } 571 572 void 573 fvalue_set_uinteger64(fvalue_t *fv, guint64 value) 574 { 575 ws_assert(fv->ftype->ftype == FT_UINT40 || 576 fv->ftype->ftype == FT_UINT48 || 577 fv->ftype->ftype == FT_UINT56 || 578 fv->ftype->ftype == FT_UINT64 || 579 fv->ftype->ftype == FT_BOOLEAN || 580 fv->ftype->ftype == FT_EUI64); 581 ws_assert(fv->ftype->set_value.set_value_uinteger64); 582 fv->ftype->set_value.set_value_uinteger64(fv, value); 583 } 584 585 void 586 fvalue_set_sinteger64(fvalue_t *fv, gint64 value) 587 { 588 ws_assert(fv->ftype->ftype == FT_INT40 || 589 fv->ftype->ftype == FT_INT48 || 590 fv->ftype->ftype == FT_INT56 || 591 fv->ftype->ftype == FT_INT64); 592 ws_assert(fv->ftype->set_value.set_value_sinteger64); 593 fv->ftype->set_value.set_value_sinteger64(fv, value); 594 } 595 596 void 597 fvalue_set_floating(fvalue_t *fv, gdouble value) 598 { 599 ws_assert(fv->ftype->ftype == FT_FLOAT || 600 fv->ftype->ftype == FT_DOUBLE); 601 ws_assert(fv->ftype->set_value.set_value_floating); 602 fv->ftype->set_value.set_value_floating(fv, value); 603 } 604 605 606 gpointer 607 fvalue_get(fvalue_t *fv) 608 { 609 ws_assert(fv->ftype->ftype == FT_BYTES || 610 fv->ftype->ftype == FT_UINT_BYTES || 611 fv->ftype->ftype == FT_AX25 || 612 fv->ftype->ftype == FT_VINES || 613 fv->ftype->ftype == FT_ETHER || 614 fv->ftype->ftype == FT_OID || 615 fv->ftype->ftype == FT_REL_OID || 616 fv->ftype->ftype == FT_SYSTEM_ID || 617 fv->ftype->ftype == FT_FCWWN || 618 fv->ftype->ftype == FT_GUID || 619 fv->ftype->ftype == FT_IPv6 || 620 fv->ftype->ftype == FT_PROTOCOL || 621 IS_FT_STRING(fv->ftype->ftype) || 622 fv->ftype->ftype == FT_UINT_STRING || 623 IS_FT_TIME(fv->ftype->ftype)); 624 ws_assert(fv->ftype->get_value.get_value_ptr); 625 return fv->ftype->get_value.get_value_ptr(fv); 626 } 627 628 guint32 629 fvalue_get_uinteger(fvalue_t *fv) 630 { 631 ws_assert(fv->ftype->ftype == FT_IEEE_11073_SFLOAT || 632 fv->ftype->ftype == FT_IEEE_11073_FLOAT || 633 fv->ftype->ftype == FT_CHAR || 634 fv->ftype->ftype == FT_UINT8 || 635 fv->ftype->ftype == FT_UINT16 || 636 fv->ftype->ftype == FT_UINT24 || 637 fv->ftype->ftype == FT_UINT32 || 638 fv->ftype->ftype == FT_IPXNET || 639 fv->ftype->ftype == FT_FRAMENUM || 640 fv->ftype->ftype == FT_IPv4); 641 ws_assert(fv->ftype->get_value.get_value_uinteger); 642 return fv->ftype->get_value.get_value_uinteger(fv); 643 } 644 645 gint32 646 fvalue_get_sinteger(fvalue_t *fv) 647 { 648 ws_assert(fv->ftype->ftype == FT_INT8 || 649 fv->ftype->ftype == FT_INT16 || 650 fv->ftype->ftype == FT_INT24 || 651 fv->ftype->ftype == FT_INT32); 652 ws_assert(fv->ftype->get_value.get_value_sinteger); 653 return fv->ftype->get_value.get_value_sinteger(fv); 654 } 655 656 guint64 657 fvalue_get_uinteger64(fvalue_t *fv) 658 { 659 ws_assert(fv->ftype->ftype == FT_UINT40 || 660 fv->ftype->ftype == FT_UINT48 || 661 fv->ftype->ftype == FT_UINT56 || 662 fv->ftype->ftype == FT_UINT64 || 663 fv->ftype->ftype == FT_BOOLEAN || 664 fv->ftype->ftype == FT_EUI64); 665 ws_assert(fv->ftype->get_value.get_value_uinteger64); 666 return fv->ftype->get_value.get_value_uinteger64(fv); 667 } 668 669 gint64 670 fvalue_get_sinteger64(fvalue_t *fv) 671 { 672 ws_assert(fv->ftype->ftype == FT_INT40 || 673 fv->ftype->ftype == FT_INT48 || 674 fv->ftype->ftype == FT_INT56 || 675 fv->ftype->ftype == FT_INT64); 676 ws_assert(fv->ftype->get_value.get_value_sinteger64); 677 return fv->ftype->get_value.get_value_sinteger64(fv); 678 } 679 680 double 681 fvalue_get_floating(fvalue_t *fv) 682 { 683 ws_assert(fv->ftype->ftype == FT_FLOAT || 684 fv->ftype->ftype == FT_DOUBLE); 685 ws_assert(fv->ftype->get_value.get_value_floating); 686 return fv->ftype->get_value.get_value_floating(fv); 687 } 688 689 gboolean 690 fvalue_eq(const fvalue_t *a, const fvalue_t *b) 691 { 692 /* XXX - check compatibility of a and b */ 693 ws_assert(a->ftype->cmp_eq); 694 return a->ftype->cmp_eq(a, b); 695 } 696 697 gboolean 698 fvalue_ne(const fvalue_t *a, const fvalue_t *b) 699 { 700 /* XXX - check compatibility of a and b */ 701 ws_assert(a->ftype->cmp_ne); 702 return a->ftype->cmp_ne(a, b); 703 } 704 705 gboolean 706 fvalue_gt(const fvalue_t *a, const fvalue_t *b) 707 { 708 /* XXX - check compatibility of a and b */ 709 ws_assert(a->ftype->cmp_gt); 710 return a->ftype->cmp_gt(a, b); 711 } 712 713 gboolean 714 fvalue_ge(const fvalue_t *a, const fvalue_t *b) 715 { 716 /* XXX - check compatibility of a and b */ 717 ws_assert(a->ftype->cmp_ge); 718 return a->ftype->cmp_ge(a, b); 719 } 720 721 gboolean 722 fvalue_lt(const fvalue_t *a, const fvalue_t *b) 723 { 724 /* XXX - check compatibility of a and b */ 725 ws_assert(a->ftype->cmp_lt); 726 return a->ftype->cmp_lt(a, b); 727 } 728 729 gboolean 730 fvalue_le(const fvalue_t *a, const fvalue_t *b) 731 { 732 /* XXX - check compatibility of a and b */ 733 ws_assert(a->ftype->cmp_le); 734 return a->ftype->cmp_le(a, b); 735 } 736 737 gboolean 738 fvalue_bitwise_and(const fvalue_t *a, const fvalue_t *b) 739 { 740 /* XXX - check compatibility of a and b */ 741 ws_assert(a->ftype->cmp_bitwise_and); 742 return a->ftype->cmp_bitwise_and(a, b); 743 } 744 745 gboolean 746 fvalue_contains(const fvalue_t *a, const fvalue_t *b) 747 { 748 /* XXX - check compatibility of a and b */ 749 ws_assert(a->ftype->cmp_contains); 750 return a->ftype->cmp_contains(a, b); 751 } 752 753 gboolean 754 fvalue_matches(const fvalue_t *a, const GRegex *b) 755 { 756 /* XXX - check compatibility of a and b */ 757 ws_assert(a->ftype->cmp_matches); 758 return a->ftype->cmp_matches(a, b); 759 } 760 761 /* 762 * Editor modelines - https://www.wireshark.org/tools/modelines.html 763 * 764 * Local variables: 765 * c-basic-offset: 8 766 * tab-width: 8 767 * indent-tabs-mode: t 768 * End: 769 * 770 * vi: set shiftwidth=8 tabstop=8 noexpandtab: 771 * :indentSize=8:tabSize=8:noTabs=false: 772 */ 773