Bug Summary

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