/src/uriparser/src/UriRecompose.c
Line | Count | Source |
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 | | # ifndef URI_DOXYGEN |
63 | | # include <uriparser/Uri.h> |
64 | | # include "UriCommon.h" |
65 | | # endif |
66 | | |
67 | | # include <limits.h> // INT_MAX |
68 | | # include <stdint.h> // SIZE_MAX |
69 | | |
70 | | static int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, |
71 | | int maxChars, int * charsWritten, int * charsRequired); |
72 | | |
73 | 0 | int URI_FUNC(ToStringCharsRequired)(const URI_TYPE(Uri) * uri, int * charsRequired) { |
74 | 0 | const int MAX_CHARS = ((unsigned int)-1) >> 1; |
75 | 0 | return URI_FUNC(ToStringEngine)(NULL, uri, MAX_CHARS, NULL, charsRequired); |
76 | 0 | } Unexecuted instantiation: uriToStringCharsRequiredA Unexecuted instantiation: uriToStringCharsRequiredW |
77 | | |
78 | | int URI_FUNC(ToString)( |
79 | 9.85k | URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten) { |
80 | 9.85k | return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL); |
81 | 9.85k | } Unexecuted instantiation: uriToStringA Line | Count | Source | 79 | 9.85k | URI_CHAR * dest, const URI_TYPE(Uri) * uri, int maxChars, int * charsWritten) { | 80 | 9.85k | return URI_FUNC(ToStringEngine)(dest, uri, maxChars, charsWritten, NULL); | 81 | 9.85k | } |
|
82 | | |
83 | | static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(Uri) * uri, |
84 | 9.85k | int maxChars, int * charsWritten, int * charsRequired) { |
85 | 9.85k | int written = 0; |
86 | 9.85k | if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) { |
87 | 0 | if (charsWritten != NULL) { |
88 | 0 | *charsWritten = 0; |
89 | 0 | } |
90 | 0 | return URI_ERROR_NULL; |
91 | 0 | } |
92 | | |
93 | 9.85k | if (maxChars < 1) { |
94 | 0 | if (charsWritten != NULL) { |
95 | 0 | *charsWritten = 0; |
96 | 0 | } |
97 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
98 | 0 | } |
99 | 9.85k | maxChars--; /* So we don't have to subtract 1 for '\0' all the time */ |
100 | | |
101 | | /* NOTE: The curly brackets here force deeper indent (and that's all) */ |
102 | 9.85k | { |
103 | 9.85k | { |
104 | 9.85k | { |
105 | | /* clang-format off */ |
106 | | /* [01/19] result = "" */ |
107 | | /* clang-format on */ |
108 | 9.85k | if (dest != NULL) { |
109 | 9.85k | dest[0] = _UT('\0'); |
110 | 9.85k | } else { |
111 | 0 | (*charsRequired) = 0; |
112 | 0 | } |
113 | | /* clang-format off */ |
114 | | /* [02/19] if defined(scheme) then */ |
115 | | /* clang-format on */ |
116 | 9.85k | if (uri->scheme.first != NULL) { |
117 | | /* clang-format off */ |
118 | | /* [03/19] append scheme to result; */ |
119 | | /* clang-format on */ |
120 | 492 | const size_t charsToWrite = uri->scheme.afterLast - uri->scheme.first; |
121 | 492 | if (dest != NULL) { |
122 | | // Detect and avoid integer overflow |
123 | 492 | if (charsToWrite > (size_t)INT_MAX - written) { |
124 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
125 | 0 | } |
126 | | |
127 | 492 | if (written + charsToWrite <= (size_t)maxChars) { |
128 | | // Detect and avoid integer overflow |
129 | 476 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
130 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
131 | 0 | } |
132 | | |
133 | 476 | memcpy(dest + written, uri->scheme.first, |
134 | 476 | charsToWrite * sizeof(URI_CHAR)); |
135 | 476 | written += charsToWrite; |
136 | 476 | } else { |
137 | 16 | dest[0] = _UT('\0'); |
138 | 16 | if (charsWritten != NULL) { |
139 | 16 | *charsWritten = 0; |
140 | 16 | } |
141 | 16 | return URI_ERROR_TOSTRING_TOO_LONG; |
142 | 16 | } |
143 | 492 | } else { |
144 | | // Detect and avoid integer overflow |
145 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { |
146 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
147 | 0 | } |
148 | | |
149 | 0 | (*charsRequired) += charsToWrite; |
150 | 0 | } |
151 | | /* clang-format off */ |
152 | | /* [04/19] append ":" to result; */ |
153 | | /* clang-format on */ |
154 | 476 | if (dest != NULL) { |
155 | 476 | if (written + 1 <= maxChars) { |
156 | 475 | memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); |
157 | 475 | written += 1; |
158 | 475 | } else { |
159 | 1 | dest[0] = _UT('\0'); |
160 | 1 | if (charsWritten != NULL) { |
161 | 1 | *charsWritten = 0; |
162 | 1 | } |
163 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
164 | 1 | } |
165 | 476 | } else { |
166 | | // Detect and avoid integer overflow |
167 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
168 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
169 | 0 | } |
170 | | |
171 | 0 | (*charsRequired) += 1; |
172 | 0 | } |
173 | | /* clang-format off */ |
174 | | /* [05/19] endif; */ |
175 | | /* clang-format on */ |
176 | 476 | } |
177 | | /* clang-format off */ |
178 | | /* [06/19] if defined(authority) then */ |
179 | | /* clang-format on */ |
180 | 9.83k | if (URI_FUNC(HasHost)(uri)) { |
181 | | /* clang-format off */ |
182 | | /* [07/19] append "//" to result; */ |
183 | | /* clang-format on */ |
184 | 1.03k | if (dest != NULL) { |
185 | 1.03k | if (written + 2 <= maxChars) { |
186 | 1.03k | memcpy(dest + written, _UT("//"), 2 * sizeof(URI_CHAR)); |
187 | 1.03k | written += 2; |
188 | 1.03k | } else { |
189 | 2 | dest[0] = _UT('\0'); |
190 | 2 | if (charsWritten != NULL) { |
191 | 2 | *charsWritten = 0; |
192 | 2 | } |
193 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
194 | 2 | } |
195 | 1.03k | } else { |
196 | | // Detect and avoid integer overflow |
197 | 0 | if (2 > (size_t)INT_MAX - *charsRequired) { |
198 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
199 | 0 | } |
200 | | |
201 | 0 | (*charsRequired) += 2; |
202 | 0 | } |
203 | | /* clang-format off */ |
204 | | /* [08/19] append authority to result; */ |
205 | | /* clang-format on */ |
206 | | /* UserInfo */ |
207 | 1.03k | if (uri->userInfo.first != NULL) { |
208 | 286 | const size_t charsToWrite = |
209 | 286 | uri->userInfo.afterLast - uri->userInfo.first; |
210 | 286 | if (dest != NULL) { |
211 | | // Detect and avoid integer overflow |
212 | 286 | if (charsToWrite > (size_t)INT_MAX - written) { |
213 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
214 | 0 | } |
215 | | |
216 | 286 | if (written + charsToWrite <= (size_t)maxChars) { |
217 | | // Detect and avoid integer overflow |
218 | 273 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
219 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
220 | 0 | } |
221 | | |
222 | 273 | memcpy(dest + written, uri->userInfo.first, |
223 | 273 | charsToWrite * sizeof(URI_CHAR)); |
224 | 273 | written += charsToWrite; |
225 | 273 | } else { |
226 | 13 | dest[0] = _UT('\0'); |
227 | 13 | if (charsWritten != NULL) { |
228 | 13 | *charsWritten = 0; |
229 | 13 | } |
230 | 13 | return URI_ERROR_TOSTRING_TOO_LONG; |
231 | 13 | } |
232 | | |
233 | 273 | if (written + 1 <= maxChars) { |
234 | 271 | memcpy(dest + written, _UT("@"), 1 * sizeof(URI_CHAR)); |
235 | 271 | written += 1; |
236 | 271 | } else { |
237 | 2 | dest[0] = _UT('\0'); |
238 | 2 | if (charsWritten != NULL) { |
239 | 2 | *charsWritten = 0; |
240 | 2 | } |
241 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
242 | 2 | } |
243 | 273 | } else { |
244 | | // Detect and avoid integer overflow |
245 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1) |
246 | 0 | || (charsToWrite + 1 |
247 | 0 | > (size_t)INT_MAX - *charsRequired)) { |
248 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
249 | 0 | } |
250 | | |
251 | 0 | (*charsRequired) += charsToWrite + 1; |
252 | 0 | } |
253 | 286 | } |
254 | | |
255 | | /* Host */ |
256 | 1.01k | if (uri->hostData.ip4 != NULL) { |
257 | | /* IPv4 */ |
258 | 49 | int i = 0; |
259 | 238 | for (; i < 4; i++) { |
260 | 192 | const unsigned char value = uri->hostData.ip4->data[i]; |
261 | 192 | const int charsToWrite = |
262 | 192 | (value > 99) ? 3 : ((value > 9) ? 2 : 1); |
263 | 192 | if (dest != NULL) { |
264 | 192 | if (written + charsToWrite <= maxChars) { |
265 | 190 | URI_CHAR text[4]; |
266 | 190 | if (value > 99) { |
267 | 16 | text[0] = _UT('0') + (value / 100); |
268 | 16 | text[1] = _UT('0') + ((value % 100) / 10); |
269 | 16 | text[2] = _UT('0') + (value % 10); |
270 | 174 | } else if (value > 9) { |
271 | 35 | text[0] = _UT('0') + (value / 10); |
272 | 35 | text[1] = _UT('0') + (value % 10); |
273 | 139 | } else { |
274 | 139 | text[0] = _UT('0') + value; |
275 | 139 | } |
276 | 190 | text[charsToWrite] = _UT('\0'); |
277 | 190 | memcpy(dest + written, text, |
278 | 190 | charsToWrite * sizeof(URI_CHAR)); |
279 | 190 | written += charsToWrite; |
280 | 190 | } else { |
281 | 2 | dest[0] = _UT('\0'); |
282 | 2 | if (charsWritten != NULL) { |
283 | 2 | *charsWritten = 0; |
284 | 2 | } |
285 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
286 | 2 | } |
287 | 190 | if (i < 3) { |
288 | 144 | if (written + 1 <= maxChars) { |
289 | 143 | memcpy(dest + written, _UT("."), |
290 | 143 | 1 * sizeof(URI_CHAR)); |
291 | 143 | written += 1; |
292 | 143 | } else { |
293 | 1 | dest[0] = _UT('\0'); |
294 | 1 | if (charsWritten != NULL) { |
295 | 1 | *charsWritten = 0; |
296 | 1 | } |
297 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
298 | 1 | } |
299 | 144 | } |
300 | 190 | } else { |
301 | 0 | const int extra = (i == 3) ? 0 : 1; |
302 | | |
303 | | // Detect and avoid integer overflow |
304 | 0 | if (charsToWrite > INT_MAX - extra |
305 | 0 | || charsToWrite + extra |
306 | 0 | > INT_MAX - *charsRequired) { |
307 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
308 | 0 | } |
309 | | |
310 | 0 | (*charsRequired) += charsToWrite + extra; |
311 | 0 | } |
312 | 192 | } |
313 | 968 | } else if (uri->hostData.ip6 != NULL) { |
314 | | /* IPv6 */ |
315 | 224 | int i = 0; |
316 | 224 | if (dest != NULL) { |
317 | 224 | if (written + 1 <= maxChars) { |
318 | 223 | memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); |
319 | 223 | written += 1; |
320 | 223 | } else { |
321 | 1 | dest[0] = _UT('\0'); |
322 | 1 | if (charsWritten != NULL) { |
323 | 1 | *charsWritten = 0; |
324 | 1 | } |
325 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
326 | 1 | } |
327 | 224 | } else { |
328 | | // Detect and avoid integer overflow |
329 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
330 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
331 | 0 | } |
332 | | |
333 | 0 | (*charsRequired) += 1; |
334 | 0 | } |
335 | | |
336 | 3.70k | for (; i < 16; i++) { |
337 | 3.49k | const unsigned char value = uri->hostData.ip6->data[i]; |
338 | 3.49k | if (dest != NULL) { |
339 | 3.49k | if (written + 2 <= maxChars) { |
340 | 3.48k | URI_CHAR text[3]; |
341 | 3.48k | text[0] = URI_FUNC(HexToLetterEx)( |
342 | 3.48k | value / 16, URI_FALSE); |
343 | 3.48k | text[1] = URI_FUNC(HexToLetterEx)( |
344 | 3.48k | value % 16, URI_FALSE); |
345 | 3.48k | text[2] = _UT('\0'); |
346 | 3.48k | memcpy(dest + written, text, 2 * sizeof(URI_CHAR)); |
347 | 3.48k | written += 2; |
348 | 3.48k | } else { |
349 | 6 | dest[0] = _UT('\0'); |
350 | 6 | if (charsWritten != NULL) { |
351 | 6 | *charsWritten = 0; |
352 | 6 | } |
353 | 6 | return URI_ERROR_TOSTRING_TOO_LONG; |
354 | 6 | } |
355 | 3.49k | } else { |
356 | | // Detect and avoid integer overflow |
357 | 0 | if (2 > (size_t)INT_MAX - *charsRequired) { |
358 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
359 | 0 | } |
360 | | |
361 | 0 | (*charsRequired) += 2; |
362 | 0 | } |
363 | 3.48k | if (((i & 1) == 1) && (i < 15)) { |
364 | 1.52k | if (dest != NULL) { |
365 | 1.52k | if (written + 1 <= maxChars) { |
366 | 1.52k | memcpy(dest + written, _UT(":"), |
367 | 1.52k | 1 * sizeof(URI_CHAR)); |
368 | 1.52k | written += 1; |
369 | 1.52k | } else { |
370 | 2 | dest[0] = _UT('\0'); |
371 | 2 | if (charsWritten != NULL) { |
372 | 2 | *charsWritten = 0; |
373 | 2 | } |
374 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
375 | 2 | } |
376 | 1.52k | } else { |
377 | | // Detect and avoid integer overflow |
378 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
379 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
380 | 0 | } |
381 | | |
382 | 0 | (*charsRequired) += 1; |
383 | 0 | } |
384 | 1.52k | } |
385 | 3.48k | } |
386 | | |
387 | 215 | if (dest != NULL) { |
388 | 215 | if (written + 1 <= maxChars) { |
389 | 214 | memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); |
390 | 214 | written += 1; |
391 | 214 | } else { |
392 | 1 | dest[0] = _UT('\0'); |
393 | 1 | if (charsWritten != NULL) { |
394 | 1 | *charsWritten = 0; |
395 | 1 | } |
396 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
397 | 1 | } |
398 | 215 | } else { |
399 | | // Detect and avoid integer overflow |
400 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
401 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
402 | 0 | } |
403 | | |
404 | 0 | (*charsRequired) += 1; |
405 | 0 | } |
406 | 744 | } else if (uri->hostData.ipFuture.first != NULL) { |
407 | | /* IPvFuture */ |
408 | 196 | const size_t charsToWrite = uri->hostData.ipFuture.afterLast |
409 | 196 | - uri->hostData.ipFuture.first; |
410 | 196 | if (dest != NULL) { |
411 | 196 | if (written + 1 <= maxChars) { |
412 | 195 | memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); |
413 | 195 | written += 1; |
414 | 195 | } else { |
415 | 1 | dest[0] = _UT('\0'); |
416 | 1 | if (charsWritten != NULL) { |
417 | 1 | *charsWritten = 0; |
418 | 1 | } |
419 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
420 | 1 | } |
421 | | |
422 | | // Detect and avoid integer overflow |
423 | 195 | if (charsToWrite > (size_t)INT_MAX - written) { |
424 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
425 | 0 | } |
426 | | |
427 | 195 | if (written + charsToWrite <= (size_t)maxChars) { |
428 | | // Detect and avoid integer overflow |
429 | 172 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
430 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
431 | 0 | } |
432 | | |
433 | 172 | memcpy(dest + written, uri->hostData.ipFuture.first, |
434 | 172 | charsToWrite * sizeof(URI_CHAR)); |
435 | 172 | written += charsToWrite; |
436 | 172 | } else { |
437 | 23 | dest[0] = _UT('\0'); |
438 | 23 | if (charsWritten != NULL) { |
439 | 23 | *charsWritten = 0; |
440 | 23 | } |
441 | 23 | return URI_ERROR_TOSTRING_TOO_LONG; |
442 | 23 | } |
443 | | |
444 | 172 | if (written + 1 <= maxChars) { |
445 | 171 | memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); |
446 | 171 | written += 1; |
447 | 171 | } else { |
448 | 1 | dest[0] = _UT('\0'); |
449 | 1 | if (charsWritten != NULL) { |
450 | 1 | *charsWritten = 0; |
451 | 1 | } |
452 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
453 | 1 | } |
454 | 172 | } else { |
455 | | // Detect and avoid integer overflow |
456 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1 - 1) |
457 | 0 | || (1 + charsToWrite + 1 |
458 | 0 | > (size_t)INT_MAX - *charsRequired)) { |
459 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
460 | 0 | } |
461 | | |
462 | 0 | (*charsRequired) += 1 + charsToWrite + 1; |
463 | 0 | } |
464 | 548 | } else if (uri->hostText.first != NULL) { |
465 | | /* Regname */ |
466 | 548 | const size_t charsToWrite = |
467 | 548 | uri->hostText.afterLast - uri->hostText.first; |
468 | 548 | if (dest != NULL) { |
469 | | // Detect and avoid integer overflow |
470 | 548 | if (charsToWrite > (size_t)INT_MAX - written) { |
471 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
472 | 0 | } |
473 | | |
474 | 548 | if (written + charsToWrite <= (size_t)maxChars) { |
475 | | // Detect and avoid integer overflow |
476 | 526 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
477 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
478 | 0 | } |
479 | | |
480 | 526 | memcpy(dest + written, uri->hostText.first, |
481 | 526 | charsToWrite * sizeof(URI_CHAR)); |
482 | 526 | written += charsToWrite; |
483 | 526 | } else { |
484 | 22 | dest[0] = _UT('\0'); |
485 | 22 | if (charsWritten != NULL) { |
486 | 22 | *charsWritten = 0; |
487 | 22 | } |
488 | 22 | return URI_ERROR_TOSTRING_TOO_LONG; |
489 | 22 | } |
490 | 548 | } else { |
491 | | // Detect and avoid integer overflow |
492 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { |
493 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
494 | 0 | } |
495 | | |
496 | 0 | (*charsRequired) += charsToWrite; |
497 | 0 | } |
498 | 548 | } |
499 | | |
500 | | /* Port */ |
501 | 957 | if (uri->portText.first != NULL) { |
502 | 88 | const size_t charsToWrite = |
503 | 88 | uri->portText.afterLast - uri->portText.first; |
504 | 88 | if (dest != NULL) { |
505 | | /* Leading ':' */ |
506 | 88 | if (written + 1 <= maxChars) { |
507 | 86 | memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); |
508 | 86 | written += 1; |
509 | 86 | } else { |
510 | 2 | dest[0] = _UT('\0'); |
511 | 2 | if (charsWritten != NULL) { |
512 | 2 | *charsWritten = 0; |
513 | 2 | } |
514 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
515 | 2 | } |
516 | | |
517 | | // Detect and avoid integer overflow |
518 | 86 | if (charsToWrite > (size_t)INT_MAX - written) { |
519 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
520 | 0 | } |
521 | | |
522 | | /* Port number */ |
523 | 86 | if (written + charsToWrite <= (size_t)maxChars) { |
524 | | // Detect and avoid integer overflow |
525 | 85 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
526 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
527 | 0 | } |
528 | | |
529 | 85 | memcpy(dest + written, uri->portText.first, |
530 | 85 | charsToWrite * sizeof(URI_CHAR)); |
531 | 85 | written += charsToWrite; |
532 | 85 | } else { |
533 | 1 | dest[0] = _UT('\0'); |
534 | 1 | if (charsWritten != NULL) { |
535 | 1 | *charsWritten = 0; |
536 | 1 | } |
537 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
538 | 1 | } |
539 | 86 | } else { |
540 | | // Detect and avoid integer overflow |
541 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1) |
542 | 0 | || (1 + charsToWrite |
543 | 0 | > (size_t)INT_MAX - *charsRequired)) { |
544 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
545 | 0 | } |
546 | | |
547 | 0 | (*charsRequired) += 1 + charsToWrite; |
548 | 0 | } |
549 | 88 | } |
550 | | /* clang-format off */ |
551 | | /* [09/19] endif; */ |
552 | | /* clang-format on */ |
553 | 957 | } |
554 | | /* clang-format off */ |
555 | | /* [10/19] append path to result; */ |
556 | | /* clang-format on */ |
557 | | /* Slash needed here? */ |
558 | 9.75k | if (uri->absolutePath |
559 | 9.49k | || ((uri->pathHead != NULL) && URI_FUNC(HasHost)(uri))) { |
560 | 369 | if (dest != NULL) { |
561 | 369 | if (written + 1 <= maxChars) { |
562 | 368 | memcpy(dest + written, _UT("/"), 1 * sizeof(URI_CHAR)); |
563 | 368 | written += 1; |
564 | 368 | } else { |
565 | 1 | dest[0] = _UT('\0'); |
566 | 1 | if (charsWritten != NULL) { |
567 | 1 | *charsWritten = 0; |
568 | 1 | } |
569 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
570 | 1 | } |
571 | 369 | } else { |
572 | | // Detect and avoid integer overflow |
573 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
574 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
575 | 0 | } |
576 | | |
577 | 0 | (*charsRequired) += 1; |
578 | 0 | } |
579 | 369 | } |
580 | | |
581 | 9.75k | if (uri->pathHead != NULL) { |
582 | 1.53k | URI_TYPE(PathSegment) * walker = uri->pathHead; |
583 | 13.0k | do { |
584 | 13.0k | const size_t charsToWrite = |
585 | 13.0k | walker->text.afterLast - walker->text.first; |
586 | 13.0k | if (dest != NULL) { |
587 | | // Detect and avoid integer overflow |
588 | 13.0k | if (charsToWrite > (size_t)INT_MAX - written) { |
589 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
590 | 0 | } |
591 | | |
592 | 13.0k | if (written + charsToWrite <= (size_t)maxChars) { |
593 | | // Detect and avoid integer overflow |
594 | 12.9k | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
595 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
596 | 0 | } |
597 | | |
598 | 12.9k | memcpy(dest + written, walker->text.first, |
599 | 12.9k | charsToWrite * sizeof(URI_CHAR)); |
600 | 12.9k | written += charsToWrite; |
601 | 12.9k | } else { |
602 | 38 | dest[0] = _UT('\0'); |
603 | 38 | if (charsWritten != NULL) { |
604 | 38 | *charsWritten = 0; |
605 | 38 | } |
606 | 38 | return URI_ERROR_TOSTRING_TOO_LONG; |
607 | 38 | } |
608 | 13.0k | } else { |
609 | | // Detect and avoid integer overflow |
610 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { |
611 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
612 | 0 | } |
613 | | |
614 | 0 | (*charsRequired) += charsToWrite; |
615 | 0 | } |
616 | | |
617 | | /* Not last segment -> append slash */ |
618 | 12.9k | if (walker->next != NULL) { |
619 | 11.4k | if (dest != NULL) { |
620 | 11.4k | if (written + 1 <= maxChars) { |
621 | 11.4k | memcpy(dest + written, _UT("/"), |
622 | 11.4k | 1 * sizeof(URI_CHAR)); |
623 | 11.4k | written += 1; |
624 | 11.4k | } else { |
625 | 2 | dest[0] = _UT('\0'); |
626 | 2 | if (charsWritten != NULL) { |
627 | 2 | *charsWritten = 0; |
628 | 2 | } |
629 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
630 | 2 | } |
631 | 11.4k | } else { |
632 | | // Detect and avoid integer overflow |
633 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
634 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
635 | 0 | } |
636 | | |
637 | 0 | (*charsRequired) += 1; |
638 | 0 | } |
639 | 11.4k | } |
640 | | |
641 | 12.9k | walker = walker->next; |
642 | 12.9k | } while (walker != NULL); |
643 | 1.53k | } |
644 | | /* clang-format off */ |
645 | | /* [11/19] if defined(query) then */ |
646 | | /* clang-format on */ |
647 | 9.71k | if (uri->query.first != NULL) { |
648 | | /* clang-format off */ |
649 | | /* [12/19] append "?" to result; */ |
650 | | /* clang-format on */ |
651 | 150 | if (dest != NULL) { |
652 | 150 | if (written + 1 <= maxChars) { |
653 | 149 | memcpy(dest + written, _UT("?"), 1 * sizeof(URI_CHAR)); |
654 | 149 | written += 1; |
655 | 149 | } else { |
656 | 1 | dest[0] = _UT('\0'); |
657 | 1 | if (charsWritten != NULL) { |
658 | 1 | *charsWritten = 0; |
659 | 1 | } |
660 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; |
661 | 1 | } |
662 | 150 | } else { |
663 | | // Detect and avoid integer overflow |
664 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
665 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
666 | 0 | } |
667 | | |
668 | 0 | (*charsRequired) += 1; |
669 | 0 | } |
670 | | /* clang-format off */ |
671 | | /* [13/19] append query to result; */ |
672 | | /* clang-format on */ |
673 | 149 | const size_t charsToWrite = uri->query.afterLast - uri->query.first; |
674 | 149 | if (dest != NULL) { |
675 | | // Detect and avoid integer overflow |
676 | 149 | if (charsToWrite > (size_t)INT_MAX - written) { |
677 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
678 | 0 | } |
679 | | |
680 | 149 | if (written + charsToWrite <= (size_t)maxChars) { |
681 | | // Detect and avoid integer overflow |
682 | 127 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
683 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
684 | 0 | } |
685 | | |
686 | 127 | memcpy(dest + written, uri->query.first, |
687 | 127 | charsToWrite * sizeof(URI_CHAR)); |
688 | 127 | written += charsToWrite; |
689 | 127 | } else { |
690 | 22 | dest[0] = _UT('\0'); |
691 | 22 | if (charsWritten != NULL) { |
692 | 22 | *charsWritten = 0; |
693 | 22 | } |
694 | 22 | return URI_ERROR_TOSTRING_TOO_LONG; |
695 | 22 | } |
696 | 149 | } else { |
697 | | // Detect and avoid integer overflow |
698 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { |
699 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
700 | 0 | } |
701 | | |
702 | 0 | (*charsRequired) += charsToWrite; |
703 | 0 | } |
704 | | /* clang-format off */ |
705 | | /* [14/19] endif; */ |
706 | | /* clang-format on */ |
707 | 149 | } |
708 | | /* clang-format off */ |
709 | | /* [15/19] if defined(fragment) then */ |
710 | | /* clang-format on */ |
711 | 9.69k | if (uri->fragment.first != NULL) { |
712 | | /* clang-format off */ |
713 | | /* [16/19] append "#" to result; */ |
714 | | /* clang-format on */ |
715 | 122 | if (dest != NULL) { |
716 | 122 | if (written + 1 <= maxChars) { |
717 | 120 | memcpy(dest + written, _UT("#"), 1 * sizeof(URI_CHAR)); |
718 | 120 | written += 1; |
719 | 120 | } else { |
720 | 2 | dest[0] = _UT('\0'); |
721 | 2 | if (charsWritten != NULL) { |
722 | 2 | *charsWritten = 0; |
723 | 2 | } |
724 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; |
725 | 2 | } |
726 | 122 | } else { |
727 | | // Detect and avoid integer overflow |
728 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { |
729 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
730 | 0 | } |
731 | | |
732 | 0 | (*charsRequired) += 1; |
733 | 0 | } |
734 | | /* clang-format off */ |
735 | | /* [17/19] append fragment to result; */ |
736 | | /* clang-format on */ |
737 | 120 | const size_t charsToWrite = |
738 | 120 | uri->fragment.afterLast - uri->fragment.first; |
739 | 120 | if (dest != NULL) { |
740 | | // Detect and avoid integer overflow |
741 | 120 | if (charsToWrite > (size_t)INT_MAX - written) { |
742 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
743 | 0 | } |
744 | | |
745 | 120 | if (written + charsToWrite <= (size_t)maxChars) { |
746 | | // Detect and avoid integer overflow |
747 | 99 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { |
748 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
749 | 0 | } |
750 | | |
751 | 99 | memcpy(dest + written, uri->fragment.first, |
752 | 99 | charsToWrite * sizeof(URI_CHAR)); |
753 | 99 | written += charsToWrite; |
754 | 99 | } else { |
755 | 21 | dest[0] = _UT('\0'); |
756 | 21 | if (charsWritten != NULL) { |
757 | 21 | *charsWritten = 0; |
758 | 21 | } |
759 | 21 | return URI_ERROR_TOSTRING_TOO_LONG; |
760 | 21 | } |
761 | 120 | } else { |
762 | | // Detect and avoid integer overflow |
763 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { |
764 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; |
765 | 0 | } |
766 | | |
767 | 0 | (*charsRequired) += charsToWrite; |
768 | 0 | } |
769 | | /* clang-format off */ |
770 | | /* [18/19] endif; */ |
771 | | /* clang-format on */ |
772 | 120 | } |
773 | | /* clang-format off */ |
774 | | /* [19/19] return result; */ |
775 | | /* clang-format on */ |
776 | 9.67k | if (dest != NULL) { |
777 | 9.67k | dest[written++] = _UT('\0'); |
778 | 9.67k | if (charsWritten != NULL) { |
779 | 9.67k | *charsWritten = written; |
780 | 9.67k | } |
781 | 9.67k | } |
782 | 9.67k | return URI_SUCCESS; |
783 | 9.69k | } |
784 | 9.69k | } |
785 | 9.69k | } |
786 | 9.69k | } Unexecuted instantiation: UriRecompose.c:uriToStringEngineA UriRecompose.c:uriToStringEngineW Line | Count | Source | 84 | 9.85k | int maxChars, int * charsWritten, int * charsRequired) { | 85 | 9.85k | int written = 0; | 86 | 9.85k | if ((uri == NULL) || ((dest == NULL) && (charsRequired == NULL))) { | 87 | 0 | if (charsWritten != NULL) { | 88 | 0 | *charsWritten = 0; | 89 | 0 | } | 90 | 0 | return URI_ERROR_NULL; | 91 | 0 | } | 92 | | | 93 | 9.85k | if (maxChars < 1) { | 94 | 0 | if (charsWritten != NULL) { | 95 | 0 | *charsWritten = 0; | 96 | 0 | } | 97 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 98 | 0 | } | 99 | 9.85k | maxChars--; /* So we don't have to subtract 1 for '\0' all the time */ | 100 | | | 101 | | /* NOTE: The curly brackets here force deeper indent (and that's all) */ | 102 | 9.85k | { | 103 | 9.85k | { | 104 | 9.85k | { | 105 | | /* clang-format off */ | 106 | | /* [01/19] result = "" */ | 107 | | /* clang-format on */ | 108 | 9.85k | if (dest != NULL) { | 109 | 9.85k | dest[0] = _UT('\0'); | 110 | 9.85k | } else { | 111 | 0 | (*charsRequired) = 0; | 112 | 0 | } | 113 | | /* clang-format off */ | 114 | | /* [02/19] if defined(scheme) then */ | 115 | | /* clang-format on */ | 116 | 9.85k | if (uri->scheme.first != NULL) { | 117 | | /* clang-format off */ | 118 | | /* [03/19] append scheme to result; */ | 119 | | /* clang-format on */ | 120 | 492 | const size_t charsToWrite = uri->scheme.afterLast - uri->scheme.first; | 121 | 492 | if (dest != NULL) { | 122 | | // Detect and avoid integer overflow | 123 | 492 | if (charsToWrite > (size_t)INT_MAX - written) { | 124 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 125 | 0 | } | 126 | | | 127 | 492 | if (written + charsToWrite <= (size_t)maxChars) { | 128 | | // Detect and avoid integer overflow | 129 | 476 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 130 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 131 | 0 | } | 132 | | | 133 | 476 | memcpy(dest + written, uri->scheme.first, | 134 | 476 | charsToWrite * sizeof(URI_CHAR)); | 135 | 476 | written += charsToWrite; | 136 | 476 | } else { | 137 | 16 | dest[0] = _UT('\0'); | 138 | 16 | if (charsWritten != NULL) { | 139 | 16 | *charsWritten = 0; | 140 | 16 | } | 141 | 16 | return URI_ERROR_TOSTRING_TOO_LONG; | 142 | 16 | } | 143 | 492 | } else { | 144 | | // Detect and avoid integer overflow | 145 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { | 146 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 147 | 0 | } | 148 | | | 149 | 0 | (*charsRequired) += charsToWrite; | 150 | 0 | } | 151 | | /* clang-format off */ | 152 | | /* [04/19] append ":" to result; */ | 153 | | /* clang-format on */ | 154 | 476 | if (dest != NULL) { | 155 | 476 | if (written + 1 <= maxChars) { | 156 | 475 | memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); | 157 | 475 | written += 1; | 158 | 475 | } else { | 159 | 1 | dest[0] = _UT('\0'); | 160 | 1 | if (charsWritten != NULL) { | 161 | 1 | *charsWritten = 0; | 162 | 1 | } | 163 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 164 | 1 | } | 165 | 476 | } else { | 166 | | // Detect and avoid integer overflow | 167 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 168 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 169 | 0 | } | 170 | | | 171 | 0 | (*charsRequired) += 1; | 172 | 0 | } | 173 | | /* clang-format off */ | 174 | | /* [05/19] endif; */ | 175 | | /* clang-format on */ | 176 | 476 | } | 177 | | /* clang-format off */ | 178 | | /* [06/19] if defined(authority) then */ | 179 | | /* clang-format on */ | 180 | 9.83k | if (URI_FUNC(HasHost)(uri)) { | 181 | | /* clang-format off */ | 182 | | /* [07/19] append "//" to result; */ | 183 | | /* clang-format on */ | 184 | 1.03k | if (dest != NULL) { | 185 | 1.03k | if (written + 2 <= maxChars) { | 186 | 1.03k | memcpy(dest + written, _UT("//"), 2 * sizeof(URI_CHAR)); | 187 | 1.03k | written += 2; | 188 | 1.03k | } else { | 189 | 2 | dest[0] = _UT('\0'); | 190 | 2 | if (charsWritten != NULL) { | 191 | 2 | *charsWritten = 0; | 192 | 2 | } | 193 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 194 | 2 | } | 195 | 1.03k | } else { | 196 | | // Detect and avoid integer overflow | 197 | 0 | if (2 > (size_t)INT_MAX - *charsRequired) { | 198 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 199 | 0 | } | 200 | | | 201 | 0 | (*charsRequired) += 2; | 202 | 0 | } | 203 | | /* clang-format off */ | 204 | | /* [08/19] append authority to result; */ | 205 | | /* clang-format on */ | 206 | | /* UserInfo */ | 207 | 1.03k | if (uri->userInfo.first != NULL) { | 208 | 286 | const size_t charsToWrite = | 209 | 286 | uri->userInfo.afterLast - uri->userInfo.first; | 210 | 286 | if (dest != NULL) { | 211 | | // Detect and avoid integer overflow | 212 | 286 | if (charsToWrite > (size_t)INT_MAX - written) { | 213 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 214 | 0 | } | 215 | | | 216 | 286 | if (written + charsToWrite <= (size_t)maxChars) { | 217 | | // Detect and avoid integer overflow | 218 | 273 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 219 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 220 | 0 | } | 221 | | | 222 | 273 | memcpy(dest + written, uri->userInfo.first, | 223 | 273 | charsToWrite * sizeof(URI_CHAR)); | 224 | 273 | written += charsToWrite; | 225 | 273 | } else { | 226 | 13 | dest[0] = _UT('\0'); | 227 | 13 | if (charsWritten != NULL) { | 228 | 13 | *charsWritten = 0; | 229 | 13 | } | 230 | 13 | return URI_ERROR_TOSTRING_TOO_LONG; | 231 | 13 | } | 232 | | | 233 | 273 | if (written + 1 <= maxChars) { | 234 | 271 | memcpy(dest + written, _UT("@"), 1 * sizeof(URI_CHAR)); | 235 | 271 | written += 1; | 236 | 271 | } else { | 237 | 2 | dest[0] = _UT('\0'); | 238 | 2 | if (charsWritten != NULL) { | 239 | 2 | *charsWritten = 0; | 240 | 2 | } | 241 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 242 | 2 | } | 243 | 273 | } else { | 244 | | // Detect and avoid integer overflow | 245 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1) | 246 | 0 | || (charsToWrite + 1 | 247 | 0 | > (size_t)INT_MAX - *charsRequired)) { | 248 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 249 | 0 | } | 250 | | | 251 | 0 | (*charsRequired) += charsToWrite + 1; | 252 | 0 | } | 253 | 286 | } | 254 | | | 255 | | /* Host */ | 256 | 1.01k | if (uri->hostData.ip4 != NULL) { | 257 | | /* IPv4 */ | 258 | 49 | int i = 0; | 259 | 238 | for (; i < 4; i++) { | 260 | 192 | const unsigned char value = uri->hostData.ip4->data[i]; | 261 | 192 | const int charsToWrite = | 262 | 192 | (value > 99) ? 3 : ((value > 9) ? 2 : 1); | 263 | 192 | if (dest != NULL) { | 264 | 192 | if (written + charsToWrite <= maxChars) { | 265 | 190 | URI_CHAR text[4]; | 266 | 190 | if (value > 99) { | 267 | 16 | text[0] = _UT('0') + (value / 100); | 268 | 16 | text[1] = _UT('0') + ((value % 100) / 10); | 269 | 16 | text[2] = _UT('0') + (value % 10); | 270 | 174 | } else if (value > 9) { | 271 | 35 | text[0] = _UT('0') + (value / 10); | 272 | 35 | text[1] = _UT('0') + (value % 10); | 273 | 139 | } else { | 274 | 139 | text[0] = _UT('0') + value; | 275 | 139 | } | 276 | 190 | text[charsToWrite] = _UT('\0'); | 277 | 190 | memcpy(dest + written, text, | 278 | 190 | charsToWrite * sizeof(URI_CHAR)); | 279 | 190 | written += charsToWrite; | 280 | 190 | } else { | 281 | 2 | dest[0] = _UT('\0'); | 282 | 2 | if (charsWritten != NULL) { | 283 | 2 | *charsWritten = 0; | 284 | 2 | } | 285 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 286 | 2 | } | 287 | 190 | if (i < 3) { | 288 | 144 | if (written + 1 <= maxChars) { | 289 | 143 | memcpy(dest + written, _UT("."), | 290 | 143 | 1 * sizeof(URI_CHAR)); | 291 | 143 | written += 1; | 292 | 143 | } else { | 293 | 1 | dest[0] = _UT('\0'); | 294 | 1 | if (charsWritten != NULL) { | 295 | 1 | *charsWritten = 0; | 296 | 1 | } | 297 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 298 | 1 | } | 299 | 144 | } | 300 | 190 | } else { | 301 | 0 | const int extra = (i == 3) ? 0 : 1; | 302 | | | 303 | | // Detect and avoid integer overflow | 304 | 0 | if (charsToWrite > INT_MAX - extra | 305 | 0 | || charsToWrite + extra | 306 | 0 | > INT_MAX - *charsRequired) { | 307 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 308 | 0 | } | 309 | | | 310 | 0 | (*charsRequired) += charsToWrite + extra; | 311 | 0 | } | 312 | 192 | } | 313 | 968 | } else if (uri->hostData.ip6 != NULL) { | 314 | | /* IPv6 */ | 315 | 224 | int i = 0; | 316 | 224 | if (dest != NULL) { | 317 | 224 | if (written + 1 <= maxChars) { | 318 | 223 | memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); | 319 | 223 | written += 1; | 320 | 223 | } else { | 321 | 1 | dest[0] = _UT('\0'); | 322 | 1 | if (charsWritten != NULL) { | 323 | 1 | *charsWritten = 0; | 324 | 1 | } | 325 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 326 | 1 | } | 327 | 224 | } else { | 328 | | // Detect and avoid integer overflow | 329 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 330 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 331 | 0 | } | 332 | | | 333 | 0 | (*charsRequired) += 1; | 334 | 0 | } | 335 | | | 336 | 3.70k | for (; i < 16; i++) { | 337 | 3.49k | const unsigned char value = uri->hostData.ip6->data[i]; | 338 | 3.49k | if (dest != NULL) { | 339 | 3.49k | if (written + 2 <= maxChars) { | 340 | 3.48k | URI_CHAR text[3]; | 341 | 3.48k | text[0] = URI_FUNC(HexToLetterEx)( | 342 | 3.48k | value / 16, URI_FALSE); | 343 | 3.48k | text[1] = URI_FUNC(HexToLetterEx)( | 344 | 3.48k | value % 16, URI_FALSE); | 345 | 3.48k | text[2] = _UT('\0'); | 346 | 3.48k | memcpy(dest + written, text, 2 * sizeof(URI_CHAR)); | 347 | 3.48k | written += 2; | 348 | 3.48k | } else { | 349 | 6 | dest[0] = _UT('\0'); | 350 | 6 | if (charsWritten != NULL) { | 351 | 6 | *charsWritten = 0; | 352 | 6 | } | 353 | 6 | return URI_ERROR_TOSTRING_TOO_LONG; | 354 | 6 | } | 355 | 3.49k | } else { | 356 | | // Detect and avoid integer overflow | 357 | 0 | if (2 > (size_t)INT_MAX - *charsRequired) { | 358 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 359 | 0 | } | 360 | | | 361 | 0 | (*charsRequired) += 2; | 362 | 0 | } | 363 | 3.48k | if (((i & 1) == 1) && (i < 15)) { | 364 | 1.52k | if (dest != NULL) { | 365 | 1.52k | if (written + 1 <= maxChars) { | 366 | 1.52k | memcpy(dest + written, _UT(":"), | 367 | 1.52k | 1 * sizeof(URI_CHAR)); | 368 | 1.52k | written += 1; | 369 | 1.52k | } else { | 370 | 2 | dest[0] = _UT('\0'); | 371 | 2 | if (charsWritten != NULL) { | 372 | 2 | *charsWritten = 0; | 373 | 2 | } | 374 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 375 | 2 | } | 376 | 1.52k | } else { | 377 | | // Detect and avoid integer overflow | 378 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 379 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 380 | 0 | } | 381 | | | 382 | 0 | (*charsRequired) += 1; | 383 | 0 | } | 384 | 1.52k | } | 385 | 3.48k | } | 386 | | | 387 | 215 | if (dest != NULL) { | 388 | 215 | if (written + 1 <= maxChars) { | 389 | 214 | memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); | 390 | 214 | written += 1; | 391 | 214 | } else { | 392 | 1 | dest[0] = _UT('\0'); | 393 | 1 | if (charsWritten != NULL) { | 394 | 1 | *charsWritten = 0; | 395 | 1 | } | 396 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 397 | 1 | } | 398 | 215 | } else { | 399 | | // Detect and avoid integer overflow | 400 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 401 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 402 | 0 | } | 403 | | | 404 | 0 | (*charsRequired) += 1; | 405 | 0 | } | 406 | 744 | } else if (uri->hostData.ipFuture.first != NULL) { | 407 | | /* IPvFuture */ | 408 | 196 | const size_t charsToWrite = uri->hostData.ipFuture.afterLast | 409 | 196 | - uri->hostData.ipFuture.first; | 410 | 196 | if (dest != NULL) { | 411 | 196 | if (written + 1 <= maxChars) { | 412 | 195 | memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR)); | 413 | 195 | written += 1; | 414 | 195 | } else { | 415 | 1 | dest[0] = _UT('\0'); | 416 | 1 | if (charsWritten != NULL) { | 417 | 1 | *charsWritten = 0; | 418 | 1 | } | 419 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 420 | 1 | } | 421 | | | 422 | | // Detect and avoid integer overflow | 423 | 195 | if (charsToWrite > (size_t)INT_MAX - written) { | 424 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 425 | 0 | } | 426 | | | 427 | 195 | if (written + charsToWrite <= (size_t)maxChars) { | 428 | | // Detect and avoid integer overflow | 429 | 172 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 430 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 431 | 0 | } | 432 | | | 433 | 172 | memcpy(dest + written, uri->hostData.ipFuture.first, | 434 | 172 | charsToWrite * sizeof(URI_CHAR)); | 435 | 172 | written += charsToWrite; | 436 | 172 | } else { | 437 | 23 | dest[0] = _UT('\0'); | 438 | 23 | if (charsWritten != NULL) { | 439 | 23 | *charsWritten = 0; | 440 | 23 | } | 441 | 23 | return URI_ERROR_TOSTRING_TOO_LONG; | 442 | 23 | } | 443 | | | 444 | 172 | if (written + 1 <= maxChars) { | 445 | 171 | memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR)); | 446 | 171 | written += 1; | 447 | 171 | } else { | 448 | 1 | dest[0] = _UT('\0'); | 449 | 1 | if (charsWritten != NULL) { | 450 | 1 | *charsWritten = 0; | 451 | 1 | } | 452 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 453 | 1 | } | 454 | 172 | } else { | 455 | | // Detect and avoid integer overflow | 456 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1 - 1) | 457 | 0 | || (1 + charsToWrite + 1 | 458 | 0 | > (size_t)INT_MAX - *charsRequired)) { | 459 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 460 | 0 | } | 461 | | | 462 | 0 | (*charsRequired) += 1 + charsToWrite + 1; | 463 | 0 | } | 464 | 548 | } else if (uri->hostText.first != NULL) { | 465 | | /* Regname */ | 466 | 548 | const size_t charsToWrite = | 467 | 548 | uri->hostText.afterLast - uri->hostText.first; | 468 | 548 | if (dest != NULL) { | 469 | | // Detect and avoid integer overflow | 470 | 548 | if (charsToWrite > (size_t)INT_MAX - written) { | 471 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 472 | 0 | } | 473 | | | 474 | 548 | if (written + charsToWrite <= (size_t)maxChars) { | 475 | | // Detect and avoid integer overflow | 476 | 526 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 477 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 478 | 0 | } | 479 | | | 480 | 526 | memcpy(dest + written, uri->hostText.first, | 481 | 526 | charsToWrite * sizeof(URI_CHAR)); | 482 | 526 | written += charsToWrite; | 483 | 526 | } else { | 484 | 22 | dest[0] = _UT('\0'); | 485 | 22 | if (charsWritten != NULL) { | 486 | 22 | *charsWritten = 0; | 487 | 22 | } | 488 | 22 | return URI_ERROR_TOSTRING_TOO_LONG; | 489 | 22 | } | 490 | 548 | } else { | 491 | | // Detect and avoid integer overflow | 492 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { | 493 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 494 | 0 | } | 495 | | | 496 | 0 | (*charsRequired) += charsToWrite; | 497 | 0 | } | 498 | 548 | } | 499 | | | 500 | | /* Port */ | 501 | 957 | if (uri->portText.first != NULL) { | 502 | 88 | const size_t charsToWrite = | 503 | 88 | uri->portText.afterLast - uri->portText.first; | 504 | 88 | if (dest != NULL) { | 505 | | /* Leading ':' */ | 506 | 88 | if (written + 1 <= maxChars) { | 507 | 86 | memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR)); | 508 | 86 | written += 1; | 509 | 86 | } else { | 510 | 2 | dest[0] = _UT('\0'); | 511 | 2 | if (charsWritten != NULL) { | 512 | 2 | *charsWritten = 0; | 513 | 2 | } | 514 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 515 | 2 | } | 516 | | | 517 | | // Detect and avoid integer overflow | 518 | 86 | if (charsToWrite > (size_t)INT_MAX - written) { | 519 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 520 | 0 | } | 521 | | | 522 | | /* Port number */ | 523 | 86 | if (written + charsToWrite <= (size_t)maxChars) { | 524 | | // Detect and avoid integer overflow | 525 | 85 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 526 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 527 | 0 | } | 528 | | | 529 | 85 | memcpy(dest + written, uri->portText.first, | 530 | 85 | charsToWrite * sizeof(URI_CHAR)); | 531 | 85 | written += charsToWrite; | 532 | 85 | } else { | 533 | 1 | dest[0] = _UT('\0'); | 534 | 1 | if (charsWritten != NULL) { | 535 | 1 | *charsWritten = 0; | 536 | 1 | } | 537 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 538 | 1 | } | 539 | 86 | } else { | 540 | | // Detect and avoid integer overflow | 541 | 0 | if ((charsToWrite > (size_t)INT_MAX - 1) | 542 | 0 | || (1 + charsToWrite | 543 | 0 | > (size_t)INT_MAX - *charsRequired)) { | 544 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 545 | 0 | } | 546 | | | 547 | 0 | (*charsRequired) += 1 + charsToWrite; | 548 | 0 | } | 549 | 88 | } | 550 | | /* clang-format off */ | 551 | | /* [09/19] endif; */ | 552 | | /* clang-format on */ | 553 | 957 | } | 554 | | /* clang-format off */ | 555 | | /* [10/19] append path to result; */ | 556 | | /* clang-format on */ | 557 | | /* Slash needed here? */ | 558 | 9.75k | if (uri->absolutePath | 559 | 9.49k | || ((uri->pathHead != NULL) && URI_FUNC(HasHost)(uri))) { | 560 | 369 | if (dest != NULL) { | 561 | 369 | if (written + 1 <= maxChars) { | 562 | 368 | memcpy(dest + written, _UT("/"), 1 * sizeof(URI_CHAR)); | 563 | 368 | written += 1; | 564 | 368 | } else { | 565 | 1 | dest[0] = _UT('\0'); | 566 | 1 | if (charsWritten != NULL) { | 567 | 1 | *charsWritten = 0; | 568 | 1 | } | 569 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 570 | 1 | } | 571 | 369 | } else { | 572 | | // Detect and avoid integer overflow | 573 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 574 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 575 | 0 | } | 576 | | | 577 | 0 | (*charsRequired) += 1; | 578 | 0 | } | 579 | 369 | } | 580 | | | 581 | 9.75k | if (uri->pathHead != NULL) { | 582 | 1.53k | URI_TYPE(PathSegment) * walker = uri->pathHead; | 583 | 13.0k | do { | 584 | 13.0k | const size_t charsToWrite = | 585 | 13.0k | walker->text.afterLast - walker->text.first; | 586 | 13.0k | if (dest != NULL) { | 587 | | // Detect and avoid integer overflow | 588 | 13.0k | if (charsToWrite > (size_t)INT_MAX - written) { | 589 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 590 | 0 | } | 591 | | | 592 | 13.0k | if (written + charsToWrite <= (size_t)maxChars) { | 593 | | // Detect and avoid integer overflow | 594 | 12.9k | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 595 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 596 | 0 | } | 597 | | | 598 | 12.9k | memcpy(dest + written, walker->text.first, | 599 | 12.9k | charsToWrite * sizeof(URI_CHAR)); | 600 | 12.9k | written += charsToWrite; | 601 | 12.9k | } else { | 602 | 38 | dest[0] = _UT('\0'); | 603 | 38 | if (charsWritten != NULL) { | 604 | 38 | *charsWritten = 0; | 605 | 38 | } | 606 | 38 | return URI_ERROR_TOSTRING_TOO_LONG; | 607 | 38 | } | 608 | 13.0k | } else { | 609 | | // Detect and avoid integer overflow | 610 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { | 611 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 612 | 0 | } | 613 | | | 614 | 0 | (*charsRequired) += charsToWrite; | 615 | 0 | } | 616 | | | 617 | | /* Not last segment -> append slash */ | 618 | 12.9k | if (walker->next != NULL) { | 619 | 11.4k | if (dest != NULL) { | 620 | 11.4k | if (written + 1 <= maxChars) { | 621 | 11.4k | memcpy(dest + written, _UT("/"), | 622 | 11.4k | 1 * sizeof(URI_CHAR)); | 623 | 11.4k | written += 1; | 624 | 11.4k | } else { | 625 | 2 | dest[0] = _UT('\0'); | 626 | 2 | if (charsWritten != NULL) { | 627 | 2 | *charsWritten = 0; | 628 | 2 | } | 629 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 630 | 2 | } | 631 | 11.4k | } else { | 632 | | // Detect and avoid integer overflow | 633 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 634 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 635 | 0 | } | 636 | | | 637 | 0 | (*charsRequired) += 1; | 638 | 0 | } | 639 | 11.4k | } | 640 | | | 641 | 12.9k | walker = walker->next; | 642 | 12.9k | } while (walker != NULL); | 643 | 1.53k | } | 644 | | /* clang-format off */ | 645 | | /* [11/19] if defined(query) then */ | 646 | | /* clang-format on */ | 647 | 9.71k | if (uri->query.first != NULL) { | 648 | | /* clang-format off */ | 649 | | /* [12/19] append "?" to result; */ | 650 | | /* clang-format on */ | 651 | 150 | if (dest != NULL) { | 652 | 150 | if (written + 1 <= maxChars) { | 653 | 149 | memcpy(dest + written, _UT("?"), 1 * sizeof(URI_CHAR)); | 654 | 149 | written += 1; | 655 | 149 | } else { | 656 | 1 | dest[0] = _UT('\0'); | 657 | 1 | if (charsWritten != NULL) { | 658 | 1 | *charsWritten = 0; | 659 | 1 | } | 660 | 1 | return URI_ERROR_TOSTRING_TOO_LONG; | 661 | 1 | } | 662 | 150 | } else { | 663 | | // Detect and avoid integer overflow | 664 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 665 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 666 | 0 | } | 667 | | | 668 | 0 | (*charsRequired) += 1; | 669 | 0 | } | 670 | | /* clang-format off */ | 671 | | /* [13/19] append query to result; */ | 672 | | /* clang-format on */ | 673 | 149 | const size_t charsToWrite = uri->query.afterLast - uri->query.first; | 674 | 149 | if (dest != NULL) { | 675 | | // Detect and avoid integer overflow | 676 | 149 | if (charsToWrite > (size_t)INT_MAX - written) { | 677 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 678 | 0 | } | 679 | | | 680 | 149 | if (written + charsToWrite <= (size_t)maxChars) { | 681 | | // Detect and avoid integer overflow | 682 | 127 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 683 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 684 | 0 | } | 685 | | | 686 | 127 | memcpy(dest + written, uri->query.first, | 687 | 127 | charsToWrite * sizeof(URI_CHAR)); | 688 | 127 | written += charsToWrite; | 689 | 127 | } else { | 690 | 22 | dest[0] = _UT('\0'); | 691 | 22 | if (charsWritten != NULL) { | 692 | 22 | *charsWritten = 0; | 693 | 22 | } | 694 | 22 | return URI_ERROR_TOSTRING_TOO_LONG; | 695 | 22 | } | 696 | 149 | } else { | 697 | | // Detect and avoid integer overflow | 698 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { | 699 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 700 | 0 | } | 701 | | | 702 | 0 | (*charsRequired) += charsToWrite; | 703 | 0 | } | 704 | | /* clang-format off */ | 705 | | /* [14/19] endif; */ | 706 | | /* clang-format on */ | 707 | 149 | } | 708 | | /* clang-format off */ | 709 | | /* [15/19] if defined(fragment) then */ | 710 | | /* clang-format on */ | 711 | 9.69k | if (uri->fragment.first != NULL) { | 712 | | /* clang-format off */ | 713 | | /* [16/19] append "#" to result; */ | 714 | | /* clang-format on */ | 715 | 122 | if (dest != NULL) { | 716 | 122 | if (written + 1 <= maxChars) { | 717 | 120 | memcpy(dest + written, _UT("#"), 1 * sizeof(URI_CHAR)); | 718 | 120 | written += 1; | 719 | 120 | } else { | 720 | 2 | dest[0] = _UT('\0'); | 721 | 2 | if (charsWritten != NULL) { | 722 | 2 | *charsWritten = 0; | 723 | 2 | } | 724 | 2 | return URI_ERROR_TOSTRING_TOO_LONG; | 725 | 2 | } | 726 | 122 | } else { | 727 | | // Detect and avoid integer overflow | 728 | 0 | if (1 > (size_t)INT_MAX - *charsRequired) { | 729 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 730 | 0 | } | 731 | | | 732 | 0 | (*charsRequired) += 1; | 733 | 0 | } | 734 | | /* clang-format off */ | 735 | | /* [17/19] append fragment to result; */ | 736 | | /* clang-format on */ | 737 | 120 | const size_t charsToWrite = | 738 | 120 | uri->fragment.afterLast - uri->fragment.first; | 739 | 120 | if (dest != NULL) { | 740 | | // Detect and avoid integer overflow | 741 | 120 | if (charsToWrite > (size_t)INT_MAX - written) { | 742 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 743 | 0 | } | 744 | | | 745 | 120 | if (written + charsToWrite <= (size_t)maxChars) { | 746 | | // Detect and avoid integer overflow | 747 | 99 | if (charsToWrite > SIZE_MAX / sizeof(URI_CHAR)) { | 748 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 749 | 0 | } | 750 | | | 751 | 99 | memcpy(dest + written, uri->fragment.first, | 752 | 99 | charsToWrite * sizeof(URI_CHAR)); | 753 | 99 | written += charsToWrite; | 754 | 99 | } else { | 755 | 21 | dest[0] = _UT('\0'); | 756 | 21 | if (charsWritten != NULL) { | 757 | 21 | *charsWritten = 0; | 758 | 21 | } | 759 | 21 | return URI_ERROR_TOSTRING_TOO_LONG; | 760 | 21 | } | 761 | 120 | } else { | 762 | | // Detect and avoid integer overflow | 763 | 0 | if (charsToWrite > (size_t)INT_MAX - *charsRequired) { | 764 | 0 | return URI_ERROR_TOSTRING_TOO_LONG; | 765 | 0 | } | 766 | | | 767 | 0 | (*charsRequired) += charsToWrite; | 768 | 0 | } | 769 | | /* clang-format off */ | 770 | | /* [18/19] endif; */ | 771 | | /* clang-format on */ | 772 | 120 | } | 773 | | /* clang-format off */ | 774 | | /* [19/19] return result; */ | 775 | | /* clang-format on */ | 776 | 9.67k | if (dest != NULL) { | 777 | 9.67k | dest[written++] = _UT('\0'); | 778 | 9.67k | if (charsWritten != NULL) { | 779 | 9.67k | *charsWritten = written; | 780 | 9.67k | } | 781 | 9.67k | } | 782 | 9.67k | return URI_SUCCESS; | 783 | 9.69k | } | 784 | 9.69k | } | 785 | 9.69k | } | 786 | 9.69k | } |
|
787 | | |
788 | | #endif |