Bug Summary

File:ctk/ctkfilefilter.c
Warning:line 374, column 29
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption

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 ctkfilefilter.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 -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/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 -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-173409-43638-1 -x c ctkfilefilter.c
1/* CTK - The GIMP Toolkit
2 * ctkfilefilter.c: Filters for selecting a file subset
3 * Copyright (C) 2003, Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * SECTION:ctkfilefilter
21 * @Short_description: A filter for selecting a file subset
22 * @Title: CtkFileFilter
23 * @see_also: #CtkFileChooser
24 *
25 * A CtkFileFilter can be used to restrict the files being shown in a
26 * #CtkFileChooser. Files can be filtered based on their name (with
27 * ctk_file_filter_add_pattern()), on their mime type (with
28 * ctk_file_filter_add_mime_type()), or by a custom filter function
29 * (with ctk_file_filter_add_custom()).
30 *
31 * Filtering by mime types handles aliasing and subclassing of mime
32 * types; e.g. a filter for text/plain also matches a file with mime
33 * type application/rtf, since application/rtf is a subclass of
34 * text/plain. Note that #CtkFileFilter allows wildcards for the
35 * subtype of a mime type, so you can e.g. filter for image/\*.
36 *
37 * Normally, filters are used by adding them to a #CtkFileChooser,
38 * see ctk_file_chooser_add_filter(), but it is also possible
39 * to manually use a filter on a file with ctk_file_filter_filter().
40 *
41 * # CtkFileFilter as CtkBuildable
42 *
43 * The CtkFileFilter implementation of the CtkBuildable interface
44 * supports adding rules using the <mime-types>, <patterns> and
45 * <applications> elements and listing the rules within. Specifying
46 * a <mime-type> or <pattern> has the same effect as as calling
47 * ctk_file_filter_add_mime_type() or ctk_file_filter_add_pattern().
48 *
49 * An example of a UI definition fragment specifying CtkFileFilter
50 * rules:
51 * |[
52 * <object class="CtkFileFilter">
53 * <mime-types>
54 * <mime-type>text/plain</mime-type>
55 * <mime-type>image/ *</mime-type>
56 * </mime-types>
57 * <patterns>
58 * <pattern>*.txt</pattern>
59 * <pattern>*.png</pattern>
60 * </patterns>
61 * </object>
62 * ]|
63 */
64
65#include "config.h"
66#include <string.h>
67
68#include <gdk-pixbuf/gdk-pixbuf.h>
69
70#include "ctkfilefilterprivate.h"
71#include "ctkbuildable.h"
72#include "ctkbuilderprivate.h"
73#include "ctkintl.h"
74#include "ctkprivate.h"
75
76typedef struct _CtkFileFilterClass CtkFileFilterClass;
77typedef struct _FilterRule FilterRule;
78
79#define CTK_FILE_FILTER_CLASS(klass)((((CtkFileFilterClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_file_filter_get_type ()))))))
(G_TYPE_CHECK_CLASS_CAST ((klass), CTK_TYPE_FILE_FILTER, CtkFileFilterClass)(((CtkFileFilterClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((klass)), ((ctk_file_filter_get_type ())))))
)
80#define CTK_IS_FILE_FILTER_CLASS(klass)(((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ctk_file_filter_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; }))))
(G_TYPE_CHECK_CLASS_TYPE ((klass), CTK_TYPE_FILE_FILTER)((__extension__ ({ GTypeClass *__class = (GTypeClass*) ((klass
)); GType __t = ((ctk_file_filter_get_type ())); gboolean __r
; if (!__class) __r = (0); else if (__class->g_type == __t
) __r = (!(0)); else __r = g_type_check_class_is_a (__class, __t
); __r; })))
)
81#define CTK_FILE_FILTER_GET_CLASS(obj)((((CtkFileFilterClass*) (((GTypeInstance*) ((obj)))->g_class
))))
(G_TYPE_INSTANCE_GET_CLASS ((obj), CTK_TYPE_FILE_FILTER, CtkFileFilterClass)(((CtkFileFilterClass*) (((GTypeInstance*) ((obj)))->g_class
)))
)
82
83typedef enum {
84 FILTER_RULE_PATTERN,
85 FILTER_RULE_MIME_TYPE,
86 FILTER_RULE_PIXBUF_FORMATS,
87 FILTER_RULE_CUSTOM
88} FilterRuleType;
89
90struct _CtkFileFilterClass
91{
92 GInitiallyUnownedClass parent_class;
93};
94
95struct _CtkFileFilter
96{
97 GInitiallyUnowned parent_instance;
98
99 gchar *name;
100 GSList *rules;
101
102 CtkFileFilterFlags needed;
103};
104
105struct _FilterRule
106{
107 FilterRuleType type;
108 CtkFileFilterFlags needed;
109
110 union {
111 gchar *pattern;
112 gchar *mime_type;
113 GSList *pixbuf_formats;
114 struct {
115 CtkFileFilterFunc func;
116 gpointer data;
117 GDestroyNotify notify;
118 } custom;
119 } u;
120};
121
122static void ctk_file_filter_finalize (GObject *object);
123
124
125static void ctk_file_filter_buildable_init (CtkBuildableIface *iface);
126static void ctk_file_filter_buildable_set_name (CtkBuildable *buildable,
127 const gchar *name);
128static const gchar* ctk_file_filter_buildable_get_name (CtkBuildable *buildable);
129
130
131static gboolean ctk_file_filter_buildable_custom_tag_start (CtkBuildable *buildable,
132 CtkBuilder *builder,
133 GObject *child,
134 const gchar *tagname,
135 GMarkupParser *parser,
136 gpointer *data);
137static void ctk_file_filter_buildable_custom_tag_end (CtkBuildable *buildable,
138 CtkBuilder *builder,
139 GObject *child,
140 const gchar *tagname,
141 gpointer *data);
142
143G_DEFINE_TYPE_WITH_CODE (CtkFileFilter, ctk_file_filter, G_TYPE_INITIALLY_UNOWNED,static void ctk_file_filter_init (CtkFileFilter *self); static
void ctk_file_filter_class_init (CtkFileFilterClass *klass);
static GType ctk_file_filter_get_type_once (void); static gpointer
ctk_file_filter_parent_class = ((void*)0); static gint CtkFileFilter_private_offset
; static void ctk_file_filter_class_intern_init (gpointer klass
) { ctk_file_filter_parent_class = g_type_class_peek_parent (
klass); if (CtkFileFilter_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkFileFilter_private_offset); ctk_file_filter_class_init
((CtkFileFilterClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_file_filter_get_instance_private
(CtkFileFilter *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkFileFilter_private_offset)))); } GType ctk_file_filter_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_file_filter_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_file_filter_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
g_initially_unowned_get_type()), g_intern_static_string ("CtkFileFilter"
), sizeof (CtkFileFilterClass), (GClassInitFunc)(void (*)(void
)) ctk_file_filter_class_intern_init, sizeof (CtkFileFilter),
(GInstanceInitFunc)(void (*)(void)) ctk_file_filter_init, (GTypeFlags
) 0); { {{ const GInterfaceInfo g_implement_interface_info = {
(GInterfaceInitFunc)(void (*)(void)) ctk_file_filter_buildable_init
, ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
144 G_IMPLEMENT_INTERFACE (CTK_TYPE_BUILDABLE,static void ctk_file_filter_init (CtkFileFilter *self); static
void ctk_file_filter_class_init (CtkFileFilterClass *klass);
static GType ctk_file_filter_get_type_once (void); static gpointer
ctk_file_filter_parent_class = ((void*)0); static gint CtkFileFilter_private_offset
; static void ctk_file_filter_class_intern_init (gpointer klass
) { ctk_file_filter_parent_class = g_type_class_peek_parent (
klass); if (CtkFileFilter_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkFileFilter_private_offset); ctk_file_filter_class_init
((CtkFileFilterClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_file_filter_get_instance_private
(CtkFileFilter *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkFileFilter_private_offset)))); } GType ctk_file_filter_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_file_filter_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_file_filter_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
g_initially_unowned_get_type()), g_intern_static_string ("CtkFileFilter"
), sizeof (CtkFileFilterClass), (GClassInitFunc)(void (*)(void
)) ctk_file_filter_class_intern_init, sizeof (CtkFileFilter),
(GInstanceInitFunc)(void (*)(void)) ctk_file_filter_init, (GTypeFlags
) 0); { {{ const GInterfaceInfo g_implement_interface_info = {
(GInterfaceInitFunc)(void (*)(void)) ctk_file_filter_buildable_init
, ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
145 ctk_file_filter_buildable_init))static void ctk_file_filter_init (CtkFileFilter *self); static
void ctk_file_filter_class_init (CtkFileFilterClass *klass);
static GType ctk_file_filter_get_type_once (void); static gpointer
ctk_file_filter_parent_class = ((void*)0); static gint CtkFileFilter_private_offset
; static void ctk_file_filter_class_intern_init (gpointer klass
) { ctk_file_filter_parent_class = g_type_class_peek_parent (
klass); if (CtkFileFilter_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkFileFilter_private_offset); ctk_file_filter_class_init
((CtkFileFilterClass*) klass); } __attribute__ ((__unused__)
) static inline gpointer ctk_file_filter_get_instance_private
(CtkFileFilter *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkFileFilter_private_offset)))); } GType ctk_file_filter_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_file_filter_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_file_filter_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
g_initially_unowned_get_type()), g_intern_static_string ("CtkFileFilter"
), sizeof (CtkFileFilterClass), (GClassInitFunc)(void (*)(void
)) ctk_file_filter_class_intern_init, sizeof (CtkFileFilter),
(GInstanceInitFunc)(void (*)(void)) ctk_file_filter_init, (GTypeFlags
) 0); { {{ const GInterfaceInfo g_implement_interface_info = {
(GInterfaceInitFunc)(void (*)(void)) ctk_file_filter_buildable_init
, ((void*)0), ((void*)0) }; g_type_add_interface_static (g_define_type_id
, (ctk_buildable_get_type ()), &g_implement_interface_info
); };} } return g_define_type_id; }
146
147static void
148ctk_file_filter_init (CtkFileFilter *object G_GNUC_UNUSED__attribute__ ((__unused__)))
149{
150}
151
152static void
153ctk_file_filter_class_init (CtkFileFilterClass *class)
154{
155 GObjectClass *gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
156
157 gobject_class->finalize = ctk_file_filter_finalize;
158}
159
160static void
161filter_rule_free (FilterRule *rule)
162{
163 switch (rule->type)
164 {
165 case FILTER_RULE_MIME_TYPE:
166 g_free (rule->u.mime_type);
167 break;
168 case FILTER_RULE_PATTERN:
169 g_free (rule->u.pattern);
170 break;
171 case FILTER_RULE_CUSTOM:
172 if (rule->u.custom.notify)
173 rule->u.custom.notify (rule->u.custom.data);
174 break;
175 case FILTER_RULE_PIXBUF_FORMATS:
176 g_slist_free (rule->u.pixbuf_formats);
177 break;
178 default:
179 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkfilefilter.c", 179,
((const char*) (__func__)), ((void*)0)); } while (0)
;
180 }
181
182 g_slice_free (FilterRule, rule)do { if (1) g_slice_free1 (sizeof (FilterRule), (rule)); else
(void) ((FilterRule*) 0 == (rule)); } while (0)
;
183}
184
185static void
186ctk_file_filter_finalize (GObject *object)
187{
188 CtkFileFilter *filter = CTK_FILE_FILTER (object)((((CtkFileFilter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_file_filter_get_type ()))))))
;
189
190 g_slist_free_full (filter->rules, (GDestroyNotify)filter_rule_free);
191
192 g_free (filter->name);
193
194 G_OBJECT_CLASS (ctk_file_filter_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_file_filter_parent_class)), (((GType) ((20) <<
(2))))))))
->finalize (object);
195}
196
197/*
198 * CtkBuildable implementation
199 */
200static void
201ctk_file_filter_buildable_init (CtkBuildableIface *iface)
202{
203 iface->custom_tag_start = ctk_file_filter_buildable_custom_tag_start;
204 iface->custom_tag_end = ctk_file_filter_buildable_custom_tag_end;
205 iface->set_name = ctk_file_filter_buildable_set_name;
206 iface->get_name = ctk_file_filter_buildable_get_name;
207}
208
209static void
210ctk_file_filter_buildable_set_name (CtkBuildable *buildable,
211 const gchar *name)
212{
213 ctk_file_filter_set_name (CTK_FILE_FILTER (buildable)((((CtkFileFilter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_file_filter_get_type ()))))))
, name);
214}
215
216static const gchar *
217ctk_file_filter_buildable_get_name (CtkBuildable *buildable)
218{
219 return ctk_file_filter_get_name (CTK_FILE_FILTER (buildable)((((CtkFileFilter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_file_filter_get_type ()))))))
);
220}
221
222typedef enum {
223 PARSE_MIME_TYPES,
224 PARSE_PATTERNS
225} ParserType;
226
227typedef struct {
228 CtkFileFilter *filter;
229 CtkBuilder *builder;
230 ParserType type;
231 GString *string;
232 gboolean parsing;
233} SubParserData;
234
235static void
236parser_start_element (GMarkupParseContext *context,
237 const gchar *element_name,
238 const gchar **names,
239 const gchar **values,
240 gpointer user_data,
241 GError **error)
242{
243 SubParserData *data = (SubParserData*)user_data;
244
245 if (!g_markup_collect_attributes (element_name, names, values, error,
246 G_MARKUP_COLLECT_INVALID, NULL((void*)0), NULL((void*)0),
247 G_MARKUP_COLLECT_INVALID))
248 {
249 _ctk_builder_prefix_error (data->builder, context, error);
250 return;
251 }
252
253 if (strcmp (element_name, "mime-types") == 0 ||
254 strcmp (element_name, "patterns") == 0)
255 {
256 if (!_ctk_builder_check_parent (data->builder, context, "object", error))
257 return;
258 }
259 else if (strcmp (element_name, "mime-type") == 0)
260 {
261 if (!_ctk_builder_check_parent (data->builder, context, "mime-types", error))
262 return;
263
264 data->parsing = TRUE(!(0));
265 }
266 else if (strcmp (element_name, "pattern") == 0)
267 {
268 if (!_ctk_builder_check_parent (data->builder, context, "patterns", error))
269 return;
270
271 data->parsing = TRUE(!(0));
272 }
273 else
274 {
275 _ctk_builder_error_unhandled_tag (data->builder, context,
276 "CtkFileFilter", element_name,
277 error);
278 }
279}
280
281static void
282parser_text_element (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
283 const gchar *text,
284 gsize text_len,
285 gpointer user_data,
286 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
287{
288 SubParserData *data = (SubParserData*)user_data;
289
290 if (data->parsing)
291 g_string_append_len (data->string, text, text_len)g_string_append_len_inline (data->string, text, text_len);
292}
293
294static void
295parser_end_element (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
296 const gchar *element_name G_GNUC_UNUSED__attribute__ ((__unused__)),
297 gpointer user_data,
298 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
299{
300 SubParserData *data = (SubParserData*)user_data;
301
302 if (data->string != NULL((void*)0) && data->string->len != 0)
303 {
304 switch (data->type)
305 {
306 case PARSE_MIME_TYPES:
307 ctk_file_filter_add_mime_type (data->filter, data->string->str);
308 break;
309 case PARSE_PATTERNS:
310 ctk_file_filter_add_pattern (data->filter, data->string->str);
311 break;
312 default:
313 break;
314 }
315 }
316
317 g_string_set_size (data->string, 0);
318 data->parsing = FALSE(0);
319}
320
321static const GMarkupParser sub_parser =
322 {
323 .start_element = parser_start_element,
324 .end_element = parser_end_element,
325 .text = parser_text_element,
326 };
327
328static gboolean
329ctk_file_filter_buildable_custom_tag_start (CtkBuildable *buildable,
330 CtkBuilder *builder,
331 GObject *child G_GNUC_UNUSED__attribute__ ((__unused__)),
332 const gchar *tagname,
333 GMarkupParser *parser,
334 gpointer *parser_data)
335{
336 SubParserData *data = NULL((void*)0);
337
338 if (strcmp (tagname, "mime-types") == 0)
339 {
340 data = g_slice_new0 (SubParserData)((SubParserData*) g_slice_alloc0 (sizeof (SubParserData)));
341 data->string = g_string_new ("");
342 data->type = PARSE_MIME_TYPES;
343 data->filter = CTK_FILE_FILTER (buildable)((((CtkFileFilter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_file_filter_get_type ()))))))
;
344 data->builder = builder;
345
346 *parser = sub_parser;
347 *parser_data = data;
348 }
349 else if (strcmp (tagname, "patterns") == 0)
350 {
351 data = g_slice_new0 (SubParserData)((SubParserData*) g_slice_alloc0 (sizeof (SubParserData)));
352 data->string = g_string_new ("");
353 data->type = PARSE_PATTERNS;
354 data->filter = CTK_FILE_FILTER (buildable)((((CtkFileFilter*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((buildable)), ((ctk_file_filter_get_type ()))))))
;
355 data->builder = builder;
356
357 *parser = sub_parser;
358 *parser_data = data;
359 }
360
361 return data != NULL((void*)0);
362}
363
364static void
365ctk_file_filter_buildable_custom_tag_end (CtkBuildable *buildable G_GNUC_UNUSED__attribute__ ((__unused__)),
366 CtkBuilder *builder G_GNUC_UNUSED__attribute__ ((__unused__)),
367 GObject *child G_GNUC_UNUSED__attribute__ ((__unused__)),
368 const gchar *tagname,
369 gpointer *user_data)
370{
371 if (strcmp (tagname, "mime-types") == 0 ||
372 strcmp (tagname, "patterns") == 0)
373 {
374 SubParserData *data = (SubParserData*)user_data;
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption
375
376 g_string_free (data->string, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(data->string), ((!(0)))) : g_string_free_and_steal (data->
string)) : (g_string_free) ((data->string), ((!(0)))))
;
377 g_slice_free (SubParserData, data)do { if (1) g_slice_free1 (sizeof (SubParserData), (data)); else
(void) ((SubParserData*) 0 == (data)); } while (0)
;
378 }
379}
380
381
382/**
383 * ctk_file_filter_new:
384 *
385 * Creates a new #CtkFileFilter with no rules added to it.
386 * Such a filter doesn’t accept any files, so is not
387 * particularly useful until you add rules with
388 * ctk_file_filter_add_mime_type(), ctk_file_filter_add_pattern(),
389 * or ctk_file_filter_add_custom(). To create a filter
390 * that accepts any file, use:
391 * |[<!-- language="C" -->
392 * CtkFileFilter *filter = ctk_file_filter_new ();
393 * ctk_file_filter_add_pattern (filter, "*");
394 * ]|
395 *
396 * Returns: a new #CtkFileFilter
397 *
398 * Since: 2.4
399 **/
400CtkFileFilter *
401ctk_file_filter_new (void)
402{
403 return g_object_new (CTK_TYPE_FILE_FILTER(ctk_file_filter_get_type ()), NULL((void*)0));
404}
405
406/**
407 * ctk_file_filter_set_name:
408 * @filter: a #CtkFileFilter
409 * @name: (allow-none): the human-readable-name for the filter, or %NULL
410 * to remove any existing name.
411 *
412 * Sets the human-readable name of the filter; this is the string
413 * that will be displayed in the file selector user interface if
414 * there is a selectable list of filters.
415 *
416 * Since: 2.4
417 **/
418void
419ctk_file_filter_set_name (CtkFileFilter *filter,
420 const gchar *name)
421{
422 g_return_if_fail (CTK_IS_FILE_FILTER (filter))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return; } } while (0)
;
423
424 g_free (filter->name);
425
426 filter->name = g_strdup (name)g_strdup_inline (name);
427}
428
429/**
430 * ctk_file_filter_get_name:
431 * @filter: a #CtkFileFilter
432 *
433 * Gets the human-readable name for the filter. See ctk_file_filter_set_name().
434 *
435 * Returns: (nullable): The human-readable name of the filter,
436 * or %NULL. This value is owned by CTK+ and must not
437 * be modified or freed.
438 *
439 * Since: 2.4
440 **/
441const gchar *
442ctk_file_filter_get_name (CtkFileFilter *filter)
443{
444 g_return_val_if_fail (CTK_IS_FILE_FILTER (filter), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return (((void*)0)); } } while
(0)
;
445
446 return filter->name;
447}
448
449static void
450file_filter_add_rule (CtkFileFilter *filter,
451 FilterRule *rule)
452{
453 filter->needed |= rule->needed;
454 filter->rules = g_slist_append (filter->rules, rule);
455}
456
457/**
458 * ctk_file_filter_add_mime_type:
459 * @filter: A #CtkFileFilter
460 * @mime_type: name of a MIME type
461 *
462 * Adds a rule allowing a given mime type to @filter.
463 *
464 * Since: 2.4
465 **/
466void
467ctk_file_filter_add_mime_type (CtkFileFilter *filter,
468 const gchar *mime_type)
469{
470 FilterRule *rule;
471
472 g_return_if_fail (CTK_IS_FILE_FILTER (filter))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return; } } while (0)
;
473 g_return_if_fail (mime_type != NULL)do { if ((mime_type != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "mime_type != NULL"); return
; } } while (0)
;
474
475 rule = g_slice_new (FilterRule)((FilterRule*) g_slice_alloc (sizeof (FilterRule)));
476 rule->type = FILTER_RULE_MIME_TYPE;
477 rule->needed = CTK_FILE_FILTER_MIME_TYPE;
478 rule->u.mime_type = g_strdup (mime_type)g_strdup_inline (mime_type);
479
480 file_filter_add_rule (filter, rule);
481}
482
483/**
484 * ctk_file_filter_add_pattern:
485 * @filter: a #CtkFileFilter
486 * @pattern: a shell style glob
487 *
488 * Adds a rule allowing a shell style glob to a filter.
489 *
490 * Since: 2.4
491 **/
492void
493ctk_file_filter_add_pattern (CtkFileFilter *filter,
494 const gchar *pattern)
495{
496 FilterRule *rule;
497
498 g_return_if_fail (CTK_IS_FILE_FILTER (filter))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return; } } while (0)
;
499 g_return_if_fail (pattern != NULL)do { if ((pattern != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "pattern != NULL"); return
; } } while (0)
;
500
501 rule = g_slice_new (FilterRule)((FilterRule*) g_slice_alloc (sizeof (FilterRule)));
502 rule->type = FILTER_RULE_PATTERN;
503 rule->needed = CTK_FILE_FILTER_DISPLAY_NAME;
504 rule->u.pattern = g_strdup (pattern)g_strdup_inline (pattern);
505
506 file_filter_add_rule (filter, rule);
507}
508
509/**
510 * ctk_file_filter_add_pixbuf_formats:
511 * @filter: a #CtkFileFilter
512 *
513 * Adds a rule allowing image files in the formats supported
514 * by GdkPixbuf.
515 *
516 * Since: 2.6
517 **/
518void
519ctk_file_filter_add_pixbuf_formats (CtkFileFilter *filter)
520{
521 FilterRule *rule;
522
523 g_return_if_fail (CTK_IS_FILE_FILTER (filter))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return; } } while (0)
;
524
525 rule = g_slice_new (FilterRule)((FilterRule*) g_slice_alloc (sizeof (FilterRule)));
526 rule->type = FILTER_RULE_PIXBUF_FORMATS;
527 rule->needed = CTK_FILE_FILTER_MIME_TYPE;
528 rule->u.pixbuf_formats = gdk_pixbuf_get_formats ();
529 file_filter_add_rule (filter, rule);
530}
531
532
533/**
534 * ctk_file_filter_add_custom:
535 * @filter: a #CtkFileFilter
536 * @needed: bitfield of flags indicating the information that the custom
537 * filter function needs.
538 * @func: callback function; if the function returns %TRUE, then
539 * the file will be displayed.
540 * @data: data to pass to @func
541 * @notify: function to call to free @data when it is no longer needed.
542 *
543 * Adds rule to a filter that allows files based on a custom callback
544 * function. The bitfield @needed which is passed in provides information
545 * about what sorts of information that the filter function needs;
546 * this allows CTK+ to avoid retrieving expensive information when
547 * it isn’t needed by the filter.
548 *
549 * Since: 2.4
550 **/
551void
552ctk_file_filter_add_custom (CtkFileFilter *filter,
553 CtkFileFilterFlags needed,
554 CtkFileFilterFunc func,
555 gpointer data,
556 GDestroyNotify notify)
557{
558 FilterRule *rule;
559
560 g_return_if_fail (CTK_IS_FILE_FILTER (filter))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((filter)); GType __t = ((ctk_file_filter_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_FILE_FILTER (filter)"); return; } } while (0)
;
561 g_return_if_fail (func != NULL)do { if ((func != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "func != NULL"); return;
} } while (0)
;
562
563 rule = g_slice_new (FilterRule)((FilterRule*) g_slice_alloc (sizeof (FilterRule)));
564 rule->type = FILTER_RULE_CUSTOM;
565 rule->needed = needed;
566 rule->u.custom.func = func;
567 rule->u.custom.data = data;
568 rule->u.custom.notify = notify;
569
570 file_filter_add_rule (filter, rule);
571}
572
573/**
574 * ctk_file_filter_get_needed:
575 * @filter: a #CtkFileFilter
576 *
577 * Gets the fields that need to be filled in for the #CtkFileFilterInfo
578 * passed to ctk_file_filter_filter()
579 *
580 * This function will not typically be used by applications; it
581 * is intended principally for use in the implementation of
582 * #CtkFileChooser.
583 *
584 * Returns: bitfield of flags indicating needed fields when
585 * calling ctk_file_filter_filter()
586 *
587 * Since: 2.4
588 **/
589CtkFileFilterFlags
590ctk_file_filter_get_needed (CtkFileFilter *filter)
591{
592 return filter->needed;
593}
594
595#ifdef CDK_WINDOWING_QUARTZ
596
597#import <Foundation/Foundation.h>
598
599NSArray * _ctk_file_filter_get_as_pattern_nsstrings (CtkFileFilter *filter)
600{
601 NSMutableArray *array = [[NSMutableArray alloc] init];
602 GSList *tmp_list;
603
604 for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
605 {
606 FilterRule *rule = tmp_list->data;
607
608 switch (rule->type)
609 {
610 case FILTER_RULE_CUSTOM:
611 [array release];
612 return NULL((void*)0);
613 break;
614 case FILTER_RULE_MIME_TYPE:
615 {
616 // convert mime-types to UTI
617 NSString *mime_type_nsstring = [NSString stringWithUTF8String: rule->u.mime_type];
618 NSString *uti_nsstring = (NSString *) UTTypeCreatePreferredIdentifierForTag (kUTTagClassMIMEType, (CFStringRef) mime_type_nsstring, NULL((void*)0));
619 if (uti_nsstring == NULL((void*)0))
620 {
621 [array release];
622 return NULL((void*)0);
623 }
624 [array addObject:uti_nsstring];
625 }
626 break;
627 case FILTER_RULE_PATTERN:
628 {
629 // patterns will need to be stripped of their leading *.
630 GString *pattern = g_string_new (rule->u.pattern);
631 if (strncmp (pattern->str, "*.", 2) == 0)
632 {
633 pattern = g_string_erase (pattern, 0, 2);
634 }
635 else if (strncmp (pattern->str, "*", 1) == 0)
636 {
637 pattern = g_string_erase (pattern, 0, 1);
638 }
639 gchar *pattern_c = g_string_free (pattern, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((pattern
), ((0))) : g_string_free_and_steal (pattern)) : (g_string_free
) ((pattern), ((0))))
;
640 NSString *pattern_nsstring = [NSString stringWithUTF8String:pattern_c];
641 g_free (pattern_c);
642 [pattern_nsstring retain];
643 [array addObject:pattern_nsstring];
644 }
645 break;
646 case FILTER_RULE_PIXBUF_FORMATS:
647 {
648 GSList *list;
649
650 for (list = rule->u.pixbuf_formats; list; list = list->next)
651 {
652 int i;
653 gchar **extensions;
654
655 extensions = gdk_pixbuf_format_get_extensions (list->data);
656
657 for (i = 0; extensions[i] != NULL((void*)0); i++)
658 {
659 NSString *extension = [NSString stringWithUTF8String: extensions[i]];
660 [extension retain];
661 [array addObject:extension];
662 }
663 g_strfreev (extensions);
664 }
665 break;
666 }
667 }
668 }
669 return array;
670}
671#endif
672
673char **
674_ctk_file_filter_get_as_patterns (CtkFileFilter *filter)
675{
676 GPtrArray *array;
677 GSList *tmp_list;
678
679 array = g_ptr_array_new_with_free_func (g_free);
680
681 for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
682 {
683 FilterRule *rule = tmp_list->data;
684
685 switch (rule->type)
686 {
687 case FILTER_RULE_CUSTOM:
688 case FILTER_RULE_MIME_TYPE:
689 g_ptr_array_free (array, TRUE(!(0)));
690 return NULL((void*)0);
691 break;
692 case FILTER_RULE_PATTERN:
693 g_ptr_array_add (array, g_strdup (rule->u.pattern)g_strdup_inline (rule->u.pattern));
694 break;
695 case FILTER_RULE_PIXBUF_FORMATS:
696 {
697 GSList *list;
698
699 for (list = rule->u.pixbuf_formats; list; list = list->next)
700 {
701 int i;
702 gchar **extensions;
703
704 extensions = gdk_pixbuf_format_get_extensions (list->data);
705
706 for (i = 0; extensions[i] != NULL((void*)0); i++)
707 g_ptr_array_add (array, g_strdup_printf ("*.%s", extensions[i]));
708
709 g_strfreev (extensions);
710 }
711 break;
712 }
713 }
714 }
715
716 g_ptr_array_add (array, NULL((void*)0)); /* Null terminate */
717 return (char **)g_ptr_array_free (array, FALSE(0));
718}
719
720/**
721 * ctk_file_filter_filter:
722 * @filter: a #CtkFileFilter
723 * @filter_info: a #CtkFileFilterInfo containing information
724 * about a file.
725 *
726 * Tests whether a file should be displayed according to @filter.
727 * The #CtkFileFilterInfo @filter_info should include
728 * the fields returned from ctk_file_filter_get_needed().
729 *
730 * This function will not typically be used by applications; it
731 * is intended principally for use in the implementation of
732 * #CtkFileChooser.
733 *
734 * Returns: %TRUE if the file should be displayed
735 *
736 * Since: 2.4
737 **/
738gboolean
739ctk_file_filter_filter (CtkFileFilter *filter,
740 const CtkFileFilterInfo *filter_info)
741{
742 GSList *tmp_list;
743
744 for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
745 {
746 FilterRule *rule = tmp_list->data;
747
748 if ((filter_info->contains & rule->needed) != rule->needed)
749 continue;
750
751 switch (rule->type)
752 {
753 case FILTER_RULE_MIME_TYPE:
754 if (filter_info->mime_type != NULL((void*)0))
755 {
756 gchar *filter_content_type, *rule_content_type;
757 gboolean match;
758
759 filter_content_type = g_content_type_from_mime_type (filter_info->mime_type);
760 rule_content_type = g_content_type_from_mime_type (rule->u.mime_type);
761 match = filter_content_type != NULL((void*)0) &&
762 rule_content_type != NULL((void*)0) &&
763 g_content_type_is_a (filter_content_type, rule_content_type);
764 g_free (filter_content_type);
765 g_free (rule_content_type);
766
767 if (match)
768 return TRUE(!(0));
769 }
770 break;
771 case FILTER_RULE_PATTERN:
772 if (filter_info->display_name != NULL((void*)0) &&
773 _ctk_fnmatch (rule->u.pattern, filter_info->display_name, FALSE(0)))
774 return TRUE(!(0));
775 break;
776 case FILTER_RULE_PIXBUF_FORMATS:
777 {
778 GSList *list;
779
780 if (!filter_info->mime_type)
781 break;
782
783 for (list = rule->u.pixbuf_formats; list; list = list->next)
784 {
785 int i;
786 gchar **mime_types;
787
788 mime_types = gdk_pixbuf_format_get_mime_types (list->data);
789
790 for (i = 0; mime_types[i] != NULL((void*)0); i++)
791 {
792 if (strcmp (mime_types[i], filter_info->mime_type) == 0)
793 {
794 g_strfreev (mime_types);
795 return TRUE(!(0));
796 }
797 }
798
799 g_strfreev (mime_types);
800 }
801 break;
802 }
803 case FILTER_RULE_CUSTOM:
804 if (rule->u.custom.func (filter_info, rule->u.custom.data))
805 return TRUE(!(0));
806 break;
807 }
808 }
809
810 return FALSE(0);
811}
812
813/**
814 * ctk_file_filter_to_gvariant:
815 * @filter: a #CtkFileFilter
816 *
817 * Serialize a file filter to an a{sv} variant.
818 *
819 * Returns: (transfer none): a new, floating, #GVariant
820 *
821 * Since: 3.22
822 */
823GVariant *
824ctk_file_filter_to_gvariant (CtkFileFilter *filter)
825{
826 GVariantBuilder builder;
827 GSList *l;
828
829 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(us)")(g_variant_type_checked_ (("a(us)"))));
830 for (l = filter->rules; l; l = l->next)
831 {
832 FilterRule *rule = l->data;
833
834 switch (rule->type)
835 {
836 case FILTER_RULE_PATTERN:
837 g_variant_builder_add (&builder, "(us)", 0, rule->u.pattern);
838 break;
839 case FILTER_RULE_MIME_TYPE:
840 g_variant_builder_add (&builder, "(us)", 1, rule->u.mime_type);
841 break;
842 case FILTER_RULE_PIXBUF_FORMATS:
843 {
844 GSList *f;
845
846 for (f = rule->u.pixbuf_formats; f; f = f->next)
847 {
848 GdkPixbufFormat *fmt = f->data;
849 gchar **mime_types;
850 int i;
851
852 mime_types = gdk_pixbuf_format_get_mime_types (fmt);
853 for (i = 0; mime_types[i]; i++)
854 g_variant_builder_add (&builder, "(us)", 1, mime_types[i]);
855 g_strfreev (mime_types);
856 }
857 }
858 break;
859 case FILTER_RULE_CUSTOM:
860 default:
861 break;
862 }
863 }
864
865 return g_variant_new ("(s@a(us))", filter->name, g_variant_builder_end (&builder));
866}
867
868/**
869 * ctk_file_filter_new_from_gvariant:
870 * @variant: an a{sv} #GVariant
871 *
872 * Deserialize a file filter from an a{sv} variant in
873 * the format produced by ctk_file_filter_to_gvariant().
874 *
875 * Returns: (transfer full): a new #CtkFileFilter object
876 *
877 * Since: 3.22
878 */
879CtkFileFilter *
880ctk_file_filter_new_from_gvariant (GVariant *variant)
881{
882 CtkFileFilter *filter;
883 GVariantIter *iter;
884 const char *name;
885 int type;
886 char *tmp;
887
888 filter = ctk_file_filter_new ();
889
890 g_variant_get (variant, "(&sa(us))", &name, &iter);
891
892 ctk_file_filter_set_name (filter, name);
893
894 while (g_variant_iter_next (iter, "(u&s)", &type, &tmp))
895 {
896 switch (type)
897 {
898 case 0:
899 ctk_file_filter_add_pattern (filter, tmp);
900 break;
901 case 1:
902 ctk_file_filter_add_mime_type (filter, tmp);
903 break;
904 default:
905 break;
906 }
907 }
908 g_variant_iter_free (iter);
909
910 return filter;
911}