Coverage Report

Created: 2026-06-02 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/uri/uriparser/src/UriCommon.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 "UriCommon.c"
47
#    undef URI_PASS_ANSI
48
#  endif
49
#  ifdef URI_ENABLE_UNICODE
50
#    define URI_PASS_UNICODE 1
51
#    include "UriCommon.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
#    include "UriSets.h"
66
#  endif
67
68
#  include <assert.h>
69
#  include <stddef.h>
70
#  include <stdint.h>  // SIZE_MAX
71
72
/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
73
/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
74
/*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
75
76
0
void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
77
0
    if (uri == NULL) {
78
0
        return;
79
0
    }
80
0
    memset(uri, 0, sizeof(URI_TYPE(Uri)));
81
0
}
Unexecuted instantiation: uriResetUriA
Unexecuted instantiation: uriResetUriW
82
83
0
int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
84
0
    assert(uri != NULL);
85
0
    assert(memory != NULL);
86
87
0
    if (uri->pathHead != NULL) {
88
0
        URI_TYPE(PathSegment) * segWalk = uri->pathHead;
89
0
        while (segWalk != NULL) {
90
0
            URI_TYPE(PathSegment) * const next = segWalk->next;
91
0
            if ((uri->owner == URI_TRUE)
92
0
                && (segWalk->text.first != segWalk->text.afterLast)) {
93
0
                memory->free(memory, (URI_CHAR *)segWalk->text.first);
94
0
            }
95
0
            segWalk->text.first = NULL;
96
0
            segWalk->text.afterLast = NULL;
97
0
            segWalk->next = NULL;
98
0
            memory->free(memory, segWalk);
99
0
            segWalk = next;
100
0
        }
101
0
        uri->pathHead = NULL;
102
0
        uri->pathTail = NULL;
103
0
    }
104
105
0
    return URI_SUCCESS;
106
0
}
Unexecuted instantiation: uriFreeUriPathA
Unexecuted instantiation: uriFreeUriPathW
107
108
/* Compares two text ranges for equal text content */
109
0
bool URI_FUNC(RangeEquals)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
110
    /* NOTE: Both NULL means equal! */
111
0
    if ((a == NULL) || (b == NULL)) {
112
0
        return a == b;
113
0
    }
114
115
    /* NOTE: Both NULL means equal! */
116
0
    if ((a->first == NULL) || (b->first == NULL)) {
117
0
        return a->first == b->first;
118
0
    }
119
120
0
    const size_t lenA = a->afterLast - a->first;
121
0
    const size_t lenB = b->afterLast - b->first;
122
123
0
    if (lenA != lenB) {
124
0
        return false;
125
0
    }
126
127
0
    return URI_STRNCMP(a->first, b->first, lenA) == 0;
128
0
}
Unexecuted instantiation: uriRangeEqualsA
Unexecuted instantiation: uriRangeEqualsW
129
130
UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
131
                            const URI_TYPE(TextRange) * sourceRange,
132
0
                            UriMemoryManager * memory) {
133
0
    const size_t lenInChars = sourceRange->afterLast - sourceRange->first;
134
0
    if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {  // detect integer overflow
135
0
        return URI_FALSE;
136
0
    }
137
0
    const size_t lenInBytes = lenInChars * sizeof(URI_CHAR);
138
0
    URI_CHAR * dup = memory->malloc(memory, lenInBytes);
139
0
    if (dup == NULL) {
140
0
        return URI_FALSE;
141
0
    }
142
0
    memcpy(dup, sourceRange->first, lenInBytes);
143
0
    destRange->first = dup;
144
0
    destRange->afterLast = dup + lenInChars;
145
146
0
    return URI_TRUE;
147
0
}
Unexecuted instantiation: uriCopyRangeA
Unexecuted instantiation: uriCopyRangeW
148
149
UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
150
                                    const URI_TYPE(TextRange) * sourceRange,
