Bug Summary

File:builds/wireshark/wireshark/epan/color_filters.c
Warning:line 977, column 13
Read function called when stream is in EOF state. Function has no effect

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-22/lib/clang/22 -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/lua5.5 -isystem /usr/include/libxml2 -D CARES_NO_DEPRECATED -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D REX_API=extern -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-22/lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../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-nonliteral -std=gnu17 -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 -fdwarf2-cfi-asm -o /builds/wireshark/wireshark/sbout/2026-10-24-100333-3661-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/filesystem.h>
25#include <wsutil/file_util.h>
26#include <wsutil/report_message.h>
27#include <wsutil/wslog.h>
28#include <wsutil/ws_assert.h>
29#include <wsutil/wmem/wmem_list.h>
30#include <wsutil/wsjson.h>
31#include <wsutil/json_dumper.h>
32
33#include <epan/packet.h>
34#include "color_filters.h"
35#include "file.h"
36#include <epan/dfilter/dfilter.h>
37#include <epan/prefs.h>
38#include <epan/epan_dissect.h>
39
40/*
41 * The coloring_rules.jsonc file is formatted as JSONC (jsonc.org). It
42 * must contain an array of named objects with the following key:value
43 * pairs:
44 * [
45 * { "Filter name": {
46 * "filter": "<display filter string>",
47 * "foreground": "#rrggbb or rrggbb",
48 * "background": "#rrggbb or rrggbb",
49 * "enabled": "<boolean value>",
50 * }
51 * }
52 * ]
53 *
54 * Each line in the legacy colorfilters file has the following format:
55 *
56 * @<filter name>@<filter string>@[<background>][<foreground>]
57 * Background and foreground colors are 16-bit comma-separated RGB
58 * triplets. Colors are 16 bits because that's what GdkColor used.
59 * We might want to use a more standard, copy+paste-able color scheme
60 * such as #RRGGBB instead.
61 */
62
63static int read_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb, bool_Bool require_json);
64static int read_legacy_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb);
65
66/* the currently active filters */
67static GSList *color_filter_list;
68
69/* keep "old" deleted filters in this list until
70 * the dissection no longer needs them (e.g. file is closed) */
71static GSList *color_filter_deleted_list;
72static GSList *color_filter_valid_list;
73
74/* Color Filters can en-/disabled. */
75static bool_Bool filters_enabled = true1;
76
77/* Remember if there are temporary coloring filters set to
78 * add sensitivity to the "Reset Coloring 1-10" menu item
79 */
80static bool_Bool tmp_colors_set;
81
82/* Create a new filter */
83color_filter_t *
84color_filter_new(const char *name, /* The name of the filter to create */
85 const char *filter_string, /* The string representing the filter */
86 color_t *bg_color, /* The background color */
87 color_t *fg_color, /* The foreground color */
88 bool_Bool enabled) /* Is the filter enabled? */
89{
90 color_filter_t *colorf;
91
92 colorf = g_new0(color_filter_t, 1)((color_filter_t *) g_malloc0_n ((1), sizeof (color_filter_t)
))
;
93 colorf->filter_name = g_strdup(name)g_strdup_inline (name);
94 colorf->filter_text = g_strdup(filter_string)g_strdup_inline (filter_string);
95 colorf->bg_color = *bg_color;
96 colorf->fg_color = *fg_color;
97 colorf->enabled = enabled;
98 return colorf;
99}
100
101/* Add ten empty (temporary) colorfilters for easy coloring */
102static void
103color_filters_add_tmp(GSList **cfl)
104{
105 char *name = NULL((void*)0);
106 uint32_t i;
107 char** bg_colors;
108 char** fg_colors;
109 unsigned long cval;
110 color_t bg_color, fg_color;
111 color_filter_t *colorf;
112
113 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"
, 113, __func__, "assertion failed: %s", "strlen(prefs.gui_colorized_fg)==69"
); } while (0)
;
114 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"
, 114, __func__, "assertion failed: %s", "strlen(prefs.gui_colorized_bg)==69"
); } while (0)
;
115 fg_colors = g_strsplit(prefs.gui_colorized_fg, ",", -1);
116 bg_colors = g_strsplit(prefs.gui_colorized_bg, ",", -1);
117
118 for ( i=1 ; i<=10 ; i++ ) {
119 name = ws_strdup_printf("%s%02d",CONVERSATION_COLOR_PREFIX,i)wmem_strdup_printf(((void*)0), "%s%02d","___conversation_color_filter___"
,i)
;
120
121 /* retrieve background and foreground colors */
122 cval = strtoul(fg_colors[i-1], NULL((void*)0), 16);
123 fg_color.red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
124 fg_color.green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
125 fg_color.blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
126 cval = strtoul(bg_colors[i-1], NULL((void*)0), 16);
127 bg_color.red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
128 bg_color.green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
129 bg_color.blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
130 colorf = color_filter_new(name, NULL((void*)0), &bg_color, &fg_color, false0);
131 colorf->filter_text = g_strdup("frame")g_strdup_inline ("frame");
132 *cfl = g_slist_append(*cfl, colorf);
133
134 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
135 }
136
137 g_strfreev(fg_colors);
138 g_strfreev(bg_colors);
139}
140
141static int
142color_filters_find_by_name_cb(const void *arg1, const void *arg2)
143{
144 const color_filter_t *colorf = (const color_filter_t *)arg1;
145 const char *name = (const char *)arg2;
146
147 return strcmp(colorf->filter_name, name);
148}
149
150/* Get the filter of a temporary color filter */
151char*
152color_filters_get_tmp(uint8_t filt_nr)
153{
154 char* name = NULL((void*)0);
155 char* filter = NULL((void*)0);
156 GSList* cfl;
157 color_filter_t* colorf;
158 /* Only perform a lookup if the supplied filter number is in the expected range */
159 if (filt_nr < 1 || filt_nr > 10)
160 return NULL((void*)0);
161
162 name = ws_strdup_printf("%s%02d", CONVERSATION_COLOR_PREFIX, filt_nr)wmem_strdup_printf(((void*)0), "%s%02d", "___conversation_color_filter___"
, filt_nr)
;
163 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
164 colorf = (color_filter_t*)cfl->data;
165
166 if (colorf->enabled)
167 filter = g_strdup(colorf->filter_text)g_strdup_inline (colorf->filter_text);
168
169 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
170
171 return filter;
172}
173
174/* Set the filter off a temporary colorfilters and enable it */
175bool_Bool
176color_filters_set_tmp(uint8_t filt_nr, const char *filter, bool_Bool enabled, char **err_msg)
177{
178 char *name = NULL((void*)0);
179 const char *tmpfilter = NULL((void*)0);
180 GSList *cfl;
181 color_filter_t *colorf;
182 dfilter_t *compiled_filter;
183 uint8_t i;
184 df_error_t *df_err = NULL((void*)0);
185 /* Go through the temporary filters and look for the same filter string.
186 * If found, clear it so that a filter can be "moved" up and down the list
187 */
188 for ( i=1 ; i<=10 ; i++ ) {
189 /* If we need to reset the temporary filter (filter==NULL), don't look
190 * for other rules with the same filter string
191 */
192 if( i!=filt_nr && filter==NULL((void*)0) )
193 continue;
194
195 name = ws_strdup_printf("%s%02d",CONVERSATION_COLOR_PREFIX,i)wmem_strdup_printf(((void*)0), "%s%02d","___conversation_color_filter___"
,i)
;
196 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
197 colorf = (color_filter_t *)cfl->data;
198
199 /* Only change the filter rule if this is the rule to change or if
200 * a matching filter string has been found
201 */
202 if(colorf && ( i == filt_nr || filter == NULL((void*)0) || !strcmp(filter, colorf->filter_text) ) ) {
203 /* set filter string to "frame" if we are resetting the rules
204 * or if we found a matching filter string which need to be cleared
205 */
206 tmpfilter = ( (filter==NULL((void*)0)) || (i!=filt_nr) ) ? "frame" : filter;
207 if (!dfilter_compile(tmpfilter, &compiled_filter, &df_err)dfilter_compile_full(tmpfilter, &compiled_filter, &df_err
, (1U << 1)|(1U << 2), __func__)
) {
208 *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)
;
209 df_error_free(&df_err);
210 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
211 return false0;
212 } else {
213 g_free(colorf->filter_text)(__builtin_object_size ((colorf->filter_text), 0) != ((size_t
) - 1)) ? g_free_sized (colorf->filter_text, __builtin_object_size
((colorf->filter_text), 0)) : (g_free) (colorf->filter_text
)
;
214 dfilter_free(colorf->c_colorfilter);
215 colorf->filter_text = g_strdup(tmpfilter)g_strdup_inline (tmpfilter);
216 colorf->c_colorfilter = compiled_filter;
217 colorf->enabled = ((i!=filt_nr) ? false0 : enabled);
218 /* Remember that there are now temporary coloring filters set */
219 if( filter )
220 tmp_colors_set = true1;
221 }
222 }
223 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
224 }
225 return true1;
226}
227
228const color_filter_t *
229color_filters_tmp_color(uint8_t filter_num) {
230 char *name;
231 color_filter_t *colorf = NULL((void*)0);
232 GSList *cfl;
233
234 name = ws_strdup_printf("%s%02d", CONVERSATION_COLOR_PREFIX, filter_num)wmem_strdup_printf(((void*)0), "%s%02d", "___conversation_color_filter___"
, filter_num)
;
235 cfl = g_slist_find_custom(color_filter_list, name, color_filters_find_by_name_cb);
236 if (cfl) {
237 colorf = (color_filter_t *)cfl->data;
238 }
239 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
240
241 return colorf;
242}
243
244/* Reset the temporary colorfilters */
245bool_Bool
246color_filters_reset_tmp(char **err_msg)
247{
248 uint8_t i;
249
250 for ( i=1 ; i<=10 ; i++ ) {
251 if (!color_filters_set_tmp(i, NULL((void*)0), false0, err_msg))
252 return false0;
253 }
254 /* Remember that there are now *no* temporary coloring filters set */
255 tmp_colors_set = false0;
256 return true1;
257}
258
259/* delete the specified filter */
260void
261color_filter_delete(color_filter_t *colorf)
262{
263 g_free(colorf->filter_name)(__builtin_object_size ((colorf->filter_name), 0) != ((size_t
) - 1)) ? g_free_sized (colorf->filter_name, __builtin_object_size
((colorf->filter_name), 0)) : (g_free) (colorf->filter_name
)
;
264 g_free(colorf->filter_text)(__builtin_object_size ((colorf->filter_text), 0) != ((size_t
) - 1)) ? g_free_sized (colorf->filter_text, __builtin_object_size
((colorf->filter_text), 0)) : (g_free) (colorf->filter_text
)
;
265 dfilter_free(colorf->c_colorfilter);
266 g_free(colorf)(__builtin_object_size ((colorf), 0) != ((size_t) - 1)) ? g_free_sized
(colorf, __builtin_object_size ((colorf), 0)) : (g_free) (colorf
)
;
267}
268
269/* delete the specified filter (called from g_slist_foreach) */
270static void
271color_filter_delete_cb(void *filter_arg)
272{
273 color_filter_t *colorf = (color_filter_t *)filter_arg;
274
275 color_filter_delete(colorf);
276}
277
278/* delete the specified list */
279void
280color_filter_list_delete(GSList **cfl)
281{
282 g_slist_free_full(*cfl, color_filter_delete_cb);
283 *cfl = NULL((void*)0);
284}
285
286/* clone a single list entries from normal to edit list */
287static color_filter_t *
288color_filter_clone(color_filter_t *colorf)
289{
290 color_filter_t *new_colorf;
291
292 new_colorf = g_new(color_filter_t, 1)((color_filter_t *) g_malloc_n ((1), sizeof (color_filter_t))
)
;
293 new_colorf->filter_name = g_strdup(colorf->filter_name)g_strdup_inline (colorf->filter_name);
294 new_colorf->filter_text = g_strdup(colorf->filter_text)g_strdup_inline (colorf->filter_text);
295 new_colorf->bg_color = colorf->bg_color;
296 new_colorf->fg_color = colorf->fg_color;
297 new_colorf->enabled = colorf->enabled;
298 new_colorf->c_colorfilter = NULL((void*)0);
299
300 return new_colorf;
301}
302
303static void
304color_filter_list_clone_cb(void *filter_arg, void *cfl_arg)
305{
306 GSList **cfl = (GSList **)cfl_arg;
307 color_filter_t *new_colorf;
308
309 new_colorf = color_filter_clone((color_filter_t *)filter_arg);
310 *cfl = g_slist_append(*cfl, new_colorf);
311}
312
313/* clone the specified list */
314static GSList *
315color_filter_list_clone(GSList *cfl)
316{
317 GSList *new_list = NULL((void*)0);
318
319 g_slist_foreach(cfl, color_filter_list_clone_cb, &new_list);
320
321 return new_list;
322}
323
324static bool_Bool
325color_filters_get(char** err_msg, color_filter_add_cb_func add_cb, const char* app_env_var_prefix)
326{
327 char *path;
328 char *legacy_path;
329 FILE *f;
330 int ret;
331
332 /* start the list with the temporary colorizing rules */
333 color_filters_add_tmp(&color_filter_list);
334
335 /*
336 * Resolve both personal paths up front, although at most one file is
337 * read. get_persconffile_path() registers each name as a profile file,
338 * which makes profile copy and the Default profile reset include it.
339 * Resolving the legacy name only when it is read would let a reset
340 * remove coloring_rules.jsonc but keep a stale colorfilters, whose
341 * rules would then come back on the next start.
342 */
343 path = get_persconffile_path(COLORING_RULES_FILE_NAME"coloring_rules.jsonc", true1, app_env_var_prefix);
344 legacy_path = get_persconffile_path(COLORFILTERS_FILE_NAME"colorfilters", true1, app_env_var_prefix);
345
346 /*
347 * If the personal coloring_rules.jsonc exists, it is the user's rule
348 * list and the only file read. A legacy colorfilters file next to it
349 * is an older copy kept for older versions; reading it as well would
350 * bring back rules the user has since deleted or changed.
351 */
352 if ((f = ws_fopenfopen(path, "r")) != NULL((void*)0)) {
353 ret = read_filters_file(path, f, &color_filter_list, add_cb, true1);
354 fclose(f);
355 if (ret != 0) {
356 *err_msg = ws_strdup_printf("Error reading coloring rules file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading coloring rules file\n\"%s\": %s."
, path, g_strerror(ret))
357 path, g_strerror(ret))wmem_strdup_printf(((void*)0), "Error reading coloring rules file\n\"%s\": %s."
, path, g_strerror(ret))
;
358 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
359 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
360 return false0;
361 }
362 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
363 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
364 return true1;
365 }
366 if (errno(*__errno_location ()) != ENOENT2) {
367 *err_msg = ws_strdup_printf("Could not open coloring rules file\n\"%s\": %s.", path,wmem_strdup_printf(((void*)0), "Could not open coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
368 g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
369 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
370 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
371 return false0;
372 }
373 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
374
375 /*
376 * No personal coloring_rules.jsonc. A legacy colorfilters file from a
377 * version before the JSONC format is the complete personal rule list,
378 * so the global rules are not added to it. The next save writes it
379 * out as coloring_rules.jsonc.
380 */
381 if ((f = ws_fopenfopen(legacy_path, "r")) != NULL((void*)0)) {
382 ret = read_legacy_filters_file(legacy_path, f, &color_filter_list, add_cb);
383 fclose(f);
384 if (ret != 0) {
385 *err_msg = ws_strdup_printf("Error reading filter file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, legacy_path, g_strerror(ret))
386 legacy_path, g_strerror(ret))wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, legacy_path, g_strerror(ret))
;
387 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
388 return false0;
389 }
390 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
391 return true1;
392 }
393 if (errno(*__errno_location ()) != ENOENT2) {
394 *err_msg = ws_strdup_printf("Could not open filter file\n\"%s\": %s.", legacy_path,wmem_strdup_printf(((void*)0), "Could not open filter file\n\"%s\": %s."
, legacy_path, g_strerror((*__errno_location ())))
395 g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open filter file\n\"%s\": %s."
, legacy_path, g_strerror((*__errno_location ())))
;
396 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
397 return false0;
398 }
399 g_free(legacy_path)(__builtin_object_size ((legacy_path), 0) != ((size_t) - 1)) ?
g_free_sized (legacy_path, __builtin_object_size ((legacy_path
), 0)) : (g_free) (legacy_path)
;
400
401 /* They don't have any personal rules; try to read the global rules */
402 return color_filters_read_globals(&color_filter_list, err_msg, add_cb, app_env_var_prefix);
403}
404
405/* Initialize the filter structures (reading from file) for general running, including app startup */
406bool_Bool
407color_filters_init(char** err_msg, color_filter_add_cb_func add_cb, const char* app_env_var_prefix)
408{
409 /* delete all currently existing filters */
410 color_filter_list_delete(&color_filter_list);
411
412 /* now try to construct the filters list */
413 return color_filters_get(err_msg, add_cb, app_env_var_prefix);
414}
415
416bool_Bool
417color_filters_reload(char** err_msg, color_filter_add_cb_func add_cb, const char* app_env_var_prefix)
418{
419 /* "move" old entries to the deleted list
420 * we must keep them until the dissection no longer needs them */
421 color_filter_deleted_list = g_slist_concat(color_filter_deleted_list, color_filter_list);
422 color_filter_list = NULL((void*)0);
423
424 /* now try to construct the filters list */
425 return color_filters_get(err_msg, add_cb, app_env_var_prefix);
426}
427
428void
429color_filters_cleanup(void)
430{
431 /* delete the previously deleted filters */
432 color_filter_list_delete(&color_filter_deleted_list);
433}
434
435typedef struct _color_clone
436{
437 void *user_data;
438 color_filter_add_cb_func add_cb;
439} color_clone_t;
440
441static void
442color_filters_clone_cb(void *filter_arg, void *user_data)
443{
444 color_clone_t* clone_data = (color_clone_t*)user_data;
445 color_filter_t * new_colorf = color_filter_clone((color_filter_t *)filter_arg);
446
447 clone_data->add_cb (new_colorf, clone_data->user_data);
448}
449
450void
451color_filters_clone(void *user_data, color_filter_add_cb_func add_cb)
452{
453 color_clone_t clone_data;
454
455 clone_data.user_data = user_data;
456 clone_data.add_cb = add_cb;
457 g_slist_foreach(color_filter_list, color_filters_clone_cb, &clone_data);
458}
459
460/* A rule takes part in matching if it compiled and is enabled. A disabled
461 * rule takes part only when asked to, and never a disabled conversation
462 * rule: unused conversation slots are compiled as "frame" and would match
463 * every packet. */
464static bool_Bool
465color_filter_in_play(const color_filter_t *colorf, bool_Bool include_disabled)
466{
467 if (colorf->c_colorfilter == NULL((void*)0))
468 return false0;
469 if (colorf->enabled)
470 return true1;
471 return include_disabled && !color_filter_is_tmp(colorf);
472}
473
474/* Compiles a filter without reporting errors. Disabled rules are compiled
475 * this way so that they can be matched while disabled rules are shown; one
476 * that does not compile simply never matches. */
477static dfilter_t *
478color_filter_compile_quiet(const char *text)
479{
480 dfilter_t *df = NULL((void*)0);
481 df_error_t *df_err = NULL((void*)0);
482
483 if (!dfilter_compile(text, &df, &df_err)dfilter_compile_full(text, &df, &df_err, (1U <<
1)|(1U << 2), __func__)
) {
484 df_error_free(&df_err);
485 }
486 return df;
487}
488
489/* Compiles the filter of a rule read from a file. An enabled rule that does
490 * not compile is reported and disabled. A disabled rule is compiled quietly
491 * when compile_disabled is set (rules read into the list used for matching)
492 * and not at all otherwise (rules read for editing). */
493static dfilter_t *
494color_filter_compile_read(const char *name, const char *text, bool_Bool *enabled,
495 bool_Bool compile_disabled, const char *path,
496 const char *file_kind)
497{
498 dfilter_t *df = NULL((void*)0);
499 df_error_t *df_err = NULL((void*)0);
500
501 if (!*enabled) {
502 return compile_disabled ? color_filter_compile_quiet(text) : NULL((void*)0);
503 }
504 if (!dfilter_compile(text, &df, &df_err)dfilter_compile_full(text, &df, &df_err, (1U <<
1)|(1U << 2), __func__)
) {
505 report_warning("Disabling color filter: Could not compile \"%s\" in %s \"%s\".\n%s",
506 name, file_kind, path, df_err->msg);
507 df_error_free(&df_err);
508 *enabled = false0;
509 }
510 return df;
511}
512
513static void
514color_filter_compile_cb(void *filter_arg, void *err)
515{
516 color_filter_t *colorf = (color_filter_t *)filter_arg;
517 char **err_msg = (char**)err;
518 df_error_t *df_err = NULL((void*)0);
519
520 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"
, 520, __func__, "assertion failed: %s", "colorf->c_colorfilter == ((void*)0)"
); } while (0)
;
521
522 /* Disabled conversation rules are never used. */
523 if (!colorf->enabled) {
524 if (!color_filter_is_tmp(colorf)) {
525 colorf->c_colorfilter = color_filter_compile_quiet(colorf->filter_text);
526 }
527 return;
528 }
529
530 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__
)
) {
531 *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)
532 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)
;
533 df_error_free(&df_err);
534 /* this filter was compilable before, so this should never happen */
535 /* except if the OK button of the parent window has been clicked */
536 /* so don't use ws_assert_not_reached() but check the filters again */
537 }
538}
539
540static void
541color_filter_validate_cb(void *filter_arg, void *err)
542{
543 color_filter_t *colorf = (color_filter_t *)filter_arg;
544 char **err_msg = (char**)err;
545 df_error_t *df_err = NULL((void*)0);
546
547 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"
, 547, __func__, "assertion failed: %s", "colorf->c_colorfilter == ((void*)0)"
); } while (0)
;
548
549 /* If the filter is disabled it doesn't matter if it compiles or not. */
550 if (!colorf->enabled) return;
551
552 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__
)
) {
553 *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)
554 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)
;
555 df_error_free(&df_err);
556
557 /* Disable the color filter in the list of color filters. */
558 colorf->enabled = false0;
559 }
560
561 /* XXX: What if the color filter tests "frame.coloring_rule.name" or
562 * "frame.coloring_rule.string"?
563 */
564}
565
566/* apply changes from the edit list */
567bool_Bool
568color_filters_apply(GSList *tmp_cfl, GSList *edit_cfl, char** err_msg)
569{
570 bool_Bool ret = true1;
571
572 *err_msg = NULL((void*)0);
573
574 /* "move" old entries to the deleted list
575 * we must keep them until the dissection no longer needs them */
576 color_filter_deleted_list = g_slist_concat(color_filter_deleted_list, color_filter_list);
577 color_filter_list = NULL((void*)0);
578
579 /* clone all list entries from tmp/edit to normal list */
580 color_filter_list_delete(&color_filter_valid_list);
581 color_filter_valid_list = color_filter_list_clone(tmp_cfl);
582 color_filter_valid_list = g_slist_concat(color_filter_valid_list,
583 color_filter_list_clone(edit_cfl) );
584
585 /* compile all filter */
586 g_slist_foreach(color_filter_valid_list, color_filter_validate_cb, err_msg);
587 if (*err_msg != NULL((void*)0)) {
588 ret = false0;
589 }
590
591 /* clone all list entries from tmp/edit to normal list */
592 color_filter_list = color_filter_list_clone(color_filter_valid_list);
593
594 /* compile all filter */
595 g_slist_foreach(color_filter_list, color_filter_compile_cb, err_msg);
596 if (*err_msg != NULL((void*)0)) {
597 ret = false0;
598 }
599
600 return ret;
601}
602
603bool_Bool
604color_filters_used(void)
605{
606 return color_filter_list != NULL((void*)0) && filters_enabled;
607}
608
609bool_Bool
610tmp_color_filters_used(void)
611{
612 return tmp_colors_set;
613}
614
615/* prepare the epan_dissect_t for the filter */
616static void
617prime_edt(void *data, void *user_data)
618{
619 color_filter_t *colorf = (color_filter_t *)data;
620 epan_dissect_t *edt = (epan_dissect_t *)user_data;
621
622 if (color_filter_in_play(colorf, prefs.gui_coloring_rules_include_disabled))
623 epan_dissect_prime_with_dfilter(edt, colorf->c_colorfilter);
624}
625
626/* Prime the epan_dissect_t with all the compiler
627 * color filters in 'color_filter_list'. */
628void
629color_filters_prime_edt(epan_dissect_t *edt)
630{
631 if (color_filters_used())
632 g_slist_foreach(color_filter_list, prime_edt, edt);
633}
634
635static int
636find_hfid(const void *data, const void *user_data)
637{
638 color_filter_t *colorf = (color_filter_t *)data;
639 int hfid = GPOINTER_TO_INT(user_data)((gint) (glong) (user_data));
640
641 if (color_filter_in_play(colorf, prefs.gui_coloring_rules_include_disabled)) {
642 if (dfilter_interested_in_field(colorf->c_colorfilter, hfid)) {
643 return 0;
644 }
645 }
646 return -1;
647}
648
649bool_Bool
650color_filters_use_hfid(int hfid)
651{
652 GSList *item = NULL((void*)0);
653 if (color_filters_used())
654 item = g_slist_find_custom(color_filter_list, GINT_TO_POINTER(hfid)((gpointer) (glong) (hfid)), find_hfid);
655 return (item != NULL((void*)0));
656}
657
658static int
659find_proto(const void *data, const void *user_data)
660{
661 color_filter_t *colorf = (color_filter_t *)data;
662 int proto_id = GPOINTER_TO_INT(user_data)((gint) (glong) (user_data));
663
664 if (color_filter_in_play(colorf, prefs.gui_coloring_rules_include_disabled)) {
665 if (dfilter_interested_in_proto(colorf->c_colorfilter, proto_id)) {
666 return 0;
667 }
668 }
669 return -1;
670}
671
672bool_Bool
673color_filters_use_proto(int proto_id)
674{
675 GSList *item = NULL((void*)0);
676 if (color_filters_used())
677 item = g_slist_find_custom(color_filter_list, GINT_TO_POINTER(proto_id)((gpointer) (glong) (proto_id)), find_proto);
678 return (item != NULL((void*)0));
679}
680
681const color_filter_t *
682color_filters_colorize_packet_all(epan_dissect_t *edt,
683 wmem_allocator_t *scope, wmem_list_t **matches, bool_Bool include_disabled)
684{
685 const color_filter_t *first_match = NULL((void*)0);
686
687 if (matches) {
688 *matches = NULL((void*)0);
689 }
690
691 /* If we have color filters, collect ALL matching ones. */
692 if ((edt->tree != NULL((void*)0)) && (color_filters_used())) {
693 for (GSList *curr = color_filter_list; curr != NULL((void*)0); curr = g_slist_next(curr)((curr) ? (((GSList *)(curr))->next) : ((void*)0))) {
694 color_filter_t *colorf = (color_filter_t *)curr->data;
695 if (color_filter_in_play(colorf, include_disabled) &&
696 dfilter_apply_edt(colorf->c_colorfilter, edt)) {
697
698 if (matches) {
699 if (*matches == NULL((void*)0)) {
700 *matches = wmem_list_new(scope);
701 }
702 wmem_list_append(*matches, colorf);
703 }
704
705 /* A disabled rule never colors the packet */
706 if (!first_match && colorf->enabled) {
707 first_match = colorf; /* Backward compatibility */
708 }
709 }
710 }
711 }
712
713 return first_match;
714}
715
716/* Parse a "#rrggbb" or "rrggbb" string into a color_t. Returns false (and
717 * leaves *color untouched) if str is NULL or not a valid hex triplet. */
718static bool_Bool
719hex_str_to_color(const char *str, color_t *color)
720{
721 unsigned long cval;
722
723 if (str == NULL((void*)0)) {
724 return false0;
725 }
726 if (str[0] == '#') {
727 str++;
728 }
729 if (strlen(str) != 6 || strspn(str, "0123456789abcdefABCDEF") != 6) {
730 return false0;
731 }
732
733 cval = strtoul(str, NULL((void*)0), 16);
734 color->red = RED_COMPONENT(cval)(uint16_t) (((((cval) >> 16) & 0xff) * 65535 / 255)
)
;
735 color->green = GREEN_COMPONENT(cval)(uint16_t) (((((cval) >> 8) & 0xff) * 65535 / 255));
736 color->blue = BLUE_COMPONENT(cval)(uint16_t) ( (((cval) & 0xff) * 65535 / 255));
737 return true1;
738}
739
740static int
741read_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb, bool_Bool require_json)
742{
743 long size;
744 char *buf;
745 size_t nread;
746 int num_tokens;
747 jsmntok_t *tokens;
748 int array_len;
749 jsmntok_t *element;
750
751 if (fseek(f, 0, SEEK_END2) == -1) {
752 return errno(*__errno_location ());
753 }
754 size = ftell(f);
755 if (size < 0) {
756 return errno(*__errno_location ());
757 }
758 if (fseek(f, 0, SEEK_SET0) == -1) {
759 return errno(*__errno_location ());
760 }
761 if (size == 0) {
762 return 0;
763 }
764
765 buf = (char *)g_malloc(size + 1);
766 nread = fread(buf, 1, size, f);
767 if (ferror(f)) {
768 int ret = errno(*__errno_location ());
769 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
770 return ret;
771 }
772 buf[nread] = '\0';
773
774 if (!json_strip_jsonc_comments(buf)) {
775 report_warning("Error parsing coloring rules file\n\"%s\": unterminated block comment.", path);
776 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
777 return 0;
778 }
779
780 num_tokens = json_parse(buf, NULL((void*)0), 0);
781 if (num_tokens == 0) {
782 /* Only comments and whitespace: a valid, empty rule list. */
783 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
784 return 0;
785 }
786 if (num_tokens < 0) {
787 /*
788 * Not JSON at all. For the personal and global rule files that is
789 * an error the user must see, since none of the file's rules are
790 * used. An imported file may be in the legacy format, which never
791 * parses as JSON, so it just yields no rules here.
792 */
793 if (require_json) {
794 report_warning("Error parsing coloring rules file\n\"%s\": invalid JSON.", path);
795 }
796 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
797 return 0;
798 }
799
800 tokens = (jsmntok_t *)g_malloc(num_tokens * sizeof(jsmntok_t));
801 if (json_parse(buf, tokens, num_tokens) <= 0 || tokens[0].type != JSMN_ARRAY) {
802 report_warning("Error parsing coloring rules file\n\"%s\": invalid JSON.", path);
803 g_free(tokens)(__builtin_object_size ((tokens), 0) != ((size_t) - 1)) ? g_free_sized
(tokens, __builtin_object_size ((tokens), 0)) : (g_free) (tokens
)
;
804 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
805 return 0;
806 }
807
808 array_len = json_get_array_len(&tokens[0]);
809 element = json_get_array_index(&tokens[0], 0);
810
811 for (int i = 0; i < array_len; i++, element = json_get_next_object(element)) {
812 char *name, *filter_str, *fg_str, *bg_str;
813 bool_Bool enabled = true1;
814 color_t fg_color = { 0, 0, 0 }, bg_color = { 0, 0, 0 };
815 dfilter_t *temp_dfilter = NULL((void*)0);
816 const char *filter_exp;
817 color_filter_t *colorf;
818 jsmntok_t *name_tok, *properties_tok;
819
820 if (element->type != JSMN_OBJECT || element->size != 1) {
821 continue;
822 }
823
824 /* "<filter name>": { ... } */
825 name_tok = element + 1;
826 properties_tok = name_tok + 1;
827 if (name_tok->type != JSMN_STRING || properties_tok->type != JSMN_OBJECT) {
828 continue;
829 }
830
831 name = g_strndup(&buf[name_tok->start], (gsize)(name_tok->end - name_tok->start));
832 if (!json_decode_string_inplace(name)) {
833 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
834 continue;
835 }
836
837 filter_str = json_get_string(buf, properties_tok, "filter");
838 fg_str = json_get_string(buf, properties_tok, "foreground");
839 bg_str = json_get_string(buf, properties_tok, "background");
840 json_get_boolean(buf, properties_tok, "enabled", &enabled);
841
842 hex_str_to_color(fg_str, &fg_color);
843 hex_str_to_color(bg_str, &bg_color);
844
845 filter_exp = filter_str ? filter_str : "";
846
847 temp_dfilter = color_filter_compile_read(name, filter_exp, &enabled,
848 user_data == &color_filter_list,
849 path, "coloring rules file");
850
851 colorf = color_filter_new(name, filter_exp, &bg_color, &fg_color, enabled);
852 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
853
854 if (user_data == &color_filter_list) {
855 GSList **cfl = (GSList **)user_data;
856
857 /* internal call */
858 colorf->c_colorfilter = temp_dfilter;
859 *cfl = g_slist_append(*cfl, colorf);
860 } else {
861 /* external call */
862 /* just editing, don't need the compiled filter */
863 dfilter_free(temp_dfilter);
864 add_cb(colorf, user_data);
865 }
866 }
867
868 g_free(tokens)(__builtin_object_size ((tokens), 0) != ((size_t) - 1)) ? g_free_sized
(tokens, __builtin_object_size ((tokens), 0)) : (g_free) (tokens
)
;
869 g_free(buf)(__builtin_object_size ((buf), 0) != ((size_t) - 1)) ? g_free_sized
(buf, __builtin_object_size ((buf), 0)) : (g_free) (buf)
;
870 return 0;
871}
872
873/* Read legacy (@-delimited) filters from the given file */
874/* XXX At what point do we drop support? */
875/* XXX Would it make more sense to use GStrings here instead of reallocing
876 our buffers? */
877static int
878read_legacy_filters_file(const char *path, FILE *f, void *user_data, color_filter_add_cb_func add_cb)
879{
880#define INIT_BUF_SIZE128 128
881 char *name;
882 char *filter_exp;
883 uint32_t name_len = INIT_BUF_SIZE128;
884 uint32_t filter_exp_len = INIT_BUF_SIZE128;
885 uint32_t i = 0;
886 int c;
887 uint16_t fg_r, fg_g, fg_b, bg_r, bg_g, bg_b;
888 bool_Bool disabled = false0;
889 bool_Bool skip_end_of_line = false0;
890 int ret = 0;
891
892 name = (char *)g_malloc(name_len + 1);
893 filter_exp = (char *)g_malloc(filter_exp_len + 1);
894
895 while (1) {
3
Loop condition is true. Entering loop body
37
Loop condition is true. Entering loop body
896
897 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
898 do {
41
Loop condition is false. Exiting loop
899 c = ws_getc_unlockedgetc_unlocked(f);
900 } while (c != EOF(-1) && c != '\n');
39
Assuming the condition is true
40
Assuming the condition is false
901 if (c == EOF(-1))
42
Taking false branch
902 break;
903 disabled = false0;
904 skip_end_of_line = false0;
905 }
906
907 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 913
43
Assuming the condition is true
44
Loop condition is false. Execution continues on line 913
908 if (c == '\n') {
909 continue;
910 }
911 }
912
913 if (c == EOF(-1))
6
Taking false branch
45
Taking false branch
914 break;
915
916 if (c == '!') {
7
Assuming the condition is false
8
Taking false branch
46
Assuming the condition is false
47
Taking false branch
917 disabled = true1;
918 continue;
919 }
920
921 /* skip # comments and invalid lines */
922 if (c != '@') {
9
Assuming the condition is false
10
Taking false branch
48
Assuming the condition is false
49
Taking false branch
923 skip_end_of_line = true1;
924 continue;
925 }
926
927 /* we get the @ delimiter.
928 * Format is:
929 * @name@filter expression@[background r,g,b][foreground r,g,b]
930 */
931
932 /* retrieve name */
933 i = 0;
934 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
935 c = ws_getc_unlockedgetc_unlocked(f);
936 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
937 break;
20
Execution continues on line 945
59
Execution continues on line 945
938 if (i
14.1
'i' is < 'name_len'
53.1
'i' is < 'name_len'
>= name_len) {
15
Taking false branch
54
Taking false branch
939 /* buffer isn't long enough; double its length.*/
940 name_len *= 2;
941 name = (char *)g_realloc(name, name_len + 1);
942 }
943 name[i++] = c;
944 }
945 name[i] = '\0';
946
947 if (c == EOF(-1)) {
21
Taking false branch
60
Taking false branch
948 break;
949 } 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
950 skip_end_of_line = true1;
951 continue;
952 }
953
954 /* retrieve filter expression */
955 i = 0;
956 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
957 c = ws_getc_unlockedgetc_unlocked(f);
958 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
959 break;
32
Execution continues on line 967
71
Execution continues on line 967
960 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
961 /* buffer isn't long enough; double its length.*/
962 filter_exp_len *= 2;
963 filter_exp = (char *)g_realloc(filter_exp, filter_exp_len + 1);
964 }
965 filter_exp[i++] = c;
966 }
967 filter_exp[i] = '\0';
968
969 if (c == EOF(-1)) {
33
Taking false branch
72
Taking false branch
970 break;
971 } 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
972 skip_end_of_line = true1;
973 continue;
974 }
975
976 /* retrieve background and foreground colors */
977 if (fscanf(f,"[%hu,%hu,%hu][%hu,%hu,%hu]",
35
Assuming stream reaches end-of-file here
36
Taking false branch
74
Read function called when stream is in EOF state. Function has no effect
978 &bg_r, &bg_g, &bg_b, &fg_r, &fg_g, &fg_b) == 6) {
979
980 /* we got a complete color filter */
981
982 color_t bg_color, fg_color;
983 color_filter_t *colorf;
984 dfilter_t *temp_dfilter = NULL((void*)0);
985 bool_Bool enabled = !disabled;
986
987 temp_dfilter = color_filter_compile_read(name, filter_exp, &enabled,
988 user_data == &color_filter_list,
989 path, "colorfilters file");
990
991 fg_color.red = fg_r;
992 fg_color.green = fg_g;
993 fg_color.blue = fg_b;
994
995 bg_color.red = bg_r;
996 bg_color.green = bg_g;
997 bg_color.blue = bg_b;
998
999 colorf = color_filter_new(name, filter_exp, &bg_color,
1000 &fg_color, enabled);
1001 if(user_data == &color_filter_list) {
1002 GSList **cfl = (GSList **)user_data;
1003
1004 /* internal call */
1005 colorf->c_colorfilter = temp_dfilter;
1006 *cfl = g_slist_append(*cfl, colorf);
1007 } else {
1008 /* external call */
1009 /* just editing, don't need the compiled filter */
1010 dfilter_free(temp_dfilter);
1011 add_cb(colorf, user_data);
1012 }
1013 } /* if sscanf */
1014
1015 skip_end_of_line = true1;
1016 }
1017
1018 if (ferror(f))
1019 ret = errno(*__errno_location ());
1020
1021 g_free(name)(__builtin_object_size ((name), 0) != ((size_t) - 1)) ? g_free_sized
(name, __builtin_object_size ((name), 0)) : (g_free) (name)
;
1022 g_free(filter_exp)(__builtin_object_size ((filter_exp), 0) != ((size_t) - 1)) ?
g_free_sized (filter_exp, __builtin_object_size ((filter_exp
), 0)) : (g_free) (filter_exp)
;
1023 return ret;
1024}
1025
1026/* read filters from the filter file */
1027bool_Bool
1028color_filters_read_globals(void *user_data, char** err_msg, color_filter_add_cb_func add_cb, const char* app_env_var_prefix)
1029{
1030 char *path;
1031 FILE *f;
1032 int ret;
1033
1034 /*
1035 * Try to get the global filters.
1036 *
1037 * Get the path for the file that would have the global filters, and
1038 * try to open it.
1039 */
1040 path = get_datafile_path(COLORING_RULES_FILE_NAME"coloring_rules.jsonc", app_env_var_prefix);
1041 if ((f = ws_fopenfopen(path, "r")) == NULL((void*)0)) {
1042 if (errno(*__errno_location ()) != ENOENT2) {
1043 /* Error trying to open the file; give up. */
1044 *err_msg = ws_strdup_printf("Could not open global coloring rules file\n\"%s\": %s.", path,wmem_strdup_printf(((void*)0), "Could not open global coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
1045 g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open global coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
1046 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1047 return false0;
1048 }
1049
1050 /*
1051 * There is no global rules file; treat that as equivalent to
1052 * that file existing bug being empty, and say we succeeded.
1053 */
1054 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1055 return true1;
1056 }
1057
1058 /* Don't try to read the legacy colorfilters file, unlike the personal config. */
1059
1060 ret = read_filters_file(path, f, user_data, add_cb, true1);
1061 fclose(f);
1062 if (ret != 0) {
1063 *err_msg = ws_strdup_printf("Error reading global coloring rules file\n\"%s\": %s.",wmem_strdup_printf(((void*)0), "Error reading global coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
1064 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading global coloring rules file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
1065 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1066 return false0;
1067 }
1068
1069 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1070 return true1;
1071}
1072
1073/* read filters from some other filter file (import) */
1074bool_Bool
1075color_filters_import(const char *path, void *user_data, char **err_msg, color_filter_add_cb_func add_cb)
1076{
1077 FILE *f;
1078 int ret;
1079
1080 if ((f = ws_fopenfopen(path, "r")) == NULL((void*)0)) {
1
Taking false branch
1081 *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 ())))
1082 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open filter file\n%s\nfor reading: %s."
, path, g_strerror((*__errno_location ())))
;
1083 return false0;
1084 }
1085
1086 /*
1087 * The file being imported might be in the legacy @-delimited
1088 * format or the newer JSONC format. Try the legacy format first,
1089 * then the JSONC format. Each parser simply finds no filters if
1090 * the file isn't in the expected format.
1091 */
1092 ret = read_legacy_filters_file(path, f, user_data, add_cb);
2
Calling 'read_legacy_filters_file'
1093 if (ret != 0) {
1094 *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 ())))
1095 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
1096 fclose(f);
1097 return false0;
1098 }
1099
1100 /* read_filters_file() seeks to the start of the file. */
1101 ret = read_filters_file(path, f, user_data, add_cb, false0);
1102 fclose(f);
1103 if (ret != 0) {
1104 *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 ())))
1105 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Error reading filter file\n\"%s\": %s."
, path, g_strerror((*__errno_location ())))
;
1106 return false0;
1107 }
1108
1109 return true1;
1110}
1111
1112struct write_filter_data
1113{
1114 FILE *f;
1115 bool_Bool only_selected;
1116};
1117
1118/* save a single filter, in the legacy @-delimited format */
1119static void
1120write_legacy_filter(void *filter_arg, void *data_arg)
1121{
1122 struct write_filter_data *data = (struct write_filter_data *)data_arg;
1123 color_filter_t *colorf = (color_filter_t *)filter_arg;
1124 FILE *f = data->f;
1125
1126 if ( (!data->only_selected) &&
1127 (strstr(colorf->filter_name,CONVERSATION_COLOR_PREFIX"___conversation_color_filter___")==NULL((void*)0)) ) {
1128 fprintf(f,"%s@%s@%s@[%u,%u,%u][%u,%u,%u]\n",
1129 colorf->enabled ? "" : "!",
1130 colorf->filter_name,
1131 colorf->filter_text,
1132 colorf->bg_color.red,
1133 colorf->bg_color.green,
1134 colorf->bg_color.blue,
1135 colorf->fg_color.red,
1136 colorf->fg_color.green,
1137 colorf->fg_color.blue);
1138 }
1139}
1140
1141/* save filters in a filter file, in the legacy @-delimited format */
1142static bool_Bool
1143write_legacy_filters_file(GSList *cfl, FILE *f, bool_Bool only_selected, const char* app_name)
1144{
1145 struct write_filter_data data;
1146
1147 data.f = f;
1148 data.only_selected = only_selected;
1149
1150 fprintf(f,"# This file was created by %s. Edit with care.\n", app_name);
1151 g_slist_foreach(cfl, write_legacy_filter, &data);
1152 return true1;
1153}
1154
1155struct write_filter_jsonc_data
1156{
1157 json_dumper *dumper;
1158 bool_Bool only_selected;
1159};
1160
1161/* save a single filter, in JSONC format */
1162static void
1163write_jsonc_filter(void *filter_arg, void *data_arg)
1164{
1165 struct write_filter_jsonc_data *data = (struct write_filter_jsonc_data *)data_arg;
1166 color_filter_t *colorf = (color_filter_t *)filter_arg;
1167 json_dumper *dumper = data->dumper;
1168 char *fg_str, *bg_str;
1169
1170 if ( (!data->only_selected) &&
1171 (strstr(colorf->filter_name,CONVERSATION_COLOR_PREFIX"___conversation_color_filter___")==NULL((void*)0)) ) {
1172 fg_str = ws_strdup_printf("#%06x", color_t_to_rgb(&colorf->fg_color))wmem_strdup_printf(((void*)0), "#%06x", color_t_to_rgb(&colorf
->fg_color))
;
1173 bg_str = ws_strdup_printf("#%06x", color_t_to_rgb(&colorf->bg_color))wmem_strdup_printf(((void*)0), "#%06x", color_t_to_rgb(&colorf
->bg_color))
;
1174
1175 json_dumper_begin_object(dumper);
1176 json_dumper_set_member_name(dumper, colorf->filter_name);
1177 json_dumper_begin_object(dumper);
1178 json_dumper_set_member_name_const(dumper, "filter")json_dumper_set_member_name_noesc(dumper, "filter", sizeof("filter"
) - 1)
;
1179 json_dumper_value_string(dumper, colorf->filter_text);
1180 json_dumper_set_member_name_const(dumper, "foreground")json_dumper_set_member_name_noesc(dumper, "foreground", sizeof
("foreground") - 1)
;
1181 json_dumper_value_string(dumper, fg_str);
1182 json_dumper_set_member_name_const(dumper, "background")json_dumper_set_member_name_noesc(dumper, "background", sizeof
("background") - 1)
;
1183 json_dumper_value_string(dumper, bg_str);
1184 json_dumper_set_member_name_const(dumper, "enabled")json_dumper_set_member_name_noesc(dumper, "enabled", sizeof("enabled"
) - 1)
;
1185 json_dumper_value_anyf(dumper, "%s", colorf->enabled ? "true" : "false");
1186 json_dumper_end_object(dumper);
1187 json_dumper_end_object(dumper);
1188
1189 g_free(fg_str)(__builtin_object_size ((fg_str), 0) != ((size_t) - 1)) ? g_free_sized
(fg_str, __builtin_object_size ((fg_str), 0)) : (g_free) (fg_str
)
;
1190 g_free(bg_str)(__builtin_object_size ((bg_str), 0) != ((size_t) - 1)) ? g_free_sized
(bg_str, __builtin_object_size ((bg_str), 0)) : (g_free) (bg_str
)
;
1191 }
1192}
1193
1194/* save filters in a coloring rules file, in JSONC format */
1195static bool_Bool
1196write_filters_file(GSList *cfl, FILE *f, bool_Bool only_selected, const char* app_name)
1197{
1198 struct write_filter_jsonc_data data;
1199 json_dumper dumper = {
1200 .output_file = f,
1201 .flags = JSON_DUMPER_FLAGS_PRETTY_PRINT(1 << 0),
1202 };
1203
1204 data.dumper = &dumper;
1205 data.only_selected = only_selected;
1206
1207 fprintf(f, "// This file was created by %s. Edit with care.\n", app_name);
1208
1209 json_dumper_begin_array(&dumper);
1210 g_slist_foreach(cfl, write_jsonc_filter, &data);
1211 json_dumper_end_array(&dumper);
1212
1213 return json_dumper_finish(&dumper);
1214}
1215
1216/* save filters in users filter file(s) */
1217bool_Bool
1218color_filters_write(GSList *cfl, const char* app_name, const char* app_env_var_prefix, char** err_msg)
1219{
1220 char *pf_dir_path;
1221 char *path;
1222 FILE *f;
1223
1224 /* Create the directory that holds personal configuration files,
1225 if necessary. */
1226 if (create_persconffile_dir(app_env_var_prefix, &pf_dir_path) == -1) {
1227 *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 ())))
1228 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 ())))
;
1229 g_free(pf_dir_path)(__builtin_object_size ((pf_dir_path), 0) != ((size_t) - 1)) ?
g_free_sized (pf_dir_path, __builtin_object_size ((pf_dir_path
), 0)) : (g_free) (pf_dir_path)
;
1230 return false0;
1231 }
1232
1233 /*
1234 * Keep an existing legacy colorfilters file current for older versions,
1235 * which read only that file. Never create it.
1236 */
1237 path = get_persconffile_path(COLORFILTERS_FILE_NAME"colorfilters", true1, app_env_var_prefix);
1238 if (g_file_test(path, G_FILE_TEST_EXISTS)) {
1239 if ((f = ws_fopenfopen(path, "w+")) == NULL((void*)0)) {
1240 *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 ())))
1241 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
;
1242 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1243 return false0;
1244 }
1245 write_legacy_filters_file(cfl, f, false0, app_name);
1246 fclose(f);
1247 }
1248 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1249
1250 path = get_persconffile_path(COLORING_RULES_FILE_NAME"coloring_rules.jsonc", true1, app_env_var_prefix);
1251 if ((f = ws_fopenfopen(path, "w+")) == NULL((void*)0)) {
1252 *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 ())))
1253 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
;
1254 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1255 return false0;
1256 }
1257 write_filters_file(cfl, f, false0, app_name);
1258 fclose(f);
1259 g_free(path)(__builtin_object_size ((path), 0) != ((size_t) - 1)) ? g_free_sized
(path, __builtin_object_size ((path), 0)) : (g_free) (path)
;
1260 return true1;
1261}
1262
1263/* Save filters in the specified file (export) */
1264bool_Bool
1265color_filters_export(const char *path, GSList *cfl, bool_Bool only_marked, const char* app_name, char** err_msg)
1266{
1267 FILE *f;
1268
1269 if ((f = ws_fopenfopen(path, "w+")) == NULL((void*)0)) {
1270 *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 ())))
1271 path, g_strerror(errno))wmem_strdup_printf(((void*)0), "Could not open\n%s\nfor writing: %s."
, path, g_strerror((*__errno_location ())))
;
1272 return false0;
1273 }
1274 write_filters_file(cfl, f, only_marked, app_name);
1275 fclose(f);
1276 return true1;
1277}
1278
1279/*
1280 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1281 *
1282 * Local variables:
1283 * c-basic-offset: 4
1284 * tab-width: 8
1285 * indent-tabs-mode: nil
1286 * End:
1287 *
1288 * vi: set shiftwidth=4 tabstop=8 expandtab:
1289 * :indentSize=4:tabSize=8:noTabs=true:
1290 */