/src/libxmlb/src/xb-builder-fixup.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2018 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | 0 | #define G_LOG_DOMAIN "XbSilo" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include <gio/gio.h> |
12 | | |
13 | | #include "xb-builder-fixup-private.h" |
14 | | |
15 | | typedef struct { |
16 | | gchar *id; |
17 | | XbBuilderFixupFunc func; |
18 | | gpointer user_data; |
19 | | GDestroyNotify user_data_free; |
20 | | gint max_depth; |
21 | | } XbBuilderFixupPrivate; |
22 | | |
23 | 0 | G_DEFINE_TYPE_WITH_PRIVATE(XbBuilderFixup, xb_builder_fixup, G_TYPE_OBJECT) |
24 | 0 | #define GET_PRIVATE(o) (xb_builder_fixup_get_instance_private(o)) |
25 | | |
26 | | typedef struct { |
27 | | XbBuilderFixup *self; |
28 | | gboolean ret; |
29 | | GError *error; |
30 | | } XbBuilderFixupHelper; |
31 | | |
32 | | static gboolean |
33 | | xb_builder_fixup_cb(XbBuilderNode *bn, gpointer data) |
34 | 0 | { |
35 | 0 | XbBuilderFixupHelper *helper = (XbBuilderFixupHelper *)data; |
36 | 0 | XbBuilderFixup *self = XB_BUILDER_FIXUP(helper->self); |
37 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
38 | | |
39 | | /* run all node funcs on the source */ |
40 | 0 | if (!priv->func(self, bn, priv->user_data, &helper->error)) { |
41 | 0 | helper->ret = FALSE; |
42 | 0 | return TRUE; |
43 | 0 | } |
44 | | |
45 | | /* keep going */ |
46 | 0 | return FALSE; |
47 | 0 | } |
48 | | |
49 | | /* private */ |
50 | | gboolean |
51 | | xb_builder_fixup_node(XbBuilderFixup *self, XbBuilderNode *bn, GError **error) |
52 | 0 | { |
53 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
54 | 0 | XbBuilderFixupHelper helper = { |
55 | 0 | .self = self, |
56 | 0 | .ret = TRUE, |
57 | 0 | .error = NULL, |
58 | 0 | }; |
59 | | |
60 | | /* visit each node */ |
61 | 0 | xb_builder_node_traverse(bn, |
62 | 0 | G_PRE_ORDER, |
63 | 0 | G_TRAVERSE_ALL, |
64 | 0 | priv->max_depth, |
65 | 0 | xb_builder_fixup_cb, |
66 | 0 | &helper); |
67 | 0 | if (!helper.ret) { |
68 | 0 | g_propagate_error(error, helper.error); |
69 | 0 | return FALSE; |
70 | 0 | } |
71 | 0 | return TRUE; |
72 | 0 | } |
73 | | |
74 | | /** |
75 | | * xb_builder_fixup_get_id: |
76 | | * @self: a #XbBuilderFixup |
77 | | * |
78 | | * Gets the fixup ID. |
79 | | * |
80 | | * Returns: string, e.g. `AppStreamUpgrade` |
81 | | * |
82 | | * Since: 0.1.3 |
83 | | **/ |
84 | | const gchar * |
85 | | xb_builder_fixup_get_id(XbBuilderFixup *self) |
86 | 0 | { |
87 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
88 | 0 | g_return_val_if_fail(XB_IS_BUILDER_FIXUP(self), NULL); |
89 | 0 | return priv->id; |
90 | 0 | } |
91 | | |
92 | | /* private */ |
93 | | gchar * |
94 | | xb_builder_fixup_get_guid(XbBuilderFixup *self) |
95 | 0 | { |
96 | 0 | g_autoptr(GString) str = g_string_new("func-id="); |
97 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
98 | |
|
99 | 0 | g_return_val_if_fail(XB_IS_BUILDER_FIXUP(self), NULL); |
100 | | |
101 | | /* build GUID using ID and max-depth, if set */ |
102 | 0 | g_string_append(str, priv->id); |
103 | 0 | if (priv->max_depth != -1) |
104 | 0 | g_string_append_printf(str, "@%i", priv->max_depth); |
105 | 0 | return g_string_free(g_steal_pointer(&str), FALSE); |
106 | 0 | } |
107 | | |
108 | | /** |
109 | | * xb_builder_fixup_get_max_depth: |
110 | | * @self: a #XbBuilderFixup |
111 | | * |
112 | | * Gets the maximum depth used for this fixup, if each node is being visited. |
113 | | * |
114 | | * Returns: integer, or -1 if unset |
115 | | * |
116 | | * Since: 0.1.3 |
117 | | **/ |
118 | | gint |
119 | | xb_builder_fixup_get_max_depth(XbBuilderFixup *self) |
120 | 0 | { |
121 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
122 | 0 | g_return_val_if_fail(XB_IS_BUILDER_FIXUP(self), 0); |
123 | 0 | return priv->max_depth; |
124 | 0 | } |
125 | | |
126 | | /** |
127 | | * xb_builder_fixup_set_max_depth: |
128 | | * @self: a #XbBuilderFixup |
129 | | * @max_depth: integer, -1 for "all" |
130 | | * |
131 | | * Sets the maximum depth used for this fixup. Use a @max_depth of 0 to only |
132 | | * visit the root node. |
133 | | * |
134 | | * Setting a maximum depth may increase performance considerably if using |
135 | | * fixup functions on large and deeply nested XML files. |
136 | | * |
137 | | * Since: 0.1.3 |
138 | | **/ |
139 | | void |
140 | | xb_builder_fixup_set_max_depth(XbBuilderFixup *self, gint max_depth) |
141 | 0 | { |
142 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
143 | 0 | g_return_if_fail(XB_IS_BUILDER_FIXUP(self)); |
144 | 0 | priv->max_depth = max_depth; |
145 | 0 | } |
146 | | |
147 | | static void |
148 | | xb_builder_fixup_finalize(GObject *obj) |
149 | 0 | { |
150 | 0 | XbBuilderFixup *self = XB_BUILDER_FIXUP(obj); |
151 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
152 | |
|
153 | 0 | if (priv->user_data_free != NULL) |
154 | 0 | priv->user_data_free(priv->user_data); |
155 | 0 | g_free(priv->id); |
156 | |
|
157 | 0 | G_OBJECT_CLASS(xb_builder_fixup_parent_class)->finalize(obj); |
158 | 0 | } |
159 | | |
160 | | static void |
161 | | xb_builder_fixup_class_init(XbBuilderFixupClass *klass) |
162 | 0 | { |
163 | 0 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
164 | 0 | object_class->finalize = xb_builder_fixup_finalize; |
165 | 0 | } |
166 | | |
167 | | static void |
168 | | xb_builder_fixup_init(XbBuilderFixup *self) |
169 | 0 | { |
170 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
171 | 0 | priv->max_depth = -1; |
172 | 0 | } |
173 | | |
174 | | /** |
175 | | * xb_builder_fixup_new: |
176 | | * @id: a text ID value, e.g. `AppStreamUpgrade` |
177 | | * @func: a callback |
178 | | * @user_data: user pointer to pass to @func, or %NULL |
179 | | * @user_data_free: a function which gets called to free @user_data, or %NULL |
180 | | * |
181 | | * Creates a function that will get run on every #XbBuilderNode compile creates. |
182 | | * |
183 | | * Returns: a new #XbBuilderFixup |
184 | | * |
185 | | * Since: 0.1.3 |
186 | | **/ |
187 | | XbBuilderFixup * |
188 | | xb_builder_fixup_new(const gchar *id, |
189 | | XbBuilderFixupFunc func, |
190 | | gpointer user_data, |
191 | | GDestroyNotify user_data_free) |
192 | 0 | { |
193 | 0 | XbBuilderFixup *self = g_object_new(XB_TYPE_BUILDER_FIXUP, NULL); |
194 | 0 | XbBuilderFixupPrivate *priv = GET_PRIVATE(self); |
195 | |
|
196 | 0 | g_return_val_if_fail(XB_IS_BUILDER_FIXUP(self), NULL); |
197 | 0 | g_return_val_if_fail(id != NULL, NULL); |
198 | 0 | g_return_val_if_fail(func != NULL, NULL); |
199 | | |
200 | 0 | priv->id = g_strdup(id); |
201 | 0 | priv->func = func; |
202 | 0 | priv->user_data = user_data; |
203 | 0 | priv->user_data_free = user_data_free; |
204 | 0 | return self; |
205 | 0 | } |