[SHLWAPI_WINETEST]
[reactos.git] / rostests / winetests / shlwapi / path.c
1 /* Unit test suite for Path functions
2 *
3 * Copyright 2002 Matthew Mastracci
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #define WIN32_NO_STATUS
21 #define _INC_WINDOWS
22 #define COM_NO_WINDOWS_H
23
24 //#include <stdarg.h>
25 #include <stdio.h>
26
27 #include <wine/test.h>
28 //#include "windef.h"
29 //#include "winbase.h"
30 #include <winreg.h>
31 #include <winnls.h>
32 #include <shlwapi.h>
33 #include <wininet.h>
34
35 static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD);
36 static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD);
37 static LPWSTR (WINAPI *pPathCombineW)(LPWSTR, LPCWSTR, LPCWSTR);
38 static HRESULT (WINAPI *pPathCreateFromUrlA)(LPCSTR, LPSTR, LPDWORD, DWORD);
39 static HRESULT (WINAPI *pPathCreateFromUrlW)(LPCWSTR, LPWSTR, LPDWORD, DWORD);
40 static HRESULT (WINAPI *pPathCreateFromUrlAlloc)(LPCWSTR, LPWSTR*, DWORD);
41 static BOOL (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
42 static BOOL (WINAPI *pPathUnExpandEnvStringsA)(LPCSTR, LPSTR, UINT);
43 static BOOL (WINAPI *pPathUnExpandEnvStringsW)(LPCWSTR, LPWSTR, UINT);
44
45 /* ################ */
46
47 static const struct {
48 const char *url;
49 const char *path;
50 DWORD ret, todo;
51 } TEST_PATHFROMURL[] = {
52 /* 0 leading slash */
53 {"file:c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
54 {"file:c|/foo/bar", "c:\\foo\\bar", S_OK, 0},
55 {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK, 0},
56 {"file:c:foo/bar", "c:foo\\bar", S_OK, 0},
57 {"file:c|foo/bar", "c:foo\\bar", S_OK, 0},
58 {"file:c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
59 {"file:foo%20ba%2fr", "foo ba/r", S_OK, 0},
60 {"file:foo/bar/", "foo\\bar\\", S_OK, 0},
61
62 /* 1 leading (back)slash */
63 {"file:/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
64 {"file:\\c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
65 {"file:/c|/foo/bar", "c:\\foo\\bar", S_OK, 0},
66 {"file:/cx|/foo/bar", "\\cx|\\foo\\bar", S_OK, 0},
67 {"file:/c:foo/bar", "c:foo\\bar", S_OK, 0},
68 {"file:/c|foo/bar", "c:foo\\bar", S_OK, 0},
69 {"file:/c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
70 {"file:/foo%20ba%2fr", "\\foo ba/r", S_OK, 0},
71 {"file:/foo/bar/", "\\foo\\bar\\", S_OK, 0},
72
73 /* 2 leading (back)slashes */
74 {"file://c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
75 {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK, 0},
76 {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK, 0},
77 {"file://cx|/foo/bar", "\\\\cx|\\foo\\bar", S_OK, 0},
78 {"file://c:foo/bar", "c:foo\\bar", S_OK, 0},
79 {"file://c|foo/bar", "c:foo\\bar", S_OK, 0},
80 {"file://c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0},
81 {"file://c%3a/foo/../bar", "\\\\c:\\foo\\..\\bar", S_OK, 0},
82 {"file://c%7c/foo/../bar", "\\\\c|\\foo\\..\\bar", S_OK, 0},
83 {"file://foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0},
84 {"file://localhost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
85 {"file://localhost/c:/foo%20ba%5Cr", "c:\\foo ba\\r", S_OK, 0},
86 {"file://LocalHost/c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
87 {"file:\\\\localhost\\c:\\foo\\bar", "c:\\foo\\bar", S_OK, 0},
88 {"file://incomplete", "\\\\incomplete", S_OK, 0},
89
90 /* 3 leading (back)slashes (omitting hostname) */
91 {"file:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
92 {"File:///c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
93 {"file:///c:/foo%20ba%2fr", "c:\\foo ba/r", S_OK, 0},
94 {"file:///foo%20ba%2fr", "\\foo ba/r", S_OK, 0},
95 {"file:///foo/bar/", "\\foo\\bar\\", S_OK, 0},
96 {"file:///localhost/c:/foo/bar", "\\localhost\\c:\\foo\\bar", S_OK, 0},
97
98 /* 4 leading (back)slashes */
99 {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK, 0},
100 {"file:////c:/foo%20ba%2fr", "c:\\foo%20ba%2fr", S_OK, 0},
101 {"file:////foo%20ba%2fr", "\\\\foo%20ba%2fr", S_OK, 0},
102
103 /* 5 and more leading (back)slashes */
104 {"file://///c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0},
105 {"file://///c:/foo%20ba%2fr", "\\\\c:\\foo ba/r", S_OK, 0},
106 {"file://///foo%20ba%2fr", "\\\\foo ba/r", S_OK, 0},
107 {"file://////c:/foo/bar", "\\\\c:\\foo\\bar", S_OK, 0},
108
109 /* Leading (back)slashes cannot be escaped */
110 {"file:%2f%2flocalhost%2fc:/foo/bar", "//localhost/c:\\foo\\bar", S_OK, 0},
111 {"file:%5C%5Clocalhost%5Cc:/foo/bar", "\\\\localhost\\c:\\foo\\bar", S_OK, 0},
112
113 /* Hostname handling */
114 {"file://l%6fcalhost/c:/foo/bar", "\\\\localhostc:\\foo\\bar", S_OK, 0},
115 {"file://localhost:80/c:/foo/bar", "\\\\localhost:80c:\\foo\\bar", S_OK, 0},
116 {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK, 0},
117 {"file://host//c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0},
118 {"file://host/\\c:/foo/bar", "\\\\host\\\\c:\\foo\\bar", S_OK, 0},
119 {"file://host/c:foo/bar", "\\\\hostc:foo\\bar", S_OK, 0},
120 {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK, 0},
121 {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK, 0},
122 {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK, 0},
123 {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK, 0},
124 {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK, 0},
125 {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK, 0},
126 {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK, 0},
127
128 /* Not file URLs */
129 {"c:\\foo\\bar", NULL, E_INVALIDARG, 0},
130 {"foo/bar", NULL, E_INVALIDARG, 0},
131 {"http://foo/bar", NULL, E_INVALIDARG, 0},
132
133 };
134
135
136 static struct {
137 const char *path;
138 BOOL expect;
139 } TEST_PATH_IS_URL[] = {
140 {"http://foo/bar", TRUE},
141 {"c:\\foo\\bar", FALSE},
142 {"c:/foo/bar", FALSE},
143 {"foo://foo/bar", TRUE},
144 {"foo\\bar", FALSE},
145 {"foo.bar", FALSE},
146 {"bogusscheme:", TRUE},
147 {"http:partial", TRUE},
148 {"www.winehq.org", FALSE},
149 /* More examples that the user might enter as the browser start page */
150 {"winehq.org", FALSE},
151 {"ftp.winehq.org", FALSE},
152 {"http://winehq.org", TRUE},
153 {"http://www.winehq.org", TRUE},
154 {"https://winehq.org", TRUE},
155 {"https://www.winehq.org", TRUE},
156 {"ftp://winehq.org", TRUE},
157 {"ftp://ftp.winehq.org", TRUE},
158 {"file://does_not_exist.txt", TRUE},
159 {"about:blank", TRUE},
160 {"about:home", TRUE},
161 {"about:mozilla", TRUE},
162 /* scheme is case independent */
163 {"HTTP://www.winehq.org", TRUE},
164 /* a space at the start is not allowed */
165 {" http://www.winehq.org", FALSE},
166 {"", FALSE},
167 {NULL, FALSE}
168 };
169
170 static const struct {
171 const char *path;
172 const char *result;
173 } TEST_PATH_UNQUOTE_SPACES[] = {
174 { "abcdef", "abcdef" },
175 { "\"abcdef\"", "abcdef" },
176 { "\"abcdef", "\"abcdef" },
177 { "abcdef\"", "abcdef\"" },
178 { "\"\"abcdef\"\"", "\"abcdef\"" },
179 { "abc\"def", "abc\"def" },
180 { "\"abc\"def", "\"abc\"def" },
181 { "\"abc\"def\"", "abc\"def" },
182 { "\'abcdef\'", "\'abcdef\'" },
183 { "\"\"", "" },
184 { "\"", "" }
185 };
186
187 /* ################ */
188
189 static LPWSTR GetWideString(const char* szString)
190 {
191 LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR));
192
193 MultiByteToWideChar(CP_ACP, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH);
194
195 return wszString;
196 }
197
198 static void FreeWideString(LPWSTR wszString)
199 {
200 HeapFree(GetProcessHeap(), 0, wszString);
201 }
202
203 static LPSTR strdupA(LPCSTR p)
204 {
205 LPSTR ret;
206 DWORD len = (strlen(p) + 1);
207 ret = HeapAlloc(GetProcessHeap(), 0, len);
208 memcpy(ret, p, len);
209 return ret;
210 }
211
212 /* ################ */
213
214 static void test_PathSearchAndQualify(void)
215 {
216 WCHAR path1[] = {'c',':','\\','f','o','o',0};
217 WCHAR expect1[] = {'c',':','\\','f','o','o',0};
218 WCHAR path2[] = {'c',':','f','o','o',0};
219 WCHAR c_drive[] = {'c',':',0};
220 WCHAR foo[] = {'f','o','o',0};
221 WCHAR path3[] = {'\\','f','o','o',0};
222 WCHAR winini[] = {'w','i','n','.','i','n','i',0};
223 WCHAR out[MAX_PATH];
224 WCHAR cur_dir[MAX_PATH];
225 WCHAR dot[] = {'.',0};
226
227 /* c:\foo */
228 ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
229 "PathSearchAndQualify rets 0\n");
230 ok(!lstrcmpiW(out, expect1), "strings don't match\n");
231
232 /* c:foo */
233 ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
234 "PathSearchAndQualify rets 0\n");
235 GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
236 PathAddBackslashW(cur_dir);
237 lstrcatW(cur_dir, foo);
238 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
239
240 /* foo */
241 ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
242 "PathSearchAndQualify rets 0\n");
243 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
244 PathAddBackslashW(cur_dir);
245 lstrcatW(cur_dir, foo);
246 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
247
248 /* \foo */
249 ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
250 "PathSearchAndQualify rets 0\n");
251 GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
252 lstrcpyW(cur_dir + 2, path3);
253 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
254
255 /* win.ini */
256 ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
257 "PathSearchAndQualify rets 0\n");
258 if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
259 GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
260 ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
261
262 }
263
264 static void test_PathCreateFromUrl(void)
265 {
266 size_t i;
267 char ret_path[INTERNET_MAX_URL_LENGTH];
268 DWORD len, len2, ret;
269 WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
270 WCHAR *pathW, *urlW;
271
272 if (!pPathCreateFromUrlA) {
273 win_skip("PathCreateFromUrlA not found\n");
274 return;
275 }
276
277 /* Won't say how much is needed without a buffer */
278 len = 0xdeca;
279 ret = pPathCreateFromUrlA("file://foo", NULL, &len, 0);
280 ok(ret == E_INVALIDARG, "got 0x%08x expected E_INVALIDARG\n", ret);
281 ok(len == 0xdeca, "got %x expected 0xdeca\n", len);
282
283 /* Test the decoding itself */
284 for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
285 len = INTERNET_MAX_URL_LENGTH;
286 ret = pPathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
287 if (!(TEST_PATHFROMURL[i].todo & 0x1))
288 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url);
289 else todo_wine
290 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url %s\n", ret, TEST_PATHFROMURL[i].url);
291 if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) {
292 if(!(TEST_PATHFROMURL[i].todo & 0x2)) {
293 ok(!lstrcmpiA(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
294 ok(len == strlen(ret_path), "ret len %d from url %s\n", len, TEST_PATHFROMURL[i].url);
295 } else todo_wine
296 /* Wrong string, don't bother checking the length */
297 ok(!lstrcmpiA(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
298 }
299
300 if (pPathCreateFromUrlW) {
301 len = INTERNET_MAX_URL_LENGTH;
302 pathW = GetWideString(TEST_PATHFROMURL[i].path);
303 urlW = GetWideString(TEST_PATHFROMURL[i].url);
304 ret = pPathCreateFromUrlW(urlW, ret_pathW, &len, 0);
305 WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),NULL,NULL);
306 if (!(TEST_PATHFROMURL[i].todo & 0x1))
307 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
308 else todo_wine
309 ok(ret == TEST_PATHFROMURL[i].ret, "ret %08x from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
310 if(SUCCEEDED(ret) && TEST_PATHFROMURL[i].path) {
311 if(!(TEST_PATHFROMURL[i].todo & 0x2)) {
312 ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n",
313 ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
314 ok(len == lstrlenW(ret_pathW), "ret len %d from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
315 } else todo_wine
316 /* Wrong string, don't bother checking the length */
317 ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n",
318 ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
319 }
320
321 if (SUCCEEDED(ret))
322 {
323 /* Check what happens if the buffer is too small */
324 len2 = 2;
325 ret = pPathCreateFromUrlW(urlW, ret_pathW, &len2, 0);
326 ok(ret == E_POINTER, "ret %08x, expected E_POINTER from url %s\n", ret, TEST_PATHFROMURL[i].url);
327 if(!(TEST_PATHFROMURL[i].todo & 0x4))
328 ok(len2 == len + 1, "got len = %d expected %d from url %s\n", len2, len + 1, TEST_PATHFROMURL[i].url);
329 else todo_wine
330 ok(len2 == len + 1, "got len = %d expected %d from url %s\n", len2, len + 1, TEST_PATHFROMURL[i].url);
331 }
332
333 FreeWideString(urlW);
334 FreeWideString(pathW);
335 }
336 }
337
338 if (pPathCreateFromUrlAlloc)
339 {
340 static const WCHAR fileW[] = {'f','i','l','e',':','/','/','f','o','o',0};
341 static const WCHAR fooW[] = {'\\','\\','f','o','o',0};
342
343 pathW = NULL;
344 ret = pPathCreateFromUrlAlloc(fileW, &pathW, 0);
345 ok(ret == S_OK, "got 0x%08x expected S_OK\n", ret);
346 ok(lstrcmpiW(pathW, fooW) == 0, "got %s expected %s\n", wine_dbgstr_w(pathW), wine_dbgstr_w(fooW));
347 HeapFree(GetProcessHeap(), 0, pathW);
348 }
349 }
350
351
352 static void test_PathIsUrl(void)
353 {
354 size_t i;
355 BOOL ret;
356
357 for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
358 ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
359 ok(ret == TEST_PATH_IS_URL[i].expect,
360 "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
361 TEST_PATH_IS_URL[i].expect);
362 }
363 }
364
365 static const DWORD SHELL_charclass[] =
366 {
367 0x00000000, 0x00000000, 0x00000000, 0x00000000,
368 0x00000000, 0x00000000, 0x00000000, 0x00000000,
369 0x00000000, 0x00000000, 0x00000000, 0x00000000,
370 0x00000000, 0x00000000, 0x00000000, 0x00000000,
371 0x00000000, 0x00000000, 0x00000000, 0x00000000,
372 0x00000000, 0x00000000, 0x00000000, 0x00000000,
373 0x00000000, 0x00000000, 0x00000000, 0x00000000,
374 0x00000000, 0x00000000, 0x00000000, 0x00000000,
375 0x00000080, 0x00000100, 0x00000200, 0x00000100,
376 0x00000100, 0x00000100, 0x00000100, 0x00000100,
377 0x00000100, 0x00000100, 0x00000002, 0x00000100,
378 0x00000040, 0x00000100, 0x00000004, 0x00000000,
379 0x00000100, 0x00000100, 0x00000100, 0x00000100,
380 0x00000100, 0x00000100, 0x00000100, 0x00000100,
381 0x00000100, 0x00000100, 0x00000010, 0x00000020,
382 0x00000000, 0x00000100, 0x00000000, 0x00000001,
383 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
384 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
385 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
386 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
387 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
388 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
389 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
390 0x00000008, 0x00000100, 0x00000100, 0x00000100,
391 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
392 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
393 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
394 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
395 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
396 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
397 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
398 0x00000000, 0x00000100, 0x00000100
399 };
400
401 static void test_PathIsValidCharA(void)
402 {
403 BOOL ret;
404 unsigned int c;
405
406 /* For whatever reason, PathIsValidCharA and PathAppendA share the same
407 * ordinal number in some native versions. Check this to prevent a crash.
408 */
409 if (!pPathIsValidCharA || pPathIsValidCharA == (void*)pPathAppendA)
410 {
411 win_skip("PathIsValidCharA isn't available\n");
412 return;
413 }
414
415 for (c = 0; c < 0x7f; c++)
416 {
417 ret = pPathIsValidCharA( c, ~0U );
418 ok ( ret || !SHELL_charclass[c], "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
419 }
420
421 for (c = 0x7f; c <= 0xff; c++)
422 {
423 ret = pPathIsValidCharA( c, ~0U );
424 ok ( ret, "PathIsValidCharA failed: 0x%02x got 0x%08x\n", c, ret );
425 }
426 }
427
428 static void test_PathIsValidCharW(void)
429 {
430 BOOL ret;
431 unsigned int c;
432
433 if (!pPathIsValidCharW)
434 {
435 win_skip("PathIsValidCharW isn't available\n");
436 return;
437 }
438
439 for (c = 0; c < 0x7f; c++)
440 {
441 ret = pPathIsValidCharW( c, ~0U );
442 ok ( ret || !SHELL_charclass[c], "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
443 }
444
445 for (c = 0x007f; c <= 0xffff; c++)
446 {
447 ret = pPathIsValidCharW( c, ~0U );
448 ok ( ret, "PathIsValidCharW failed: 0x%02x got 0x%08x\n", c, ret );
449 }
450 }
451
452 static void test_PathMakePretty(void)
453 {
454 char buff[MAX_PATH];
455
456 ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
457 buff[0] = '\0';
458 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
459
460 strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
461 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
462 ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
463 "PathMakePretty: Long UC name not changed\n");
464
465 strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
466 ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
467 ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
468 "PathMakePretty: Failed but modified path\n");
469
470 strcpy(buff, "TEST");
471 ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Short name failed\n");
472 ok (strcmp(buff, "Test") == 0, "PathMakePretty: 1st char lowercased %s\n", buff);
473 }
474
475 static void test_PathMatchSpec(void)
476 {
477 static const char file[] = "c:\\foo\\bar\\filename.ext";
478 static const char spec1[] = ".ext";
479 static const char spec2[] = "*.ext";
480 static const char spec3[] = "*.ext ";
481 static const char spec4[] = " *.ext";
482 static const char spec5[] = "* .ext";
483 static const char spec6[] = "*. ext";
484 static const char spec7[] = "* . ext";
485 static const char spec8[] = "*.e?t";
486 static const char spec9[] = "filename.ext";
487 static const char spec10[] = "*bar\\filename.ext";
488 static const char spec11[] = " foo; *.ext";
489 static const char spec12[] = "*.ext;*.bar";
490 static const char spec13[] = "*bar*";
491
492 ok (PathMatchSpecA(file, spec1) == FALSE, "PathMatchSpec: Spec1 failed\n");
493 ok (PathMatchSpecA(file, spec2) == TRUE, "PathMatchSpec: Spec2 failed\n");
494 ok (PathMatchSpecA(file, spec3) == FALSE, "PathMatchSpec: Spec3 failed\n");
495 ok (PathMatchSpecA(file, spec4) == TRUE, "PathMatchSpec: Spec4 failed\n");
496 todo_wine ok (PathMatchSpecA(file, spec5) == TRUE, "PathMatchSpec: Spec5 failed\n");
497 todo_wine ok (PathMatchSpecA(file, spec6) == TRUE, "PathMatchSpec: Spec6 failed\n");
498 ok (PathMatchSpecA(file, spec7) == FALSE, "PathMatchSpec: Spec7 failed\n");
499 ok (PathMatchSpecA(file, spec8) == TRUE, "PathMatchSpec: Spec8 failed\n");
500 ok (PathMatchSpecA(file, spec9) == FALSE, "PathMatchSpec: Spec9 failed\n");
501 ok (PathMatchSpecA(file, spec10) == TRUE, "PathMatchSpec: Spec10 failed\n");
502 ok (PathMatchSpecA(file, spec11) == TRUE, "PathMatchSpec: Spec11 failed\n");
503 ok (PathMatchSpecA(file, spec12) == TRUE, "PathMatchSpec: Spec12 failed\n");
504 ok (PathMatchSpecA(file, spec13) == TRUE, "PathMatchSpec: Spec13 failed\n");
505 }
506
507 static void test_PathCombineW(void)
508 {
509 LPWSTR wszString, wszString2;
510 WCHAR wbuf[MAX_PATH+1], wstr1[MAX_PATH] = {'C',':','\\',0}, wstr2[MAX_PATH];
511 static const WCHAR expout[] = {'C',':','\\','A','A',0};
512 int i;
513
514 if (!pPathCombineW)
515 {
516 win_skip("PathCombineW isn't available\n");
517 return;
518 }
519
520 wszString2 = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
521
522 /* NULL test */
523 wszString = pPathCombineW(NULL, NULL, NULL);
524 ok (wszString == NULL, "Expected a NULL return\n");
525
526 /* Some NULL */
527 wszString2[0] = 'a';
528 wszString = pPathCombineW(wszString2, NULL, NULL);
529 ok (wszString == NULL ||
530 broken(wszString[0] == 'a'), /* Win95 and some W2K */
531 "Expected a NULL return\n");
532 ok (wszString2[0] == 0 ||
533 broken(wszString2[0] == 'a'), /* Win95 and some W2K */
534 "Destination string not empty\n");
535
536 HeapFree(GetProcessHeap(), 0, wszString2);
537
538 /* overflow test */
539 wstr2[0] = wstr2[1] = wstr2[2] = 'A';
540 for (i=3; i<MAX_PATH/2; i++)
541 wstr1[i] = wstr2[i] = 'A';
542 wstr1[(MAX_PATH/2) - 1] = wstr2[MAX_PATH/2] = 0;
543 memset(wbuf, 0xbf, sizeof(wbuf));
544
545 wszString = pPathCombineW(wbuf, wstr1, wstr2);
546 ok(wszString == NULL, "Expected a NULL return\n");
547 ok(wbuf[0] == 0 ||
548 broken(wbuf[0] == 0xbfbf), /* Win95 and some W2K */
549 "Buffer contains data\n");
550
551 /* PathCombineW can be used in place */
552 wstr1[3] = 0;
553 wstr2[2] = 0;
554 ok(PathCombineW(wstr1, wstr1, wstr2) == wstr1, "Expected a wstr1 return\n");
555 ok(StrCmpW(wstr1, expout) == 0, "Unexpected PathCombine output\n");
556 }
557
558
559 #define LONG_LEN (MAX_PATH * 2)
560 #define HALF_LEN (MAX_PATH / 2 + 1)
561
562 static void test_PathCombineA(void)
563 {
564 LPSTR str;
565 char dest[MAX_PATH];
566 char too_long[LONG_LEN];
567 char one[HALF_LEN], two[HALF_LEN];
568
569 /* try NULL dest */
570 SetLastError(0xdeadbeef);
571 str = PathCombineA(NULL, "C:\\", "one\\two\\three");
572 ok(str == NULL, "Expected NULL, got %p\n", str);
573 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
574
575 /* try NULL dest and NULL directory */
576 SetLastError(0xdeadbeef);
577 str = PathCombineA(NULL, NULL, "one\\two\\three");
578 ok(str == NULL, "Expected NULL, got %p\n", str);
579 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
580
581 /* try all NULL*/
582 SetLastError(0xdeadbeef);
583 str = PathCombineA(NULL, NULL, NULL);
584 ok(str == NULL, "Expected NULL, got %p\n", str);
585 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
586
587 /* try NULL file part */
588 SetLastError(0xdeadbeef);
589 lstrcpyA(dest, "control");
590 str = PathCombineA(dest, "C:\\", NULL);
591 ok(str == dest, "Expected str == dest, got %p\n", str);
592 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
593 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
594
595 /* try empty file part */
596 SetLastError(0xdeadbeef);
597 lstrcpyA(dest, "control");
598 str = PathCombineA(dest, "C:\\", "");
599 ok(str == dest, "Expected str == dest, got %p\n", str);
600 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
601 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
602
603 /* try empty directory and file part */
604 SetLastError(0xdeadbeef);
605 lstrcpyA(dest, "control");
606 str = PathCombineA(dest, "", "");
607 ok(str == dest, "Expected str == dest, got %p\n", str);
608 ok(!lstrcmpA(str, "\\") ||
609 broken(!lstrcmpA(str, "control")), /* Win95 and some W2K */
610 "Expected \\, got %s\n", str);
611 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
612
613 /* try NULL directory */
614 SetLastError(0xdeadbeef);
615 lstrcpyA(dest, "control");
616 str = PathCombineA(dest, NULL, "one\\two\\three");
617 ok(str == dest, "Expected str == dest, got %p\n", str);
618 ok(!lstrcmpA(str, "one\\two\\three"), "Expected one\\two\\three, got %s\n", str);
619 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
620
621 /* try NULL directory and empty file part */
622 SetLastError(0xdeadbeef);
623 lstrcpyA(dest, "control");
624 str = PathCombineA(dest, NULL, "");
625 ok(str == dest, "Expected str == dest, got %p\n", str);
626 ok(!lstrcmpA(str, "\\") ||
627 broken(!lstrcmpA(str, "one\\two\\three")), /* Win95 and some W2K */
628 "Expected \\, got %s\n", str);
629 ok(GetLastError() == 0xdeadbeef ||
630 broken(GetLastError() == ERROR_INVALID_PARAMETER), /* Win95 */
631 "Expected 0xdeadbeef, got %d\n", GetLastError());
632
633 /* try NULL directory and file part */
634 SetLastError(0xdeadbeef);
635 lstrcpyA(dest, "control");
636 str = PathCombineA(dest, NULL, NULL);
637 ok(str == NULL ||
638 broken(str != NULL), /* Win95 and some W2K */
639 "Expected str == NULL, got %p\n", str);
640 ok(lstrlenA(dest) == 0 ||
641 broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
642 "Expected 0 length, got %i\n", lstrlenA(dest));
643 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
644
645 /* try directory without backslash */
646 SetLastError(0xdeadbeef);
647 lstrcpyA(dest, "control");
648 str = PathCombineA(dest, "C:", "one\\two\\three");
649 ok(str == dest, "Expected str == dest, got %p\n", str);
650 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
651 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
652
653 /* try directory with backslash */
654 SetLastError(0xdeadbeef);
655 lstrcpyA(dest, "control");
656 str = PathCombineA(dest, "C:\\", "one\\two\\three");
657 ok(str == dest, "Expected str == dest, got %p\n", str);
658 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
659 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
660
661 /* try directory with backslash and file with prepended backslash */
662 SetLastError(0xdeadbeef);
663 lstrcpyA(dest, "control");
664 str = PathCombineA(dest, "C:\\", "\\one\\two\\three");
665 ok(str == dest, "Expected str == dest, got %p\n", str);
666 ok(!lstrcmpA(str, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", str);
667 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
668
669 /* try previous test, with backslash appended as well */
670 SetLastError(0xdeadbeef);
671 lstrcpyA(dest, "control");
672 str = PathCombineA(dest, "C:\\", "\\one\\two\\three\\");
673 ok(str == dest, "Expected str == dest, got %p\n", str);
674 ok(!lstrcmpA(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
675 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
676
677 /* try a relative directory */
678 SetLastError(0xdeadbeef);
679 lstrcpyA(dest, "control");
680 str = PathCombineA(dest, "relative\\dir", "\\one\\two\\three\\");
681 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
682 /* Vista fails which probably makes sense as PathCombineA expects an absolute dir */
683 if (str)
684 {
685 ok(str == dest, "Expected str == dest, got %p\n", str);
686 ok(!lstrcmpA(str, "one\\two\\three\\"), "Expected one\\two\\three\\, got %s\n", str);
687 }
688
689 /* try forward slashes */
690 SetLastError(0xdeadbeef);
691 lstrcpyA(dest, "control");
692 str = PathCombineA(dest, "C:\\", "one/two/three\\");
693 ok(str == dest, "Expected str == dest, got %p\n", str);
694 ok(!lstrcmpA(str, "C:\\one/two/three\\"), "Expected one/two/three\\, got %s\n", str);
695 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
696
697 /* try a really weird directory */
698 SetLastError(0xdeadbeef);
699 lstrcpyA(dest, "control");
700 str = PathCombineA(dest, "C:\\/\\/", "\\one\\two\\three\\");
701 ok(str == dest, "Expected str == dest, got %p\n", str);
702 ok(!lstrcmpA(str, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", str);
703 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
704
705 /* try periods */
706 SetLastError(0xdeadbeef);
707 lstrcpyA(dest, "control");
708 str = PathCombineA(dest, "C:\\", "one\\..\\two\\.\\three");
709 ok(str == dest, "Expected str == dest, got %p\n", str);
710 ok(!lstrcmpA(str, "C:\\two\\three"), "Expected C:\\two\\three, got %s\n", str);
711 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
712
713 /* try .. as file */
714 /* try forward slashes */
715 SetLastError(0xdeadbeef);
716 lstrcpyA(dest, "control");
717 str = PathCombineA(dest, "C:\\", "..");
718 ok(str == dest, "Expected str == dest, got %p\n", str);
719 ok(!lstrcmpA(str, "C:\\"), "Expected C:\\, got %s\n", str);
720 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
721
722 memset(too_long, 'a', LONG_LEN);
723 too_long[LONG_LEN - 1] = '\0';
724
725 /* try a file longer than MAX_PATH */
726 SetLastError(0xdeadbeef);
727 lstrcpyA(dest, "control");
728 str = PathCombineA(dest, "C:\\", too_long);
729 ok(str == NULL, "Expected str == NULL, got %p\n", str);
730 ok(lstrlenA(dest) == 0 ||
731 broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
732 "Expected 0 length, got %i\n", lstrlenA(dest));
733 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
734
735 /* try a directory longer than MAX_PATH */
736 SetLastError(0xdeadbeef);
737 lstrcpyA(dest, "control");
738 str = PathCombineA(dest, too_long, "one\\two\\three");
739 ok(str == NULL, "Expected str == NULL, got %p\n", str);
740 ok(lstrlenA(dest) == 0 ||
741 broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
742 "Expected 0 length, got %i\n", lstrlenA(dest));
743 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
744
745 memset(one, 'b', HALF_LEN);
746 memset(two, 'c', HALF_LEN);
747 one[HALF_LEN - 1] = '\0';
748 two[HALF_LEN - 1] = '\0';
749
750 /* destination string is longer than MAX_PATH, but not the constituent parts */
751 SetLastError(0xdeadbeef);
752 lstrcpyA(dest, "control");
753 str = PathCombineA(dest, one, two);
754 ok(str == NULL, "Expected str == NULL, got %p\n", str);
755 ok(lstrlenA(dest) == 0 ||
756 broken(!lstrcmpA(dest, "control")), /* Win95 and some W2K */
757 "Expected 0 length, got %i\n", lstrlenA(dest));
758 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
759 }
760
761 static void test_PathAddBackslash(void)
762 {
763 LPSTR str;
764 char path[MAX_PATH];
765 char too_long[LONG_LEN];
766
767 /* try a NULL path */
768 SetLastError(0xdeadbeef);
769 str = PathAddBackslashA(NULL);
770 ok(str == NULL, "Expected str == NULL, got %p\n", str);
771 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
772
773 /* try an empty path */
774 path[0] = '\0';
775 SetLastError(0xdeadbeef);
776 str = PathAddBackslashA(path);
777 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
778 ok(lstrlenA(path) == 0, "Expected empty string, got %i\n", lstrlenA(path));
779 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
780
781 /* try a relative path */
782 lstrcpyA(path, "one\\two");
783 SetLastError(0xdeadbeef);
784 str = PathAddBackslashA(path);
785 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
786 ok(!lstrcmpA(path, "one\\two\\"), "Expected one\\two\\, got %s\n", path);
787 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
788
789 /* try periods */
790 lstrcpyA(path, "one\\..\\two");
791 SetLastError(0xdeadbeef);
792 str = PathAddBackslashA(path);
793 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
794 ok(!lstrcmpA(path, "one\\..\\two\\"), "Expected one\\..\\two\\, got %s\n", path);
795 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
796
797 /* try just a space */
798 lstrcpyA(path, " ");
799 SetLastError(0xdeadbeef);
800 str = PathAddBackslashA(path);
801 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
802 ok(!lstrcmpA(path, " \\"), "Expected \\, got %s\n", path);
803 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
804
805 /* path already has backslash */
806 lstrcpyA(path, "C:\\one\\");
807 SetLastError(0xdeadbeef);
808 str = PathAddBackslashA(path);
809 ok(str == (path + lstrlenA(path)), "Expected str to point to end of path, got %p\n", str);
810 ok(!lstrcmpA(path, "C:\\one\\"), "Expected C:\\one\\, got %s\n", path);
811 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
812
813 memset(too_long, 'a', LONG_LEN);
814 too_long[LONG_LEN - 1] = '\0';
815
816 /* path is longer than MAX_PATH */
817 SetLastError(0xdeadbeef);
818 str = PathAddBackslashA(too_long);
819 ok(str == NULL, "Expected str == NULL, got %p\n", str);
820 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
821 }
822
823 static void test_PathAppendA(void)
824 {
825 char path[MAX_PATH];
826 char too_long[LONG_LEN];
827 char half[HALF_LEN];
828 BOOL res;
829
830 lstrcpyA(path, "C:\\one");
831
832 /* try NULL pszMore */
833 SetLastError(0xdeadbeef);
834 res = PathAppendA(path, NULL);
835 ok(!res, "Expected failure\n");
836 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
837 ok(!lstrcmpA(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
838
839 /* try empty pszMore */
840 SetLastError(0xdeadbeef);
841 res = PathAppendA(path, "");
842 ok(res, "Expected success\n");
843 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
844 ok(!lstrcmpA(path, "C:\\one"), "Expected C:\\one, got %s\n", path);
845
846 /* try NULL pszPath */
847 SetLastError(0xdeadbeef);
848 res = PathAppendA(NULL, "two\\three");
849 ok(!res, "Expected failure\n");
850 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
851
852 /* try empty pszPath */
853 path[0] = '\0';
854 SetLastError(0xdeadbeef);
855 res = PathAppendA(path, "two\\three");
856 ok(res, "Expected success\n");
857 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
858 ok(!lstrcmpA(path, "two\\three"), "Expected \\two\\three, got %s\n", path);
859
860 /* try empty pszPath and empty pszMore */
861 path[0] = '\0';
862 SetLastError(0xdeadbeef);
863 res = PathAppendA(path, "");
864 ok(res, "Expected success\n");
865 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
866 ok(!lstrcmpA(path, "\\"), "Expected \\, got %s\n", path);
867
868 /* try legit params */
869 lstrcpyA(path, "C:\\one");
870 SetLastError(0xdeadbeef);
871 res = PathAppendA(path, "two\\three");
872 ok(res, "Expected success\n");
873 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
874 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
875
876 /* try pszPath with backslash after it */
877 lstrcpyA(path, "C:\\one\\");
878 SetLastError(0xdeadbeef);
879 res = PathAppendA(path, "two\\three");
880 ok(res, "Expected success\n");
881 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
882 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
883
884 /* try pszMore with backslash before it */
885 lstrcpyA(path, "C:\\one");
886 SetLastError(0xdeadbeef);
887 res = PathAppendA(path, "\\two\\three");
888 ok(res, "Expected success\n");
889 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
890 ok(!lstrcmpA(path, "C:\\one\\two\\three"), "Expected C:\\one\\two\\three, got %s\n", path);
891
892 /* try pszMore with backslash after it */
893 lstrcpyA(path, "C:\\one");
894 SetLastError(0xdeadbeef);
895 res = PathAppendA(path, "two\\three\\");
896 ok(res, "Expected success\n");
897 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
898 ok(!lstrcmpA(path, "C:\\one\\two\\three\\"), "Expected C:\\one\\two\\three\\, got %s\n", path);
899
900 /* try spaces in pszPath */
901 lstrcpyA(path, "C: \\ one ");
902 SetLastError(0xdeadbeef);
903 res = PathAppendA(path, "two\\three");
904 ok(res, "Expected success\n");
905 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
906 ok(!lstrcmpA(path, "C: \\ one \\two\\three"), "Expected C: \\ one \\two\\three, got %s\n", path);
907
908 /* try spaces in pszMore */
909 lstrcpyA(path, "C:\\one");
910 SetLastError(0xdeadbeef);
911 res = PathAppendA(path, " two \\ three ");
912 ok(res, "Expected success\n");
913 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
914 ok(!lstrcmpA(path, "C:\\one\\ two \\ three "), "Expected 'C:\\one\\ two \\ three ', got %s\n", path);
915
916 /* pszPath is too long */
917 memset(too_long, 'a', LONG_LEN);
918 too_long[LONG_LEN - 1] = '\0';
919 SetLastError(0xdeadbeef);
920 res = PathAppendA(too_long, "two\\three");
921 ok(!res, "Expected failure\n");
922 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
923 ok(lstrlenA(too_long) == 0 ||
924 broken(lstrlenA(too_long) == (LONG_LEN - 1)), /* Win95 and some W2K */
925 "Expected length of too_long to be zero, got %i\n", lstrlenA(too_long));
926
927 /* pszMore is too long */
928 lstrcpyA(path, "C:\\one");
929 memset(too_long, 'a', LONG_LEN);
930 too_long[LONG_LEN - 1] = '\0';
931 SetLastError(0xdeadbeef);
932 res = PathAppendA(path, too_long);
933 ok(!res, "Expected failure\n");
934 todo_wine ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
935 ok(lstrlenA(path) == 0 ||
936 broken(!lstrcmpA(path, "C:\\one")), /* Win95 and some W2K */
937 "Expected length of path to be zero, got %i\n", lstrlenA(path));
938
939 /* both params combined are too long */
940 memset(path, 'a', HALF_LEN);
941 path[HALF_LEN - 1] = '\0';
942 memset(half, 'b', HALF_LEN);
943 half[HALF_LEN - 1] = '\0';
944 SetLastError(0xdeadbeef);
945 res = PathAppendA(path, half);
946 ok(!res, "Expected failure\n");
947 ok(lstrlenA(path) == 0 ||
948 broken(lstrlenA(path) == (HALF_LEN - 1)), /* Win95 and some W2K */
949 "Expected length of path to be zero, got %i\n", lstrlenA(path));
950 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
951 }
952
953 static void test_PathCanonicalizeA(void)
954 {
955 char dest[LONG_LEN + MAX_PATH];
956 char too_long[LONG_LEN];
957 BOOL res;
958
959 /* try a NULL source */
960 lstrcpyA(dest, "test");
961 SetLastError(0xdeadbeef);
962 res = PathCanonicalizeA(dest, NULL);
963 ok(!res, "Expected failure\n");
964 ok(GetLastError() == ERROR_INVALID_PARAMETER,
965 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
966 ok(dest[0] == 0 || !lstrcmpA(dest, "test"),
967 "Expected either an empty string (Vista) or test, got %s\n", dest);
968
969 /* try an empty source */
970 lstrcpyA(dest, "test");
971 SetLastError(0xdeadbeef);
972 res = PathCanonicalizeA(dest, "");
973 ok(res, "Expected success\n");
974 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
975 ok(!lstrcmpA(dest, "\\") ||
976 broken(!lstrcmpA(dest, "test")), /* Win95 and some W2K */
977 "Expected \\, got %s\n", dest);
978
979 /* try a NULL dest */
980 SetLastError(0xdeadbeef);
981 res = PathCanonicalizeA(NULL, "C:\\");
982 ok(!res, "Expected failure\n");
983 ok(GetLastError() == ERROR_INVALID_PARAMETER,
984 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
985
986 /* try empty dest */
987 dest[0] = '\0';
988 SetLastError(0xdeadbeef);
989 res = PathCanonicalizeA(dest, "C:\\");
990 ok(res, "Expected success\n");
991 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
992 ok(!lstrcmpA(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
993
994 /* try non-empty dest */
995 lstrcpyA(dest, "test");
996 SetLastError(0xdeadbeef);
997 res = PathCanonicalizeA(dest, "C:\\");
998 ok(res, "Expected success\n");
999 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1000 ok(!lstrcmpA(dest, "C:\\"), "Expected C:\\, got %s\n", dest);
1001
1002 /* try a space for source */
1003 lstrcpyA(dest, "test");
1004 SetLastError(0xdeadbeef);
1005 res = PathCanonicalizeA(dest, " ");
1006 ok(res, "Expected success\n");
1007 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1008 ok(!lstrcmpA(dest, " "), "Expected ' ', got %s\n", dest);
1009
1010 /* try a relative path */
1011 lstrcpyA(dest, "test");
1012 SetLastError(0xdeadbeef);
1013 res = PathCanonicalizeA(dest, "one\\two");
1014 ok(res, "Expected success\n");
1015 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1016 ok(!lstrcmpA(dest, "one\\two"), "Expected one\\two, got %s\n", dest);
1017
1018 /* try current dir and previous dir */
1019 lstrcpyA(dest, "test");
1020 SetLastError(0xdeadbeef);
1021 res = PathCanonicalizeA(dest, "C:\\one\\.\\..\\two\\three\\..");
1022 ok(res, "Expected success\n");
1023 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1024 ok(!lstrcmpA(dest, "C:\\two"), "Expected C:\\two, got %s\n", dest);
1025
1026 /* try simple forward slashes */
1027 lstrcpyA(dest, "test");
1028 SetLastError(0xdeadbeef);
1029 res = PathCanonicalizeA(dest, "C:\\one/two/three\\four/five\\six");
1030 ok(res, "Expected success\n");
1031 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1032 ok(!lstrcmpA(dest, "C:\\one/two/three\\four/five\\six"),
1033 "Expected C:\\one/two/three\\four/five\\six, got %s\n", dest);
1034
1035 /* try simple forward slashes with same dir */
1036 lstrcpyA(dest, "test");
1037 SetLastError(0xdeadbeef);
1038 res = PathCanonicalizeA(dest, "C:\\one/.\\two");
1039 ok(res, "Expected success\n");
1040 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1041 ok(!lstrcmpA(dest, "C:\\one/.\\two"), "Expected C:\\one/.\\two, got %s\n", dest);
1042
1043 /* try simple forward slashes with change dir */
1044 lstrcpyA(dest, "test");
1045 SetLastError(0xdeadbeef);
1046 res = PathCanonicalizeA(dest, "C:\\one/.\\two\\..");
1047 ok(res, "Expected success\n");
1048 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1049 ok(!lstrcmpA(dest, "C:\\one/.") ||
1050 !lstrcmpA(dest, "C:\\one/"), /* Vista */
1051 "Expected \"C:\\one/.\" or \"C:\\one/\", got \"%s\"\n", dest);
1052
1053 /* try forward slashes with change dirs
1054 * NOTE: if there is a forward slash in between two backslashes,
1055 * everything in between the two backslashes is considered on dir
1056 */
1057 lstrcpyA(dest, "test");
1058 SetLastError(0xdeadbeef);
1059 res = PathCanonicalizeA(dest, "C:\\one/.\\..\\two/three\\..\\four/.five");
1060 ok(res, "Expected success\n");
1061 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1062 ok(!lstrcmpA(dest, "C:\\four/.five"), "Expected C:\\four/.five, got %s\n", dest);
1063
1064 /* try src is too long */
1065 memset(too_long, 'a', LONG_LEN);
1066 too_long[LONG_LEN - 1] = '\0';
1067 lstrcpyA(dest, "test");
1068 SetLastError(0xdeadbeef);
1069 res = PathCanonicalizeA(dest, too_long);
1070 ok(!res ||
1071 broken(res), /* Win95, some W2K and XP-SP1 */
1072 "Expected failure\n");
1073 todo_wine
1074 {
1075 ok(GetLastError() == 0xdeadbeef || GetLastError() == ERROR_FILENAME_EXCED_RANGE /* Vista */,
1076 "Expected 0xdeadbeef or ERROR_FILENAME_EXCED_RANGE, got %d\n", GetLastError());
1077 }
1078 ok(lstrlenA(too_long) == LONG_LEN - 1, "Expected length LONG_LEN - 1, got %i\n", lstrlenA(too_long));
1079 }
1080
1081 static void test_PathFindExtensionA(void)
1082 {
1083 LPSTR ext;
1084 char path[MAX_PATH];
1085 char too_long[LONG_LEN];
1086
1087 /* try a NULL path */
1088 SetLastError(0xdeadbeef);
1089 ext = PathFindExtensionA(NULL);
1090 ok(ext == NULL, "Expected NULL, got %p\n", ext);
1091 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1092
1093 /* try an empty path */
1094 path[0] = '\0';
1095 SetLastError(0xdeadbeef);
1096 ext = PathFindExtensionA(path);
1097 ok(ext == path, "Expected ext == path, got %p\n", ext);
1098 ok(lstrlenA(ext) == 0, "Expected length 0, got %i\n", lstrlenA(ext));
1099 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1100
1101 /* try a path without an extension */
1102 lstrcpyA(path, "file");
1103 SetLastError(0xdeadbeef);
1104 ext = PathFindExtensionA(path);
1105 ok(ext == path + lstrlenA(path), "Expected ext == path, got %p\n", ext);
1106 ok(lstrlenA(ext) == 0, "Expected length 0, got %i\n", lstrlenA(ext));
1107 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1108
1109 /* try a path with an extension */
1110 lstrcpyA(path, "file.txt");
1111 SetLastError(0xdeadbeef);
1112 ext = PathFindExtensionA(path);
1113 ok(ext == path + lstrlenA("file"),
1114 "Expected ext == path + lstrlenA(\"file\"), got %p\n", ext);
1115 ok(!lstrcmpA(ext, ".txt"), "Expected .txt, got %s\n", ext);
1116 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1117
1118 /* try a path with two extensions */
1119 lstrcpyA(path, "file.txt.doc");
1120 SetLastError(0xdeadbeef);
1121 ext = PathFindExtensionA(path);
1122 ok(ext == path + lstrlenA("file.txt"),
1123 "Expected ext == path + lstrlenA(\"file.txt\"), got %p\n", ext);
1124 ok(!lstrcmpA(ext, ".doc"), "Expected .txt, got %s\n", ext);
1125 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1126
1127 /* try a path longer than MAX_PATH without an extension*/
1128 memset(too_long, 'a', LONG_LEN);
1129 too_long[LONG_LEN - 1] = '\0';
1130 SetLastError(0xdeadbeef);
1131 ext = PathFindExtensionA(too_long);
1132 ok(ext == too_long + LONG_LEN - 1, "Expected ext == too_long + LONG_LEN - 1, got %p\n", ext);
1133 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1134
1135 /* try a path longer than MAX_PATH with an extension*/
1136 memset(too_long, 'a', LONG_LEN);
1137 too_long[LONG_LEN - 1] = '\0';
1138 lstrcpyA(too_long + 300, ".abcde");
1139 too_long[lstrlenA(too_long)] = 'a';
1140 SetLastError(0xdeadbeef);
1141 ext = PathFindExtensionA(too_long);
1142 ok(ext == too_long + 300, "Expected ext == too_long + 300, got %p\n", ext);
1143 ok(lstrlenA(ext) == LONG_LEN - 301, "Expected LONG_LEN - 301, got %i\n", lstrlenA(ext));
1144 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1145 }
1146
1147 static void test_PathBuildRootA(void)
1148 {
1149 LPSTR root;
1150 char path[10];
1151 char root_expected[26][4];
1152 char drive;
1153 int j;
1154
1155 /* set up the expected paths */
1156 for (drive = 'A'; drive <= 'Z'; drive++)
1157 sprintf(root_expected[drive - 'A'], "%c:\\", drive);
1158
1159 /* test the expected values */
1160 for (j = 0; j < 26; j++)
1161 {
1162 SetLastError(0xdeadbeef);
1163 lstrcpyA(path, "aaaaaaaaa");
1164 root = PathBuildRootA(path, j);
1165 ok(root == path, "Expected root == path, got %p\n", root);
1166 ok(!lstrcmpA(root, root_expected[j]), "Expected %s, got %s\n", root_expected[j], root);
1167 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1168 }
1169
1170 /* test a negative drive number */
1171 SetLastError(0xdeadbeef);
1172 lstrcpyA(path, "aaaaaaaaa");
1173 root = PathBuildRootA(path, -1);
1174 ok(root == path, "Expected root == path, got %p\n", root);
1175 ok(!lstrcmpA(path, "aaaaaaaaa") ||
1176 lstrlenA(path) == 0, /* Vista */
1177 "Expected aaaaaaaaa or empty string, got %s\n", path);
1178 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1179
1180 /* test a drive number greater than 25 */
1181 SetLastError(0xdeadbeef);
1182 lstrcpyA(path, "aaaaaaaaa");
1183 root = PathBuildRootA(path, 26);
1184 ok(root == path, "Expected root == path, got %p\n", root);
1185 ok(!lstrcmpA(path, "aaaaaaaaa") ||
1186 lstrlenA(path) == 0, /* Vista */
1187 "Expected aaaaaaaaa or empty string, got %s\n", path);
1188 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1189
1190 /* length of path is less than 4 */
1191 SetLastError(0xdeadbeef);
1192 lstrcpyA(path, "aa");
1193 root = PathBuildRootA(path, 0);
1194 ok(root == path, "Expected root == path, got %p\n", root);
1195 ok(!lstrcmpA(path, "A:\\"), "Expected A:\\, got %s\n", path);
1196 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1197
1198 /* path is NULL */
1199 SetLastError(0xdeadbeef);
1200 root = PathBuildRootA(NULL, 0);
1201 ok(root == NULL, "Expected root == NULL, got %p\n", root);
1202 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1203 }
1204
1205 static void test_PathCommonPrefixA(void)
1206 {
1207 char path1[MAX_PATH], path2[MAX_PATH];
1208 char out[MAX_PATH];
1209 int count;
1210
1211 /* test NULL path1 */
1212 SetLastError(0xdeadbeef);
1213 lstrcpyA(path2, "C:\\");
1214 lstrcpyA(out, "aaa");
1215 count = PathCommonPrefixA(NULL, path2, out);
1216 ok(count == 0, "Expected 0, got %i\n", count);
1217 todo_wine
1218 {
1219 ok(!lstrcmpA(out, "aaa"), "Expected aaa, got %s\n", out);
1220 }
1221 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1222 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1223
1224 /* test NULL path2 */
1225 SetLastError(0xdeadbeef);
1226 lstrcpyA(path1, "C:\\");
1227 lstrcpyA(out, "aaa");
1228 count = PathCommonPrefixA(path1, NULL, out);
1229 ok(count == 0, "Expected 0, got %i\n", count);
1230 todo_wine
1231 {
1232 ok(!lstrcmpA(out, "aaa"), "Expected aaa, got %s\n", out);
1233 }
1234 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1235 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1236
1237 /* test empty path1 */
1238 SetLastError(0xdeadbeef);
1239 path1[0] = '\0';
1240 lstrcpyA(path2, "C:\\");
1241 lstrcpyA(out, "aaa");
1242 count = PathCommonPrefixA(path1, path2, out);
1243 ok(count == 0, "Expected 0, got %i\n", count);
1244 ok(lstrlenA(out) == 0, "Expected 0 length out, got %i\n", lstrlenA(out));
1245 ok(lstrlenA(path1) == 0, "Expected 0 length path1, got %i\n", lstrlenA(path1));
1246 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1247 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1248
1249 /* test empty path1 */
1250 SetLastError(0xdeadbeef);
1251 path2[0] = '\0';
1252 lstrcpyA(path1, "C:\\");
1253 lstrcpyA(out, "aaa");
1254 count = PathCommonPrefixA(path1, path2, out);
1255 ok(count == 0, "Expected 0, got %i\n", count);
1256 ok(lstrlenA(out) == 0, "Expected 0 length out, got %i\n", lstrlenA(out));
1257 ok(lstrlenA(path2) == 0, "Expected 0 length path2, got %i\n", lstrlenA(path2));
1258 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1259 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1260
1261 /* paths are legit, out is NULL */
1262 SetLastError(0xdeadbeef);
1263 lstrcpyA(path1, "C:\\");
1264 lstrcpyA(path2, "C:\\");
1265 count = PathCommonPrefixA(path1, path2, NULL);
1266 ok(count == 3, "Expected 3, got %i\n", count);
1267 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1268 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1269 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1270
1271 /* all parameters legit */
1272 SetLastError(0xdeadbeef);
1273 lstrcpyA(path1, "C:\\");
1274 lstrcpyA(path2, "C:\\");
1275 lstrcpyA(out, "aaa");
1276 count = PathCommonPrefixA(path1, path2, out);
1277 ok(count == 3, "Expected 3, got %i\n", count);
1278 ok(!lstrcmpA(path1, "C:\\"), "Expected C:\\, got %s\n", path1);
1279 ok(!lstrcmpA(path2, "C:\\"), "Expected C:\\, got %s\n", path2);
1280 ok(!lstrcmpA(out, "C:\\"), "Expected C:\\, got %s\n", out);
1281 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1282
1283 /* path1 and path2 not the same, but common prefix */
1284 SetLastError(0xdeadbeef);
1285 lstrcpyA(path1, "C:\\one\\two");
1286 lstrcpyA(path2, "C:\\one\\three");
1287 lstrcpyA(out, "aaa");
1288 count = PathCommonPrefixA(path1, path2, out);
1289 ok(count == 6, "Expected 6, got %i\n", count);
1290 ok(!lstrcmpA(path1, "C:\\one\\two"), "Expected C:\\one\\two, got %s\n", path1);
1291 ok(!lstrcmpA(path2, "C:\\one\\three"), "Expected C:\\one\\three, got %s\n", path2);
1292 ok(!lstrcmpA(out, "C:\\one"), "Expected C:\\one, got %s\n", out);
1293 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1294
1295 /* try . prefix */
1296 SetLastError(0xdeadbeef);
1297 lstrcpyA(path1, "one\\.two");
1298 lstrcpyA(path2, "one\\.three");
1299 lstrcpyA(out, "aaa");
1300 count = PathCommonPrefixA(path1, path2, out);
1301 ok(count == 3, "Expected 3, got %i\n", count);
1302 ok(!lstrcmpA(path1, "one\\.two"), "Expected one\\.two, got %s\n", path1);
1303 ok(!lstrcmpA(path2, "one\\.three"), "Expected one\\.three, got %s\n", path2);
1304 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1305 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1306
1307 /* try .. prefix */
1308 SetLastError(0xdeadbeef);
1309 lstrcpyA(path1, "one\\..two");
1310 lstrcpyA(path2, "one\\..three");
1311 lstrcpyA(out, "aaa");
1312 count = PathCommonPrefixA(path1, path2, out);
1313 ok(count == 3, "Expected 3, got %i\n", count);
1314 ok(!lstrcmpA(path1, "one\\..two"), "Expected one\\..two, got %s\n", path1);
1315 ok(!lstrcmpA(path2, "one\\..three"), "Expected one\\..three, got %s\n", path2);
1316 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1317 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1318
1319 /* try ... prefix */
1320 SetLastError(0xdeadbeef);
1321 lstrcpyA(path1, "one\\...two");
1322 lstrcpyA(path2, "one\\...three");
1323 lstrcpyA(out, "aaa");
1324 count = PathCommonPrefixA(path1, path2, out);
1325 ok(count == 3, "Expected 3, got %i\n", count);
1326 ok(!lstrcmpA(path1, "one\\...two"), "Expected one\\...two, got %s\n", path1);
1327 ok(!lstrcmpA(path2, "one\\...three"), "Expected one\\...three, got %s\n", path2);
1328 ok(!lstrcmpA(out, "one"), "Expected one, got %s\n", out);
1329 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1330
1331 /* try .\ prefix */
1332 SetLastError(0xdeadbeef);
1333 lstrcpyA(path1, "one\\.\\two");
1334 lstrcpyA(path2, "one\\.\\three");
1335 lstrcpyA(out, "aaa");
1336 count = PathCommonPrefixA(path1, path2, out);
1337 ok(count == 5, "Expected 5, got %i\n", count);
1338 ok(!lstrcmpA(path1, "one\\.\\two"), "Expected one\\.\\two, got %s\n", path1);
1339 ok(!lstrcmpA(path2, "one\\.\\three"), "Expected one\\.\\three, got %s\n", path2);
1340 ok(!lstrcmpA(out, "one\\."), "Expected one\\., got %s\n", out);
1341 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1342
1343 /* try ..\ prefix */
1344 SetLastError(0xdeadbeef);
1345 lstrcpyA(path1, "one\\..\\two");
1346 lstrcpyA(path2, "one\\..\\three");
1347 lstrcpyA(out, "aaa");
1348 count = PathCommonPrefixA(path1, path2, out);
1349 ok(count == 6, "Expected 6, got %i\n", count);
1350 ok(!lstrcmpA(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1351 ok(!lstrcmpA(path2, "one\\..\\three"), "Expected one\\..\\three, got %s\n", path2);
1352 ok(!lstrcmpA(out, "one\\.."), "Expected one\\.., got %s\n", out);
1353 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1354
1355 /* try ...\\ prefix */
1356 SetLastError(0xdeadbeef);
1357 lstrcpyA(path1, "one\\...\\two");
1358 lstrcpyA(path2, "one\\...\\three");
1359 lstrcpyA(out, "aaa");
1360 count = PathCommonPrefixA(path1, path2, out);
1361 ok(count == 7, "Expected 7, got %i\n", count);
1362 ok(!lstrcmpA(path1, "one\\...\\two"), "Expected one\\...\\two, got %s\n", path1);
1363 ok(!lstrcmpA(path2, "one\\...\\three"), "Expected one\\...\\three, got %s\n", path2);
1364 ok(!lstrcmpA(out, "one\\..."), "Expected one\\..., got %s\n", out);
1365 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1366
1367 /* try prefix that is not an msdn labeled prefix type */
1368 SetLastError(0xdeadbeef);
1369 lstrcpyA(path1, "same");
1370 lstrcpyA(path2, "same");
1371 lstrcpyA(out, "aaa");
1372 count = PathCommonPrefixA(path1, path2, out);
1373 ok(count == 4, "Expected 4, got %i\n", count);
1374 ok(!lstrcmpA(path1, "same"), "Expected same, got %s\n", path1);
1375 ok(!lstrcmpA(path2, "same"), "Expected same, got %s\n", path2);
1376 ok(!lstrcmpA(out, "same"), "Expected same, got %s\n", out);
1377 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1378
1379 /* try . after directory */
1380 SetLastError(0xdeadbeef);
1381 lstrcpyA(path1, "one\\mid.\\two");
1382 lstrcpyA(path2, "one\\mid.\\three");
1383 lstrcpyA(out, "aaa");
1384 count = PathCommonPrefixA(path1, path2, out);
1385 ok(count == 8, "Expected 8, got %i\n", count);
1386 ok(!lstrcmpA(path1, "one\\mid.\\two"), "Expected one\\mid.\\two, got %s\n", path1);
1387 ok(!lstrcmpA(path2, "one\\mid.\\three"), "Expected one\\mid.\\three, got %s\n", path2);
1388 ok(!lstrcmpA(out, "one\\mid."), "Expected one\\mid., got %s\n", out);
1389 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1390
1391 /* try . in the middle of a directory */
1392 SetLastError(0xdeadbeef);
1393 lstrcpyA(path1, "one\\mid.end\\two");
1394 lstrcpyA(path2, "one\\mid.end\\three");
1395 lstrcpyA(out, "aaa");
1396 count = PathCommonPrefixA(path1, path2, out);
1397 ok(count == 11, "Expected 11, got %i\n", count);
1398 ok(!lstrcmpA(path1, "one\\mid.end\\two"), "Expected one\\mid.end\\two, got %s\n", path1);
1399 ok(!lstrcmpA(path2, "one\\mid.end\\three"), "Expected one\\mid.end\\three, got %s\n", path2);
1400 ok(!lstrcmpA(out, "one\\mid.end"), "Expected one\\mid.end, got %s\n", out);
1401 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1402
1403 /* try comparing a .. with the expanded path */
1404 SetLastError(0xdeadbeef);
1405 lstrcpyA(path1, "one\\..\\two");
1406 lstrcpyA(path2, "two");
1407 lstrcpyA(out, "aaa");
1408 count = PathCommonPrefixA(path1, path2, out);
1409 ok(count == 0, "Expected 0, got %i\n", count);
1410 ok(!lstrcmpA(path1, "one\\..\\two"), "Expected one\\..\\two, got %s\n", path1);
1411 ok(!lstrcmpA(path2, "two"), "Expected two, got %s\n", path2);
1412 ok(lstrlenA(out) == 0, "Expected 0 length out, got %i\n", lstrlenA(out));
1413 ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
1414 }
1415
1416 static void test_PathUnquoteSpaces(void)
1417 {
1418 int i;
1419 for(i = 0; i < sizeof(TEST_PATH_UNQUOTE_SPACES) / sizeof(TEST_PATH_UNQUOTE_SPACES[0]); i++)
1420 {
1421 char *path = strdupA(TEST_PATH_UNQUOTE_SPACES[i].path);
1422 WCHAR *pathW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].path);
1423 WCHAR *resultW = GetWideString(TEST_PATH_UNQUOTE_SPACES[i].result);
1424
1425 PathUnquoteSpacesA(path);
1426 ok(!strcmp(path, TEST_PATH_UNQUOTE_SPACES[i].result), "%s (A): got %s expected %s\n",
1427 TEST_PATH_UNQUOTE_SPACES[i].path, path,
1428 TEST_PATH_UNQUOTE_SPACES[i].result);
1429
1430 PathUnquoteSpacesW(pathW);
1431 ok(!lstrcmpW(pathW, resultW), "%s (W): strings differ\n",
1432 TEST_PATH_UNQUOTE_SPACES[i].path);
1433 FreeWideString(pathW);
1434 FreeWideString(resultW);
1435 HeapFree(GetProcessHeap(), 0, path);
1436 }
1437 }
1438
1439 static void test_PathGetDriveNumber(void)
1440 {
1441 static const CHAR test1A[] = "a:\\test.file";
1442 static const CHAR test2A[] = "file:////b:\\test.file";
1443 static const CHAR test3A[] = "file:///c:\\test.file";
1444 static const CHAR test4A[] = "file:\\\\c:\\test.file";
1445 int ret;
1446
1447 SetLastError(0xdeadbeef);
1448 ret = PathGetDriveNumberA(NULL);
1449 ok(ret == -1, "got %d\n", ret);
1450 ok(GetLastError() == 0xdeadbeef, "got %d\n", GetLastError());
1451
1452 ret = PathGetDriveNumberA(test1A);
1453 ok(ret == 0, "got %d\n", ret);
1454 ret = PathGetDriveNumberA(test2A);
1455 ok(ret == -1, "got %d\n", ret);
1456 ret = PathGetDriveNumberA(test3A);
1457 ok(ret == -1, "got %d\n", ret);
1458 ret = PathGetDriveNumberA(test4A);
1459 ok(ret == -1, "got %d\n", ret);
1460 }
1461
1462 static void test_PathUnExpandEnvStrings(void)
1463 {
1464 static const WCHAR sysrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
1465 static const WCHAR sysdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
1466 static const WCHAR nonpathW[] = {'p','a','t','h',0};
1467 static const char sysrootA[] = "%SystemRoot%";
1468 static const char sysdriveA[] = "%SystemDrive%";
1469 WCHAR pathW[MAX_PATH], buffW[MAX_PATH], sysdrvW[3];
1470 char path[MAX_PATH], buff[MAX_PATH], sysdrvA[3], envvarA[10];
1471 BOOL ret;
1472 UINT len;
1473
1474 if (!pPathUnExpandEnvStringsA || !pPathUnExpandEnvStringsW)
1475 {
1476 win_skip("PathUnExpandEnvStrings not available\n");
1477 return;
1478 }
1479
1480 /* something that can't be represented with env var */
1481 strcpy(path, "somepath_name");
1482 strcpy(buff, "xx");
1483 SetLastError(0xdeadbeef);
1484 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1485 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1486 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1487
1488 len = GetSystemDirectoryA(path, MAX_PATH);
1489 ok(len > 0, "failed to get sysdir\n");
1490
1491 sysdrvA[0] = path[0];
1492 strcpy(&sysdrvA[1], ":");
1493
1494 /* buffer size is not enough */
1495 strcpy(buff, "xx");
1496 SetLastError(0xdeadbeef);
1497 ret = pPathUnExpandEnvStringsA(path, buff, 5);
1498 ok(!ret && GetLastError() == 0xdeadbeef, "got %d\n", ret);
1499 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1500
1501 /* buffer size is enough to hold variable name only */
1502 strcpy(buff, "xx");
1503 SetLastError(0xdeadbeef);
1504 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(sysrootA));
1505 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1506 ok(buff[0] == 'x', "wrong return string %s\n", buff);
1507
1508 /* enough size */
1509 buff[0] = 0;
1510 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1511 ok(ret, "got %d\n", ret);
1512 ok(!strncmp(buff, sysrootA, sizeof(sysrootA)-1), "wrong return string %s\n", buff);
1513
1514 /* expanded value occurs multiple times */
1515 /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */
1516 buff[0] = 0;
1517 strcpy(path, sysdrvA);
1518 strcat(path, sysdrvA);
1519 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1520 ok(ret, "got %d\n", ret);
1521 /* expected string */
1522 strcpy(path, sysdriveA);
1523 strcat(path, sysdrvA);
1524 ok(!strcmp(buff, path), "wrong unexpanded string %s, expected %s\n", buff, path);
1525
1526 /* now with altered variable */
1527 ret = GetEnvironmentVariableA("SystemDrive", envvarA, sizeof(envvarA));
1528 ok(ret, "got %d\n", ret);
1529
1530 ret = SetEnvironmentVariableA("SystemDrive", "WW");
1531 ok(ret, "got %d\n", ret);
1532
1533 /* variables are not cached */
1534 strcpy(path, sysdrvA);
1535 strcat(path, sysdrvA);
1536 SetLastError(0xdeadbeef);
1537 ret = pPathUnExpandEnvStringsA(path, buff, sizeof(buff));
1538 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1539
1540 ret = SetEnvironmentVariableA("SystemDrive", envvarA);
1541 ok(ret, "got %d\n", ret);
1542
1543 /* PathUnExpandEnvStringsW */
1544
1545 /* something that can't be represented with env var */
1546 lstrcpyW(pathW, nonpathW);
1547 buffW[0] = 'x'; buffW[1] = 0;
1548 SetLastError(0xdeadbeef);
1549 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
1550 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1551 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1552
1553 len = GetSystemDirectoryW(pathW, MAX_PATH);
1554 ok(len > 0, "failed to get sysdir\n");
1555
1556 sysdrvW[0] = pathW[0];
1557 sysdrvW[1] = ':';
1558 sysdrvW[2] = 0;
1559
1560 /* buffer size is not enough */
1561 buffW[0] = 'x'; buffW[1] = 0;
1562 SetLastError(0xdeadbeef);
1563 ret = pPathUnExpandEnvStringsW(pathW, buffW, 5);
1564 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1565 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1566
1567 /* buffer size is enough to hold variable name only */
1568 buffW[0] = 'x'; buffW[1] = 0;
1569 SetLastError(0xdeadbeef);
1570 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(sysrootW)/sizeof(WCHAR));
1571 ok(!ret && GetLastError() == 0xdeadbeef, "got %d, error %d\n", ret, GetLastError());
1572 ok(buffW[0] == 'x', "wrong return string %s\n", wine_dbgstr_w(buffW));
1573
1574 /* enough size */
1575 buffW[0] = 0;
1576 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buffW)/sizeof(WCHAR));
1577 ok(ret, "got %d\n", ret);
1578 ok(!memcmp(buffW, sysrootW, sizeof(sysrootW) - sizeof(WCHAR)), "wrong return string %s\n", wine_dbgstr_w(buffW));
1579
1580 /* expanded value occurs multiple times */
1581 /* for drive C: it unexpands it like 'C:C:' -> '%SystemDrive%C:' */
1582 buffW[0] = 0;
1583 lstrcpyW(pathW, sysdrvW);
1584 lstrcatW(pathW, sysdrvW);
1585 ret = pPathUnExpandEnvStringsW(pathW, buffW, sizeof(buff)/sizeof(WCHAR));
1586 ok(ret, "got %d\n", ret);
1587 /* expected string */
1588 lstrcpyW(pathW, sysdriveW);
1589 lstrcatW(pathW, sysdrvW);
1590 ok(!lstrcmpW(buffW, pathW), "wrong unexpanded string %s, expected %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(pathW));
1591 }
1592
1593 START_TEST(path)
1594 {
1595 HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll");
1596
1597 /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
1598 if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
1599 win_skip("Too old shlwapi version\n");
1600 return;
1601 }
1602
1603 pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
1604 pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
1605 pPathCreateFromUrlAlloc = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlAlloc");
1606 pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
1607 pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
1608 pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
1609 pPathAppendA = (void*)GetProcAddress(hShlwapi, "PathAppendA");
1610 pPathUnExpandEnvStringsA = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsA");
1611 pPathUnExpandEnvStringsW = (void*)GetProcAddress(hShlwapi, "PathUnExpandEnvStringsW");
1612
1613 test_PathSearchAndQualify();
1614 test_PathCreateFromUrl();
1615 test_PathIsUrl();
1616
1617 test_PathAddBackslash();
1618 test_PathMakePretty();
1619 test_PathMatchSpec();
1620
1621 test_PathIsValidCharA();
1622 test_PathIsValidCharW();
1623
1624 test_PathCombineW();
1625 test_PathCombineA();
1626 test_PathAppendA();
1627 test_PathCanonicalizeA();
1628 test_PathFindExtensionA();
1629 test_PathBuildRootA();
1630 test_PathCommonPrefixA();
1631 test_PathUnquoteSpaces();
1632 test_PathGetDriveNumber();
1633 test_PathUnExpandEnvStrings();
1634 }