1 /*
2  * uriparser - RFC 3986 URI parsing library
3  *
4  * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
5  * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.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  *     1. Redistributions  of  source  code   must  retain  the  above
13  *        copyright notice, this list  of conditions and the following
14  *        disclaimer.
15  *
16  *     2. 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  *     3. Neither the  name of the  copyright holder nor the  names of
22  *        its 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
30  * THE  COPYRIGHT HOLDER  OR CONTRIBUTORS  BE LIABLE  FOR ANY  DIRECT,
31  * INDIRECT, 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 "UriRecompose.c"
47 #  undef URI_PASS_ANSI
48 # endif
49 # ifdef URI_ENABLE_UNICODE
50 #  define URI_PASS_UNICODE 1
51 #  include "UriRecompose.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 
71 static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
72 		int maxChars, int * charsWritten, int * charsRequired);
73 
74 
75 
URI_FUNC(ToStringCharsRequired)76 int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri,
77 		int * charsRequired) {
78 	const int MAX_CHARS = ((unsigned int)-1) >> 1;
79 	return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired);
80 }
81 
82 
83 
URI_FUNC(ToString)84 int URI_FUNC(ToString)(URI_CHAR * dest, const URI_TYPE(Uri) * uri,
85 		int maxChars, int * charsWritten) {
86 	return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL);
87 }
88 
89 
90 
URI_FUNC(ToStringEngine)91 static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest,
92 		const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten,
93 		int * charsRequired) {
94 	int written = 0;
95 	if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) {
96 		if (charsWritten != NULL) {
97 			*charsWritten = 0;
98 		}
99 		return URI_ERROR_NULL;
100 	}
101 
102 	if (maxChars < 1) {
103 		if (charsWritten != NULL) {
104 			*charsWritten = 0;
105 		}
106 		return URI_ERROR_TOSTRING_TOO_LONG;
107 	}
108 	maxChars--; /* So we don't have to subtract 1 for '\0' all the time */
109 
110 	/* [01/19]	result = "" */
111 				if (dest != NULL) {
112 					dest[0] = _UT('\0');
113 				} else {
114 					(*charsRequired) = 0;
115 				}
116 	/* [02/19]	if defined(scheme) then */
117 				if (uri->scheme.first != NULL) {
118 	/* [03/19]		append scheme to result; */
119 					const int charsToWrite
120 							= (int)(uri->scheme.afterLast - uri->scheme.first);
121 					if (dest != NULL) {
122 						if (written + charsToWrite <= maxChars) {
123 							memcpy(dest + written, uri->scheme.first,
124 									charsToWrite * sizeof(URI_CHAR));
125 							written += charsToWrite;
126 						} else {
127 							dest[0] = _UT('\0');
128 							if (charsWritten != NULL) {
129 								*charsWritten = 0;
130 							}
131 							return URI_ERROR_TOSTRING_TOO_LONG;
132 						}
133 					} else {
134 						(*charsRequired) += charsToWrite;
135 					}
136 	/* [04/19]		append ":" to result; */
137 					if (dest != NULL) {
138 						if (written + 1 <= maxChars) {
139 							memcpy(dest + written, _UT(":"),
140 									1 * sizeof(URI_CHAR));
141 							written += 1;
142 						} else {
143 							dest[0] = _UT('\0');
144 							if (charsWritten != NULL) {
145 								*charsWritten = 0;
146 							}
147 							return URI_ERROR_TOSTRING_TOO_LONG;
148 						}
149 					} else {
150 						(*charsRequired) += 1;
151 					}
152 	/* [05/19]	endif; */
153 				}
154 	/* [06/19]	if defined(authority) then */
155 				if (URI_FUNC(IsHostSet)(uri)) {
156 	/* [07/19]		append "//" to result; */
157 					if (dest != NULL) {
158 						if (written + 2 <= maxChars) {
159 							memcpy(dest + written, _UT("//"),
160 									2 * sizeof(URI_CHAR));
161 							written += 2;
162 						} else {
163 							dest[0] = _UT('\0');
164 							if (charsWritten != NULL) {
165 								*charsWritten = 0;
166 							}
167 							return URI_ERROR_TOSTRING_TOO_LONG;
168 						}
169 					} else {
170 						(*charsRequired) += 2;
171 					}
172 	/* [08/19]		append authority to result; */
173 					/* UserInfo */
174 					if (uri->userInfo.first != NULL) {
175 						const int charsToWrite = (int)(uri->userInfo.afterLast - uri->userInfo.first);
176 						if (dest != NULL) {
177 							if (written + charsToWrite <= maxChars) {
178 								memcpy(dest + written, uri->userInfo.first,
179 										charsToWrite * sizeof(URI_CHAR));
180 								written += charsToWrite;
181 							} else {
182 								dest[0] = _UT('\0');
183 								if (charsWritten != NULL) {
184 									*charsWritten = 0;
185 								}
186 								return URI_ERROR_TOSTRING_TOO_LONG;
187 							}
188 
189 							if (written + 1 <= maxChars) {
190 								memcpy(dest + written, _UT("@"),
191 										1 * sizeof(URI_CHAR));
192 								written += 1;
193 							} else {
194 								dest[0] = _UT('\0');
195 								if (charsWritten != NULL) {
196 									*charsWritten = 0;
197 								}
198 								return URI_ERROR_TOSTRING_TOO_LONG;
199 							}
200 						} else {
201 							(*charsRequired) += charsToWrite + 1;
202 						}
203 					}
204 
205 					/* Host */
206 					if (uri->hostData.ip4 != NULL) {
207 						/* IPv4 */
208 						int i = 0;
209 						for (; i < 4; i++) {
210 							const unsigned char value = uri->hostData.ip4->data[i];
211 							const int charsToWrite = (value > 99) ? 3 : ((value > 9) ? 2 : 1);
212 							if (dest != NULL) {
213 								if (written + charsToWrite <= maxChars) {
214 									URI_CHAR text[4];
215 									if (value > 99) {
216 										text[0] = _UT('0') + (value / 100);
217 										text[1] = _UT('0') + ((value % 100) / 10);
218 										text[2] = _UT('0') + (value % 10);
219 									} else if (value > 9)  {
220 										text[0] = _UT('0') + (value / 10);
221 										text[1] = _UT('0') + (value % 10);
222 									} else {
223 										text[0] = _UT('0') + value;
224 									}
225 									text[charsToWrite] = _UT('\0');
226 									memcpy(dest + written, text, charsToWrite * sizeof(URI_CHAR));
227 									written += charsToWrite;
228 								} else {
229 									dest[0] = _UT('\0');
230 									if (charsWritten != NULL) {
231 										*charsWritten = 0;
232 									}
233 									return URI_ERROR_TOSTRING_TOO_LONG;
234 								}
235 								if (i < 3) {
236 									if (written + 1 <= maxChars) {
237 										memcpy(dest + written, _UT("."),
238 												1 * sizeof(URI_CHAR));
239 										written += 1;
240 									} else {
241 										dest[0] = _UT('\0');
242 										if (charsWritten != NULL) {
243 											*charsWritten = 0;
244 										}
245 										return URI_ERROR_TOSTRING_TOO_LONG;
246 									}
247 								}
248 							} else {
249 								(*charsRequired) += charsToWrite + ((i == 3) ? 0 : 1);
250 							}
251 						}
252 					} else if (uri->hostData.ip6 != NULL) {
253 						/* IPv6 */
254 						int i = 0;
255 						if (dest != NULL) {
256 							if (written + 1 <= maxChars) {
257 								memcpy(dest + written, _UT("["),
258 										1 * sizeof(URI_CHAR));
259 								written += 1;
260 							} else {
261 								dest[0] = _UT('\0');
262 								if (charsWritten != NULL) {
263 									*charsWritten = 0;
264 								}
265 								return URI_ERROR_TOSTRING_TOO_LONG;
266 							}
267 						} else {
268 							(*charsRequired) += 1;
269 						}
270 
271 						for (; i < 16; i++) {
272 							const unsigned char value = uri->hostData.ip6->data[i];
273 							if (dest != NULL) {
274 								if (written + 2 <= maxChars) {
275 									URI_CHAR text[3];
276 									text[0] = URI_FUNC(HexToLetterEx)(value / 16, URI_FALSE);
277 									text[1] = URI_FUNC(HexToLetterEx)(value % 16, URI_FALSE);
278 									text[2] = _UT('\0');
279 									memcpy(dest + written, text, 2 * sizeof(URI_CHAR));
280 									written += 2;
281 								} else {
282 									dest[0] = _UT('\0');
283 									if (charsWritten != NULL) {
284 										*charsWritten = 0;
285 									}
286 									return URI_ERROR_TOSTRING_TOO_LONG;
287 								}
288 							} else {
289 								(*charsRequired) += 2;
290 							}
291 							if (((i & 1) == 1) && (i < 15)) {
292 								if (dest != NULL) {
293 									if (written + 1 <= maxChars) {
294 										memcpy(dest + written, _UT(":"),
295 												1 * sizeof(URI_CHAR));
296 										written += 1;
297 									} else {
298 										dest[0] = _UT('\0');
299 										if (charsWritten != NULL) {
300 											*charsWritten = 0;
301 										}
302 										return URI_ERROR_TOSTRING_TOO_LONG;
303 									}
304 								} else {
305 									(*charsRequired) += 1;
306 								}
307 							}
308 						}
309 
310 						if (dest != NULL) {
311 							if (written + 1 <= maxChars) {
312 								memcpy(dest + written, _UT("]"),
313 										1 * sizeof(URI_CHAR));
314 								written += 1;
315 							} else {
316 								dest[0] = _UT('\0');
317 								if (charsWritten != NULL) {
318 									*charsWritten = 0;
319 								}
320 								return URI_ERROR_TOSTRING_TOO_LONG;
321 							}
322 						} else {
323 							(*charsRequired) += 1;
324 						}
325 					} else if (uri->hostData.ipFuture.first != NULL) {
326 						/* IPvFuture */
327 						const int charsToWrite = (int)(uri->hostData.ipFuture.afterLast
328 								- uri->hostData.ipFuture.first);
329 						if (dest != NULL) {
330 							if (written + 1 <= maxChars) {
331 								memcpy(dest + written, _UT("["),
332 										1 * sizeof(URI_CHAR));
333 								written += 1;
334 							} else {
335 								dest[0] = _UT('\0');
336 								if (charsWritten != NULL) {
337 									*charsWritten = 0;
338 								}
339 								return URI_ERROR_TOSTRING_TOO_LONG;
340 							}
341 
342 							if (written + charsToWrite <= maxChars) {
343 								memcpy(dest + written, uri->hostData.ipFuture.first, charsToWrite * sizeof(URI_CHAR));
344 								written += charsToWrite;
345 							} else {
346 								dest[0] = _UT('\0');
347 								if (charsWritten != NULL) {
348 									*charsWritten = 0;
349 								}
350 								return URI_ERROR_TOSTRING_TOO_LONG;
351 							}
352 
353 							if (written + 1 <= maxChars) {
354 								memcpy(dest + written, _UT("]"),
355 										1 * sizeof(URI_CHAR));
356 								written += 1;
357 							} else {
358 								dest[0] = _UT('\0');
359 								if (charsWritten != NULL) {
360 									*charsWritten = 0;
361 								}
362 								return URI_ERROR_TOSTRING_TOO_LONG;
363 							}
364 						} else {
365 							(*charsRequired) += 1 + charsToWrite + 1;
366 						}
367 					} else if (uri->hostText.first != NULL) {
368 						/* Regname */
369 						const int charsToWrite = (int)(uri->hostText.afterLast - uri->hostText.first);
370 						if (dest != NULL) {
371 							if (written + charsToWrite <= maxChars) {
372 								memcpy(dest + written, uri->hostText.first,
373 										charsToWrite * sizeof(URI_CHAR));
374 								written += charsToWrite;
375 							} else {
376 								dest[0] = _UT('\0');
377 								if (charsWritten != NULL) {
378 									*charsWritten = 0;
379 								}
380 								return URI_ERROR_TOSTRING_TOO_LONG;
381 							}
382 						} else {
383 							(*charsRequired) += charsToWrite;
384 						}
385 					}
386 
387 					/* Port */
388 					if (uri->portText.first != NULL) {
389 						const int charsToWrite = (int)(uri->portText.afterLast - uri->portText.first);
390 						if (dest != NULL) {
391 							/* Leading ':' */
392 							if (written + 1 <= maxChars) {
393 									memcpy(dest + written, _UT(":"),
394 											1 * sizeof(URI_CHAR));
395 									written += 1;
396 							} else {
397 								dest[0] = _UT('\0');
398 								if (charsWritten != NULL) {
399 									*charsWritten = 0;
400 								}
401 								return URI_ERROR_TOSTRING_TOO_LONG;
402 							}
403 
404 							/* Port number */
405 							if (written + charsToWrite <= maxChars) {
406 								memcpy(dest + written, uri->portText.first,
407 										charsToWrite * sizeof(URI_CHAR));
408 								written += charsToWrite;
409 							} else {
410 								dest[0] = _UT('\0');
411 								if (charsWritten != NULL) {
412 									*charsWritten = 0;
413 								}
414 								return URI_ERROR_TOSTRING_TOO_LONG;
415 							}
416 						} else {
417 							(*charsRequired) += 1 + charsToWrite;
418 						}
419 					}
420 	/* [09/19]	endif; */
421 				}
422 	/* [10/19]	append path to result; */
423 				/* Slash needed here? */
424 				if (uri->absolutePath || ((uri->pathHead != NULL)
425 						&& URI_FUNC(IsHostSet)(uri))) {
426 					if (dest != NULL) {
427 						if (written + 1 <= maxChars) {
428 							memcpy(dest + written, _UT("/"),
429 									1 * sizeof(URI_CHAR));
430 							written += 1;
431 						} else {
432 							dest[0] = _UT('\0');
433 							if (charsWritten != NULL) {
434 								*charsWritten = 0;
435 							}
436 							return URI_ERROR_TOSTRING_TOO_LONG;
437 						}
438 					} else {
439 						(*charsRequired) += 1;
440 					}
441 				}
442 
443 				if (uri->pathHead != NULL) {
444 					URI_TYPE(PathSegment) * walker = uri->pathHead;
445 					do {
446 						const int charsToWrite = (int)(walker->text.afterLast - walker->text.first);
447 						if (dest != NULL) {
448 							if (written + charsToWrite <= maxChars) {
449 								memcpy(dest + written, walker->text.first,
450 										charsToWrite * sizeof(URI_CHAR));
451 								written += charsToWrite;
452 							} else {
453 								dest[0] = _UT('\0');
454 								if (charsWritten != NULL) {
455 									*charsWritten = 0;
456 								}
457 								return URI_ERROR_TOSTRING_TOO_LONG;
458 							}
459 						} else {
460 							(*charsRequired) += charsToWrite;
461 						}
462 
463 						/* Not last segment -> append slash */
464 						if (walker->next != NULL) {
465 							if (dest != NULL) {
466 								if (written + 1 <= maxChars) {
467 									memcpy(dest + written, _UT("/"),
468 											1 * sizeof(URI_CHAR));
469 									written += 1;
470 								} else {
471 									dest[0] = _UT('\0');
472 									if (charsWritten != NULL) {
473 										*charsWritten = 0;
474 									}
475 									return URI_ERROR_TOSTRING_TOO_LONG;
476 								}
477 							} else {
478 								(*charsRequired) += 1;
479 							}
480 						}
481 
482 						walker = walker->next;
483 					} while (walker != NULL);
484 				}
485 	/* [11/19]	if defined(query) then */
486 				if (uri->query.first != NULL) {
487 	/* [12/19]		append "?" to result; */
488 					if (dest != NULL) {
489 						if (written + 1 <= maxChars) {
490 							memcpy(dest + written, _UT("?"),
491 									1 * sizeof(URI_CHAR));
492 							written += 1;
493 						} else {
494 							dest[0] = _UT('\0');
495 							if (charsWritten != NULL) {
496 								*charsWritten = 0;
497 							}
498 							return URI_ERROR_TOSTRING_TOO_LONG;
499 						}
500 					} else {
501 						(*charsRequired) += 1;
502 					}
503 	/* [13/19]		append query to result; */
504 					{
505 						const int charsToWrite
506 								= (int)(uri->query.afterLast - uri->query.first);
507 						if (dest != NULL) {
508 							if (written + charsToWrite <= maxChars) {
509 								memcpy(dest + written, uri->query.first,
510 										charsToWrite * sizeof(URI_CHAR));
511 								written += charsToWrite;
512 							} else {
513 								dest[0] = _UT('\0');
514 								if (charsWritten != NULL) {
515 									*charsWritten = 0;
516 								}
517 								return URI_ERROR_TOSTRING_TOO_LONG;
518 							}
519 						} else {
520 							(*charsRequired) += charsToWrite;
521 						}
522 					}
523 	/* [14/19]	endif; */
524 				}
525 	/* [15/19]	if defined(fragment) then */
526 				if (uri->fragment.first != NULL) {
527 	/* [16/19]		append "#" to result; */
528 					if (dest != NULL) {
529 						if (written + 1 <= maxChars) {
530 							memcpy(dest + written, _UT("#"),
531 									1 * sizeof(URI_CHAR));
532 							written += 1;
533 						} else {
534 							dest[0] = _UT('\0');
535 							if (charsWritten != NULL) {
536 								*charsWritten = 0;
537 							}
538 							return URI_ERROR_TOSTRING_TOO_LONG;
539 						}
540 					} else {
541 						(*charsRequired) += 1;
542 					}
543 	/* [17/19]		append fragment to result; */
544 					{
545 						const int charsToWrite
546 								= (int)(uri->fragment.afterLast - uri->fragment.first);
547 						if (dest != NULL) {
548 							if (written + charsToWrite <= maxChars) {
549 								memcpy(dest + written, uri->fragment.first,
550 										charsToWrite * sizeof(URI_CHAR));
551 								written += charsToWrite;
552 							} else {
553 								dest[0] = _UT('\0');
554 								if (charsWritten != NULL) {
555 									*charsWritten = 0;
556 								}
557 								return URI_ERROR_TOSTRING_TOO_LONG;
558 							}
559 						} else {
560 							(*charsRequired) += charsToWrite;
561 						}
562 					}
563 	/* [18/19]	endif; */
564 				}
565 	/* [19/19]	return result; */
566 				if (dest != NULL) {
567 					dest[written++] = _UT('\0');
568 					if (charsWritten != NULL) {
569 						*charsWritten = written;
570 					}
571 				}
572 				return URI_SUCCESS;
573 }
574 
575 
576 
577 #endif
578