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