Coverage Report

Created: 2026-06-09 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
uriToStringW
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