Coverage Report

Created: 2026-06-02 06:40

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