ReactOS 0.4.17-dev-117-g313be0c
path.c
Go to the documentation of this file.
1/*
2 * Path Functions
3 *
4 * Copyright 1999, 2000 Juergen Schmied
5 * Copyright 2001, 2002 Jon Griffiths
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22#include "config.h"
23#include "wine/port.h"
24
25#include <stdarg.h>
26#include <string.h>
27#include <stdlib.h>
28
29#include "wine/unicode.h"
30#include "windef.h"
31#include "winbase.h"
32#include "wingdi.h"
33#include "winuser.h"
34#include "winreg.h"
35#include "winternl.h"
36#define NO_SHLWAPI_STREAM
37#include "shlwapi.h"
38#ifdef __REACTOS__
39#include "winnetwk.h"
40#endif
41#include "wine/debug.h"
42
44
45#ifdef __REACTOS__
46
47#include <shlobj.h>
48#include <shlwapi_undoc.h>
49
50int WINAPI IsNetDrive(int drive);
51
52#else
53
54/* Get a function pointer from a DLL handle */
55#define GET_FUNC(func, module, name, fail) \
56 do { \
57 if (!func) { \
58 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
59 func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
60 if (!func) return fail; \
61 } \
62 } while (0)
63
64/* DLL handles for late bound calls */
66
67/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
70
71#endif /* __REACTOS__ */
72
73
75
77{
78 WCHAR *ret = NULL;
79
80 if (str)
81 {
83 ret = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
84 if (ret)
86 }
87
88 return ret;
89}
90
91/*************************************************************************
92 * PathAppendA [SHLWAPI.@]
93 *
94 * Append one path to another.
95 *
96 * PARAMS
97 * lpszPath [I/O] Initial part of path, and destination for output
98 * lpszAppend [I] Path to append
99 *
100 * RETURNS
101 * Success: TRUE. lpszPath contains the newly created path.
102 * Failure: FALSE, if either path is NULL, or PathCombineA() fails.
103 *
104 * NOTES
105 * lpszAppend must contain at least one backslash ('\') if not NULL.
106 * Because PathCombineA() is used to join the paths, the resulting
107 * path is also canonicalized.
108 */
109BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend)
110{
111 TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend));
112
113 if (lpszPath && lpszAppend)
114 {
115 if (!PathIsUNCA(lpszAppend))
116 while (*lpszAppend == '\\')
117 lpszAppend++;
118 if (PathCombineA(lpszPath, lpszPath, lpszAppend))
119 return TRUE;
120 }
121 return FALSE;
122}
123
124/*************************************************************************
125 * PathAppendW [SHLWAPI.@]
126 *
127 * See PathAppendA.
128 */
129BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
130{
131 TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend));
132
133 if (lpszPath && lpszAppend)
134 {
135 if (!PathIsUNCW(lpszAppend))
136 while (*lpszAppend == '\\')
137 lpszAppend++;
138 if (PathCombineW(lpszPath, lpszPath, lpszAppend))
139 return TRUE;
140 }
141 return FALSE;
142}
143
144/*************************************************************************
145 * PathCombineA [SHLWAPI.@]
146 *
147 * Combine two paths together.
148 *
149 * PARAMS
150 * lpszDest [O] Destination for combined path
151 * lpszDir [I] Directory path
152 * lpszFile [I] File path
153 *
154 * RETURNS
155 * Success: The output path
156 * Failure: NULL, if inputs are invalid.
157 *
158 * NOTES
159 * lpszDest should be at least MAX_PATH in size, and may point to the same
160 * memory location as lpszDir. The combined path is canonicalised.
161 */
163{
164 WCHAR szDest[MAX_PATH];
165 WCHAR szDir[MAX_PATH];
166 WCHAR szFile[MAX_PATH];
167 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile));
168
169 /* Invalid parameters */
170 if (!lpszDest)
171 return NULL;
172 if (!lpszDir && !lpszFile)
173 goto fail;
174
175 if (lpszDir)
176 if (!MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH))
177 goto fail;
178
179 if (lpszFile)
180 if (!MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH))
181 goto fail;
182
183 if (PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL))
184 if (WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0))
185 return lpszDest;
186
187fail:
188 lpszDest[0] = 0;
189 return NULL;
190}
191
192/*************************************************************************
193 * PathCombineW [SHLWAPI.@]
194 *
195 * See PathCombineA.
196 */
198{
199 WCHAR szTemp[MAX_PATH];
200 BOOL bUseBoth = FALSE, bStrip = FALSE;
201
202 TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile));
203
204 /* Invalid parameters */
205 if (!lpszDest)
206 return NULL;
207 if (!lpszDir && !lpszFile)
208 {
209 lpszDest[0] = 0;
210 return NULL;
211 }
212
213 if ((!lpszFile || !*lpszFile) && lpszDir)
214 {
215 /* Use dir only */
216 lstrcpynW(szTemp, lpszDir, MAX_PATH);
217 }
218 else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile))
219 {
220 if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile))
221 {
222 /* Use file only */
223 lstrcpynW(szTemp, lpszFile, MAX_PATH);
224 }
225 else
226 {
227 bUseBoth = TRUE;
228 bStrip = TRUE;
229 }
230 }
231 else
232 bUseBoth = TRUE;
233
234 if (bUseBoth)
235 {
236 lstrcpynW(szTemp, lpszDir, MAX_PATH);
237 if (bStrip)
238 {
239 PathStripToRootW(szTemp);
240 lpszFile++; /* Skip '\' */
241 }
242 if (!PathAddBackslashW(szTemp) || strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH)
243 {
244 lpszDest[0] = 0;
245 return NULL;
246 }
247 strcatW(szTemp, lpszFile);
248 }
249
251 return lpszDest;
252}
253
254/*************************************************************************
255 * PathAddBackslashA [SHLWAPI.@]
256 *
257 * Append a backslash ('\') to a path if one doesn't exist.
258 *
259 * PARAMS
260 * lpszPath [I/O] The path to append a backslash to.
261 *
262 * RETURNS
263 * Success: The position of the last backslash in the path.
264 * Failure: NULL, if lpszPath is NULL or the path is too large.
265 */
267{
268 size_t iLen;
269 LPSTR prev = lpszPath;
270
271 TRACE("(%s)\n",debugstr_a(lpszPath));
272
273 if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH)
274 return NULL;
275
276 if (iLen)
277 {
278 do {
279 lpszPath = CharNextA(prev);
280 if (*lpszPath)
281 prev = lpszPath;
282 } while (*lpszPath);
283 if (*prev != '\\')
284 {
285 *lpszPath++ = '\\';
286 *lpszPath = '\0';
287 }
288 }
289 return lpszPath;
290}
291
292/*************************************************************************
293 * PathAddBackslashW [SHLWAPI.@]
294 *
295 * See PathAddBackslashA.
296 */
298{
299 size_t iLen;
300
301 TRACE("(%s)\n",debugstr_w(lpszPath));
302
303 if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH)
304 return NULL;
305
306 if (iLen)
307 {
308 lpszPath += iLen;
309 if (lpszPath[-1] != '\\')
310 {
311 *lpszPath++ = '\\';
312 *lpszPath = '\0';
313 }
314 }
315 return lpszPath;
316}
317
318/*************************************************************************
319 * PathBuildRootA [SHLWAPI.@]
320 *
321 * Create a root drive string (e.g. "A:\") from a drive number.
322 *
323 * PARAMS
324 * lpszPath [O] Destination for the drive string
325 *
326 * RETURNS
327 * lpszPath
328 *
329 * NOTES
330 * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath.
331 */
333{
334 TRACE("(%p,%d)\n", lpszPath, drive);
335
336 if (lpszPath && drive >= 0 && drive < 26)
337 {
338 lpszPath[0] = 'A' + drive;
339 lpszPath[1] = ':';
340 lpszPath[2] = '\\';
341 lpszPath[3] = '\0';
342 }
343 return lpszPath;
344}
345
346/*************************************************************************
347 * PathBuildRootW [SHLWAPI.@]
348 *
349 * See PathBuildRootA.
350 */
352{
353 TRACE("(%p,%d)\n", lpszPath, drive);
354
355 if (lpszPath && drive >= 0 && drive < 26)
356 {
357 lpszPath[0] = 'A' + drive;
358 lpszPath[1] = ':';
359 lpszPath[2] = '\\';
360 lpszPath[3] = '\0';
361 }
362 return lpszPath;
363}
364
365/*************************************************************************
366 * PathFindFileNameA [SHLWAPI.@]
367 *
368 * Locate the start of the file name in a path
369 *
370 * PARAMS
371 * lpszPath [I] Path to search
372 *
373 * RETURNS
374 * A pointer to the first character of the file name
375 */
377{
378 LPCSTR lastSlash = lpszPath;
379
380 TRACE("(%s)\n",debugstr_a(lpszPath));
381
382 while (lpszPath && *lpszPath)
383 {
384 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
385 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
386 lastSlash = lpszPath + 1;
387 lpszPath = CharNextA(lpszPath);
388 }
389 return (LPSTR)lastSlash;
390}
391
392/*************************************************************************
393 * PathFindFileNameW [SHLWAPI.@]
394 *
395 * See PathFindFileNameA.
396 */
398{
399 LPCWSTR lastSlash = lpszPath;
400
401 TRACE("(%s)\n",debugstr_w(lpszPath));
402
403 while (lpszPath && *lpszPath)
404 {
405 if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
406 lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
407 lastSlash = lpszPath + 1;
408 lpszPath++;
409 }
410 return (LPWSTR)lastSlash;
411}
412
413/*************************************************************************
414 * PathFindExtensionA [SHLWAPI.@]
415 *
416 * Locate the start of the file extension in a path
417 *
418 * PARAMS
419 * lpszPath [I] The path to search
420 *
421 * RETURNS
422 * A pointer to the first character of the extension, the end of
423 * the string if the path has no extension, or NULL If lpszPath is NULL
424 */
426{
427 LPCSTR lastpoint = NULL;
428
429 TRACE("(%s)\n", debugstr_a(lpszPath));
430
431 if (lpszPath)
432 {
433 while (*lpszPath)
434 {
435 if (*lpszPath == '\\' || *lpszPath==' ')
436 lastpoint = NULL;
437 else if (*lpszPath == '.')
438 lastpoint = lpszPath;
439 lpszPath = CharNextA(lpszPath);
440 }
441 }
442 return (LPSTR)(lastpoint ? lastpoint : lpszPath);
443}
444
445/*************************************************************************
446 * PathFindExtensionW [SHLWAPI.@]
447 *
448 * See PathFindExtensionA.
449 */
451{
452 LPCWSTR lastpoint = NULL;
453
454 TRACE("(%s)\n", debugstr_w(lpszPath));
455
456 if (lpszPath)
457 {
458 while (*lpszPath)
459 {
460 if (*lpszPath == '\\' || *lpszPath==' ')
461 lastpoint = NULL;
462 else if (*lpszPath == '.')
463 lastpoint = lpszPath;
464 lpszPath++;
465 }
466 }
467 return (LPWSTR)(lastpoint ? lastpoint : lpszPath);
468}
469
470/*************************************************************************
471 * PathGetArgsA [SHLWAPI.@]
472 *
473 * Find the next argument in a string delimited by spaces.
474 *
475 * PARAMS
476 * lpszPath [I] The string to search for arguments in
477 *
478 * RETURNS
479 * The start of the next argument in lpszPath, or NULL if lpszPath is NULL
480 *
481 * NOTES
482 * Spaces in quoted strings are ignored as delimiters.
483 */
485{
486 BOOL bSeenQuote = FALSE;
487
488 TRACE("(%s)\n",debugstr_a(lpszPath));
489
490 if (lpszPath)
491 {
492 while (*lpszPath)
493 {
494 if ((*lpszPath==' ') && !bSeenQuote)
495 return (LPSTR)lpszPath + 1;
496 if (*lpszPath == '"')
497 bSeenQuote = !bSeenQuote;
498 lpszPath = CharNextA(lpszPath);
499 }
500 }
501 return (LPSTR)lpszPath;
502}
503
504/*************************************************************************
505 * PathGetArgsW [SHLWAPI.@]
506 *
507 * See PathGetArgsA.
508 */
510{
511 BOOL bSeenQuote = FALSE;
512
513 TRACE("(%s)\n",debugstr_w(lpszPath));
514
515 if (lpszPath)
516 {
517 while (*lpszPath)
518 {
519 if ((*lpszPath==' ') && !bSeenQuote)
520 return (LPWSTR)lpszPath + 1;
521 if (*lpszPath == '"')
522 bSeenQuote = !bSeenQuote;
523 lpszPath++;
524 }
525 }
526 return (LPWSTR)lpszPath;
527}
528
529/*************************************************************************
530 * PathGetDriveNumberA [SHLWAPI.@]
531 *
532 * Return the drive number from a path
533 *
534 * PARAMS
535 * lpszPath [I] Path to get the drive number from
536 *
537 * RETURNS
538 * Success: The drive number corresponding to the drive in the path
539 * Failure: -1, if lpszPath contains no valid drive
540 */
542{
543 TRACE ("(%s)\n",debugstr_a(lpszPath));
544
545 if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' &&
546 tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z')
547 return tolower(*lpszPath) - 'a';
548 return -1;
549}
550
551/*************************************************************************
552 * PathGetDriveNumberW [SHLWAPI.@]
553 *
554 * See PathGetDriveNumberA.
555 */
557{
558 WCHAR drive;
559
560 static const WCHAR nt_prefixW[] = {'\\','\\','?','\\'};
561
562 TRACE("(%s)\n", debugstr_w(path));
563
564 if (!path)
565 return -1;
566
567 if (!strncmpW(path, nt_prefixW, 4))
568 path += 4;
569
570 drive = tolowerW(path[0]);
571 if (drive < 'a' || drive > 'z' || path[1] != ':')
572 return -1;
573
574 return drive - 'a';
575}
576
577/*************************************************************************
578 * PathRemoveFileSpecA [SHLWAPI.@]
579 *
580 * Remove the file specification from a path.
581 *
582 * PARAMS
583 * lpszPath [I/O] Path to remove the file spec from
584 *
585 * RETURNS
586 * TRUE If the path was valid and modified
587 * FALSE Otherwise
588 */
590{
591 LPSTR lpszFileSpec = lpszPath;
592 BOOL bModified = FALSE;
593
594 TRACE("(%s)\n",debugstr_a(lpszPath));
595
596 if(lpszPath)
597 {
598 /* Skip directory or UNC path */
599 if (*lpszPath == '\\')
600 lpszFileSpec = ++lpszPath;
601 if (*lpszPath == '\\')
602 lpszFileSpec = ++lpszPath;
603
604 while (*lpszPath)
605 {
606 if(*lpszPath == '\\')
607 lpszFileSpec = lpszPath; /* Skip dir */
608 else if(*lpszPath == ':')
609 {
610 lpszFileSpec = ++lpszPath; /* Skip drive */
611 if (*lpszPath == '\\')
612 lpszFileSpec++;
613 }
614 if (!(lpszPath = CharNextA(lpszPath)))
615 break;
616 }
617
618 if (*lpszFileSpec)
619 {
620 *lpszFileSpec = '\0';
621 bModified = TRUE;
622 }
623 }
624 return bModified;
625}
626
627/*************************************************************************
628 * PathRemoveFileSpecW [SHLWAPI.@]
629 *
630 * See PathRemoveFileSpecA.
631 */
633{
634 LPWSTR lpszFileSpec = lpszPath;
635 BOOL bModified = FALSE;
636
637 TRACE("(%s)\n",debugstr_w(lpszPath));
638
639 if(lpszPath)
640 {
641 /* Skip directory or UNC path */
642 if (*lpszPath == '\\')
643 lpszFileSpec = ++lpszPath;
644 if (*lpszPath == '\\')
645 lpszFileSpec = ++lpszPath;
646
647 while (*lpszPath)
648 {
649 if(*lpszPath == '\\')
650 lpszFileSpec = lpszPath; /* Skip dir */
651 else if(*lpszPath == ':')
652 {
653 lpszFileSpec = ++lpszPath; /* Skip drive */
654 if (*lpszPath == '\\')
655 lpszFileSpec++;
656 }
657 lpszPath++;
658 }
659
660 if (*lpszFileSpec)
661 {
662 *lpszFileSpec = '\0';
663 bModified = TRUE;
664 }
665 }
666 return bModified;
667}
668
669/*************************************************************************
670 * PathStripPathA [SHLWAPI.@]
671 *
672 * Remove the initial path from the beginning of a filename
673 *
674 * PARAMS
675 * lpszPath [I/O] Path to remove the initial path from
676 *
677 * RETURNS
678 * Nothing.
679 */
681{
682 TRACE("(%s)\n", debugstr_a(lpszPath));
683
684 if (lpszPath)
685 {
686 LPSTR lpszFileName = PathFindFileNameA(lpszPath);
687 if(lpszFileName != lpszPath)
688 RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1);
689 }
690}
691
692/*************************************************************************
693 * PathStripPathW [SHLWAPI.@]
694 *
695 * See PathStripPathA.
696 */
698{
699 LPWSTR lpszFileName;
700
701 TRACE("(%s)\n", debugstr_w(lpszPath));
702 lpszFileName = PathFindFileNameW(lpszPath);
703 if(lpszFileName != lpszPath)
704 RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR));
705}
706
707/*************************************************************************
708 * PathStripToRootA [SHLWAPI.@]
709 *
710 * Reduce a path to its root.
711 *
712 * PARAMS
713 * lpszPath [I/O] the path to reduce
714 *
715 * RETURNS
716 * Success: TRUE if the stripped path is a root path
717 * Failure: FALSE if the path cannot be stripped or is NULL
718 */
720{
721 TRACE("(%s)\n", debugstr_a(lpszPath));
722
723 if (!lpszPath)
724 return FALSE;
725 while(!PathIsRootA(lpszPath))
726 if (!PathRemoveFileSpecA(lpszPath))
727 return FALSE;
728 return TRUE;
729}
730
731/*************************************************************************
732 * PathStripToRootW [SHLWAPI.@]
733 *
734 * See PathStripToRootA.
735 */
737{
738 TRACE("(%s)\n", debugstr_w(lpszPath));
739
740 if (!lpszPath)
741 return FALSE;
742 while(!PathIsRootW(lpszPath))
743 if (!PathRemoveFileSpecW(lpszPath))
744 return FALSE;
745 return TRUE;
746}
747
748/*************************************************************************
749 * PathRemoveArgsA [SHLWAPI.@]
750 *
751 * Strip space separated arguments from a path.
752 *
753 * PARAMS
754 * lpszPath [I/O] Path to remove arguments from
755 *
756 * RETURNS
757 * Nothing.
758 */
760{
761 TRACE("(%s)\n",debugstr_a(lpszPath));
762
763 if(lpszPath)
764 {
765 LPSTR lpszArgs = PathGetArgsA(lpszPath);
766 if (*lpszArgs)
767 lpszArgs[-1] = '\0';
768 else
769 {
770 LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
771 if(*lpszLastChar == ' ')
772 *lpszLastChar = '\0';
773 }
774 }
775}
776
777/*************************************************************************
778 * PathRemoveArgsW [SHLWAPI.@]
779 *
780 * See PathRemoveArgsA.
781 */
783{
784 TRACE("(%s)\n",debugstr_w(lpszPath));
785
786 if(lpszPath)
787 {
788 LPWSTR lpszArgs = PathGetArgsW(lpszPath);
789 if (*lpszArgs || (lpszArgs > lpszPath && lpszArgs[-1] == ' '))
790 lpszArgs[-1] = '\0';
791 }
792}
793
794/*************************************************************************
795 * PathRemoveExtensionA [SHLWAPI.@]
796 *
797 * Remove the file extension from a path
798 *
799 * PARAMS
800 * lpszPath [I/O] Path to remove the extension from
801 *
802 * NOTES
803 * The NUL terminator must be written only if extension exists
804 * and if the pointed character is not already NUL.
805 *
806 * RETURNS
807 * Nothing.
808 */
810{
811 TRACE("(%s)\n", debugstr_a(lpszPath));
812
813 if (lpszPath)
814 {
815 lpszPath = PathFindExtensionA(lpszPath);
816 if (lpszPath && *lpszPath != '\0')
817 *lpszPath = '\0';
818 }
819}
820
821/*************************************************************************
822 * PathRemoveExtensionW [SHLWAPI.@]
823 *
824 * See PathRemoveExtensionA.
825*/
827{
828 TRACE("(%s)\n", debugstr_w(lpszPath));
829
830 if (lpszPath)
831 {
832 lpszPath = PathFindExtensionW(lpszPath);
833 if (lpszPath && *lpszPath != '\0')
834 *lpszPath = '\0';
835 }
836}
837
838/*************************************************************************
839 * PathRemoveBackslashA [SHLWAPI.@]
840 *
841 * Remove a trailing backslash from a path.
842 *
843 * PARAMS
844 * lpszPath [I/O] Path to remove backslash from
845 *
846 * RETURNS
847 * Success: A pointer to the end of the path
848 * Failure: NULL, if lpszPath is NULL
849 */
851{
852 LPSTR szTemp = NULL;
853
854 TRACE("(%s)\n", debugstr_a(lpszPath));
855
856 if(lpszPath)
857 {
858 szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
859 if (!PathIsRootA(lpszPath) && *szTemp == '\\')
860 *szTemp = '\0';
861 }
862 return szTemp;
863}
864
865/*************************************************************************
866 * PathRemoveBackslashW [SHLWAPI.@]
867 *
868 * See PathRemoveBackslashA.
869 */
871{
872 LPWSTR szTemp = NULL;
873
874 TRACE("(%s)\n", debugstr_w(lpszPath));
875
876 if(lpszPath)
877 {
878 szTemp = lpszPath + strlenW(lpszPath);
879 if (szTemp > lpszPath) szTemp--;
880 if (!PathIsRootW(lpszPath) && *szTemp == '\\')
881 *szTemp = '\0';
882 }
883 return szTemp;
884}
885
886/*************************************************************************
887 * PathRemoveBlanksA [SHLWAPI.@]
888 *
889 * Remove Spaces from the start and end of a path.
890 *
891 * PARAMS
892 * lpszPath [I/O] Path to strip blanks from
893 *
894 * RETURNS
895 * Nothing.
896 */
898{
900
901 TRACE("(%s)\n", debugstr_a(pszPath));
902
903 if (!pszPath || !*pszPath)
904 return;
905
906 start = first = pszPath;
907
908 while (*pszPath == ' ')
909 pszPath = CharNextA(pszPath);
910
911 while (*pszPath)
912 *start++ = *pszPath++;
913
914 if (start != first)
915 while (start[-1] == ' ')
916 start--;
917
918 *start = '\0';
919}
920
921/*************************************************************************
922 * PathRemoveBlanksW [SHLWAPI.@]
923 *
924 * See PathRemoveBlanksA.
925 */
927{
929
930 TRACE("(%s)\n", debugstr_w(pszPath));
931
932 if (!pszPath || !*pszPath)
933 return;
934
935 start = first = pszPath;
936
937 while (*pszPath == ' ')
938 pszPath++;
939
940 while (*pszPath)
941 *start++ = *pszPath++;
942
943 if (start != first)
944 while (start[-1] == ' ')
945 start--;
946
947 *start = '\0';
948}
949
950/*************************************************************************
951 * PathQuoteSpacesA [SHLWAPI.@]
952 *
953 * Surround a path containing spaces in quotes.
954 *
955 * PARAMS
956 * lpszPath [I/O] Path to quote
957 *
958 * RETURNS
959 * Nothing.
960 *
961 * NOTES
962 * The path is not changed if it is invalid or has no spaces.
963 */
965{
966 TRACE("(%s)\n", debugstr_a(lpszPath));
967
968 if(lpszPath && StrChrA(lpszPath,' '))
969 {
970 size_t iLen = strlen(lpszPath) + 1;
971
972 if (iLen + 2 < MAX_PATH)
973 {
974 memmove(lpszPath + 1, lpszPath, iLen);
975 lpszPath[0] = '"';
976 lpszPath[iLen] = '"';
977 lpszPath[iLen + 1] = '\0';
978 }
979 }
980}
981
982/*************************************************************************
983 * PathQuoteSpacesW [SHLWAPI.@]
984 *
985 * See PathQuoteSpacesA.
986 */
988{
989 TRACE("(%s)\n", debugstr_w(lpszPath));
990
991 if(lpszPath && StrChrW(lpszPath,' '))
992 {
993 int iLen = strlenW(lpszPath) + 1;
994
995 if (iLen + 2 < MAX_PATH)
996 {
997 memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR));
998 lpszPath[0] = '"';
999 lpszPath[iLen] = '"';
1000 lpszPath[iLen + 1] = '\0';
1001 }
1002 }
1003}
1004
1005/*************************************************************************
1006 * PathUnquoteSpacesA [SHLWAPI.@]
1007 *
1008 * Remove quotes ("") from around a path, if present.
1009 *
1010 * PARAMS
1011 * lpszPath [I/O] Path to strip quotes from
1012 *
1013 * RETURNS
1014 * Nothing
1015 *
1016 * NOTES
1017 * If the path contains a single quote only, an empty string will result.
1018 * Otherwise quotes are only removed if they appear at the start and end
1019 * of the path.
1020 */
1022{
1023 TRACE("(%s)\n", debugstr_a(lpszPath));
1024
1025 if (lpszPath && *lpszPath == '"')
1026 {
1027 DWORD dwLen = strlen(lpszPath) - 1;
1028
1029 if (lpszPath[dwLen] == '"')
1030 {
1031 lpszPath[dwLen] = '\0';
1032 for (; *lpszPath; lpszPath++)
1033 *lpszPath = lpszPath[1];
1034 }
1035 }
1036}
1037
1038/*************************************************************************
1039 * PathUnquoteSpacesW [SHLWAPI.@]
1040 *
1041 * See PathUnquoteSpacesA.
1042 */
1044{
1045 TRACE("(%s)\n", debugstr_w(lpszPath));
1046
1047 if (lpszPath && *lpszPath == '"')
1048 {
1049 DWORD dwLen = strlenW(lpszPath) - 1;
1050
1051 if (lpszPath[dwLen] == '"')
1052 {
1053 lpszPath[dwLen] = '\0';
1054 for (; *lpszPath; lpszPath++)
1055 *lpszPath = lpszPath[1];
1056 }
1057 }
1058}
1059
1060/*************************************************************************
1061 * PathParseIconLocationA [SHLWAPI.@]
1062 *
1063 * Parse the location of an icon from a path.
1064 *
1065 * PARAMS
1066 * lpszPath [I/O] The path to parse the icon location from.
1067 *
1068 * RETURNS
1069 * Success: The number of the icon
1070 * Failure: 0 if the path does not contain an icon location or is NULL
1071 *
1072 * NOTES
1073 * The path has surrounding quotes and spaces removed regardless
1074 * of whether the call succeeds or not.
1075 */
1077{
1078 int iRet = 0;
1079 LPSTR lpszComma;
1080
1081 TRACE("(%s)\n", debugstr_a(lpszPath));
1082
1083 if (lpszPath)
1084 {
1085 if ((lpszComma = strchr(lpszPath, ',')))
1086 {
1087 *lpszComma++ = '\0';
1088 iRet = StrToIntA(lpszComma);
1089 }
1090 PathUnquoteSpacesA(lpszPath);
1091 PathRemoveBlanksA(lpszPath);
1092 }
1093 return iRet;
1094}
1095
1096/*************************************************************************
1097 * PathParseIconLocationW [SHLWAPI.@]
1098 *
1099 * See PathParseIconLocationA.
1100 */
1102{
1103 int iRet = 0;
1104 LPWSTR lpszComma;
1105
1106 TRACE("(%s)\n", debugstr_w(lpszPath));
1107
1108 if (lpszPath)
1109 {
1110 if ((lpszComma = StrChrW(lpszPath, ',')))
1111 {
1112 *lpszComma++ = '\0';
1113 iRet = StrToIntW(lpszComma);
1114 }
1115 PathUnquoteSpacesW(lpszPath);
1116 PathRemoveBlanksW(lpszPath);
1117 }
1118 return iRet;
1119}
1120
1121/*************************************************************************
1122 * @ [SHLWAPI.4]
1123 *
1124 * Unicode version of PathFileExistsDefExtA.
1125 */
1127{
1128 static const WCHAR pszExts[][5] = { { '.', 'p', 'i', 'f', 0},
1129 { '.', 'c', 'o', 'm', 0},
1130 { '.', 'e', 'x', 'e', 0},
1131 { '.', 'b', 'a', 't', 0},
1132 { '.', 'l', 'n', 'k', 0},
1133 { '.', 'c', 'm', 'd', 0},
1134 { 0, 0, 0, 0, 0} };
1135
1136 TRACE("(%s,%d)\n", debugstr_w(lpszPath), dwWhich);
1137
1138 if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath))
1139 return FALSE;
1140
1141 if (dwWhich)
1142 {
1143 LPCWSTR szExt = PathFindExtensionW(lpszPath);
1144#ifndef __REACTOS__
1145 if (!*szExt || dwWhich & 0x40)
1146#else
1147 if (!*szExt || dwWhich & WHICH_OPTIONAL)
1148#endif
1149 {
1150 size_t iChoose = 0;
1151 int iLen = lstrlenW(lpszPath);
1152 if (iLen > (MAX_PATH - 5))
1153 return FALSE;
1154#ifndef __REACTOS__
1155 while ( (dwWhich & 0x1) && pszExts[iChoose][0] )
1156#else
1157 while (pszExts[iChoose][0])
1158#endif
1159 {
1160#ifdef __REACTOS__
1161 if (dwWhich & 0x1)
1162 {
1164#endif
1165 lstrcpyW(lpszPath + iLen, pszExts[iChoose]);
1166 if (PathFileExistsW(lpszPath))
1167 return TRUE;
1168#ifdef __REACTOS__
1169 }
1170#endif
1171 iChoose++;
1172 dwWhich >>= 1;
1173 }
1174 *(lpszPath + iLen) = (WCHAR)'\0';
1175 return FALSE;
1176 }
1177 }
1178 return PathFileExistsW(lpszPath);
1179}
1180
1181/*************************************************************************
1182 * @ [SHLWAPI.3]
1183 *
1184 * Determine if a file exists locally and is of an executable type.
1185 *
1186 * PARAMS
1187 * lpszPath [I/O] File to search for
1188 * dwWhich [I] Type of executable to search for
1189 *
1190 * RETURNS
1191 * TRUE If the file was found. lpszPath contains the file name.
1192 * FALSE Otherwise.
1193 *
1194 * NOTES
1195 * lpszPath is modified in place and must be at least MAX_PATH in length.
1196 * If the function returns FALSE, the path is modified to its original state.
1197 * If the given path contains an extension or dwWhich is 0, executable
1198 * extensions are not checked.
1199 *
1200 * Ordinals 3-6 are a classic case of MS exposing limited functionality to
1201 * users (here through PathFindOnPathA()) and keeping advanced functionality for
1202 * their own developers exclusive use. Monopoly, anyone?
1203 */
1205{
1206 BOOL bRet = FALSE;
1207
1208 TRACE("(%s,%d)\n", debugstr_a(lpszPath), dwWhich);
1209
1210 if (lpszPath)
1211 {
1214 bRet = PathFileExistsDefExtW(szPath, dwWhich);
1215 if (bRet)
1216 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
1217 }
1218 return bRet;
1219}
1220
1221/*************************************************************************
1222 * SHLWAPI_PathFindInOtherDirs
1223 *
1224 * Internal helper for SHLWAPI_PathFindOnPathExA/W.
1225 */
1227{
1228 static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
1229 static const WCHAR szPath[] = { 'P','A','T','H','\0'};
1230 DWORD dwLenPATH;
1231 LPCWSTR lpszCurr;
1232 WCHAR *lpszPATH;
1234
1235 TRACE("(%s,%08x)\n", debugstr_w(lpszFile), dwWhich);
1236
1237 /* Try system directories */
1239 if (!PathAppendW(buff, lpszFile))
1240 return FALSE;
1241 if (PathFileExistsDefExtW(buff, dwWhich))
1242 {
1243 strcpyW(lpszFile, buff);
1244 return TRUE;
1245 }
1247 if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile))
1248 return FALSE;
1249 if (PathFileExistsDefExtW(buff, dwWhich))
1250 {
1251 strcpyW(lpszFile, buff);
1252 return TRUE;
1253 }
1255 if (!PathAppendW(buff, lpszFile))
1256 return FALSE;
1257 if (PathFileExistsDefExtW(buff, dwWhich))
1258 {
1259 strcpyW(lpszFile, buff);
1260 return TRUE;
1261 }
1262 /* Try dirs listed in %PATH% */
1264
1265 if (!dwLenPATH || !(lpszPATH = HeapAlloc(GetProcessHeap(), 0, (dwLenPATH + 1) * sizeof (WCHAR))))
1266 return FALSE;
1267
1268 GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1);
1269 lpszCurr = lpszPATH;
1270 while (lpszCurr)
1271 {
1272 LPCWSTR lpszEnd = lpszCurr;
1273 LPWSTR pBuff = buff;
1274
1275 while (*lpszEnd == ' ')
1276 lpszEnd++;
1277 while (*lpszEnd && *lpszEnd != ';')
1278 *pBuff++ = *lpszEnd++;
1279 *pBuff = '\0';
1280
1281 if (*lpszEnd)
1282 lpszCurr = lpszEnd + 1;
1283 else
1284 lpszCurr = NULL; /* Last Path, terminate after this */
1285
1286 if (!PathAppendW(buff, lpszFile))
1287 {
1288 HeapFree(GetProcessHeap(), 0, lpszPATH);
1289 return FALSE;
1290 }
1291 if (PathFileExistsDefExtW(buff, dwWhich))
1292 {
1293 strcpyW(lpszFile, buff);
1294 HeapFree(GetProcessHeap(), 0, lpszPATH);
1295 return TRUE;
1296 }
1297 }
1298 HeapFree(GetProcessHeap(), 0, lpszPATH);
1299 return FALSE;
1300}
1301
1302/*************************************************************************
1303 * @ [SHLWAPI.5]
1304 *
1305 * Search a range of paths for a specific type of executable.
1306 *
1307 * PARAMS
1308 * lpszFile [I/O] File to search for
1309 * lppszOtherDirs [I] Other directories to look in
1310 * dwWhich [I] Type of executable to search for
1311 *
1312 * RETURNS
1313 * Success: TRUE. The path to the executable is stored in lpszFile.
1314 * Failure: FALSE. The path to the executable is unchanged.
1315 */
1316BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich)
1317{
1318 WCHAR szFile[MAX_PATH];
1320
1321 TRACE("(%s,%p,%08x)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich);
1322
1323 if (!lpszFile || !PathIsFileSpecA(lpszFile))
1324 return FALSE;
1325
1326 MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
1327
1328 /* Search provided directories first */
1329 if (lppszOtherDirs && *lppszOtherDirs)
1330 {
1331 WCHAR szOther[MAX_PATH];
1332 LPCSTR *lpszOtherPath = lppszOtherDirs;
1333
1334 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
1335 {
1336 MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH);
1337 PathCombineW(buff, szOther, szFile);
1338 if (PathFileExistsDefExtW(buff, dwWhich))
1339 {
1340 WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0);
1341 return TRUE;
1342 }
1343 lpszOtherPath++;
1344 }
1345 }
1346 /* Not found, try system and path dirs */
1347 if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich))
1348 {
1349 WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0);
1350 return TRUE;
1351 }
1352 return FALSE;
1353}
1354
1355/*************************************************************************
1356 * @ [SHLWAPI.6]
1357 *
1358 * Unicode version of PathFindOnPathExA.
1359 */
1360BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich)
1361{
1363
1364 TRACE("(%s,%p,%08x)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich);
1365
1366 if (!lpszFile || !PathIsFileSpecW(lpszFile))
1367 return FALSE;
1368
1369 /* Search provided directories first */
1370 if (lppszOtherDirs && *lppszOtherDirs)
1371 {
1372 LPCWSTR *lpszOtherPath = lppszOtherDirs;
1373 while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
1374 {
1375 PathCombineW(buff, *lpszOtherPath, lpszFile);
1376 if (PathFileExistsDefExtW(buff, dwWhich))
1377 {
1378 strcpyW(lpszFile, buff);
1379 return TRUE;
1380 }
1381 lpszOtherPath++;
1382 }
1383 }
1384 /* Not found, try system and path dirs */
1385 return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich);
1386}
1387
1388/*************************************************************************
1389 * PathFindOnPathA [SHLWAPI.@]
1390 *
1391 * Search a range of paths for an executable.
1392 *
1393 * PARAMS
1394 * lpszFile [I/O] File to search for
1395 * lppszOtherDirs [I] Other directories to look in
1396 *
1397 * RETURNS
1398 * Success: TRUE. The path to the executable is stored in lpszFile.
1399 * Failure: FALSE. The path to the executable is unchanged.
1400 */
1401BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs)
1402{
1403 TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs);
1404 return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0);
1405 }
1406
1407/*************************************************************************
1408 * PathFindOnPathW [SHLWAPI.@]
1409 *
1410 * See PathFindOnPathA.
1411 */
1412BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
1413{
1414 TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs);
1415 return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0);
1416}
1417
1418/*************************************************************************
1419 * PathCompactPathExA [SHLWAPI.@]
1420 *
1421 * Compact a path into a given number of characters.
1422 *
1423 * PARAMS
1424 * lpszDest [O] Destination for compacted path
1425 * lpszPath [I] Source path
1426 * cchMax [I] Maximum size of compacted path
1427 * dwFlags [I] Reserved
1428 *
1429 * RETURNS
1430 * Success: TRUE. The compacted path is written to lpszDest.
1431 * Failure: FALSE. lpszPath is undefined.
1432 *
1433 * NOTES
1434 * If cchMax is given as 0, lpszDest will still be NUL terminated.
1435 *
1436 * The Win32 version of this function contains a bug: When cchMax == 7,
1437 * 8 bytes will be written to lpszDest. This bug is fixed in the Wine
1438 * implementation.
1439 *
1440 * Some relative paths will be different when cchMax == 5 or 6. This occurs
1441 * because Win32 will insert a "\" in lpszDest, even if one is
1442 * not present in the original path.
1443 */
1446{
1447 BOOL bRet = FALSE;
1448
1449 TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags);
1450
1451 if (lpszPath && lpszDest)
1452 {
1454 WCHAR szDest[MAX_PATH];
1455
1457 szDest[0] = '\0';
1458 bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags);
1460 }
1461 return bRet;
1462}
1463
1464/*************************************************************************
1465 * PathCompactPathExW [SHLWAPI.@]
1466 *
1467 * See PathCompactPathExA.
1468 */
1471{
1472 static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
1473 LPCWSTR lpszFile;
1474 DWORD dwLen, dwFileLen = 0;
1475
1476 TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags);
1477
1478 if (!lpszPath)
1479 return FALSE;
1480
1481 if (!lpszDest)
1482 {
1483 WARN("Invalid lpszDest would crash under Win32!\n");
1484 return FALSE;
1485 }
1486
1487 *lpszDest = '\0';
1488
1489 if (cchMax < 2)
1490 return TRUE;
1491
1492 dwLen = strlenW(lpszPath) + 1;
1493
1494 if (dwLen < cchMax)
1495 {
1496 /* Don't need to compact */
1497 memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
1498 return TRUE;
1499 }
1500
1501 /* Path must be compacted to fit into lpszDest */
1502 lpszFile = PathFindFileNameW(lpszPath);
1503 dwFileLen = lpszPath + dwLen - lpszFile;
1504
1505 if (dwFileLen == dwLen)
1506 {
1507 /* No root in psth */
1508 if (cchMax <= 4)
1509 {
1510 while (--cchMax > 0) /* No room left for anything but ellipses */
1511 *lpszDest++ = '.';
1512 *lpszDest = '\0';
1513 return TRUE;
1514 }
1515 /* Compact the file name with ellipses at the end */
1516 cchMax -= 4;
1517 memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
1518 strcpyW(lpszDest + cchMax, szEllipses);
1519 return TRUE;
1520 }
1521 /* We have a root in the path */
1522 lpszFile--; /* Start compacted filename with the path separator */
1523 dwFileLen++;
1524
1525 if (dwFileLen + 3 > cchMax)
1526 {
1527 /* Compact the file name */
1528 if (cchMax <= 4)
1529 {
1530 while (--cchMax > 0) /* No room left for anything but ellipses */
1531 *lpszDest++ = '.';
1532 *lpszDest = '\0';
1533 return TRUE;
1534 }
1535 strcpyW(lpszDest, szEllipses);
1536 lpszDest += 3;
1537 cchMax -= 4;
1538 *lpszDest++ = *lpszFile++;
1539 if (cchMax <= 4)
1540 {
1541 while (--cchMax > 0) /* No room left for anything but ellipses */
1542 *lpszDest++ = '.';
1543 *lpszDest = '\0';
1544 return TRUE;
1545 }
1546 cchMax -= 4;
1547 memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
1548 strcpyW(lpszDest + cchMax, szEllipses);
1549 return TRUE;
1550 }
1551
1552 /* Only the root needs to be Compacted */
1553 dwLen = cchMax - dwFileLen - 3;
1554 memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
1555 strcpyW(lpszDest + dwLen, szEllipses);
1556 strcpyW(lpszDest + dwLen + 3, lpszFile);
1557 return TRUE;
1558}
1559
1560/*************************************************************************
1561 * PathIsRelativeA [SHLWAPI.@]
1562 *
1563 * Determine if a path is a relative path.
1564 *
1565 * PARAMS
1566 * lpszPath [I] Path to check
1567 *
1568 * RETURNS
1569 * TRUE: The path is relative, or is invalid.
1570 * FALSE: The path is not relative.
1571 */
1573{
1574 TRACE("(%s)\n",debugstr_a(lpszPath));
1575
1576 if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath))
1577 return TRUE;
1578 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
1579 return FALSE;
1580 return TRUE;
1581}
1582
1583/*************************************************************************
1584 * PathIsRelativeW [SHLWAPI.@]
1585 *
1586 * See PathIsRelativeA.
1587 */
1589{
1590 TRACE("(%s)\n",debugstr_w(lpszPath));
1591
1592 if (!lpszPath || !*lpszPath)
1593 return TRUE;
1594 if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
1595 return FALSE;
1596 return TRUE;
1597}
1598
1599/*************************************************************************
1600 * PathIsRootA [SHLWAPI.@]
1601 *
1602 * Determine if a path is a root path.
1603 *
1604 * PARAMS
1605 * lpszPath [I] Path to check
1606 *
1607 * RETURNS
1608 * TRUE If lpszPath is valid and a root path,
1609 * FALSE Otherwise
1610 */
1612{
1613 TRACE("(%s)\n", debugstr_a(lpszPath));
1614
1615 if (lpszPath && *lpszPath)
1616 {
1617 if (*lpszPath == '\\')
1618 {
1619 if (!lpszPath[1])
1620 return TRUE; /* \ */
1621 else if (lpszPath[1]=='\\')
1622 {
1623 BOOL bSeenSlash = FALSE;
1624 lpszPath += 2;
1625
1626 /* Check for UNC root path */
1627 while (*lpszPath)
1628 {
1629 if (*lpszPath == '\\')
1630 {
1631 if (bSeenSlash)
1632 return FALSE;
1633 bSeenSlash = TRUE;
1634 }
1635 lpszPath = CharNextA(lpszPath);
1636 }
1637 return TRUE;
1638 }
1639 }
1640 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
1641 return TRUE; /* X:\ */
1642 }
1643 return FALSE;
1644}
1645
1646/*************************************************************************
1647 * PathIsRootW [SHLWAPI.@]
1648 *
1649 * See PathIsRootA.
1650 */
1652{
1653 TRACE("(%s)\n", debugstr_w(lpszPath));
1654
1655 if (lpszPath && *lpszPath)
1656 {
1657 if (*lpszPath == '\\')
1658 {
1659 if (!lpszPath[1])
1660 return TRUE; /* \ */
1661 else if (lpszPath[1]=='\\')
1662 {
1663 BOOL bSeenSlash = FALSE;
1664 lpszPath += 2;
1665
1666 /* Check for UNC root path */
1667 while (*lpszPath)
1668 {
1669 if (*lpszPath == '\\')
1670 {
1671 if (bSeenSlash)
1672 return FALSE;
1673 bSeenSlash = TRUE;
1674 }
1675 lpszPath++;
1676 }
1677 return TRUE;
1678 }
1679 }
1680 else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
1681 return TRUE; /* X:\ */
1682 }
1683 return FALSE;
1684}
1685
1686/*************************************************************************
1687 * PathIsDirectoryA [SHLWAPI.@]
1688 *
1689 * Determine if a path is a valid directory
1690 *
1691 * PARAMS
1692 * lpszPath [I] Path to check.
1693 *
1694 * RETURNS
1695 * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes)
1696 * FALSE if lpszPath is invalid or not a directory.
1697 *
1698 * NOTES
1699 * Although this function is prototyped as returning a BOOL, it returns
1700 * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as:
1701 *
1702 *| if (PathIsDirectoryA("c:\\windows\\") == TRUE)
1703 *| ...
1704 *
1705 * will always fail.
1706 */
1708{
1709 DWORD dwAttr;
1710
1711 TRACE("(%s)\n", debugstr_a(lpszPath));
1712
1713 if (!lpszPath || PathIsUNCServerA(lpszPath))
1714 return FALSE;
1715
1716 if (PathIsUNCServerShareA(lpszPath))
1717 {
1718#ifdef __REACTOS__
1719 LPSTR lpSystem = NULL;
1720 BYTE buffer[512] = {0};
1721 DWORD cbBuffer = sizeof(buffer);
1723 DWORD dwError;
1724
1725 pNetRes->dwScope = RESOURCE_GLOBALNET;
1726 pNetRes->dwType = RESOURCETYPE_ANY;
1727 pNetRes->lpRemoteName = (LPSTR)lpszPath;
1728
1729 dwError = WNetGetResourceInformationA(pNetRes, pNetRes, &cbBuffer, &lpSystem);
1730 if (dwError == NO_ERROR && pNetRes->dwDisplayType != RESOURCEDISPLAYTYPE_GENERIC)
1731 {
1732 return (pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE) &&
1733 (pNetRes->dwType == RESOURCETYPE_ANY || pNetRes->dwType == RESOURCETYPE_DISK);
1734 }
1735#else
1736 FIXME("UNC Server Share not yet supported - FAILING\n");
1737 return FALSE;
1738#endif
1739 }
1740
1741 if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES)
1742 return FALSE;
1743 return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
1744}
1745
1746/*************************************************************************
1747 * PathIsDirectoryW [SHLWAPI.@]
1748 *
1749 * See PathIsDirectoryA.
1750 */
1752{
1753 DWORD dwAttr;
1754
1755 TRACE("(%s)\n", debugstr_w(lpszPath));
1756
1757 if (!lpszPath || PathIsUNCServerW(lpszPath))
1758 return FALSE;
1759
1760 if (PathIsUNCServerShareW(lpszPath))
1761 {
1762#ifdef __REACTOS__
1763 LPWSTR lpSystem = NULL;
1764 BYTE buffer[1024] = {0};
1765 DWORD cbBuffer = sizeof(buffer);
1767 DWORD dwError;
1768
1769 pNetRes->dwScope = RESOURCE_GLOBALNET;
1770 pNetRes->dwType = RESOURCETYPE_ANY;
1771 pNetRes->lpRemoteName = (LPWSTR)lpszPath;
1772
1773 dwError = WNetGetResourceInformationW(pNetRes, pNetRes, &cbBuffer, &lpSystem);
1774 if (dwError == NO_ERROR && pNetRes->dwDisplayType != RESOURCEDISPLAYTYPE_GENERIC)
1775 {
1776 return (pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE) &&
1777 (pNetRes->dwType == RESOURCETYPE_ANY || pNetRes->dwType == RESOURCETYPE_DISK);
1778 }
1779#else
1780 FIXME("UNC Server Share not yet supported - FAILING\n");
1781 return FALSE;
1782#endif
1783 }
1784
1785 if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
1786 return FALSE;
1787 return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
1788}
1789
1790/*************************************************************************
1791 * PathFileExistsA [SHLWAPI.@]
1792 *
1793 * Determine if a file exists.
1794 *
1795 * PARAMS
1796 * lpszPath [I] Path to check
1797 *
1798 * RETURNS
1799 * TRUE If the file exists and is readable
1800 * FALSE Otherwise
1801 */
1803{
1804 UINT iPrevErrMode;
1805 DWORD dwAttr;
1806
1807 TRACE("(%s)\n",debugstr_a(lpszPath));
1808
1809 if (!lpszPath)
1810 return FALSE;
1811
1812 /* Prevent a dialog box if path is on a disk that has been ejected. */
1813 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
1814 dwAttr = GetFileAttributesA(lpszPath);
1815 SetErrorMode(iPrevErrMode);
1816 return dwAttr != INVALID_FILE_ATTRIBUTES;
1817}
1818
1819/*************************************************************************
1820 * PathFileExistsW [SHLWAPI.@]
1821 *
1822 * See PathFileExistsA.
1823 */
1825{
1826 UINT iPrevErrMode;
1827 DWORD dwAttr;
1828
1829 TRACE("(%s)\n",debugstr_w(lpszPath));
1830
1831 if (!lpszPath)
1832 return FALSE;
1833
1834 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
1835 dwAttr = GetFileAttributesW(lpszPath);
1836 SetErrorMode(iPrevErrMode);
1837 return dwAttr != INVALID_FILE_ATTRIBUTES;
1838}
1839
1840/*************************************************************************
1841 * PathFileExistsAndAttributesA [SHLWAPI.445]
1842 *
1843 * Determine if a file exists.
1844 *
1845 * PARAMS
1846 * lpszPath [I] Path to check
1847 * dwAttr [O] attributes of file
1848 *
1849 * RETURNS
1850 * TRUE If the file exists and is readable
1851 * FALSE Otherwise
1852 */
1854{
1855 UINT iPrevErrMode;
1856 DWORD dwVal = 0;
1857
1858 TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr);
1859
1860 if (dwAttr)
1861 *dwAttr = INVALID_FILE_ATTRIBUTES;
1862
1863 if (!lpszPath)
1864 return FALSE;
1865
1866 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
1867 dwVal = GetFileAttributesA(lpszPath);
1868 SetErrorMode(iPrevErrMode);
1869 if (dwAttr)
1870 *dwAttr = dwVal;
1871 return (dwVal != INVALID_FILE_ATTRIBUTES);
1872}
1873
1874/*************************************************************************
1875 * PathFileExistsAndAttributesW [SHLWAPI.446]
1876 *
1877 * See PathFileExistsA.
1878 */
1880{
1881 UINT iPrevErrMode;
1882 DWORD dwVal;
1883
1884 TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr);
1885
1886 if (!lpszPath)
1887 return FALSE;
1888
1889 iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
1890 dwVal = GetFileAttributesW(lpszPath);
1891 SetErrorMode(iPrevErrMode);
1892 if (dwAttr)
1893 *dwAttr = dwVal;
1894 return (dwVal != INVALID_FILE_ATTRIBUTES);
1895}
1896
1897/*************************************************************************
1898 * PathMatchSingleMaskA [internal]
1899 */
1901{
1902 while (*name && *mask && *mask!=';')
1903 {
1904 if (*mask == '*')
1905 {
1906 do
1907 {
1909 return TRUE; /* try substrings */
1910 } while (*name++);
1911 return FALSE;
1912 }
1913
1914 if (toupper(*mask) != toupper(*name) && *mask != '?')
1915 return FALSE;
1916
1917 name = CharNextA(name);
1918 mask = CharNextA(mask);
1919 }
1920
1921 if (!*name)
1922 {
1923 while (*mask == '*')
1924 mask++;
1925 if (!*mask || *mask == ';')
1926 return TRUE;
1927 }
1928 return FALSE;
1929}
1930
1931/*************************************************************************
1932 * PathMatchSingleMaskW [internal]
1933 */
1935{
1936 while (*name && *mask && *mask != ';')
1937 {
1938 if (*mask == '*')
1939 {
1940 do
1941 {
1943 return TRUE; /* try substrings */
1944 } while (*name++);
1945 return FALSE;
1946 }
1947
1948 if (toupperW(*mask) != toupperW(*name) && *mask != '?')
1949 return FALSE;
1950
1951 name++;
1952 mask++;
1953 }
1954 if (!*name)
1955 {
1956 while (*mask == '*')
1957 mask++;
1958 if (!*mask || *mask == ';')
1959 return TRUE;
1960 }
1961 return FALSE;
1962}
1963
1964/*************************************************************************
1965 * PathMatchSpecA [SHLWAPI.@]
1966 *
1967 * Determine if a path matches one or more search masks.
1968 *
1969 * PARAMS
1970 * lpszPath [I] Path to check
1971 * lpszMask [I] Search mask(s)
1972 *
1973 * RETURNS
1974 * TRUE If lpszPath is valid and is matched
1975 * FALSE Otherwise
1976 *
1977 * NOTES
1978 * Multiple search masks may be given if they are separated by ";". The
1979 * pattern "*.*" is treated specially in that it matches all paths (for
1980 * backwards compatibility with DOS).
1981 */
1983{
1984 TRACE("(%s,%s)\n", lpszPath, lpszMask);
1985
1986 if (!lstrcmpA(lpszMask, "*.*"))
1987 return TRUE; /* Matches every path */
1988
1989 while (*lpszMask)
1990 {
1991 while (*lpszMask == ' ')
1992 lpszMask++; /* Eat leading spaces */
1993
1994 if (PathMatchSingleMaskA(lpszPath, lpszMask))
1995 return TRUE; /* Matches the current mask */
1996
1997 while (*lpszMask && *lpszMask != ';')
1998 lpszMask = CharNextA(lpszMask); /* masks separated by ';' */
1999
2000 if (*lpszMask == ';')
2001 lpszMask++;
2002 }
2003 return FALSE;
2004}
2005
2006/*************************************************************************
2007 * PathMatchSpecW [SHLWAPI.@]
2008 *
2009 * See PathMatchSpecA.
2010 */
2012{
2013 static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' };
2014
2015 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask));
2016
2017 if (!lstrcmpW(lpszMask, szStarDotStar))
2018 return TRUE; /* Matches every path */
2019
2020 while (*lpszMask)
2021 {
2022 while (*lpszMask == ' ')
2023 lpszMask++; /* Eat leading spaces */
2024
2025 if (PathMatchSingleMaskW(lpszPath, lpszMask))
2026 return TRUE; /* Matches the current path */
2027
2028 while (*lpszMask && *lpszMask != ';')
2029 lpszMask++; /* masks separated by ';' */
2030
2031 if (*lpszMask == ';')
2032 lpszMask++;
2033 }
2034 return FALSE;
2035}
2036
2037/*************************************************************************
2038 * PathIsSameRootA [SHLWAPI.@]
2039 *
2040 * Determine if two paths share the same root.
2041 *
2042 * PARAMS
2043 * lpszPath1 [I] Source path
2044 * lpszPath2 [I] Path to compare with
2045 *
2046 * RETURNS
2047 * TRUE If both paths are valid and share the same root.
2048 * FALSE If either path is invalid or the paths do not share the same root.
2049 */
2051{
2052 LPCSTR lpszStart;
2053 int dwLen;
2054
2055 TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2));
2056
2057 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1)))
2058 return FALSE;
2059
2060 dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1;
2061 if (lpszStart - lpszPath1 > dwLen)
2062 return FALSE; /* Paths not common up to length of the root */
2063 return TRUE;
2064}
2065
2066/*************************************************************************
2067 * PathIsSameRootW [SHLWAPI.@]
2068 *
2069 * See PathIsSameRootA.
2070 */
2072{
2073 LPCWSTR lpszStart;
2074 int dwLen;
2075
2076 TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
2077
2078 if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1)))
2079 return FALSE;
2080
2081 dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1;
2082 if (lpszStart - lpszPath1 > dwLen)
2083 return FALSE; /* Paths not common up to length of the root */
2084 return TRUE;
2085}
2086
2087/*************************************************************************
2088 * PathIsContentTypeA [SHLWAPI.@]
2089 *
2090 * Determine if a file is of a given registered content type.
2091 *
2092 * PARAMS
2093 * lpszPath [I] File to check
2094 * lpszContentType [I] Content type to check for
2095 *
2096 * RETURNS
2097 * TRUE If lpszPath is a given registered content type,
2098 * FALSE Otherwise.
2099 *
2100 * NOTES
2101 * This function looks up the registered content type for lpszPath. If
2102 * a content type is registered, it is compared (case insensitively) to
2103 * lpszContentType. Only if this matches does the function succeed.
2104 */
2105BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType)
2106{
2107 LPCSTR szExt;
2108 DWORD dwDummy;
2109 char szBuff[MAX_PATH];
2110
2111 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType));
2112
2113 if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt &&
2114 !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type",
2115 REG_NONE, szBuff, &dwDummy) &&
2116 !strcasecmp(lpszContentType, szBuff))
2117 {
2118 return TRUE;
2119 }
2120 return FALSE;
2121}
2122
2123/*************************************************************************
2124 * PathIsContentTypeW [SHLWAPI.@]
2125 *
2126 * See PathIsContentTypeA.
2127 */
2129{
2130 static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' };
2131 LPCWSTR szExt;
2132 DWORD dwDummy;
2133 WCHAR szBuff[MAX_PATH];
2134
2135 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType));
2136
2137 if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt &&
2138 !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType,
2139 REG_NONE, szBuff, &dwDummy) &&
2140 !strcmpiW(lpszContentType, szBuff))
2141 {
2142 return TRUE;
2143 }
2144 return FALSE;
2145}
2146
2147/*************************************************************************
2148 * PathIsFileSpecA [SHLWAPI.@]
2149 *
2150 * Determine if a path is a file specification.
2151 *
2152 * PARAMS
2153 * lpszPath [I] Path to check
2154 *
2155 * RETURNS
2156 * TRUE If lpszPath is a file specification (i.e. Contains no directories).
2157 * FALSE Otherwise.
2158 */
2160{
2161 TRACE("(%s)\n", debugstr_a(lpszPath));
2162
2163 if (!lpszPath)
2164 return FALSE;
2165
2166 while (*lpszPath)
2167 {
2168 if (*lpszPath == '\\' || *lpszPath == ':')
2169 return FALSE;
2170 lpszPath = CharNextA(lpszPath);
2171 }
2172 return TRUE;
2173}
2174
2175/*************************************************************************
2176 * PathIsFileSpecW [SHLWAPI.@]
2177 *
2178 * See PathIsFileSpecA.
2179 */
2181{
2182 TRACE("(%s)\n", debugstr_w(lpszPath));
2183
2184 if (!lpszPath)
2185 return FALSE;
2186
2187 while (*lpszPath)
2188 {
2189 if (*lpszPath == '\\' || *lpszPath == ':')
2190 return FALSE;
2191 lpszPath++;
2192 }
2193 return TRUE;
2194}
2195
2196/*************************************************************************
2197 * PathIsPrefixA [SHLWAPI.@]
2198 *
2199 * Determine if a path is a prefix of another.
2200 *
2201 * PARAMS
2202 * lpszPrefix [I] Prefix
2203 * lpszPath [I] Path to check
2204 *
2205 * RETURNS
2206 * TRUE If lpszPath has lpszPrefix as its prefix,
2207 * FALSE If either path is NULL or lpszPrefix is not a prefix
2208 */
2209BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath)
2210{
2211 TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath));
2212
2213 if (lpszPrefix && lpszPath &&
2214 PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix))
2215 return TRUE;
2216 return FALSE;
2217}
2218
2219/*************************************************************************
2220 * PathIsPrefixW [SHLWAPI.@]
2221 *
2222 * See PathIsPrefixA.
2223 */
2225{
2226 TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath));
2227
2228 if (lpszPrefix && lpszPath &&
2229 PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix))
2230 return TRUE;
2231 return FALSE;
2232}
2233
2234/*************************************************************************
2235 * PathIsSystemFolderA [SHLWAPI.@]
2236 *
2237 * Determine if a path or file attributes are a system folder.
2238 *
2239 * PARAMS
2240 * lpszPath [I] Path to check.
2241 * dwAttrib [I] Attributes to check, if lpszPath is NULL.
2242 *
2243 * RETURNS
2244 * TRUE If lpszPath or dwAttrib are a system folder.
2245 * FALSE If GetFileAttributesA() fails or neither parameter is a system folder.
2246 */
2248{
2249 TRACE("(%s,0x%08x)\n", debugstr_a(lpszPath), dwAttrib);
2250
2251 if (lpszPath && *lpszPath)
2252 dwAttrib = GetFileAttributesA(lpszPath);
2253
2254 if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
2256 return FALSE;
2257 return TRUE;
2258}
2259
2260/*************************************************************************
2261 * PathIsSystemFolderW [SHLWAPI.@]
2262 *
2263 * See PathIsSystemFolderA.
2264 */
2266{
2267 TRACE("(%s,0x%08x)\n", debugstr_w(lpszPath), dwAttrib);
2268
2269 if (lpszPath && *lpszPath)
2270 dwAttrib = GetFileAttributesW(lpszPath);
2271
2272 if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
2274 return FALSE;
2275 return TRUE;
2276}
2277
2278/*************************************************************************
2279 * PathIsUNCA [SHLWAPI.@]
2280 *
2281 * Determine if a path is in UNC format.
2282 *
2283 * PARAMS
2284 * lpszPath [I] Path to check
2285 *
2286 * RETURNS
2287 * TRUE: The path is UNC.
2288 * FALSE: The path is not UNC or is NULL.
2289 */
2291{
2292 TRACE("(%s)\n",debugstr_a(lpszPath));
2293
2294/*
2295 * On Windows 2003, tests show that strings starting with "\\?" are
2296 * considered UNC, while on Windows Vista+ this is not the case anymore.
2297 */
2298// #ifdef __REACTOS__
2299#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
2300 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
2301#else
2302 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'))
2303#endif
2304 return TRUE;
2305 return FALSE;
2306}
2307
2308/*************************************************************************
2309 * PathIsUNCW [SHLWAPI.@]
2310 *
2311 * See PathIsUNCA.
2312 */
2314{
2315 TRACE("(%s)\n",debugstr_w(lpszPath));
2316
2317/*
2318 * On Windows 2003, tests show that strings starting with "\\?" are
2319 * considered UNC, while on Windows Vista+ this is not the case anymore.
2320 */
2321// #ifdef __REACTOS__
2322#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
2323 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
2324#else
2325 if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'))
2326#endif
2327 return TRUE;
2328 return FALSE;
2329}
2330
2331/*************************************************************************
2332 * PathIsUNCServerA [SHLWAPI.@]
2333 *
2334 * Determine if a path is a UNC server name ("\\SHARENAME").
2335 *
2336 * PARAMS
2337 * lpszPath [I] Path to check.
2338 *
2339 * RETURNS
2340 * TRUE If lpszPath is a valid UNC server name.
2341 * FALSE Otherwise.
2342 *
2343 * NOTES
2344 * This routine is bug compatible with Win32: Server names with a
2345 * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly.
2346 * Fixing this bug may break other shlwapi functions!
2347 */
2349{
2350 TRACE("(%s)\n", debugstr_a(lpszPath));
2351
2352 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
2353 {
2354 while (*lpszPath)
2355 {
2356 if (*lpszPath == '\\')
2357 return FALSE;
2358 lpszPath = CharNextA(lpszPath);
2359 }
2360 return TRUE;
2361 }
2362 return FALSE;
2363}
2364
2365/*************************************************************************
2366 * PathIsUNCServerW [SHLWAPI.@]
2367 *
2368 * See PathIsUNCServerA.
2369 */
2371{
2372 TRACE("(%s)\n", debugstr_w(lpszPath));
2373
2374 if (lpszPath && lpszPath[0] == '\\' && lpszPath[1] == '\\')
2375 {
2376 return !strchrW( lpszPath + 2, '\\' );
2377 }
2378 return FALSE;
2379}
2380
2381/*************************************************************************
2382 * PathIsUNCServerShareA [SHLWAPI.@]
2383 *
2384 * Determine if a path is a UNC server share ("\\SHARENAME\SHARE").
2385 *
2386 * PARAMS
2387 * lpszPath [I] Path to check.
2388 *
2389 * RETURNS
2390 * TRUE If lpszPath is a valid UNC server share.
2391 * FALSE Otherwise.
2392 *
2393 * NOTES
2394 * This routine is bug compatible with Win32: Server shares with a
2395 * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly.
2396 * Fixing this bug may break other shlwapi functions!
2397 */
2399{
2400 TRACE("(%s)\n", debugstr_a(lpszPath));
2401
2402 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
2403 {
2404 BOOL bSeenSlash = FALSE;
2405 while (*lpszPath)
2406 {
2407 if (*lpszPath == '\\')
2408 {
2409 if (bSeenSlash)
2410 return FALSE;
2411 bSeenSlash = TRUE;
2412 }
2413 lpszPath = CharNextA(lpszPath);
2414 }
2415 return bSeenSlash;
2416 }
2417 return FALSE;
2418}
2419
2420/*************************************************************************
2421 * PathIsUNCServerShareW [SHLWAPI.@]
2422 *
2423 * See PathIsUNCServerShareA.
2424 */
2426{
2427 TRACE("(%s)\n", debugstr_w(lpszPath));
2428
2429 if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
2430 {
2431 BOOL bSeenSlash = FALSE;
2432 while (*lpszPath)
2433 {
2434 if (*lpszPath == '\\')
2435 {
2436 if (bSeenSlash)
2437 return FALSE;
2438 bSeenSlash = TRUE;
2439 }
2440 lpszPath++;
2441 }
2442 return bSeenSlash;
2443 }
2444 return FALSE;
2445}
2446
2447/*************************************************************************
2448 * PathCanonicalizeA [SHLWAPI.@]
2449 *
2450 * Convert a path to its canonical form.
2451 *
2452 * PARAMS
2453 * lpszBuf [O] Output path
2454 * lpszPath [I] Path to canonicalize
2455 *
2456 * RETURNS
2457 * Success: TRUE. lpszBuf contains the output path,
2458 * Failure: FALSE, If input path is invalid. lpszBuf is undefined
2459 */
2461{
2462 BOOL bRet = FALSE;
2463
2464 TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath));
2465
2466 if (lpszBuf)
2467 *lpszBuf = '\0';
2468
2469 if (!lpszBuf || !lpszPath)
2471 else
2472 {
2474 WCHAR szBuff[MAX_PATH];
2475 int ret = MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
2476
2477 if (!ret) {
2478 WARN("Failed to convert string to widechar (too long?), LE %d.\n", GetLastError());
2479 return FALSE;
2480 }
2481 bRet = PathCanonicalizeW(szBuff, szPath);
2482 WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
2483 }
2484 return bRet;
2485}
2486
2487
2488/*************************************************************************
2489 * PathCanonicalizeW [SHLWAPI.@]
2490 *
2491 * See PathCanonicalizeA.
2492 */
2494{
2495 LPWSTR lpszDst = lpszBuf;
2496 LPCWSTR lpszSrc = lpszPath;
2497
2498 TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath));
2499
2500 if (lpszBuf)
2501 *lpszDst = '\0';
2502
2503 if (!lpszBuf || !lpszPath)
2504 {
2506 return FALSE;
2507 }
2508
2509 if (!*lpszPath)
2510 {
2511 *lpszBuf++ = '\\';
2512 *lpszBuf = '\0';
2513 return TRUE;
2514 }
2515
2516 /* Copy path root */
2517 if (*lpszSrc == '\\')
2518 {
2519 *lpszDst++ = *lpszSrc++;
2520 }
2521 else if (*lpszSrc && lpszSrc[1] == ':')
2522 {
2523 /* X:\ */
2524 *lpszDst++ = *lpszSrc++;
2525 *lpszDst++ = *lpszSrc++;
2526 if (*lpszSrc == '\\')
2527 *lpszDst++ = *lpszSrc++;
2528 }
2529
2530 /* Canonicalize the rest of the path */
2531 while (*lpszSrc)
2532 {
2533 if (*lpszSrc == '.')
2534 {
2535 if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':'))
2536 {
2537 lpszSrc += 2; /* Skip .\ */
2538 }
2539 else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\'))
2540 {
2541 /* \.. backs up a directory, over the root if it has no \ following X:.
2542 * .. is ignored if it would remove a UNC server name or initial \\
2543 */
2544 if (lpszDst != lpszBuf)
2545 {
2546 *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
2547 if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' &&
2548 (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2))
2549 {
2550 if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':'))
2551 {
2552 lpszDst -= 2;
2553 while (lpszDst > lpszBuf && *lpszDst != '\\')
2554 lpszDst--;
2555 if (*lpszDst == '\\')
2556 lpszDst++; /* Reset to last '\' */
2557 else
2558 lpszDst = lpszBuf; /* Start path again from new root */
2559 }
2560 else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf))
2561 lpszDst -= 2;
2562 }
2563 while (lpszDst > lpszBuf && *lpszDst != '\\')
2564 lpszDst--;
2565 if (lpszDst == lpszBuf)
2566 {
2567 *lpszDst++ = '\\';
2568 lpszSrc++;
2569 }
2570 }
2571 lpszSrc += 2; /* Skip .. in src path */
2572 }
2573 else
2574 *lpszDst++ = *lpszSrc++;
2575 }
2576 else
2577 *lpszDst++ = *lpszSrc++;
2578 }
2579 /* Append \ to naked drive specs */
2580 if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':')
2581 *lpszDst++ = '\\';
2582 *lpszDst++ = '\0';
2583 return TRUE;
2584}
2585
2586/*************************************************************************
2587 * PathFindNextComponentA [SHLWAPI.@]
2588 *
2589 * Find the next component in a path.
2590 *
2591 * PARAMS
2592 * lpszPath [I] Path to find next component in
2593 *
2594 * RETURNS
2595 * Success: A pointer to the next component, or the end of the string.
2596 * Failure: NULL, If lpszPath is invalid
2597 *
2598 * NOTES
2599 * A 'component' is either a backslash character (\‍) or UNC marker (\\‍).
2600 * Because of this, relative paths (e.g "c:foo") are regarded as having
2601 * only one component.
2602 */
2604{
2605 LPSTR lpszSlash;
2606
2607 TRACE("(%s)\n", debugstr_a(lpszPath));
2608
2609 if(!lpszPath || !*lpszPath)
2610 return NULL;
2611
2612 if ((lpszSlash = StrChrA(lpszPath, '\\')))
2613 {
2614 if (lpszSlash[1] == '\\')
2615 lpszSlash++;
2616 return lpszSlash + 1;
2617 }
2618 return (LPSTR)lpszPath + strlen(lpszPath);
2619}
2620
2621/*************************************************************************
2622 * PathFindNextComponentW [SHLWAPI.@]
2623 *
2624 * See PathFindNextComponentA.
2625 */
2627{
2628 LPWSTR lpszSlash;
2629
2630 TRACE("(%s)\n", debugstr_w(lpszPath));
2631
2632 if(!lpszPath || !*lpszPath)
2633 return NULL;
2634
2635 if ((lpszSlash = StrChrW(lpszPath, '\\')))
2636 {
2637 if (lpszSlash[1] == '\\')
2638 lpszSlash++;
2639 return lpszSlash + 1;
2640 }
2641 return (LPWSTR)lpszPath + strlenW(lpszPath);
2642}
2643
2644/*************************************************************************
2645 * PathAddExtensionA [SHLWAPI.@]
2646 *
2647 * Add a file extension to a path
2648 *
2649 * PARAMS
2650 * lpszPath [I/O] Path to add extension to
2651 * lpszExtension [I] Extension to add to lpszPath
2652 *
2653 * RETURNS
2654 * TRUE If the path was modified,
2655 * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an
2656 * extension already, or the new path length is too big.
2657 *
2658 * FIXME
2659 * What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k
2660 * does not do this, so the behaviour was removed.
2661 */
2662BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension)
2663{
2664 size_t dwLen;
2665
2666 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension));
2667
2668 if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath)))
2669 return FALSE;
2670
2671 dwLen = strlen(lpszPath);
2672
2673 if (dwLen + strlen(lpszExtension) >= MAX_PATH)
2674 return FALSE;
2675
2676 strcpy(lpszPath + dwLen, lpszExtension);
2677 return TRUE;
2678}
2679
2680/*************************************************************************
2681 * PathAddExtensionW [SHLWAPI.@]
2682 *
2683 * See PathAddExtensionA.
2684 */
2686{
2687 size_t dwLen;
2688
2689 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension));
2690
2691 if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath)))
2692 return FALSE;
2693
2694 dwLen = strlenW(lpszPath);
2695
2696 if (dwLen + strlenW(lpszExtension) >= MAX_PATH)
2697 return FALSE;
2698
2699 strcpyW(lpszPath + dwLen, lpszExtension);
2700 return TRUE;
2701}
2702
2703/*************************************************************************
2704 * PathMakePrettyA [SHLWAPI.@]
2705 *
2706 * Convert an uppercase DOS filename into lowercase.
2707 *
2708 * PARAMS
2709 * lpszPath [I/O] Path to convert.
2710 *
2711 * RETURNS
2712 * TRUE If the path was an uppercase DOS path and was converted,
2713 * FALSE Otherwise.
2714 */
2716{
2717 LPSTR pszIter = lpszPath;
2718
2719 TRACE("(%s)\n", debugstr_a(lpszPath));
2720
2721 if (!pszIter)
2722 return FALSE;
2723
2724 if (*pszIter)
2725 {
2726 do
2727 {
2728 if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
2729 return FALSE; /* Not DOS path */
2730 pszIter++;
2731 } while (*pszIter);
2732 pszIter = lpszPath + 1;
2733 while (*pszIter)
2734 {
2735 *pszIter = tolower(*pszIter);
2736 pszIter++;
2737 }
2738 }
2739 return TRUE;
2740}
2741
2742/*************************************************************************
2743 * PathMakePrettyW [SHLWAPI.@]
2744 *
2745 * See PathMakePrettyA.
2746 */
2748{
2749 LPWSTR pszIter = lpszPath;
2750
2751 TRACE("(%s)\n", debugstr_w(lpszPath));
2752
2753 if (!pszIter)
2754 return FALSE;
2755
2756 if (*pszIter)
2757 {
2758 do
2759 {
2760 if (islowerW(*pszIter))
2761 return FALSE; /* Not DOS path */
2762 pszIter++;
2763 } while (*pszIter);
2764 pszIter = lpszPath + 1;
2765 while (*pszIter)
2766 {
2767 *pszIter = tolowerW(*pszIter);
2768 pszIter++;
2769 }
2770 }
2771 return TRUE;
2772}
2773
2774/*************************************************************************
2775 * PathCommonPrefixA [SHLWAPI.@]
2776 *
2777 * Determine the length of the common prefix between two paths.
2778 *
2779 * PARAMS
2780 * lpszFile1 [I] First path for comparison
2781 * lpszFile2 [I] Second path for comparison
2782 * achPath [O] Destination for common prefix string
2783 *
2784 * RETURNS
2785 * The length of the common prefix. This is 0 if there is no common
2786 * prefix between the paths or if any parameters are invalid. If the prefix
2787 * is non-zero and achPath is not NULL, achPath is filled with the common
2788 * part of the prefix and NUL terminated.
2789 *
2790 * NOTES
2791 * A common prefix of 2 is always returned as 3. It is thus possible for
2792 * the length returned to be invalid (i.e. Longer than one or both of the
2793 * strings given as parameters). This Win32 behaviour has been implemented
2794 * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls.
2795 * To work around this when using this function, always check that the byte
2796 * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix.
2797 */
2798int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath)
2799{
2800 size_t iLen = 0;
2801 LPCSTR lpszIter1 = lpszFile1;
2802 LPCSTR lpszIter2 = lpszFile2;
2803
2804 TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath);
2805
2806 if (achPath)
2807 *achPath = '\0';
2808
2809 if (!lpszFile1 || !lpszFile2)
2810 return 0;
2811
2812 /* Handle roots first */
2813 if (PathIsUNCA(lpszFile1))
2814 {
2815 if (!PathIsUNCA(lpszFile2))
2816 return 0;
2817 lpszIter1 += 2;
2818 lpszIter2 += 2;
2819 }
2820 else if (PathIsUNCA(lpszFile2))
2821 return 0; /* Know already lpszFile1 is not UNC */
2822
2823 do
2824 {
2825 /* Update len */
2826 if ((!*lpszIter1 || *lpszIter1 == '\\') &&
2827 (!*lpszIter2 || *lpszIter2 == '\\'))
2828 iLen = lpszIter1 - lpszFile1; /* Common to this point */
2829
2830 if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2)))
2831 break; /* Strings differ at this point */
2832
2833 lpszIter1++;
2834 lpszIter2++;
2835 } while (1);
2836
2837 if (iLen == 2)
2838 iLen++; /* Feature/Bug compatible with Win32 */
2839
2840 if (iLen && achPath)
2841 {
2842 memcpy(achPath,lpszFile1,iLen);
2843 achPath[iLen] = '\0';
2844 }
2845 return iLen;
2846}
2847
2848/*************************************************************************
2849 * PathCommonPrefixW [SHLWAPI.@]
2850 *
2851 * See PathCommonPrefixA.
2852 */
2853int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath)
2854{
2855 size_t iLen = 0;
2856 LPCWSTR lpszIter1 = lpszFile1;
2857 LPCWSTR lpszIter2 = lpszFile2;
2858
2859 TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath);
2860
2861 if (achPath)
2862 *achPath = '\0';
2863
2864 if (!lpszFile1 || !lpszFile2)
2865 return 0;
2866
2867 /* Handle roots first */
2868 if (PathIsUNCW(lpszFile1))
2869 {
2870 if (!PathIsUNCW(lpszFile2))
2871 return 0;
2872 lpszIter1 += 2;
2873 lpszIter2 += 2;
2874 }
2875 else if (PathIsUNCW(lpszFile2))
2876 return 0; /* Know already lpszFile1 is not UNC */
2877
2878 do
2879 {
2880 /* Update len */
2881 if ((!*lpszIter1 || *lpszIter1 == '\\') &&
2882 (!*lpszIter2 || *lpszIter2 == '\\'))
2883 iLen = lpszIter1 - lpszFile1; /* Common to this point */
2884
2885 if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2)))
2886 break; /* Strings differ at this point */
2887
2888 lpszIter1++;
2889 lpszIter2++;
2890 } while (1);
2891
2892 if (iLen == 2)
2893 iLen++; /* Feature/Bug compatible with Win32 */
2894
2895 if (iLen && achPath)
2896 {
2897 memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR));
2898 achPath[iLen] = '\0';
2899 }
2900 return iLen;
2901}
2902
2903/*************************************************************************
2904 * PathCompactPathA [SHLWAPI.@]
2905 *
2906 * Make a path fit into a given width when printed to a DC.
2907 *
2908 * PARAMS
2909 * hDc [I] Destination DC
2910 * lpszPath [I/O] Path to be printed to hDc
2911 * dx [I] Desired width
2912 *
2913 * RETURNS
2914 * TRUE If the path was modified/went well.
2915 * FALSE Otherwise.
2916 */
2918{
2919 BOOL bRet = FALSE;
2920
2921 TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx);
2922
2923 if (lpszPath)
2924 {
2927 bRet = PathCompactPathW(hDC, szPath, dx);
2928 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
2929 }
2930 return bRet;
2931}
2932
2933/*************************************************************************
2934 * PathCompactPathW [SHLWAPI.@]
2935 *
2936 * See PathCompactPathA.
2937 */
2939{
2940 static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
2941 BOOL bRet = TRUE;
2942 HDC hdc = 0;
2944 SIZE size;
2945 DWORD dwLen;
2946
2947 TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx);
2948
2949 if (!lpszPath)
2950 return FALSE;
2951
2952 if (!hDC)
2953 hdc = hDC = GetDC(0);
2954
2955 /* Get the length of the whole path */
2956 dwLen = strlenW(lpszPath);
2957 GetTextExtentPointW(hDC, lpszPath, dwLen, &size);
2958
2959 if ((UINT)size.cx > dx)
2960 {
2961 /* Path too big, must reduce it */
2962 LPWSTR sFile;
2963 DWORD dwEllipsesLen = 0, dwPathLen = 0;
2964
2965 sFile = PathFindFileNameW(lpszPath);
2966 if (sFile != lpszPath) sFile--;
2967
2968 /* Get the size of ellipses */
2969 GetTextExtentPointW(hDC, szEllipses, 3, &size);
2970 dwEllipsesLen = size.cx;
2971 /* Get the size of the file name */
2972 GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size);
2973 dwPathLen = size.cx;
2974
2975 if (sFile != lpszPath)
2976 {
2977 LPWSTR sPath = sFile;
2978 BOOL bEllipses = FALSE;
2979
2980 /* The path includes a file name. Include as much of the path prior to
2981 * the file name as possible, allowing for the ellipses, e.g:
2982 * c:\some very long path\filename ==> c:\some v...\filename
2983 */
2984 lstrcpynW(buff, sFile, MAX_PATH);
2985
2986 do
2987 {
2988 DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen;
2989
2990 GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size);
2991 dwTotalLen += size.cx;
2992 if (dwTotalLen <= dx)
2993 break;
2994 sPath--;
2995 if (!bEllipses)
2996 {
2997 bEllipses = TRUE;
2998 sPath -= 2;
2999 }
3000 } while (sPath > lpszPath);
3001
3002 if (sPath > lpszPath)
3003 {
3004 if (bEllipses)
3005 {
3006 strcpyW(sPath, szEllipses);
3007 strcpyW(sPath+3, buff);
3008 }
3009 bRet = TRUE;
3010 goto end;
3011 }
3012 strcpyW(lpszPath, szEllipses);
3013 strcpyW(lpszPath+3, buff);
3014 bRet = FALSE;
3015 goto end;
3016 }
3017
3018 /* Trim the path by adding ellipses to the end, e.g:
3019 * A very long file name.txt ==> A very...
3020 */
3021 dwLen = strlenW(lpszPath);
3022
3023 if (dwLen > MAX_PATH - 3)
3024 dwLen = MAX_PATH - 3;
3025 lstrcpynW(buff, sFile, dwLen);
3026
3027 do {
3028 dwLen--;
3029 GetTextExtentPointW(hDC, buff, dwLen, &size);
3030 } while (dwLen && size.cx + dwEllipsesLen > dx);
3031
3032 if (!dwLen)
3033 {
3034 DWORD dwWritten = 0;
3035
3036 dwEllipsesLen /= 3; /* Size of a single '.' */
3037
3038 /* Write as much of the Ellipses string as possible */
3039 while (dwWritten + dwEllipsesLen < dx && dwLen < 3)
3040 {
3041 *lpszPath++ = '.';
3042 dwWritten += dwEllipsesLen;
3043 dwLen++;
3044 }
3045 *lpszPath = '\0';
3046 bRet = FALSE;
3047 }
3048 else
3049 {
3050 strcpyW(buff + dwLen, szEllipses);
3051 strcpyW(lpszPath, buff);
3052 }
3053 }
3054
3055end:
3056 if (hdc)
3057 ReleaseDC(0, hdc);
3058
3059 return bRet;
3060}
3061
3062/*************************************************************************
3063 * PathGetCharTypeA [SHLWAPI.@]
3064 *
3065 * Categorise a character from a file path.
3066 *
3067 * PARAMS
3068 * ch [I] Character to get the type of
3069 *
3070 * RETURNS
3071 * A set of GCT_ bit flags (from "shlwapi.h") indicating the character type.
3072 */
3074{
3075 return PathGetCharTypeW(ch);
3076}
3077
3078/*************************************************************************
3079 * PathGetCharTypeW [SHLWAPI.@]
3080 *
3081 * See PathGetCharTypeA.
3082 */
3084{
3085 UINT flags = 0;
3086
3087 TRACE("(%d)\n", ch);
3088
3089 if (!ch || ch < ' ' || ch == '<' || ch == '>' ||
3090 ch == '"' || ch == '|' || ch == '/')
3091 flags = GCT_INVALID; /* Invalid */
3092 else if (ch == '*' || ch=='?')
3093 flags = GCT_WILD; /* Wildchars */
3094 else if ((ch == '\\') || (ch == ':'))
3095 return GCT_SEPARATOR; /* Path separators */
3096 else
3097 {
3098 if (ch < 126)
3099 {
3100 if (((ch & 0x1) && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' ||
3101 ch == '.' || ch == '@' || ch == '^' ||
3102 ch == '\'' || ch == 130 || ch == '`')
3103 flags |= GCT_SHORTCHAR; /* All these are valid for DOS */
3104 }
3105 else
3106 flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */
3107 flags |= GCT_LFNCHAR; /* Valid for long file names */
3108 }
3109 return flags;
3110}
3111
3112/*************************************************************************
3113 * SHLWAPI_UseSystemForSystemFolders
3114 *
3115 * Internal helper for PathMakeSystemFolderW.
3116 */
3118{
3119 static BOOL bCheckedReg = FALSE;
3120 static BOOL bUseSystemForSystemFolders = FALSE;
3121
3122 if (!bCheckedReg)
3123 {
3124 bCheckedReg = TRUE;
3125
3126 /* Key tells Win what file attributes to use on system folders */
3128 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
3129 "UseSystemForSystemFolders", 0, 0, 0))
3130 bUseSystemForSystemFolders = TRUE;
3131 }
3132 return bUseSystemForSystemFolders;
3133}
3134
3135/*************************************************************************
3136 * PathMakeSystemFolderA [SHLWAPI.@]
3137 *
3138 * Set system folder attribute for a path.
3139 *
3140 * PARAMS
3141 * lpszPath [I] The path to turn into a system folder
3142 *
3143 * RETURNS
3144 * TRUE If the path was changed to/already was a system folder
3145 * FALSE If the path is invalid or SetFileAttributesA() fails
3146 */
3148{
3149 BOOL bRet = FALSE;
3150
3151 TRACE("(%s)\n", debugstr_a(lpszPath));
3152
3153 if (lpszPath && *lpszPath)
3154 {
3158 }
3159 return bRet;
3160}
3161
3162/*************************************************************************
3163 * PathMakeSystemFolderW [SHLWAPI.@]
3164 *
3165 * See PathMakeSystemFolderA.
3166 */
3168{
3169 DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr;
3171
3172 TRACE("(%s)\n", debugstr_w(lpszPath));
3173
3174 if (!lpszPath || !*lpszPath)
3175 return FALSE;
3176
3177 /* If the directory is already a system directory, don't do anything */
3179 if (!strcmpW(buff, lpszPath))
3180 return TRUE;
3181
3183 if (!strcmpW(buff, lpszPath))
3184 return TRUE;
3185
3186 /* "UseSystemForSystemFolders" Tells Win what attributes to use */
3188 dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM;
3189
3190 if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
3191 return FALSE;
3192
3193 /* Change file attributes to system attributes */
3195 return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr);
3196}
3197
3198/*************************************************************************
3199 * PathRenameExtensionA [SHLWAPI.@]
3200 *
3201 * Swap the file extension in a path with another extension.
3202 *
3203 * PARAMS
3204 * lpszPath [I/O] Path to swap the extension in
3205 * lpszExt [I] The new extension
3206 *
3207 * RETURNS
3208 * TRUE if lpszPath was modified,
3209 * FALSE if lpszPath or lpszExt is NULL, or the new path is too long
3210 */
3212{
3213 LPSTR lpszExtension;
3214
3215 TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt));
3216
3217 lpszExtension = PathFindExtensionA(lpszPath);
3218
3219 if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH))
3220 return FALSE;
3221
3222 strcpy(lpszExtension, lpszExt);
3223 return TRUE;
3224}
3225
3226/*************************************************************************
3227 * PathRenameExtensionW [SHLWAPI.@]
3228 *
3229 * See PathRenameExtensionA.
3230 */
3232{
3233 LPWSTR lpszExtension;
3234
3235 TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt));
3236
3237 lpszExtension = PathFindExtensionW(lpszPath);
3238
3239 if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH))
3240 return FALSE;
3241
3242 strcpyW(lpszExtension, lpszExt);
3243 return TRUE;
3244}
3245
3246/*************************************************************************
3247 * PathSearchAndQualifyA [SHLWAPI.@]
3248 *
3249 * Determine if a given path is correct and fully qualified.
3250 *
3251 * PARAMS
3252 * lpszPath [I] Path to check
3253 * lpszBuf [O] Output for correct path
3254 * cchBuf [I] Size of lpszBuf
3255 *
3256 * RETURNS
3257 * Unknown.
3258 */
3260{
3261 TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
3262
3263 if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
3264 return TRUE;
3265 return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL);
3266}
3267
3268/*************************************************************************
3269 * PathSearchAndQualifyW [SHLWAPI.@]
3270 *
3271 * See PathSearchAndQualifyA.
3272 */
3274{
3275 TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
3276
3277 if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
3278 return TRUE;
3279 return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL);
3280}
3281
3282/*************************************************************************
3283 * PathSkipRootA [SHLWAPI.@]
3284 *
3285 * Return the portion of a path following the drive letter or mount point.
3286 *
3287 * PARAMS
3288 * lpszPath [I] The path to skip on
3289 *
3290 * RETURNS
3291 * Success: A pointer to the next character after the root.
3292 * Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string.
3293 */
3295{
3296 TRACE("(%s)\n", debugstr_a(lpszPath));
3297
3298 if (!lpszPath || !*lpszPath)
3299 return NULL;
3300
3301 if (*lpszPath == '\\' && lpszPath[1] == '\\')
3302 {
3303 /* Network share: skip share server and mount point */
3304 lpszPath += 2;
3305 if ((lpszPath = StrChrA(lpszPath, '\\')) &&
3306 (lpszPath = StrChrA(lpszPath + 1, '\\')))
3307 lpszPath++;
3308 return (LPSTR)lpszPath;
3309 }
3310
3311 if (IsDBCSLeadByte(*lpszPath))
3312 return NULL;
3313
3314 /* Check x:\ */
3315 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
3316 return (LPSTR)lpszPath + 3;
3317 return NULL;
3318}
3319
3320/*************************************************************************
3321 * PathSkipRootW [SHLWAPI.@]
3322 *
3323 * See PathSkipRootA.
3324 */
3326{
3327 TRACE("(%s)\n", debugstr_w(lpszPath));
3328
3329 if (!lpszPath || !*lpszPath)
3330 return NULL;
3331
3332 if (*lpszPath == '\\' && lpszPath[1] == '\\')
3333 {
3334 /* Network share: skip share server and mount point */
3335 lpszPath += 2;
3336 if ((lpszPath = StrChrW(lpszPath, '\\')) &&
3337 (lpszPath = StrChrW(lpszPath + 1, '\\')))
3338 lpszPath++;
3339 return (LPWSTR)lpszPath;
3340 }
3341
3342 /* Check x:\ */
3343 if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
3344 return (LPWSTR)lpszPath + 3;
3345 return NULL;
3346}
3347
3348/*************************************************************************
3349 * PathCreateFromUrlA [SHLWAPI.@]
3350 *
3351 * See PathCreateFromUrlW
3352 */
3355{
3356 WCHAR bufW[MAX_PATH];
3357 WCHAR *pathW = bufW;
3358 UNICODE_STRING urlW;
3359 HRESULT ret;
3360 DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
3361
3362 if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
3363 return E_INVALIDARG;
3364
3365 if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
3366 return E_INVALIDARG;
3367 if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
3368 pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
3369 ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
3370 }
3371 if(ret == S_OK) {
3372 RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
3373 if(*pcchPath > lenA) {
3374 RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
3375 pszPath[lenA] = 0;
3376 *pcchPath = lenA;
3377 } else {
3378 *pcchPath = lenA + 1;
3379 ret = E_POINTER;
3380 }
3381 }
3382 if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
3383 RtlFreeUnicodeString(&urlW);
3384 return ret;
3385}
3386
3387/*************************************************************************
3388 * PathCreateFromUrlW [SHLWAPI.@]
3389 *
3390 * Create a path from a URL
3391 *
3392 * PARAMS
3393 * lpszUrl [I] URL to convert into a path
3394 * lpszPath [O] Output buffer for the resulting Path
3395 * pcchPath [I] Length of lpszPath
3396 * dwFlags [I] Flags controlling the conversion
3397 *
3398 * RETURNS
3399 * Success: S_OK. lpszPath contains the URL in path format,
3400 * Failure: An HRESULT error code such as E_INVALIDARG.
3401 */
3404{
3405 static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
3406 static const WCHAR localhost[] = { 'l','o','c','a','l','h','o','s','t',0 };
3407 DWORD nslashes, unescape, len;
3408 const WCHAR *src;
3409 WCHAR *tpath, *dst;
3410 HRESULT ret;
3411
3412 TRACE("(%s,%p,%p,0x%08x)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved);
3413
3414 if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
3415 return E_INVALIDARG;
3416
3417 if (lstrlenW(pszUrl) < 5)
3418 return E_INVALIDARG;
3419
3421 file_colon, 5) != CSTR_EQUAL)
3422 return E_INVALIDARG;
3423 pszUrl += 5;
3424 ret = S_OK;
3425
3426 src = pszUrl;
3427 nslashes = 0;
3428 while (*src == '/' || *src == '\\') {
3429 nslashes++;
3430 src++;
3431 }
3432
3433 /* We need a temporary buffer so we can compute what size to ask for.
3434 * We know that the final string won't be longer than the current pszUrl
3435 * plus at most two backslashes. All the other transformations make it
3436 * shorter.
3437 */
3438 len = 2 + lstrlenW(pszUrl) + 1;
3439 if (*pcchPath < len)
3440 tpath = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3441 else
3442 tpath = pszPath;
3443
3444 len = 0;
3445 dst = tpath;
3446 unescape = 1;
3447 switch (nslashes)
3448 {
3449 case 0:
3450 /* 'file:' + escaped DOS path */
3451 break;
3452 case 1:
3453 /* 'file:/' + escaped DOS path */
3454 /* fall through */
3455 case 3:
3456 /* 'file:///' (implied localhost) + escaped DOS path */
3457 if (!isalphaW(*src) || (src[1] != ':' && src[1] != '|'))
3458 src -= 1;
3459 break;
3460 case 2:
3462 src, 9, localhost, 9) == CSTR_EQUAL && (src[9] == '/' || src[9] == '\\'))
3463 {
3464 /* 'file://localhost/' + escaped DOS path */
3465 src += 10;
3466 }
3467 else if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
3468 {
3469 /* 'file://' + unescaped DOS path */
3470 unescape = 0;
3471 }
3472 else
3473 {
3474 /* 'file://hostname:port/path' (where path is escaped)
3475 * or 'file:' + escaped UNC path (\\server\share\path)
3476 * The second form is clearly specific to Windows and it might
3477 * even be doing a network lookup to try to figure it out.
3478 */
3479 while (*src && *src != '/' && *src != '\\')
3480 src++;
3481 len = src - pszUrl;
3482 StrCpyNW(dst, pszUrl, len + 1);
3483 dst += len;
3484 if (*src && isalphaW(src[1]) && (src[2] == ':' || src[2] == '|'))
3485 {
3486 /* 'Forget' to add a trailing '/', just like Windows */
3487 src++;
3488 }
3489 }
3490 break;
3491 case 4:
3492 /* 'file://' + unescaped UNC path (\\server\share\path) */
3493 unescape = 0;
3494 if (isalphaW(*src) && (src[1] == ':' || src[1] == '|'))
3495 break;
3496 /* fall through */
3497 default:
3498 /* 'file:/...' + escaped UNC path (\\server\share\path) */
3499 src -= 2;
3500 }
3501
3502 /* Copy the remainder of the path */
3503 len += lstrlenW(src);
3504 StrCpyW(dst, src);
3505
3506 /* First do the Windows-specific path conversions */
3507 for (dst = tpath; *dst; dst++)
3508 if (*dst == '/') *dst = '\\';
3509 if (isalphaW(*tpath) && tpath[1] == '|')
3510 tpath[1] = ':'; /* c| -> c: */
3511
3512 /* And only then unescape the path (i.e. escaped slashes are left as is) */
3513 if (unescape)
3514 {
3516 if (ret == S_OK)
3517 {
3518 /* When working in-place UrlUnescapeW() does not set len */
3519 len = lstrlenW(tpath);
3520 }
3521 }
3522
3523 if (*pcchPath < len + 1)
3524 {
3525 ret = E_POINTER;
3526 *pcchPath = len + 1;
3527 }
3528 else
3529 {
3530 *pcchPath = len;
3531 if (tpath != pszPath)
3532 StrCpyW(pszPath, tpath);
3533 }
3534 if (tpath != pszPath)
3535 HeapFree(GetProcessHeap(), 0, tpath);
3536
3537 TRACE("Returning (%u) %s\n", *pcchPath, debugstr_w(pszPath));
3538 return ret;
3539}
3540
3541/*************************************************************************
3542 * PathCreateFromUrlAlloc [SHLWAPI.@]
3543 */
3546{
3548 DWORD size;
3549 HRESULT hr;
3550
3551 size = MAX_PATH;
3553 if (SUCCEEDED(hr))
3554 {
3555 /* Yes, this is supposed to crash if pszPath is NULL */
3556 *pszPath = StrDupW(pathW);
3557 }
3558 return hr;
3559}
3560
3561/*************************************************************************
3562 * PathRelativePathToA [SHLWAPI.@]
3563 *
3564 * Create a relative path from one path to another.
3565 *
3566 * PARAMS
3567 * lpszPath [O] Destination for relative path
3568 * lpszFrom [I] Source path
3569 * dwAttrFrom [I] File attribute of source path
3570 * lpszTo [I] Destination path
3571 * dwAttrTo [I] File attributes of destination path
3572 *
3573 * RETURNS
3574 * TRUE If a relative path can be formed. lpszPath contains the new path
3575 * FALSE If the paths are not relative or any parameters are invalid
3576 *
3577 * NOTES
3578 * lpszTo should be at least MAX_PATH in length.
3579 *
3580 * Calling this function with relative paths for lpszFrom or lpszTo may
3581 * give erroneous results.
3582 *
3583 * The Win32 version of this function contains a bug where the lpszTo string
3584 * may be referenced 1 byte beyond the end of the string. As a result random
3585 * garbage may be written to the output path, depending on what lies beyond
3586 * the last byte of the string. This bug occurs because of the behaviour of
3587 * PathCommonPrefix() (see notes for that function), and no workaround seems
3588 * possible with Win32.
3589 *
3590 * This bug has been fixed here, so for example the relative path from "\\"
3591 * to "\\" is correctly determined as "." in this implementation.
3592 */
3593BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom,
3594 LPCSTR lpszTo, DWORD dwAttrTo)
3595{
3596 BOOL bRet = FALSE;
3597
3598 TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_a(lpszFrom),
3599 dwAttrFrom, debugstr_a(lpszTo), dwAttrTo);
3600
3601 if(lpszPath && lpszFrom && lpszTo)
3602 {
3604 WCHAR szFrom[MAX_PATH];
3605 WCHAR szTo[MAX_PATH];
3606 MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH);
3607 MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH);
3608 bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo);
3609 WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
3610 }
3611 return bRet;
3612}
3613
3614/*************************************************************************
3615 * PathRelativePathToW [SHLWAPI.@]
3616 *
3617 * See PathRelativePathToA.
3618 */
3619BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom,
3620 LPCWSTR lpszTo, DWORD dwAttrTo)
3621{
3622 static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' };
3623 static const WCHAR szPrevDir[] = { '.', '.', '\0' };
3624 WCHAR szFrom[MAX_PATH];
3625 WCHAR szTo[MAX_PATH];
3626 DWORD dwLen;
3627
3628 TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_w(lpszFrom),
3629 dwAttrFrom, debugstr_w(lpszTo), dwAttrTo);
3630
3631 if(!lpszPath || !lpszFrom || !lpszTo)
3632 return FALSE;
3633
3634 *lpszPath = '\0';
3635 lstrcpynW(szFrom, lpszFrom, MAX_PATH);
3636 lstrcpynW(szTo, lpszTo, MAX_PATH);
3637
3638 if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
3639 PathRemoveFileSpecW(szFrom);
3640 if(!(dwAttrTo & FILE_ATTRIBUTE_DIRECTORY))
3641 PathRemoveFileSpecW(szTo);
3642
3643 /* Paths can only be relative if they have a common root */
3644 if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0)))
3645 return FALSE;
3646
3647 /* Strip off lpszFrom components to the root, by adding "..\" */
3648 lpszFrom = szFrom + dwLen;
3649 if (!*lpszFrom)
3650 {
3651 lpszPath[0] = '.';
3652 lpszPath[1] = '\0';
3653 }
3654 if (*lpszFrom == '\\')
3655 lpszFrom++;
3656
3657 while (*lpszFrom)
3658 {
3659 lpszFrom = PathFindNextComponentW(lpszFrom);
3660 strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir);
3661 }
3662
3663 /* From the root add the components of lpszTo */
3664 lpszTo += dwLen;
3665 /* We check lpszTo[-1] to avoid skipping end of string. See the notes for
3666 * this function.
3667 */
3668 if (*lpszTo && lpszTo[-1])
3669 {
3670 if (*lpszTo != '\\')
3671 lpszTo--;
3672 dwLen = strlenW(lpszPath);
3673 if (dwLen + strlenW(lpszTo) >= MAX_PATH)
3674 {
3675 *lpszPath = '\0';
3676 return FALSE;
3677 }
3678 strcpyW(lpszPath + dwLen, lpszTo);
3679 }
3680 return TRUE;
3681}
3682
3683/*************************************************************************
3684 * PathUnmakeSystemFolderA [SHLWAPI.@]
3685 *
3686 * Remove the system folder attributes from a path.
3687 *
3688 * PARAMS
3689 * lpszPath [I] The path to remove attributes from
3690 *
3691 * RETURNS
3692 * Success: TRUE.
3693 * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling
3694 * SetFileAttributesA() fails.
3695 */
3697{
3698 DWORD dwAttr;
3699
3700 TRACE("(%s)\n", debugstr_a(lpszPath));
3701
3702 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
3703 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
3704 return FALSE;
3705
3707 return SetFileAttributesA(lpszPath, dwAttr);
3708}
3709
3710/*************************************************************************
3711 * PathUnmakeSystemFolderW [SHLWAPI.@]
3712 *
3713 * See PathUnmakeSystemFolderA.
3714 */
3716{
3717 DWORD dwAttr;
3718
3719 TRACE("(%s)\n", debugstr_w(lpszPath));
3720
3721 if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
3722 !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
3723 return FALSE;
3724
3726 return SetFileAttributesW(lpszPath, dwAttr);
3727}
3728
3729
3730/*************************************************************************
3731 * PathSetDlgItemPathA [SHLWAPI.@]
3732 *
3733 * Set the text of a dialog item to a path, shrinking the path to fit
3734 * if it is too big for the item.
3735 *
3736 * PARAMS
3737 * hDlg [I] Dialog handle
3738 * id [I] ID of item in the dialog
3739 * lpszPath [I] Path to set as the items text
3740 *
3741 * RETURNS
3742 * Nothing.
3743 *
3744 * NOTES
3745 * If lpszPath is NULL, a blank string ("") is set (i.e. The previous
3746 * window text is erased).
3747 */
3749{
3751
3752 TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath));
3753
3754 if (lpszPath)
3756 else
3757 szPath[0] = '\0';
3758 PathSetDlgItemPathW(hDlg, id, szPath);
3759}
3760
3761/*************************************************************************
3762 * PathSetDlgItemPathW [SHLWAPI.@]
3763 *
3764 * See PathSetDlgItemPathA.
3765 */
3767{
3768 WCHAR path[MAX_PATH + 1];
3769 HWND hwItem;
3770 RECT rect;
3771 HDC hdc;
3772 HGDIOBJ hPrevObj;
3773
3774 TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath));
3775
3776 if (!(hwItem = GetDlgItem(hDlg, id)))
3777 return;
3778
3779 if (lpszPath)
3780 lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR));
3781 else
3782 path[0] = '\0';
3783
3784 GetClientRect(hwItem, &rect);
3785 hdc = GetDC(hDlg);
3786 hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0));
3787
3788 if (hPrevObj)
3789 {
3791 SelectObject(hdc, hPrevObj);
3792 }
3793
3794 ReleaseDC(hDlg, hdc);
3795 SetWindowTextW(hwItem, path);
3796}
3797
3798/*************************************************************************
3799 * PathIsNetworkPathA [SHLWAPI.@]
3800 *
3801 * Determine if the given path is a network path.
3802 *
3803 * PARAMS
3804 * lpszPath [I] Path to check
3805 *
3806 * RETURNS
3807 * TRUE If lpszPath is a UNC share or mapped network drive, or
3808 * FALSE If lpszPath is a local drive or cannot be determined
3809 */
3811{
3812 int dwDriveNum;
3813
3814 TRACE("(%s)\n",debugstr_a(lpszPath));
3815
3816 if (!lpszPath)
3817 return FALSE;
3818 if (*lpszPath == '\\' && lpszPath[1] == '\\')
3819 return TRUE;
3820 dwDriveNum = PathGetDriveNumberA(lpszPath);
3821 if (dwDriveNum == -1)
3822 return FALSE;
3823#ifdef __REACTOS__
3824 return IsNetDrive(dwDriveNum);
3825#else
3826 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
3827 return pIsNetDrive(dwDriveNum);
3828#endif
3829}
3830
3831/*************************************************************************
3832 * PathIsNetworkPathW [SHLWAPI.@]
3833 *
3834 * See PathIsNetworkPathA.
3835 */
3837{
3838 int dwDriveNum;
3839
3840 TRACE("(%s)\n", debugstr_w(lpszPath));
3841
3842 if (!lpszPath)
3843 return FALSE;
3844 if (*lpszPath == '\\' && lpszPath[1] == '\\')
3845 return TRUE;
3846 dwDriveNum = PathGetDriveNumberW(lpszPath);
3847 if (dwDriveNum == -1)
3848 return FALSE;
3849#ifdef __REACTOS__
3850 return IsNetDrive(dwDriveNum);
3851#else
3852 GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
3853 return pIsNetDrive(dwDriveNum);
3854#endif
3855}
3856
3857/*************************************************************************
3858 * PathIsLFNFileSpecA [SHLWAPI.@]
3859 *
3860 * Determine if the given path is a long file name
3861 *
3862 * PARAMS
3863 * lpszPath [I] Path to check
3864 *
3865 * RETURNS
3866 * TRUE If path is a long file name,
3867 * FALSE If path is a valid DOS short file name
3868 */
3870{
3871 DWORD dwNameLen = 0, dwExtLen = 0;
3872
3873 TRACE("(%s)\n",debugstr_a(lpszPath));
3874
3875 if (!lpszPath)
3876 return FALSE;
3877
3878 while (*lpszPath)
3879 {
3880 if (*lpszPath == ' ')
3881 return TRUE; /* DOS names cannot have spaces */
3882 if (*lpszPath == '.')
3883 {
3884 if (dwExtLen)
3885 return TRUE; /* DOS names have only one dot */
3886 dwExtLen = 1;
3887 }
3888 else if (dwExtLen)
3889 {
3890 dwExtLen++;
3891 if (dwExtLen > 4)
3892 return TRUE; /* DOS extensions are <= 3 chars*/
3893 }
3894 else
3895 {
3896 dwNameLen++;
3897 if (dwNameLen > 8)
3898 return TRUE; /* DOS names are <= 8 chars */
3899 }
3900 lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1;
3901 }
3902 return FALSE; /* Valid DOS path */
3903}
3904
3905/*************************************************************************
3906 * PathIsLFNFileSpecW [SHLWAPI.@]
3907 *
3908 * See PathIsLFNFileSpecA.
3909 */
3911{
3912 DWORD dwNameLen = 0, dwExtLen = 0;
3913
3914 TRACE("(%s)\n",debugstr_w(lpszPath));
3915
3916 if (!lpszPath)
3917 return FALSE;
3918
3919 while (*lpszPath)
3920 {
3921 if (*lpszPath == ' ')
3922 return TRUE; /* DOS names cannot have spaces */
3923 if (*lpszPath == '.')
3924 {
3925 if (dwExtLen)
3926 return TRUE; /* DOS names have only one dot */
3927 dwExtLen = 1;
3928 }
3929 else if (dwExtLen)
3930 {
3931 dwExtLen++;
3932 if (dwExtLen > 4)
3933 return TRUE; /* DOS extensions are <= 3 chars*/
3934 }
3935 else
3936 {
3937 dwNameLen++;
3938 if (dwNameLen > 8)
3939 return TRUE; /* DOS names are <= 8 chars */
3940 }
3941 lpszPath++;
3942 }
3943 return FALSE; /* Valid DOS path */
3944}
3945
3946/*************************************************************************
3947 * PathIsDirectoryEmptyA [SHLWAPI.@]
3948 *
3949 * Determine if a given directory is empty.
3950 *
3951 * PARAMS
3952 * lpszPath [I] Directory to check
3953 *
3954 * RETURNS
3955 * TRUE If the directory exists and contains no files,
3956 * FALSE Otherwise
3957 */
3959{
3960 BOOL bRet = FALSE;
3961
3962 TRACE("(%s)\n",debugstr_a(lpszPath));
3963
3964 if (lpszPath)
3965 {
3969 }
3970 return bRet;
3971}
3972
3973/*************************************************************************
3974 * PathIsDirectoryEmptyW [SHLWAPI.@]
3975 *
3976 * See PathIsDirectoryEmptyA.
3977 */
3979{
3980 static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' };
3981 WCHAR szSearch[MAX_PATH];
3982 DWORD dwLen;
3983 HANDLE hfind;
3984 BOOL retVal = TRUE;
3986
3987 TRACE("(%s)\n",debugstr_w(lpszPath));
3988
3989 if (!lpszPath || !PathIsDirectoryW(lpszPath))
3990 return FALSE;
3991
3992 lstrcpynW(szSearch, lpszPath, MAX_PATH);
3993 PathAddBackslashW(szSearch);
3994 dwLen = strlenW(szSearch);
3995 if (dwLen > MAX_PATH - 4)
3996 return FALSE;
3997
3998 strcpyW(szSearch + dwLen, szAllFiles);
3999 hfind = FindFirstFileW(szSearch, &find_data);
4000 if (hfind == INVALID_HANDLE_VALUE)
4001 return FALSE;
4002
4003 do
4004 {
4005 if (find_data.cFileName[0] == '.')
4006 {
4007 if (find_data.cFileName[1] == '\0') continue;
4008 if (find_data.cFileName[1] == '.' && find_data.cFileName[2] == '\0') continue;
4009 }
4010
4011 retVal = FALSE;
4012 break;
4013 }
4014 while (FindNextFileW(hfind, &find_data));
4015
4016 FindClose(hfind);
4017 return retVal;
4018}
4019
4020
4021/*************************************************************************
4022 * PathFindSuffixArrayA [SHLWAPI.@]
4023 *
4024 * Find a suffix string in an array of suffix strings
4025 *
4026 * PARAMS
4027 * lpszSuffix [I] Suffix string to search for
4028 * lppszArray [I] Array of suffix strings to search
4029 * dwCount [I] Number of elements in lppszArray
4030 *
4031 * RETURNS
4032 * Success: The index of the position of lpszSuffix in lppszArray
4033 * Failure: 0, if any parameters are invalid or lpszSuffix is not found
4034 *
4035 * NOTES
4036 * The search is case sensitive.
4037 * The match is made against the end of the suffix string, so for example:
4038 * lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not.
4039 */
4040LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
4041{
4042 size_t dwLen;
4043 int dwRet = 0;
4044
4045 TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount);
4046
4047 if (lpszSuffix && lppszArray && dwCount > 0)
4048 {
4049 dwLen = strlen(lpszSuffix);
4050
4051 while (dwRet < dwCount)
4052 {
4053 size_t dwCompareLen = strlen(*lppszArray);
4054 if (dwCompareLen < dwLen)
4055 {
4056 if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
4057 return *lppszArray; /* Found */
4058 }
4059 dwRet++;
4060 lppszArray++;
4061 }
4062 }
4063 return NULL;
4064}
4065
4066/*************************************************************************
4067 * PathFindSuffixArrayW [SHLWAPI.@]
4068 *
4069 * See PathFindSuffixArrayA.
4070 */
4071LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
4072{
4073 size_t dwLen;
4074 int dwRet = 0;
4075
4076 TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount);
4077
4078 if (lpszSuffix && lppszArray && dwCount > 0)
4079 {
4080 dwLen = strlenW(lpszSuffix);
4081
4082 while (dwRet < dwCount)
4083 {
4084 size_t dwCompareLen = strlenW(*lppszArray);
4085 if (dwCompareLen < dwLen)
4086 {
4087 if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
4088 return *lppszArray; /* Found */
4089 }
4090 dwRet++;
4091 lppszArray++;
4092 }
4093 }
4094 return NULL;
4095}
4096
4097/*************************************************************************
4098 * PathUndecorateA [SHLWAPI.@]
4099 *
4100 * Undecorate a file path
4101 *
4102 * PARAMS
4103 * lpszPath [I/O] Path to remove any decoration from
4104 *
4105 * RETURNS
4106 * Nothing
4107 *
4108 * NOTES
4109 * A decorations form is "path[n].ext" where "n" is an optional decimal number.
4110 */
4112{
4113 char *ext, *skip;
4114
4115 TRACE("(%s)\n", debugstr_a(pszPath));
4116
4117 if (!pszPath) return;
4118
4119 ext = PathFindExtensionA(pszPath);
4120 if (ext == pszPath || ext[-1] != ']') return;
4121
4122 skip = ext - 2;
4123 while (skip > pszPath && '0' <= *skip && *skip <= '9')
4124 skip--;
4125
4126 if (skip > pszPath && *skip == '[' && skip[-1] != '\\')
4127 memmove(skip, ext, strlen(ext) + 1);
4128}
4129
4130/*************************************************************************
4131 * PathUndecorateW [SHLWAPI.@]
4132 *
4133 * See PathUndecorateA.
4134 */
4136{
4137 WCHAR *ext, *skip;
4138
4139 TRACE("(%s)\n", debugstr_w(pszPath));
4140
4141 if (!pszPath) return;
4142
4143 ext = PathFindExtensionW(pszPath);
4144 if (ext == pszPath || ext[-1] != ']') return;
4145
4146 skip = ext - 2;
4147 while (skip > pszPath && '0' <= *skip && *skip <= '9')
4148 skip--;
4149
4150 if (skip > pszPath && *skip == '[' && skip[-1] != '\\')
4151 memmove(skip, ext, (wcslen(ext) + 1) * sizeof(WCHAR));
4152}
4153
4154/*************************************************************************
4155 * PathUnExpandEnvStringsA [SHLWAPI.@]
4156 *
4157 * Substitute folder names in a path with their corresponding environment
4158 * strings.
4159 *
4160 * PARAMS
4161 * path [I] Buffer containing the path to unexpand.
4162 * buffer [O] Buffer to receive the unexpanded path.
4163 * buf_len [I] Size of pszBuf in characters.
4164 *
4165 * RETURNS
4166 * Success: TRUE
4167 * Failure: FALSE
4168 */
4170{
4171 WCHAR bufferW[MAX_PATH], *pathW;
4172 DWORD len;
4173 BOOL ret;
4174
4175 TRACE("(%s, %p, %d)\n", debugstr_a(path), buffer, buf_len);
4176
4178 if (!pathW) return FALSE;
4179
4182 if (!ret) return FALSE;
4183
4184 len = WideCharToMultiByte(CP_ACP, 0, bufferW, -1, NULL, 0, NULL, NULL);
4185 if (buf_len < len + 1) return FALSE;
4186
4187 WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, buf_len, NULL, NULL);
4188 return TRUE;
4189}
4190
4191static const WCHAR allusersprofileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%',0};
4192static const WCHAR appdataW[] = {'%','A','P','P','D','A','T','A','%',0};
4193static const WCHAR programfilesW[] = {'%','P','r','o','g','r','a','m','F','i','l','e','s','%',0};
4194static const WCHAR systemrootW[] = {'%','S','y','s','t','e','m','R','o','o','t','%',0};
4195static const WCHAR systemdriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%',0};
4196static const WCHAR userprofileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%',0};
4197
4198struct envvars_map
4199{
4200 const WCHAR *var;
4203 DWORD len;
4204};
4205
4207{
4208 while (map->var)
4209 {
4210 map->len = ExpandEnvironmentStringsW(map->var, map->path, sizeof(map->path)/sizeof(WCHAR));
4211 /* exclude null from length */
4212 if (map->len) map->len--;
4213 map++;
4214 }
4215}
4216
4217/*************************************************************************
4218 * PathUnExpandEnvStringsW [SHLWAPI.@]
4219 *
4220 * Unicode version of PathUnExpandEnvStringsA.
4221 */
4223{
4224 static struct envvars_map null_var = {NULL, 0, {0}, 0};
4225 struct envvars_map *match = &null_var, *cur;
4226 struct envvars_map envvars[] = {
4227 { allusersprofileW, sizeof(allusersprofileW)/sizeof(WCHAR) },
4228 { appdataW, sizeof(appdataW)/sizeof(WCHAR) },
4229 { programfilesW, sizeof(programfilesW)/sizeof(WCHAR) },
4230 { systemrootW, sizeof(systemrootW)/sizeof(WCHAR) },
4231 { systemdriveW, sizeof(systemdriveW)/sizeof(WCHAR) },
4232 { userprofileW, sizeof(userprofileW)/sizeof(WCHAR) },
4233 { NULL }
4234 };
4235 DWORD pathlen;
4236 UINT needed;
4237
4238 TRACE("(%s, %p, %d)\n", debugstr_w(path), buffer, buf_len);
4239
4240 pathlen = strlenW(path);
4241 init_envvars_map(envvars);
4242 cur = envvars;
4243 while (cur->var)
4244 {
4245 /* path can't contain expanded value or value wasn't retrieved */
4246 if (cur->len == 0 || cur->len > pathlen || strncmpiW(cur->path, path, cur->len))
4247 {
4248 cur++;
4249 continue;
4250 }
4251
4252 if (cur->len > match->len)
4253 match = cur;
4254 cur++;
4255 }
4256
4257 /* 'varlen' includes NULL termination char */
4258 needed = match->varlen + pathlen - match->len;
4259 if (match->len == 0 || needed > buf_len) return FALSE;
4260
4261 strcpyW(buffer, match->var);
4262 strcatW(buffer, &path[match->len]);
4263 TRACE("ret %s\n", debugstr_w(buffer));
4264
4265 return TRUE;
4266}
4267
4268/*************************************************************************
4269 * @ [SHLWAPI.440]
4270 *
4271 * Find localised or default web content in "%WINDOWS%\web\".
4272 *
4273 * PARAMS
4274 * lpszFile [I] File name containing content to look for
4275 * lpszPath [O] Buffer to contain the full path to the file
4276 * dwPathLen [I] Length of lpszPath
4277 *
4278 * RETURNS
4279 * Success: S_OK. lpszPath contains the full path to the content.
4280 * Failure: E_FAIL. The content does not exist or lpszPath is too short.
4281 */
4283{
4284 WCHAR szFile[MAX_PATH], szPath[MAX_PATH];
4285 HRESULT hRet;
4286
4287 TRACE("(%s,%p,%d)\n", lpszFile, lpszPath, dwPathLen);
4288
4289 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH);
4290 szPath[0] = '\0';
4291 hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen);
4292 WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0);
4293 return hRet;
4294}
4295
4296/*************************************************************************
4297 * @ [SHLWAPI.441]
4298 *
4299 * Unicode version of SHGetWebFolderFilePathA.
4300 */
4302{
4303 static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'};
4304 static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'};
4305#define szWebLen (sizeof(szWeb)/sizeof(WCHAR))
4306#define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR))
4307 DWORD dwLen, dwFileLen;
4308 LANGID lidSystem, lidUser;
4309
4310 TRACE("(%s,%p,%d)\n", debugstr_w(lpszFile), lpszPath, dwPathLen);
4311
4312 /* Get base directory for web content */
4313 dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen);
4314 if (dwLen > 0 && lpszPath[dwLen-1] == '\\')
4315 dwLen--;
4316
4317 dwFileLen = strlenW(lpszFile);
4318
4319 if (dwLen + dwFileLen + szWebLen >= dwPathLen)
4320 return E_FAIL; /* lpszPath too short */
4321
4322 strcpyW(lpszPath+dwLen, szWeb);
4323 dwLen += szWebLen;
4324 dwPathLen = dwPathLen - dwLen; /* Remaining space */
4325
4326 lidSystem = GetSystemDefaultUILanguage();
4327 lidUser = GetUserDefaultUILanguage();
4328
4329 if (lidSystem != lidUser)
4330 {
4331 if (dwFileLen + szWebMuiLen < dwPathLen)
4332 {
4333 /* Use localised content in the users UI language if present */
4334 wsprintfW(lpszPath + dwLen, szWebMui, lidUser);
4335 strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile);
4336 if (PathFileExistsW(lpszPath))
4337 return S_OK;
4338 }
4339 }
4340
4341 /* Fall back to OS default installed content */
4342 strcpyW(lpszPath + dwLen, lpszFile);
4343 if (PathFileExistsW(lpszPath))
4344 return S_OK;
4345 return E_FAIL;
4346}
4347
4348#ifndef __REACTOS__ /* Defined in <shlwapi_undoc.h> */
4349#define PATH_CHAR_CLASS_LETTER 0x00000001
4350#define PATH_CHAR_CLASS_ASTERIX 0x00000002
4351#define PATH_CHAR_CLASS_DOT 0x00000004
4352#define PATH_CHAR_CLASS_BACKSLASH 0x00000008
4353#define PATH_CHAR_CLASS_COLON 0x00000010
4354#define PATH_CHAR_CLASS_SEMICOLON 0x00000020
4355#define PATH_CHAR_CLASS_COMMA 0x00000040
4356#define PATH_CHAR_CLASS_SPACE 0x00000080
4357#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
4358#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200
4359
4360#define PATH_CHAR_CLASS_INVALID 0x00000000
4361#define PATH_CHAR_CLASS_ANY 0xffffffff
4362#endif
4363
4364static const DWORD SHELL_charclass[] =
4365{
4366 /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID,
4367 /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID,
4368 /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID,
4369 /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID,
4370 /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID,
4371 /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID,
4372 /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID,
4373 /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID,
4374 /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID,
4375 /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID,
4376 /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID,
4377 /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID,
4378 /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID,
4379 /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID,
4380 /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID,
4381 /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID,
4389 /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID,
4399 /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY,
4400 /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY,
4401 /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY,
4402 /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY,
4403 /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY,
4404 /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY,
4405 /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY,
4406 /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY,
4407 /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY,
4408 /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY,
4409 /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY,
4410 /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY,
4415 /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY,
4416 /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY,
4417 /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY,
4418 /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY,
4419 /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY,
4420 /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY,
4421 /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY,
4422 /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY,
4423 /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY,
4424 /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY,
4425 /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY,
4426 /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY,
4430};
4431
4432/*************************************************************************
4433 * @ [SHLWAPI.455]
4434 *
4435 * Check if an ASCII char is of a certain class
4436 */
4438{
4439 if ((unsigned)c > 0x7e)
4440 return class & PATH_CHAR_CLASS_OTHER_VALID;
4441
4442 return class & SHELL_charclass[(unsigned)c];
4443}
4444
4445/*************************************************************************
4446 * @ [SHLWAPI.456]
4447 *
4448 * Check if a Unicode char is of a certain class
4449 */
4451{
4452 if (c > 0x7e)
4453 return class & PATH_CHAR_CLASS_OTHER_VALID;
4454
4455 return class & SHELL_charclass[c];
4456}
static HDC hDC
Definition: 3dtext.c:33
@ shell32
Definition: LocaleTests.cpp:20
UINT cchMax
WCHAR lpszDest[260]
#define islower(c)
Definition: acclib.h:72
#define skip(...)
Definition: atltest.h:64
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
Definition: _map.h:48
RECT rect
Definition: combotst.c:67
#define NO_ERROR
Definition: dderror.h:5
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_FAIL
Definition: ddrawi.h:102
HRESULT hr
Definition: delayimp.cpp:573
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static int find_data(const struct Vector *v, const BYTE *pData, int size)
Definition: filtermapper.c:162
INT WINAPI StrToIntW(LPCWSTR lpString)
Definition: string.c:407
LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
Definition: string.c:464
INT WINAPI StrToIntA(LPCSTR lpszStr)
Definition: string.c:370
LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
Definition: string.c:266
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define CP_ACP
Definition: compat.h:109
#define GetEnvironmentVariableW(x, y, z)
Definition: compat.h:755
#define SetLastError(x)
Definition: compat.h:752
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define HeapAlloc
Definition: compat.h:733
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define lstrcpyW
Definition: compat.h:749
#define WideCharToMultiByte
Definition: compat.h:111
#define MultiByteToWideChar
Definition: compat.h:110
#define lstrcpynW
Definition: compat.h:738
#define lstrlenW
Definition: compat.h:750
static const WCHAR *const ext[]
Definition: module.c:53
DWORD WINAPI ExpandEnvironmentStringsW(IN LPCWSTR lpSrc, IN LPWSTR lpDst, IN DWORD nSize)
Definition: environ.c:520
UINT WINAPI SetErrorMode(IN UINT uMode)
Definition: except.c:751
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:636
BOOL WINAPI SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:778
BOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
Definition: fileinfo.c:760
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:620
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
DWORD WINAPI SearchPathA(IN LPCSTR lpPath OPTIONAL, IN LPCSTR lpFileName, IN LPCSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart OPTIONAL)
Definition: path.c:1123
DWORD WINAPI SearchPathW(IN LPCWSTR lpPath OPTIONAL, IN LPCWSTR lpFileName, IN LPCWSTR lpExtension OPTIONAL, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart OPTIONAL)
Definition: path.c:1298
DWORD WINAPI GetFullPathNameA(IN LPCSTR lpFileName, IN DWORD nBufferLength, OUT LPSTR lpBuffer, OUT LPSTR *lpFilePart)
Definition: path.c:993
UINT WINAPI GetSystemDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2232
UINT WINAPI GetSystemWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2316
DWORD WINAPI GetFullPathNameW(IN LPCWSTR lpFileName, IN DWORD nBufferLength, OUT LPWSTR lpBuffer, OUT LPWSTR *lpFilePart)
Definition: path.c:1106
UINT WINAPI GetWindowsDirectoryW(OUT LPWSTR lpBuffer, IN UINT uSize)
Definition: path.c:2271
BOOL WINAPI IsDBCSLeadByte(BYTE testchar)
Definition: locale.c:2126
int WINAPI lstrcmpW(LPCWSTR str1, LPCWSTR str2)
Definition: locale.c:4152
INT WINAPI CompareStringW(LCID lcid, DWORD flags, LPCWSTR str1, INT len1, LPCWSTR str2, INT len2)
Definition: locale.c:3946
LANGID WINAPI GetUserDefaultUILanguage(void)
Definition: locale.c:1380
int WINAPI lstrcmpA(LPCSTR str1, LPCSTR str2)
Definition: locale.c:4104
LANGID WINAPI GetSystemDefaultUILanguage(void)
Definition: locale.c:1400
int WINAPI PathCommonPrefixW(const WCHAR *file1, const WCHAR *file2, WCHAR *path)
Definition: path.c:1620
BOOL WINAPI PathIsRootA(const char *path)
Definition: path.c:1088
#define PATH_CHAR_CLASS_DOUBLEQUOTE
Definition: path.c:2140
BOOL WINAPI PathMatchSpecA(const char *path, const char *mask)
Definition: path.c:2456
BOOL WINAPI PathIsSameRootW(const WCHAR *path1, const WCHAR *path2)
Definition: path.c:2576
void WINAPI PathRemoveExtensionW(WCHAR *path)
Definition: path.c:1946
#define PATH_CHAR_CLASS_OTHER_VALID
Definition: path.c:2139
void WINAPI PathRemoveBlanksW(WCHAR *path)
Definition: path.c:1910
BOOL WINAPI PathIsUNCW(const WCHAR *path)
Definition: path.c:1013
LPSTR WINAPI PathFindExtensionA(const char *path)
Definition: path.c:1253
BOOL WINAPI PathIsPrefixA(const char *prefix, const char *path)
Definition: path.c:1670
HRESULT WINAPI UrlUnescapeW(WCHAR *url, WCHAR *unescaped, DWORD *unescaped_len, DWORD flags)
Definition: path.c:2936
static WCHAR * heap_strdupAtoW(const char *str)
Definition: path.c:131
int WINAPI PathCommonPrefixA(const char *file1, const char *file2, char *path)
Definition: path.c:1570
void WINAPI PathRemoveBlanksA(char *path)
Definition: path.c:1886
void WINAPI PathUnquoteSpacesW(WCHAR *path)
Definition: path.c:2006
int WINAPI PathGetDriveNumberW(const WCHAR *path)
Definition: path.c:1810
#define PATH_CHAR_CLASS_SPACE
Definition: path.c:2138
#define PATH_CHAR_CLASS_ASTERIX
Definition: path.c:2132
void WINAPI PathQuoteSpacesA(char *path)
Definition: path.c:2526
BOOL WINAPI PathRemoveFileSpecA(char *path)
Definition: path.c:1108
WCHAR *WINAPI PathRemoveBackslashW(WCHAR *path)
Definition: path.c:2040
HRESULT WINAPI PathCreateFromUrlW(const WCHAR *url, WCHAR *path, DWORD *pcchPath, DWORD dwReserved)
Definition: path.c:3073
BOOL WINAPI PathIsUNCServerShareW(const WCHAR *path)
Definition: path.c:1064
BOOL WINAPI PathIsUNCServerA(const char *path)
Definition: path.c:1859
BOOL WINAPI PathIsFileSpecA(const char *path)
Definition: path.c:1825
WCHAR *WINAPI PathFindFileNameW(const WCHAR *path)
Definition: path.c:1701
BOOL WINAPI PathFileExistsA(const char *path)
Definition: path.c:2590
UINT WINAPI PathGetCharTypeA(UCHAR ch)
Definition: path.c:1793
BOOL WINAPI PathRelativePathToA(char *path, const char *from, DWORD attributes_from, const char *to, DWORD attributes_to)
Definition: path.c:2357
HRESULT WINAPI PathCreateFromUrlA(const char *pszUrl, char *pszPath, DWORD *pcchPath, DWORD dwReserved)
Definition: path.c:3040
#define PATH_CHAR_CLASS_ANY
Definition: path.c:2143
char *WINAPI PathFindNextComponentA(const char *path)
Definition: path.c:2229
char *WINAPI PathGetArgsA(const char *path)
Definition: path.c:1718
#define PATH_CHAR_CLASS_LETTER
Definition: path.c:2131
BOOL WINAPI PathSearchAndQualifyA(const char *path, char *buffer, UINT length)
Definition: path.c:2338
void WINAPI PathStripPathA(char *path)
Definition: path.c:2316
void WINAPI PathStripPathW(WCHAR *path)
Definition: path.c:2328
BOOL WINAPI PathRemoveFileSpecW(WCHAR *path)
Definition: path.c:1145
void WINAPI PathRemoveExtensionA(char *path)
Definition: path.c:1934
LPWSTR WINAPI PathFindExtensionW(const WCHAR *path)
Definition: path.c:1274
char *WINAPI PathSkipRootA(const char *path)
Definition: path.c:2267
BOOL WINAPI PathUnExpandEnvStringsW(const WCHAR *path, WCHAR *buffer, UINT buf_len)
Definition: path.c:2705
int WINAPI PathGetDriveNumberA(const char *path)
Definition: path.c:1798
#define PATH_CHAR_CLASS_SEMICOLON
Definition: path.c:2136
BOOL WINAPI PathIsRelativeA(const char *path)
Definition: path.c:1020
int WINAPI PathParseIconLocationA(char *path)
Definition: path.c:2623
void WINAPI PathUnquoteSpacesA(char *path)
Definition: path.c:1988
#define PATH_CHAR_CLASS_COLON
Definition: path.c:2135
BOOL WINAPI PathIsRelativeW(const WCHAR *path)
Definition: path.c:1030
int WINAPI PathParseIconLocationW(WCHAR *path)
Definition: path.c:2644
BOOL WINAPI PathSearchAndQualifyW(const WCHAR *path, WCHAR *buffer, UINT length)
Definition: path.c:2348
char *WINAPI PathRemoveBackslashA(char *path)
Definition: path.c:2024
BOOL WINAPI PathStripToRootW(WCHAR *path)
Definition: path.c:1195
BOOL WINAPI PathStripToRootA(char *path)
Definition: path.c:1181
BOOL WINAPI PathIsSameRootA(const char *path1, const char *path2)
Definition: path.c:2562
BOOL WINAPI PathIsUNCServerW(const WCHAR *path)
Definition: path.c:1876
static void init_envvars_map(struct envvars_map *map)
Definition: path.c:2694
HRESULT WINAPI PathCreateFromUrlAlloc(const WCHAR *url, WCHAR **path, DWORD reserved)
Definition: path.c:3205
BOOL WINAPI PathIsValidCharW(WCHAR c, DWORD class)
Definition: path.c:2221
BOOL WINAPI PathMatchSpecW(const WCHAR *path, const WCHAR *mask)
Definition: path.c:2521
WCHAR *WINAPI PathGetArgsW(const WCHAR *path)
Definition: path.c:1740
BOOL WINAPI PathIsLFNFileSpecA(const char *path)
Definition: path.c:2057
UINT WINAPI PathGetCharTypeW(WCHAR ch)
Definition: path.c:1762
BOOL WINAPI PathIsValidCharA(char c, DWORD class)
Definition: path.c:2213
WCHAR *WINAPI PathSkipRootW(const WCHAR *path)
Definition: path.c:2293
#define PATH_CHAR_CLASS_COMMA
Definition: path.c:2137
BOOL WINAPI PathRelativePathToW(WCHAR *path, const WCHAR *from, DWORD attributes_from, const WCHAR *to, DWORD attributes_to)
Definition: path.c:2376
BOOL WINAPI PathFileExistsW(const WCHAR *path)
Definition: path.c:2607
BOOL WINAPI PathUnExpandEnvStringsA(const char *path, char *buffer, UINT buf_len)
Definition: path.c:2665
#define PATH_CHAR_CLASS_INVALID
Definition: path.c:2142
char *WINAPI PathFindFileNameA(const char *path)
Definition: path.c:1684
BOOL WINAPI PathIsFileSpecW(const WCHAR *path)
Definition: path.c:1842
BOOL WINAPI PathIsRootW(const WCHAR *path)
Definition: path.c:1101
BOOL WINAPI PathIsLFNFileSpecW(const WCHAR *path)
Definition: path.c:2094
BOOL WINAPI PathIsPrefixW(const WCHAR *prefix, const WCHAR *path)
Definition: path.c:1677
#define PATH_CHAR_CLASS_BACKSLASH
Definition: path.c:2134
#define PATH_CHAR_CLASS_DOT
Definition: path.c:2133
WCHAR *WINAPI PathFindNextComponentW(const WCHAR *path)
Definition: path.c:2248
BOOL WINAPI PathIsUNCA(const char *path)
Definition: path.c:1006
BOOL WINAPI PathIsUNCServerShareA(const char *path)
Definition: path.c:1040
void WINAPI PathQuoteSpacesW(WCHAR *path)
Definition: path.c:2544
LPSTR WINAPI CharNextA(const char *ptr)
Definition: string.c:1107
WCHAR *WINAPI StrDupW(const WCHAR *str)
Definition: string.c:313
LPSTR WINAPI CharPrevA(const char *start, const char *ptr)
Definition: string.c:1128
WCHAR *WINAPI StrCpyNW(WCHAR *dst, const WCHAR *src, int count)
Definition: string.c:462
unsigned char ch[4][2]
Definition: console.c:118
int CDECL isalnum(int c)
Definition: ctype.c:214
int CDECL tolower(int c)
Definition: ctype.c:572
int CDECL toupper(int c)
Definition: ctype.c:514
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2983
_ACRTIMP char *__cdecl strchr(const char *, int)
Definition: string.c:3286
_ACRTIMP size_t __cdecl strlen(const char *)
Definition: string.c:1592
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3319
HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen)
Definition: path.c:4282
void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
Definition: path.c:782
static const WCHAR userprofileW[]
Definition: path.c:4196
BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath, DWORD dwWhich)
Definition: path.c:1204
#define szWebMuiLen
BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
Definition: path.c:1707
BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath)
Definition: path.c:3147
static const WCHAR systemdriveW[]
Definition: path.c:4195
BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath)
Definition: path.c:3836
LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive)
Definition: path.c:332
#define szWebLen
BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath)
Definition: path.c:3167
BOOL(WINAPI * fnpIsNetDrive)(int)
Definition: path.c:68
static const WCHAR programfilesW[]
Definition: path.c:4193
BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath)
Definition: path.c:3810
static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
Definition: path.c:1934
BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DWORD dwWhich)
Definition: path.c:1316
void WINAPI PathRemoveArgsA(LPSTR lpszPath)
Definition: path.c:759
static const DWORD SHELL_charclass[]
Definition: path.c:4364
#define GET_FUNC(func, module, name, fail)
Definition: path.c:55
BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
Definition: path.c:1412
BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
Definition: path.c:3978
BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath, UINT cchMax, DWORD dwFlags)
Definition: path.c:1444
BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib)
Definition: path.c:2247
BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath, UINT cchMax, DWORD dwFlags)
Definition: path.c:1469
static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
Definition: path.c:1900
static BOOL SHLWAPI_UseSystemForSystemFolders(void)
Definition: path.c:3117
BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath)
Definition: path.c:2747
static BOOL SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich)
Definition: path.c:1226
void WINAPI PathUndecorateW(LPWSTR pszPath)
Definition: path.c:4135
BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
Definition: path.c:2917
BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath)
Definition: path.c:3715
BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs)
Definition: path.c:1401
static fnpIsNetDrive pIsNetDrive
Definition: path.c:69
LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive)
Definition: path.c:351
BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr)
Definition: path.c:1853
static HMODULE SHLWAPI_hshell32
Definition: path.c:65
HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR, LPWSTR, DWORD)
Definition: path.c:4301
VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath)
Definition: path.c:3748
BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType)
Definition: path.c:2128
BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
Definition: path.c:2938
BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib)
Definition: path.c:2265
BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich)
Definition: path.c:1360
BOOL WINAPI PathMakePrettyA(LPSTR lpszPath)
Definition: path.c:2715
static const WCHAR allusersprofileW[]
Definition: path.c:4191
void WINAPI PathUndecorateA(LPSTR pszPath)
Definition: path.c:4111
LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
Definition: path.c:4040
static const WCHAR appdataW[]
Definition: path.c:4192
static const WCHAR systemrootW[]
Definition: path.c:4194
BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath)
Definition: path.c:3696
VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath)
Definition: path.c:3766
LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
Definition: path.c:4071
BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
Definition: path.c:1879
BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath, DWORD dwWhich)
Definition: path.c:1126
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1751
BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType)
Definition: path.c:2105
BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath)
Definition: path.c:3958
DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
Definition: reg.c:1278
DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, LPDWORD pwType, LPVOID pvData, LPDWORD pcbData)
Definition: reg.c:1249
LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc)
Definition: string.c:514
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
return ret
Definition: mutex.c:146
#define strcasecmp
Definition: fake.h:9
static unsigned char buff[32768]
Definition: fatten.c:17
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxCollectionEntry * cur
GLuint start
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLenum src
Definition: glext.h:6340
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLenum GLint GLuint mask
Definition: glext.h:6028
GLenum GLenum dst
Definition: glext.h:6340
GLbitfield flags
Definition: glext.h:7161
const GLint * first
Definition: glext.h:5794
GLenum GLsizei len
Definition: glext.h:6722
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
BOOL unescape(WCHAR *str, size_t *len)
Definition: lex.c:227
#define c
Definition: ke_i.h:80
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
USHORT LANGID
Definition: mui.h:9
GLint dx
Definition: linetemp.h:97
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
LPCWSTR szPath
Definition: env.c:37
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
static const BYTE localhost[]
Definition: encode.c:1391
static LPWSTR PDWORD pcchPath
Definition: asmcache.c:747
static const WCHAR pathW[]
Definition: path.c:2368
static unsigned(__cdecl *hash_bstr)(bstr_t s)
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:95
unsigned int UINT
Definition: ndis.h:50
NTSYSAPI BOOLEAN NTAPI RtlCreateUnicodeStringFromAsciiz(_Out_ PUNICODE_STRING Destination, _In_ PCSZ Source)
#define SEM_FAILCRITICALERRORS
Definition: rtltypes.h:69
_In_ LPWSTR _In_ DWORD _In_ DWORD _In_ DWORD dwFlags
Definition: netsh.h:141
_Use_decl_annotations_ NTSTATUS NTAPI RtlUnicodeToMultiByteN(_Out_ PCHAR MbString, _In_ ULONG MbSize, _Out_opt_ PULONG ResultSize, _In_ PCWCH UnicodeString, _In_ ULONG UnicodeSize)
Definition: nlsboot.c:108
_Use_decl_annotations_ NTSTATUS NTAPI RtlUnicodeToMultiByteSize(_Out_ PULONG MbSize, _In_ PCWCH UnicodeString, _In_ ULONG UnicodeSize)
Definition: nlsboot.c:146
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define BOOL
Definition: nt_native.h:43
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define REG_NONE
Definition: nt_native.h:1495
#define LOCALE_INVARIANT
#define PathAddExtensionA
Definition: pathcch.h:305
#define PathCanonicalizeA
Definition: pathcch.h:313
#define PathAddExtensionW
Definition: pathcch.h:306
#define PathCombineA
Definition: pathcch.h:317
#define PathAppendA
Definition: pathcch.h:309
#define PathCanonicalizeW
Definition: pathcch.h:314
#define PathAddBackslashA
Definition: pathcch.h:301
#define PathCombineW
Definition: pathcch.h:318
#define PathRenameExtensionA
Definition: pathcch.h:321
#define PathRenameExtensionW
Definition: pathcch.h:322
#define PathAddBackslashW
Definition: pathcch.h:302
#define PathAppendW
Definition: pathcch.h:310
short WCHAR
Definition: pedump.c:58
#define GCT_SHORTCHAR
Definition: shlwapi.h:273
#define GCT_LFNCHAR
Definition: shlwapi.h:272
#define GCT_SEPARATOR
Definition: shlwapi.h:275
#define URL_UNESCAPE_INPLACE
Definition: shlwapi.h:525
_In_ UINT cchBuf
Definition: shlwapi.h:378
#define GCT_INVALID
Definition: shlwapi.h:271
#define GCT_WILD
Definition: shlwapi.h:274
const WCHAR * str
strcpy
Definition: string.h:131
EXTERN_C int WINAPI IsNetDrive(int drive)
Definition: shlfileop.cpp:2342
#define WHICH_OPTIONAL
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwDisplayType
Definition: winnetwk.h:169
DWORD dwScope
Definition: winnetwk.h:167
LPSTR lpRemoteName
Definition: winnetwk.h:172
DWORD dwType
Definition: winnetwk.h:168
DWORD dwType
Definition: winnetwk.h:178
DWORD dwDisplayType
Definition: winnetwk.h:179
DWORD dwScope
Definition: winnetwk.h:177
LPWSTR lpRemoteName
Definition: winnetwk.h:182
const WCHAR * var
Definition: path.c:2689
DWORD len
Definition: path.c:2691
UINT varlen
Definition: path.c:4201
Definition: match.c:28
Definition: name.c:39
LONG right
Definition: windef.h:108
const char * LPCSTR
Definition: typedefs.h:52
const uint16_t * LPCWSTR
Definition: typedefs.h:57
unsigned char UCHAR
Definition: typedefs.h:53
uint16_t * LPWSTR
Definition: typedefs.h:56
uint32_t * LPDWORD
Definition: typedefs.h:59
char * LPSTR
Definition: typedefs.h:51
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define GetFileAttributes
Definition: winbase.h:3564
#define WINAPI
Definition: msvc.h:6
#define strncmpiW(s1, s2, n)
Definition: unicode.h:40
#define toupperW(n)
Definition: unicode.h:45
#define strcmpW(s1, s2)
Definition: unicode.h:38
#define strchrW(s, c)
Definition: unicode.h:34
#define strcmpiW(s1, s2)
Definition: unicode.h:39
#define tolowerW(n)
Definition: unicode.h:44
#define strlenW(s)
Definition: unicode.h:28
#define strcatW(d, s)
Definition: unicode.h:30
#define islowerW(n)
Definition: unicode.h:46
#define strncmpW(s1, s2, n)
Definition: unicode.h:36
#define strcpyW(d, s)
Definition: unicode.h:29
#define isalphaW(n)
Definition: unicode.h:48
#define E_POINTER
Definition: winerror.h:3480
BOOL WINAPI GetTextExtentPointW(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE lpsz)
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
struct _NETRESOURCEA * LPNETRESOURCEA
#define RESOURCEDISPLAYTYPE_SHARE
Definition: winnetwk.h:78
#define RESOURCEDISPLAYTYPE_GENERIC
Definition: winnetwk.h:75
#define RESOURCETYPE_DISK
Definition: winnetwk.h:64
#define RESOURCETYPE_ANY
Definition: winnetwk.h:63
struct _NETRESOURCEW * LPNETRESOURCEW
#define RESOURCE_GLOBALNET
Definition: winnetwk.h:59
#define NORM_IGNORECASE
Definition: winnls.h:187
#define CSTR_EQUAL
Definition: winnls.h:500
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define HKEY_CLASSES_ROOT
Definition: winreg.h:10
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
#define WM_GETFONT
Definition: winuser.h:1679
HWND WINAPI GetDlgItem(_In_opt_ HWND, _In_ int)
BOOL WINAPI SetWindowTextW(_In_ HWND, _In_opt_ LPCWSTR)
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
HDC WINAPI GetDC(_In_opt_ HWND)
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
DWORD WINAPI WNetGetResourceInformationA(LPNETRESOURCEA lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPSTR *lplpSystem)
Definition: wnet.c:1822
DWORD WINAPI WNetGetResourceInformationW(LPNETRESOURCEW lpNetResource, LPVOID lpBuffer, LPDWORD cbBuffer, LPWSTR *lplpSystem)
Definition: wnet.c:1937
unsigned char BYTE
Definition: xxhash.c:193