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