Coverage Report

Created: 2026-06-02 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/uri/uriparser/src/UriFile.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 "UriFile.c"
47
#    undef URI_PASS_ANSI
48
#  endif
49
#  ifdef URI_ENABLE_UNICODE
50
#    define URI_PASS_UNICODE 1
51
#    include "UriFile.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
#  endif
65
66
#  include <stddef.h>  // size_t
67
#  include <stdint.h>  // SIZE_MAX
68
69
static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
70
                                                    URI_CHAR * uriString,
71
0
                                                    UriBool fromUnix) {
72
0
    const URI_CHAR * input = filename;
73
0
    const URI_CHAR * lastSep = input - 1;
74
0
    UriBool firstSegment = URI_TRUE;
75
0
    URI_CHAR * output = uriString;
76
0
    UriBool absolute;
77
0
    UriBool is_windows_network;
78
79
0
    if ((filename == NULL) || (uriString == NULL)) {
80
0
        return URI_ERROR_NULL;
81
0
    }
82
83
0
    is_windows_network = (filename[0] == _UT('\\')) && (filename[1] == _UT('\\'));
84
0
    absolute = fromUnix ? (filename[0] == _UT('/'))
85
0
                        : (((filename[0] != _UT('\0')) && (filename[1] == _UT(':')))
86
0
                           || is_windows_network);
87
88
0
    if (absolute) {
89
0
        const URI_CHAR * const prefix = fromUnix             ? _UT("file://")
90
0
                                        : is_windows_network ? _UT("file:")
91
0
                                                             : _UT("file:///");
92
0
        const size_t prefixLen = URI_STRLEN(prefix);
93
94
        // Detect and avoid integer overflow
95
0
        if (prefixLen > SIZE_MAX / sizeof(URI_CHAR)) {
96
0
            return URI_ERROR_OUTPUT_TOO_LARGE;
97
0
        }
98
99
        /* Copy prefix */
100
0
        memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
101
0
        output += prefixLen;
102
0
    }
103
104
    /* Copy and escape on the fly */
105
0
    for (;;) {
106
0
        if ((input[0] == _UT('\0')) || (fromUnix && input[0] == _UT('/'))
107
0
            || (!fromUnix && input[0] == _UT('\\'))) {
108
            /* Copy text after last separator */
109
0
            if (lastSep + 1 < input) {
110
0
                if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
111
                    /* Quick hack to not convert "C:" to "C%3A" */
112
0
                    const size_t charsToCopy = input - (lastSep + 1);
113
114
                    // Detect and avoid integer overflow
115
0
                    if (charsToCopy > SIZE_MAX / sizeof(URI_CHAR)) {
116
0
                        return URI_ERROR_OUTPUT_TOO_LARGE;
117
0
                    }
118
119
0
                    memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
120
0
                    output += charsToCopy;
121
0
                } else {
122
0
                    output = URI_FUNC(EscapeEx)(lastSep + 1, input, output, URI_FALSE,
123
0
                                                URI_FALSE);
124
0
                }
125
0
            }
126
0
            firstSegment = URI_FALSE;
127
0
        }
128
129
0
        if (input[0] == _UT('\0')) {
130
0
            output[0] = _UT('\0');
131
0
            break;
132
0
        } else if (fromUnix && (input[0] == _UT('/'))) {
133
            /* Copy separators unmodified */
134
0
            output[0] = _UT('/');
135
0
            output++;
136
0
            lastSep = input;
137
0
        } else if (!fromUnix && (input[0] == _UT('\\'))) {
138
            /* Convert backslashes to forward slashes */
139
0
            output[0] = _UT('/');
140
0
            output++;
141
0
            lastSep = input;
142
0
        }
143
0
        input++;
144
0
    }
145
146
0
    return URI_SUCCESS;