151
0
                                    UriMemoryManager * memory) {
152
0
    if (sourceRange->first == NULL) {
153
0
        destRange->first = NULL;
154
0
        destRange->afterLast = NULL;
155
0
    } else if (sourceRange->first == sourceRange->afterLast) {
156
0
        destRange->first = URI_FUNC(SafeToPointTo);
157
0
        destRange->afterLast = URI_FUNC(SafeToPointTo);
158
0
    } else {
159
0
        return URI_FUNC(CopyRange)(destRange, sourceRange, memory);
160
0
    }
161
162
0
    return URI_TRUE;
163
0
}
Unexecuted instantiation: uriCopyRangeAsNeededA
Unexecuted instantiation: uriCopyRangeAsNeededW
164
165
UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative,
166
0
                                      UriBool pathOwned, UriMemoryManager * memory) {
167
0
    URI_TYPE(PathSegment) * walker;
168
0
    if ((uri == NULL) || (uri->pathHead == NULL)) {
169
0
        return URI_TRUE;
170
0
    }
171
172
0
    walker = uri->pathHead;
173
0
    walker->reserved = NULL; /* Prev pointer */
174
0
    do {
175
0
        UriBool removeSegment = URI_FALSE;
176
0
        const size_t len = walker->text.afterLast - walker->text.first;
177
0
        switch (len) {
178
0
        case 1:
179
0
            if ((walker->text.first)[0] == _UT('.')) {
180
                /* "." segment -> remove if not essential */
181
0
                URI_TYPE(PathSegment) * const prev = walker->reserved;
182
0
                URI_TYPE(PathSegment) * const nextBackup = walker->next;
183
184
                /*
185
                 * Is this dot segment essential,
186
                 * i.e. is there a chance of changing semantics by dropping this dot
187
                 * segment?
188
                 *
189
                 * For example, changing "./http://foo" into "http://foo" would change
190
                 * semantics and hence the dot segment is essential to that case and
191
                 * cannot be removed.
192
                 *
193
                 * Other examples that would change semantics are:
194
                 * - cutting "/.//" down to "//"
195
                 * - cutting "scheme:/.//" down to "scheme://".
196
                 */
197
0
                removeSegment = URI_TRUE;
198
0
                if ((walker == uri->pathHead) && (walker->next != NULL)) {
199
                    /* Detect case "/.//" (with or without scheme) */
200
0
                    if ((walker->next->text.first == walker->next->text.afterLast)
201
0
                        && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
202
0
                        removeSegment = URI_FALSE;
203
                        /* Detect case "./withcolon:" */
204
0
                    } else if (relative) {
205
0
                        const URI_CHAR * ch = walker->next->text.first;
206
0
                        for (; ch < walker->next->text.afterLast; ch++) {
207
0
                            if (*ch == _UT(':')) {
208
0
                                removeSegment = URI_FALSE;
209
0
                                break;
210
0
                            }
211
0
                        }
212
0
                    }
213
0
                }
214
215
0
                if (removeSegment) {
216
                    /* .. then let's go remove that segment. */
217
                    /* Last segment? */
218
0
                    if (walker->next != NULL) {
219
                        /* Not last segment, i.e. first or middle segment
220
                         * OLD: (prev|NULL) <- walker <- next
221
                         * NEW: (prev|NULL) <----------- next */
222
0
                        walker->next->reserved = prev;
223
224
0
                        if (prev == NULL) {
225
                            /* First but not last segment
226
                             * OLD: head -> walker -> next
227
                             * NEW: head -----------> next */
228
0
                            uri->pathHead = walker->next;
229
0
                        } else {
230
                            /* Middle segment
231
                             * OLD: prev -> walker -> next
232
                             * NEW: prev -----------> next */
233
0
                            prev->next = walker->next;
234
0
                        }
235
236
0
                        if (pathOwned && (walker->text.first != walker->text.afterLast)) {
237
0
                            memory->free(memory, (URI_CHAR *)walker->text.first);
238
0
                        }
239
0
                        memory->free(memory, walker);
240
0
                    } else {
241
                        /* Last segment */
242
0
                        if (pathOwned && (walker->text.first != walker->text.afterLast)) {
243
0
                            memory->free(memory, (URI_CHAR *)walker->text.first);
244
0
                        }
245
246
0
                        if (prev == NULL) {
247
                            /* Last and first */
248
0
                            if (URI_FUNC(HasHost)(uri)) {
249
                                /* Replace "." with empty segment to represent trailing
250
                                 * slash */
251
0
                                walker->text.first = URI_FUNC(SafeToPointTo);
252
0
                                walker->text.afterLast = URI_FUNC(SafeToPointTo);
253
0
                            } else {
254
0
                                memory->free(memory, walker);
255
256
0
                                uri->pathHead = NULL;
257
0
                                uri->pathTail = NULL;
258
0
                            }
259
0
                        } else {
260
                            /* Last but not first, replace "." with empty segment to
261
                             * represent trailing slash */
262
0
                            walker->text.first = URI_FUNC(SafeToPointTo);
263
0
                            walker->text.afterLast = URI_FUNC(SafeToPointTo);
264
0
                        }
265
0
                    }
266
267
0
                    walker = nextBackup;
268
0
                }
269
0
            }
270
0
            break;
271
272
0
        case 2:
273
0
            if (((walker->text.first)[0] == _UT('.'))
274
0
                && ((walker->text.first)[1] == _UT('.'))) {
275
                /* Path ".." -> remove this and the previous segment */
276
0
                URI_TYPE(PathSegment) * const prev = walker->reserved;
277
0
                URI_TYPE(PathSegment) * prevPrev;
278
0
                URI_TYPE(PathSegment) * const nextBackup = walker->next;
279
280
0
                removeSegment = URI_TRUE;
281
0
                if (relative) {
282
0
                    if (prev == NULL) {
283
                        /* We cannot remove traversal beyond because the
284
                         * URI is relative and may be resolved later.
285
                         * So we can simplify "a/../b/d" to "b/d" but
286
                         * we cannot simplify "../b/d" (outside of reference resolution).
287
                         */
288
0
                        removeSegment = URI_FALSE;
289
0
                    } else if ((prev != NULL)
290
0
                               && ((prev->text.afterLast - prev->text.first) == 2)
291
0
                               && ((prev->text.first)[0] == _UT('.'))
292
0
                               && ((prev->text.first)[1] == _UT('.'))) {
293
                        /* We need to protect against mis-simplifying "a/../../b" to
294
                         * "a/b". */
295
0
                        removeSegment = URI_FALSE;
296
0
                    }
297
0
                }
298
299
0
                if (removeSegment) {
300
0
                    if (prev != NULL) {
301
                        /* Not first segment */
302
0
                        prevPrev = prev->reserved;
303
0
                        if (prevPrev != NULL) {
304
                            /* Not even prev is the first one
305
                             * OLD: prevPrev -> prev -> walker -> (next|NULL)
306
                             * NEW: prevPrev -------------------> (next|NULL) */
307
0
                            prevPrev->next = walker->next;
308
0
                            if (walker->next != NULL) {
309
                                /* Update parent relationship as well
310
                                 * OLD: prevPrev <- prev <- walker <- next
311
                                 * NEW: prevPrev <------------------- next */
312
0
                                walker->next->reserved = prevPrev;
313
0
                            } else {
314
                                /* Last segment -> insert "" segment to represent trailing
315
                                 * slash, update tail */
316
0
                                URI_TYPE(PathSegment) * const segment = memory->calloc(
317
0
                                    memory, 1, sizeof(URI_TYPE(PathSegment)));
318
0
                                if (segment == NULL) {
319
0
                                    if (pathOwned
320
0
                                        && (walker->text.first
321
0
                                            != walker->text.afterLast)) {
322
0
                                        memory->free(memory,
323
0
                                                     (URI_CHAR *)walker->text.first);
324
0
                                    }
325
0
                                    memory->free(memory, walker);
326
327
0
                                    if (pathOwned
328
0
                                        && (prev->text.first != prev->text.afterLast)) {
329
0
                                        memory->free(memory,
330
0
                                                     (URI_CHAR *)prev->text.first);
331
0
                                    }
332
0
                                    memory->free(memory, prev);
333
334
0
                                    return URI_FALSE; /* Raises malloc error */
335
0
                                }
336
0
                                segment->text.first = URI_FUNC(SafeToPointTo);
337
0
                                segment->text.afterLast = URI_FUNC(SafeToPointTo);
338
0
                                prevPrev->next = segment;
339
0
                                uri->pathTail = segment;
340
0
                            }
341
342
0
                            if (pathOwned
343
0
                                && (walker->text.first != walker->text.afterLast)) {
344
0
                                memory->free(memory, (URI_CHAR *)walker->text.first);
345
0
                            }
346
0
                            memory->free(memory, walker);
347
348
0
                            if (pathOwned && (prev->text.first != prev->text.afterLast)) {
349
0
                                memory->free(memory, (URI_CHAR *)prev->text.first);
350
0
                            }
351
0
                            memory->free(memory, prev);
352
353
0
                            walker = nextBackup;
354
0
                        } else {
355
                            /* Prev is the first segment */
356
0
                            if (walker->next != NULL) {
357
0
                                uri->pathHead = walker->next;
358
0
                                walker->next->reserved = NULL;
359
360
0
                                if (pathOwned
361
0
                                    && (walker->text.first != walker->text.afterLast)) {
362
0
                                    memory->free(memory, (URI_CHAR *)walker->text.first);
363
0
                                }
364
0
                                memory->free(memory, walker);
365
0
                            } else {
366
                                /* Reuse segment for "" path segment to represent trailing
367
                                 * slash, update tail */
368
0
                                URI_TYPE(PathSegment) * const segment = walker;
369
0
                                if (pathOwned
370
0
                                    && (segment->text.first != segment->text.afterLast)) {
371
0
                                    memory->free(memory, (URI_CHAR *)segment->text.first);
372
0
                                }
373
0
                                segment->text.first = URI_FUNC(SafeToPointTo);
374
0
                                segment->text.afterLast = URI_FUNC(SafeToPointTo);
375
0
                                uri->pathHead = segment;
376
0
                                uri->pathTail = segment;
377
0
                            }
378
379
0
                            if (pathOwned && (prev->text.first != prev->text.afterLast)) {
380
0
                                memory->free(memory, (URI_CHAR *)prev->text.first);
381
0
                            }
382
0
                            memory->free(memory, prev);
383
384
0
                            walker = nextBackup;
385
0
                        }
386
0
                    } else {
387
0
                        URI_TYPE(PathSegment) * const anotherNextBackup = walker->next;
388
0
                        int freeWalker = URI_TRUE;
389
390
                        /* First segment */
391
0
                        if (walker->next != NULL) {
392
                            /* First segment of multiple -> update head
393
                             * OLD: head -> walker -> next
394
                             * NEW: head -----------> next */
395
0
                            uri->pathHead = walker->next;
396
397
                            /* Update parent link as well
398
                             * OLD: head <- walker <- next
399
                             * NEW: head <----------- next */
400
0
                            walker->next->reserved = NULL;
401
0
                        } else {
402
0
                            if (uri->absolutePath) {
403
                                /* First and only segment -> update head
404
                                 * OLD: head -> walker -> NULL
405
                                 * NEW: head -----------> NULL */
406
0
                                uri->pathHead = NULL;
407
408
                                /* Last segment -> update tail
409
                                 * OLD: tail -> walker
410
                                 * NEW: tail -> NULL */
411
0
                                uri->pathTail = NULL;
412
0
                            } else {
413
                                /* Reuse segment for "" path segment to represent trailing
414
                                 * slash, then update head and tail */
415
0
                                if (pathOwned
416
0
                                    && (walker->text.first != walker->text.afterLast)) {
417
0
                                    memory->free(memory, (URI_CHAR *)walker->text.first);
418
0
                                }
419
0
                                walker->text.first = URI_FUNC(SafeToPointTo);
420
0
                                walker->text.afterLast = URI_FUNC(SafeToPointTo);
421
0
                                freeWalker = URI_FALSE;
422
0
                            }
423
0
                        }
424
425
0
                        if (freeWalker) {
426
0
                            if (pathOwned
427
0
                                && (walker->text.first != walker->text.afterLast)) {
428
0
                                memory->free(memory, (URI_CHAR *)walker->text.first);
429
0
                            }
430
0
                            memory->free(memory, walker);
431
0
                        }
432
433
0
                        walker = anotherNextBackup;
434
0
                    }
435
0
                }
436
0
            }
437
0
            break;
438
0
        } /* end of switch */
439
440
0
        if (!removeSegment) {
441
            /* .. then let's move to the next element, and start again. */
442
0
            if (walker->next != NULL) {
443
0
                walker->next->reserved = walker;
444
0
            } else {
445
                /* Last segment -> update tail */
446
0
                uri->pathTail = walker;
447
0
            }
448
0
            walker = walker->next;
449
0
        }
450
0
    } while (walker != NULL);
451
452
0
    return URI_TRUE;
453
0
}
Unexecuted instantiation: uriRemoveDotSegmentsExA
Unexecuted instantiation: uriRemoveDotSegmentsExW
454
455
/* Properly removes "." and ".." path segments */
456
UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
457
0
                                            UriMemoryManager * memory) {
458
0
    const UriBool ABSOLUTE = URI_FALSE;
459
0
    if (uri == NULL) {
460
0
        return URI_TRUE;
461
0
    }
462
0
    return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory);
