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