147
0
}
Unexecuted instantiation: UriFile.c:uriFilenameToUriStringA
Unexecuted instantiation: UriFile.c:uriFilenameToUriStringW
148
149
static URI_INLINE int URI_FUNC(UriStringToFilename)(const URI_CHAR * uriString,
150
0
                                                    URI_CHAR * filename, UriBool toUnix) {
151
0
    if ((uriString == NULL) || (filename == NULL)) {
152
0
        return URI_ERROR_NULL;
153
0
    }
154
155
0
    const UriBool file_unknown_slashes =
156
0
        URI_STRNCMP(uriString, _UT("file:"), URI_STRLEN(_UT("file:"))) == 0;
157
0
    const UriBool file_one_or_more_slashes =
158
0
        file_unknown_slashes
159
0
        && (URI_STRNCMP(uriString, _UT("file:/"), URI_STRLEN(_UT("file:/"))) == 0);
160
0
    const UriBool file_two_or_more_slashes =
161
0
        file_one_or_more_slashes
162
0
        && (URI_STRNCMP(uriString, _UT("file://"), URI_STRLEN(_UT("file://"))) == 0);
163
0
    const UriBool file_three_or_more_slashes =
164
0
        file_two_or_more_slashes
165
0
        && (URI_STRNCMP(uriString, _UT("file:///"), URI_STRLEN(_UT("file:///"))) == 0);
166
167
0
    const size_t charsToSkip =
168
0
        file_two_or_more_slashes
169
0
            ? file_three_or_more_slashes ? toUnix
170
                                               /* file:///bin/bash */
171
0
                                               ? URI_STRLEN(_UT("file://"))
172
                                               /* file:///E:/Documents%20and%20Settings */
173
0
                                               : URI_STRLEN(_UT("file:///"))
174
                                         /* file://Server01/Letter.txt */
175
0
                                         : URI_STRLEN(_UT("file://"))
176
0
            : ((file_one_or_more_slashes && toUnix)
177
                   /* file:/bin/bash */
178
                   /* https://tools.ietf.org/html/rfc8089#appendix-B */
179
0
                   ? URI_STRLEN(_UT("file:"))
180
0
                   : ((!toUnix && file_unknown_slashes && !file_one_or_more_slashes)
181
                          /* file:c:/path/to/file */
182
                          /* https://tools.ietf.org/html/rfc8089#appendix-E.2 */
183
0
                          ? URI_STRLEN(_UT("file:"))
184
0
                          : 0));
185
0
    const size_t charsToCopy = URI_STRLEN(uriString + charsToSkip) + 1;
186
187
0
    const UriBool is_windows_network_with_authority =
188
0
        (toUnix == URI_FALSE) && file_two_or_more_slashes && !file_three_or_more_slashes;
189
190
0
    URI_CHAR * const unescape_target =
191
0
        is_windows_network_with_authority ? (filename + 2) : filename;
192
193
0
    if (is_windows_network_with_authority) {
194
0
        filename[0] = '\\';
195
0
        filename[1] = '\\';
196
0
    }
197
198
0
    memcpy(unescape_target, uriString + charsToSkip, charsToCopy * sizeof(URI_CHAR));
199
0
    URI_FUNC(UnescapeInPlaceEx)(filename, URI_FALSE, URI_BR_DONT_TOUCH);
200
201
    /* Convert forward slashes to backslashes */
202
0
    if (!toUnix) {
203
0
        URI_CHAR * walker = filename;
204
0
        while (walker[0] != _UT('\0')) {
205
0
            if (walker[0] == _UT('/')) {
206
0
                walker[0] = _UT('\\');
207
0
            }
208
0
            walker++;
209
0
        }
210
0
    }
211
212
0
    return URI_SUCCESS;
213
0
}
Unexecuted instantiation: UriFile.c:uriUriStringToFilenameA
Unexecuted instantiation: UriFile.c:uriUriStringToFilenameW
214
215
0
int URI_FUNC(UnixFilenameToUriString)(const URI_CHAR * filename, URI_CHAR * uriString) {
216
0
    return URI_FUNC(FilenameToUriString)(filename, uriString, URI_TRUE);
217
0
}
Unexecuted instantiation: uriUnixFilenameToUriStringA
Unexecuted instantiation: uriUnixFilenameToUriStringW
218
219
int URI_FUNC(WindowsFilenameToUriString)(const URI_CHAR * filename,
220
0
                                         URI_CHAR * uriString) {
221
0
    return URI_FUNC(FilenameToUriString)(filename, uriString, URI_FALSE);
222
0
}
Unexecuted instantiation: uriWindowsFilenameToUriStringA
Unexecuted instantiation: uriWindowsFilenameToUriStringW
223
224
0
int URI_FUNC(UriStringToUnixFilename)(const URI_CHAR * uriString, URI_CHAR * filename) {
225
0
    return URI_FUNC(UriStringToFilename)(uriString, filename, URI_TRUE);
226
0
}
Unexecuted instantiation: uriUriStringToUnixFilenameA
Unexecuted instantiation: uriUriStringToUnixFilenameW
227
228
int URI_FUNC(UriStringToWindowsFilename)(const URI_CHAR * uriString,
229
0
                                         URI_CHAR * filename) {
230
0
    return URI_FUNC(UriStringToFilename)(uriString, filename, URI_FALSE);
231
0
}
Unexecuted instantiation: uriUriStringToWindowsFilenameA
Unexecuted instantiation: uriUriStringToWindowsFilenameW
232
233
#endif