Coverage Report

Created: 2026-09-03 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tinysparql/src/libtinysparql/tracker-uri.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2008-2010, Nokia <ivan.frade@nokia.com>
3
 * Copyright (C) 2010, Codeminded BVBA <abustany@gnome.org>
4
 * Copyright (C) 2016, Sam Thursfield <sam@afuera.me.uk>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the
18
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
 * Boston, MA  02110-1301, USA.
20
 */
21
22
#include "config.h"
23
24
#include <string.h>
25
26
#include <glib.h>
27
28
#include "tracker-uri.h"
29
#include "tracker-utils.h"
30
31
/* The TrackerUri GType is useful when encapsulating a URI inside a GValue.
32
 * When we generate SPARQL we need to treat URIs differently to normal strings
33
 * (one goes in "", one goes in <>) so we can't use regular G_TYPE_STRING for
34
 * them.
35
 */
36
GType
37
tracker_uri_get_type (void)
38
0
{
39
0
  static gsize g_define_type_id = 0;
40
0
  if (g_once_init_enter (&g_define_type_id)) {
41
0
    GTypeInfo info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, };
42
0
    GType type = g_type_register_static (G_TYPE_STRING,
43
0
                                         g_intern_static_string ("TrackerUri"),
44
0
                                         &info,
45
0
                                         0);
46
0
    g_once_init_leave (&g_define_type_id, type);
47
0
  }
48
0
  return g_define_type_id;
49
0
}
50
51
static const char *
52
find_conversion (const char  *format,
53
                 const char **after)
54
0
{
55
0
  const char *start = format;
56
0
  const char *cp;
57
58
0
  while (*start != '\0' && *start != '%')
59
0
    start++;
60
61
0
  if (*start == '\0') {
62
0
    *after = start;
63
0
    return NULL;
64
0
  }
65
66
0
  cp = start + 1;
67
68
0
  if (*cp == '\0') {
69
0
    *after = cp;
70
0
    return NULL;
71
0
  }
72
73
  /* Test for positional argument.  */
74
0
  if (*cp >= '0' && *cp <= '9') {
75
0
    const char *np;
76
77
0
    for (np = cp; *np >= '0' && *np <= '9'; np++)
78
0
      ;
79
0
    if (*np == '$')
80
0
      cp = np + 1;
81
0
  }
82
83
  /* Skip the flags.  */
84
0
  for (;;) {
85
0
    if (*cp == '\'' ||
86
0
        *cp == '-' ||
87
0
        *cp == '+' ||
88
0
        *cp == ' ' ||
89
0
        *cp == '#' ||
90
0
        *cp == '0')
91
0
      cp++;
92
0
    else
93
0
      break;
94
0
  }
95
96
  /* Skip the field width.  */
97
0
  if (*cp == '*') {
98
0
    cp++;
99
100
    /* Test for positional argument.  */
101
0
    if (*cp >= '0' && *cp <= '9') {
102
0
      const char *np;
103
104
0
      for (np = cp; *np >= '0' && *np <= '9'; np++)
105
0
        ;
106
0
      if (*np == '$')
107
0
        cp = np + 1;
108
0
    }
109
0
  } else {
110
0
    for (; *cp >= '0' && *cp <= '9'; cp++)
111
0
      ;
112
0
  }
113
114
  /* Skip the precision.  */
115
0
  if (*cp == '.') {
116
0
    cp++;
117
0
    if (*cp == '*') {
118
0
      cp++;
119
120
      /* Test for positional argument.  */
121
0
      if (*cp >= '0' && *cp <= '9') {
122
0
        const char *np;
123
124
0
        for (np = cp; *np >= '0' && *np <= '9'; np++)
125
0
          ;
126
0
        if (*np == '$')
127
0
          cp = np + 1;
128
0
      }
129
0
    } else {
130
0
      for (; *cp >= '0' && *cp <= '9'; cp++)
131
0
        ;
132
0
    }
133
0
  }
134
135
  /* Skip argument type/size specifiers.  */
136
0
  while (*cp == 'h' ||
137
0
         *cp == 'L' ||
138
0
         *cp == 'l' ||
139
0
         *cp == 'j' ||
140
0
         *cp == 'z' ||
141
0
         *cp == 'Z' ||
142
0
         *cp == 't')
143
0
    cp++;
144
145
  /* Skip the conversion character.  */
146
0
  cp++;
147
148
0
  *after = cp;
149
0
  return start;
150
0
}
151
152
/**
153
 * tracker_sparql_escape_uri_vprintf:
154
 * @format: a standard printf() format string, but notice
155
 *     <link linkend="string-precision">string precision pitfalls</link> documented in g_strdup_printf()
156
 * @args: the list of parameters to insert into the format string
157
 *
158
 * Formats and escapes a string for use as a URI. This function takes a `va_list`.
159
 *
160
 * Similar to the standard C vsprintf() function but safer, since it
161
 * calculates the maximum space required and allocates memory to hold
162
 * the result.
163
 *
164
 * Returns: (transfer full): a newly-allocated string holding the result.
165
 */
