Coverage Report

Created: 2026-04-12 06:45

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