Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dfilter / dfilter.c
blob61f6aa4828bc563851a7062bd69c8e7b9ee6fa50
1 /*
2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
10 #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
12 #include <stdio.h>
13 #include <string.h>
15 #include "dfilter-int.h"
16 #include "syntax-tree.h"
17 #include "gencode.h"
18 #include "semcheck.h"
19 #include "dfvm.h"
20 #include <epan/epan_dissect.h>
21 #include <epan/exceptions.h>
22 #include "dfilter.h"
23 #include "dfunctions.h"
24 #include "dfilter-macro.h"
25 #include "dfilter-plugin.h"
26 #include "scanner_lex.h"
27 #include <wsutil/wslog.h>
28 #include <wsutil/ws_assert.h>
29 #include "grammar.h"
32 #define DFILTER_TOKEN_ID_OFFSET 1
34 /* Holds the singular instance of our Lemon parser object */
35 static void* ParserObj;
37 df_loc_t loc_empty = {-1, 0};
39 void
40 dfilter_vfail(void *state, int code, df_loc_t loc,
41 const char *format, va_list args)
43 df_error_t **ptr = &((dfstate_t *)state)->error;
44 /* If we've already reported one error, don't overwite it */
45 if (*ptr != NULL)
46 return;
48 *ptr = df_error_new_vprintf(code, &loc, format, args);
51 void
52 dfilter_fail(void *state, int code, df_loc_t loc,
53 const char *format, ...)
55 va_list args;
57 va_start(args, format);
58 dfilter_vfail(state, code, loc, format, args);
59 va_end(args);
62 void
63 dfilter_fail_throw(void *state, int code, df_loc_t loc, const char *format, ...)
65 va_list args;
67 va_start(args, format);
68 dfilter_vfail(state, code, loc, format, args);
69 va_end(args);
70 THROW(TypeError);
73 void
74 dfw_set_error_location(dfwork_t *dfw, df_loc_t loc)
76 ws_assert(dfw->error);
77 dfw->error->loc = loc;
80 header_field_info *
81 dfilter_resolve_unparsed(const char *name, GPtrArray *deprecated)
83 header_field_info *hfinfo;
85 hfinfo = proto_registrar_get_byname(name);
86 if (hfinfo != NULL) {
87 /* It's a field name */
88 return hfinfo;
91 hfinfo = proto_registrar_get_byalias(name);
92 if (hfinfo != NULL) {
93 /* It's an aliased field name */
94 if (deprecated)
95 add_deprecated_token(deprecated, name);
96 return hfinfo;
99 /* It's not a field. */
100 return NULL;
103 /* Initialize the dfilter module */
104 void
105 dfilter_init(void)
107 if (ParserObj) {
108 ws_message("I expected ParserObj to be NULL\n");
109 /* Free the Lemon Parser object */
110 DfilterFree(ParserObj, g_free);
112 /* Allocate an instance of our Lemon-based parser */
113 ParserObj = DfilterAlloc(g_malloc);
115 /* Initialize the syntax-tree sub-sub-system */
116 sttype_init();
118 df_func_init();
119 dfilter_macro_init();
120 dfilter_plugins_init();
123 /* Clean-up the dfilter module */
124 void
125 dfilter_cleanup(void)
127 dfilter_plugins_cleanup();
128 dfilter_macro_cleanup();
129 df_func_cleanup();
131 /* Free the Lemon Parser object */
132 if (ParserObj) {
133 DfilterFree(ParserObj, g_free);
136 /* Clean up the syntax-tree sub-sub-system */
137 sttype_cleanup();
140 static dfilter_t*
141 dfilter_new(GPtrArray *deprecated)
143 dfilter_t *df;
145 df = g_new0(dfilter_t, 1);
146 df->insns = NULL;
147 df->function_stack = NULL;
148 df->set_stack = NULL;
149 df->warnings = NULL;
150 if (deprecated)
151 df->deprecated = g_ptr_array_ref(deprecated);
152 return df;
155 /* Given a GPtrArray of instructions (dfvm_insn_t),
156 * free them. */
157 static void
158 free_insns(GPtrArray *insns)
160 unsigned int i;
161 dfvm_insn_t *insn;
163 for (i = 0; i < insns->len; i++) {
164 insn = (dfvm_insn_t *)g_ptr_array_index(insns, i);
165 dfvm_insn_free(insn);
167 g_ptr_array_free(insns, true);
170 void
171 dfilter_free(dfilter_t *df)
173 if (!df)
174 return;
176 if (df->insns) {
177 free_insns(df->insns);
180 g_free(df->interesting_fields);
182 g_hash_table_destroy(df->references);
183 g_hash_table_destroy(df->raw_references);
185 if (df->deprecated)
186 g_ptr_array_unref(df->deprecated);
188 if (df->function_stack != NULL) {
189 ws_critical("Function stack list should be NULL");
190 g_slist_free(df->function_stack);
193 if (df->set_stack != NULL) {
194 ws_critical("Set stack list should be NULL");
195 g_slist_free(df->set_stack);
198 if (df->warnings)
199 g_slist_free_full(df->warnings, g_free);
201 g_free(df->registers);
202 g_free(df->expanded_text);
203 g_free(df->syntax_tree_str);
204 g_free(df);
207 static void free_refs_array(void *data)
209 /* Array data must be freed. */
210 (void)g_ptr_array_free(data, true);
213 static dfsyntax_t*
214 dfsyntax_new(unsigned flags)
216 dfsyntax_t *dfs = g_new0(dfsyntax_t, 1);
217 dfs->deprecated = g_ptr_array_new_full(0, g_free);
218 dfs->flags = flags;
219 return dfs;
222 static void
223 dfsyntax_free(dfsyntax_t *dfs)
225 if (dfs->error)
226 df_error_free(&dfs->error);
228 if (dfs->st_root)
229 stnode_free(dfs->st_root);
231 if (dfs->deprecated)
232 g_ptr_array_unref(dfs->deprecated);
234 if (dfs->lval)
235 stnode_free(dfs->lval);
237 if (dfs->quoted_string)
238 g_string_free(dfs->quoted_string, TRUE);
242 g_free(dfs);
245 static dfwork_t*
246 dfwork_new(const char *expanded_text, unsigned flags)
248 dfwork_t *dfw = g_new0(dfwork_t, 1);
249 dfw->expanded_text = g_strdup(expanded_text);
250 dfw->flags = flags;
252 dfw->references =
253 g_hash_table_new_full(g_direct_hash, g_direct_equal,
254 NULL, (GDestroyNotify)free_refs_array);
256 dfw->raw_references =
257 g_hash_table_new_full(g_direct_hash, g_direct_equal,
258 NULL, (GDestroyNotify)free_refs_array);
260 dfw->dfw_scope = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE);
262 return dfw;
265 static void
266 dfwork_free(dfwork_t *dfw)
268 if (dfw->st_root) {
269 stnode_free(dfw->st_root);
272 if (dfw->loaded_fields) {
273 g_hash_table_destroy(dfw->loaded_fields);
276 if (dfw->loaded_raw_fields) {
277 g_hash_table_destroy(dfw->loaded_raw_fields);
280 if (dfw->interesting_fields) {
281 g_hash_table_destroy(dfw->interesting_fields);
284 if (dfw->references) {
285 g_hash_table_destroy(dfw->references);
288 if (dfw->raw_references) {
289 g_hash_table_destroy(dfw->raw_references);
292 if (dfw->insns) {
293 free_insns(dfw->insns);
296 if (dfw->deprecated)
297 g_ptr_array_unref(dfw->deprecated);
299 if (dfw->warnings)
300 g_slist_free_full(dfw->warnings, g_free);
302 g_free(dfw->expanded_text);
304 if (dfw->error)
305 df_error_free(&dfw->error);
307 wmem_destroy_allocator(dfw->dfw_scope);
310 * We don't free the error message string; our caller will return
311 * it to its caller.
313 g_free(dfw);
316 const char *tokenstr(int token)
318 switch (token) {
319 case TOKEN_TEST_AND: return "TEST_AND";
320 case TOKEN_TEST_OR: return "TEST_OR";
321 case TOKEN_TEST_XOR: return "TEST_XOR";
322 case TOKEN_TEST_ALL_EQ: return "TEST_ALL_EQ";
323 case TOKEN_TEST_ANY_EQ: return "TEST_ANY_EQ";
324 case TOKEN_TEST_ALL_NE: return "TEST_ALL_NE";
325 case TOKEN_TEST_ANY_NE: return "TEST_ANY_NE";
326 case TOKEN_TEST_LT: return "TEST_LT";
327 case TOKEN_TEST_LE: return "TEST_LE";
328 case TOKEN_TEST_GT: return "TEST_GT";
329 case TOKEN_TEST_GE: return "TEST_GE";
330 case TOKEN_TEST_CONTAINS: return "TEST_CONTAINS";
331 case TOKEN_TEST_MATCHES: return "TEST_MATCHES";
332 case TOKEN_BITWISE_AND: return "BITWISE_AND";
333 case TOKEN_PLUS: return "PLUS";
334 case TOKEN_MINUS: return "MINUS";
335 case TOKEN_STAR: return "STAR";
336 case TOKEN_RSLASH: return "RSLASH";
337 case TOKEN_PERCENT: return "PERCENT";
338 case TOKEN_TEST_NOT: return "TEST_NOT";
339 case TOKEN_STRING: return "STRING";
340 case TOKEN_CHARCONST: return "CHARCONST";
341 case TOKEN_IDENTIFIER: return "IDENTIFIER";
342 case TOKEN_UNPARSED: return "UNPARSED";
343 case TOKEN_LITERAL: return "LITERAL";
344 case TOKEN_NUMBER: return "NUMBER";
345 case TOKEN_FIELD: return "FIELD";
346 case TOKEN_LBRACKET: return "LBRACKET";
347 case TOKEN_RBRACKET: return "RBRACKET";
348 case TOKEN_COMMA: return "COMMA";
349 case TOKEN_RANGE_NODE: return "RANGE_NODE";
350 case TOKEN_TEST_IN: return "TEST_IN";
351 case TOKEN_LBRACE: return "LBRACE";
352 case TOKEN_RBRACE: return "RBRACE";
353 case TOKEN_DOTDOT: return "DOTDOT";
354 case TOKEN_LPAREN: return "LPAREN";
355 case TOKEN_RPAREN: return "RPAREN";
356 case TOKEN_DOLLAR: return "DOLLAR";
357 case TOKEN_ATSIGN: return "ATSIGN";
358 case TOKEN_HASH: return "HASH";
359 case TOKEN_INDEX: return "INDEX";
361 return "<unknown>";
364 void
365 add_deprecated_token(GPtrArray *deprecated, const char *token)
367 for (unsigned i = 0; i < deprecated->len; i++) {
368 const char *str = g_ptr_array_index(deprecated, i);
369 if (g_ascii_strcasecmp(token, str) == 0) {
370 /* It's already in our list */
371 return;
374 g_ptr_array_add(deprecated, g_strdup(token));
377 void
378 add_compile_warning(dfwork_t *dfw, const char *format, ...)
380 va_list ap;
381 va_start(ap, format);
382 char *msg = ws_strdup_vprintf(format, ap);
383 va_end(ap);
384 dfw->warnings = g_slist_prepend(dfw->warnings, msg);
387 char *
388 dfilter_expand(const char *expr, df_error_t **err_ret)
390 return dfilter_macro_apply(expr, err_ret);
393 static bool
394 dfwork_parse(const char *expanded_text, dfsyntax_t *dfs)
396 yyscan_t scanner;
397 YY_BUFFER_STATE in_buffer;
398 unsigned token_count = 0;
399 int token;
401 if (df_yylex_init(&scanner) != 0) {
402 dfs->error = df_error_new_printf(DF_ERROR_GENERIC, NULL, "Can't initialize scanner: %s", g_strerror(errno));
403 return false;
406 in_buffer = df_yy_scan_string(expanded_text, scanner);
407 df_yyset_extra(dfs, scanner);
409 #ifdef NDEBUG
410 if (dfs->flags & DF_DEBUG_FLEX || dfs->flags & DF_DEBUG_LEMON) {
411 ws_message("Compile Wireshark without NDEBUG to enable Flex and/or Lemon debug traces");
413 #else
414 /* Enable/disable debugging for Flex. */
415 df_yyset_debug(dfs->flags & DF_DEBUG_FLEX, scanner);
417 /* Enable/disable debugging for Lemon. */
418 DfilterTrace(dfs->flags & DF_DEBUG_LEMON ? stderr : NULL, "lemon> ");
419 #endif
421 while (1) {
422 token = df_yylex(scanner);
424 /* Check for scanner failure */
425 if (token == SCAN_FAILED) {
426 ws_noisy("Scanning failed");
427 ws_assert(dfs->error != NULL);
428 break;
431 /* Check for end-of-input */
432 if (token == 0) {
433 ws_noisy("Scanning finished");
434 break;
437 ws_noisy("(%u) Token %d %s %s",
438 ++token_count, token, tokenstr(token),
439 stnode_token(dfs->lval));
441 /* Give the token to the parser */
442 Dfilter(ParserObj, token, dfs->lval, dfs);
443 /* The parser has freed the lval for us. */
444 dfs->lval = NULL;
446 if (dfs->error) {
447 break;
450 } /* while (1) */
452 /* Tell the parser that we have reached the end of input; that
453 * way, it'll reset its state for the next compile. (We want
454 * to do that even if we got a syntax error, to make sure the
455 * parser state is cleaned up; we don't create a new parser
456 * object when we start a new parse, and don't destroy it when
457 * the parse finishes.) */
458 Dfilter(ParserObj, 0, NULL, dfs);
460 /* Free scanner state */
461 df_yy_delete_buffer(in_buffer, scanner);
462 df_yylex_destroy(scanner);
464 return dfs->error == NULL;
467 static dfilter_t *
468 dfwork_build(dfwork_t *dfw)
470 dfilter_t *dfilter;
471 char *tree_str;
473 log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree before semantic check", NULL);
475 /* Check semantics and do necessary type conversion*/
476 if (!dfw_semcheck(dfw))
477 return NULL;
479 /* Cache tree representation in tree_str. */
480 tree_str = NULL;
481 log_syntax_tree(LOG_LEVEL_NOISY, dfw->st_root, "Syntax tree after successful semantic check", &tree_str);
483 if ((dfw->flags & DF_SAVE_TREE) && tree_str == NULL) {
484 tree_str = dump_syntax_tree_str(dfw->st_root);
487 /* Create bytecode */
488 dfw_gencode(dfw);
490 /* Tuck away the bytecode in the dfilter_t */
491 dfilter = dfilter_new(dfw->deprecated);
492 dfilter->insns = dfw->insns;
493 dfw->insns = NULL;
494 dfilter->interesting_fields = dfw_interesting_fields(dfw,
495 &dfilter->num_interesting_fields);
496 dfilter->expanded_text = dfw->expanded_text;
497 dfw->expanded_text = NULL;
498 dfilter->references = dfw->references;
499 dfw->references = NULL;
500 dfilter->raw_references = dfw->raw_references;
501 dfw->raw_references = NULL;
502 dfilter->warnings = dfw->warnings;
503 dfw->warnings = NULL;
504 dfilter->ret_type = dfw->ret_type;
506 if (dfw->flags & DF_SAVE_TREE) {
507 ws_assert(tree_str);
508 dfilter->syntax_tree_str = tree_str;
509 tree_str = NULL;
511 else {
512 dfilter->syntax_tree_str = NULL;
513 g_free(tree_str);
514 tree_str = NULL;
517 /* Initialize run-time space */
518 dfilter->num_registers = dfw->next_register;
519 dfilter->registers = g_new0(df_cell_t, dfilter->num_registers);
521 return dfilter;
524 static dfilter_t *
525 compile_filter(const char *expanded_text, unsigned flags, df_error_t **err_ptr)
527 dfsyntax_t *dfs = NULL;
528 dfwork_t *dfw = NULL;
529 dfilter_t *dfcode = NULL;
530 df_error_t *error = NULL;
531 bool ok;
533 dfs = dfsyntax_new(flags);
535 ok = dfwork_parse(expanded_text, dfs);
536 if (!ok) {
537 error = dfs->error;
538 dfs->error = NULL;
539 goto FAILURE;
541 else if (dfs->st_root == NULL) {
542 /* Is it an empty filter? If so set the dfcode to NULL and return success.
543 * This can happen if the user clears the display filter toolbar in the UI.
544 * In that case the compilation succeeds and the NULL dfcode clears the filter
545 * (show all frames). */
546 dfsyntax_free(dfs);
547 *err_ptr = NULL;
548 return NULL;
551 dfw = dfwork_new(expanded_text, dfs->flags);
552 dfw->st_root = dfs->st_root;
553 dfs->st_root = NULL;
554 dfw->deprecated = g_ptr_array_ref(dfs->deprecated);
555 dfsyntax_free(dfs);
556 dfs = NULL;
558 dfcode = dfwork_build(dfw);
559 if (dfcode == NULL) {
560 error = dfw->error;
561 dfw->error = NULL;
562 goto FAILURE;
565 /* SUCCESS */
566 dfwork_free(dfw);
567 return dfcode;
569 FAILURE:
570 if (error == NULL || error->msg == NULL) {
571 /* We require an error message. */
572 ws_critical("Unknown error compiling filter: %s", expanded_text);
573 error = df_error_new_msg("Unknown error compiling filter");
576 ws_assert(err_ptr && error);
577 *err_ptr = error;
579 if (dfs)
580 dfsyntax_free(dfs);
581 if (dfw)
582 dfwork_free(dfw);
583 return NULL;
586 static inline bool
587 compile_failure(df_error_t *error, df_error_t **err_ptr)
589 ws_assert(error);
590 ws_debug("Error compiling filter: (%d) %s", error->code, error->msg);
592 if (err_ptr)
593 *err_ptr = error;
594 else
595 df_error_free(&error);
597 return false;
600 bool
601 dfilter_compile_full(const char *text, dfilter_t **dfp,
602 df_error_t **err_ptr, unsigned flags,
603 const char *caller)
605 char *expanded_text;
606 dfilter_t *dfcode;
607 df_error_t *error = NULL;
609 ws_assert(dfp);
610 *dfp = NULL;
611 if (caller == NULL)
612 caller = "(unknown)";
614 if (text == NULL) {
615 /* This is a bug. */
616 ws_warning("Called from %s() with invalid NULL expression", caller);
617 if (err_ptr) {
618 *err_ptr = df_error_new_msg("BUG: NULL text argument is invalid");
620 return false;
623 ws_debug("Called from %s() with filter: %s", caller, text);
625 if (flags & DF_EXPAND_MACROS) {
626 expanded_text = dfilter_macro_apply(text, &error);
627 if (expanded_text == NULL) {
628 return compile_failure(error, err_ptr);
630 ws_noisy("Expanded text: %s", expanded_text);
632 else {
633 expanded_text = g_strdup(text);
634 ws_noisy("Verbatim text: %s", expanded_text);
637 dfcode = compile_filter(expanded_text, flags, &error);
638 g_free(expanded_text);
639 expanded_text = NULL;
641 if(error != NULL) {
642 return compile_failure(error, err_ptr);
645 *dfp = dfcode;
646 ws_info("Compiled display filter: %s", text);
647 return true;
650 struct stnode *dfilter_get_syntax_tree(const char *text)
652 dfsyntax_t *dfs = NULL;
653 dfwork_t *dfw = NULL;
655 dfs = dfsyntax_new(DF_EXPAND_MACROS);
657 char *expanded_text = dfilter_macro_apply(text, NULL);
658 if (!expanded_text) {
659 dfsyntax_free(dfs);
660 return NULL;
663 bool ok = dfwork_parse(expanded_text, dfs);
664 if (!ok || !dfs->st_root) {
665 g_free(expanded_text);
666 dfsyntax_free(dfs);
667 return NULL;
670 dfw = dfwork_new(expanded_text, dfs->flags);
671 dfw->st_root = dfs->st_root;
672 dfs->st_root = NULL;
673 g_free(expanded_text);
674 dfsyntax_free(dfs);
676 if (!dfw_semcheck(dfw)) {
677 dfwork_free(dfw);
678 return NULL;
681 stnode_t *st_root = dfw->st_root;
682 dfw->st_root = NULL;
683 dfwork_free(dfw);
685 return st_root;
688 bool
689 dfilter_apply(dfilter_t *df, proto_tree *tree)
691 return dfvm_apply(df, tree);
694 bool
695 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
697 return dfvm_apply(df, edt->tree);
700 bool
701 dfilter_apply_full(dfilter_t *df, proto_tree *tree, GPtrArray **fvals)
703 return dfvm_apply_full(df, tree, fvals);
706 void
707 dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
709 int i;
711 for (i = 0; i < df->num_interesting_fields; i++) {
712 proto_tree_prime_with_hfid(tree, df->interesting_fields[i]);
716 void
717 dfilter_prime_proto_tree_print(const dfilter_t *df, proto_tree *tree)
719 for (int i = 0; i < df->num_interesting_fields; i++) {
720 proto_tree_prime_with_hfid_print(tree, df->interesting_fields[i]);
724 bool
725 dfilter_has_interesting_fields(const dfilter_t *df)
727 return (df->num_interesting_fields > 0);
730 bool
731 dfilter_interested_in_field(const dfilter_t *df, int hfid)
733 int i;
735 for (i = 0; i < df->num_interesting_fields; i++) {
736 if (df->interesting_fields[i] == hfid) {
737 return true;
740 return false;
743 bool
744 dfilter_interested_in_proto(const dfilter_t *df, int proto_id)
746 int i;
748 for (i = 0; i < df->num_interesting_fields; i++) {
749 int df_hfid = df->interesting_fields[i];
750 if (proto_registrar_is_protocol(df_hfid)) {
751 /* XXX: Should we go up to the parent of a pino?
752 * We can tell if df_hfid is a PINO, but there's
753 * no function to return the parent proto ID yet.
755 if (df_hfid == proto_id) {
756 return true;
758 } else {
759 if (proto_registrar_get_parent(df_hfid) == proto_id) {
760 return true;
764 return false;
767 bool
768 dfilter_requires_columns(const dfilter_t *df)
770 if (df == NULL) {
771 return false;
774 /* XXX: Could cache this like packet_cache_proto_handles */
775 static int proto_cols;
776 if (proto_cols <= 0) {
777 proto_cols = proto_get_id_by_filter_name("_ws.col");
779 ws_assert(proto_cols > 0);
781 return dfilter_interested_in_proto(df, proto_cols);
784 GPtrArray *
785 dfilter_deprecated_tokens(dfilter_t *df) {
786 if (df->deprecated && df->deprecated->len > 0) {
787 return df->deprecated;
789 return NULL;
792 GSList *
793 dfilter_get_warnings(dfilter_t *df)
795 return df->warnings;
798 void
799 dfilter_dump(FILE *fp, dfilter_t *df, uint16_t flags)
801 dfvm_dump(fp, df, flags);
804 const char *
805 dfilter_text(dfilter_t *df)
807 return df->expanded_text;
810 const char *
811 dfilter_syntax_tree(dfilter_t *df)
813 return df->syntax_tree_str;
816 ftenum_t
817 dfilter_get_return_type(dfilter_t *df)
819 return df->ret_type;
822 void
823 dfilter_log_full(const char *domain, enum ws_log_level level,
824 const char *file, long line, const char *func,
825 dfilter_t *df, const char *msg)
827 if (!ws_log_msg_is_active(domain, level))
828 return;
830 if (df == NULL) {
831 ws_log_write_always_full(domain, level, file, line, func,
832 "%s: NULL display filter", msg ? msg : "?");
833 return;
836 char *str = dfvm_dump_str(NULL, df, true);
837 if (G_UNLIKELY(msg == NULL))
838 ws_log_write_always_full(domain, level, file, line, func, "\nFilter:\n %s\n\n%s", dfilter_text(df), str);
839 else
840 ws_log_write_always_full(domain, level, file, line, func, "%s:\nFilter:\n %s\n\n%s", msg, dfilter_text(df), str);
841 g_free(str);
844 static int
845 compare_ref_layer(const void *_a, const void *_b)
847 const df_reference_t *a = *(const df_reference_t **)_a;
848 const df_reference_t *b = *(const df_reference_t **)_b;
849 return a->proto_layer_num - b->proto_layer_num;
852 static void
853 load_references(GHashTable *table, proto_tree *tree, bool raw)
855 GHashTableIter iter;
856 GPtrArray *finfos;
857 field_info *finfo;
858 header_field_info *hfinfo;
859 GPtrArray *refs;
861 if (g_hash_table_size(table) == 0) {
862 /* Nothing to do. */
863 return;
866 g_hash_table_iter_init(&iter, table);
867 while (g_hash_table_iter_next(&iter, (void **)&hfinfo, (void **)&refs)) {
868 /* If we have a previous array free the data */
869 g_ptr_array_set_size(refs, 0);
871 while (hfinfo) {
872 finfos = proto_find_finfo(tree, hfinfo->id);
873 if (finfos == NULL) {
874 hfinfo = hfinfo->same_name_next;
875 continue;
877 for (unsigned i = 0; i < finfos->len; i++) {
878 finfo = g_ptr_array_index(finfos, i);
879 g_ptr_array_add(refs, reference_new(finfo, raw));
881 g_ptr_array_free(finfos, true);
882 hfinfo = hfinfo->same_name_next;
885 g_ptr_array_sort(refs, compare_ref_layer);
889 void
890 dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
892 load_references(df->references, tree, false);
893 load_references(df->raw_references, tree, true);
896 void
897 dfilter_load_field_references_edt(const dfilter_t *df, epan_dissect_t *edt)
899 dfilter_load_field_references(df, edt->tree);
902 df_reference_t *
903 reference_new(const field_info *finfo, bool raw)
905 df_reference_t *ref = g_new(df_reference_t, 1);
906 ref->hfinfo = finfo->hfinfo;
907 if (raw) {
908 ref->value = dfvm_get_raw_fvalue(finfo);
910 else {
911 ref->value = fvalue_dup(finfo->value);
913 ref->proto_layer_num = finfo->proto_layer_num;
914 return ref;
917 void
918 reference_free(df_reference_t *ref)
920 fvalue_free(ref->value);
921 g_free(ref);
924 df_error_t *
925 df_error_new(int code, char *msg, df_loc_t *loc)
927 df_error_t *err = g_new(df_error_t, 1);
928 err->code = code;
929 err->msg = msg;
930 if (loc) {
931 err->loc.col_start = loc->col_start;
932 err->loc.col_len = loc->col_len;
934 else {
935 err->loc.col_start = -1;
936 err->loc.col_len = 0;
938 return err;
941 df_error_t *
942 df_error_new_vprintf(int code, df_loc_t *loc, const char *fmt, va_list ap)
944 df_error_t *err = g_new(df_error_t, 1);
945 err->code = code;
946 err->msg = ws_strdup_vprintf(fmt, ap);
947 if (loc) {
948 err->loc.col_start = loc->col_start;
949 err->loc.col_len = loc->col_len;
951 else {
952 err->loc.col_start = -1;
953 err->loc.col_len = 0;
955 return err;
958 df_error_t *
959 df_error_new_printf(int code, df_loc_t *loc, const char *fmt, ...)
961 va_list ap;
962 va_start(ap, fmt);
963 df_error_t *err = df_error_new_vprintf(code, loc, fmt, ap);
964 va_end(ap);
965 return err;
968 void
969 df_error_free(df_error_t **ep)
971 if (*ep == NULL)
972 return;
973 g_free((*ep)->msg);
974 g_free(*ep);
975 *ep = NULL;
978 void
979 df_cell_append(df_cell_t *rp, fvalue_t *fv)
981 /* Assert cell has been initialized. */
982 ws_assert(rp->array != NULL);
983 g_ptr_array_add(rp->array, fv);
986 GPtrArray *
987 df_cell_ref(df_cell_t *rp)
989 if (rp->array == NULL)
990 return NULL;
991 return g_ptr_array_ref(rp->array);
994 size_t
995 df_cell_size(const df_cell_t *rp)
997 if (rp->array == NULL)
998 return 0;
999 return rp->array->len;
1002 fvalue_t **
1003 df_cell_array(const df_cell_t *rp)
1005 if (rp->array == NULL)
1006 return NULL;
1007 return (fvalue_t **)rp->array->pdata;
1010 bool
1011 df_cell_is_empty(const df_cell_t *rp)
1013 if (rp->array == NULL)
1014 return true;
1015 return rp->array->len == 0;
1018 bool
1019 df_cell_is_null(const df_cell_t *rp)
1021 return rp->array == NULL;
1024 void
1025 df_cell_init(df_cell_t *rp, bool free_seg)
1027 df_cell_clear(rp);
1028 if (free_seg)
1029 rp->array = g_ptr_array_new_with_free_func((GDestroyNotify)fvalue_free);
1030 else
1031 rp->array = g_ptr_array_new();
1034 void
1035 df_cell_clear(df_cell_t *rp)
1037 if (rp->array)
1038 g_ptr_array_unref(rp->array);
1039 rp->array = NULL;
1042 void
1043 df_cell_iter_init(df_cell_t *rp, df_cell_iter_t *iter)
1045 iter->ptr = rp->array;
1046 iter->idx = 0;
1049 fvalue_t *
1050 df_cell_iter_next(df_cell_iter_t *iter)
1052 if (iter->idx < iter->ptr->len) {
1053 return iter->ptr->pdata[iter->idx++];
1055 return NULL;
1059 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1061 * Local variables:
1062 * c-basic-offset: 8
1063 * tab-width: 8
1064 * indent-tabs-mode: t
1065 * End:
1067 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1068 * :indentSize=8:tabSize=8:noTabs=false: