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