463
0
}
Unexecuted instantiation: uriRemoveDotSegmentsAbsoluteA
Unexecuted instantiation: uriRemoveDotSegmentsAbsoluteW
464
465
0
unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
466
0
    switch (hexdig) {
467
0
    case URI_SET_DIGIT(_UT):
468
0
        return (unsigned char)(9 + hexdig - _UT('9'));
469
0
    case URI_SET_HEX_LETTER_LOWER(_UT):
470
0
        return (unsigned char)(15 + hexdig - _UT('f'));
471
0
    case URI_SET_HEX_LETTER_UPPER(_UT):
472
0
        return (unsigned char)(15 + hexdig - _UT('F'));
473
474
0
    default:
475
0
        return 0;
476
0
    }
477
0
}
Unexecuted instantiation: uriHexdigToIntA
Unexecuted instantiation: uriHexdigToIntW
478
479
0
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
480
0
    switch (value) {
481
0
    case 0:
482
0
        return _UT('0');
483
0
    case 1:
484
0
        return _UT('1');
485
0
    case 2:
486
0
        return _UT('2');
487
0
    case 3:
488
0
        return _UT('3');
489
0
    case 4:
490
0
        return _UT('4');
491
0
    case 5:
492
0
        return _UT('5');
493
0
    case 6:
494
0
        return _UT('6');
495
0
    case 7:
496
0
        return _UT('7');
497
0
    case 8:
498
0
        return _UT('8');
499
0
    case 9:
500
0
        return _UT('9');
501
502
0
    case 10:
503
0
        return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
504
0
    case 11:
505
0
        return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
506
0
    case 12:
507
0
        return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
508
0
    case 13:
509
0
        return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
510
0
    case 14:
511
0
        return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
512
0
    default:
513
0
        return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
514
0
    }
