Bug Summary

File:epan/color_filters.c
Warning:line 708, column 13
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name color_filters.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan -isystem /builds/wireshark/wireshark/build/epan -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /usr/include/lua5.4 -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -D epan_EXPORTS -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -I /builds/wireshark/wireshark/wiretap -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-11-05-100318-3623-1 -x c /builds/wireshark/wireshark/epan/color_filters.c
1/* color_filters.c
2 * Routines for color filters
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 * Updated 1 Dec 10 jjm
12 */
13
14#include <config.h>
15#define WS_LOG_DOMAIN"Epan" LOG_DOMAIN_EPAN"Epan"
16
17#include <glib.h>
18
19#include <errno(*__errno_location ()).h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include <wsutil/application_flavor.h>
25#include <wsutil/filesystem.h>
26#include <wsutil/file_util.h>
27#include <wsutil/report_message.h>
28#include <wsutil/wslog.h>
29#include <wsutil/ws_assert.h>
30#include <wsutil/application_flavor.h>
31
32#include <epan/packet.h>
33#include "color_filters.h"
34#include "file.h"
35#include <epan/dfilter/dfilter.h>
36#include <epan/prefs.h>
37#include <epan/epan_dissect.h>
38
39/*
40 * Each line in the colorfilters file has the following format:
41 *
42 * @<filter name>@<filter string>@[<background>][<foreground>]
43 * Background and foreground colors are 16-bit comma-separated RGB
44 * triplets. Colors are 16 bits because that's what GdkColor used.
45 * We might want to use a more standard, copy+paste-able color scheme
46 * such as #RRGGBB instead.
47 */
48
49#define RED_COMPONENT(x)(uint16_t) (((((x) >> 16) & 0xff) * 65535 / 255)) (uint16_t) (((((x) >> 16) & 0xff) * 65535 / 255))
50#define GREEN_COMPONENT(x)(uint16_t) (((((x) >> 8) & 0xff) * 65535 / 255)) (uint16_t) (((((x) >> 8) & 0xff) * 65535 / 255))
51#define BLUE_COMPONENT(x)(uint16_t) ( (((x) & 0xff) * 65535 / 255)) (uint16_t) ( (((x) & 0xff) * 65535 / 255))
52
53static int read_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb);
54
55/* the currently active filters */
56static GSList *color_filter_list;
57
58/* keep "old" deleted filters in this list until
59 * the dissection no longer needs them (e.g. file is closed) */
60static GSList *color_filter_deleted_list;
61static GSList *color_filter_valid_list;
62
63/* Color Filters can en-/disabled. */
64static bool_Bool filters_enabled = true1;
65
66/* Remember if there are temporary coloring filters set to
67 * add sensitivity to the "Reset Coloring 1-10" menu item
68 */
69static bool_Bool tmp_colors_set;
70
71/* Create a new filter */
72color_filter_t *
73color_filter_new(const char *name, /* The name of the filter to create */
74 const char *filter_string, /* The string representing the filter */
75 color_t *bg_color, /* The background color */
76 color_t *fg_color, /* The foreground color */
77 bool_Bool disabled) /* Is the filter disabled? */
78{
79 color_filter_t *colorf;
80
81 colorf = g_new0(color_filter_t, 1)((color_filter_t *) g_malloc0_n ((1), sizeof (color_filter_t)
))
;
82 colorf->filter_name = g_strdup(name)g_strdup_inline (name);
83 colorf->filter_text = g_strdup(filter_string)g_strdup_inline (filter_string);
84 colorf->bg_color = *bg_color;
85 colorf->fg_color = *fg_color;
86 colorf->disabled = disabled;
87 return colorf;
88}
89
90/* Add ten empty (temporary) colorfilters for easy coloring */
91static void
92color_filters_add_tmp(GSList **cfl)
93{
94 char *name = NULL((void*)0);
95 uint32_t i;
96 char** bg_colors;
97 char** fg_colors;
98 unsigned long cval;
99 color_t bg_color, fg_color;
100 color_filter_t *colorf;
101
102 ws_assert(strlen(prefs.gui_colorized_fg)==69)do { if ((1) && !(strlen(prefs.gui_colorized_fg)==69)
) ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/color_filters.c"
, 102, __func__, "assertion failed: %s", "strlen(prefs.gui_colorized_fg)==69"
); } while (0)
;
103 ws_assert(strlen(prefs.gui_colorized_bg)==69)do { if ((1) && !(strlen(prefs.gui_colorized_bg)==69)
) ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/color_filters.c"
, 103, __func__, "assertion failed: %s", "strlen(prefs.gui_colorized_bg)==69"
); } while (0)
;
104 fg_colors = g_strsplit(prefs.gui_colorized_fg, ",", -1);
105 bg_colors = g_strsplit(prefs.gui_colorized_bg, ",", -1);
106
107 for ( i=1 ; i<=10 ; i++ ) {
108 name = ws_strdup_printf("%s%02d",CONVERSATION_COLOR_PREFIX,i)wmem_strdup_printf(((void*)0), "%s%02d","___conversation_color_filter___"
,i)
;
109
110 /* retrieve background and foreground colors */
111 cval = strtoul(fg_colors[i-1], NULL((void*)0), 16);
112 fg_color.red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
113 fg_color.green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
114 fg_color.blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
115 cval = strtoul(bg_colors[i-1], NULL((void*)0), 16);
116 bg_color.red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
117 bg_color.green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
118 bg_color.blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
119 colorf = color_filter_new(name, NULL((void*)0), &bg_color, &fg_color, true1);
120 colorf->filter_text = g_strdup("frame")g_strdup_inline ("frame");
121 *cfl = g_slist_append(*cfl, colorf);
122
123 g_free(name);
124 }
125
126 g_strfreev(fg_colors);
127 g_strfreev(bg_colors);
128}
129
130static int
131color_filters_find_by_name_cb(const void *arg1, const void *arg2)
132{
133 const color_filter_t *colorf = (const color_filter_t *)arg1;
134 const char *name = (const char *)arg2;
135
136 return strcmp(colorf->filter_name, name);
137}
138
139/* Get the filter of a temporary color filter */
140char*
141color_filters_get_tmp(uint8_t filt_nr)
142{
143 char* name = NULL((void*)0);
144 char* filter = NULL((void*)0);
145 GSList* cfl;
146 color_filter_t* colorf;
147 /* Only perform a lookup if the supplied filter number is in the expected range */
148 if (filt_nr < 1 || filt_nr > 10)
149 return NULL((void*)0);
150
151 name = ws_strdup_printf("%s%02d", CONVERSATION_COLOR_PREFIX, filt_nr)wmem_strdup_printf(((void*)0), "%s%02d", "___conversation_color_filter___"
, filt_nr)
;
152 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
153 colorf = (color_filter_t*)cfl->data;
154
155 if (!colorf->disabled)
156 filter = g_strdup(colorf->filter_text)g_strdup_inline (colorf->filter_text);
157
158 g_free(name);
159
160 return filter;
161}
162
163/* Set the filter off a temporary colorfilters and enable it */
164bool_Bool
165color_filters_set_tmp(uint8_t filt_nr, const char *filter, bool_Bool disabled, char **err_msg)
166{
167 char *name = NULL((void*)0);
168 const char *tmpfilter = NULL((void*)0);
169 GSList *cfl;
170 color_filter_t *colorf;
171 dfilter_t *compiled_filter;
172 uint8_t i;
173 df_error_t *df_err = NULL((void*)0);
174 /* Go through the temporary filters and look for the same filter string.
175 * If found, clear it so that a filter can be "moved" up and down the list
176 */
177 for ( i=1 ; i<=10 ; i++ ) {
178 /* If we need to reset the temporary filter (filter==NULL), don't look
179 * for other rules with the same filter string
180 */
181 if( i!=filt_nr && filter==NULL((void*)0) )
182 continue;
183
184 name = ws_strdup_printf("%s%02d",CONVERSATION_COLOR_PREFIX,i)wmem_strdup_printf(((void*)0), "%s%02d","___conversation_color_filter___"
,i)
;
185 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
186 colorf = (color_filter_t *)cfl->data;
187
188 /* Only change the filter rule if this is the rule to change or if
189 * a matching filter string has been found
190 */
191 if(colorf && ( i == filt_nr || filter == NULL((void*)0) || !strcmp(filter, colorf->filter_text) ) ) {
192 /* set filter string to "frame" if we are resetting the rules
193 * or if we found a matching filter string which need to be cleared
194 */
195 tmpfilter = ( (filter==NULL((void*)0)) || (i!=filt_nr) ) ? "frame" : filter;
196 if (!dfilter_compile(tmpfilter, &compiled_filter, &df_err)dfilter_compile_full(tmpfilter, &compiled_filter, &df_err
, (1U << 1)|(1U << 2), __func__)
) {
197 *err_msg = ws_strdup_printf( "Could not compile color filter name: \"%s\" text: \"%s\".\n%s", name, filter, df_err->msg)wmem_strdup_printf(((void*)0), "Could not compile color filter name: \"%s\" text: \"%s\".\n%s"
, name, filter, df_err->msg)
;
198 df_error_free(&df_err);
199 g_free(name);
200 return false0;
201 } else {
202 g_free(colorf->filter_text);
203 dfilter_free(colorf->c_colorfilter);
204 colorf->filter_text = g_strdup(tmpfilter)g_strdup_inline (tmpfilter);
205 colorf->c_colorfilter = compiled_filter;
206 colorf->disabled = ((i!=filt_nr) ? true1 : disabled);
207 /* Remember that there are now temporary coloring filters set */
208 if( filter )
209 tmp_colors_set = true1;
210 }
211 }
212 g_free(name);
213 }
214 return true1;
215}
216
217const color_filter_t *
218color_filters_tmp_color(uint8_t filter_num) {
219 char *name;
220 color_filter_t *colorf = NULL((void*)0);
221 GSList *cfl;
222
223 name = ws_strdup_printf("%s%02d", CONVERSATION_COLOR_PREFIX, filter_num)wmem_strdup_printf(((void*)0), "%s%02d", "___conversation_color_filter___"
, filter_num)
;
224 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
225 if (cfl) {
226 colorf = (color_filter_t *)cfl->data;
227 }
228 g_free(name);
229
230 return colorf;
231}
232
233/* Reset the temporary colorfilters */
234bool_Bool
235color_filters_reset_tmp(char **err_msg)
236{
237 uint8_t i;
238
239 for ( i=1 ; i<=10 ; i++ ) {
240 if (!color_filters_set_tmp(i, NULL((void*)0), true1, err_msg))
241 return false0;
242 }
243 /* Remember that there are now *no* temporary coloring filters set */
244 tmp_colors_set = false0;
245 return true1;
246}
247
248/* delete the specified filter */
249void
250color_filter_delete(color_filter_t *colorf)
251{
252 g_free(colorf->filter_name);
253 g_free(colorf->filter_text);
254 dfilter_free(colorf->c_colorfilter);
255 g_free(colorf);
256}
257
258/* delete the specified filter (called from g_slist_foreach) */
259static void
260color_filter_delete_cb(void *filter_arg)
261{
262 color_filter_t *colorf = (color_filter_t *)filter_arg;
263
264 color_filter_delete(colorf);
265}
266
267/* delete the specified list */
268void
269color_filter_list_delete(GSList **cfl)
270{
271 g_slist_free_full(*cfl, color_filter_delete_cb);
272 *cfl = NULL((void*)0);
273}
274
275/* clone a single list entries from normal to edit list */
276static color_filter_t *
277color_filter_clone(color_filter_t *colorf)
278{
279 color_filter_t *new_colorf;
280
281 new_colorf = g_new(color_filter_t, 1)((color_filter_t *) g_malloc_n ((1), sizeof (color_filter_t))
)
;
282 new_colorf->filter_name = g_strdup(colorf->filter_name)g_strdup_inline (colorf->filter_name);
283 new_colorf->filter_text = g_strdup(colorf->filter_text)g_strdup_inline (colorf->filter_text);
284 new_colorf->bg_color = colorf->bg_color;
285 new_colorf->fg_color = colorf->fg_color;
286 new_colorf->disabled = colorf->disabled;
287 new_colorf->c_colorfilter = NULL((void*)0);
288
289 return new_colorf;
290}
291
292static void
293color_filter_list_clone_cb(void *filter_arg, void *cfl_arg)
294{
295 GSList **cfl = (GSList **)cfl_arg;
296 color_filter_t *new_colorf;
297
298 new_colorf = color_filter_clone((color_filter_t *)filter_arg);
299 *cfl = g_slist_append(*cfl, new_colorf);
300}
301
302/* clone the specified list */
303static GSList *
304color_filter_list_clone(GSList *cfl)
305{
306 GSList *new_list = NULL((void*)0);
307
308 g_slist_foreach(cfl, color_filter_list_clone_cb, &new_list);
309
310 return new_list;
311}
312
313static bool_Bool
314color_filters_get(char** err_msg, color_filter_add_cb_func add_cb)
315{
316 char *path;
317 FILE *f;
318 int ret;
319
320 /* start the list with the temporary colorizing rules */
321 color_filters_add_tmp(&color_filter_list);
322
323 /*
324 * Try to get the user's filters.
325 *
326 * Get the path for the file that would have their filters, and
327 * try to open it.
328 */
329 path = get_persconffile_path(COLORFILTERS_FILE_NAME"colorfilters", true1, application_configuration_environment_prefix());
330 if ((f = ws_fopenfopen(path, "r")) == NULL((void*)0)) {
331 if (errno(*__errno_location ()) != ENOENT2) {
332 /* Error trying to open the file; give up. */
333 *err_msg = ws_strdup_printf("Could not open filter file\n\"%s\": %s.", path,wmem_strdup_printf(((void*)0), "Could not open filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
334 g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
335 g_free(path);
336 return false0;
337 }
338 /* They don't have any filters; try to read the global filters */
339 g_free(path);
340 return color_filters_read_globals(&color_filter_list, err_msg, add_cb);
341 }
342
343 /*
344 * We've opened it; try to read it.
345 */
346 ret = read_filters_file(path, f, &color_filter_list, add_cb);
347 if (ret != 0) {
348 *err_msg = ws_strdup_printf("Error reading filter file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
349 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
350 fclose(f);
351 g_free(path);
352 return false0;
353 }
354
355 /* Success. */
356 fclose(f);
357 g_free(path);
358 return true1;
359}
360
361/* Initialize the filter structures (reading from file) for general running, including app startup */
362bool_Bool
363color_filters_init(char** err_msg, color_filter_add_cb_func add_cb)
364{
365 /* delete all currently existing filters */
366 color_filter_list_delete(&color_filter_list);
367
368 /* now try to construct the filters list */
369 return color_filters_get(err_msg, add_cb);
370}
371
372bool_Bool
373color_filters_reload(char** err_msg, color_filter_add_cb_func add_cb)
374{
375 /* "move" old entries to the deleted list
376 * we must keep them until the dissection no longer needs them */
377 color_filter_deleted_list = g_slist_concat(color_filter_deleted_list, color_filter_list);
378 color_filter_list = NULL((void*)0);
379
380 /* now try to construct the filters list */
381 return color_filters_get(err_msg, add_cb);
382}
383
384void
385color_filters_cleanup(void)
386{
387 /* delete the previously deleted filters */
388 color_filter_list_delete(&color_filter_deleted_list);
389}
390
391typedef struct _color_clone
392{
393 void *user_data;
394 color_filter_add_cb_func add_cb;
395} color_clone_t;
396
397static void
398color_filters_clone_cb(void *filter_arg, void *user_data)
399{
400 color_clone_t* clone_data = (color_clone_t*)user_data;
401 color_filter_t * new_colorf = color_filter_clone((color_filter_t *)filter_arg);
402
403 clone_data->add_cb (new_colorf, clone_data->user_data);
404}
405
406void
407color_filters_clone(void *user_data, color_filter_add_cb_func add_cb)
408{
409 color_clone_t clone_data;
410
411 clone_data.user_data = user_data;
412 clone_data.add_cb = add_cb;
413 g_slist_foreach(color_filter_list, color_filters_clone_cb, &clone_data);
414}
415
416
417static void
418color_filter_compile_cb(void *filter_arg, void *err)
419{
420 color_filter_t *colorf = (color_filter_t *)filter_arg;
421 char **err_msg = (char**)err;
422 df_error_t *df_err = NULL((void*)0);
423
424 ws_assert(colorf->c_colorfilter == NULL)do { if ((1) && !(colorf->c_colorfilter == ((void*
)0))) ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/color_filters.c"
, 424, __func__, "assertion failed: %s", "colorf->c_colorfilter == ((void*)0)"
); } while (0)
;
425
426 /* If the filter is disabled it doesn't matter if it compiles or not. */
427 if (colorf->disabled) return;
428
429 if (!dfilter_compile(colorf->filter_text, &colorf->c_colorfilter, &df_err)dfilter_compile_full(colorf->filter_text, &colorf->
c_colorfilter, &df_err, (1U << 1)|(1U << 2), __func__
)
) {
430 *err_msg = ws_strdup_printf("Could not compile color filter name: \"%s\" text: \"%s\".\n%s",wmem_strdup_printf(((void*)0), "Could not compile color filter name: \"%s\" text: \"%s\".\n%s"
, colorf->filter_name, colorf->filter_text, df_err->
msg)
431 colorf->filter_name, colorf->filter_text, df_err->msg)wmem_strdup_printf(((void*)0), "Could not compile color filter name: \"%s\" text: \"%s\".\n%s"
, colorf->filter_name, colorf->filter_text, df_err->
msg)
;
432 df_error_free(&df_err);
433 /* this filter was compilable before, so this should never happen */
434 /* except if the OK button of the parent window has been clicked */
435 /* so don't use ws_assert_not_reached() but check the filters again */
436 }
437}
438
439static void
440color_filter_validate_cb(void *filter_arg, void *err)
441{
442 color_filter_t *colorf = (color_filter_t *)filter_arg;
443 char **err_msg = (char**)err;
444 df_error_t *df_err = NULL((void*)0);
445
446 ws_assert(colorf->c_colorfilter == NULL)do { if ((1) && !(colorf->c_colorfilter == ((void*
)0))) ws_log_fatal_full("Epan", LOG_LEVEL_ERROR, "epan/color_filters.c"
, 446, __func__, "assertion failed: %s", "colorf->c_colorfilter == ((void*)0)"
); } while (0)
;
447
448 /* If the filter is disabled it doesn't matter if it compiles or not. */
449 if (colorf->disabled) return;
450
451 if (!dfilter_compile(colorf->filter_text, &colorf->c_colorfilter, &df_err)dfilter_compile_full(colorf->filter_text, &colorf->
c_colorfilter, &df_err, (1U << 1)|(1U << 2), __func__
)
) {
452 *err_msg = ws_strdup_printf("Disabling color filter name: \"%s\" filter: \"%s\".\n%s",wmem_strdup_printf(((void*)0), "Disabling color filter name: \"%s\" filter: \"%s\".\n%s"
, colorf->filter_name, colorf->filter_text, df_err->
msg)
453 colorf->filter_name, colorf->filter_text, df_err->msg)wmem_strdup_printf(((void*)0), "Disabling color filter name: \"%s\" filter: \"%s\".\n%s"
, colorf->filter_name, colorf->filter_text, df_err->
msg)
;
454 df_error_free(&df_err);
455
456 /* Disable the color filter in the list of color filters. */
457 colorf->disabled = true1;
458 }
459
460 /* XXX: What if the color filter tests "frame.coloring_rule.name" or
461 * "frame.coloring_rule.string"?
462 */
463}
464
465/* apply changes from the edit list */
466bool_Bool
467color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl, char** err_msg)
468{
469 bool_Bool ret = true1;
470
471 *err_msg = NULL((void*)0);
472
473 /* "move" old entries to the deleted list
474 * we must keep them until the dissection no longer needs them */
475 color_filter_deleted_list = g_slist_concat(color_filter_deleted_list, color_filter_list);
476 color_filter_list = NULL((void*)0);
477
478 /* clone all list entries from tmp/edit to normal list */
479 color_filter_list_delete(&color_filter_valid_list);
480 color_filter_valid_list = color_filter_list_clone(tmp_cfl);
481 color_filter_valid_list = g_slist_concat(color_filter_valid_list,
482 color_filter_list_clone(edit_cfl) );
483
484 /* compile all filter */
485 g_slist_foreach(color_filter_valid_list, color_filter_validate_cb, err_msg);
486 if (*err_msg != NULL((void*)0)) {
487 ret = false0;
488 }
489
490 /* clone all list entries from tmp/edit to normal list */
491 color_filter_list = color_filter_list_clone(color_filter_valid_list);
492
493 /* compile all filter */
494 g_slist_foreach(color_filter_list, color_filter_compile_cb, err_msg);
495 if (*err_msg != NULL((void*)0)) {
496 ret = false0;
497 }
498
499 return ret;
500}
501
502bool_Bool
503color_filters_used(void)
504{
505 return color_filter_list != NULL((void*)0) && filters_enabled;
506}
507
508bool_Bool
509tmp_color_filters_used(void)
510{
511 return tmp_colors_set;
512}
513
514/* prepare the epan_dissect_t for the filter */
515static void
516prime_edt(void *data, void *user_data)
517{
518 color_filter_t *colorf = (color_filter_t *)data;
519 epan_dissect_t *edt = (epan_dissect_t *)user_data;
520
521 if (colorf->c_colorfilter != NULL((void*)0))
522 epan_dissect_prime_with_dfilter(edt, colorf->c_colorfilter);
523}
524
525/* Prime the epan_dissect_t with all the compiler
526 * color filters in 'color_filter_list'. */
527void
528color_filters_prime_edt(epan_dissect_t *edt)
529{
530 if (color_filters_used())
531 g_slist_foreach(color_filter_list, prime_edt, edt);
532}
533
534static int
535find_hfid(const void *data, const void *user_data)
536{
537 color_filter_t *colorf = (color_filter_t *)data;
538 int hfid = GPOINTER_TO_INT(user_data)((gint) (glong) (user_data));
539
540 if ((!colorf->disabled) && colorf->c_colorfilter != NULL((void*)0)) {
541 if (dfilter_interested_in_field(colorf->c_colorfilter, hfid)) {
542 return 0;
543 }
544 }
545 return -1;
546}
547
548bool_Bool
549color_filters_use_hfid(int hfid)
550{
551 GSList *item = NULL((void*)0);
552 if (color_filters_used())
553 item = g_slist_find_custom(color_filter_list, GINT_TO_POINTER(hfid)((gpointer) (glong) (hfid)), find_hfid);
554 return (item != NULL((void*)0));
555}
556
557static int
558find_proto(const void *data, const void *user_data)
559{
560 color_filter_t *colorf = (color_filter_t *)data;
561 int proto_id = GPOINTER_TO_INT(user_data)((gint) (glong) (user_data));
562
563 if ((!colorf->disabled) && colorf->c_colorfilter != NULL((void*)0)) {
564 if (dfilter_interested_in_proto(colorf->c_colorfilter, proto_id)) {
565 return 0;
566 }
567 }
568 return -1;
569}
570
571bool_Bool
572color_filters_use_proto(int proto_id)
573{
574 GSList *item = NULL((void*)0);
575 if (color_filters_used())
576 item = g_slist_find_custom(color_filter_list, GINT_TO_POINTER(proto_id)((gpointer) (glong) (proto_id)), find_proto);
577 return (item != NULL((void*)0));
578}
579
580/* * Return the color_t for later use */
581const color_filter_t *
582color_filters_colorize_packet(epan_dissect_t *edt)
583{
584 GSList *curr;
585 color_filter_t *colorf;
586
587 /* If we have color filters, "search" for the matching one. */
588 if ((edt->tree != NULL((void*)0)) && (color_filters_used())) {
589 curr = color_filter_list;
590
591 while(curr != NULL((void*)0)) {
592 colorf = (color_filter_t *)curr->data;
593 if ( (!colorf->disabled) &&
594 (colorf->c_colorfilter != NULL((void*)0)) &&
595 dfilter_apply_edt(colorf->c_colorfilter, edt)) {
596 return colorf;
597 }
598 curr = g_slist_next(curr)((curr) ? (((GSList *)(curr))->next) : ((void*)0));
599 }
600 }
601
602 return NULL((void*)0);
603}
604
605/* read filters from the given file */
606/* XXX - Would it make more sense to use GStrings here instead of reallocing
607 our buffers? */
608static int
609read_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb)
610{
611#define INIT_BUF_SIZE128 128
612 char *name;
613 char *filter_exp;
614 uint32_t name_len = INIT_BUF_SIZE128;
615 uint32_t filter_exp_len = INIT_BUF_SIZE128;
616 uint32_t i = 0;
617 int c;
618 uint16_t fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
619 bool_Bool disabled = false0;
620 bool_Bool skip_end_of_line = false0;
621 int ret = 0;
622
623 name = (char *)g_malloc(name_len + 1);
624 filter_exp = (char *)g_malloc(filter_exp_len + 1);
625
626 while (1) {
3
Loop condition is true. Entering loop body
37
Loop condition is true. Entering loop body
627
628 if (skip_end_of_line
3.1
'skip_end_of_line' is false
37.1
'skip_end_of_line' is true
) {
38
Taking true branch
629 do {
41
Loop condition is false. Exiting loop
630 c = ws_getc_unlockedgetc_unlocked(f);
631 } while (c != EOF(-1) && c != '\n');
39
Assuming the condition is true
40
Assuming the condition is false
632 if (c == EOF(-1))
42
Taking false branch
633 break;
634 disabled = false0;
635 skip_end_of_line = false0;
636 }
637
638 while ((c = ws_getc_unlockedgetc_unlocked(f)) != EOF(-1) && g_ascii_isspace(c)((g_ascii_table[(guchar) (c)] & G_ASCII_SPACE) != 0)) {
4
Assuming the condition is true
5
Loop condition is false. Execution continues on line 644
43
Assuming the condition is true
44
Loop condition is false. Execution continues on line 644
639 if (c == '\n') {
640 continue;
641 }
642 }
643
644 if (c == EOF(-1))
6
Taking false branch
45
Taking false branch
645 break;
646
647 if (c == '!') {
7
Assuming the condition is false
8
Taking false branch
46
Assuming the condition is false
47
Taking false branch
648 disabled = true1;
649 continue;
650 }
651
652 /* skip # comments and invalid lines */
653 if (c != '@') {
9
Assuming the condition is false
10
Taking false branch
48
Assuming the condition is false
49
Taking false branch
654 skip_end_of_line = true1;
655 continue;
656 }
657
658 /* we get the @ delimiter.
659 * Format is:
660 * @name@filter expression@[background r,g,b][foreground r,g,b]
661 */
662
663 /* retrieve name */
664 i = 0;
665 while (1) {
11
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
50
Loop condition is true. Entering loop body
55
Loop condition is true. Entering loop body
666 c = ws_getc_unlockedgetc_unlocked(f);
667 if (c == EOF(-1) || c == '@')
12
Assuming the condition is false
13
Assuming the condition is false
14
Taking false branch
17
Assuming the condition is false
18
Assuming the condition is true
19
Taking true branch
51
Assuming the condition is false
52
Assuming the condition is false
53
Taking false branch
56
Assuming the condition is false
57
Assuming the condition is true
58
Taking true branch
668 break;
20
Execution continues on line 676
59
Execution continues on line 676
669 if (i
14.1
'i' is < 'name_len'
53.1
'i' is < 'name_len'
>= name_len) {
15
Taking false branch
54
Taking false branch
670 /* buffer isn't long enough; double its length.*/
671 name_len *= 2;
672 name = (char *)g_realloc(name, name_len + 1);
673 }
674 name[i++] = c;
675 }
676 name[i] = '\0';
677
678 if (c == EOF(-1)) {
21
Taking false branch
60
Taking false branch
679 break;
680 } else if (i
21.1
'i' is not equal to 0
60.1
'i' is not equal to 0
== 0) {
22
Taking false branch
61
Taking false branch
681 skip_end_of_line = true1;
682 continue;
683 }
684
685 /* retrieve filter expression */
686 i = 0;
687 while (1) {
23
Loop condition is true. Entering loop body
28
Loop condition is true. Entering loop body
62
Loop condition is true. Entering loop body
67
Loop condition is true. Entering loop body
688 c = ws_getc_unlockedgetc_unlocked(f);
689 if (c == EOF(-1) || c == '@')
24
Assuming the condition is false
25
Assuming the condition is false
26
Taking false branch
29
Assuming the condition is false
30
Assuming the condition is true
31
Taking true branch
63
Assuming the condition is false
64
Assuming the condition is false
65
Taking false branch
68
Assuming the condition is false
69
Assuming the condition is true
70
Taking true branch
690 break;
32
Execution continues on line 698
71
Execution continues on line 698
691 if (i
26.1
'i' is < 'filter_exp_len'
65.1
'i' is < 'filter_exp_len'
>= filter_exp_len) {
27
Taking false branch
66
Taking false branch
692 /* buffer isn't long enough; double its length.*/
693 filter_exp_len *= 2;
694 filter_exp = (char *)g_realloc(filter_exp, filter_exp_len + 1);
695 }
696 filter_exp[i++] = c;
697 }
698 filter_exp[i] = '\0';
699
700 if (c == EOF(-1)) {
33
Taking false branch
72
Taking false branch
701 break;
702 } else if (i
33.1
'i' is not equal to 0
72.1
'i' is not equal to 0
== 0) {
34
Taking false branch
73
Taking false branch
703 skip_end_of_line = true1;
704 continue;
705 }
706
707 /* retrieve background and foreground colors */
708 if (fscanf(f,"[%hu,%hu,%hu][%hu,%hu,%hu]",
35
Assuming this stream operation fails
36
Taking false branch
74
File position of the stream might be 'indeterminate' after a failed operation. Can cause undefined behavior
709 &bg_r, &bg_g, &bg_b, &fg_r, &fg_g, &fg_b) == 6) {
710
711 /* we got a complete color filter */
712
713 color_t bg_color, fg_color;
714 color_filter_t *colorf;
715 dfilter_t *temp_dfilter = NULL((void*)0);
716 df_error_t *df_err = NULL((void*)0);
717
718 if (!disabled && !dfilter_compile(filter_exp, &temp_dfilter, &df_err)dfilter_compile_full(filter_exp, &temp_dfilter, &df_err
, (1U << 1)|(1U << 2), __func__)
) {
719 report_warning("Disabling color filter: Could not compile \"%s\" in colorfilters file \"%s\".\n%s", name, path, df_err->msg);
720 df_error_free(&df_err);
721
722 /* skip_end_of_line = true; */
723 disabled = true1;
724 }
725
726 fg_color.red = fg_r;
727 fg_color.green = fg_g;
728 fg_color.blue = fg_b;
729
730 bg_color.red = bg_r;
731 bg_color.green = bg_g;
732 bg_color.blue = bg_b;
733
734 colorf = color_filter_new(name, filter_exp, &bg_color,
735 &fg_color, disabled);
736 if(user_data == &color_filter_list) {
737 GSList **cfl = (GSList **)user_data;
738
739 /* internal call */
740 colorf->c_colorfilter = temp_dfilter;
741 *cfl = g_slist_append(*cfl, colorf);
742 } else {
743 /* external call */
744 /* just editing, don't need the compiled filter */
745 dfilter_free(temp_dfilter);
746 add_cb(colorf, user_data);
747 }
748 } /* if sscanf */
749
750 skip_end_of_line = true1;
751 }
752
753 if (ferror(f))
754 ret = errno(*__errno_location ());
755
756 g_free(name);
757 g_free(filter_exp);
758 return ret;
759}
760
761/* read filters from the filter file */
762bool_Bool
763color_filters_read_globals(void *user_data, char** err_msg, color_filter_add_cb_func add_cb)
764{
765 char *path;
766 FILE *f;
767 int ret;
768
769 /*
770 * Try to get the global filters.
771 *
772 * Get the path for the file that would have the global filters, and
773 * try to open it.
774 */
775 path = get_datafile_path(COLORFILTERS_FILE_NAME"colorfilters", application_configuration_environment_prefix());
776 if ((f = ws_fopenfopen(path, "r")) == NULL((void*)0)) {
777 if (errno(*__errno_location ()) != ENOENT2) {
778 /* Error trying to open the file; give up. */
779 *err_msg = ws_strdup_printf("Could not open global filter file\n\"%s\": %s.", path,wmem_strdup_printf(((void*)0), "Could not open global filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
780 g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open global filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
781 g_free(path);
782 return false0;
783 }
784
785 /*
786 * There is no global filter file; treat that as equivalent to
787 * that file existing bug being empty, and say we succeeded.
788 */
789 g_free(path);
790 return true1;
791 }
792
793 ret = read_filters_file(path, f, user_data, add_cb);
794 if (ret != 0) {
795 *err_msg = ws_strdup_printf("Error reading global filter file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading global filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
796 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading global filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
797 fclose(f);
798 g_free(path);
799 return false0;
800 }
801
802 fclose(f);
803 g_free(path);
804 return true1;
805}
806
807/* read filters from some other filter file (import) */
808bool_Bool
809color_filters_import(const char *path, void *user_data, char **err_msg, color_filter_add_cb_func add_cb)
810{
811 FILE *f;
812 int ret;
813
814 if ((f = ws_fopenfopen(path, "r")) == NULL((void*)0)) {
1
Taking false branch
815 *err_msg = ws_strdup_printf("Could not open filter file\n%s\nfor reading: %s.",wmem_strdup_printf(((void*)0), "Could not open filter file\n%s\nfor reading: %s."
, path, g_strerror((*__errno_location ())))
816 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open filter file\n%s\nfor reading: %s."
, path, g_strerror((*__errno_location ())))
;
817 return false0;
818 }
819
820 ret = read_filters_file(path, f, user_data, add_cb);
2
Calling 'read_filters_file'
821 if (ret != 0) {
822 *err_msg = ws_strdup_printf("Error reading filter file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
823 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
824 fclose(f);
825 return false0;
826 }
827
828 fclose(f);
829 return true1;
830}
831
832struct write_filter_data
833{
834 FILE *f;
835 bool_Bool only_selected;
836};
837
838/* save a single filter */
839static void
840write_filter(void *filter_arg, void *data_arg)
841{
842 struct write_filter_data *data = (struct write_filter_data *)data_arg;
843 color_filter_t *colorf = (color_filter_t *)filter_arg;
844 FILE *f = data->f;
845
846 if ( (!data->only_selected) &&
847 (strstr(colorf->filter_name,CONVERSATION_COLOR_PREFIX"___conversation_color_filter___")==NULL((void*)0)) ) {
848 fprintf(f,"%s@%s@%s@[%u,%u,%u][%u,%u,%u]\n",
849 colorf->disabled ? "!" : "",
850 colorf->filter_name,
851 colorf->filter_text,
852 colorf->bg_color.red,
853 colorf->bg_color.green,
854 colorf->bg_color.blue,
855 colorf->fg_color.red,
856 colorf->fg_color.green,
857 colorf->fg_color.blue);
858 }
859}
860
861/* save filters in a filter file */
862static bool_Bool
863write_filters_file(GSList *cfl, FILE *f, bool_Bool only_selected)
864{
865 struct write_filter_data data;
866
867 data.f = f;
868 data.only_selected = only_selected;
869
870 fprintf(f,"# This file was created by %s. Edit with care.\n", application_flavor_name_proper());
871 g_slist_foreach(cfl, write_filter, &data);
872 return true1;
873}
874
875/* save filters in users filter file */
876bool_Bool
877color_filters_write(GSList *cfl, char** err_msg)
878{
879 char *pf_dir_path;
880 char *path;
881 FILE *f;
882
883 /* Create the directory that holds personal configuration files,
884 if necessary. */
885 if (create_persconffile_dir(application_configuration_environment_prefix(), &pf_dir_path) == -1) {
886 *err_msg = ws_strdup_printf("Can't create directory\n\"%s\"\nfor color files: %s.",wmem_strdup_printf(((void*)0), "Can't create directory\n\"%s\"\nfor color files: %s."
, pf_dir_path, g_strerror((*__errno_location ())))
887 pf_dir_path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Can't create directory\n\"%s\"\nfor color files: %s."
, pf_dir_path, g_strerror((*__errno_location ())))
;
888 g_free(pf_dir_path);
889 return false0;
890 }
891
892 path = get_persconffile_path(COLORFILTERS_FILE_NAME"colorfilters", true1, application_configuration_environment_prefix());
893 if ((f = ws_fopenfopen(path, "w+")) == NULL((void*)0)) {
894 *err_msg = ws_strdup_printf("Could not open\n%s\nfor writing: %s.",wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
895 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
;
896 g_free(path);
897 return false0;
898 }
899 g_free(path);
900 write_filters_file(cfl, f, false0);
901 fclose(f);
902 return true1;
903}
904
905/* save filters in some other filter file (export) */
906bool_Bool
907color_filters_export(const char *path, GSList *cfl, bool_Bool only_marked, char** err_msg)
908{
909 FILE *f;
910
911 if ((f = ws_fopenfopen(path, "w+")) == NULL((void*)0)) {
912 *err_msg = ws_strdup_printf("Could not open\n%s\nfor writing: %s.",wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
913 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
;
914 return false0;
915 }
916 write_filters_file(cfl, f, only_marked);
917 fclose(f);
918 return true1;
919}
920
921/*
922 * Editor modelines - https://www.wireshark.org/tools/modelines.html
923 *
924 * Local variables:
925 * c-basic-offset: 4
926 * tab-width: 8
927 * indent-tabs-mode: nil
928 * End:
929 *
930 * vi: set shiftwidth=4 tabstop=8 expandtab:
931 * :indentSize=4:tabSize=8:noTabs=true:
932 */