166
gchar *
167
tracker_sparql_escape_uri_vprintf (const gchar *format,
168
                                   va_list      args)
169
0
{
170
0
  GString *format1;
171
0
  GString *format2;
172
0
  GString *result = NULL;
173
0
  gchar *output1 = NULL;
174
0
  gchar *output2 = NULL;
175
0
  const char *p;
176
0
  gchar *op1, *op2;
177
0
  va_list args2;
178
179
0
  format1 = g_string_new (NULL);
180
0
  format2 = g_string_new (NULL);
181
0
  p = format;
182
0
  while (TRUE) {
183
0
    const char *after;
184
0
    const char *conv = find_conversion (p, &after);
185
0
    if (!conv)
186
0
      break;
187
188
0
    g_string_append_len (format1, conv, after - conv);
189
0
    g_string_append_c (format1, 'X');
190
0
    g_string_append_len (format2, conv, after - conv);
191
0
    g_string_append_c (format2, 'Y');
192
193
0
    p = after;
194
0
  }
195
196
  /* Use them to format the arguments
197
   */
198
0
  G_VA_COPY (args2, args);
199
200
0
  output1 = g_strdup_vprintf (format1->str, args);
201
0
  va_end (args);
202
0
  if (!output1) {
203
0
    va_end (args2);
204
0
    goto cleanup;
205
0
  }
206
207
0
  output2 = g_strdup_vprintf (format2->str, args2);
208
0
  va_end (args2);
209
0
  if (!output2)
210
0
    goto cleanup;
211
212
0
  result = g_string_new (NULL);
213
214
0
  op1 = output1;
215
0
  op2 = output2;
216
0
  p = format;
217
0
  while (TRUE) {
218
0
    const char *after;
219
0
    const char *output_start;
220
0
    const char *conv = find_conversion (p, &after);
221
0
    char *escaped;
222
223
0
    if (!conv) {
224
0
      g_string_append_len (result, p, after - p);
225
0
      break;
226
0
    }
227
228
0
    g_string_append_len (result, p, conv - p);
229
0
    output_start = op1;
230
0
    while (*op1 == *op2) {
231
0
      op1++;
232
0
      op2++;
233
0
    }
234
235
0
    *op1 = '\0';
236
0
    escaped = g_uri_escape_string (output_start, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT, FALSE);
237
0
    g_string_append (result, escaped);
238
0
    g_free (escaped);
239
240
0
    p = after;
241
0
    op1++;
242
0
    op2++;
243
0
  }
244
245
0
cleanup:
246
0
  g_string_free (format1, TRUE);
247
0
  g_string_free (format2, TRUE);
248
0
  g_free (output1);
249
0
  g_free (output2);
250
251
0
  if (result)
252
0
    return g_string_free (result, FALSE);
253
0
  else
254
0
    return NULL;
255
0
}
256
257
/**
258
 * tracker_sparql_escape_uri_printf:
259
 * @format: a standard printf() format string, but notice
260
 *     <link linkend="string-precision">string precision pitfalls</link> documented in g_strdup_printf()
261
 * @...: the parameters to insert into the format string
262
 *
263
 * Formats and escapes a string for use as a URI. This function takes variadic arguments.
264
 *
265
 * Returns: (transfer full): a newly-allocated string holding the result.The returned string
266
 * should be freed with g_free() when no longer needed.
267
 */
268
gchar *
269
tracker_sparql_escape_uri_printf (const gchar *format, ...)
270
0
{
271
0
  gchar *result;
272
0
  va_list args;
273
274
0
  va_start (args, format);
275
0
  result = tracker_sparql_escape_uri_vprintf (format, args);
276
0
  va_end (args);
277
278
0
  return result;
279
0
}
280
281
/**
282
 * tracker_sparql_escape_uri:
283
 * @uri: a string to be escaped, following the tracker sparql rules
284
 *
285
 * Escapes a string for use as a URI.
286
 *
287
 * Returns: (transfer full): a newly-allocated string holding the result.
288
 */
289
gchar *
290
tracker_sparql_escape_uri (const gchar *uri)
291
0
{
292
0
  gchar *result;
293
294
0
  result = tracker_sparql_escape_uri_printf ("%s", uri);
295
296
0
  return result;
297
0
}