515
0
}
Unexecuted instantiation: uriHexToLetterExA
Unexecuted instantiation: uriHexToLetterExW
516
517
/* Checks if a URI has the host component set. */
518
0
UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri) {
519
    /* NOTE: .hostData.ipFuture.first is not being checked,   *
520
     *       because we do check .hostText.first and          *
521
     *       .hostData.ipFuture.first has to be identical to  *
522
     *       .hostText.first if set, and hence there is       *
523
     *       no more information to be gained.                */
524
0
    return (uri != NULL)
525
0
           && ((uri->hostText.first != NULL) || (uri->hostData.ip4 != NULL)
526
0
               || (uri->hostData.ip6 != NULL));
527
0
}
Unexecuted instantiation: uriHasHostA
Unexecuted instantiation: uriHasHostW
528
529
/* Copies the path segment list from one URI to another. */
530
UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
531
0
                           UriMemoryManager * memory) {
532
0
    if (source->pathHead == NULL) {
533
        /* No path component */
534
0
        dest->pathHead = NULL;
535
0
        dest->pathTail = NULL;
536
0
    } else {
537
        /* Copy list but not the text contained */
538
0
        URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
539
0
        URI_TYPE(PathSegment) * destPrev = NULL;
540
0
        do {
541
0
            URI_TYPE(PathSegment) * cur =
542
0
                memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
543
0
            if (cur == NULL) {
544
                /* Fix broken list */
545
0
                if (destPrev != NULL) {
546
0
                    destPrev->next = NULL;
547
0
                }
548
0
                return URI_FALSE; /* Raises malloc error */
549
0
            }
550
551
            /* From this functions usage we know that *
552
             * the dest URI cannot be uri->owner      */
553
0
            cur->text = sourceWalker->text;
554
0
            if (destPrev == NULL) {
555
                /* First segment ever */
556
0
                dest->pathHead = cur;
557
0
            } else {
558
0
                destPrev->next = cur;
559
0
            }
560
0
            destPrev = cur;
561
0
            sourceWalker = sourceWalker->next;
562
0
        } while (sourceWalker != NULL);
563
0
        dest->pathTail = destPrev;
564
0
        dest->pathTail->next = NULL;
565
0
    }
566
567
0
    dest->absolutePath = source->absolutePath;
568
0
    return URI_TRUE;
569
0
}
Unexecuted instantiation: uriCopyPathA
Unexecuted instantiation: uriCopyPathW
570
571
/* Copies the authority part of an URI over to another. */
572
UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
573
0
                                UriMemoryManager * memory) {
574
    /* From this functions usage we know that *
575
     * the dest URI cannot be uri->owner      */
576
577
    /* Copy userInfo */
578
0
    dest->userInfo = source->userInfo;
579
580
    /* Copy hostText */
581
0
    dest->hostText = source->hostText;
582
583
    /* Copy hostData */
584
0
    if (source->hostData.ip4 != NULL) {
585
0
        dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
586
0
        if (dest->hostData.ip4 == NULL) {
587
0
            return URI_FALSE; /* Raises malloc error */
588
0
        }
589
0
        *(dest->hostData.ip4) = *(source->hostData.ip4);
590
0
        dest->hostData.ip6 = NULL;
591
0
        dest->hostData.ipFuture.first = NULL;
592
0
        dest->hostData.ipFuture.afterLast = NULL;
593
0
    } else if (source->hostData.ip6 != NULL) {
594
0
        dest->hostData.ip4 = NULL;
595
0
        dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
596
0
        if (dest->hostData.ip6 == NULL) {
597
0
            return URI_FALSE; /* Raises malloc error */
598
0
        }
599
0
        *(dest->hostData.ip6) = *(source->hostData.ip6);
600
0
        dest->hostData.ipFuture.first = NULL;
601
0
        dest->hostData.ipFuture.afterLast = NULL;
602
0
    } else {
603
0
        dest->hostData.ip4 = NULL;
604
0
        dest->hostData.ip6 = NULL;
605
0
        dest->hostData.ipFuture = source->hostData.ipFuture;
606
0
    }
607
608
    /* Copy portText */
609
0
    dest->portText = source->portText;
610
611
0
    return URI_TRUE;
612
0
}
Unexecuted instantiation: uriCopyAuthorityA
Unexecuted instantiation: uriCopyAuthorityW
613
614
0
UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
615
0
    URI_TYPE(PathSegment) * segment;
