ReactOS 0.4.16-dev-1946-g52006dd
url.c
Go to the documentation of this file.
1/* Unit test suite for Path functions
2 *
3 * Copyright 2002 Matthew Mastracci
4 * Copyright 2007-2010 Detlef Riekenberg
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include <stdarg.h>
22#include <stdio.h>
23
24#include "wine/test.h"
25#include "windef.h"
26#include "winbase.h"
27#include "winreg.h"
28#include "shlwapi.h"
29#include "wininet.h"
30#include "intshcut.h"
31#include "winternl.h"
32
33static const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
34static const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
35static const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
36
37static const WCHAR winehqW[] = L"http://www.winehq.org/";
38static const char winehqA[] = "http://www.winehq.org/";
39static const CHAR untouchedA[] = "untouched";
40
41typedef struct _TEST_URL_APPLY {
42 const char * url;
45 const char * newurl;
47
48static const TEST_URL_APPLY TEST_APPLY[] = {
49 {"www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, "http://www.winehq.org"},
50 {"www.winehq.org", URL_APPLY_GUESSSCHEME, S_OK, "http://www.winehq.org"},
51 {"www.winehq.org", URL_APPLY_DEFAULT, S_OK, "http://www.winehq.org"},
52 {"ftp.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, "ftp://ftp.winehq.org"},
53 {"ftp.winehq.org", URL_APPLY_GUESSSCHEME, S_OK, "ftp://ftp.winehq.org"},
54 {"ftp.winehq.org", URL_APPLY_DEFAULT, S_OK, "http://ftp.winehq.org"},
55 {"winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, "http://winehq.org"},
56 {"winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE},
57 {"winehq.org", URL_APPLY_DEFAULT, S_OK, "http://winehq.org"},
58 {"http://www.winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE},
59 {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY, S_FALSE},
60 {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY | URL_APPLY_DEFAULT, S_OK, "http://http://www.winehq.org"},
61 {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_FALSE},
64 {"", URL_APPLY_DEFAULT, S_OK, "http://"},
65 {"u:\\windows", URL_APPLY_GUESSFILE | URL_APPLY_DEFAULT, S_OK, "file:///u:/windows"},
66 {"u:\\windows", URL_APPLY_GUESSFILE, S_OK, "file:///u:/windows"},
67 {"u:\\windows", URL_APPLY_DEFAULT, S_OK, "http://u:\\windows"},
68 {"file:///c:/windows", URL_APPLY_GUESSFILE, S_FALSE},
69 {"aa:\\windows", URL_APPLY_GUESSFILE, S_FALSE},
70 {"\\\\server\\share", URL_APPLY_DEFAULT, S_OK, "http://\\\\server\\share"},
71 {"\\\\server\\share", URL_APPLY_GUESSFILE, S_OK, "file://server/share"},
72 {"\\\\server\\share", URL_APPLY_GUESSSCHEME, S_FALSE},
73 {"file://server/share", URL_APPLY_GUESSFILE, S_FALSE},
74 {"file://server/share", URL_APPLY_GUESSSCHEME, S_FALSE},
75};
76
77typedef struct _TEST_URL_ESCAPE {
78 const char *url;
80 const char *expecturl;
82
83static const TEST_URL_ESCAPE TEST_ESCAPE[] = {
84 {"http://www.winehq.org/tests0", 0, "http://www.winehq.org/tests0"},
85 {"http://www.winehq.org/tests1\n", 0, "http://www.winehq.org/tests1%0A"},
86 {"http://www.winehq.org/tests2\r", 0, "http://www.winehq.org/tests2%0D"},
87 {"http://www.winehq.org/tests3\r", URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, "http://www.winehq.org/tests3\r"},
88 {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, "http://www.winehq.org/tests4\r"},
89 {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, "http://www.winehq.org/tests5\r"},
90 {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"},
91
92 {"file://////foo/bar\\baz", 0, "file://foo/bar/baz"},
93 {"file://///foo/bar\\baz", 0, "file://foo/bar/baz"},
94 {"file:////foo/bar\\baz", 0, "file://foo/bar/baz"},
95 {"file:///localhost/foo/bar\\baz", 0, "file:///localhost/foo/bar/baz"},
96 {"file:///foo/bar\\baz", 0, "file:///foo/bar/baz"},
97 {"file://loCalHost/foo/bar\\baz", 0, "file:///foo/bar/baz"},
98 {"file://foo/bar\\baz", 0, "file://foo/bar/baz"},
99 {"file:/localhost/foo/bar\\baz", 0, "file:///localhost/foo/bar/baz"},
100 {"file:/foo/bar\\baz", 0, "file:///foo/bar/baz"},
101 {"file:foo/bar\\baz", 0, "file:foo/bar/baz"},
102 {"file:\\foo/bar\\baz", 0, "file:///foo/bar/baz"},
103 {"file:\\\\foo/bar\\baz", 0, "file://foo/bar/baz"},
104 {"file:\\\\\\foo/bar\\baz", 0, "file:///foo/bar/baz"},
105 {"file:\\\\localhost\\foo/bar\\baz", 0, "file:///foo/bar/baz"},
106 {"file:///f oo/b?a r\\baz", 0, "file:///f%20oo/b?a r\\baz"},
107 {"file:///foo/b#a r\\baz", 0, "file:///foo/b%23a%20r/baz"},
108 {"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"},
109 {"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, "file:///f%20o%25o/b?a r\\b%az"},
110 {"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, "file:%2Ffoo%2Fbar%5Cbaz"},
111
112 {"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, "foo%2Fb%ar%5Cba%3Fz%5C"},
113 {"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, "foo%2Fb%25ar%5Cba%3Fz%5C"},
114 {"foo/bar\\ba?z\\", 0, "foo/bar%5Cba?z\\"},
115 {"/foo/bar\\ba?z\\", 0, "/foo/bar%5Cba?z\\"},
116 {"/foo/bar\\ba#z\\", 0, "/foo/bar%5Cba#z\\"},
117 {"/foo/%5C", 0, "/foo/%5C"},
118 {"/foo/%5C", URL_ESCAPE_PERCENT, "/foo/%255C"},
119
120 {"http://////foo/bar\\baz", 0, "http://////foo/bar/baz"},
121 {"http://///foo/bar\\baz", 0, "http://///foo/bar/baz"},
122 {"http:////foo/bar\\baz", 0, "http:////foo/bar/baz"},
123 {"http:///foo/bar\\baz", 0, "http:///foo/bar/baz"},
124 {"http://localhost/foo/bar\\baz", 0, "http://localhost/foo/bar/baz"},
125 {"http://foo/bar\\baz", 0, "http://foo/bar/baz"},
126 {"http:/foo/bar\\baz", 0, "http:/foo/bar/baz"},
127 {"http:foo/bar\\ba?z\\", 0, "http:foo%2Fbar%2Fba?z\\"},
128 {"http:foo/bar\\ba#z\\", 0, "http:foo%2Fbar%2Fba#z\\"},
129 {"http:\\foo/bar\\baz", 0, "http:/foo/bar/baz"},
130 {"http:\\\\foo/bar\\baz", 0, "http://foo/bar/baz"},
131 {"http:\\\\\\foo/bar\\baz", 0, "http:///foo/bar/baz"},
132 {"http:\\\\\\\\foo/bar\\baz", 0, "http:////foo/bar/baz"},
133 {"http:/fo ?o/b ar\\baz", 0, "http:/fo%20?o/b ar\\baz"},
134 {"http:fo ?o/b ar\\baz", 0, "http:fo%20?o/b ar\\baz"},
135 {"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, "http:%2Ffoo%2Fbar%5Cbaz"},
136
137 {"https://foo/bar\\baz", 0, "https://foo/bar/baz"},
138 {"https:/foo/bar\\baz", 0, "https:/foo/bar/baz"},
139 {"https:\\foo/bar\\baz", 0, "https:/foo/bar/baz"},
140
141 {"foo:////foo/bar\\baz", 0, "foo:////foo/bar%5Cbaz"},
142 {"foo:///foo/bar\\baz", 0, "foo:///foo/bar%5Cbaz"},
143 {"foo://localhost/foo/bar\\baz", 0, "foo://localhost/foo/bar%5Cbaz"},
144 {"foo://foo/bar\\baz", 0, "foo://foo/bar%5Cbaz"},
145 {"foo:/foo/bar\\baz", 0, "foo:/foo/bar%5Cbaz"},
146 {"foo:foo/bar\\baz", 0, "foo:foo%2Fbar%5Cbaz"},
147 {"foo:\\foo/bar\\baz", 0, "foo:%5Cfoo%2Fbar%5Cbaz"},
148 {"foo:/foo/bar\\ba?\\z", 0, "foo:/foo/bar%5Cba?\\z"},
149 {"foo:/foo/bar\\ba#\\z", 0, "foo:/foo/bar%5Cba#\\z"},
150
151 {"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
152 {"mailto:fo/o@b\\%a?\\r.b#\\az", 0, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"},
153 {"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"},
154
155 {"ftp:fo/o@bar.baz/foo/bar", 0, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"},
156 {"ftp:/fo/o@bar.baz/foo/bar", 0, "ftp:/fo/o@bar.baz/foo/bar"},
157 {"ftp://fo/o@bar.baz/fo?o\\bar", 0, "ftp://fo/o@bar.baz/fo?o\\bar"},
158 {"ftp://fo/o@bar.baz/fo#o\\bar", 0, "ftp://fo/o@bar.baz/fo#o\\bar"},
159 {"ftp://localhost/o@bar.baz/fo#o\\bar", 0, "ftp://localhost/o@bar.baz/fo#o\\bar"},
160 {"ftp:///fo/o@bar.baz/foo/bar", 0, "ftp:///fo/o@bar.baz/foo/bar"},
161 {"ftp:////fo/o@bar.baz/foo/bar", 0, "ftp:////fo/o@bar.baz/foo/bar"},
162
163 {"ftp\x1f\1end/", 0, "ftp%1F%01end/"}
164};
165
166typedef struct _TEST_URL_ESCAPEW {
172
174 {L" <>\"", URL_ESCAPE_AS_UTF8, L"%20%3C%3E%22"},
175 {L"{}|\\", URL_ESCAPE_AS_UTF8, L"%7B%7D%7C%5C"},
176 {L"^][`", URL_ESCAPE_AS_UTF8, L"%5E%5D%5B%60"},
177 {L"&/?#", URL_ESCAPE_AS_UTF8, L"%26/?#"},
178 {L"Mass", URL_ESCAPE_AS_UTF8, L"Mass"},
179
180 /* broken < Win8/10 */
181 {L"Ma\xdf", URL_ESCAPE_AS_UTF8, L"Ma%C3%9F", L"Ma%DF"},
182 {L"\xd841\xdf0e", URL_ESCAPE_AS_UTF8, L"%F0%A0%9C%8E", L"%EF%BF%BD%EF%BF%BD"}, /* 0x2070E */
183 {L"\xd85e\xde3e", URL_ESCAPE_AS_UTF8, L"%F0%A7%A8%BE", L"%EF%BF%BD%EF%BF%BD"}, /* 0x27A3E */
184 {L"\xd85e", URL_ESCAPE_AS_UTF8, L"%EF%BF%BD", L"\xd85e"},
185 {L"\xd85eQ", URL_ESCAPE_AS_UTF8, L"%EF%BF%BDQ", L"\xd85eQ"},
186 {L"\xdc00", URL_ESCAPE_AS_UTF8, L"%EF%BF%BD", L"\xdc00"},
187 {L"\xffff", URL_ESCAPE_AS_UTF8, L"%EF%BF%BF", L"\xffff"},
188};
189
190/* ################ */
191
192typedef struct _TEST_URL_COMBINE {
193 const char *url1;
194 const char *url2;
196 const char *expecturl;
198
200 {"http://www.winehq.org/tests", "tests1", 0, "http://www.winehq.org/tests1"},
201 {"http://www.%77inehq.org/tests", "tests1", 0, "http://www.%77inehq.org/tests1"},
202 /*FIXME {"http://www.winehq.org/tests", "../tests2", 0, "http://www.winehq.org/tests2"},*/
203 {"http://www.winehq.org/tests/", "../tests3", 0, "http://www.winehq.org/tests3"},
204 {"http://www.winehq.org/tests/test1", "test2", 0, "http://www.winehq.org/tests/test2"},
205 {"http://www.winehq.org/tests/../tests", "tests4", 0, "http://www.winehq.org/tests4"},
206 {"http://www.winehq.org/tests/../tests/", "tests5", 0, "http://www.winehq.org/tests/tests5"},
207 {"http://www.winehq.org/tests/../tests/", "/tests6/..", 0, "http://www.winehq.org/"},
208 {"http://www.winehq.org/tests/../tests/", "\\tests6\\..", 0, "http://www.winehq.org/"},
209 {"http://www.winehq.org/tests/../tests/..", "tests7/..", 0, "http://www.winehq.org/"},
210 {"http://www.winehq.org/tests/?query=x&return=y", "tests8", 0, "http://www.winehq.org/tests/tests8"},
211 {"http://www.winehq.org/tests/#example", "tests9", 0, "http://www.winehq.org/tests/tests9"},
212 {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, "http://www.winehq.org/tests10/.."},
213 {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, "http://www.winehq.org/tests/../tests11"},
214 {"http://www.winehq.org/test12", "#", 0, "http://www.winehq.org/test12#"},
215 {"http://www.winehq.org/test13#aaa", "#bbb", 0, "http://www.winehq.org/test13#bbb"},
216 {"http://www.winehq.org/test14#aaa/bbb#ccc", "#", 0, "http://www.winehq.org/test14#"},
217 {"http://www.winehq.org/tests/?query=x/y/z", "tests15", 0, "http://www.winehq.org/tests/tests15"},
218 {"http://www.winehq.org/tests/?query=x/y/z#example", "tests16", 0, "http://www.winehq.org/tests/tests16"},
219 {"file:///C:\\dir\\file.txt", "test.txt", 0, "file:///C:/dir/test.txt"},
220 {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, "file:///C:/dir/file.txt#hash/test.txt"},
221 {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, "file:///C:/dir/test.html"},
222 {"file:///C:\\dir\\file.htm#hash\\hash", "test.htm", 0, "file:///C:/dir/test.htm"},
223 {"file:///C:\\dir\\file.hTmL#hash\\hash", "test.hTmL", 0, "file:///C:/dir/test.hTmL"},
224 {"file:///C:\\dir.html\\file.txt#hash\\hash", "test.txt", 0, "file:///C:/dir.html/file.txt#hash/test.txt"},
225 {"C:\\winehq\\winehq.txt", "C:\\Test\\test.txt", 0, "file:///C:/Test/test.txt"},
226 {"http://www.winehq.org/test/", "test%20file.txt", 0, "http://www.winehq.org/test/test%20file.txt"},
227 {"http://www.winehq.org/test/", "test%20file.txt", URL_FILE_USE_PATHURL, "http://www.winehq.org/test/test%20file.txt"},
228 {"http://www.winehq.org%2ftest/", "test%20file.txt", URL_FILE_USE_PATHURL, "http://www.winehq.org%2ftest/test%20file.txt"},
229 {"xxx:@MSITStore:file.chm/file.html", "dir/file", 0, "xxx:dir/file"},
230 {"mk:@MSITStore:file.chm::/file.html", "/dir/file", 0, "mk:@MSITStore:file.chm::/dir/file"},
231 {"mk:@MSITStore:file.chm::/file.html", "mk:@MSITStore:file.chm::/dir/file", 0, "mk:@MSITStore:file.chm::/dir/file"},
232 {"foo:today", "foo:calendar", 0, "foo:calendar"},
233 {"foo:today", "bar:calendar", 0, "bar:calendar"},
234 {"foo:/today", "foo:calendar", 0, "foo:/calendar"},
235 {"Foo:/today/", "fOo:calendar", 0, "foo:/today/calendar"},
236 {"mk:@MSITStore:dir/test.chm::dir/index.html", "image.jpg", 0, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
237 {"mk:@MSITStore:dir/test.chm::dir/dir2/index.html", "../image.jpg", 0, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
238 {"c:\\test\\", "//share/file.txt", 0, "file://share/file.txt"},
239 {"c:\\test\\", "\\\\share\\file.txt", 0, "file://share/file.txt"},
240 /* UrlCombine case 2 tests. Schemes do not match */
241 {"outbind://xxxxxxxxx", "http://wine1/dir", 0, "http://wine1/dir"},
242 {"xxxx://xxxxxxxxx", "http://wine2/dir", 0, "http://wine2/dir"},
243 {"ftp://xxxxxxxxx/", "http://wine3/dir", 0, "http://wine3/dir"},
244 {"outbind://xxxxxxxxx", "http://wine4/dir", URL_PLUGGABLE_PROTOCOL, "http://wine4/dir"},
245 {"xxx://xxxxxxxxx", "http://wine5/dir", URL_PLUGGABLE_PROTOCOL, "http://wine5/dir"},
246 {"ftp://xxxxxxxxx/", "http://wine6/dir", URL_PLUGGABLE_PROTOCOL, "http://wine6/dir"},
247 {"http://xxxxxxxxx", "outbind://wine7/dir", 0, "outbind://wine7/dir"},
248 {"xxx://xxxxxxxxx", "ftp://wine8/dir", 0, "ftp://wine8/dir"},
249 {"ftp://xxxxxxxxx/", "xxx://wine9/dir", 0, "xxx://wine9/dir"},
250 {"http://xxxxxxxxx", "outbind://wine10/dir", URL_PLUGGABLE_PROTOCOL, "outbind://wine10/dir"},
251 {"xxx://xxxxxxxxx", "ftp://wine11/dir", URL_PLUGGABLE_PROTOCOL, "ftp://wine11/dir"},
252 {"ftp://xxxxxxxxx/", "xxx://wine12/dir", URL_PLUGGABLE_PROTOCOL, "xxx://wine12/dir"},
253 {"http://xxxxxxxxx", "outbind:wine13/dir", 0, "outbind:wine13/dir"},
254 {"xxx://xxxxxxxxx", "ftp:wine14/dir", 0, "ftp:wine14/dir"},
255 {"ftp://xxxxxxxxx/", "xxx:wine15/dir", 0, "xxx:wine15/dir"},
256 {"outbind://xxxxxxxxx/", "http:wine16/dir", 0, "http:wine16/dir"},
257 {"http://xxxxxxxxx", "outbind:wine17/dir", URL_PLUGGABLE_PROTOCOL, "outbind:wine17/dir"},
258 {"xxx://xxxxxxxxx", "ftp:wine18/dir", URL_PLUGGABLE_PROTOCOL, "ftp:wine18/dir"},
259 {"ftp://xxxxxxxxx/", "xXx:wine19/dir", URL_PLUGGABLE_PROTOCOL, "xxx:wine19/dir"},
260 {"outbind://xxxxxxxxx/", "http:wine20/dir", URL_PLUGGABLE_PROTOCOL, "http:wine20/dir"},
261 {"file:///c:/dir/file.txt", "index.html?test=c:/abc", URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, "file:///c:/dir/index.html?test=c:/abc"}
262};
263
264/* ################ */
265
266static const struct {
267 const char *path;
268 const char *url;
270} TEST_URLFROMPATH [] = {
271 {"foo", "file:foo", S_OK},
272 {"foo\\bar", "file:foo/bar", S_OK},
273 {"\\foo\\bar", "file:///foo/bar", S_OK},
274 {"c:\\foo\\bar", "file:///c:/foo/bar", S_OK},
275 {"c:foo\\bar", "file:///c:foo/bar", S_OK},
276 {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK},
277 {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK},
278 {"file:///c:/foo/bar", "file:///c:/foo/bar", S_FALSE},
279 {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE}
281
282/* ################ */
283
284static struct {
285 char url[30];
286 const char *expect;
287} TEST_URL_UNESCAPE[] = {
288 {"file://foo/bar", "file://foo/bar"},
289 {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"},
290 {"file://%24%25foobar", "file://$%foobar"}
292
293static struct
294{
295 const WCHAR *url;
296 const WCHAR *expect;
299{
300 { L"file://foo/bar", L"file://foo/bar" },
301 { L"file://fo%20o%5Ca/bar", L"file://fo o\\a/bar" },
302 { L"file://%24%25foobar", L"file://$%foobar" },
303 { L"file:///C:/Program Files", L"file:///C:/Program Files" },
304 { L"file:///C:/Program Files", L"file:///C:/Program Files", URL_UNESCAPE_AS_UTF8 },
305 { L"file:///C:/Program%20Files", L"file:///C:/Program Files" },
306 { L"file:///C:/Program%20Files", L"file:///C:/Program Files", URL_UNESCAPE_AS_UTF8 },
307 { L"file://foo/%E4%B8%AD%E6%96%87/bar", L"file://foo/\xe4\xb8\xad\xe6\x96\x87/bar" }, /* with 3 btyes utf-8 */
308 { L"file://foo/%E4%B8%AD%E6%96%87/bar", L"file://foo/\x4e2d\x6587/bar", URL_UNESCAPE_AS_UTF8 },
309 /* mix corrupt and good utf-8 */
310 { L"file://foo/%E4%AD%E6%96%87/bar", L"file://foo/\xfffd\x6587/bar", URL_UNESCAPE_AS_UTF8 },
311 { L"file://foo/%F0%9F%8D%B7/bar", L"file://foo/\xf0\x9f\x8d\xb7/bar" }, /* with 4 btyes utf-8 */
312 { L"file://foo/%F0%9F%8D%B7/bar", L"file://foo/\xd83c\xdf77/bar", URL_UNESCAPE_AS_UTF8 },
313 /* non-escaped chars between multi-byte escaped chars */
314#if defined(__REACTOS__) && defined(_MSC_VER)
315 { L"file://foo/%E4%B8%ADabc%E6%96%87/bar", L"file://foo/\x4e2d""abc""\u6587/bar", URL_UNESCAPE_AS_UTF8 },
316 { L"file://foo/%E4B8%AD/bar", L"file://foo/\ufffd""B8\ufffd/bar", URL_UNESCAPE_AS_UTF8 },
317 { L"file://foo/%E4%G8%AD/bar", L"file://foo/\ufffd""%G8\ufffd/bar", URL_UNESCAPE_AS_UTF8 },
318#else
319 { L"file://foo/%E4%B8%ADabc%E6%96%87/bar", L"file://foo/\x4e2d""abc""\x6587/bar", URL_UNESCAPE_AS_UTF8 },
320 { L"file://foo/%E4B8%AD/bar", L"file://foo/\xfffd""B8\xfffd/bar", URL_UNESCAPE_AS_UTF8 },
321 { L"file://foo/%E4%G8%AD/bar", L"file://foo/\xfffd""%G8\xfffd/bar", URL_UNESCAPE_AS_UTF8 },
322#endif
323 { L"file://foo/%G4%B8%AD/bar", L"file://foo/%G4\xfffd\xfffd/bar", URL_UNESCAPE_AS_UTF8 },
325
326static const struct {
327 const char *path;
328 BOOL expect;
329} TEST_PATH_IS_URL[] = {
330 {"http://foo/bar", TRUE},
331 {"c:\\foo\\bar", FALSE},
332 {"foo://foo/bar", TRUE},
333 {"foo\\bar", FALSE},
334 {"foo.bar", FALSE},
335 {"bogusscheme:", TRUE},
336 {"http:partial", TRUE}
338
339/* ################ */
340
341static const struct {
342 const char *url;
345} TEST_URLIS_ATTRIBS[] = {
346 { "ftp:", FALSE, FALSE },
347 { "http:", FALSE, FALSE },
348 { "gopher:", FALSE, FALSE },
349 { "mailto:", TRUE, FALSE },
350 { "news:", FALSE, FALSE },
351 { "nntp:", FALSE, FALSE },
352 { "telnet:", FALSE, FALSE },
353 { "wais:", FALSE, FALSE },
354 { "file:", FALSE, TRUE },
355 { "mk:", FALSE, FALSE },
356 { "https:", FALSE, FALSE },
357 { "shell:", TRUE, FALSE },
358 { "https:", FALSE, FALSE },
359 { "snews:", FALSE, FALSE },
360 { "local:", FALSE, FALSE },
361 { "javascript:", TRUE, FALSE },
362 { "vbscript:", TRUE, FALSE },
363 { "about:", TRUE, FALSE },
364 { "res:", FALSE, FALSE },
365 { "bogusscheme:", FALSE, FALSE },
366 { "file:\\\\e:\\b\\c", FALSE, TRUE },
367 { "file://e:/b/c", FALSE, TRUE },
368 { "http:partial", FALSE, FALSE },
369 { "mailto://www.winehq.org/test.html", TRUE, FALSE },
370 { "file:partial", FALSE, TRUE },
371 { "File:partial", FALSE, TRUE },
373
374/* ########################### */
375
376static LPWSTR GetWideString(const char* szString)
377{
378 LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
379
380 MultiByteToWideChar(CP_ACP, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
381
382 return wszString;
383}
384
385
386static void FreeWideString(LPWSTR wszString)
387{
388 HeapFree(GetProcessHeap(), 0, wszString);
389}
390
391/* ########################### */
392
393static void test_UrlApplyScheme(void)
394{
397 HRESULT res;
398 DWORD len;
399 DWORD i;
400
401 for (i = 0; i < ARRAY_SIZE(TEST_APPLY); i++) {
403 strcpy(newurl, "untouched");
405 ok( res == TEST_APPLY[i].res,
406 "#%ldA: got HRESULT 0x%lx (expected 0x%lx)\n", i, res, TEST_APPLY[i].res);
407 if (res == S_OK)
408 {
409 ok(len == strlen(newurl), "Test %lu: Expected length %Iu, got %lu.\n", i, strlen(newurl), len);
410 ok(!strcmp(newurl, TEST_APPLY[i].newurl), "Test %lu: Expected %s, got %s.\n",
412 }
413 else
414 {
415 ok(len == ARRAY_SIZE(newurl), "Test %lu: Got length %lu.\n", i, len);
416 ok(!strcmp(newurl, "untouched"), "Test %lu: Got %s.\n", i, debugstr_a(newurl));
417 }
418
419 /* returned length is in character */
420 MultiByteToWideChar(CP_ACP, 0, TEST_APPLY[i].url, -1, urlW, ARRAY_SIZE(urlW));
421 MultiByteToWideChar(CP_ACP, 0, TEST_APPLY[i].newurl, -1, expectW, ARRAY_SIZE(expectW));
422
423 len = ARRAY_SIZE(newurlW);
424 wcscpy(newurlW, L"untouched");
425 res = UrlApplySchemeW(urlW, newurlW, &len, TEST_APPLY[i].flags);
426 ok( res == TEST_APPLY[i].res,
427 "#%ldW: got HRESULT 0x%lx (expected 0x%lx)\n", i, res, TEST_APPLY[i].res);
428 if (res == S_OK)
429 {
430 ok(len == wcslen(newurlW), "Test %lu: Expected length %Iu, got %lu.\n", i, wcslen(newurlW), len);
431 ok(!wcscmp(newurlW, expectW), "Test %lu: Expected %s, got %s.\n",
432 i, debugstr_w(expectW), debugstr_w(newurlW));
433 }
434 else
435 {
436 ok(len == ARRAY_SIZE(newurlW), "Test %lu: Got length %lu.\n", i, len);
437 ok(!wcscmp(newurlW, L"untouched"), "Test %lu: Got %s.\n", i, debugstr_w(newurlW));
438 }
439 }
440
441 /* buffer too small */
445 ok(res == E_POINTER, "got HRESULT 0x%lx (expected E_POINTER)\n", res);
446 /* The returned length include the space for the terminating 0 */
447 i = lstrlenA(TEST_APPLY[0].newurl)+1;
448 ok(len == i, "got len %ld (expected %ld)\n", len, i);
449 ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA);
450
451 /* NULL as parameter. The length and the buffer are not modified */
455 ok(res == E_INVALIDARG, "got HRESULT 0x%lx (expected E_INVALIDARG)\n", res);
456 ok(len == ARRAY_SIZE(newurl), "got len %ld\n", len);
457 ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA);
458
461 ok(res == E_INVALIDARG, "got HRESULT 0x%lx (expected E_INVALIDARG)\n", res);
462 ok(len == ARRAY_SIZE(newurl), "got len %ld\n", len);
463
466 ok(res == E_INVALIDARG, "got HRESULT 0x%lx (expected E_INVALIDARG)\n", res);
467 ok(!lstrcmpA(newurl, untouchedA), "got '%s' (expected '%s')\n", newurl, untouchedA);
468
469}
470
471/* ########################### */
472
473static void hash_url(const char* szUrl)
474{
475 LPCSTR szTestUrl = szUrl;
476 LPWSTR wszTestUrl = GetWideString(szTestUrl);
477 HRESULT res;
478
479 DWORD cbSize = sizeof(DWORD);
480 DWORD dwHash1, dwHash2;
481 res = UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize);
482 ok(res == S_OK, "UrlHashA returned 0x%lx (expected S_OK) for %s\n", res, szUrl);
483
484 res = UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize);
485 ok(res == S_OK, "UrlHashW returned 0x%lx (expected S_OK) for %s\n", res, szUrl);
486 ok(dwHash1 == dwHash2,
487 "Hashes didn't match (A: 0x%lx, W: 0x%lx) for %s\n", dwHash1, dwHash2, szUrl);
488 FreeWideString(wszTestUrl);
489}
490
491static void test_UrlHash(void)
492{
496}
497
498static void test_UrlGetPart(void)
499{
500 WCHAR bufferW[200];
501 char buffer[200];
502 unsigned int i;
503 HRESULT hr;
504 DWORD size;
505
506 static const struct
507 {
508 const char *url;
509 DWORD part;
510 DWORD flags;
511 HRESULT hr;
512 const char *expect;
513 }
514 tests[] =
515 {
516 {"hi", URL_PART_SCHEME, 0, S_FALSE, ""},
517 {"hi", URL_PART_USERNAME, 0, E_FAIL},
518 {"hi", URL_PART_PASSWORD, 0, E_FAIL},
519 {"hi", URL_PART_HOSTNAME, 0, E_FAIL},
520 {"hi", URL_PART_PORT, 0, E_FAIL},
521 {"hi", URL_PART_QUERY, 0, S_FALSE, ""},
522
523 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_SCHEME, 0, S_OK, "http"},
524 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_USERNAME, 0, S_OK, "foo"},
525 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_PASSWORD, 0, S_OK, "bar"},
526 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
527 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_PORT, 0, S_OK, "21"},
528 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_QUERY, 0, S_OK, "query=x&return=y"},
529 {"http://foo:bar@localhost:21/internal.php#anchor", URL_PART_QUERY, 0, S_FALSE, ""},
530 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_SCHEME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http"},
531 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_USERNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:foo"},
532 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_PASSWORD, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:bar"},
533 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:localhost"},
534 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_PORT, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:21"},
535 {"http://foo:bar@localhost:21/internal.php?query=x&return=y", URL_PART_QUERY, URL_PARTFLAG_KEEPSCHEME, S_OK, "query=x&return=y"},
536
537 {"http://localhost/", URL_PART_USERNAME, 0, E_INVALIDARG},
538 {"http://localhost/", URL_PART_PASSWORD, 0, E_INVALIDARG},
539 {"http://localhost/", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
540 {"http://localhost/", URL_PART_PORT, 0, E_INVALIDARG},
541 {"http://localhost/", URL_PART_QUERY, 0, S_FALSE, ""},
542
543 {"http://localhost:port/", URL_PART_USERNAME, 0, E_INVALIDARG},
544 {"http://localhost:port/", URL_PART_PASSWORD, 0, E_INVALIDARG},
545 {"http://localhost:port/", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
546 {"http://localhost:port/", URL_PART_PORT, 0, S_OK, "port"},
547 {"http://:", URL_PART_HOSTNAME, 0, S_FALSE, ""},
548 {"http://:", URL_PART_PORT, 0, S_FALSE, ""},
549
550 {"http://user@localhost", URL_PART_USERNAME, 0, S_OK, "user"},
551 {"http://user@localhost", URL_PART_PASSWORD, 0, E_INVALIDARG},
552 {"http://user@localhost", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
553 {"http://user@localhost", URL_PART_PORT, 0, E_INVALIDARG},
554 {"http://@", URL_PART_USERNAME, 0, S_FALSE, ""},
555 {"http://@", URL_PART_PASSWORD, 0, E_INVALIDARG},
556 {"http://@", URL_PART_HOSTNAME, 0, S_FALSE, ""},
557
558 {"http://user:pass@localhost", URL_PART_USERNAME, 0, S_OK, "user"},
559 {"http://user:pass@localhost", URL_PART_PASSWORD, 0, S_OK, "pass"},
560 {"http://user:pass@localhost", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
561 {"http://user:pass@localhost", URL_PART_PORT, 0, E_INVALIDARG},
562 {"http://:@", URL_PART_USERNAME, 0, S_FALSE, ""},
563 {"http://:@", URL_PART_PASSWORD, 0, S_FALSE, ""},
564 {"http://:@", URL_PART_HOSTNAME, 0, S_FALSE, ""},
565
566 {"http://host:port:q", URL_PART_HOSTNAME, 0, S_OK, "host"},
567 {"http://host:port:q", URL_PART_PORT, 0, S_OK, "port:q"},
568 {"http://user:pass:q@host", URL_PART_USERNAME, 0, S_OK, "user"},
569 {"http://user:pass:q@host", URL_PART_PASSWORD, 0, S_OK, "pass:q"},
570 {"http://user@host@q", URL_PART_USERNAME, 0, S_OK, "user"},
571 {"http://user@host@q", URL_PART_HOSTNAME, 0, S_OK, "host@q"},
572
573 {"http:localhost/index.html", URL_PART_HOSTNAME, 0, E_FAIL},
574 {"http:/localhost/index.html", URL_PART_HOSTNAME, 0, E_FAIL},
575
576 {"http://localhost\\index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
577 {"http:/\\localhost/index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
578 {"http:\\/localhost/index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
579
580 {"ftp://localhost\\index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
581 {"ftp:/\\localhost/index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
582 {"ftp:\\/localhost/index.html", URL_PART_HOSTNAME, 0, S_OK, "localhost"},
583
584 {"http://host?a:b@c:d", URL_PART_HOSTNAME, 0, S_OK, "host"},
585 {"http://host?a:b@c:d", URL_PART_QUERY, 0, S_OK, "a:b@c:d"},
586 {"http://host#a:b@c:d", URL_PART_HOSTNAME, 0, S_OK, "host"},
587 {"http://host#a:b@c:d", URL_PART_QUERY, 0, S_FALSE, ""},
588
589 /* All characters, other than those with special meaning, are allowed. */
590 {"http://foo:bar@google.*.com:21/internal.php?query=x&return=y", URL_PART_HOSTNAME, 0, S_OK, "google.*.com"},
591 {"http:// !\"$%&'()*+,-.;<=>[]^_`{|~}:pass@host", URL_PART_USERNAME, 0, S_OK, " !\"$%&'()*+,-.;<=>[]^_`{|~}"},
592 {"http://user: !\"$%&'()*+,-.;<=>[]^_`{|~}@host", URL_PART_PASSWORD, 0, S_OK, " !\"$%&'()*+,-.;<=>[]^_`{|~}"},
593 {"http:// !\"$%&'()*+,-.;<=>[]^_`{|~}", URL_PART_HOSTNAME, 0, S_OK, " !\"$%&'()*+,-.;<=>[]^_`{|~}"},
594 {"http://host: !\"$%&'()*+,-.;<=>[]^_`{|~}", URL_PART_PORT, 0, S_OK, " !\"$%&'()*+,-.;<=>[]^_`{|~}"},
595
596 {"http:///index.html", URL_PART_HOSTNAME, 0, S_FALSE, ""},
597 {"http:///index.html", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:"},
598 {"file://h o s t/c:/windows/file", URL_PART_HOSTNAME, 0, S_OK, "h o s t"},
599 {"file://h o s t/c:/windows/file", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "h o s t"},
600 {"file://foo:bar@localhost:21/file?query=x", URL_PART_USERNAME, 0, E_FAIL},
601 {"file://foo:bar@localhost:21/file?query=x", URL_PART_PASSWORD, 0, E_FAIL},
602 {"file://foo:bar@localhost:21/file?query=x", URL_PART_HOSTNAME, 0, S_OK, "foo:bar@localhost:21"},
603 {"file://foo:bar@localhost:21/file?query=x", URL_PART_PORT, 0, E_FAIL},
604 {"file://foo:bar@localhost:21/file?query=x", URL_PART_QUERY, 0, S_OK, "query=x"},
605 {"http://user:pass 123@www.wine hq.org", URL_PART_HOSTNAME, 0, S_OK, "www.wine hq.org"},
606 {"http://user:pass 123@www.wine hq.org", URL_PART_PASSWORD, 0, S_OK, "pass 123"},
607 {"about:blank", URL_PART_SCHEME, 0, S_OK, "about"},
608 {"about:blank", URL_PART_HOSTNAME, 0, E_FAIL},
609 {"x-excid://36C00000/guid:{048B4E89-2E92-496F-A837-33BA02FF6D32}/Message.htm", URL_PART_SCHEME, 0, S_OK, "x-excid"},
610 {"x-excid://36C00000/guid:{048B4E89-2E92-496F-A837-33BA02FF6D32}/Message.htm", URL_PART_HOSTNAME, 0, E_FAIL},
611 {"x-excid://36C00000/guid:{048B4E89-2E92-496F-A837-33BA02FF6D32}/Message.htm", URL_PART_QUERY, 0, S_FALSE, ""},
612 {"foo://bar-url/test", URL_PART_SCHEME, 0, S_OK, "foo"},
613 {"foo://bar-url/test", URL_PART_HOSTNAME, 0, E_FAIL},
614 {"foo://bar-url/test", URL_PART_QUERY, 0, S_FALSE, ""},
615 {"ascheme:", URL_PART_SCHEME, 0, S_OK, "ascheme"},
616 {"res://some.dll/find.dlg", URL_PART_SCHEME, 0, S_OK, "res"},
617 {"res://some.dll/find.dlg", URL_PART_QUERY, 0, S_FALSE, ""},
618 {"http://www.winehq.org", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:www.winehq.org"},
619 {"file:///index.html", URL_PART_HOSTNAME, 0, S_FALSE, ""},
620 {"file:///index.html", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_FALSE, ""},
621 {"file://c:\\index.htm", URL_PART_HOSTNAME, 0, S_FALSE, ""},
622 {"file://c:\\index.htm", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_FALSE, ""},
623 {"file:some text", URL_PART_HOSTNAME, 0, S_FALSE, ""},
624 {"index.htm", URL_PART_HOSTNAME, 0, E_FAIL},
625 {"sChEmE-.+:", URL_PART_SCHEME, 0, S_OK, "scheme-.+"},
626 {"scheme_:", URL_PART_SCHEME, 0, S_FALSE, ""},
627 {"scheme :", URL_PART_SCHEME, 0, S_FALSE, ""},
628 {"sch eme:", URL_PART_SCHEME, 0, S_FALSE, ""},
629 {":", URL_PART_SCHEME, 0, S_FALSE, ""},
630 {"a:", URL_PART_SCHEME, 0, S_FALSE, ""},
631 {"0:", URL_PART_SCHEME, 0, S_FALSE, ""},
632 {"ab:", URL_PART_SCHEME, 0, S_OK, "ab"},
633
634 {"about://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
635 {"file://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
636 {"ftp://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
637 {"gopher://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
638 {"http://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
639 {"https://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
640 {"javascript://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
641 {"local://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
642 {"mailto://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
643 {"mk://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
644 {"news://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
645 {"nntp://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
646 {"res://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
647 {"shell://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
648 {"snews://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
649 {"telnet://hostname/", URL_PART_HOSTNAME, 0, S_OK, "hostname"},
650 {"vbscript://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
651 {"wais://hostname/", URL_PART_HOSTNAME, 0, E_FAIL},
652
653 {"file://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "hostname"},
654 {"ftp://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "ftp:hostname"},
655 {"gopher://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "gopher:hostname"},
656 {"http://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "http:hostname"},
657 {"https://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "https:hostname"},
658 {"news://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "news:hostname"},
659 {"nntp://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "nntp:hostname"},
660 {"snews://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "snews:hostname"},
661 {"telnet://hostname/", URL_PART_HOSTNAME, URL_PARTFLAG_KEEPSCHEME, S_OK, "telnet:hostname"},
662 };
663
665 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
666
668 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
669
670 hr = UrlGetPartA("res://some.dll/find.dlg", NULL, &size, URL_PART_SCHEME, 0);
671 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
672
673 hr = UrlGetPartA("res://some.dll/find.dlg", buffer, NULL, URL_PART_SCHEME, 0);
674 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
675
676 size = 0;
677 strcpy(buffer, "x");
679 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
680 ok(!strcmp(buffer, "x"), "Got result %s.\n", debugstr_a(buffer));
681 ok(!size, "Got size %lu.\n", size);
682#ifdef __REACTOS__
683 if (LOBYTE(LOWORD(GetVersion())) < 6) {
684 skip("UrlGetPart test list broken on WS03.\n");
685 goto skip_UrlGetPartTestList;
686 }
687#endif
688
689 for (i = 0; i < ARRAY_SIZE(tests); ++i)
690 {
691 WCHAR urlW[200], expectW[200];
692 const char *expect = tests[i].expect;
693 const char *url = tests[i].url;
694 DWORD flags = tests[i].flags;
695 DWORD part = tests[i].part;
696
697 winetest_push_context("URL %s, part %#lx, flags %#lx", debugstr_a(url), part, flags);
698
699 size = 1;
700 strcpy(buffer, "x");
701 hr = UrlGetPartA(url, buffer, &size, part, flags);
702 if (tests[i].hr == S_OK)
703 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
704 else
705 ok(hr == tests[i].hr, "Got hr %#lx.\n", hr);
706
707 if (hr == S_FALSE)
708 {
709 ok(!size, "Got size %lu.\n", size);
710 ok(!buffer[0], "Got result %s.\n", debugstr_a(buffer));
711 }
712 else
713 {
714 if (hr == E_POINTER)
715 ok(size == strlen(expect) + 1, "Got size %lu.\n", size);
716 else
717 ok(size == 1, "Got size %lu.\n", size);
718 ok(!strcmp(buffer, "x"), "Got result %s.\n", debugstr_a(buffer));
719 }
720
721 size = sizeof(buffer);
722 strcpy(buffer, "x");
723 hr = UrlGetPartA(url, buffer, &size, part, flags);
724 ok(hr == tests[i].hr, "Got hr %#lx.\n", hr);
725 if (SUCCEEDED(hr))
726 {
727 ok(size == strlen(buffer), "Got size %lu.\n", size);
728 ok(!strcmp(buffer, expect), "Got result %s.\n", debugstr_a(buffer));
729 }
730 else
731 {
732 ok(size == sizeof(buffer), "Got size %lu.\n", size);
733 ok(!strcmp(buffer, "x"), "Got result %s.\n", debugstr_a(buffer));
734 }
735
736 MultiByteToWideChar(CP_ACP, 0, url, -1, urlW, ARRAY_SIZE(urlW));
737
738 size = 1;
739 wcscpy(bufferW, L"x");
740 hr = UrlGetPartW(urlW, bufferW, &size, part, flags);
741 if (tests[i].hr == S_OK)
742 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
743 else
744 ok(hr == (tests[i].hr == S_FALSE ? S_OK : tests[i].hr), "Got hr %#lx.\n", hr);
745
746 if (SUCCEEDED(hr))
747 {
748 ok(!size, "Got size %lu.\n", size);
749 ok(!buffer[0], "Got result %s.\n", debugstr_a(buffer));
750 }
751 else
752 {
753 if (hr == E_POINTER)
754 ok(size == strlen(expect) + 1, "Got size %lu.\n", size);
755 else
756 ok(size == 1, "Got size %lu.\n", size);
757 ok(!wcscmp(bufferW, L"x"), "Got result %s.\n", debugstr_w(bufferW));
758 }
759
760 size = ARRAY_SIZE(bufferW);
761 wcscpy(bufferW, L"x");
762 hr = UrlGetPartW(urlW, bufferW, &size, part, flags);
763 ok(hr == (tests[i].hr == S_FALSE ? S_OK : tests[i].hr), "Got hr %#lx.\n", hr);
764 if (SUCCEEDED(hr))
765 {
766 ok(size == wcslen(bufferW), "Got size %lu.\n", size);
767 MultiByteToWideChar(CP_ACP, 0, buffer, -1, expectW, ARRAY_SIZE(expectW));
768 ok(!wcscmp(bufferW, expectW), "Got result %s.\n", debugstr_w(bufferW));
769 }
770 else
771 {
772 ok(size == ARRAY_SIZE(bufferW), "Got size %lu.\n", size);
773 ok(!wcscmp(bufferW, L"x"), "Got result %s.\n", debugstr_w(bufferW));
774 }
775
777 }
778
779 /* Test non-ASCII characters. */
780#ifdef __REACTOS__
781skip_UrlGetPartTestList:
782#endif
783
784 size = ARRAY_SIZE(bufferW);
785 wcscpy(bufferW, L"x");
786 hr = UrlGetPartW(L"http://\x01\x7f\x80\xff:pass@host", bufferW, &size, URL_PART_USERNAME, 0);
787 ok(hr == S_OK, "Got hr %#lx.\n", hr);
788 ok(size == wcslen(bufferW), "Got size %lu.\n", size);
789 ok(!wcscmp(bufferW, L"\x01\x7f\x80\xff"), "Got result %s.\n", debugstr_w(bufferW));
790}
791
792/* ########################### */
793static void check_url_canonicalize(const char *url, DWORD flags, const char *expect)
794{
795 char output[INTERNET_MAX_URL_LENGTH];
797 WCHAR *urlW = GetWideString(url);
798 WCHAR *expectW;
799 HRESULT hr;
800 DWORD size;
801
802 winetest_push_context("URL %s, flags %#lx", debugstr_a(url), flags);
803
806 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
807 hr = UrlCanonicalizeA(url, output, &size, flags);
808 ok(hr == S_OK || (!url[0] && hr == S_FALSE) /* Vista+ */, "Got unexpected hr %#lx.\n", hr);
809 ok(!strcmp(output, expect), "Expected %s, got %s.\n", debugstr_a(expect), debugstr_a(output));
810
812 hr = UrlCanonicalizeW(urlW, NULL, &size, flags);
813 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
814 hr = UrlCanonicalizeW(urlW, outputW, &size, flags);
815 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
816
817 expectW = GetWideString(output);
818 ok(!wcscmp(outputW, expectW), "Expected %s, got %s.\n", debugstr_w(expectW), debugstr_w(outputW));
819 FreeWideString(expectW);
820
821 FreeWideString(urlW);
822
824}
825
826
827static void test_UrlEscapeA(void)
828{
829 DWORD size = 0;
830 HRESULT ret;
831 unsigned int i;
832 char empty_string[] = "";
833
834 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", NULL, &size, URL_ESCAPE_SPACES_ONLY);
835 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
836 ok(size == 0, "got %ld, expected %d\n", size, 0);
837
838 size = 0;
839 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
840 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
841 ok(size == 0, "got %ld, expected %d\n", size, 0);
842
843 size = 1;
844 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", NULL, &size, URL_ESCAPE_SPACES_ONLY);
845 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
846 ok(size == 1, "got %ld, expected %d\n", size, 1);
847
848 size = 1;
849 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, NULL, URL_ESCAPE_SPACES_ONLY);
850 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
851 ok(size == 1, "got %ld, expected %d\n", size, 1);
852
853 size = 1;
854 empty_string[0] = 127;
855 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
856 ok(ret == E_POINTER, "got %lx, expected %lx\n", ret, E_POINTER);
857 ok(size == 34, "got %ld, expected %d\n", size, 34);
858 ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]);
859
860 size = 1;
861 empty_string[0] = 127;
862 ret = UrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_AS_UTF8);
863#ifdef __REACTOS__
864 ok(ret == E_NOTIMPL || broken(ret == E_POINTER) /* Vista */, "Got unexpected hr %#lx.\n", ret);
865 ok(size == 1 || broken(size == 34) /* Vista */, "Got unexpected size %lu.\n", size);
866#else
867 ok(ret == E_NOTIMPL, "Got unexpected hr %#lx.\n", ret);
868 ok(size == 1, "Got unexpected size %lu.\n", size);
869#endif
870 ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]);
871
872 for (i = 0; i < ARRAY_SIZE(TEST_ESCAPE); i++) {
874
877 ok(ret == S_OK, "Got unexpected hr %#lx for %s.\n", ret, debugstr_a(TEST_ESCAPE[i].url));
878 ok(!strcmp(ret_url, TEST_ESCAPE[i].expecturl), "Expected \"%s\", but got \"%s\" for \"%s\"\n",
879 TEST_ESCAPE[i].expecturl, ret_url, TEST_ESCAPE[i].url);
880 }
881}
882
883static void test_UrlEscapeW(void)
884{
886 WCHAR overwrite[10] = L"foo bar";
887 WCHAR empty_string[] = {0};
888 DWORD size;
889 HRESULT ret;
890 WCHAR wc;
891 int i;
892#ifdef __REACTOS__
893 DWORD _ntVersion = GetVersion();
894 BYTE _ntMajor = LOBYTE(LOWORD(_ntVersion));
895 BYTE _ntMinor = HIBYTE(LOWORD(_ntVersion));
896#endif
897
898 /* Check error paths */
899
901 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
902
903 size = 0;
905 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
906 ok(size == 0, "got %ld, expected %d\n", size, 0);
907
908 ret = UrlEscapeW(L"/test", empty_string, NULL, URL_ESCAPE_SPACES_ONLY);
909 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
910
911 size = 0;
912 ret = UrlEscapeW(L"/test", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
913 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
914 ok(size == 0, "got %ld, expected %d\n", size, 0);
915
917 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
918
919 size = 1;
921 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
922 ok(size == 1, "got %ld, expected %d\n", size, 1);
923
924 ret = UrlEscapeW(L"/test", empty_string, NULL, URL_ESCAPE_SPACES_ONLY);
925 ok(ret == E_INVALIDARG, "got %lx, expected %lx\n", ret, E_INVALIDARG);
926
927 size = 1;
928 ret = UrlEscapeW(L"/test", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
929 ok(ret == E_POINTER, "got %lx, expected %lx\n", ret, E_POINTER);
930 ok(size == 6, "got %ld, expected %d\n", size, 6);
931
932 /* Check actual escaping */
933
934 size = ARRAY_SIZE(overwrite);
935 ret = UrlEscapeW(overwrite, overwrite, &size, URL_ESCAPE_SPACES_ONLY);
936 ok(ret == S_OK, "got %lx, expected S_OK\n", ret);
937 ok(size == 9, "got %ld, expected 9\n", size);
938 ok(!wcscmp(overwrite, L"foo%20bar"), "Got unexpected string %s.\n", debugstr_w(overwrite));
939
940 size = 1;
941 wc = 127;
942 ret = UrlEscapeW(overwrite, &wc, &size, URL_ESCAPE_SPACES_ONLY);
943 ok(ret == E_POINTER, "got %lx, expected %lx\n", ret, E_POINTER);
944 ok(size == 10, "got %ld, expected 10\n", size);
945 ok(wc == 127, "String has changed, wc = %d\n", wc);
946
947 /* non-ASCII range */
948 size = ARRAY_SIZE(ret_urlW);
949 ret = UrlEscapeW(L"ftp\x1f\xff\xfa\x2122q/", ret_urlW, &size, 0);
950 ok(ret == S_OK, "got %lx, expected S_OK\n", ret);
951 ok(!wcscmp(ret_urlW, L"ftp%1F%FF%FA\x2122q/"), "Got unexpected string %s.\n", debugstr_w(ret_urlW));
952
953 for (i = 0; i < ARRAY_SIZE(TEST_ESCAPE); i++) {
954
955 WCHAR *urlW, *expected_urlW;
956
959 expected_urlW = GetWideString(TEST_ESCAPE[i].expecturl);
960 ret = UrlEscapeW(urlW, ret_urlW, &size, TEST_ESCAPE[i].flags);
961 ok(ret == S_OK, "Got unexpected hr %#lx for %s.\n", ret, debugstr_w(urlW));
962 ok(!lstrcmpW(ret_urlW, expected_urlW), "Expected %s, but got %s for %s flags %08lx\n",
963 wine_dbgstr_w(expected_urlW), wine_dbgstr_w(ret_urlW), wine_dbgstr_w(urlW), TEST_ESCAPE[i].flags);
964 FreeWideString(urlW);
965 FreeWideString(expected_urlW);
966 }
967
968 for (i = 0; i < ARRAY_SIZE(TEST_ESCAPEW); i++) {
970
971#ifdef __REACTOS__
972 /* TEST_ESCAPEW[6, 7] is incorrect for WS03, Vista. */
973 if ((i == 6 || i == 7) && (_ntMajor < 6 || (_ntMajor == 6 && _ntMinor == 0)))
974 continue;
975#endif
978 ok(ret == S_OK, "Got unexpected hr %#lx for %s.\n", ret, debugstr_w(TEST_ESCAPEW[i].url));
979 ok(!wcscmp(ret_url, TEST_ESCAPEW[i].expecturl)
980 || broken(!wcscmp(ret_url, TEST_ESCAPEW[i].win7url)),
981 "Expected %s, but got %s for %s.\n", debugstr_w(TEST_ESCAPEW[i].expecturl),
983 }
984}
985
987{
988 const char *url;
990 const char *expect;
991};
992
993static void test_UrlCanonicalizeA(void)
994{
995 CHAR szReturnUrl[4*INTERNET_MAX_URL_LENGTH];
996 CHAR longurl[4*INTERNET_MAX_URL_LENGTH];
997 char url[200], expect[200];
998 unsigned int f, i, j;
1000 DWORD urllen;
1001 HRESULT hr;
1002
1003 static const struct canonicalize_test unk_scheme_tests[] =
1004 {
1005 /* Single and double dots behave as one would expect, with the following
1006 * notable rules:
1007 *
1008 * (1) A single or double dot as the first element (the "hostname") is
1009 * always emitted as-is.
1010 *
1011 * (2) If a double dot would undo the hostname, it is emitted as-is
1012 * instead.
1013 *
1014 * (3) If a single or double dot is the last element (either because of
1015 * the above rule or because of URL_DONT_SIMPLIFY), a trailing
1016 * backslash is appended.
1017 *
1018 * A trailing backslash is always appended after the hostname.
1019 */
1020
1021 {"//", 0, "///"},
1022 {"//a", 0, "//a/"},
1023 {"//a/", 0, "//a/"},
1024 {"//a/b", 0, "//a/b"},
1025 {"//a/b/", 0, "//a/b/"},
1026 {"//.", 0, "//./"},
1027 {"//./", 0, "//./"},
1028 {"//./a", 0, "//./a"},
1029 {"//././a", 0, "//./a"},
1030 {"//a/.", 0, "//a/"},
1031 {"//a/./", 0, "//a/"},
1032 {"//a/./b", 0, "//a/b"},
1033 {"///./a", 0, "///a"},
1034 {"//a/.b/", 0, "//a/.b/"},
1035 {"//a/b./", 0, "//a/b./"},
1036
1037 {"//..", 0, "//../"},
1038 {"//../", 0, "//../"},
1039 {"//../a", 0, "//../a"},
1040 {"//../a/..", 0, "//../"},
1041 {"//.././..", 0, "//../../"},
1042 {"//../a/../..", 0, "//../../"},
1043 {"//./a/../..", 0, "//./../"},
1044 {"//a/..", 0, "//a/../"},
1045 {"//a/../../b/./c/..", 0, "//a/../../b/"},
1046 {"//a/b/..", 0, "//a/"},
1047 {"//a/b/...", 0, "//a/b/..."},
1048 {"//a/b/../", 0, "//a/"},
1049 {"//a/b/../c", 0, "//a/c"},
1050 {"//a/b/../c/..", 0, "//a/"},
1051 {"//a/b/../c/../..", 0, "//a/../"},
1052 {"//a/b/../../../c", 0, "//a/../../c"},
1053 {"///..", 0, "///../"},
1054 {"////..", 0, "///"},
1055 {"//a/..b/", 0, "//a/..b/"},
1056 {"//a/b../", 0, "//a/b../"},
1057 {"//A/B", 0, "//A/B"},
1058
1059 {"//././a", URL_DONT_SIMPLIFY, "//././a"},
1060 {"//a/.", URL_DONT_SIMPLIFY, "//a/./"},
1061 {"//a/./", URL_DONT_SIMPLIFY, "//a/./"},
1062 {"//a/./b", URL_DONT_SIMPLIFY, "//a/./b"},
1063 {"///./a", URL_DONT_SIMPLIFY, "///./a"},
1064
1065 {"//..", URL_DONT_SIMPLIFY, "//../"},
1066 {"//../", URL_DONT_SIMPLIFY, "//../"},
1067 {"//../a", URL_DONT_SIMPLIFY, "//../a"},
1068 {"//../a/..", URL_DONT_SIMPLIFY, "//../a/../"},
1069 {"//../a/...", URL_DONT_SIMPLIFY, "//../a/..."},
1070 {"//.././..", URL_DONT_SIMPLIFY, "//.././../"},
1071 {"//../a/../..", URL_DONT_SIMPLIFY, "//../a/../../"},
1072 {"//./a/../..", URL_DONT_SIMPLIFY, "//./a/../../"},
1073 {"//a/..", URL_DONT_SIMPLIFY, "//a/../"},
1074 {"//a/../../b/./c/..", URL_DONT_SIMPLIFY, "//a/../../b/./c/../"},
1075 {"//a/b/..", URL_DONT_SIMPLIFY, "//a/b/../"},
1076 {"//a/b/../", URL_DONT_SIMPLIFY, "//a/b/../"},
1077 {"//a/b/../c", URL_DONT_SIMPLIFY, "//a/b/../c"},
1078 {"//a/b/../c/..", URL_DONT_SIMPLIFY, "//a/b/../c/../"},
1079 {"//a/b/../c/../..", URL_DONT_SIMPLIFY, "//a/b/../c/../../"},
1080 {"///..", URL_DONT_SIMPLIFY, "///../"},
1081 {"////..", URL_DONT_SIMPLIFY, "////../"},
1082
1083 /* After ? or #, dots are not simplified. */
1084 {"//a/b?c/./d", 0, "//a/b?c/./d"},
1085 {"//a/b#c/./d", 0, "//a/b#c/./d"},
1086 {"//a/b#c/.", 0, "//a/b#c/."},
1087 /* ? and # can also be considered a boundary for trailing dots. */
1088 {"//a/b/.?", 0, "//a/b/?"},
1089 {"//a/b/..?", 0, "//a/?"},
1090 {"//a/b/..?", URL_DONT_SIMPLIFY, "//a/b/../?"},
1091 {"//a/b/.#", 0, "//a/b/#"},
1092 {"//a/b/..#", 0, "//a/#"},
1093 {"//a/b/..#", URL_DONT_SIMPLIFY, "//a/b/../#"},
1094 {"//a/..?", 0, "//a/../?"},
1095 {"//a/..#", 0, "//a/../#"},
1096 {"//..?", 0, "//../?"},
1097 {"//..#", 0, "//../#"},
1098 {"//?/a/./", 0, "///?/a/./"},
1099 {"//#/a/./", 0, "///#/a/./"},
1100 /* The first ? is reordered before the first #. */
1101 {"//a/b#c?d", 0, "//a/b?d#c"},
1102 {"//a/b?c#d?e", 0, "//a/b?c#d?e"},
1103 {"//a/b#c?d#e", 0, "//a/b?d#e#c"},
1104 {"//a/b#c#d?e", 0, "//a/b?e#c#d"},
1105 {"//a/b#c?d?e", 0, "//a/b?d?e#c"},
1106
1107 /* Backslashes are not treated as path separators. */
1108 {"//a/b\\c/../.\\", 0, "//a/.\\"},
1109 {"//a\\b/../", 0, "//a\\b/../"},
1110 {"//a/b\\../", 0, "//a/b\\../"},
1111 {"//a/b/..\\", 0, "//a/b/..\\"},
1112
1113 /* Whitespace and unsafe characters are not (by default) escaped. */
1114 {"//a/b &c", 0, "//a/b &c"},
1115
1116 /* If one slash is omitted, the rules are much the same, except that
1117 * there is no "hostname". Single dots are always collapsed; double dots
1118 * are collapsed unless they would undo the "scheme". */
1119
1120 {"/a", 0, "/a"},
1121 {"/a/", 0, "/a/"},
1122 {"/.", 0, "/"},
1123 {"/./", 0, "/"},
1124 {"/././a", 0, "/a"},
1125 {"/a/.", 0, "/a/"},
1126 {"/a/./", 0, "/a/"},
1127 {"/a/./b", 0, "/a/b"},
1128
1129 {"/..", 0, "/../"},
1130 {"/../", 0, "/../"},
1131 {"/../a", 0, "/../a"},
1132 {"/../a/..", 0, "/../"},
1133 {"/a/..", 0, "/"},
1134 {"/a/../..", 0, "/../"},
1135 {"/a/b/..", 0, "/a/"},
1136 {"/a/b/../", 0, "/a/"},
1137 {"/a/b/../c", 0, "/a/c"},
1138 {"/a/b/../c/..", 0, "/a/"},
1139 {"/a/b/../c/../..", 0, "/"},
1140
1141 {"/a/b?c/./d", 0, "/a/b?c/./d"},
1142 {"/a/b#c/./d", 0, "/a/b#c/./d"},
1143 {"/a/b#c?d", 0, "/a/b?d#c"},
1144
1145 /* Just as above, backslashes are not treated as path separators. */
1146 {"/a/b\\c/../.\\", 0, "/a/.\\"},
1147 {"/a/b\\/c", 0, "/a/b\\/c"},
1148 {"/a/b\\.c", 0, "/a/b\\.c"},
1149 /* If the first character after the slash is a backslash, it is skipped.
1150 * It is not interpreted as a forward slash.
1151 * The tests above show that this is not due to the backslash being
1152 * interpreted as an escape character. */
1153 {"/\\././a", 0, "/a"},
1154 /* The sequence /\/ does not result in use of the double-slash rules.
1155 * Rather, the resulting // is treated as an empty path element. */
1156 {"/\\/././a", 0, "//a"},
1157 {"/\\/././a/", 0, "//a/"},
1158 {"/\\/..", 0, "/"},
1159 {"//a/\\b", 0, "//a/\\b"},
1160
1161 {"/a/b &c", 0, "/a/b &c"},
1162
1163 {"//a/b%20%26c", URL_UNESCAPE, "//a/b &c"},
1164 };
1165
1166 static const struct
1167 {
1168 const char *url;
1169 DWORD flags;
1170 const char *expect;
1171 const char *expect_ftp;
1172 }
1173 http_tests[] =
1174 {
1175 /* A set of schemes including http differs from the "default" behaviour
1176 * in the following ways:
1177 *
1178 * (1) If a double dot would undo the hostname, it is dropped instead.
1179 *
1180 * (2) If the first element after the hostname is a single or double
1181 * dot, no further dots are simplified.
1182 *
1183 * (3) Trailing backslashes are not automatically appended after dots.
1184 */
1185
1186 {"//", 0, "///"},
1187 {"//a", 0, "//a/"},
1188 {"//a/", 0, "//a/"},
1189 {"//a/b", 0, "//a/b"},
1190 {"//a/b/", 0, "//a/b/"},
1191 {"//.", 0, "//./"},
1192 {"//./", 0, "//./"},
1193 {"//././a/.", 0, "//././a/."},
1194 {"//a/.", 0, "//a/."},
1195 {"//a/./b/./../", 0, "//a/./b/./../"},
1196 {"//a/b/.", 0, "//a/b/"},
1197 {"//a/b/.", URL_DONT_SIMPLIFY, "//a/b/."},
1198 {"//a/b/./", 0, "//a/b/"},
1199 {"//a/b/./c", 0, "//a/b/c"},
1200 {"///./a", 0, "///./a"},
1201 {"////./a", 0, "////a"},
1202
1203 {"//..", 0, "//../"},
1204 {"//../", 0, "//../"},
1205 {"//../a", 0, "//../a"},
1206 {"//../a/..", 0, "//../"},
1207 {"//../a/../..", 0, "//../"},
1208 {"//./a/../..", 0, "//./"},
1209 {"//a/../", 0, "//a/../"},
1210 {"//a/../../b/./../", 0, "//a/../../b/./../"},
1211 {"//a/.././", 0, "//a/.././"},
1212 {"//a/b/..", 0, "//a/"},
1213 {"//a/b/..", URL_DONT_SIMPLIFY, "//a/b/.."},
1214 {"//a/b/../", 0, "//a/"},
1215 {"//a/b/.././", 0, "//a/"},
1216 {"//a/b/../c", 0, "//a/c"},
1217 {"//a/b/../c/..", 0, "//a/"},
1218 {"//a/b/../c/../..", 0, "//a/"},
1219 {"//a/b/../../../c", 0, "//a/c"},
1220 {"///a/.", 0, "///a/"},
1221 {"///..", 0, "///.."},
1222 {"////..", 0, "///"},
1223 {"//a//../../..", 0, "//a/"},
1224
1225 {"//a/b?c/./d", 0, "//a/b?c/./d"},
1226 {"//a/b#c/./d", 0, "//a/b#c/./d"},
1227 {"//a/b#c?d", 0, "//a/b#c?d"},
1228 {"//a/b?c#d", 0, "//a/b?c#d"},
1229
1230 {"//localhost/b", 0, "//localhost/b"},
1231
1232 /* Most of these schemes translates backslashes to forward slashes,
1233 * including the initial pair, and interpret them appropriately.
1234 *
1235 * A few schemes, including ftp, don't translate backslashes to forward
1236 * slashes, but still interpret them as path separators, with the
1237 * exception that the hostname must end in a forward slash. */
1238
1239 {"//a/b\\", 0, "//a/b/", "//a/b\\"},
1240 {"//a/b\\./c", 0, "//a/b/c", "//a/b\\c"},
1241 {"//a/b/.\\c", 0, "//a/b/c"},
1242 {"//a/b\\c/../.\\", 0, "//a/b/", "//a/b\\"},
1243 {"//a\\b", 0, "//a/b", "//a\\b/"},
1244 {"//a\\b/..", 0, "//a/", "//a\\b/.."},
1245 {"//a/b\\c", 0, "//a/b/c", "//a/b\\c"},
1246 {"/\\a\\..", 0, "//a/..", "/\\a\\../"},
1247 {"\\/a\\..", 0, "//a/..", "\\/a\\../"},
1248
1249 {"//a/b &c", 0, "//a/b &c"},
1250
1251 /* If one or both slashes is missing, the portion after the colon is
1252 * treated like a normal path, without a hostname. Single and double
1253 * dots are always collapsed, and double dots which would rewind past
1254 * the scheme are dropped instead. */
1255
1256 {"a", 0, "a"},
1257 {"a/", 0, "a/"},
1258 {"a/.", 0, "a/"},
1259 {"a/..", 0, ""},
1260 {"a/../..", 0, ""},
1261 {"a/../..", URL_DONT_SIMPLIFY, "a/../.."},
1262 {"", 0, ""},
1263 {"/", 0, "/"},
1264 {"/.", 0, "/"},
1265 {"/..", 0, ""},
1266 {"/../..", 0, ""},
1267 {".", 0, ""},
1268 {"..", 0, ""},
1269 {"./", 0, ""},
1270 {"../", 0, ""},
1271
1272 {"a/b?c/.\\d", 0, "a/b?c/.\\d"},
1273 {"a/b#c/.\\d", 0, "a/b#c/.\\d"},
1274
1275 {"a\\b\\", 0, "a/b/", "a\\b\\"},
1276
1277 {"a/b &c", 0, "a/b &c"},
1278
1279 {"/foo/bar/baz", URL_ESCAPE_SEGMENT_ONLY, "/foo/bar/baz"},
1280 {"/foo/bar/baz?a#b", URL_ESCAPE_SEGMENT_ONLY, "/foo/bar/baz?a#b"},
1281
1282 {"//www.winehq.org/tests\n", URL_ESCAPE_SPACES_ONLY | URL_ESCAPE_UNSAFE, "//www.winehq.org/tests"},
1283 {"//www.winehq.org/tests\r", URL_ESCAPE_SPACES_ONLY | URL_ESCAPE_UNSAFE, "//www.winehq.org/tests"},
1284 {"//www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY | URL_DONT_ESCAPE_EXTRA_INFO, "//www.winehq.org/tests/foo%20bar"},
1285 {"//www.winehq.org/tests/foo%20bar", 0, "//www.winehq.org/tests/foo%20bar"},
1286 {"//www.winehq.org/tests/foo%20bar", URL_UNESCAPE, "//www.winehq.org/tests/foo bar"},
1287 {"//www.winehq.org/%E6%A1%9C.html", 0, "//www.winehq.org/%E6%A1%9C.html"},
1288 };
1289
1290 static const struct canonicalize_test opaque_tests[] =
1291 {
1292 /* Opaque protocols, predictably, do not modify the portion after the
1293 * scheme. */
1294 {"//a/b/./c/../d\\e", 0, "//a/b/./c/../d\\e"},
1295 {"/a/b/./c/../d\\e", 0, "/a/b/./c/../d\\e"},
1296 {"a/b/./c/../d\\e", 0, "a/b/./c/../d\\e"},
1297 {"", 0, ""},
1298 {"//a/b &c", 0, "//a/b &c"},
1299 {"//a/b%20%26c", URL_UNESCAPE, "//a/b &c"},
1300 };
1301
1302 static const struct canonicalize_test file_tests[] =
1303 {
1304 /* file:// is almost identical to http://, except that a URL beginning
1305 * with file://// (four or more slashes) is stripped down to two
1306 * slashes. The first non-empty element is interpreted as a hostname;
1307 * and the rest follows the usual rules.
1308 *
1309 * The intent here is probably to detect UNC paths, although it's
1310 * unclear why an arbitrary number of slashes are skipped in that case.
1311 */
1312
1313 {"file://", 0, "file:///"},
1314 {"file://a", 0, "file://a/"},
1315 {"file://a/", 0, "file://a/"},
1316 {"file://a//", 0, "file://a//"},
1317 {"file://a/b", 0, "file://a/b"},
1318 {"file://a/b/", 0, "file://a/b/"},
1319 {"file://.", 0, "file://./"},
1320 {"file://./", 0, "file://./"},
1321 {"file://././a/.", 0, "file://././a/."},
1322 {"file://a/.", 0, "file://a/."},
1323 {"file://a/./b/./../", 0, "file://a/./b/./../"},
1324 {"file://a/b/.", 0, "file://a/b/"},
1325 {"file://a/b/.", URL_DONT_SIMPLIFY, "file://a/b/."},
1326 {"file://a/b/./", 0, "file://a/b/"},
1327 {"file://a/b/./c", 0, "file://a/b/c"},
1328 {"file:///./a", 0, "file:///./a"},
1329 {"file:////./a", 0, "file://./a"},
1330
1331 {"file://..", 0, "file://../"},
1332 {"file://../", 0, "file://../"},
1333 {"file://../a", 0, "file://../a"},
1334 {"file://../a/..", 0, "file://../"},
1335 {"file://../a/../..", 0, "file://../"},
1336 {"file://./a/../..", 0, "file://./"},
1337 {"file://a/../", 0, "file://a/../"},
1338 {"file://a/../../b/./../", 0, "file://a/../../b/./../"},
1339 {"file://a/.././", 0, "file://a/.././"},
1340 {"file://a/b/..", 0, "file://a/"},
1341 {"file://a/b/../", 0, "file://a/"},
1342 {"file://a/b/.././", 0, "file://a/"},
1343 {"file://a/b/../c", 0, "file://a/c"},
1344 {"file://a/b/../c/..", 0, "file://a/"},
1345 {"file://a/b/../c/../..", 0, "file://a/"},
1346 {"file://a/b/../../../c", 0, "file://a/c"},
1347 {"file:///.", 0, "file:///."},
1348 {"file:///..", 0, "file:///.."},
1349 {"file:///a/.", 0, "file:///a/"},
1350
1351 {"file:////", 0, "file:///"},
1352 {"file:////a/./b/../c", 0, "file://a/./b/../c"},
1353 {"file://///a/./b/../c", 0, "file://a/./b/../c"},
1354 {"file://////a/./b/../c", 0, "file://a/./b/../c"},
1355 {"file:////a/b/./../c", 0, "file://a/c"},
1356 {"file:////a/b/./../..", 0, "file://a/"},
1357 {"file://///a/b/./../c", 0, "file://a/c"},
1358 {"file://////a/b/./../c", 0, "file://a/c"},
1359 {"file:////.", 0, "file://./"},
1360 {"file:////..", 0, "file://../"},
1361 {"file:////./b/./../c", 0, "file://./c"},
1362 {"file:////./b/./../..", 0, "file://./"},
1363 {"file://///./b/./../c", 0, "file://./c"},
1364 {"file://////./b/./../c", 0, "file://./c"},
1365
1366 /* Drive-like paths get an extra slash (i.e. an empty hostname, to
1367 * signal that the host is the local machine). The drive letter is
1368 * treated as the path root. */
1369 {"file://a:", 0, "file:///a:"},
1370 {"file://a:/b", 0, "file:///a:/b"},
1371 {"file://a:/b/../..", 0, "file:///a:/"},
1372 {"file://a:/./../..", 0, "file:///a:/./../.."},
1373 {"file://a|/b", 0, "file:///a|/b"},
1374 {"file://ab:/c", 0, "file://ab:/c"},
1375 {"file:///a:", 0, "file:///a:"},
1376 {"file:////a:", 0, "file:///a:"},
1377 {"file://///a:", 0, "file:///a:"},
1378 {"file://host/a:/b/../..", 0, "file://host/a:/"},
1379
1380 /* URL_FILE_USE_PATHURL (and URL_WININET_COMPATIBILITY) have their own
1381 * set of rules:
1382 *
1383 * (1) Dot processing works exactly like the "unknown scheme" rules,
1384 * instead of the file/http rules demonstrated above.
1385 *
1386 * (2) Some number of backslashes is appended after the two forward
1387 * slashes. The number basically corresponds to the detected path
1388 * type (two for a remote path, one for a local path, none for a
1389 * local drive path). A local path is one where the hostname is
1390 * empty or "localhost". If all path elements are empty then no
1391 * backslashes are appended.
1392 */
1393
1394 {"file://", URL_FILE_USE_PATHURL, "file://"},
1395 {"file://a", URL_FILE_USE_PATHURL, "file://\\\\a"},
1396 {"file://a/", URL_FILE_USE_PATHURL, "file://\\\\a"},
1397 {"file://a//", URL_FILE_USE_PATHURL, "file://\\\\a\\\\"},
1398 {"file://a/b", URL_FILE_USE_PATHURL, "file://\\\\a\\b"},
1399 {"file://a//b", URL_FILE_USE_PATHURL, "file://\\\\a\\\\b"},
1400 {"file://a/.", URL_FILE_USE_PATHURL, "file://\\\\a\\"},
1401 {"file://a/../../b/./c/..", URL_FILE_USE_PATHURL, "file://\\\\a\\..\\..\\b\\"},
1402 {"file://./../../b/./c/..", URL_FILE_USE_PATHURL, "file://\\\\.\\..\\..\\b\\"},
1403 {"file://../../../b/./c/..", URL_FILE_USE_PATHURL, "file://\\\\..\\..\\..\\b\\"},
1404 {"file://a/b/.", URL_FILE_USE_PATHURL, "file://\\\\a\\b\\"},
1405 {"file://a/b/.", URL_FILE_USE_PATHURL | URL_DONT_SIMPLIFY, "file://\\\\a\\b\\.\\"},
1406 {"file://a/b/../../../c", URL_FILE_USE_PATHURL, "file://\\\\a\\..\\..\\c"},
1407
1408 {"file:///", URL_FILE_USE_PATHURL, "file://"},
1409 {"file:///.", URL_FILE_USE_PATHURL, "file://\\"},
1410 {"file:///..", URL_FILE_USE_PATHURL, "file://\\..\\"},
1411 {"file:///../../b/./c/..", URL_FILE_USE_PATHURL, "file://\\..\\..\\b\\"},
1412 {"file:///a/b/./c/..", URL_FILE_USE_PATHURL, "file://\\a\\b\\"},
1413
1414 {"file:////", URL_FILE_USE_PATHURL, "file://"},
1415 {"file:////.", URL_FILE_USE_PATHURL, "file://\\\\."},
1416 {"file:////a/./b/../c", URL_FILE_USE_PATHURL, "file://\\\\a\\c"},
1417 {"file://///", URL_FILE_USE_PATHURL, "file://"},
1418 {"file://///a/./b/../c", URL_FILE_USE_PATHURL, "file://\\\\a\\c"},
1419
1420 {"file://a:", URL_FILE_USE_PATHURL, "file://a:"},
1421 {"file://a:/", URL_FILE_USE_PATHURL, "file://a:\\"},
1422 {"file://a:/b", URL_FILE_USE_PATHURL, "file://a:\\b"},
1423 {"file://a:/b/../..", URL_FILE_USE_PATHURL, "file://a:\\..\\"},
1424 {"file://a|/b", URL_FILE_USE_PATHURL, "file://a|\\b"},
1425 {"file:///a:", URL_FILE_USE_PATHURL, "file://a:"},
1426 {"file:////a:", URL_FILE_USE_PATHURL, "file://a:"},
1427
1428 /* URL_WININET_COMPATIBILITY is almost identical, but ensures a trailing
1429 * backslash in two cases:
1430 *
1431 * (1) if all path elements are empty,
1432 *
1433 * (2) if the path consists of just the hostname.
1434 */
1435
1436 {"file://", URL_WININET_COMPATIBILITY, "file://\\"},
1437 {"file://a", URL_WININET_COMPATIBILITY, "file://\\\\a\\"},
1438 {"file://a/", URL_WININET_COMPATIBILITY, "file://\\\\a\\"},
1439 {"file://a//", URL_WININET_COMPATIBILITY, "file://\\\\a\\\\"},
1440 {"file://a/b", URL_WININET_COMPATIBILITY, "file://\\\\a\\b"},
1441 {"file://a//b", URL_WININET_COMPATIBILITY, "file://\\\\a\\\\b"},
1442 {"file://a/.", URL_WININET_COMPATIBILITY, "file://\\\\a\\"},
1443 {"file://a/../../b/./c/..", URL_WININET_COMPATIBILITY, "file://\\\\a\\..\\..\\b\\"},
1444 {"file://./../../b/./c/..", URL_WININET_COMPATIBILITY, "file://\\\\.\\..\\..\\b\\"},
1445 {"file://../../../b/./c/..", URL_WININET_COMPATIBILITY, "file://\\\\..\\..\\..\\b\\"},
1446 {"file://a/b/../../../c", URL_WININET_COMPATIBILITY, "file://\\\\a\\..\\..\\c"},
1447
1448 {"file:///", URL_WININET_COMPATIBILITY, "file://\\"},
1449 {"file:///.", URL_WININET_COMPATIBILITY, "file://\\"},
1450 {"file:///..", URL_WININET_COMPATIBILITY, "file://\\..\\"},
1451 {"file:///../../b/./c/..", URL_WININET_COMPATIBILITY, "file://\\..\\..\\b\\"},
1452 {"file:///a/b/./c/..", URL_WININET_COMPATIBILITY, "file://\\a\\b\\"},
1453
1454 {"file:////", URL_WININET_COMPATIBILITY, "file://\\"},
1455 {"file:////.", URL_WININET_COMPATIBILITY, "file://\\\\.\\"},
1456 {"file:////a/./b/../c", URL_WININET_COMPATIBILITY, "file://\\\\a\\c"},
1457 {"file://///", URL_WININET_COMPATIBILITY, "file://\\"},
1458 {"file://///a/./b/../c", URL_WININET_COMPATIBILITY, "file://\\\\a\\c"},
1459
1460 {"file://a:", URL_WININET_COMPATIBILITY, "file://a:"},
1461
1462 {"file://", URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY, "file://"},
1463
1464 {"file://localhost/a", 0, "file://localhost/a"},
1465 {"file://localhost//a", 0, "file://localhost//a"},
1466 {"file://localhost/a:", 0, "file://localhost/a:"},
1467 {"file://localhost/a:/b/../..", 0, "file://localhost/a:/"},
1468 {"file://localhost/a:/./../..", 0, "file://localhost/a:/./../.."},
1469 {"file://localhost", URL_FILE_USE_PATHURL, "file://"},
1470 {"file://localhost/", URL_FILE_USE_PATHURL, "file://"},
1471 {"file://localhost/b", URL_FILE_USE_PATHURL, "file://\\b"},
1472 {"file://127.0.0.1/b", URL_FILE_USE_PATHURL, "file://\\\\127.0.0.1\\b"},
1473 {"file://localhost//b", URL_FILE_USE_PATHURL, "file://\\b"},
1474 {"file://localhost///b", URL_FILE_USE_PATHURL, "file://\\\\b"},
1475 {"file:///localhost/b", URL_FILE_USE_PATHURL, "file://\\localhost\\b"},
1476 {"file:////localhost/b", URL_FILE_USE_PATHURL, "file://\\b"},
1477 {"file://///localhost/b", URL_FILE_USE_PATHURL, "file://\\b"},
1478 {"file://localhost/a:", URL_FILE_USE_PATHURL, "file://a:"},
1479 {"file://localhost/a:/b/../..", URL_FILE_USE_PATHURL, "file://a:\\..\\"},
1480 {"file://localhost?a/b", URL_FILE_USE_PATHURL, "file://"},
1481 {"file://localhost#a/b", URL_FILE_USE_PATHURL, "file://\\\\localhost#a/b"},
1482 {"file://localhostq", URL_FILE_USE_PATHURL, "file://\\\\localhostq"},
1483
1484 {"file://localhost", URL_WININET_COMPATIBILITY, "file://\\"},
1485 {"file://localhost/", URL_WININET_COMPATIBILITY, "file://\\"},
1486 {"file://localhost/b", URL_WININET_COMPATIBILITY, "file://\\b"},
1487 {"file://localhost//b", URL_WININET_COMPATIBILITY, "file://\\b"},
1488 {"file://127.0.0.1/b", URL_WININET_COMPATIBILITY, "file://\\\\127.0.0.1\\b"},
1489 {"file://localhost/a:", URL_WININET_COMPATIBILITY, "file://a:"},
1490 {"file://localhost?a/b", URL_WININET_COMPATIBILITY, "file://\\?a/b"},
1491 {"file://localhost#a/b", URL_WININET_COMPATIBILITY, "file://\\\\localhost#a/b"},
1492
1493 /* # has some weird behaviour:
1494 *
1495 * - Dot processing happens normally after it, including rewinding past
1496 * the #. It's not treated as a path separator for the purposes of
1497 * rewinding.
1498 *
1499 * - However, if neither file flag is used, and the first character
1500 * after the hostname (plus an optional slash) is a hash, no dot
1501 * processing takes place.
1502 *
1503 * - If the previous path segment ends in .htm or .html, the rest of
1504 * the URL is emitted verbatim (no dot or slash canonicalization).
1505 * This does not apply to the hostname. If URL_FILE_USE_PATHURL is
1506 * used, though, the rest of the URL including the # is omitted.
1507 *
1508 * - It is treated as a path terminator for dots, but only if neither
1509 * file flag is used. It does not begin a path element.
1510 *
1511 * - If there is a # anywhere in the output string (and the string
1512 * doesn't fall under the .html exception), all subsequent slashes
1513 * are converted to forward slashes instead of backslashes.
1514 * This means that rewinding past the hash will revert to backslashes.
1515 * (This of course only affects the case where file flags are used;
1516 * if no file flags are used then slashes are converted to forward
1517 * slashes anyway.)
1518 */
1519 {"file://a/b#c/../d\\e", 0, "file://a/d/e"},
1520 {"file://a/b#c/./d\\e", 0, "file://a/b#c/d/e"},
1521 {"file://a/b.htm#c/../d\\e", 0, "file://a/b.htm#c/../d\\e"},
1522 {"file://a/b.html#c/../d\\e", 0, "file://a/b.html#c/../d\\e"},
1523 {"file://a/b.hTmL#c/../d\\e", 0, "file://a/b.hTmL#c/../d\\e"},
1524 {"file://a/b.xhtml#c/../d\\e", 0, "file://a/d/e"},
1525 {"file://a/b.php#c/../d\\e", 0, "file://a/d/e"},
1526 {"file://a/b.asp#c/../d\\e", 0, "file://a/d/e"},
1527 {"file://a/b.aspx#c/../d\\e", 0, "file://a/d/e"},
1528 {"file://a/b.ht#c/../d\\e", 0, "file://a/d/e"},
1529 {"file://a/b.txt#c/../d\\e", 0, "file://a/d/e"},
1530 {"file://a/b.htmlq#c/../d\\e", 0, "file://a/d/e"},
1531 {"file://a/b.html/q#c/../d\\e", 0, "file://a/b.html/d/e"},
1532 {"file://a/.html#c/../d\\e", 0, "file://a/.html#c/../d\\e"},
1533 {"file://a/html#c/../d\\e", 0, "file://a/d/e"},
1534 {"file://a/b#c/./d.html#e/../f", 0, "file://a/b#c/d.html#e/../f"},
1535 {"file://a.html#/b/../c", 0, "file://a.html#/c"},
1536 {"file://a/b#c/../d/e", URL_FILE_USE_PATHURL, "file://\\\\a\\d\\e"},
1537 {"file://a/b#c/./d/e", URL_FILE_USE_PATHURL, "file://\\\\a\\b#c/d/e"},
1538 {"file://a/b.html#c/../d\\e", URL_FILE_USE_PATHURL, "file://\\\\a\\b.html"},
1539 {"file://a/b.html#c/../d\\e", URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY, "file://\\\\a\\b.html"},
1540 {"file://a/b#c/../d/e", URL_WININET_COMPATIBILITY, "file://\\\\a\\d\\e"},
1541 {"file://a/b#c/./d/e", URL_WININET_COMPATIBILITY, "file://\\\\a\\b#c/d/e"},
1542 {"file://a/b.html#c/../d\\e", URL_WININET_COMPATIBILITY, "file://\\\\a\\b.html#c/../d\\e"},
1543 {"file://a/c#/../d", 0, "file://a/d"},
1544 {"file://a/c#/../d", URL_FILE_USE_PATHURL, "file://\\\\a\\d"},
1545 {"file://a/c#/../d", URL_WININET_COMPATIBILITY, "file://\\\\a\\d"},
1546 {"file://a/#c/../d\\e", 0, "file://a/#c/../d\\e"},
1547 {"file://a/#c/../d/e", URL_FILE_USE_PATHURL, "file://\\\\a\\d\\e"},
1548 {"file://a/#c/../d/e", URL_WININET_COMPATIBILITY, "file://\\\\a\\d\\e"},
1549 {"file://a//#c/../d", 0, "file://a//#c/../d"},
1550 {"file://a//#c/../d", URL_FILE_USE_PATHURL, "file://\\\\a\\\\d"},
1551 {"file://a//#c/../d", URL_WININET_COMPATIBILITY, "file://\\\\a\\\\d"},
1552 {"file://a/\\#c/../d", 0, "file://a//#c/../d"},
1553 {"file://a///#c/../d", 0, "file://a///d"},
1554 {"file://a/b/#c/../d", 0, "file://a/b/d"},
1555 {"file://a/b/.#c", 0, "file://a/b/#c"},
1556 {"file://a/b/..#c", 0, "file://a/#c"},
1557 {"file://a/b/.#c", URL_FILE_USE_PATHURL, "file://\\\\a\\b\\.#c"},
1558 {"file://a/b/..#c", URL_FILE_USE_PATHURL, "file://\\\\a\\b\\..#c"},
1559 {"file://a/b/.#c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b\\.#c"},
1560 {"file://a/b/..#c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b\\..#c"},
1561 {"file://a/b#../c", 0, "file://a/b#../c"},
1562 {"file://a/b/#../c", 0, "file://a/b/#../c"},
1563 {"file://a/b#../c", URL_FILE_USE_PATHURL, "file://\\\\a\\b#../c"},
1564 {"file://a/b#../c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b#../c"},
1565 {"file://#/b\\./", 0, "file://#/b/"},
1566 {"file://#/./b\\./", 0, "file://#/./b/./"},
1567 {"file://#/b\\./", URL_FILE_USE_PATHURL, "file://\\\\#/b/"},
1568 {"file://#/b\\./", URL_WININET_COMPATIBILITY, "file://\\\\#/b/"},
1569 {"file://a#/b\\./", 0, "file://a#/b/"},
1570 {"file://a#/./b\\./", 0, "file://a#/./b/./"},
1571 {"file://a#/b\\./", URL_FILE_USE_PATHURL, "file://\\\\a#/b/"},
1572 {"file://a#/b\\./", URL_WININET_COMPATIBILITY, "file://\\\\a#/b/"},
1573 {"file://a#/b\\./", URL_FILE_USE_PATHURL | URL_DONT_SIMPLIFY, "file://\\\\a#/b/./"},
1574 {"file://a#/b\\.", URL_FILE_USE_PATHURL | URL_DONT_SIMPLIFY, "file://\\\\a#/b/./"},
1575 {"file://a#/b/../../", 0, "file://a#/"},
1576
1577 /* ? is similar, with the following exceptions:
1578 *
1579 * - URLs ending in .htm(l) are not treated specially.
1580 *
1581 * - With URL_FILE_USE_PATHURL, the rest of the URL including the ? is
1582 * just omitted (much like the .html case above).
1583 *
1584 * - With URL_WININET_COMPATIBILITY, the rest of the URL is always
1585 * emitted verbatim (completely opaque, like other schemes).
1586 */
1587
1588 {"file://a/b?c/../d\\e", 0, "file://a/d/e"},
1589 {"file://a/b.html?c/../d\\e", 0, "file://a/d/e"},
1590 {"file://a/b?c/../d\\e", URL_FILE_USE_PATHURL, "file://\\\\a\\b"},
1591 {"file://a/b.html?c/../d\\e", URL_FILE_USE_PATHURL, "file://\\\\a\\b.html"},
1592 {"file://a/b?c/../d\\e", URL_WININET_COMPATIBILITY, "file://\\\\a\\b?c/../d\\e"},
1593 {"file://a/b.html?c/../d\\e", URL_WININET_COMPATIBILITY, "file://\\\\a\\b.html?c/../d\\e"},
1594 {"file://a/b?c/../d", URL_FILE_USE_PATHURL | URL_WININET_COMPATIBILITY, "file://\\\\a\\b"},
1595 {"file://a/?c/../d", 0, "file://a/?c/../d"},
1596 {"file://a/?c/../d", URL_FILE_USE_PATHURL, "file://\\\\a"},
1597 {"file://a/?c/../d", URL_WININET_COMPATIBILITY, "file://\\\\a\\?c/../d"},
1598 {"file://a//?c/../d", 0, "file://a//?c/../d"},
1599 {"file://a//?c/../d", URL_FILE_USE_PATHURL, "file://\\\\a\\\\"},
1600 {"file://a//?c/../d", URL_WININET_COMPATIBILITY, "file://\\\\a\\\\?c/../d"},
1601 {"file://a/\\?c/../d", 0, "file://a//?c/../d"},
1602 {"file://a///?c/../d", 0, "file://a///d"},
1603 {"file://a/b/?c/../d", 0, "file://a/b/d"},
1604 {"file://a/b/.?c", 0, "file://a/b/?c"},
1605 {"file://a/b/..?c", 0, "file://a/?c"},
1606 {"file://a/b/.?c", URL_FILE_USE_PATHURL, "file://\\\\a\\b\\"},
1607 {"file://a/b/..?c", URL_FILE_USE_PATHURL, "file://\\\\a\\"},
1608 {"file://a/b/.?c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b\\?c"},
1609 {"file://a/b/..?c", URL_WININET_COMPATIBILITY, "file://\\\\a\\?c"},
1610 {"file://?/a\\./", 0, "file://?/a/"},
1611 {"file://?/./a\\./", 0, "file://?/./a/./"},
1612 {"file://?/a\\./", URL_FILE_USE_PATHURL, "file://"},
1613 {"file://?/a\\./", URL_WININET_COMPATIBILITY, "file://\\?/a\\./"},
1614 {"file://a?/a\\./", 0, "file://a?/a/"},
1615 {"file://a?/./a\\./", 0, "file://a?/./a/./"},
1616 {"file://a?/a\\./", URL_FILE_USE_PATHURL, "file://\\\\a"},
1617 {"file://a?/a\\./", URL_WININET_COMPATIBILITY, "file://\\\\a\\?/a\\./"},
1618
1619 {"file://a/b.html?c#d/..", 0, "file://a/"},
1620 {"file://a/b.html?c.html#d/..", 0, "file://a/b.html?c.html#d/.."},
1621 {"file://a/b?\\#c\\d", 0, "file://a/b?/#c/d"},
1622 {"file://a/b?\\#c\\d", URL_WININET_COMPATIBILITY, "file://\\\\a\\b?\\#c\\d"},
1623 {"file://a/b?\\#c\\d", URL_FILE_USE_PATHURL, "file://\\\\a\\b"},
1624 {"file://a/b#\\?c\\d", 0, "file://a/b#/?c/d"},
1625 {"file://a/b#\\?c\\d", URL_WININET_COMPATIBILITY, "file://\\\\a\\b#/?c\\d"},
1626 {"file://a/b#\\?c\\d", URL_FILE_USE_PATHURL, "file://\\\\a\\b#/"},
1627 {"file://a/b.html#c?d", URL_WININET_COMPATIBILITY, "file://\\\\a\\b.html?d#c"},
1628
1629 /* file: treats backslashes like forward slashes, including the
1630 * initial pair. */
1631 {"file://a/b\\", 0, "file://a/b/"},
1632 {"file://a/b\\c/../.\\", 0, "file://a/b/"},
1633 {"file://a\\b", 0, "file://a/b"},
1634 {"file:/\\a\\..", 0, "file://a/.."},
1635 {"file:\\/a\\..", 0, "file://a/.."},
1636 {"file:\\\\a\\b", URL_FILE_USE_PATHURL, "file://\\\\a\\b"},
1637 {"file:\\\\a\\b", URL_WININET_COMPATIBILITY, "file://\\\\a\\b"},
1638 {"file:\\///a/./b/../c", 0, "file://a/./b/../c"},
1639 {"file:/\\//a/./b/../c", 0, "file://a/./b/../c"},
1640 {"file://\\/a/./b/../c", 0, "file://a/./b/../c"},
1641 {"file:///\\a/./b/../c", 0, "file://a/./b/../c"},
1642
1643 {"file://a/b &c", 0, "file://a/b &c"},
1644 {"file://a/b &c", URL_FILE_USE_PATHURL, "file://\\\\a\\b &c"},
1645 {"file://a/b &c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b &c"},
1646 {"file://a/b !\"$%&'()*+,-:;<=>@[]^_`{|}~c", URL_ESCAPE_UNSAFE, "file://a/b%20!%22$%%26'()*+,-:;%3C=%3E@%5B%5D%5E_%60%7B%7C%7D~c"},
1647 {"file://a/b%20%26c", 0, "file://a/b%20%26c"},
1648 {"file://a/b%20%26c", URL_FILE_USE_PATHURL, "file://\\\\a\\b &c"},
1649 {"file://a/b%20%26c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b%20%26c"},
1650
1651 /* Omitting one slash behaves as if the URL had been written with an
1652 * empty hostname, and the output adds two slashes as such. */
1653
1654 {"file:/", 0, "file:///"},
1655 {"file:/a", 0, "file:///a"},
1656 {"file:/./a", 0, "file:///./a"},
1657 {"file:/../a/..", 0, "file:///../a/.."},
1658 {"file:/./..", 0, "file:///./.."},
1659 {"file:/a/.", 0, "file:///a/"},
1660 {"file:/a/../..", 0, "file:///"},
1661 {"file:/a:", 0, "file:///a:"},
1662 {"file:/a:/b/../..", 0, "file:///a:/"},
1663
1664 /* The same applies to the flags. */
1665
1666 {"file:/", URL_FILE_USE_PATHURL, "file://"},
1667 {"file:/a", URL_FILE_USE_PATHURL, "file://\\a"},
1668 {"file:/.", URL_FILE_USE_PATHURL, "file://\\"},
1669 {"file:/./a", URL_FILE_USE_PATHURL, "file://\\a"},
1670 {"file:/../a", URL_FILE_USE_PATHURL, "file://\\..\\a"},
1671 {"file:/a/../..", URL_FILE_USE_PATHURL, "file://\\..\\"},
1672 {"file:/a/.", URL_FILE_USE_PATHURL | URL_DONT_SIMPLIFY, "file://\\a\\.\\"},
1673 {"file:/a:", URL_FILE_USE_PATHURL, "file://a:"},
1674 {"file:/a:/b/../..", URL_FILE_USE_PATHURL, "file://a:\\..\\"},
1675
1676 {"file:/", URL_WININET_COMPATIBILITY, "file://\\"},
1677 {"file:/a", URL_WININET_COMPATIBILITY, "file://\\a"},
1678 {"file:/.", URL_WININET_COMPATIBILITY, "file://\\"},
1679 {"file:/a:", URL_WININET_COMPATIBILITY, "file://a:"},
1680
1681 {"file:/a/b#c/../d", 0, "file:///a/d"},
1682 {"file:/a/b?c/../d", 0, "file:///a/d"},
1683
1684 {"file:/a\\b\\", 0, "file:///a/b/"},
1685 {"file:\\a/b/", 0, "file:///a/b/"},
1686 {"file:\\a\\b", URL_FILE_USE_PATHURL, "file://\\a\\b"},
1687 {"file:\\a\\b", URL_WININET_COMPATIBILITY, "file://\\a\\b"},
1688
1689 {"file:/a/b &c", 0, "file:///a/b &c"},
1690
1691 /* Omitting both slashes causes all dots to be collapsed, in the same
1692 * way as bare http. */
1693
1694 {"file:a", 0, "file:a"},
1695 {"file:a/", 0, "file:a/"},
1696 {"file:a/.", 0, "file:a/"},
1697 {"file:a/..", 0, "file:"},
1698 {"file:a/../..", 0, "file:"},
1699 {"file:", 0, "file:"},
1700 {"file:.", 0, "file:"},
1701 {"file:..", 0, "file:"},
1702 {"file:./", 0, "file:"},
1703 {"file:../", 0, "file:"},
1704
1705 {"file:a:", 0, "file:///a:"},
1706
1707 /* URL_FILE_USE_PATHURL treats everything here as a local (relative?)
1708 * path. In the case that the path resolves to the current directory
1709 * a single backslash is emitted. */
1710 {"file:", URL_FILE_USE_PATHURL, "file://"},
1711 {"file:a", URL_FILE_USE_PATHURL, "file://a"},
1712 {"file:a/.", URL_FILE_USE_PATHURL, "file://a\\"},
1713 {"file:a/../..", URL_FILE_USE_PATHURL, "file://..\\"},
1714 {"file:./a", URL_FILE_USE_PATHURL, "file://a"},
1715 {"file:../a", URL_FILE_USE_PATHURL, "file://..\\a"},
1716 {"file:a/.", URL_FILE_USE_PATHURL | URL_DONT_SIMPLIFY, "file://a\\.\\"},
1717 {"file:a:", URL_FILE_USE_PATHURL, "file://a:"},
1718
1719 /* URL_WININET_COMPATIBILITY doesn't emit a double slash. */
1720 {"file:", URL_WININET_COMPATIBILITY, "file:"},
1721 {"file:a", URL_WININET_COMPATIBILITY, "file:a"},
1722 {"file:./a", URL_WININET_COMPATIBILITY, "file:a"},
1723 {"file:../a", URL_WININET_COMPATIBILITY, "file:..\\a"},
1724 {"file:../b/./c/../d", URL_WININET_COMPATIBILITY | URL_DONT_SIMPLIFY, "file:..\\b\\.\\c\\..\\d"},
1725 {"file:a:", URL_WININET_COMPATIBILITY, "file://a:"},
1726
1727 {"file:a/b?c/../d", 0, "file:a/d"},
1728 {"file:a/b#c/../d", 0, "file:a/d"},
1729
1730 {"file:a\\b\\", 0, "file:a/b/"},
1731
1732 {"file:a/b &c", 0, "file:a/b &c"},
1733
1734 {"fIlE://A/B", 0, "file://A/B"},
1735 {"fIlE://A/B", URL_FILE_USE_PATHURL, "file://\\\\A\\B"},
1736 {"fIlE://A/B", URL_WININET_COMPATIBILITY, "file://\\\\A\\B"},
1737 {"fIlE:A:/B", 0, "file:///A:/B"},
1738 {"fIlE:A:/B", URL_FILE_USE_PATHURL, "file://A:\\B"},
1739 {"fIlE:A:/B", URL_WININET_COMPATIBILITY, "file://A:\\B"},
1740 {"fIlE://lOcAlHoSt/B", 0, "file://lOcAlHoSt/B"},
1741 {"fIlE://lOcAlHoSt/B", URL_FILE_USE_PATHURL, "file://\\B"},
1742
1743 /* Drive paths are automatically converted to file paths. Dots are
1744 * collapsed unless the first segment after q: or q:/ is a dot. */
1745
1746 {"q:a", 0, "file:///q:a"},
1747 {"q:a/.", 0, "file:///q:a/"},
1748 {"q:a/..", 0, "file:///q:"},
1749 {"q:a/../..", 0, "file:///q:"},
1750 {"q:./a/..", 0, "file:///q:./a/.."},
1751 {"q:../a/..", 0, "file:///q:../a/.."},
1752 {"q:/", 0, "file:///q:/"},
1753 {"q:/a", 0, "file:///q:/a"},
1754 {"q:/a/.", 0, "file:///q:/a/"},
1755 {"q:/a/..", 0, "file:///q:/"},
1756 {"q:/./a/..", 0, "file:///q:/./a/.."},
1757 {"q:/../a/..", 0, "file:///q:/../a/.."},
1758 {"q://./a", 0, "file:///q://a"},
1759 {"q://../a", 0, "file:///q:/a"},
1760
1761 /* File flags use the "unknown scheme" rules, and the root of the path
1762 * is the first slash. */
1763
1764 {"q:/a", URL_FILE_USE_PATHURL, "file://q:\\a"},
1765 {"q:/a/../..", URL_FILE_USE_PATHURL, "file://q:\\..\\"},
1766 {"q:a/../../b/..", URL_FILE_USE_PATHURL, "file://q:a\\..\\..\\"},
1767 {"q:./../../b/..", URL_FILE_USE_PATHURL, "file://q:.\\..\\..\\"},
1768 {"q:/a", URL_WININET_COMPATIBILITY, "file://q:\\a"},
1769 {"q:/a/../..", URL_WININET_COMPATIBILITY, "file://q:\\..\\"},
1770 {"q:a/../../b/..", URL_WININET_COMPATIBILITY, "file://q:a\\..\\..\\"},
1771 {"q:./../../b/..", URL_WININET_COMPATIBILITY, "file://q:.\\..\\..\\"},
1772
1773 {"q:/a/b?c/../d", 0, "file:///q:/a/d"},
1774 {"q:/a/b#c/../d", 0, "file:///q:/a/d"},
1775 {"q:a?b", URL_FILE_USE_PATHURL, "file://q:a"},
1776
1777 {"q:a\\b\\", 0, "file:///q:a/b/"},
1778 {"q:\\a/b", 0, "file:///q:/a/b"},
1779
1780 /* Drive paths are also unique in that unsafe characters (and spaces)
1781 * are automatically escaped—but not if the file flags are used. */
1782
1783 {"q:/a/b !\"$%&'()*+,-:;<=>@[]^_`{|}~c", 0, "file:///q:/a/b%20!%22$%25%26'()*+,-:;%3C=%3E@%5B%5D%5E_%60%7B%7C%7D~c"},
1784 {"q:/a/b &c", URL_FILE_USE_PATHURL, "file://q:\\a\\b &c"},
1785 {"q:/a/b &c", URL_WININET_COMPATIBILITY, "file://q:\\a\\b &c"},
1786
1787 {"q:/a/b%20%26c", 0, "file:///q:/a/b%2520%2526c"},
1788 {"q:/a/b%20%26c", URL_UNESCAPE, "file:///q:/a/b &c"},
1789 {"q:/a/b%20%26c", URL_UNESCAPE | URL_ESCAPE_UNSAFE, "file:///q:/a/b%20%26c"},
1790 {"q:/a/b%20%26c", URL_FILE_USE_PATHURL, "file://q:\\a\\b &c"},
1791 {"q:/a/b%20%26c", URL_FILE_USE_PATHURL | URL_UNESCAPE, "file://q:\\a\\b &c"},
1792 {"q:/a/b%20%26c", URL_WININET_COMPATIBILITY, "file://q:\\a\\b%20%26c"},
1793 {"q:/a/b%20%26c", URL_WININET_COMPATIBILITY | URL_UNESCAPE, "file://q:\\a\\b &c"},
1794
1795 {"q|a", 0, "file:///q%7Ca"},
1796 {"-:a", 0, "-:a"},
1797 {"Q:A", 0, "file:///Q:A"},
1798
1799 /* A double initial backslash is also converted to a file path. The same
1800 * rules for hostnames apply. */
1801
1802 {"\\\\", 0, "file:///"},
1803 {"\\\\a", 0, "file://a/"},
1804 {"\\\\../a\\b/..\\c/.\\", 0, "file://../a/c/"},
1805 {"\\\\a/./b/../c", 0, "file://a/./b/../c"},
1806 /* And, of course, four or more slashes gets collapsed... */
1807 {"\\\\//./b/./../c", 0, "file://./c"},
1808 {"\\\\///./b/./../c", 0, "file://./c"},
1809
1810 {"\\\\a/b?c/../d", 0, "file://a/d"},
1811 {"\\\\a/b#c/../d", 0, "file://a/d"},
1812
1813 /* Drive paths are "recognized" too, though. The following isn't
1814 * actually a local path, but UrlCanonicalize() doesn't seem to realize
1815 * that. */
1816 {"\\\\a:/b", 0, "file:///a:/b"},
1817
1818 {"\\\\", URL_FILE_USE_PATHURL, "file://"},
1819 {"\\\\a", URL_FILE_USE_PATHURL, "file://\\\\a"},
1820 {"\\\\a/./..", URL_FILE_USE_PATHURL, "file://\\\\a\\..\\"},
1821 {"\\\\a:/b", URL_FILE_USE_PATHURL, "file://a:\\b"},
1822 {"\\\\", URL_WININET_COMPATIBILITY, "file://\\"},
1823 {"\\\\a", URL_WININET_COMPATIBILITY, "file://\\\\a\\"},
1824 {"\\\\a/./..", URL_WININET_COMPATIBILITY, "file://\\\\a\\..\\"},
1825 {"\\\\a:/b", URL_WININET_COMPATIBILITY, "file://a:\\b"},
1826
1827 /* And, as with drive paths, unsafe characters are escaped. */
1828 {"\\\\a/b !\"$%&'()*+,-:;<=>@[]^_`{|}~c", 0, "file://a/b%20!%22$%25%26'()*+,-:;%3C=%3E@%5B%5D%5E_%60%7B%7C%7D~c"},
1829 {"\\\\a/b &c", URL_FILE_USE_PATHURL, "file://\\\\a\\b &c"},
1830 {"\\\\a/b &c", URL_WININET_COMPATIBILITY, "file://\\\\a\\b &c"},
1831
1832 {"\\\\/b", 0, "file:///b"},
1833 {"\\\\/b", URL_FILE_USE_PATHURL, "file://\\b"},
1834 {"\\\\localhost/b", URL_FILE_USE_PATHURL, "file://\\b"},
1835 {"\\\\127.0.0.1/b", URL_FILE_USE_PATHURL, "file://\\\\127.0.0.1\\b"},
1836 {"\\\\localhost/b", URL_WININET_COMPATIBILITY, "file://\\b"},
1837 {"\\\\127.0.0.1/b", URL_WININET_COMPATIBILITY, "file://\\\\127.0.0.1\\b"},
1838
1839 {"\\\\A/B", 0, "file://A/B"},
1840
1841 {"file:///c:/tests/foo%20bar", URL_UNESCAPE, "file:///c:/tests/foo bar"},
1842 {"file:///c:/tests\\foo%20bar", URL_UNESCAPE, "file:///c:/tests/foo bar"},
1843 {"file:///c:/tests/foo%20bar", 0, "file:///c:/tests/foo%20bar"},
1844 {"file:///c:/tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1845 {"file://localhost/c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1846 {"file://localhost\\c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1847 {"file://localhost\\\\c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1848 {"file://localhost\\c:\\tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1849 {"file://c:/tests/../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1850 {"file://c:/tests\\../tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1851 {"file://c:/tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\tests\\foo bar"},
1852 {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, "file://c:\\\\tests\\foo bar"},
1853 {"file:///c:\\tests\\foo bar", 0, "file:///c:/tests/foo bar"},
1854 {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, "file:///c:/tests/foo bar"},
1855 {"file:///c:\\tests\\foobar", 0, "file:///c:/tests/foobar"},
1856 {"file:///c:\\tests\\foobar", URL_WININET_COMPATIBILITY, "file://c:\\tests\\foobar"},
1857 {"file://home/user/file", 0, "file://home/user/file"},
1858 {"file:///home/user/file", 0, "file:///home/user/file"},
1859 {"file:////home/user/file", 0, "file://home/user/file"},
1860 {"file://home/user/file", URL_WININET_COMPATIBILITY, "file://\\\\home\\user\\file"},
1861 {"file:///home/user/file", URL_WININET_COMPATIBILITY, "file://\\home\\user\\file"},
1862 {"file:////home/user/file", URL_WININET_COMPATIBILITY, "file://\\\\home\\user\\file"},
1863 {"file://///home/user/file", URL_WININET_COMPATIBILITY, "file://\\\\home\\user\\file"},
1864 {"file://C:/user/file", 0, "file:///C:/user/file"},
1865 {"file://C:/user/file/../asdf", 0, "file:///C:/user/asdf"},
1866 {"file:///C:/user/file", 0, "file:///C:/user/file"},
1867 {"file:////C:/user/file", 0, "file:///C:/user/file"},
1868 {"file://C:/user/file", URL_WININET_COMPATIBILITY, "file://C:\\user\\file"},
1869 {"file:///C:/user/file", URL_WININET_COMPATIBILITY, "file://C:\\user\\file"},
1870 {"file:////C:/user/file", URL_WININET_COMPATIBILITY, "file://C:\\user\\file"},
1871 };
1872
1873 static const struct canonicalize_test misc_tests[] =
1874 {
1875 {"", 0, ""},
1876
1877 /* If both slashes are omitted, everything afterwards is replicated
1878 * as-is, with the exception that the final period is dropped from
1879 * "scheme:." */
1880
1881 {"wine:.", 0, "wine:"},
1882 {"wine:.", URL_DONT_SIMPLIFY, "wine:."},
1883 {"wine:./", 0, "wine:./"},
1884 {"wine:..", 0, "wine:.."},
1885 {"wine:../", 0, "wine:../"},
1886 {"wine:a", 0, "wine:a"},
1887 {"wine:a/", 0, "wine:a/"},
1888 {"wine:a/b/./../c", 0, "wine:a/b/./../c"},
1889
1890 {"wine:a/b?c/./d", 0, "wine:a/b?c/./d"},
1891 {"wine:a/b#c/./d", 0, "wine:a/b#c/./d"},
1892 {"wine:a/b#c?d", 0, "wine:a/b?d#c"},
1893 {"wine:.#c?d", 0, "wine:?d#c"},
1894
1895 /* A backslash directly after the colon is not treated specially. */
1896 {"wine:\\././a", 0, "wine:\\././a"},
1897
1898 {"wine:a/b &c", 0, "wine:a/b &c"},
1899
1900 /* If there's no scheme or hostname, things mostly follow the "unknown
1901 * scheme" rules, except that a would-be empty string results in a
1902 * single slash instead. */
1903
1904 {"a", 0, "a"},
1905 {"a/", 0, "a/"},
1906 {".", 0, "/"},
1907 {".", URL_DONT_SIMPLIFY, "./"},
1908 {"./", 0, "/"},
1909 {"./.", 0, "/"},
1910 {"././a", 0, "a"},
1911 {"a/.", 0, "a/"},
1912 {"a/./", 0, "a/"},
1913 {"a/./b", 0, "a/b"},
1914
1915 {"..", 0, "../"},
1916 {"../", 0, "../"},
1917 {"../a", 0, "../a"},
1918 {"../a/..", 0, "../"},
1919 {"a/..", 0, "/"},
1920 {"a/../..", 0, "../"},
1921 {"a/b/..", 0, "a/"},
1922 {"a/b/../", 0, "a/"},
1923 {"a/b/../c", 0, "a/c"},
1924 {"a/b/../c/..", 0, "a/"},
1925 {"a/b/../c/../..", 0, "/"},
1926
1927 {"a/b?c/./d", 0, "a/b?c/./d"},
1928 {"a/b#c/./d", 0, "a/b#c/./d"},
1929 {"a/b#c?d", 0, "a/b?d#c"},
1930 {"?c", 0, "?c"},
1931 {".?c", 0, "/?c"},
1932
1933 {"?c/./d", 0, "?c/./d"},
1934 {"#c/./d", 0, "#c/./d"},
1935
1936 {"a\\b/..", 0, "/"},
1937
1938 {"a/b &c", 0, "a/b &c"},
1939
1940 /* A colon by itself is not interpreted as any sort of scheme. */
1941 {"://../../a", 0, "a"},
1942
1943 /* mk: is another idiosyncratic scheme, although thankfully it behaves
1944 * rather simply. It has no concept of a hostname; if two slashes follow
1945 * the scheme it simply treats them as two empty path elements. */
1946 {"mk:", 0, "mk:"},
1947 {"mk:.", 0, "mk:"},
1948 {"mk:..", 0, "mk:"},
1949 {"mk:/", 0, "mk:/"},
1950 {"mk:/.", 0, "mk:/"},
1951 {"mk:/..", 0, "mk:"},
1952 {"mk:a", 0, "mk:a"},
1953 {"mk:a:", 0, "mk:a:"},
1954 {"mk://", 0, "mk://"},
1955 {"mk://.", 0, "mk://"},
1956 {"mk://..", 0, "mk:/"},
1957 {"mk://../..", 0, "mk:"},
1958 {"mk://../..", URL_DONT_SIMPLIFY, "mk://../.."},
1959 {"mk://../../..", 0, "mk:"},
1960
1961 /* Backslashes are not translated into forward slashes. They are treated
1962 * as path separators, but in a somewhat buggy manner: only dots before
1963 * a forward slash are collapsed, and a double dot rewinds to the
1964 * previous forward slash. */
1965 {"mk:a/.\\", 0, "mk:a/.\\"},
1966 {"mk:a/.\\b", 0, "mk:a/.\\b"},
1967 {"mk:a\\.\\b", 0, "mk:a\\.\\b"},
1968 {"mk:a\\./b", 0, "mk:a\\b"},
1969 {"mk:a./b", 0, "mk:a./b"},
1970 {"mk:a\\b/..\\c", 0, "mk:a\\b/..\\c"},
1971 {"mk:a\\b\\..\\c", 0, "mk:a\\b\\..\\c"},
1972 {"mk:a/b\\../c", 0, "mk:a/c"},
1973 {"mk:a\\b../c", 0, "mk:a\\b../c"},
1974
1975 /* Progids get a forward slash appended if there isn't one already, and
1976 * dots don't rewind past them. Despite the fact that progids are
1977 * supposed to end with a colon, UrlCanonicalize() considers them to
1978 * end with the slash.
1979 *
1980 * If the first path segment is a dot or double dot, it's treated as
1981 * a relative path, like http, but only before a forward slash. */
1982
1983 {"mk:@", 0, "mk:@/"},
1984 {"mk:@progid", 0, "mk:@progid/"},
1985 {"mk:@progid:a", 0, "mk:@progid:a/"},
1986 {"mk:@progid:a/b", 0, "mk:@progid:a/b"},
1987 {"mk:@Progid:a/b/../..", 0, "mk:@Progid:a/"},
1988 {"mk:@progid/a", 0, "mk:@progid/a"},
1989 {"mk:@progid\\a", 0, "mk:@progid\\a/"},
1990 {"mk:@progid/a/../..", 0, "mk:@progid/"},
1991 {"mk:@progid/.", 0, "mk:@progid/."},
1992 {"mk:@progid/.?", 0, "mk:@progid/.?"},
1993 {"mk:@progid/./..", 0, "mk:@progid/./.."},
1994 {"mk:@progid/../..", 0, "mk:@progid/../.."},
1995 {"mk:@progid/a\\.\\b", 0, "mk:@progid/a\\.\\b"},
1996 {"mk:@progid/a\\..\\b", 0, "mk:@progid/a\\..\\b"},
1997 {"mk:@progid/.\\..", 0, "mk:@progid/"},
1998
1999 {"mk:a/b?c/../d", 0, "mk:a/b?c/../d"},
2000 {"mk:a/b#c/../d", 0, "mk:a/b#c/../d"},
2001 {"mk:a/b#c?d", 0, "mk:a/b#c?d"},
2002 {"mk:@progid/a/b?c/../d", 0, "mk:@progid/a/b?c/../d"},
2003 {"mk:@progid?c/d/..", 0, "mk:@progid?c/"},
2004
2005 {"mk:a/b &c", 0, "mk:a/b &c"},
2006
2007 {"mk:@MSITStore:dir/test.chm::/file.html/..", 0, "mk:@MSITStore:dir/test.chm::/"},
2008 {"mk:@MSITStore:dir/test.chm::/file.html/../..", 0, "mk:@MSITStore:dir/"},
2009
2010 /* Whitespace except for plain spaces are stripped before parsing. */
2011 {" \t\n\rwi\t\n\rne\t\n\r:\t\n\r/\t\n\r/\t\n\r./../a/.\t\n\r./ \t\n\r", 0, "wine://./../"},
2012 /* Initial and final spaces and C0 control characters are also stripped,
2013 * but not 007F or C1 control characters. */
2014 {" \a\t\x01 wine://./.. \x1f\n\v ", 0, "wine://./../"},
2015 {" wine ://./..", 0, "wine :/"},
2016 {" wine: //a/../b", 0, "wine: //a/../b"},
2017 {" wine://a/b c/.. ", 0, "wine://a/"},
2018 {"\x7f/\a/\v/\x01/\x1f/\x80", 0, "\x7f/\a/\v/\x01/\x1f/\x80"},
2019
2020 /* Schemes are not case-sensitive, but are flattened to lowercase.
2021 * The hostname for http-like schemes is also flattened to lowercase
2022 * (but not for file; see above). */
2023 {"wInE://A/B", 0, "wine://A/B"},
2024 {"hTtP://A/b/../../C", 0, "http://a/C"},
2025 {"fTP://A/B\\./C", 0, "ftp://a/B\\C"},
2026 {"aBoUT://A/B/./", 0, "about://A/B/./"},
2027 {"mK://..", 0, "mk:/"},
2028
2029 /* Characters allowed in a scheme are alphanumeric, hyphen, plus, period. */
2030 {"0Aa+-.://./..", 0, "0aa+-.://./../"},
2031 {"a_://./..", 0, "a_:/"},
2032 {"a,://./..", 0, "a,:/"},
2033
2034 {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY, "/uri-res/N2R?urn:sha1:B3K"} /* LimeWire online installer calls this */,
2035 {"mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0,
2036 "mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
2037 };
2038
2039 static const DWORD file_flags[] = {0, URL_FILE_USE_PATHURL, URL_WININET_COMPATIBILITY};
2040
2041 urllen = lstrlenA(winehqA);
2042
2043 /* Parameter checks */
2044 dwSize = ARRAY_SIZE(szReturnUrl);
2045 hr = UrlCanonicalizeA(NULL, szReturnUrl, &dwSize, URL_UNESCAPE);
2046 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2047 ok(dwSize == ARRAY_SIZE(szReturnUrl), "got size %lu\n", dwSize);
2048
2049 dwSize = ARRAY_SIZE(szReturnUrl);
2051 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2052 ok(dwSize == ARRAY_SIZE(szReturnUrl), "got size %lu\n", dwSize);
2053
2054 hr = UrlCanonicalizeA(winehqA, szReturnUrl, NULL, URL_UNESCAPE);
2055 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2056
2057 dwSize = 0;
2058 hr = UrlCanonicalizeA(winehqA, szReturnUrl, &dwSize, URL_UNESCAPE);
2059 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2060 ok(!dwSize, "got size %lu\n", dwSize);
2061
2062 /* buffer has no space for the result */
2063 dwSize=urllen-1;
2064 memset(szReturnUrl, '#', urllen+4);
2065 szReturnUrl[urllen+4] = '\0';
2066 SetLastError(0xdeadbeef);
2068 ok( (hr == E_POINTER) && (dwSize == (urllen + 1)),
2069 "got 0x%lx with %lu and size %lu for '%s' and %u (expected 'E_POINTER' and size %lu)\n",
2070 hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), urllen+1);
2071
2072 /* buffer has no space for the terminating '\0' */
2073 dwSize=urllen;
2074 memset(szReturnUrl, '#', urllen+4);
2075 szReturnUrl[urllen+4] = '\0';
2076 SetLastError(0xdeadbeef);
2078 ok( (hr == E_POINTER) && (dwSize == (urllen + 1)),
2079 "got 0x%lx with %lu and size %lu for '%s' and %u (expected 'E_POINTER' and size %lu)\n",
2080 hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), urllen+1);
2081
2082 /* buffer has the required size */
2083 dwSize=urllen+1;
2084 memset(szReturnUrl, '#', urllen+4);
2085 szReturnUrl[urllen+4] = '\0';
2086 SetLastError(0xdeadbeef);
2088 ok( (hr == S_OK) && (dwSize == urllen),
2089 "got 0x%lx with %lu and size %lu for '%s' and %u (expected 'S_OK' and size %lu)\n",
2090 hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), urllen);
2091
2092 /* buffer is larger as the required size */
2093 dwSize=urllen+2;
2094 memset(szReturnUrl, '#', urllen+4);
2095 szReturnUrl[urllen+4] = '\0';
2096 SetLastError(0xdeadbeef);
2098 ok( (hr == S_OK) && (dwSize == urllen),
2099 "got 0x%lx with %lu and size %lu for '%s' and %u (expected 'S_OK' and size %lu)\n",
2100 hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), urllen);
2101
2102 /* length is set to 0 */
2103 dwSize=0;
2104 memset(szReturnUrl, '#', urllen+4);
2105 szReturnUrl[urllen+4] = '\0';
2106 SetLastError(0xdeadbeef);
2108 ok( (hr == E_INVALIDARG) && (dwSize == 0),
2109 "got 0x%lx with %lu and size %lu for '%s' and %u (expected 'E_INVALIDARG' and size %u)\n",
2110 hr, GetLastError(), dwSize, szReturnUrl, lstrlenA(szReturnUrl), 0);
2111
2112 /* url length > INTERNET_MAX_URL_SIZE */
2113 dwSize=sizeof(szReturnUrl);
2114 memset(longurl, 'a', sizeof(longurl));
2115 memcpy(longurl, winehqA, sizeof(winehqA)-1);
2116 longurl[sizeof(longurl)-1] = '\0';
2118 ok(hr == S_OK, "hr = %lx\n", hr);
2119 ok(dwSize == strlen(szReturnUrl), "got size %lu\n", dwSize);
2120
2121 for (f = 0; f < ARRAY_SIZE(file_flags); ++f)
2122 {
2123 for (i = 0; i < ARRAY_SIZE(unk_scheme_tests); ++i)
2124 {
2125 check_url_canonicalize(unk_scheme_tests[i].url,
2126 unk_scheme_tests[i].flags | file_flags[f], unk_scheme_tests[i].expect);
2127 sprintf(url, "wine:%s", unk_scheme_tests[i].url);
2128 sprintf(expect, "wine:%s", unk_scheme_tests[i].expect);
2129 check_url_canonicalize(url, unk_scheme_tests[i].flags | file_flags[f], expect);
2130 }
2131
2132 for (i = 0; i < ARRAY_SIZE(http_tests); ++i)
2133 {
2134 static const struct
2135 {
2136 const char *prefix;
2137 BOOL ftp_like;
2138 }
2139 prefixes[] =
2140 {
2141 {"ftp", TRUE},
2142 {"gopher"},
2143 {"http"},
2144 {"https"},
2145 {"local", TRUE},
2146 {"news"},
2147 {"nntp"},
2148 {"res", TRUE},
2149 {"snews"},
2150 {"telnet"},
2151 {"wais", TRUE},
2152 };
2153
2154 for (j = 0; j < ARRAY_SIZE(prefixes); ++j)
2155 {
2156 sprintf(url, "%s:%s", prefixes[j].prefix, http_tests[i].url);
2157 if (prefixes[j].ftp_like && http_tests[i].expect_ftp)
2158 sprintf(expect, "%s:%s", prefixes[j].prefix, http_tests[i].expect_ftp);
2159 else
2160 sprintf(expect, "%s:%s", prefixes[j].prefix, http_tests[i].expect);
2161
2162 check_url_canonicalize(url, http_tests[i].flags | file_flags[f], expect);
2163 }
2164 }
2165
2166 for (i = 0; i < ARRAY_SIZE(opaque_tests); ++i)
2167 {
2168 static const char *const prefixes[] = {"about", "javascript", "mailto", "shell", "vbscript"};
2169
2170 for (j = 0; j < ARRAY_SIZE(prefixes); ++j)
2171 {
2172 sprintf(url, "%s:%s", prefixes[j], opaque_tests[i].url);
2173 sprintf(expect, "%s:%s", prefixes[j], opaque_tests[i].expect);
2174 check_url_canonicalize(url, opaque_tests[i].flags | file_flags[f], expect);
2175 }
2176 }
2177
2178 for (i = 0; i < ARRAY_SIZE(misc_tests); i++)
2179 check_url_canonicalize(misc_tests[i].url, misc_tests[i].flags | file_flags[f], misc_tests[i].expect);
2180 }
2181
2182 for (i = 0; i < ARRAY_SIZE(file_tests); i++)
2183 check_url_canonicalize(file_tests[i].url, file_tests[i].flags, file_tests[i].expect);
2184}
2185
2186/* ########################### */
2187
2188static void test_UrlCanonicalizeW(void)
2189{
2190 WCHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
2191 DWORD dwSize;
2192 DWORD urllen;
2193 HRESULT hr;
2194 int i;
2195
2196 urllen = lstrlenW(winehqW);
2197
2198 /* Parameter checks */
2199 dwSize = ARRAY_SIZE(szReturnUrl);
2200 hr = UrlCanonicalizeW(NULL, szReturnUrl, &dwSize, URL_UNESCAPE);
2201 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2202 ok(dwSize == ARRAY_SIZE(szReturnUrl), "got size %lu\n", dwSize);
2203
2204 dwSize = ARRAY_SIZE(szReturnUrl);
2206 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2207 ok(dwSize == ARRAY_SIZE(szReturnUrl), "got size %lu\n", dwSize);
2208
2209 hr = UrlCanonicalizeW(winehqW, szReturnUrl, NULL, URL_UNESCAPE);
2210 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2211
2212 dwSize = 0;
2213 hr = UrlCanonicalizeW(winehqW, szReturnUrl, &dwSize, URL_UNESCAPE);
2214 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
2215 ok(!dwSize, "got size %lu\n", dwSize);
2216
2217 /* buffer has no space for the result */
2218 dwSize = (urllen-1);
2219 memset(szReturnUrl, '#', (urllen+4) * sizeof(WCHAR));
2220 szReturnUrl[urllen+4] = '\0';
2221 SetLastError(0xdeadbeef);
2223 ok( (hr == E_POINTER) && (dwSize == (urllen + 1)),
2224 "got 0x%lx with %lu and size %lu for %u (expected 'E_POINTER' and size %lu)\n",
2225 hr, GetLastError(), dwSize, lstrlenW(szReturnUrl), urllen+1);
2226
2227
2228 /* buffer has no space for the terminating '\0' */
2229 dwSize = urllen;
2230 memset(szReturnUrl, '#', (urllen+4) * sizeof(WCHAR));
2231 szReturnUrl[urllen+4] = '\0';
2232 SetLastError(0xdeadbeef);
2234 ok( (hr == E_POINTER) && (dwSize == (urllen + 1)),
2235 "got 0x%lx with %lu and size %lu for %u (expected 'E_POINTER' and size %lu)\n",
2236 hr, GetLastError(), dwSize, lstrlenW(szReturnUrl), urllen+1);
2237
2238 /* buffer has the required size */
2239 dwSize = urllen +1;
2240 memset(szReturnUrl, '#', (urllen+4) * sizeof(WCHAR));
2241 szReturnUrl[urllen+4] = '\0';
2242 SetLastError(0xdeadbeef);
2244 ok( (hr == S_OK) && (dwSize == urllen),
2245 "got 0x%lx with %lu and size %lu for %u (expected 'S_OK' and size %lu)\n",
2246 hr, GetLastError(), dwSize, lstrlenW(szReturnUrl), urllen);
2247
2248 /* buffer is larger as the required size */
2249 dwSize = (urllen+2);
2250 memset(szReturnUrl, '#', (urllen+4) * sizeof(WCHAR));
2251 szReturnUrl[urllen+4] = '\0';
2252 SetLastError(0xdeadbeef);
2254 ok( (hr == S_OK) && (dwSize == urllen),
2255 "got 0x%lx with %lu and size %lu for %u (expected 'S_OK' and size %lu)\n",
2256 hr, GetLastError(), dwSize, lstrlenW(szReturnUrl), urllen);
2257
2258 /* Only ASCII alphanumeric characters are allowed in a scheme. */
2259 dwSize = ARRAY_SIZE(szReturnUrl);
2260 hr = UrlCanonicalizeW(L"f\xe8ve://./..", szReturnUrl, &dwSize, 0);
2261 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2262 ok(!wcscmp(szReturnUrl, L"f\xe8ve:/"), "Got URL %s.\n", debugstr_w(szReturnUrl));
2263 ok(dwSize == wcslen(szReturnUrl), "got size %lu\n", dwSize);
2264
2265 /* check that the characters 1..32 are chopped from the end of the string */
2266 for (i = 1; i < 65536; i++)
2267 {
2268 WCHAR szUrl[128];
2269 BOOL choped;
2270 int pos;
2271
2272 wcscpy(szUrl, L"http://www.winehq.org/X");
2273 pos = lstrlenW(szUrl) - 1;
2274 szUrl[pos] = i;
2275 urllen = INTERNET_MAX_URL_LENGTH;
2276 UrlCanonicalizeW(szUrl, szReturnUrl, &urllen, 0);
2277 choped = lstrlenW(szReturnUrl) < lstrlenW(szUrl);
2278 ok(choped == (i <= 32), "Incorrect char chopping for char %d\n", i);
2279 }
2280}
2281
2282/* ########################### */
2283
2284static void check_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, const char *szExpectUrl)
2285{
2286 HRESULT hr;
2287 CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
2288 WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
2289 LPWSTR wszUrl1, wszUrl2, wszExpectUrl, wszConvertedUrl;
2290
2291 DWORD dwSize;
2292 DWORD dwExpectLen = lstrlenA(szExpectUrl);
2293
2294 wszUrl1 = GetWideString(szUrl1);
2295 wszUrl2 = GetWideString(szUrl2);
2296 wszExpectUrl = GetWideString(szExpectUrl);
2297
2298 dwSize = ARRAY_SIZE(szReturnUrl);
2299 hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
2300 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2301 ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
2302 ok(!strcmp(szReturnUrl, szExpectUrl), "Expected %s, got %s.\n", szExpectUrl, szReturnUrl);
2303
2304 dwSize = ARRAY_SIZE(wszReturnUrl);
2305 hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
2306 ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
2307 ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
2308 wszConvertedUrl = GetWideString(szReturnUrl);
2309 ok(!wcscmp(wszReturnUrl, wszConvertedUrl), "Expected %s, got %s.\n",
2310 debugstr_w(wszConvertedUrl), debugstr_w(wszReturnUrl));
2311 FreeWideString(wszConvertedUrl);
2312
2313 FreeWideString(wszUrl1);
2314 FreeWideString(wszUrl2);
2315 FreeWideString(wszExpectUrl);
2316}
2317
2318/* ########################### */
2319
2320static void test_UrlCombine(void)
2321{
2322 WCHAR bufferW[30];
2323 char buffer[30];
2324 unsigned int i;
2325 HRESULT hr;
2326 DWORD size;
2327
2328 hr = UrlCombineA("http://base/", "relative", NULL, NULL, 0);
2329 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
2330
2331 size = 0;
2332 hr = UrlCombineA("http://base/", "relative", NULL, &size, 0);
2333 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2334 ok(size == strlen("http://base/relative") + 1, "Got size %lu.\n", size);
2335
2336 --size;
2337 strcpy(buffer, "x");
2338 hr = UrlCombineA("http://base/", "relative", buffer, &size, 0);
2339 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2340 ok(size == strlen("http://base/relative") + 1, "Got size %lu.\n", size);
2341 ok(!strcmp(buffer, "x"), "Got buffer contents %s.\n", debugstr_a(buffer));
2342
2343 strcpy(buffer, "x");
2344 hr = UrlCombineA("http://base/", "relative", buffer, &size, 0);
2345 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2346 ok(size == strlen("http://base/relative"), "Got size %lu.\n", size);
2347 ok(!strcmp(buffer, "http://base/relative"), "Got buffer contents %s.\n", debugstr_a(buffer));
2348
2349 hr = UrlCombineW(L"http://base/", L"relative", NULL, NULL, 0);
2350 ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
2351
2352 size = 0;
2353 hr = UrlCombineW(L"http://base/", L"relative", NULL, &size, 0);
2354 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2355 ok(size == strlen("http://base/relative") + 1, "Got size %lu.\n", size);
2356
2357 --size;
2358 wcscpy(bufferW, L"x");
2359 hr = UrlCombineW(L"http://base/", L"relative", bufferW, &size, 0);
2360 ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
2361 ok(size == strlen("http://base/relative") + 1, "Got size %lu.\n", size);
2362 ok(!wcscmp(bufferW, L"x"), "Got buffer contents %s.\n", debugstr_a(buffer));
2363
2364 wcscpy(bufferW, L"x");
2365 hr = UrlCombineW(L"http://base/", L"relative", bufferW, &size, 0);
2366 ok(hr == S_OK, "Got hr %#lx.\n", hr);
2367 ok(size == strlen("http://base/relative"), "Got size %lu.\n", size);
2368 ok(!wcscmp(bufferW, L"http://base/relative"), "Got buffer contents %s.\n", debugstr_w(bufferW));
2369
2370 for (i = 0; i < ARRAY_SIZE(TEST_COMBINE); i++) {
2372 }
2373}
2374
2375/* ########################### */
2376
2377static void test_UrlCreateFromPath(void)
2378{
2379 size_t i;
2380 char ret_url[INTERNET_MAX_URL_LENGTH];
2381 DWORD len, ret;
2383 WCHAR *pathW, *urlW;
2384
2385 for (i = 0; i < ARRAY_SIZE(TEST_URLFROMPATH); i++) {
2387 ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
2388 ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path %s\n", ret, TEST_URLFROMPATH[i].path);
2389 ok(!lstrcmpiA(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
2390 ok(len == strlen(ret_url), "ret len %ld from path %s\n", len, TEST_URLFROMPATH[i].path);
2391
2395 ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
2396 WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
2397 ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path L\"%s\", expected %08lx\n",
2399 ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n",
2401 ok(len == lstrlenW(ret_urlW), "ret len %ld from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
2402 FreeWideString(urlW);
2403 FreeWideString(pathW);
2404 }
2405}
2406
2407/* ########################### */
2408
2410{
2411 BOOL ret;
2412 ret = UrlIsA(NULL, flag);
2413 ok(ret == FALSE, "pUrlIsA(NULL, %ld) failed\n", flag);
2414 ret = UrlIsW(NULL, flag);
2415 ok(ret == FALSE, "pUrlIsW(NULL, %ld) failed\n", flag);
2416}
2417
2418static void test_UrlIs(void)
2419{
2420 BOOL ret;
2421 size_t i;
2422 WCHAR wurl[80];
2423
2431
2432 for (i = 0; i < ARRAY_SIZE(TEST_PATH_IS_URL); i++) {
2434
2437 "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
2439
2440 ret = UrlIsW( wurl, URLIS_URL );
2442 "returned %d from path (UrlIsW) %s, expected %d\n", ret,
2444 }
2445 for (i = 0; i < ARRAY_SIZE(TEST_URLIS_ATTRIBS); i++) {
2447
2450 "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
2454 "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
2456
2457 ret = UrlIsW( wurl, URLIS_OPAQUE);
2459 "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n",
2461 ret = UrlIsW( wurl, URLIS_FILEURL);
2463 "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n",
2465 }
2466}
2467
2468/* ########################### */
2469
2470static void test_UrlUnescape(void)
2471{
2473 CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
2474 DWORD dwEscaped, unescaped;
2475 BOOL utf8_support = TRUE;
2476 static char inplace[] = "file:///C:/Program%20Files";
2477 static char another_inplace[] = "file:///C:/Program%20Files";
2478 static const char expected[] = "file:///C:/Program Files";
2479 HRESULT res;
2480 int i;
2481
2482 for (i = 0; i < ARRAY_SIZE(TEST_URL_UNESCAPE); i++) {
2483 dwEscaped=INTERNET_MAX_URL_LENGTH;
2484 res = UrlUnescapeA(TEST_URL_UNESCAPE[i].url, szReturnUrl, &dwEscaped, 0);
2485 ok(res == S_OK,
2486 "UrlUnescapeA returned 0x%lx (expected S_OK) for \"%s\"\n",
2488 ok(strcmp(szReturnUrl,TEST_URL_UNESCAPE[i].expect)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", TEST_URL_UNESCAPE[i].expect, szReturnUrl, TEST_URL_UNESCAPE[i].url);
2489
2490 ZeroMemory(szReturnUrl, sizeof(szReturnUrl));
2491 /* if we set the buffer pointer to NULL here, UrlUnescape fails and the string is not converted */
2492 res = UrlUnescapeA(TEST_URL_UNESCAPE[i].url, szReturnUrl, NULL, 0);
2493 ok(res == E_INVALIDARG,
2494 "UrlUnescapeA returned 0x%lx (expected E_INVALIDARG) for \"%s\"\n",
2496 ok(strcmp(szReturnUrl,"")==0, "Expected empty string\n");
2497 }
2498
2499 unescaped = INTERNET_MAX_URL_LENGTH;
2500 lstrcpyW(urlW, L"%F0%9F%8D%B7");
2502 ok(res == S_OK, "Got %#lx.\n", res);
2503 if (!wcscmp(urlW, L"\xf0\x9f\x8d\xb7"))
2504 {
2505 utf8_support = FALSE;
2506 win_skip("Skip URL_UNESCAPE_AS_UTF8 tests for pre-win7 systems.\n");
2507 }
2508
2509 for (i = 0; i < ARRAYSIZE(TEST_URL_UNESCAPEW); i++)
2510 {
2511 if (TEST_URL_UNESCAPEW[i].flags & URL_UNESCAPE_AS_UTF8 && !utf8_support)
2512 continue;
2513
2515
2516 memset(bufferW, 0xff, sizeof(bufferW));
2517 unescaped = INTERNET_MAX_URL_LENGTH;
2518 res = UrlUnescapeW(urlW, bufferW, &unescaped, TEST_URL_UNESCAPEW[i].flags);
2519 ok(res == S_OK, "[%d]: returned %#lx.\n", i, res);
2520 ok(unescaped == wcslen(TEST_URL_UNESCAPEW[i].expect), "[%d]: got unescaped %ld.\n", i, unescaped);
2521 ok(!wcscmp(bufferW, TEST_URL_UNESCAPEW[i].expect), "[%d]: got result %s.\n", i, debugstr_w(bufferW));
2522
2523 /* Test with URL_UNESCAPE_INPLACE */
2524 unescaped = INTERNET_MAX_URL_LENGTH;
2526 ok(res == S_OK, "[%d]: returned %#lx.\n", i, res);
2527 ok(unescaped == INTERNET_MAX_URL_LENGTH, "[%d]: got unescaped %ld.\n", i, unescaped);
2528 ok(!wcscmp(urlW, TEST_URL_UNESCAPEW[i].expect), "[%d]: got result %s.\n", i, debugstr_w(urlW));
2529
2531 unescaped = wcslen(TEST_URL_UNESCAPEW[i].expect) - 1;
2532 res = UrlUnescapeW(urlW, bufferW, &unescaped, TEST_URL_UNESCAPEW[i].flags);
2533 ok(res == E_POINTER, "[%d]: returned %#lx.\n", i, res);
2534 }
2535
2536 dwEscaped = sizeof(inplace);
2537 res = UrlUnescapeA(inplace, NULL, &dwEscaped, URL_UNESCAPE_INPLACE);
2538 ok(res == S_OK, "UrlUnescapeA returned 0x%lx (expected S_OK)\n", res);
2539 ok(!strcmp(inplace, expected), "got %s expected %s\n", inplace, expected);
2540 ok(dwEscaped == 27, "got %ld expected 27\n", dwEscaped);
2541
2542 /* if we set the buffer pointer to NULL, the string apparently still gets converted (Google Lively does this) */
2543 res = UrlUnescapeA(another_inplace, NULL, NULL, URL_UNESCAPE_INPLACE);
2544 ok(res == S_OK, "UrlUnescapeA returned 0x%lx (expected S_OK)\n", res);
2545 ok(!strcmp(another_inplace, expected), "got %s expected %s\n", another_inplace, expected);
2546}
2547
2548static const struct parse_url_test_t {
2549 const char *url;
2553} parse_url_tests[] = {
2554 {"http://www.winehq.org/",S_OK,4,URL_SCHEME_HTTP},
2555 {"https://www.winehq.org/",S_OK,5,URL_SCHEME_HTTPS},
2556 {"ftp://www.winehq.org/",S_OK,3,URL_SCHEME_FTP},
2557 {"test.txt?test=c:/dir",URL_E_INVALID_SYNTAX},
2558 {"test.txt",URL_E_INVALID_SYNTAX},
2559 {"xxx://www.winehq.org/",S_OK,3,URL_SCHEME_UNKNOWN},
2560 {"1xx://www.winehq.org/",S_OK,3,URL_SCHEME_UNKNOWN},
2561 {"-xx://www.winehq.org/",S_OK,3,URL_SCHEME_UNKNOWN},
2562 {"xx0://www.winehq.org/",S_OK,3,URL_SCHEME_UNKNOWN},
2563 {"x://www.winehq.org/",URL_E_INVALID_SYNTAX},
2564 {"xx$://www.winehq.org/",URL_E_INVALID_SYNTAX},
2565 {"htt?p://www.winehq.org/",URL_E_INVALID_SYNTAX},
2566 {"ab-://www.winehq.org/",S_OK,3,URL_SCHEME_UNKNOWN},
2567 {" http://www.winehq.org/",URL_E_INVALID_SYNTAX},
2568 {"HTTP://www.winehq.org/",S_OK,4,URL_SCHEME_HTTP},
2569 {"a+-.://www.winehq.org/",S_OK,4,URL_SCHEME_UNKNOWN},
2571
2572static void test_ParseURL(void)
2573{
2574 const struct parse_url_test_t *test;
2576 PARSEDURLA parseda;
2577 PARSEDURLW parsedw;
2578 HRESULT hres;
2579
2581 memset(&parseda, 0xd0, sizeof(parseda));
2582 parseda.cbSize = sizeof(parseda);
2583 hres = ParseURLA(test->url, &parseda);
2584 ok(hres == test->hres, "ParseURL failed: %08lx, expected %08lx\n", hres, test->hres);
2585 if(hres == S_OK) {
2586 ok(parseda.pszProtocol == test->url, "parseda.pszProtocol = %s, expected %s\n",
2587 parseda.pszProtocol, test->url);
2588 ok(parseda.cchProtocol == test->protocol_len, "parseda.cchProtocol = %d, expected %d\n",
2589 parseda.cchProtocol, test->protocol_len);
2590 ok(parseda.pszSuffix == test->url+test->protocol_len+1, "parseda.pszSuffix = %s, expected %s\n",
2591 parseda.pszSuffix, test->url+test->protocol_len+1);
2592 ok(parseda.cchSuffix == strlen(test->url+test->protocol_len+1),
2593 "parseda.pszSuffix = %d, expected %d\n",
2594 parseda.cchSuffix, lstrlenA(test->url+test->protocol_len+1));
2595 ok(parseda.nScheme == test->scheme, "parseda.nScheme = %d, expected %d\n",
2596 parseda.nScheme, test->scheme);
2597 }else {
2598 ok(!parseda.pszProtocol, "parseda.pszProtocol = %p\n", parseda.pszProtocol);
2599 ok(parseda.nScheme == 0xd0d0d0d0, "nScheme = %d\n", parseda.nScheme);
2600 }
2601
2603
2604 memset(&parsedw, 0xd0, sizeof(parsedw));
2605 parsedw.cbSize = sizeof(parsedw);
2606 hres = ParseURLW(url, &parsedw);
2607 ok(hres == test->hres, "ParseURL failed: %08lx, expected %08lx\n", hres, test->hres);
2608 if(hres == S_OK) {
2609 ok(parsedw.pszProtocol == url, "parsedw.pszProtocol = %s, expected %s\n",
2611 ok(parsedw.cchProtocol == test->protocol_len, "parsedw.cchProtocol = %d, expected %d\n",
2612 parsedw.cchProtocol, test->protocol_len);
2613 ok(parsedw.pszSuffix == url+test->protocol_len+1, "parsedw.pszSuffix = %s, expected %s\n",
2614 wine_dbgstr_w(parsedw.pszSuffix), wine_dbgstr_w(url+test->protocol_len+1));
2615 ok(parsedw.cchSuffix == strlen(test->url+test->protocol_len+1),
2616 "parsedw.pszSuffix = %d, expected %d\n",
2617 parsedw.cchSuffix, lstrlenA(test->url+test->protocol_len+1));
2618 ok(parsedw.nScheme == test->scheme, "parsedw.nScheme = %d, expected %d\n",
2619 parsedw.nScheme, test->scheme);
2620 }else {
2621 ok(!parsedw.pszProtocol, "parsedw.pszProtocol = %p\n", parseda.pszProtocol);
2622 ok(parsedw.nScheme == 0xd0d0d0d0, "nScheme = %d\n", parsedw.nScheme);
2623 }
2624 }
2625}
2626
2627static void test_HashData(void)
2628{
2629 HRESULT res;
2630 BYTE input[16] = {0x51, 0x33, 0x4F, 0xA7, 0x45, 0x15, 0xF0, 0x52, 0x90,
2631 0x2B, 0xE7, 0xF5, 0xFD, 0xE1, 0xA6, 0xA7};
2632 BYTE output[32];
2633 static const BYTE expected[] = {0x54, 0x9C, 0x92, 0x55, 0xCD, 0x82, 0xFF,
2634 0xA1, 0x8E, 0x0F, 0xCF, 0x93, 0x14, 0xAA,
2635 0xE3, 0x2D};
2636 static const BYTE expected2[] = {0x54, 0x9C, 0x92, 0x55, 0xCD, 0x82, 0xFF,
2637 0xA1, 0x8E, 0x0F, 0xCF, 0x93, 0x14, 0xAA,
2638 0xE3, 0x2D, 0x47, 0xFC, 0x80, 0xB8, 0xD0,
2639 0x49, 0xE6, 0x13, 0x2A, 0x30, 0x51, 0x8D,
2640 0xF9, 0x4B, 0x07, 0xA6};
2641 static const BYTE expected3[] = {0x2B, 0xDC, 0x9A, 0x1B, 0xF0, 0x5A, 0xF9,
2642 0xC6, 0xBE, 0x94, 0x6D, 0xF3, 0x33, 0xC1,
2643 0x36, 0x07};
2644 int i;
2645
2646 /* Test hashing with identically sized input/output buffers. */
2647 res = HashData(input, 16, output, 16);
2648 ok(res == S_OK, "Expected HashData to return S_OK, got 0x%08lx\n", res);
2649 ok(!memcmp(output, expected, sizeof(expected)), "data didn't match\n");
2650
2651 /* Test hashing with larger output buffer. */
2652 res = HashData(input, 16, output, 32);
2653 ok(res == S_OK, "Expected HashData to return S_OK, got 0x%08lx\n", res);
2654 ok(!memcmp(output, expected2, sizeof(expected2)), "data didn't match\n");
2655
2656 /* Test hashing with smaller input buffer. */
2657 res = HashData(input, 8, output, 16);
2658 ok(res == S_OK, "Expected HashData to return S_OK, got 0x%08lx\n", res);
2659 ok(!memcmp(output, expected3, sizeof(expected3)), "data didn't match\n");
2660
2661 /* Test passing NULL pointers for input/output parameters. */
2662 res = HashData(NULL, 0, NULL, 0);
2663 ok(res == E_INVALIDARG, "Got unexpected hr %#lx.\n", res);
2664
2665 res = HashData(input, 0, NULL, 0);
2666 ok(res == E_INVALIDARG, "Got unexpected hr %#lx.\n", res);
2667
2668 res = HashData(NULL, 0, output, 0);
2669 ok(res == E_INVALIDARG, "Got unexpected hr %#lx.\n", res);
2670
2671 /* Test passing valid pointers with sizes of zero. */
2672 for (i = 0; i < ARRAY_SIZE(input); i++)
2673 input[i] = 0x00;
2674
2675 for (i = 0; i < ARRAY_SIZE(output); i++)
2676 output[i] = 0xFF;
2677
2678 res = HashData(input, 0, output, 0);
2679 ok(res == S_OK, "Expected HashData to return S_OK, got 0x%08lx\n", res);
2680
2681 /* The buffers should be unchanged. */
2682 for (i = 0; i < ARRAY_SIZE(input); i++)
2683 ok(input[i] == 0x00, "Expected the input buffer to be unchanged\n");
2684
2685 for (i = 0; i < ARRAY_SIZE(output); i++)
2686 ok(output[i] == 0xFF, "Expected the output buffer to be unchanged\n");
2687
2688 /* Input/output parameters are not validated. */
2689 res = HashData((BYTE *)0xdeadbeef, 0, (BYTE *)0xdeadbeef, 0);
2690 ok(res == S_OK, "Expected HashData to return S_OK, got 0x%08lx\n", res);
2691
2692 if (0)
2693 {
2694 res = HashData((BYTE *)0xdeadbeef, 1, (BYTE *)0xdeadbeef, 1);
2695 trace("HashData returned 0x%08lx\n", res);
2696 }
2697}
2698
2699/* ########################### */
2700
2702{
2704 test_UrlHash();
2712 test_UrlIs();
2714 test_ParseURL();
2715 test_HashData();
2716}
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
#define ARRAY_SIZE(A)
Definition: main.h:20
wcscpy
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define GetProcessHeap()
Definition: compat.h:736
#define CP_ACP
Definition: compat.h:109
#define SetLastError(x)
Definition: compat.h:752
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define lstrlenW
Definition: compat.h:750
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4246
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4198
int WINAPI lstrcmpiW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4265
int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4227
DWORD WINAPI GetVersion(void)
Definition: version.c:1458
HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, LPWSTR pszCombined, LPDWORD pcchCombined, DWORD dwFlags)
Definition: url.c:662
HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwPart, DWORD dwFlags)
Definition: url.c:2269
HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
Definition: url.c:1616
BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis)
Definition: url.c:1880
HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
Definition: url.c:1662
HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y)
Definition: url.c:197
HRESULT WINAPI UrlUnescapeW(LPWSTR pszUrl, LPWSTR pszUnescaped, LPDWORD pcchUnescaped, DWORD dwFlags)
Definition: url.c:1367
HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y)
Definition: url.c:161
BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis)
Definition: url.c:1933
HRESULT WINAPI HashData(const unsigned char *lpSrc, DWORD nSrcLen, unsigned char *lpDest, DWORD nDestLen)
Definition: url.c:1575
HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
Definition: url.c:2497
HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen)
Definition: url.c:1630
HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved)
Definition: url.c:2452
HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwPart, DWORD dwFlags)
Definition: url.c:2229
HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, LPDWORD pcchCanonicalized, DWORD dwFlags)
Definition: url.c:282
HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags)
Definition: url.c:1817
HRESULT WINAPI UrlUnescapeA(LPSTR pszUrl, LPSTR pszUnescaped, LPDWORD pcchUnescaped, DWORD dwFlags)
Definition: url.c:1298
HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative, LPSTR pszCombined, LPDWORD pcchCombined, DWORD dwFlags)
Definition: url.c:614
HRESULT WINAPI UrlEscapeA(LPCSTR pszUrl, LPSTR pszEscaped, LPDWORD pcchEscaped, DWORD dwFlags)
Definition: url.c:950
HRESULT WINAPI UrlEscapeW(LPCWSTR pszUrl, LPWSTR pszEscaped, LPDWORD pcchEscaped, DWORD dwFlags)
Definition: url.c:1076
HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, LPDWORD pcchCanonicalized, DWORD dwFlags)
Definition: url.c:247
#define INTERNET_MAX_URL_LENGTH
Definition: session.c:1418
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint res
Definition: glext.h:9613
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLfloat f
Definition: glext.h:7540
GLbitfield flags
Definition: glext.h:7161
GLenum GLsizei len
Definition: glext.h:6722
GLenum GLenum GLenum input
Definition: glext.h:9031
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean flag
Definition: glfuncs.h:52
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
static int prefixes
Definition: i386-dis.c:276
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define URL_E_INVALID_SYNTAX
Definition: intshcut.h:32
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
#define f
Definition: ke_i.h:83
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
LPSTR WINAPI lstrcpyA(LPSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:100
int WINAPI lstrlenA(LPCSTR lpString)
Definition: lstring.c:145
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl winetest_push_context(const char *fmt,...) __WINE_PRINTF_ATTR(1
#define win_skip
Definition: minitest.h:67
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl void winetest_pop_context(void)
#define ZeroMemory
Definition: minwinbase.h:31
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
static struct test_info tests[]
#define sprintf
Definition: sprintf.c:45
static const WCHAR url[]
Definition: encode.c:1384
BOOL expected
Definition: store.c:2000
HRESULT hres
Definition: protocol.c:465
static void test_UrlCombine(void)
Definition: url.c:2320
static void test_UrlEscapeW(void)
Definition: url.c:883
static void test_HashData(void)
Definition: url.c:2627
static const char * TEST_URL_3
Definition: url.c:35
DWORD flags
Definition: url.c:297
static const TEST_URL_ESCAPEW TEST_ESCAPEW[]
Definition: url.c:173
static void test_ParseURL(void)
Definition: url.c:2572
static void test_UrlHash(void)
Definition: url.c:491
struct _TEST_URL_COMBINE TEST_URL_COMBINE
static const CHAR untouchedA[]
Definition: url.c:39
const char * path
Definition: url.c:267
static void test_UrlCanonicalizeA(void)
Definition: url.c:993
static void check_url_canonicalize(const char *url, DWORD flags, const char *expect)
Definition: url.c:793
static struct @1841 TEST_URL_UNESCAPE[]
static const WCHAR winehqW[]
Definition: url.c:37
static struct @1842 TEST_URL_UNESCAPEW[]
struct _TEST_URL_ESCAPE TEST_URL_ESCAPE
static const struct @1840 TEST_URLFROMPATH[]
static LPWSTR GetWideString(const char *szString)
Definition: url.c:376
static const TEST_URL_COMBINE TEST_COMBINE[]
Definition: url.c:199
static const TEST_URL_APPLY TEST_APPLY[]
Definition: url.c:48
static void hash_url(const char *szUrl)
Definition: url.c:473
static void test_UrlIs(void)
Definition: url.c:2418
struct _TEST_URL_APPLY TEST_URL_APPLY
static const TEST_URL_ESCAPE TEST_ESCAPE[]
Definition: url.c:83
static const struct @1843 TEST_PATH_IS_URL[]
static void test_UrlEscapeA(void)
Definition: url.c:827
static const struct @1844 TEST_URLIS_ATTRIBS[]
static void test_UrlUnescape(void)
Definition: url.c:2470
static const char winehqA[]
Definition: url.c:38
static const char * TEST_URL_2
Definition: url.c:34
static void FreeWideString(LPWSTR wszString)
Definition: url.c:386
struct _TEST_URL_ESCAPEW TEST_URL_ESCAPEW
BOOL expectFile
Definition: url.c:344
static void test_UrlCanonicalizeW(void)
Definition: url.c:2188
static void test_UrlApplyScheme(void)
Definition: url.c:393
static void test_UrlGetPart(void)
Definition: url.c:498
BOOL expectOpaque
Definition: url.c:343
const char * expect
Definition: url.c:286
static const char * TEST_URL_1
Definition: url.c:33
static const struct parse_url_test_t parse_url_tests[]
static void test_UrlCreateFromPath(void)
Definition: url.c:2377
static void test_UrlIs_null(DWORD flag)
Definition: url.c:2409
static void check_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, const char *szExpectUrl)
Definition: url.c:2284
static const WCHAR url1[]
Definition: misc.c:300
static const WCHAR url2[]
Definition: misc.c:302
unsigned int UINT
Definition: ndis.h:50
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
#define DWORD
Definition: nt_native.h:44
#define LOWORD(l)
Definition: pedump.c:82
@ URLIS_NOHISTORY
Definition: shlwapi.h:599
@ URLIS_OPAQUE
Definition: shlwapi.h:598
@ URLIS_APPLIABLE
Definition: shlwapi.h:601
@ URLIS_DIRECTORY
Definition: shlwapi.h:602
@ URLIS_FILEURL
Definition: shlwapi.h:600
@ URLIS_URL
Definition: shlwapi.h:597
@ URLIS_HASQUERY
Definition: shlwapi.h:603
#define URL_ESCAPE_UNSAFE
Definition: shlwapi.h:533
@ URL_SCHEME_UNKNOWN
Definition: shlwapi.h:544
@ URL_SCHEME_HTTPS
Definition: shlwapi.h:555
@ URL_SCHEME_FTP
Definition: shlwapi.h:545
@ URL_SCHEME_HTTP
Definition: shlwapi.h:546
#define URL_WININET_COMPATIBILITY
Definition: shlwapi.h:535
@ URL_PART_SCHEME
Definition: shlwapi.h:586
@ URL_PART_QUERY
Definition: shlwapi.h:591
@ URL_PART_HOSTNAME
Definition: shlwapi.h:587
@ URL_PART_USERNAME
Definition: shlwapi.h:588
@ URL_PART_PORT
Definition: shlwapi.h:590
@ URL_PART_PASSWORD
Definition: shlwapi.h:589
#define URL_DONT_ESCAPE_EXTRA_INFO
Definition: shlwapi.h:529
#define URL_UNESCAPE
Definition: shlwapi.h:532
#define URL_UNESCAPE_AS_UTF8
Definition: shlwapi.h:536
#define URL_APPLY_FORCEAPPLY
Definition: shlwapi.h:520
#define URL_ESCAPE_AS_UTF8
Definition: shlwapi.h:524
#define URL_APPLY_GUESSSCHEME
Definition: shlwapi.h:518
#define URL_APPLY_DEFAULT
Definition: shlwapi.h:517
#define URL_PLUGGABLE_PROTOCOL
Definition: shlwapi.h:534
#define URL_ESCAPE_SPACES_ONLY
Definition: shlwapi.h:530
#define URL_ESCAPE_SEGMENT_ONLY
Definition: shlwapi.h:522
#define URL_DONT_SIMPLIFY
Definition: shlwapi.h:531
#define URL_UNESCAPE_INPLACE
Definition: shlwapi.h:525
#define URL_FILE_USE_PATHURL
Definition: shlwapi.h:523
#define URL_PARTFLAG_KEEPSCHEME
Definition: shlwapi.h:594
#define URL_APPLY_GUESSFILE
Definition: shlwapi.h:519
#define URL_ESCAPE_PERCENT
Definition: shlwapi.h:521
#define test
Definition: rosglue.h:37
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
strcpy
Definition: string.h:131
#define memset(x, y, z)
Definition: compat.h:39
HRESULT hr
Definition: shlfolder.c:183
const char * url
Definition: url.c:42
DWORD flags
Definition: url.c:43
HRESULT res
Definition: url.c:44
const char * newurl
Definition: url.c:45
const char * url1
Definition: url.c:193
const char * expecturl
Definition: url.c:196
DWORD flags
Definition: url.c:195
const char * url2
Definition: url.c:194
const WCHAR url[INTERNET_MAX_URL_LENGTH]
Definition: url.c:167
const WCHAR win7url[INTERNET_MAX_URL_LENGTH]
Definition: url.c:170
DWORD flags
Definition: url.c:168
const WCHAR expecturl[INTERNET_MAX_URL_LENGTH]
Definition: url.c:169
const char * expecturl
Definition: url.c:80
const char * url
Definition: url.c:78
DWORD flags
Definition: url.c:79
const char * expect
Definition: url.c:990
DWORD flags
Definition: url.c:989
const char * url
Definition: url.c:988
UINT protocol_len
Definition: url.c:2551
UINT scheme
Definition: url.c:2552
const char * url
Definition: url.c:2549
HRESULT hres
Definition: url.c:2550
UINT nScheme
Definition: shlwapi.h:612
UINT cchSuffix
Definition: shlwapi.h:611
LPCSTR pszSuffix
Definition: shlwapi.h:610
UINT cchProtocol
Definition: shlwapi.h:609
DWORD cbSize
Definition: shlwapi.h:607
LPCSTR pszProtocol
Definition: shlwapi.h:608
UINT cchProtocol
Definition: shlwapi.h:618
LPCWSTR pszSuffix
Definition: shlwapi.h:619
DWORD cbSize
Definition: shlwapi.h:616
UINT nScheme
Definition: shlwapi.h:621
UINT cchSuffix
Definition: shlwapi.h:620
LPCWSTR pszProtocol
Definition: shlwapi.h:617
Character const *const prefix
Definition: tempnam.cpp:195
unsigned char * LPBYTE
Definition: typedefs.h:53
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define S_FALSE
Definition: winerror.h:3451
#define E_POINTER
Definition: winerror.h:3480
const char * newurl
Definition: shdocvw.c:51
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193