Coverage Report

Created: 2025-11-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}