616
617
0
    if (/* Case 1: absolute path, empty first segment */
618
0
        (uri->absolutePath && (uri->pathHead != NULL)
619
0
         && (uri->pathHead->text.afterLast == uri->pathHead->text.first))
620
621
        /* Case 2: relative path, empty first and second segment */
622
0
        || (!uri->absolutePath && (uri->pathHead != NULL) && (uri->pathHead->next != NULL)
623
0
            && (uri->pathHead->text.afterLast == uri->pathHead->text.first)
624
0
            && (uri->pathHead->next->text.afterLast
625
0
                == uri->pathHead->next->text.first))) {
626
        /* NOOP */
627
0
    } else {
628
0
        return URI_TRUE;
629
0
    }
630
631
0
    segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
632
0
    if (segment == NULL) {
633
0
        return URI_FALSE; /* Raises malloc error */
634
0
    }
635
636
    /* Insert "." segment in front */
637
0
    segment->next = uri->pathHead;
638
0
    segment->text.first = URI_FUNC(ConstPwd);
639
0
    segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
640
0
    uri->pathHead = segment;
641
0
    return URI_TRUE;
642
0
}
Unexecuted instantiation: uriFixAmbiguityA
Unexecuted instantiation: uriFixAmbiguityW
643
644
static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri,
645
0
                                              UriMemoryManager * memory) {
646
0
    assert(uri != NULL);
647
0
    assert(memory != NULL);
648
649
0
    URI_TYPE(PathSegment) * const segment =
650
0
        memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
651
652
0
    if (segment == NULL) {
653
0
        return URI_FALSE; /* i.e. raise malloc error */
654
0
    }
655
656
0
    segment->next = uri->pathHead;
657
658
0
    URI_TYPE(TextRange) dotRange;
659
0
    dotRange.first = URI_FUNC(ConstPwd);
660
0
    dotRange.afterLast = URI_FUNC(ConstPwd) + 1;
661
662
0
    if (uri->owner == URI_TRUE) {
663
0
        if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) {
664
0
            memory->free(memory, segment);
665
0
            return URI_FALSE; /* i.e. raise malloc error */
666
0
        }
667
0
    } else {
668
0
        segment->text = dotRange; /* copies all members */
669
0
    }
