summaryrefslogtreecommitdiffstats
path: root/plugins/uriparser/UriQuery.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/uriparser/UriQuery.c')
-rw-r--r--plugins/uriparser/UriQuery.c460
1 files changed, 460 insertions, 0 deletions
diff --git a/plugins/uriparser/UriQuery.c b/plugins/uriparser/UriQuery.c
new file mode 100644
index 0000000..7adb073
--- /dev/null
+++ b/plugins/uriparser/UriQuery.c
@@ -0,0 +1,460 @@
1/*
2 * uriparser - RFC 3986 URI parsing library
3 *
4 * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
5 * Copyright (C) 2007, Sebastian Pipping <webmaster@hartwork.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the <ORGANIZATION> nor the names of its
22 * contributors may be used to endorse or promote products
23 * derived from this software without specific prior written
24 * permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
37 * OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/* What encodings are enabled? */
41#include <uriparser/UriDefsConfig.h>
42#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
43/* Include SELF twice */
44# ifdef URI_ENABLE_ANSI
45# define URI_PASS_ANSI 1
46# include "UriQuery.c"
47# undef URI_PASS_ANSI
48# endif
49# ifdef URI_ENABLE_UNICODE
50# define URI_PASS_UNICODE 1
51# include "UriQuery.c"
52# undef URI_PASS_UNICODE
53# endif
54#else
55# ifdef URI_PASS_ANSI
56# include <uriparser/UriDefsAnsi.h>
57# else
58# include <uriparser/UriDefsUnicode.h>
59# include <wchar.h>
60# endif
61
62
63
64#ifndef URI_DOXYGEN
65# include <uriparser/Uri.h>
66# include "UriCommon.h"
67#endif
68
69
70
71static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
72 const URI_TYPE(QueryList) * queryList,
73 int maxChars, int * charsWritten, int * charsRequired,
74 UriBool spaceToPlus, UriBool normalizeBreaks);
75
76static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
77 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
78 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
79 UriBool plusToSpace, UriBreakConversion breakConversion);
80
81
82
83int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
84 int * charsRequired) {
85 const UriBool spaceToPlus = URI_TRUE;
86 const UriBool normalizeBreaks = URI_TRUE;
87
88 return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired,
89 spaceToPlus, normalizeBreaks);
90}
91
92
93
94int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
95 int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) {
96 if ((queryList == NULL) || (charsRequired == NULL)) {
97 return URI_ERROR_NULL;
98 }
99
100 return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL,
101 charsRequired, spaceToPlus, normalizeBreaks);
102}
103
104
105
106int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
107 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) {
108 const UriBool spaceToPlus = URI_TRUE;
109 const UriBool normalizeBreaks = URI_TRUE;
110
111 return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten,
112 spaceToPlus, normalizeBreaks);
113}
114
115
116
117int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
118 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
119 UriBool spaceToPlus, UriBool normalizeBreaks) {
120 if ((dest == NULL) || (queryList == NULL)) {
121 return URI_ERROR_NULL;
122 }
123
124 if (maxChars < 1) {
125 return URI_ERROR_OUTPUT_TOO_LARGE;
126 }
127
128 return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars,
129 charsWritten, NULL, spaceToPlus, normalizeBreaks);
130}
131
132
133
134int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
135 const URI_TYPE(QueryList) * queryList) {
136 const UriBool spaceToPlus = URI_TRUE;
137 const UriBool normalizeBreaks = URI_TRUE;
138
139 return URI_FUNC(ComposeQueryMallocEx)(dest, queryList,
140 spaceToPlus, normalizeBreaks);
141}
142
143
144
145int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
146 const URI_TYPE(QueryList) * queryList,
147 UriBool spaceToPlus, UriBool normalizeBreaks) {
148 int charsRequired;
149 int res;
150 URI_CHAR * queryString;
151
152 if (dest == NULL) {
153 return URI_ERROR_NULL;
154 }
155
156 /* Calculate space */
157 res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired,
158 spaceToPlus, normalizeBreaks);
159 if (res != URI_SUCCESS) {
160 return res;
161 }
162 charsRequired++;
163
164 /* Allocate space */
165 queryString = malloc(charsRequired * sizeof(URI_CHAR));
166 if (queryString == NULL) {
167 return URI_ERROR_MALLOC;
168 }
169
170 /* Put query in */
171 res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired,
172 NULL, spaceToPlus, normalizeBreaks);
173 if (res != URI_SUCCESS) {
174 free(queryString);
175 return res;
176 }
177
178 *dest = queryString;
179 return URI_SUCCESS;
180}
181
182
183
184int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
185 const URI_TYPE(QueryList) * queryList,
186 int maxChars, int * charsWritten, int * charsRequired,
187 UriBool spaceToPlus, UriBool normalizeBreaks) {
188 UriBool firstItem = URI_TRUE;
189 int ampersandLen = 0;
190 URI_CHAR * write = dest;
191
192 /* Subtract terminator */
193 if (dest == NULL) {
194 *charsRequired = 0;
195 } else {
196 maxChars--;
197 }
198
199 while (queryList != NULL) {
200 const URI_CHAR * const key = queryList->key;
201 const URI_CHAR * const value = queryList->value;
202 const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3);
203 const int keyLen = (key == NULL) ? 0 : (int)URI_STRLEN(key);
204 const int keyRequiredChars = worstCase * keyLen;
205 const int valueLen = (value == NULL) ? 0 : (int)URI_STRLEN(value);
206 const int valueRequiredChars = worstCase * valueLen;
207
208 if (dest == NULL) {
209 if (firstItem == URI_TRUE) {
210 ampersandLen = 1;
211 firstItem = URI_FALSE;
212 }
213
214 (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL)
215 ? 0
216 : 1 + valueRequiredChars);
217 } else {
218 URI_CHAR * afterKey;
219
220 if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) {
221 return URI_ERROR_OUTPUT_TOO_LARGE;
222 }
223
224 /* Copy key */
225 if (firstItem == URI_TRUE) {
226 firstItem = URI_FALSE;
227 } else {
228 write[0] = _UT('&');
229 write++;
230 }
231 afterKey = URI_FUNC(EscapeEx)(key, key + keyLen,
232 write, spaceToPlus, normalizeBreaks);
233 write += (afterKey - write);
234
235 if (value != NULL) {
236 URI_CHAR * afterValue;
237
238 if ((write - dest) + 1 + valueRequiredChars > maxChars) {
239 return URI_ERROR_OUTPUT_TOO_LARGE;
240 }
241
242 /* Copy value */
243 write[0] = _UT('=');
244 write++;
245 afterValue = URI_FUNC(EscapeEx)(value, value + valueLen,
246 write, spaceToPlus, normalizeBreaks);
247 write += (afterValue - write);
248 }
249 }
250
251 queryList = queryList->next;
252 }
253
254 if (dest != NULL) {
255 write[0] = _UT('\0');
256 if (charsWritten != NULL) {
257 *charsWritten = (int)(write - dest) + 1; /* .. for terminator */
258 }
259 }
260
261 return URI_SUCCESS;
262}
263
264
265
266UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
267 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
268 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
269 UriBool plusToSpace, UriBreakConversion breakConversion) {
270 const int keyLen = (int)(keyAfter - keyFirst);
271 const int valueLen = (int)(valueAfter - valueFirst);
272 URI_CHAR * key;
273 URI_CHAR * value;
274
275 if ((prevNext == NULL) || (itemCount == NULL)
276 || (keyFirst == NULL) || (keyAfter == NULL)
277 || (keyFirst > keyAfter) || (valueFirst > valueAfter)
278 || ((keyFirst == keyAfter)
279 && (valueFirst == NULL) && (valueAfter == NULL))) {
280 return URI_TRUE;
281 }
282
283 /* Append new empty item */
284 *prevNext = malloc(1 * sizeof(URI_TYPE(QueryList)));
285 if (*prevNext == NULL) {
286 return URI_FALSE; /* Raises malloc error */
287 }
288 (*prevNext)->next = NULL;
289
290
291 /* Fill key */
292 key = malloc((keyLen + 1) * sizeof(URI_CHAR));
293 if (key == NULL) {
294 free(*prevNext);
295 *prevNext = NULL;
296 return URI_FALSE; /* Raises malloc error */
297 }
298
299 key[keyLen] = _UT('\0');
300 if (keyLen > 0) {
301 /* Copy 1:1 */
302 memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR));
303
304 /* Unescape */
305 URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion);
306 }
307 (*prevNext)->key = key;
308
309
310 /* Fill value */
311 if (valueFirst != NULL) {
312 value = malloc((valueLen + 1) * sizeof(URI_CHAR));
313 if (value == NULL) {
314 free(key);
315 free(*prevNext);
316 *prevNext = NULL;
317 return URI_FALSE; /* Raises malloc error */
318 }
319
320 value[valueLen] = _UT('\0');
321 if (valueLen > 0) {
322 /* Copy 1:1 */
323 memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR));
324
325 /* Unescape */
326 URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion);
327 }
328 (*prevNext)->value = value;
329 } else {
330 value = NULL;
331 }
332 (*prevNext)->value = value;
333
334 (*itemCount)++;
335 return URI_TRUE;
336}
337
338
339
340void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) {
341 while (queryList != NULL) {
342 URI_TYPE(QueryList) * nextBackup = queryList->next;
343 free((URI_CHAR *)queryList->key); /* const cast */
344 free((URI_CHAR *)queryList->value); /* const cast */
345 free(queryList);
346 queryList = nextBackup;
347 }
348}
349
350
351
352int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount,
353 const URI_CHAR * first, const URI_CHAR * afterLast) {
354 const UriBool plusToSpace = URI_TRUE;
355 const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
356
357 return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast,
358 plusToSpace, breakConversion);
359}
360
361
362
363int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount,
364 const URI_CHAR * first, const URI_CHAR * afterLast,
365 UriBool plusToSpace, UriBreakConversion breakConversion) {
366 const URI_CHAR * walk = first;
367 const URI_CHAR * keyFirst = first;
368 const URI_CHAR * keyAfter = NULL;
369 const URI_CHAR * valueFirst = NULL;
370 const URI_CHAR * valueAfter = NULL;
371 URI_TYPE(QueryList) ** prevNext = dest;
372 int nullCounter;
373 int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount;
374
375 if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) {
376 return URI_ERROR_NULL;
377 }
378
379 if (first > afterLast) {
380 return URI_ERROR_RANGE_INVALID;
381 }
382
383 *dest = NULL;
384 *itemsAppended = 0;
385
386 /* Parse query string */
387 for (; walk < afterLast; walk++) {
388 switch (*walk) {
389 case _UT('&'):
390 if (valueFirst != NULL) {
391 valueAfter = walk;
392 } else {
393 keyAfter = walk;
394 }
395
396 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended,
397 keyFirst, keyAfter, valueFirst, valueAfter,
398 plusToSpace, breakConversion)
399 == URI_FALSE) {
400 /* Free list we built */
401 *itemsAppended = 0;
402 URI_FUNC(FreeQueryList)(*dest);
403 return URI_ERROR_MALLOC;
404 }
405
406 /* Make future items children of the current */
407 if ((prevNext != NULL) && (*prevNext != NULL)) {
408 prevNext = &((*prevNext)->next);
409 }
410
411 if (walk + 1 < afterLast) {
412 keyFirst = walk + 1;
413 } else {
414 keyFirst = NULL;
415 }
416 keyAfter = NULL;
417 valueFirst = NULL;
418 valueAfter = NULL;
419 break;
420
421 case _UT('='):
422 /* NOTE: WE treat the first '=' as a separator, */
423 /* all following go into the value part */
424 if (keyAfter == NULL) {
425 keyAfter = walk;
426 if (walk + 1 <= afterLast) {
427 valueFirst = walk + 1;
428 valueAfter = walk + 1;
429 }
430 }
431 break;
432
433 default:
434 break;
435 }
436 }
437
438 if (valueFirst != NULL) {
439 /* Must be key/value pair */
440 valueAfter = walk;
441 } else {
442 /* Must be key only */
443 keyAfter = walk;
444 }
445
446 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter,
447 valueFirst, valueAfter, plusToSpace, breakConversion)
448 == URI_FALSE) {
449 /* Free list we built */
450 *itemsAppended = 0;
451 URI_FUNC(FreeQueryList)(*dest);
452 return URI_ERROR_MALLOC;
453 }
454
455 return URI_SUCCESS;
456}
457
458
459
460#endif