No issues found
1 /*
2 * Copyright (C) 2008-2010, Nokia <ivan.frade@nokia.com>
3 * Copyright (C) 2010, Codeminded BVBA <abustany@gnome.org>
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.1 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, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <glib.h>
26
27 gchar *
28 tracker_sparql_escape_uri_vprintf (const gchar *format,
29 va_list args);
30 gchar *
31 tracker_sparql_escape_uri_printf (const gchar* format,
32 ...);
33
34 static const char *
35 find_conversion (const char *format,
36 const char **after)
37 {
38 const char *start = format;
39 const char *cp;
40
41 while (*start != '\0' && *start != '%')
42 start++;
43
44 if (*start == '\0') {
45 *after = start;
46 return NULL;
47 }
48
49 cp = start + 1;
50
51 if (*cp == '\0') {
52 *after = cp;
53 return NULL;
54 }
55
56 /* Test for positional argument. */
57 if (*cp >= '0' && *cp <= '9') {
58 const char *np;
59
60 for (np = cp; *np >= '0' && *np <= '9'; np++)
61 ;
62 if (*np == '$')
63 cp = np + 1;
64 }
65
66 /* Skip the flags. */
67 for (;;) {
68 if (*cp == '\'' ||
69 *cp == '-' ||
70 *cp == '+' ||
71 *cp == ' ' ||
72 *cp == '#' ||
73 *cp == '0')
74 cp++;
75 else
76 break;
77 }
78
79 /* Skip the field width. */
80 if (*cp == '*') {
81 cp++;
82
83 /* Test for positional argument. */
84 if (*cp >= '0' && *cp <= '9') {
85 const char *np;
86
87 for (np = cp; *np >= '0' && *np <= '9'; np++)
88 ;
89 if (*np == '$')
90 cp = np + 1;
91 }
92 } else {
93 for (; *cp >= '0' && *cp <= '9'; cp++)
94 ;
95 }
96
97 /* Skip the precision. */
98 if (*cp == '.') {
99 cp++;
100 if (*cp == '*') {
101 /* Test for positional argument. */
102 if (*cp >= '0' && *cp <= '9') {
103 const char *np;
104
105 for (np = cp; *np >= '0' && *np <= '9'; np++)
106 ;
107 if (*np == '$')
108 cp = np + 1;
109 }
110 } else {
111 for (; *cp >= '0' && *cp <= '9'; cp++)
112 ;
113 }
114 }
115
116 /* Skip argument type/size specifiers. */
117 while (*cp == 'h' ||
118 *cp == 'L' ||
119 *cp == 'l' ||
120 *cp == 'j' ||
121 *cp == 'z' ||
122 *cp == 'Z' ||
123 *cp == 't')
124 cp++;
125
126 /* Skip the conversion character. */
127 cp++;
128
129 *after = cp;
130 return start;
131 }
132
133 /**
134 * tracker_sparql_escape_uri_vprintf:
135 * @format: a standard printf() format string, but notice
136 * <link linkend="string-precision">string precision pitfalls</link> documented in g_strdup_printf()
137 * @args: the list of parameters to insert into the format string
138 *
139 * Similar to the standard C vsprintf() function but safer, since it
140 * calculates the maximum space required and allocates memory to hold
141 * the result.
142 *
143 * The result is escaped using g_uri_escape_string().
144 *
145 * Returns: a newly-allocated string holding the result. The returned string
146 * should be freed with g_free() when no longer needed.
147 *
148 * Since: 0.10
149 */
150 gchar *
151 tracker_sparql_escape_uri_vprintf (const gchar *format,
152 va_list args)
153 {
154 GString *format1;
155 GString *format2;
156 GString *result = NULL;
157 gchar *output1 = NULL;
158 gchar *output2 = NULL;
159 const char *p;
160 gchar *op1, *op2;
161 va_list args2;
162
163 format1 = g_string_new (NULL);
164 format2 = g_string_new (NULL);
165 p = format;
166 while (TRUE) {
167 const char *after;
168 const char *conv = find_conversion (p, &after);
169 if (!conv)
170 break;
171
172 g_string_append_len (format1, conv, after - conv);
173 g_string_append_c (format1, 'X');
174 g_string_append_len (format2, conv, after - conv);
175 g_string_append_c (format2, 'Y');
176
177 p = after;
178 }
179
180 /* Use them to format the arguments
181 */
182 G_VA_COPY (args2, args);
183
184 output1 = g_strdup_vprintf (format1->str, args);
185 va_end (args);
186 if (!output1) {
187 va_end (args2);
188 goto cleanup;
189 }
190
191 output2 = g_strdup_vprintf (format2->str, args2);
192 va_end (args2);
193 if (!output2)
194 goto cleanup;
195
196 result = g_string_new (NULL);
197
198 op1 = output1;
199 op2 = output2;
200 p = format;
201 while (TRUE) {
202 const char *after;
203 const char *output_start;
204 const char *conv = find_conversion (p, &after);
205 char *escaped;
206
207 if (!conv) {
208 g_string_append_len (result, p, after - p);
209 break;
210 }
211
212 g_string_append_len (result, p, conv - p);
213 output_start = op1;
214 while (*op1 == *op2) {
215 op1++;
216 op2++;
217 }
218
219 *op1 = '\0';
220 escaped = g_uri_escape_string (output_start, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT, FALSE);
221 g_string_append (result, escaped);
222 g_free (escaped);
223
224 p = after;
225 op1++;
226 op2++;
227 }
228
229 cleanup:
230 g_string_free (format1, TRUE);
231 g_string_free (format2, TRUE);
232 g_free (output1);
233 g_free (output2);
234
235 if (result)
236 return g_string_free (result, FALSE);
237 else
238 return NULL;
239 }
240
241 /**
242 * tracker_sparql_escape_uri_printf:
243 * @format: a standard printf() format string, but notice
244 * <link linkend="string-precision">string precision pitfalls</link> documented in g_strdup_printf()
245 * @...: the parameters to insert into the format string
246 *
247 * Calls tracker_sparql_escape_uri_vprintf() with the @... supplied.
248 *
249 * Returns: a newly-allocated string holding the result.The returned string
250 * should be freed with g_free() when no longer needed.
251 *
252 * Since: 0.10
253 */
254 gchar *
255 tracker_sparql_escape_uri_printf (const gchar *format, ...)
256 {
257 gchar *result;
258 va_list args;
259
260 va_start (args, format);
261 result = tracker_sparql_escape_uri_vprintf (format, args);
262 va_end (args);
263
264 return result;
265 }