670
671
0
    uri->pathHead = segment;
672
673
0
    return URI_TRUE;
674
0
}
Unexecuted instantiation: UriCommon.c:uriPrependNewDotSegmentA
Unexecuted instantiation: UriCommon.c:uriPrependNewDotSegmentW
675
676
/* When dropping a scheme from a URI without a host and with a colon (":")
677
 * in the first path segment, a consecutive reparse would rightfully
678
 * mis-classify the first path segment as a scheme due to the colon.
679
 * To protect against this case, we prepend an artificial "." segment
680
 * to the path in here; the function is called after the scheme has
681
 * just been dropped.
682
 *
683
 * 0. We start with parsed URI "scheme:path1:/path2/path3".
684
 * 1. We drop the scheme naively and yield "path1:/path2/path3".
685
 * 2. We prepend "." and yield unambiguous "./path1:/path2/path3".
686
 *
687
 * From the view of the RFC 3986 grammar, this is replacing rule path-rootless
688
 * by path-noscheme content.
689
 *
690
 * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
691
 * Returns URI_FALSE to signal out-of-memory.
692
 */
693
0
UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
694
0
    assert(uri != NULL);
695
0
    assert(memory != NULL);
696
697
0
    if ((uri->absolutePath == URI_TRUE) || (uri->pathHead == NULL)
698
0
        || (uri->scheme.first != NULL) || URI_FUNC(HasHost)(uri)) {
699
0
        return URI_TRUE; /* i.e. nothing to do */
700
0
    }
