Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright 2025 GNOME Foundation, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General Public
18 : : * License along with this library; if not, write to the Free Software
19 : : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : : *
21 : : * Authors:
22 : : * - Philip Withnall <pwithnall@gnome.org>
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <glib.h>
28 : :
29 : : #include "filter-list.h"
30 : :
31 : :
32 : : /**
33 : : * mct_filter_list_parse_from_data:
34 : : * @filter_contents: (array length=filter_contents_len): contents of the filter
35 : : * list file, this may contain arbitrary byte values
36 : : * @filter_contents_len: length of @filter_contents, in bytes
37 : : * @callback: (scope call) (not nullable): callback to call for each entry
38 : : * parsed from @filter_contents
39 : : * @user_data: data to pass to @callback
40 : : * @error: return location for a [type@GLib.Error]
41 : : *
42 : : * Parse a filter list from the given data.
43 : : *
44 : : * @filter_contents is typically expected to be a memory mapped file.
45 : : *
46 : : * A filter list is a set of hostnames to filter. The format is common to many
47 : : * filter lists available on the internet:
48 : : * - At most one hostname per line
49 : : * - Lines separated by `\n` characters
50 : : * - Comment lines start with `#` and continue to the end of the line
51 : : * - Whitespace is stripped from each line and blank lines are ignored
52 : : *
53 : : * Returns: true on success, false otherwise
54 : : * Since: 0.14.0
55 : : */
56 : : gboolean
57 : 14 : mct_filter_list_parse_from_data (const char *filter_contents,
58 : : size_t filter_contents_len,
59 : : MctFilterListParseCallback callback,
60 : : void *user_data,
61 : : GError **error)
62 : : {
63 : 14 : size_t filter_contents_pos = 0;
64 : :
65 [ + + ]: 24 : while (filter_contents_pos < filter_contents_len)
66 : : {
67 : : /* Consume leading whitespace. */
68 [ + + ]: 39 : while (filter_contents_pos < filter_contents_len &&
69 [ + + ]: 36 : g_ascii_isspace (filter_contents[filter_contents_pos]))
70 : 20 : filter_contents_pos++;
71 [ + + ]: 19 : if (filter_contents_pos >= filter_contents_len)
72 : 3 : break;
73 : :
74 : : /* If the line is a comment, skip the rest of the line. */
75 [ + + ]: 16 : if (filter_contents[filter_contents_pos] == '#')
76 : : {
77 : 5 : const char *next_newline = memchr (filter_contents + filter_contents_pos,
78 : : '\n',
79 : : filter_contents_len - filter_contents_pos);
80 : :
81 [ + + ]: 5 : if (next_newline == NULL)
82 : 2 : break;
83 : :
84 : 3 : filter_contents_pos = next_newline - filter_contents + 1;
85 : : }
86 : : else
87 : : {
88 : : /* Otherwise, it’s a hostname, so grab that until the next
89 : : * newline, then chop off any trailing whitespace. */
90 : 11 : const char *hostname = filter_contents + filter_contents_pos;
91 : : size_t hostname_len;
92 : 11 : const char *next_newline = memchr (filter_contents + filter_contents_pos,
93 : : '\n',
94 : : filter_contents_len - filter_contents_pos);
95 : :
96 [ + + ]: 11 : if (next_newline == NULL)
97 : 4 : hostname_len = filter_contents_len - filter_contents_pos;
98 : : else
99 : 7 : hostname_len = next_newline - hostname;
100 : :
101 [ + - + + ]: 17 : while (hostname_len > 0 && g_ascii_isspace (hostname[hostname_len - 1]))
102 : 6 : hostname_len--;
103 : :
104 : 11 : g_assert (hostname_len > 0);
105 : :
106 : : /* Expose the parsed hostname to the caller to validate and save as
107 : : * they wish */
108 [ + + ]: 11 : if (!callback (hostname, hostname_len, user_data, error))
109 : 1 : return FALSE;
110 : :
111 [ + + ]: 10 : if (next_newline == NULL)
112 : 3 : break;
113 : :
114 : 7 : filter_contents_pos = next_newline - filter_contents + 1;
115 : : }
116 : : }
117 : :
118 : 13 : return TRUE;
119 : : }
|