701
702
    /* Check for troublesome first path segment containing a colon */
703
0
    UriBool colonFound = URI_FALSE;
704
0
    const URI_CHAR * walker = uri->pathHead->text.first;
705
706
0
    while (walker < uri->pathHead->text.afterLast) {
707
0
        if (walker[0] == _UT(':')) {
708
0
            colonFound = URI_TRUE;
709
0
            break;
710
0
        }
711
0
        walker++;
712
0
    }
713
714
0
    assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE));
715
716
0
    if (colonFound == URI_FALSE) {
717
0
        return URI_TRUE; /* i.e. nothing to do */
718
0
    }
719
720
    /* Insert "." segment in front */
721
0
    return URI_FUNC(PrependNewDotSegment)(uri, memory);
722
0
}
Unexecuted instantiation: uriFixPathNoSchemeA
Unexecuted instantiation: uriFixPathNoSchemeW
723
724
/* When dropping a host from a URI without a scheme, an absolute path
725
 * and empty first path segment, a consecutive reparse would rightfully
726
 * mis-classify the first path segment as a host marker due to the "//".
727
 * To protect against this case, we prepend an artificial "." segment
728
 * to the path in here; the function is called after the host has
729
 * just been dropped.
730
 *
731
 * 0. We start with parsed URI "//host//path1/path2".
732
 * 1. We drop the host naively and yield "//path1/path2".
733
 * 2. We insert "./" and yield unambiguous "/.//path1/path2".
734
 *
735
 * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
736
 * Returns URI_FALSE to signal out-of-memory.
737
 */
738
UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri,
739
0
                                                     UriMemoryManager * memory) {
740
0
    assert(uri != NULL);
741
0
    assert(memory != NULL);
742
743
0
    if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->absolutePath == URI_FALSE)
744
0
        || (uri->pathHead == NULL)
745
0
        || (uri->pathHead == uri->pathTail) /* i.e. no second slash */
746
0
        || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
747
0
        return URI_TRUE; /* i.e. nothing to do */
748
0
    }
749
750
    /* Insert "." segment in front */
751
0
    return URI_FUNC(PrependNewDotSegment)(uri, memory);
752
0
}
Unexecuted instantiation: uriEnsureThatPathIsNotMistakenForHostA
Unexecuted instantiation: uriEnsureThatPathIsNotMistakenForHostW
753
754
0
void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
755
    /* Fix path if only one empty segment */
756
0
    if (!uri->absolutePath && !URI_FUNC(HasHost)(uri) && (uri->pathHead != NULL)
757
0
        && (uri->pathHead->next == NULL)
758
0
        && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
759
0
        memory->free(memory, uri->pathHead);
760
0
        uri->pathHead = NULL;
761
        uri->pathTail = NULL;
762
0
    }
763
0
}
Unexecuted instantiation: uriFixEmptyTrailSegmentA
Unexecuted instantiation: uriFixEmptyTrailSegmentW
764
765
#endif