ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

path.c
Go to the documentation of this file.
00001 /*
00002  * Path Functions
00003  *
00004  * Copyright 1999, 2000 Juergen Schmied
00005  * Copyright 2001, 2002 Jon Griffiths
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "config.h"
00023 #include "wine/port.h"
00024 
00025 #include <stdarg.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 
00029 #include "wine/unicode.h"
00030 #include "windef.h"
00031 #include "winbase.h"
00032 #include "wingdi.h"
00033 #include "winuser.h"
00034 #include "winreg.h"
00035 #include "winternl.h"
00036 #define NO_SHLWAPI_STREAM
00037 #include "shlwapi.h"
00038 #include "wine/debug.h"
00039 
00040 WINE_DEFAULT_DEBUG_CHANNEL(shell);
00041 
00042 /* Get a function pointer from a DLL handle */
00043 #define GET_FUNC(func, module, name, fail) \
00044   do { \
00045     if (!func) { \
00046       if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
00047       func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \
00048       if (!func) return fail; \
00049     } \
00050   } while (0)
00051 
00052 /* DLL handles for late bound calls */
00053 static HMODULE SHLWAPI_hshell32;
00054 
00055 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
00056 typedef BOOL (WINAPI *fnpIsNetDrive)(int);
00057 static  fnpIsNetDrive pIsNetDrive;
00058 
00059 HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD);
00060 
00061 /*************************************************************************
00062  * PathAppendA    [SHLWAPI.@]
00063  *
00064  * Append one path to another.
00065  *
00066  * PARAMS
00067  *  lpszPath   [I/O] Initial part of path, and destination for output
00068  *  lpszAppend [I]   Path to append
00069  *
00070  * RETURNS
00071  *  Success: TRUE. lpszPath contains the newly created path.
00072  *  Failure: FALSE, if either path is NULL, or PathCombineA() fails.
00073  *
00074  * NOTES
00075  *  lpszAppend must contain at least one backslash ('\') if not NULL.
00076  *  Because PathCombineA() is used to join the paths, the resulting
00077  *  path is also canonicalized.
00078  */
00079 BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend)
00080 {
00081   TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend));
00082 
00083   if (lpszPath && lpszAppend)
00084   {
00085     if (!PathIsUNCA(lpszAppend))
00086       while (*lpszAppend == '\\')
00087         lpszAppend++;
00088     if (PathCombineA(lpszPath, lpszPath, lpszAppend))
00089       return TRUE;
00090   }
00091   return FALSE;
00092 }
00093 
00094 /*************************************************************************
00095  * PathAppendW    [SHLWAPI.@]
00096  *
00097  * See PathAppendA.
00098  */
00099 BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
00100 {
00101   TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend));
00102 
00103   if (lpszPath && lpszAppend)
00104   {
00105     if (!PathIsUNCW(lpszAppend))
00106       while (*lpszAppend == '\\')
00107         lpszAppend++;
00108     if (PathCombineW(lpszPath, lpszPath, lpszAppend))
00109       return TRUE;
00110   }
00111   return FALSE;
00112 }
00113 
00114 /*************************************************************************
00115  * PathCombineA     [SHLWAPI.@]
00116  *
00117  * Combine two paths together.
00118  *
00119  * PARAMS
00120  *  lpszDest [O] Destination for combined path
00121  *  lpszDir  [I] Directory path
00122  *  lpszFile [I] File path
00123  *
00124  * RETURNS
00125  *  Success: The output path
00126  *  Failure: NULL, if inputs are invalid.
00127  *
00128  * NOTES
00129  *  lpszDest should be at least MAX_PATH in size, and may point to the same
00130  *  memory location as lpszDir. The combined path is canonicalised.
00131  */
00132 LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile)
00133 {
00134   WCHAR szDest[MAX_PATH];
00135   WCHAR szDir[MAX_PATH];
00136   WCHAR szFile[MAX_PATH];
00137   TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile));
00138 
00139   /* Invalid parameters */
00140   if (!lpszDest)
00141     return NULL;
00142   if (!lpszDir && !lpszFile)
00143   {
00144     lpszDest[0] = 0;
00145     return NULL;
00146   }
00147 
00148   if (lpszDir)
00149     MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH);
00150   if (lpszFile)
00151     MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
00152 
00153   if (PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL))
00154     if (WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0))
00155       return lpszDest;
00156 
00157   lpszDest[0] = 0;
00158   return NULL;
00159 }
00160 
00161 /*************************************************************************
00162  * PathCombineW      [SHLWAPI.@]
00163  *
00164  * See PathCombineA.
00165  */
00166 LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
00167 {
00168   WCHAR szTemp[MAX_PATH];
00169   BOOL bUseBoth = FALSE, bStrip = FALSE;
00170 
00171   TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile));
00172 
00173   /* Invalid parameters */
00174   if (!lpszDest)
00175     return NULL;
00176   if (!lpszDir && !lpszFile)
00177   {
00178     lpszDest[0] = 0;
00179     return NULL;
00180   }
00181 
00182   if ((!lpszFile || !*lpszFile) && lpszDir)
00183   {
00184     /* Use dir only */
00185     lstrcpynW(szTemp, lpszDir, MAX_PATH);
00186   }
00187   else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile))
00188   {
00189     if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile))
00190     {
00191       /* Use file only */
00192       lstrcpynW(szTemp, lpszFile, MAX_PATH);
00193     }
00194     else
00195     {
00196       bUseBoth = TRUE;
00197       bStrip = TRUE;
00198     }
00199   }
00200   else
00201     bUseBoth = TRUE;
00202 
00203   if (bUseBoth)
00204   {
00205     lstrcpynW(szTemp, lpszDir, MAX_PATH);
00206     if (bStrip)
00207     {
00208       PathStripToRootW(szTemp);
00209       lpszFile++; /* Skip '\' */
00210     }
00211     if (!PathAddBackslashW(szTemp) || strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH)
00212     {
00213       lpszDest[0] = 0;
00214       return NULL;
00215     }
00216     strcatW(szTemp, lpszFile);
00217   }
00218 
00219   PathCanonicalizeW(lpszDest, szTemp);
00220   return lpszDest;
00221 }
00222 
00223 /*************************************************************************
00224  * PathAddBackslashA    [SHLWAPI.@]
00225  *
00226  * Append a backslash ('\') to a path if one doesn't exist.
00227  *
00228  * PARAMS
00229  *  lpszPath [I/O] The path to append a backslash to.
00230  *
00231  * RETURNS
00232  *  Success: The position of the last backslash in the path.
00233  *  Failure: NULL, if lpszPath is NULL or the path is too large.
00234  */
00235 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
00236 {
00237   size_t iLen;
00238   LPSTR prev = lpszPath;
00239 
00240   TRACE("(%s)\n",debugstr_a(lpszPath));
00241 
00242   if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH)
00243     return NULL;
00244 
00245   if (iLen)
00246   {
00247     do {
00248       lpszPath = CharNextA(prev);
00249       if (*lpszPath)
00250         prev = lpszPath;
00251     } while (*lpszPath);
00252     if (*prev != '\\')
00253     {
00254       *lpszPath++ = '\\';
00255       *lpszPath = '\0';
00256     }
00257   }
00258   return lpszPath;
00259 }
00260 
00261 /*************************************************************************
00262  * PathAddBackslashW  [SHLWAPI.@]
00263  *
00264  * See PathAddBackslashA.
00265  */
00266 LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath )
00267 {
00268   size_t iLen;
00269 
00270   TRACE("(%s)\n",debugstr_w(lpszPath));
00271 
00272   if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH)
00273     return NULL;
00274 
00275   if (iLen)
00276   {
00277     lpszPath += iLen;
00278     if (lpszPath[-1] != '\\')
00279     {
00280       *lpszPath++ = '\\';
00281       *lpszPath = '\0';
00282     }
00283   }
00284   return lpszPath;
00285 }
00286 
00287 /*************************************************************************
00288  * PathBuildRootA    [SHLWAPI.@]
00289  *
00290  * Create a root drive string (e.g. "A:\") from a drive number.
00291  *
00292  * PARAMS
00293  *  lpszPath [O] Destination for the drive string
00294  *
00295  * RETURNS
00296  *  lpszPath
00297  *
00298  * NOTES
00299  *  If lpszPath is NULL or drive is invalid, nothing is written to lpszPath.
00300  */
00301 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive)
00302 {
00303   TRACE("(%p,%d)\n", lpszPath, drive);
00304 
00305   if (lpszPath && drive >= 0 && drive < 26)
00306   {
00307     lpszPath[0] = 'A' + drive;
00308     lpszPath[1] = ':';
00309     lpszPath[2] = '\\';
00310     lpszPath[3] = '\0';
00311   }
00312   return lpszPath;
00313 }
00314 
00315 /*************************************************************************
00316  * PathBuildRootW    [SHLWAPI.@]
00317  *
00318  * See PathBuildRootA.
00319  */
00320 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive)
00321 {
00322   TRACE("(%p,%d)\n", lpszPath, drive);
00323 
00324   if (lpszPath && drive >= 0 && drive < 26)
00325   {
00326     lpszPath[0] = 'A' + drive;
00327     lpszPath[1] = ':';
00328     lpszPath[2] = '\\';
00329     lpszPath[3] = '\0';
00330   }
00331   return lpszPath;
00332 }
00333 
00334 /*************************************************************************
00335  * PathFindFileNameA  [SHLWAPI.@]
00336  *
00337  * Locate the start of the file name in a path
00338  *
00339  * PARAMS
00340  *  lpszPath [I] Path to search
00341  *
00342  * RETURNS
00343  *  A pointer to the first character of the file name
00344  */
00345 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
00346 {
00347   LPCSTR lastSlash = lpszPath;
00348 
00349   TRACE("(%s)\n",debugstr_a(lpszPath));
00350 
00351   while (lpszPath && *lpszPath)
00352   {
00353     if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
00354         lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
00355       lastSlash = lpszPath + 1;
00356     lpszPath = CharNextA(lpszPath);
00357   }
00358   return (LPSTR)lastSlash;
00359 }
00360 
00361 /*************************************************************************
00362  * PathFindFileNameW  [SHLWAPI.@]
00363  *
00364  * See PathFindFileNameA.
00365  */
00366 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
00367 {
00368   LPCWSTR lastSlash = lpszPath;
00369 
00370   TRACE("(%s)\n",debugstr_w(lpszPath));
00371 
00372   while (lpszPath && *lpszPath)
00373   {
00374     if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
00375         lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
00376       lastSlash = lpszPath + 1;
00377     lpszPath++;
00378   }
00379   return (LPWSTR)lastSlash;
00380 }
00381 
00382 /*************************************************************************
00383  * PathFindExtensionA  [SHLWAPI.@]
00384  *
00385  * Locate the start of the file extension in a path
00386  *
00387  * PARAMS
00388  *  lpszPath [I] The path to search
00389  *
00390  * RETURNS
00391  *  A pointer to the first character of the extension, the end of
00392  *  the string if the path has no extension, or NULL If lpszPath is NULL
00393  */
00394 LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath )
00395 {
00396   LPCSTR lastpoint = NULL;
00397 
00398   TRACE("(%s)\n", debugstr_a(lpszPath));
00399 
00400   if (lpszPath)
00401   {
00402     while (*lpszPath)
00403     {
00404       if (*lpszPath == '\\' || *lpszPath==' ')
00405         lastpoint = NULL;
00406       else if (*lpszPath == '.')
00407         lastpoint = lpszPath;
00408       lpszPath = CharNextA(lpszPath);
00409     }
00410   }
00411   return (LPSTR)(lastpoint ? lastpoint : lpszPath);
00412 }
00413 
00414 /*************************************************************************
00415  * PathFindExtensionW  [SHLWAPI.@]
00416  *
00417  * See PathFindExtensionA.
00418  */
00419 LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath )
00420 {
00421   LPCWSTR lastpoint = NULL;
00422 
00423   TRACE("(%s)\n", debugstr_w(lpszPath));
00424 
00425   if (lpszPath)
00426   {
00427     while (*lpszPath)
00428     {
00429       if (*lpszPath == '\\' || *lpszPath==' ')
00430         lastpoint = NULL;
00431       else if (*lpszPath == '.')
00432         lastpoint = lpszPath;
00433       lpszPath++;
00434     }
00435   }
00436   return (LPWSTR)(lastpoint ? lastpoint : lpszPath);
00437 }
00438 
00439 /*************************************************************************
00440  * PathGetArgsA    [SHLWAPI.@]
00441  *
00442  * Find the next argument in a string delimited by spaces.
00443  *
00444  * PARAMS
00445  *  lpszPath [I] The string to search for arguments in
00446  *
00447  * RETURNS
00448  *  The start of the next argument in lpszPath, or NULL if lpszPath is NULL
00449  *
00450  * NOTES
00451  *  Spaces in quoted strings are ignored as delimiters.
00452  */
00453 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath)
00454 {
00455   BOOL bSeenQuote = FALSE;
00456 
00457   TRACE("(%s)\n",debugstr_a(lpszPath));
00458 
00459   if (lpszPath)
00460   {
00461     while (*lpszPath)
00462     {
00463       if ((*lpszPath==' ') && !bSeenQuote)
00464         return (LPSTR)lpszPath + 1;
00465       if (*lpszPath == '"')
00466         bSeenQuote = !bSeenQuote;
00467       lpszPath = CharNextA(lpszPath);
00468     }
00469   }
00470   return (LPSTR)lpszPath;
00471 }
00472 
00473 /*************************************************************************
00474  * PathGetArgsW    [SHLWAPI.@]
00475  *
00476  * See PathGetArgsA.
00477  */
00478 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
00479 {
00480   BOOL bSeenQuote = FALSE;
00481 
00482   TRACE("(%s)\n",debugstr_w(lpszPath));
00483 
00484   if (lpszPath)
00485   {
00486     while (*lpszPath)
00487     {
00488       if ((*lpszPath==' ') && !bSeenQuote)
00489         return (LPWSTR)lpszPath + 1;
00490       if (*lpszPath == '"')
00491         bSeenQuote = !bSeenQuote;
00492       lpszPath++;
00493     }
00494   }
00495   return (LPWSTR)lpszPath;
00496 }
00497 
00498 /*************************************************************************
00499  * PathGetDriveNumberA  [SHLWAPI.@]
00500  *
00501  * Return the drive number from a path
00502  *
00503  * PARAMS
00504  *  lpszPath [I] Path to get the drive number from
00505  *
00506  * RETURNS
00507  *  Success: The drive number corresponding to the drive in the path
00508  *  Failure: -1, if lpszPath contains no valid drive
00509  */
00510 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
00511 {
00512   TRACE ("(%s)\n",debugstr_a(lpszPath));
00513 
00514   if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' &&
00515       tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z')
00516     return tolower(*lpszPath) - 'a';
00517   return -1;
00518 }
00519 
00520 /*************************************************************************
00521  * PathGetDriveNumberW  [SHLWAPI.@]
00522  *
00523  * See PathGetDriveNumberA.
00524  */
00525 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
00526 {
00527   TRACE ("(%s)\n",debugstr_w(lpszPath));
00528 
00529   if (lpszPath)
00530   {
00531       WCHAR tl = tolowerW(lpszPath[0]);
00532       if (tl >= 'a' && tl <= 'z' && lpszPath[1] == ':')
00533           return tl - 'a';
00534   }
00535   return -1;
00536 }
00537 
00538 /*************************************************************************
00539  * PathRemoveFileSpecA  [SHLWAPI.@]
00540  *
00541  * Remove the file specification from a path.
00542  *
00543  * PARAMS
00544  *  lpszPath [I/O] Path to remove the file spec from
00545  *
00546  * RETURNS
00547  *  TRUE  If the path was valid and modified
00548  *  FALSE Otherwise
00549  */
00550 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
00551 {
00552   LPSTR lpszFileSpec = lpszPath;
00553   BOOL bModified = FALSE;
00554 
00555   TRACE("(%s)\n",debugstr_a(lpszPath));
00556 
00557   if(lpszPath)
00558   {
00559     /* Skip directory or UNC path */
00560     if (*lpszPath == '\\')
00561       lpszFileSpec = ++lpszPath;
00562     if (*lpszPath == '\\')
00563       lpszFileSpec = ++lpszPath;
00564 
00565     while (*lpszPath)
00566     {
00567       if(*lpszPath == '\\')
00568         lpszFileSpec = lpszPath; /* Skip dir */
00569       else if(*lpszPath == ':')
00570       {
00571         lpszFileSpec = ++lpszPath; /* Skip drive */
00572         if (*lpszPath == '\\')
00573           lpszFileSpec++;
00574       }
00575       if (!(lpszPath = CharNextA(lpszPath)))
00576         break;
00577     }
00578 
00579     if (*lpszFileSpec)
00580     {
00581       *lpszFileSpec = '\0';
00582       bModified = TRUE;
00583     }
00584   }
00585   return bModified;
00586 }
00587 
00588 /*************************************************************************
00589  * PathRemoveFileSpecW  [SHLWAPI.@]
00590  *
00591  * See PathRemoveFileSpecA.
00592  */
00593 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
00594 {
00595   LPWSTR lpszFileSpec = lpszPath;
00596   BOOL bModified = FALSE;
00597 
00598   TRACE("(%s)\n",debugstr_w(lpszPath));
00599 
00600   if(lpszPath)
00601   {
00602     /* Skip directory or UNC path */
00603     if (*lpszPath == '\\')
00604       lpszFileSpec = ++lpszPath;
00605     if (*lpszPath == '\\')
00606       lpszFileSpec = ++lpszPath;
00607 
00608     while (*lpszPath)
00609     {
00610       if(*lpszPath == '\\')
00611         lpszFileSpec = lpszPath; /* Skip dir */
00612       else if(*lpszPath == ':')
00613       {
00614         lpszFileSpec = ++lpszPath; /* Skip drive */
00615         if (*lpszPath == '\\')
00616           lpszFileSpec++;
00617       }
00618       lpszPath++;
00619     }
00620 
00621     if (*lpszFileSpec)
00622     {
00623       *lpszFileSpec = '\0';
00624       bModified = TRUE;
00625     }
00626   }
00627   return bModified;
00628 }
00629 
00630 /*************************************************************************
00631  * PathStripPathA   [SHLWAPI.@]
00632  *
00633  * Remove the initial path from the beginning of a filename
00634  *
00635  * PARAMS
00636  *  lpszPath [I/O] Path to remove the initial path from
00637  *
00638  * RETURNS
00639  *  Nothing.
00640  */
00641 void WINAPI PathStripPathA(LPSTR lpszPath)
00642 {
00643   TRACE("(%s)\n", debugstr_a(lpszPath));
00644 
00645   if (lpszPath)
00646   {
00647     LPSTR lpszFileName = PathFindFileNameA(lpszPath);
00648     if(lpszFileName)
00649       RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1);
00650   }
00651 }
00652 
00653 /*************************************************************************
00654  * PathStripPathW   [SHLWAPI.@]
00655  *
00656  * See PathStripPathA.
00657  */
00658 void WINAPI PathStripPathW(LPWSTR lpszPath)
00659 {
00660   LPWSTR lpszFileName;
00661 
00662   TRACE("(%s)\n", debugstr_w(lpszPath));
00663   lpszFileName = PathFindFileNameW(lpszPath);
00664   if(lpszFileName)
00665     RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR));
00666 }
00667 
00668 /*************************************************************************
00669  * PathStripToRootA [SHLWAPI.@]
00670  *
00671  * Reduce a path to its root.
00672  *
00673  * PARAMS
00674  *  lpszPath [I/O] the path to reduce
00675  *
00676  * RETURNS
00677  *  Success: TRUE if the stripped path is a root path
00678  *  Failure: FALSE if the path cannot be stripped or is NULL
00679  */
00680 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
00681 {
00682   TRACE("(%s)\n", debugstr_a(lpszPath));
00683 
00684   if (!lpszPath)
00685     return FALSE;
00686   while(!PathIsRootA(lpszPath))
00687     if (!PathRemoveFileSpecA(lpszPath))
00688       return FALSE;
00689   return TRUE;
00690 }
00691 
00692 /*************************************************************************
00693  * PathStripToRootW [SHLWAPI.@]
00694  *
00695  * See PathStripToRootA.
00696  */
00697 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
00698 {
00699   TRACE("(%s)\n", debugstr_w(lpszPath));
00700 
00701   if (!lpszPath)
00702     return FALSE;
00703   while(!PathIsRootW(lpszPath))
00704     if (!PathRemoveFileSpecW(lpszPath))
00705       return FALSE;
00706   return TRUE;
00707 }
00708 
00709 /*************************************************************************
00710  * PathRemoveArgsA  [SHLWAPI.@]
00711  *
00712  * Strip space separated arguments from a path.
00713  *
00714  * PARAMS
00715  *  lpszPath [I/O] Path to remove arguments from
00716  *
00717  * RETURNS
00718  *  Nothing.
00719  */
00720 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
00721 {
00722   TRACE("(%s)\n",debugstr_a(lpszPath));
00723 
00724   if(lpszPath)
00725   {
00726     LPSTR lpszArgs = PathGetArgsA(lpszPath);
00727     if (*lpszArgs)
00728       lpszArgs[-1] = '\0';
00729     else
00730     {
00731       LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
00732       if(*lpszLastChar == ' ')
00733         *lpszLastChar = '\0';
00734     }
00735   }
00736 }
00737 
00738 /*************************************************************************
00739  * PathRemoveArgsW  [SHLWAPI.@]
00740  *
00741  * See PathRemoveArgsA.
00742  */
00743 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
00744 {
00745   TRACE("(%s)\n",debugstr_w(lpszPath));
00746 
00747   if(lpszPath)
00748   {
00749     LPWSTR lpszArgs = PathGetArgsW(lpszPath);
00750     if (*lpszArgs || (lpszArgs > lpszPath && lpszArgs[-1] == ' '))
00751       lpszArgs[-1] = '\0';
00752   }
00753 }
00754 
00755 /*************************************************************************
00756  * PathRemoveExtensionA     [SHLWAPI.@]
00757  *
00758  * Remove the file extension from a path
00759  *
00760  * PARAMS
00761  *  lpszPath [I/O] Path to remove the extension from
00762  *
00763  * RETURNS
00764  *  Nothing.
00765  */
00766 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
00767 {
00768   TRACE("(%s)\n", debugstr_a(lpszPath));
00769 
00770   if (lpszPath)
00771   {
00772     lpszPath = PathFindExtensionA(lpszPath);
00773     *lpszPath = '\0';
00774   }
00775 }
00776 
00777 /*************************************************************************
00778  * PathRemoveExtensionW     [SHLWAPI.@]
00779  *
00780  * See PathRemoveExtensionA.
00781 */
00782 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
00783 {
00784   TRACE("(%s)\n", debugstr_w(lpszPath));
00785 
00786   if (lpszPath)
00787   {
00788     lpszPath = PathFindExtensionW(lpszPath);
00789     *lpszPath = '\0';
00790   }
00791 }
00792 
00793 /*************************************************************************
00794  * PathRemoveBackslashA [SHLWAPI.@]
00795  *
00796  * Remove a trailing backslash from a path.
00797  *
00798  * PARAMS
00799  *  lpszPath [I/O] Path to remove backslash from
00800  *
00801  * RETURNS
00802  *  Success: A pointer to the end of the path
00803  *  Failure: NULL, if lpszPath is NULL
00804  */
00805 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
00806 {
00807   LPSTR szTemp = NULL;
00808 
00809   TRACE("(%s)\n", debugstr_a(lpszPath));
00810 
00811   if(lpszPath)
00812   {
00813     szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
00814     if (!PathIsRootA(lpszPath) && *szTemp == '\\')
00815       *szTemp = '\0';
00816   }
00817   return szTemp;
00818 }
00819 
00820 /*************************************************************************
00821  * PathRemoveBackslashW [SHLWAPI.@]
00822  *
00823  * See PathRemoveBackslashA.
00824  */
00825 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
00826 {
00827   LPWSTR szTemp = NULL;
00828 
00829   TRACE("(%s)\n", debugstr_w(lpszPath));
00830 
00831   if(lpszPath)
00832   {
00833     szTemp = lpszPath + strlenW(lpszPath);
00834     if (szTemp > lpszPath) szTemp--;
00835     if (!PathIsRootW(lpszPath) && *szTemp == '\\')
00836       *szTemp = '\0';
00837   }
00838   return szTemp;
00839 }
00840 
00841 /*************************************************************************
00842  * PathRemoveBlanksA [SHLWAPI.@]
00843  *
00844  * Remove Spaces from the start and end of a path.
00845  *
00846  * PARAMS
00847  *  lpszPath [I/O] Path to strip blanks from
00848  *
00849  * RETURNS
00850  *  Nothing.
00851  */
00852 VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath)
00853 {
00854   TRACE("(%s)\n", debugstr_a(lpszPath));
00855 
00856   if(lpszPath && *lpszPath)
00857   {
00858     LPSTR start = lpszPath;
00859 
00860     while (*lpszPath == ' ')
00861       lpszPath = CharNextA(lpszPath);
00862 
00863     while(*lpszPath)
00864       *start++ = *lpszPath++;
00865 
00866     if (start != lpszPath)
00867       while (start[-1] == ' ')
00868         start--;
00869     *start = '\0';
00870   }
00871 }
00872 
00873 /*************************************************************************
00874  * PathRemoveBlanksW [SHLWAPI.@]
00875  *
00876  * See PathRemoveBlanksA.
00877  */
00878 VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath)
00879 {
00880   TRACE("(%s)\n", debugstr_w(lpszPath));
00881 
00882   if(lpszPath && *lpszPath)
00883   {
00884     LPWSTR start = lpszPath;
00885 
00886     while (*lpszPath == ' ')
00887       lpszPath++;
00888 
00889     while(*lpszPath)
00890       *start++ = *lpszPath++;
00891 
00892     if (start != lpszPath)
00893       while (start[-1] == ' ')
00894         start--;
00895     *start = '\0';
00896   }
00897 }
00898 
00899 /*************************************************************************
00900  * PathQuoteSpacesA [SHLWAPI.@]
00901  *
00902  * Surround a path containing spaces in quotes.
00903  *
00904  * PARAMS
00905  *  lpszPath [I/O] Path to quote
00906  *
00907  * RETURNS
00908  *  Nothing.
00909  *
00910  * NOTES
00911  *  The path is not changed if it is invalid or has no spaces.
00912  */
00913 VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath)
00914 {
00915   TRACE("(%s)\n", debugstr_a(lpszPath));
00916 
00917   if(lpszPath && StrChrA(lpszPath,' '))
00918   {
00919     size_t iLen = strlen(lpszPath) + 1;
00920 
00921     if (iLen + 2 < MAX_PATH)
00922     {
00923       memmove(lpszPath + 1, lpszPath, iLen);
00924       lpszPath[0] = '"';
00925       lpszPath[iLen] = '"';
00926       lpszPath[iLen + 1] = '\0';
00927     }
00928   }
00929 }
00930 
00931 /*************************************************************************
00932  * PathQuoteSpacesW [SHLWAPI.@]
00933  *
00934  * See PathQuoteSpacesA.
00935  */
00936 VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
00937 {
00938   TRACE("(%s)\n", debugstr_w(lpszPath));
00939 
00940   if(lpszPath && StrChrW(lpszPath,' '))
00941   {
00942     int iLen = strlenW(lpszPath) + 1;
00943 
00944     if (iLen + 2 < MAX_PATH)
00945     {
00946       memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR));
00947       lpszPath[0] = '"';
00948       lpszPath[iLen] = '"';
00949       lpszPath[iLen + 1] = '\0';
00950     }
00951   }
00952 }
00953 
00954 /*************************************************************************
00955  * PathUnquoteSpacesA [SHLWAPI.@]
00956  *
00957  * Remove quotes ("") from around a path, if present.
00958  *
00959  * PARAMS
00960  *  lpszPath [I/O] Path to strip quotes from
00961  *
00962  * RETURNS
00963  *  Nothing
00964  *
00965  * NOTES
00966  *  If the path contains a single quote only, an empty string will result.
00967  *  Otherwise quotes are only removed if they appear at the start and end
00968  *  of the path.
00969  */
00970 VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath)
00971 {
00972   TRACE("(%s)\n", debugstr_a(lpszPath));
00973 
00974   if (lpszPath && *lpszPath == '"')
00975   {
00976     DWORD dwLen = strlen(lpszPath) - 1;
00977 
00978     if (lpszPath[dwLen] == '"')
00979     {
00980       lpszPath[dwLen] = '\0';
00981       for (; *lpszPath; lpszPath++)
00982         *lpszPath = lpszPath[1];
00983     }
00984   }
00985 }
00986 
00987 /*************************************************************************
00988  * PathUnquoteSpacesW [SHLWAPI.@]
00989  *
00990  * See PathUnquoteSpacesA.
00991  */
00992 VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath)
00993 {
00994   TRACE("(%s)\n", debugstr_w(lpszPath));
00995 
00996   if (lpszPath && *lpszPath == '"')
00997   {
00998     DWORD dwLen = strlenW(lpszPath) - 1;
00999 
01000     if (lpszPath[dwLen] == '"')
01001     {
01002       lpszPath[dwLen] = '\0';
01003       for (; *lpszPath; lpszPath++)
01004         *lpszPath = lpszPath[1];
01005     }
01006   }
01007 }
01008 
01009 /*************************************************************************
01010  * PathParseIconLocationA  [SHLWAPI.@]
01011  *
01012  * Parse the location of an icon from a path.
01013  *
01014  * PARAMS
01015  *  lpszPath [I/O] The path to parse the icon location from.
01016  *
01017  * RETURNS
01018  *  Success: The number of the icon
01019  *  Failure: 0 if the path does not contain an icon location or is NULL
01020  *
01021  * NOTES
01022  *  The path has surrounding quotes and spaces removed regardless
01023  *  of whether the call succeeds or not.
01024  */
01025 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
01026 {
01027   int iRet = 0;
01028   LPSTR lpszComma;
01029 
01030   TRACE("(%s)\n", debugstr_a(lpszPath));
01031 
01032   if (lpszPath)
01033   {
01034     if ((lpszComma = strchr(lpszPath, ',')))
01035     {
01036       *lpszComma++ = '\0';
01037       iRet = StrToIntA(lpszComma);
01038     }
01039     PathUnquoteSpacesA(lpszPath);
01040     PathRemoveBlanksA(lpszPath);
01041   }
01042   return iRet;
01043 }
01044 
01045 /*************************************************************************
01046  * PathParseIconLocationW  [SHLWAPI.@]
01047  *
01048  * See PathParseIconLocationA.
01049  */
01050 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
01051 {
01052   int iRet = 0;
01053   LPWSTR lpszComma;
01054 
01055   TRACE("(%s)\n", debugstr_w(lpszPath));
01056 
01057   if (lpszPath)
01058   {
01059     if ((lpszComma = StrChrW(lpszPath, ',')))
01060     {
01061       *lpszComma++ = '\0';
01062       iRet = StrToIntW(lpszComma);
01063     }
01064     PathUnquoteSpacesW(lpszPath);
01065     PathRemoveBlanksW(lpszPath);
01066   }
01067   return iRet;
01068 }
01069 
01070 /*************************************************************************
01071  * @    [SHLWAPI.4]
01072  *
01073  * Unicode version of PathFileExistsDefExtA.
01074  */
01075 BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich)
01076 {
01077   static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', 0},
01078                                        { '.', 'c', 'o', 'm', 0},
01079                                        { '.', 'e', 'x', 'e', 0},
01080                                        { '.', 'b', 'a', 't', 0},
01081                                        { '.', 'l', 'n', 'k', 0},
01082                                        { '.', 'c', 'm', 'd', 0},
01083                                        { 0, 0, 0, 0, 0} };
01084 
01085   TRACE("(%s,%d)\n", debugstr_w(lpszPath), dwWhich);
01086 
01087   if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath))
01088     return FALSE;
01089 
01090   if (dwWhich)
01091   {
01092     LPCWSTR szExt = PathFindExtensionW(lpszPath);
01093     if (!*szExt || dwWhich & 0x40)
01094     {
01095       size_t iChoose = 0;
01096       int iLen = lstrlenW(lpszPath);
01097       if (iLen > (MAX_PATH - 5))
01098         return FALSE;
01099       while ( (dwWhich & 0x1) && pszExts[iChoose][0] )
01100       {
01101         lstrcpyW(lpszPath + iLen, pszExts[iChoose]);
01102         if (PathFileExistsW(lpszPath))
01103           return TRUE;
01104         iChoose++;
01105         dwWhich >>= 1;
01106       }
01107       *(lpszPath + iLen) = (WCHAR)'\0';
01108       return FALSE;
01109     }
01110   }
01111   return PathFileExistsW(lpszPath);
01112 }
01113 
01114 /*************************************************************************
01115  * @    [SHLWAPI.3]
01116  *
01117  * Determine if a file exists locally and is of an executable type.
01118  *
01119  * PARAMS
01120  *  lpszPath       [I/O] File to search for
01121  *  dwWhich        [I]   Type of executable to search for
01122  *
01123  * RETURNS
01124  *  TRUE  If the file was found. lpszPath contains the file name.
01125  *  FALSE Otherwise.
01126  *
01127  * NOTES
01128  *  lpszPath is modified in place and must be at least MAX_PATH in length.
01129  *  If the function returns FALSE, the path is modified to its original state.
01130  *  If the given path contains an extension or dwWhich is 0, executable
01131  *  extensions are not checked.
01132  *
01133  *  Ordinals 3-6 are a classic case of MS exposing limited functionality to
01134  *  users (here through PathFindOnPathA()) and keeping advanced functionality for
01135  *  their own developers exclusive use. Monopoly, anyone?
01136  */
01137 BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich)
01138 {
01139   BOOL bRet = FALSE;
01140 
01141   TRACE("(%s,%d)\n", debugstr_a(lpszPath), dwWhich);
01142 
01143   if (lpszPath)
01144   {
01145     WCHAR szPath[MAX_PATH];
01146     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
01147     bRet = PathFileExistsDefExtW(szPath, dwWhich);
01148     if (bRet)
01149       WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
01150   }
01151   return bRet;
01152 }
01153 
01154 /*************************************************************************
01155  * SHLWAPI_PathFindInOtherDirs
01156  *
01157  * Internal helper for SHLWAPI_PathFindOnPathExA/W.
01158  */
01159 static BOOL SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich)
01160 {
01161   static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
01162   static const WCHAR szPath[] = { 'P','A','T','H','\0'};
01163   DWORD dwLenPATH;
01164   LPCWSTR lpszCurr;
01165   WCHAR *lpszPATH;
01166   WCHAR buff[MAX_PATH];
01167 
01168   TRACE("(%s,%08x)\n", debugstr_w(lpszFile), dwWhich);
01169 
01170   /* Try system directories */
01171   GetSystemDirectoryW(buff, MAX_PATH);
01172   if (!PathAppendW(buff, lpszFile))
01173      return FALSE;
01174   if (PathFileExistsDefExtW(buff, dwWhich))
01175   {
01176     strcpyW(lpszFile, buff);
01177     return TRUE;
01178   }
01179   GetWindowsDirectoryW(buff, MAX_PATH);
01180   if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile))
01181     return FALSE;
01182   if (PathFileExistsDefExtW(buff, dwWhich))
01183   {
01184     strcpyW(lpszFile, buff);
01185     return TRUE;
01186   }
01187   GetWindowsDirectoryW(buff, MAX_PATH);
01188   if (!PathAppendW(buff, lpszFile))
01189     return FALSE;
01190   if (PathFileExistsDefExtW(buff, dwWhich))
01191   {
01192     strcpyW(lpszFile, buff);
01193     return TRUE;
01194   }
01195   /* Try dirs listed in %PATH% */
01196   dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH);
01197 
01198   if (!dwLenPATH || !(lpszPATH = HeapAlloc(GetProcessHeap(), 0, (dwLenPATH + 1) * sizeof (WCHAR))))
01199     return FALSE;
01200 
01201   GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1);
01202   lpszCurr = lpszPATH;
01203   while (lpszCurr)
01204   {
01205     LPCWSTR lpszEnd = lpszCurr;
01206     LPWSTR pBuff = buff;
01207 
01208     while (*lpszEnd == ' ')
01209       lpszEnd++;
01210     while (*lpszEnd && *lpszEnd != ';')
01211       *pBuff++ = *lpszEnd++;
01212     *pBuff = '\0';
01213 
01214     if (*lpszEnd)
01215       lpszCurr = lpszEnd + 1;
01216     else
01217       lpszCurr = NULL; /* Last Path, terminate after this */
01218 
01219     if (!PathAppendW(buff, lpszFile))
01220     {
01221       HeapFree(GetProcessHeap(), 0, lpszPATH);
01222       return FALSE;
01223     }
01224     if (PathFileExistsDefExtW(buff, dwWhich))
01225     {
01226       strcpyW(lpszFile, buff);
01227       HeapFree(GetProcessHeap(), 0, lpszPATH);
01228       return TRUE;
01229     }
01230   }
01231   HeapFree(GetProcessHeap(), 0, lpszPATH);
01232   return FALSE;
01233 }
01234 
01235 /*************************************************************************
01236  * @    [SHLWAPI.5]
01237  *
01238  * Search a range of paths for a specific type of executable.
01239  *
01240  * PARAMS
01241  *  lpszFile       [I/O] File to search for
01242  *  lppszOtherDirs [I]   Other directories to look in
01243  *  dwWhich        [I]   Type of executable to search for
01244  *
01245  * RETURNS
01246  *  Success: TRUE. The path to the executable is stored in lpszFile.
01247  *  Failure: FALSE. The path to the executable is unchanged.
01248  */
01249 BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich)
01250 {
01251   WCHAR szFile[MAX_PATH];
01252   WCHAR buff[MAX_PATH];
01253 
01254   TRACE("(%s,%p,%08x)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich);
01255 
01256   if (!lpszFile || !PathIsFileSpecA(lpszFile))
01257     return FALSE;
01258 
01259   MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH);
01260 
01261   /* Search provided directories first */
01262   if (lppszOtherDirs && *lppszOtherDirs)
01263   {
01264     WCHAR szOther[MAX_PATH];
01265     LPCSTR *lpszOtherPath = lppszOtherDirs;
01266 
01267     while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
01268     {
01269       MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH);
01270       PathCombineW(buff, szOther, szFile);
01271       if (PathFileExistsDefExtW(buff, dwWhich))
01272       {
01273         WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0);
01274         return TRUE;
01275       }
01276       lpszOtherPath++;
01277     }
01278   }
01279   /* Not found, try system and path dirs */
01280   if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich))
01281   {
01282     WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0);
01283     return TRUE;
01284   }
01285   return FALSE;
01286 }
01287 
01288 /*************************************************************************
01289  * @    [SHLWAPI.6]
01290  *
01291  * Unicode version of PathFindOnPathExA.
01292  */
01293 BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich)
01294 {
01295   WCHAR buff[MAX_PATH];
01296 
01297   TRACE("(%s,%p,%08x)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich);
01298 
01299   if (!lpszFile || !PathIsFileSpecW(lpszFile))
01300     return FALSE;
01301 
01302   /* Search provided directories first */
01303   if (lppszOtherDirs && *lppszOtherDirs)
01304   {
01305     LPCWSTR *lpszOtherPath = lppszOtherDirs;
01306     while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
01307     {
01308       PathCombineW(buff, *lpszOtherPath, lpszFile);
01309       if (PathFileExistsDefExtW(buff, dwWhich))
01310       {
01311         strcpyW(lpszFile, buff);
01312         return TRUE;
01313       }
01314       lpszOtherPath++;
01315     }
01316   }
01317   /* Not found, try system and path dirs */
01318   return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich);
01319 }
01320 
01321 /*************************************************************************
01322  * PathFindOnPathA  [SHLWAPI.@]
01323  *
01324  * Search a range of paths for an executable.
01325  *
01326  * PARAMS
01327  *  lpszFile       [I/O] File to search for
01328  *  lppszOtherDirs [I]   Other directories to look in
01329  *
01330  * RETURNS
01331  *  Success: TRUE. The path to the executable is stored in lpszFile.
01332  *  Failure: FALSE. The path to the executable is unchanged.
01333  */
01334 BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs)
01335 {
01336   TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs);
01337   return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0);
01338  }
01339 
01340 /*************************************************************************
01341  * PathFindOnPathW      [SHLWAPI.@]
01342  *
01343  * See PathFindOnPathA.
01344  */
01345 BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
01346 {
01347   TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs);
01348   return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0);
01349 }
01350 
01351 /*************************************************************************
01352  * PathCompactPathExA   [SHLWAPI.@]
01353  *
01354  * Compact a path into a given number of characters.
01355  *
01356  * PARAMS
01357  *  lpszDest [O] Destination for compacted path
01358  *  lpszPath [I] Source path
01359  *  cchMax   [I] Maximum size of compacted path
01360  *  dwFlags  [I] Reserved
01361  *
01362  * RETURNS
01363  *  Success: TRUE. The compacted path is written to lpszDest.
01364  *  Failure: FALSE. lpszPath is undefined.
01365  *
01366  * NOTES
01367  *  If cchMax is given as 0, lpszDest will still be NUL terminated.
01368  *
01369  *  The Win32 version of this function contains a bug: When cchMax == 7,
01370  *  8 bytes will be written to lpszDest. This bug is fixed in the Wine
01371  *  implementation.
01372  *
01373  *  Some relative paths will be different when cchMax == 5 or 6. This occurs
01374  *  because Win32 will insert a "\" in lpszDest, even if one is
01375  *  not present in the original path.
01376  */
01377 BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath,
01378                                UINT cchMax, DWORD dwFlags)
01379 {
01380   BOOL bRet = FALSE;
01381 
01382   TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags);
01383 
01384   if (lpszPath && lpszDest)
01385   {
01386     WCHAR szPath[MAX_PATH];
01387     WCHAR szDest[MAX_PATH];
01388 
01389     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
01390     szDest[0] = '\0';
01391     bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags);
01392     WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0);
01393   }
01394   return bRet;
01395 }
01396 
01397 /*************************************************************************
01398  * PathCompactPathExW   [SHLWAPI.@]
01399  *
01400  * See PathCompactPathExA.
01401  */
01402 BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath,
01403                                UINT cchMax, DWORD dwFlags)
01404 {
01405   static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
01406   LPCWSTR lpszFile;
01407   DWORD dwLen, dwFileLen = 0;
01408 
01409   TRACE("(%p,%s,%d,0x%08x)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags);
01410 
01411   if (!lpszPath)
01412     return FALSE;
01413 
01414   if (!lpszDest)
01415   {
01416     WARN("Invalid lpszDest would crash under Win32!\n");
01417     return FALSE;
01418   }
01419 
01420   *lpszDest = '\0';
01421 
01422   if (cchMax < 2)
01423     return TRUE;
01424 
01425   dwLen = strlenW(lpszPath) + 1;
01426 
01427   if (dwLen < cchMax)
01428   {
01429     /* Don't need to compact */
01430     memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
01431     return TRUE;
01432   }
01433 
01434   /* Path must be compacted to fit into lpszDest */
01435   lpszFile = PathFindFileNameW(lpszPath);
01436   dwFileLen = lpszPath + dwLen - lpszFile;
01437 
01438   if (dwFileLen == dwLen)
01439   {
01440     /* No root in psth */
01441     if (cchMax <= 4)
01442     {
01443       while (--cchMax > 0) /* No room left for anything but ellipses */
01444         *lpszDest++ = '.';
01445       *lpszDest = '\0';
01446       return TRUE;
01447     }
01448     /* Compact the file name with ellipses at the end */
01449     cchMax -= 4;
01450     memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
01451     strcpyW(lpszDest + cchMax, szEllipses);
01452     return TRUE;
01453   }
01454   /* We have a root in the path */
01455   lpszFile--; /* Start compacted filename with the path separator */
01456   dwFileLen++;
01457 
01458   if (dwFileLen + 3 > cchMax)
01459   {
01460     /* Compact the file name */
01461     if (cchMax <= 4)
01462     {
01463       while (--cchMax > 0) /* No room left for anything but ellipses */
01464         *lpszDest++ = '.';
01465       *lpszDest = '\0';
01466       return TRUE;
01467     }
01468     strcpyW(lpszDest, szEllipses);
01469     lpszDest += 3;
01470     cchMax -= 4;
01471     *lpszDest++ = *lpszFile++;
01472     if (cchMax <= 4)
01473     {
01474       while (--cchMax > 0) /* No room left for anything but ellipses */
01475         *lpszDest++ = '.';
01476       *lpszDest = '\0';
01477       return TRUE;
01478     }
01479     cchMax -= 4;
01480     memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR));
01481     strcpyW(lpszDest + cchMax, szEllipses);
01482     return TRUE;
01483   }
01484 
01485   /* Only the root needs to be Compacted */
01486   dwLen = cchMax - dwFileLen - 3;
01487   memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR));
01488   strcpyW(lpszDest + dwLen, szEllipses);
01489   strcpyW(lpszDest + dwLen + 3, lpszFile);
01490   return TRUE;
01491 }
01492 
01493 /*************************************************************************
01494  * PathIsRelativeA  [SHLWAPI.@]
01495  *
01496  * Determine if a path is a relative path.
01497  *
01498  * PARAMS
01499  *  lpszPath [I] Path to check
01500  *
01501  * RETURNS
01502  *  TRUE:  The path is relative, or is invalid.
01503  *  FALSE: The path is not relative.
01504  */
01505 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
01506 {
01507   TRACE("(%s)\n",debugstr_a(lpszPath));
01508 
01509   if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath))
01510     return TRUE;
01511   if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
01512     return FALSE;
01513   return TRUE;
01514 }
01515 
01516 /*************************************************************************
01517  *  PathIsRelativeW [SHLWAPI.@]
01518  *
01519  * See PathIsRelativeA.
01520  */
01521 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
01522 {
01523   TRACE("(%s)\n",debugstr_w(lpszPath));
01524 
01525   if (!lpszPath || !*lpszPath)
01526     return TRUE;
01527   if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
01528     return FALSE;
01529   return TRUE;
01530 }
01531 
01532 /*************************************************************************
01533  * PathIsRootA      [SHLWAPI.@]
01534  *
01535  * Determine if a path is a root path.
01536  *
01537  * PARAMS
01538  *  lpszPath [I] Path to check
01539  *
01540  * RETURNS
01541  *  TRUE  If lpszPath is valid and a root path,
01542  *  FALSE Otherwise
01543  */
01544 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
01545 {
01546   TRACE("(%s)\n", debugstr_a(lpszPath));
01547 
01548   if (lpszPath && *lpszPath)
01549   {
01550     if (*lpszPath == '\\')
01551     {
01552       if (!lpszPath[1])
01553         return TRUE; /* \ */
01554       else if (lpszPath[1]=='\\')
01555       {
01556         BOOL bSeenSlash = FALSE;
01557         lpszPath += 2;
01558 
01559         /* Check for UNC root path */
01560         while (*lpszPath)
01561         {
01562           if (*lpszPath == '\\')
01563           {
01564             if (bSeenSlash)
01565               return FALSE;
01566             bSeenSlash = TRUE;
01567           }
01568           lpszPath = CharNextA(lpszPath);
01569         }
01570         return TRUE;
01571       }
01572     }
01573     else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
01574       return TRUE; /* X:\ */
01575   }
01576   return FALSE;
01577 }
01578 
01579 /*************************************************************************
01580  * PathIsRootW      [SHLWAPI.@]
01581  *
01582  * See PathIsRootA.
01583  */
01584 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath)
01585 {
01586   TRACE("(%s)\n", debugstr_w(lpszPath));
01587 
01588   if (lpszPath && *lpszPath)
01589   {
01590     if (*lpszPath == '\\')
01591     {
01592       if (!lpszPath[1])
01593         return TRUE; /* \ */
01594       else if (lpszPath[1]=='\\')
01595       {
01596         BOOL bSeenSlash = FALSE;
01597         lpszPath += 2;
01598 
01599         /* Check for UNC root path */
01600         while (*lpszPath)
01601         {
01602           if (*lpszPath == '\\')
01603           {
01604             if (bSeenSlash)
01605               return FALSE;
01606             bSeenSlash = TRUE;
01607           }
01608           lpszPath++;
01609         }
01610         return TRUE;
01611       }
01612     }
01613     else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
01614       return TRUE; /* X:\ */
01615   }
01616   return FALSE;
01617 }
01618 
01619 /*************************************************************************
01620  * PathIsDirectoryA [SHLWAPI.@]
01621  *
01622  * Determine if a path is a valid directory
01623  *
01624  * PARAMS
01625  *  lpszPath [I] Path to check.
01626  *
01627  * RETURNS
01628  *  FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes)
01629  *  FALSE if lpszPath is invalid or not a directory.
01630  *
01631  * NOTES
01632  *  Although this function is prototyped as returning a BOOL, it returns
01633  *  FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as:
01634  *
01635  *|  if (PathIsDirectoryA("c:\\windows\\") == TRUE)
01636  *|    ...
01637  *
01638  *  will always fail.
01639  */
01640 BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
01641 {
01642   DWORD dwAttr;
01643 
01644   TRACE("(%s)\n", debugstr_a(lpszPath));
01645 
01646   if (!lpszPath || PathIsUNCServerA(lpszPath))
01647     return FALSE;
01648 
01649   if (PathIsUNCServerShareA(lpszPath))
01650   {
01651     FIXME("UNC Server Share not yet supported - FAILING\n");
01652     return FALSE;
01653   }
01654 
01655   if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES)
01656     return FALSE;
01657   return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
01658 }
01659 
01660 /*************************************************************************
01661  * PathIsDirectoryW [SHLWAPI.@]
01662  *
01663  * See PathIsDirectoryA.
01664  */
01665 BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
01666 {
01667   DWORD dwAttr;
01668 
01669   TRACE("(%s)\n", debugstr_w(lpszPath));
01670 
01671   if (!lpszPath || PathIsUNCServerW(lpszPath))
01672     return FALSE;
01673 
01674   if (PathIsUNCServerShareW(lpszPath))
01675   {
01676     FIXME("UNC Server Share not yet supported - FAILING\n");
01677     return FALSE;
01678   }
01679 
01680   if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
01681     return FALSE;
01682   return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
01683 }
01684 
01685 /*************************************************************************
01686  * PathFileExistsA  [SHLWAPI.@]
01687  *
01688  * Determine if a file exists.
01689  *
01690  * PARAMS
01691  *  lpszPath [I] Path to check
01692  *
01693  * RETURNS
01694  *  TRUE  If the file exists and is readable
01695  *  FALSE Otherwise
01696  */
01697 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath)
01698 {
01699   UINT iPrevErrMode;
01700   DWORD dwAttr;
01701 
01702   TRACE("(%s)\n",debugstr_a(lpszPath));
01703 
01704   if (!lpszPath)
01705     return FALSE;
01706 
01707   /* Prevent a dialog box if path is on a disk that has been ejected. */
01708   iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
01709   dwAttr = GetFileAttributesA(lpszPath);
01710   SetErrorMode(iPrevErrMode);
01711   return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE;
01712 }
01713 
01714 /*************************************************************************
01715  * PathFileExistsW  [SHLWAPI.@]
01716  *
01717  * See PathFileExistsA.
01718  */
01719 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
01720 {
01721   UINT iPrevErrMode;
01722   DWORD dwAttr;
01723 
01724   TRACE("(%s)\n",debugstr_w(lpszPath));
01725 
01726   if (!lpszPath)
01727     return FALSE;
01728 
01729   iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
01730   dwAttr = GetFileAttributesW(lpszPath);
01731   SetErrorMode(iPrevErrMode);
01732   return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE;
01733 }
01734 
01735 /*************************************************************************
01736  * PathFileExistsAndAttributesA [SHLWAPI.445]
01737  *
01738  * Determine if a file exists.
01739  *
01740  * PARAMS
01741  *  lpszPath [I] Path to check
01742  *  dwAttr   [O] attributes of file
01743  *
01744  * RETURNS
01745  *  TRUE  If the file exists and is readable
01746  *  FALSE Otherwise
01747  */
01748 BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr)
01749 {
01750   UINT iPrevErrMode;
01751   DWORD dwVal = 0;
01752 
01753   TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr);
01754 
01755   if (dwAttr)
01756     *dwAttr = INVALID_FILE_ATTRIBUTES;
01757 
01758   if (!lpszPath)
01759     return FALSE;
01760 
01761   iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
01762   dwVal = GetFileAttributesA(lpszPath);
01763   SetErrorMode(iPrevErrMode);
01764   if (dwAttr)
01765     *dwAttr = dwVal;
01766   return (dwVal != INVALID_FILE_ATTRIBUTES);
01767 }
01768 
01769 /*************************************************************************
01770  * PathFileExistsAndAttributesW [SHLWAPI.446]
01771  *
01772  * See PathFileExistsA.
01773  */
01774 BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr)
01775 {
01776   UINT iPrevErrMode;
01777   DWORD dwVal;
01778 
01779   TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr);
01780 
01781   if (!lpszPath)
01782     return FALSE;
01783 
01784   iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
01785   dwVal = GetFileAttributesW(lpszPath);
01786   SetErrorMode(iPrevErrMode);
01787   if (dwAttr)
01788     *dwAttr = dwVal;
01789   return (dwVal != INVALID_FILE_ATTRIBUTES);
01790 }
01791 
01792 /*************************************************************************
01793  * PathMatchSingleMaskA [internal]
01794  */
01795 static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
01796 {
01797   while (*name && *mask && *mask!=';')
01798   {
01799     if (*mask == '*')
01800     {
01801       do
01802       {
01803         if (PathMatchSingleMaskA(name,mask+1))
01804           return TRUE;  /* try substrings */
01805       } while (*name++);
01806       return FALSE;
01807     }
01808 
01809     if (toupper(*mask) != toupper(*name) && *mask != '?')
01810       return FALSE;
01811 
01812     name = CharNextA(name);
01813     mask = CharNextA(mask);
01814   }
01815 
01816   if (!*name)
01817   {
01818     while (*mask == '*')
01819       mask++;
01820     if (!*mask || *mask == ';')
01821       return TRUE;
01822   }
01823   return FALSE;
01824 }
01825 
01826 /*************************************************************************
01827  * PathMatchSingleMaskW [internal]
01828  */
01829 static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
01830 {
01831   while (*name && *mask && *mask != ';')
01832   {
01833     if (*mask == '*')
01834     {
01835       do
01836       {
01837         if (PathMatchSingleMaskW(name,mask+1))
01838           return TRUE;  /* try substrings */
01839       } while (*name++);
01840       return FALSE;
01841     }
01842 
01843     if (toupperW(*mask) != toupperW(*name) && *mask != '?')
01844       return FALSE;
01845 
01846     name++;
01847     mask++;
01848   }
01849   if (!*name)
01850   {
01851     while (*mask == '*')
01852       mask++;
01853     if (!*mask || *mask == ';')
01854       return TRUE;
01855   }
01856   return FALSE;
01857 }
01858 
01859 /*************************************************************************
01860  * PathMatchSpecA   [SHLWAPI.@]
01861  *
01862  * Determine if a path matches one or more search masks.
01863  *
01864  * PARAMS
01865  *  lpszPath [I] Path to check
01866  *  lpszMask [I] Search mask(s)
01867  *
01868  * RETURNS
01869  *  TRUE  If lpszPath is valid and is matched
01870  *  FALSE Otherwise
01871  *
01872  * NOTES
01873  *  Multiple search masks may be given if they are separated by ";". The
01874  *  pattern "*.*" is treated specially in that it matches all paths (for
01875  *  backwards compatibility with DOS).
01876  */
01877 BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask)
01878 {
01879   TRACE("(%s,%s)\n", lpszPath, lpszMask);
01880 
01881   if (!lstrcmpA(lpszMask, "*.*"))
01882     return TRUE; /* Matches every path */
01883 
01884   while (*lpszMask)
01885   {
01886     while (*lpszMask == ' ')
01887       lpszMask++; /* Eat leading spaces */
01888 
01889     if (PathMatchSingleMaskA(lpszPath, lpszMask))
01890       return TRUE; /* Matches the current mask */
01891 
01892     while (*lpszMask && *lpszMask != ';')
01893       lpszMask = CharNextA(lpszMask); /* masks separated by ';' */
01894 
01895     if (*lpszMask == ';')
01896       lpszMask++;
01897   }
01898   return FALSE;
01899 }
01900 
01901 /*************************************************************************
01902  * PathMatchSpecW   [SHLWAPI.@]
01903  *
01904  * See PathMatchSpecA.
01905  */
01906 BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask)
01907 {
01908   static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' };
01909 
01910   TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask));
01911 
01912   if (!lstrcmpW(lpszMask, szStarDotStar))
01913     return TRUE; /* Matches every path */
01914 
01915   while (*lpszMask)
01916   {
01917     while (*lpszMask == ' ')
01918       lpszMask++; /* Eat leading spaces */
01919 
01920     if (PathMatchSingleMaskW(lpszPath, lpszMask))
01921       return TRUE; /* Matches the current path */
01922 
01923     while (*lpszMask && *lpszMask != ';')
01924       lpszMask++; /* masks separated by ';' */
01925 
01926     if (*lpszMask == ';')
01927       lpszMask++;
01928   }
01929   return FALSE;
01930 }
01931 
01932 /*************************************************************************
01933  * PathIsSameRootA  [SHLWAPI.@]
01934  *
01935  * Determine if two paths share the same root.
01936  *
01937  * PARAMS
01938  *  lpszPath1 [I] Source path
01939  *  lpszPath2 [I] Path to compare with
01940  *
01941  * RETURNS
01942  *  TRUE  If both paths are valid and share the same root.
01943  *  FALSE If either path is invalid or the paths do not share the same root.
01944  */
01945 BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
01946 {
01947   LPCSTR lpszStart;
01948   int dwLen;
01949 
01950   TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2));
01951 
01952   if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1)))
01953     return FALSE;
01954 
01955   dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1;
01956   if (lpszStart - lpszPath1 > dwLen)
01957     return FALSE; /* Paths not common up to length of the root */
01958   return TRUE;
01959 }
01960 
01961 /*************************************************************************
01962  * PathIsSameRootW  [SHLWAPI.@]
01963  *
01964  * See PathIsSameRootA.
01965  */
01966 BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
01967 {
01968   LPCWSTR lpszStart;
01969   int dwLen;
01970 
01971   TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
01972 
01973   if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1)))
01974     return FALSE;
01975 
01976   dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1;
01977   if (lpszStart - lpszPath1 > dwLen)
01978     return FALSE; /* Paths not common up to length of the root */
01979   return TRUE;
01980 }
01981 
01982 /*************************************************************************
01983  * PathIsContentTypeA   [SHLWAPI.@]
01984  *
01985  * Determine if a file is of a given registered content type.
01986  *
01987  * PARAMS
01988  *  lpszPath        [I] File to check
01989  *  lpszContentType [I] Content type to check for
01990  *
01991  * RETURNS
01992  *  TRUE  If lpszPath is a given registered content type,
01993  *  FALSE Otherwise.
01994  *
01995  * NOTES
01996  *  This function looks up the registered content type for lpszPath. If
01997  *  a content type is registered, it is compared (case insensitively) to
01998  *  lpszContentType. Only if this matches does the function succeed.
01999  */
02000 BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType)
02001 {
02002   LPCSTR szExt;
02003   DWORD dwDummy;
02004   char szBuff[MAX_PATH];
02005 
02006   TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType));
02007 
02008   if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt &&
02009       !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type",
02010                    REG_NONE, szBuff, &dwDummy) &&
02011       !strcasecmp(lpszContentType, szBuff))
02012   {
02013     return TRUE;
02014   }
02015   return FALSE;
02016 }
02017 
02018 /*************************************************************************
02019  * PathIsContentTypeW   [SHLWAPI.@]
02020  *
02021  * See PathIsContentTypeA.
02022  */
02023 BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType)
02024 {
02025   static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' };
02026   LPCWSTR szExt;
02027   DWORD dwDummy;
02028   WCHAR szBuff[MAX_PATH];
02029 
02030   TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType));
02031 
02032   if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt &&
02033       !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType,
02034                    REG_NONE, szBuff, &dwDummy) &&
02035       !strcmpiW(lpszContentType, szBuff))
02036   {
02037     return TRUE;
02038   }
02039   return FALSE;
02040 }
02041 
02042 /*************************************************************************
02043  * PathIsFileSpecA   [SHLWAPI.@]
02044  *
02045  * Determine if a path is a file specification.
02046  *
02047  * PARAMS
02048  *  lpszPath [I] Path to check
02049  *
02050  * RETURNS
02051  *  TRUE  If lpszPath is a file specification (i.e. Contains no directories).
02052  *  FALSE Otherwise.
02053  */
02054 BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath)
02055 {
02056   TRACE("(%s)\n", debugstr_a(lpszPath));
02057 
02058   if (!lpszPath)
02059     return FALSE;
02060 
02061   while (*lpszPath)
02062   {
02063     if (*lpszPath == '\\' || *lpszPath == ':')
02064       return FALSE;
02065     lpszPath = CharNextA(lpszPath);
02066   }
02067   return TRUE;
02068 }
02069 
02070 /*************************************************************************
02071  * PathIsFileSpecW   [SHLWAPI.@]
02072  *
02073  * See PathIsFileSpecA.
02074  */
02075 BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath)
02076 {
02077   TRACE("(%s)\n", debugstr_w(lpszPath));
02078 
02079   if (!lpszPath)
02080     return FALSE;
02081 
02082   while (*lpszPath)
02083   {
02084     if (*lpszPath == '\\' || *lpszPath == ':')
02085       return FALSE;
02086     lpszPath++;
02087   }
02088   return TRUE;
02089 }
02090 
02091 /*************************************************************************
02092  * PathIsPrefixA   [SHLWAPI.@]
02093  *
02094  * Determine if a path is a prefix of another.
02095  *
02096  * PARAMS
02097  *  lpszPrefix [I] Prefix
02098  *  lpszPath   [I] Path to check
02099  *
02100  * RETURNS
02101  *  TRUE  If lpszPath has lpszPrefix as its prefix,
02102  *  FALSE If either path is NULL or lpszPrefix is not a prefix
02103  */
02104 BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath)
02105 {
02106   TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath));
02107 
02108   if (lpszPrefix && lpszPath &&
02109       PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix))
02110     return TRUE;
02111   return FALSE;
02112 }
02113 
02114 /*************************************************************************
02115  *  PathIsPrefixW   [SHLWAPI.@]
02116  *
02117  *  See PathIsPrefixA.
02118  */
02119 BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath)
02120 {
02121   TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath));
02122 
02123   if (lpszPrefix && lpszPath &&
02124       PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix))
02125     return TRUE;
02126   return FALSE;
02127 }
02128 
02129 /*************************************************************************
02130  * PathIsSystemFolderA   [SHLWAPI.@]
02131  *
02132  * Determine if a path or file attributes are a system folder.
02133  *
02134  * PARAMS
02135  *  lpszPath  [I] Path to check.
02136  *  dwAttrib  [I] Attributes to check, if lpszPath is NULL.
02137  *
02138  * RETURNS
02139  *  TRUE   If lpszPath or dwAttrib are a system folder.
02140  *  FALSE  If GetFileAttributesA() fails or neither parameter is a system folder.
02141  */
02142 BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib)
02143 {
02144   TRACE("(%s,0x%08x)\n", debugstr_a(lpszPath), dwAttrib);
02145 
02146   if (lpszPath && *lpszPath)
02147     dwAttrib = GetFileAttributesA(lpszPath);
02148 
02149   if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
02150       !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
02151     return FALSE;
02152   return TRUE;
02153 }
02154 
02155 /*************************************************************************
02156  * PathIsSystemFolderW   [SHLWAPI.@]
02157  *
02158  * See PathIsSystemFolderA.
02159  */
02160 BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib)
02161 {
02162   TRACE("(%s,0x%08x)\n", debugstr_w(lpszPath), dwAttrib);
02163 
02164   if (lpszPath && *lpszPath)
02165     dwAttrib = GetFileAttributesW(lpszPath);
02166 
02167   if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
02168       !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
02169     return FALSE;
02170   return TRUE;
02171 }
02172 
02173 /*************************************************************************
02174  * PathIsUNCA       [SHLWAPI.@]
02175  *
02176  * Determine if a path is in UNC format.
02177  *
02178  * PARAMS
02179  *  lpszPath [I] Path to check
02180  *
02181  * RETURNS
02182  *  TRUE: The path is UNC.
02183  *  FALSE: The path is not UNC or is NULL.
02184  */
02185 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath)
02186 {
02187   TRACE("(%s)\n",debugstr_a(lpszPath));
02188 
02189   if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
02190     return TRUE;
02191   return FALSE;
02192 }
02193 
02194 /*************************************************************************
02195  * PathIsUNCW       [SHLWAPI.@]
02196  *
02197  * See PathIsUNCA.
02198  */
02199 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath)
02200 {
02201   TRACE("(%s)\n",debugstr_w(lpszPath));
02202 
02203   if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\') && (lpszPath[2]!='?'))
02204     return TRUE;
02205   return FALSE;
02206 }
02207 
02208 /*************************************************************************
02209  * PathIsUNCServerA   [SHLWAPI.@]
02210  *
02211  * Determine if a path is a UNC server name ("\\SHARENAME").
02212  *
02213  * PARAMS
02214  *  lpszPath  [I] Path to check.
02215  *
02216  * RETURNS
02217  *  TRUE   If lpszPath is a valid UNC server name.
02218  *  FALSE  Otherwise.
02219  *
02220  * NOTES
02221  *  This routine is bug compatible with Win32: Server names with a
02222  *  trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly.
02223  *  Fixing this bug may break other shlwapi functions!
02224  */
02225 BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath)
02226 {
02227   TRACE("(%s)\n", debugstr_a(lpszPath));
02228 
02229   if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
02230   {
02231     while (*lpszPath)
02232     {
02233       if (*lpszPath == '\\')
02234         return FALSE;
02235       lpszPath = CharNextA(lpszPath);
02236     }
02237     return TRUE;
02238   }
02239   return FALSE;
02240 }
02241 
02242 /*************************************************************************
02243  * PathIsUNCServerW   [SHLWAPI.@]
02244  *
02245  * See PathIsUNCServerA.
02246  */
02247 BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath)
02248 {
02249   TRACE("(%s)\n", debugstr_w(lpszPath));
02250 
02251   if (lpszPath && lpszPath[0] == '\\' && lpszPath[1] == '\\')
02252   {
02253       return !strchrW( lpszPath + 2, '\\' );
02254   }
02255   return FALSE;
02256 }
02257 
02258 /*************************************************************************
02259  * PathIsUNCServerShareA   [SHLWAPI.@]
02260  *
02261  * Determine if a path is a UNC server share ("\\SHARENAME\SHARE").
02262  *
02263  * PARAMS
02264  *  lpszPath  [I] Path to check.
02265  *
02266  * RETURNS
02267  *  TRUE   If lpszPath is a valid UNC server share.
02268  *  FALSE  Otherwise.
02269  *
02270  * NOTES
02271  *  This routine is bug compatible with Win32: Server shares with a
02272  *  trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly.
02273  *  Fixing this bug may break other shlwapi functions!
02274  */
02275 BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath)
02276 {
02277   TRACE("(%s)\n", debugstr_a(lpszPath));
02278 
02279   if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
02280   {
02281     BOOL bSeenSlash = FALSE;
02282     while (*lpszPath)
02283     {
02284       if (*lpszPath == '\\')
02285       {
02286         if (bSeenSlash)
02287           return FALSE;
02288         bSeenSlash = TRUE;
02289       }
02290       lpszPath = CharNextA(lpszPath);
02291     }
02292     return bSeenSlash;
02293   }
02294   return FALSE;
02295 }
02296 
02297 /*************************************************************************
02298  * PathIsUNCServerShareW   [SHLWAPI.@]
02299  *
02300  * See PathIsUNCServerShareA.
02301  */
02302 BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath)
02303 {
02304   TRACE("(%s)\n", debugstr_w(lpszPath));
02305 
02306   if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
02307   {
02308     BOOL bSeenSlash = FALSE;
02309     while (*lpszPath)
02310     {
02311       if (*lpszPath == '\\')
02312       {
02313         if (bSeenSlash)
02314           return FALSE;
02315         bSeenSlash = TRUE;
02316       }
02317       lpszPath++;
02318     }
02319     return bSeenSlash;
02320   }
02321   return FALSE;
02322 }
02323 
02324 /*************************************************************************
02325  * PathCanonicalizeA   [SHLWAPI.@]
02326  *
02327  * Convert a path to its canonical form.
02328  *
02329  * PARAMS
02330  *  lpszBuf  [O] Output path
02331  *  lpszPath [I] Path to canonicalize
02332  *
02333  * RETURNS
02334  *  Success: TRUE.  lpszBuf contains the output path,
02335  *  Failure: FALSE, If input path is invalid. lpszBuf is undefined
02336  */
02337 BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath)
02338 {
02339   BOOL bRet = FALSE;
02340 
02341   TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath));
02342 
02343   if (lpszBuf)
02344     *lpszBuf = '\0';
02345 
02346   if (!lpszBuf || !lpszPath)
02347     SetLastError(ERROR_INVALID_PARAMETER);
02348   else
02349   {
02350     WCHAR szPath[MAX_PATH];
02351     WCHAR szBuff[MAX_PATH];
02352     int ret = MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
02353 
02354     if (!ret) {
02355     WARN("Failed to convert string to widechar (too long?), LE %d.\n", GetLastError());
02356     return FALSE;
02357     }
02358     bRet = PathCanonicalizeW(szBuff, szPath);
02359     WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
02360   }
02361   return bRet;
02362 }
02363 
02364 
02365 /*************************************************************************
02366  * PathCanonicalizeW   [SHLWAPI.@]
02367  *
02368  * See PathCanonicalizeA.
02369  */
02370 BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath)
02371 {
02372   LPWSTR lpszDst = lpszBuf;
02373   LPCWSTR lpszSrc = lpszPath;
02374 
02375   TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath));
02376 
02377   if (lpszBuf)
02378     *lpszDst = '\0';
02379 
02380   if (!lpszBuf || !lpszPath)
02381   {
02382     SetLastError(ERROR_INVALID_PARAMETER);
02383     return FALSE;
02384   }
02385 
02386   if (!*lpszPath)
02387   {
02388     *lpszBuf++ = '\\';
02389     *lpszBuf = '\0';
02390     return TRUE;
02391   }
02392 
02393   /* Copy path root */
02394   if (*lpszSrc == '\\')
02395   {
02396     *lpszDst++ = *lpszSrc++;
02397   }
02398   else if (*lpszSrc && lpszSrc[1] == ':')
02399   {
02400     /* X:\ */
02401     *lpszDst++ = *lpszSrc++;
02402     *lpszDst++ = *lpszSrc++;
02403     if (*lpszSrc == '\\')
02404       *lpszDst++ = *lpszSrc++;
02405   }
02406 
02407   /* Canonicalize the rest of the path */
02408   while (*lpszSrc)
02409   {
02410     if (*lpszSrc == '.')
02411     {
02412       if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':'))
02413       {
02414         lpszSrc += 2; /* Skip .\ */
02415       }
02416       else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\'))
02417       {
02418         /* \.. backs up a directory, over the root if it has no \ following X:.
02419          * .. is ignored if it would remove a UNC server name or inital \\
02420          */
02421         if (lpszDst != lpszBuf)
02422         {
02423           *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
02424           if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' &&
02425              (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2))
02426           {
02427             if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':'))
02428             {
02429               lpszDst -= 2;
02430               while (lpszDst > lpszBuf && *lpszDst != '\\')
02431                 lpszDst--;
02432               if (*lpszDst == '\\')
02433                 lpszDst++; /* Reset to last '\' */
02434               else
02435                 lpszDst = lpszBuf; /* Start path again from new root */
02436             }
02437             else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf))
02438               lpszDst -= 2;
02439           }
02440           while (lpszDst > lpszBuf && *lpszDst != '\\')
02441             lpszDst--;
02442           if (lpszDst == lpszBuf)
02443           {
02444             *lpszDst++ = '\\';
02445             lpszSrc++;
02446           }
02447         }
02448         lpszSrc += 2; /* Skip .. in src path */
02449       }
02450       else
02451         *lpszDst++ = *lpszSrc++;
02452     }
02453     else
02454       *lpszDst++ = *lpszSrc++;
02455   }
02456   /* Append \ to naked drive specs */
02457   if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':')
02458     *lpszDst++ = '\\';
02459   *lpszDst++ = '\0';
02460   return TRUE;
02461 }
02462 
02463 /*************************************************************************
02464  * PathFindNextComponentA   [SHLWAPI.@]
02465  *
02466  * Find the next component in a path.
02467  *
02468  * PARAMS
02469  *   lpszPath [I] Path to find next component in
02470  *
02471  * RETURNS
02472  *  Success: A pointer to the next component, or the end of the string.
02473  *  Failure: NULL, If lpszPath is invalid
02474  *
02475  * NOTES
02476  *  A 'component' is either a backslash character (\) or UNC marker (\\).
02477  *  Because of this, relative paths (e.g "c:foo") are regarded as having
02478  *  only one component.
02479  */
02480 LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath)
02481 {
02482   LPSTR lpszSlash;
02483 
02484   TRACE("(%s)\n", debugstr_a(lpszPath));
02485 
02486   if(!lpszPath || !*lpszPath)
02487     return NULL;
02488 
02489   if ((lpszSlash = StrChrA(lpszPath, '\\')))
02490   {
02491     if (lpszSlash[1] == '\\')
02492       lpszSlash++;
02493     return lpszSlash + 1;
02494   }
02495   return (LPSTR)lpszPath + strlen(lpszPath);
02496 }
02497 
02498 /*************************************************************************
02499  * PathFindNextComponentW   [SHLWAPI.@]
02500  *
02501  * See PathFindNextComponentA.
02502  */
02503 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath)
02504 {
02505   LPWSTR lpszSlash;
02506 
02507   TRACE("(%s)\n", debugstr_w(lpszPath));
02508 
02509   if(!lpszPath || !*lpszPath)
02510     return NULL;
02511 
02512   if ((lpszSlash = StrChrW(lpszPath, '\\')))
02513   {
02514     if (lpszSlash[1] == '\\')
02515       lpszSlash++;
02516     return lpszSlash + 1;
02517   }
02518   return (LPWSTR)lpszPath + strlenW(lpszPath);
02519 }
02520 
02521 /*************************************************************************
02522  * PathAddExtensionA   [SHLWAPI.@]
02523  *
02524  * Add a file extension to a path
02525  *
02526  * PARAMS
02527  *  lpszPath      [I/O] Path to add extension to
02528  *  lpszExtension [I]   Extension to add to lpszPath
02529  *
02530  * RETURNS
02531  *  TRUE  If the path was modified,
02532  *  FALSE If lpszPath or lpszExtension are invalid, lpszPath has an
02533  *        extension already, or the new path length is too big.
02534  *
02535  * FIXME
02536  *  What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k
02537  *  does not do this, so the behaviour was removed.
02538  */
02539 BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension)
02540 {
02541   size_t dwLen;
02542 
02543   TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension));
02544 
02545   if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath)))
02546     return FALSE;
02547 
02548   dwLen = strlen(lpszPath);
02549 
02550   if (dwLen + strlen(lpszExtension) >= MAX_PATH)
02551     return FALSE;
02552 
02553   strcpy(lpszPath + dwLen, lpszExtension);
02554   return TRUE;
02555 }
02556 
02557 /*************************************************************************
02558  * PathAddExtensionW   [SHLWAPI.@]
02559  *
02560  * See PathAddExtensionA.
02561  */
02562 BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension)
02563 {
02564   size_t dwLen;
02565 
02566   TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension));
02567 
02568   if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath)))
02569     return FALSE;
02570 
02571   dwLen = strlenW(lpszPath);
02572 
02573   if (dwLen + strlenW(lpszExtension) >= MAX_PATH)
02574     return FALSE;
02575 
02576   strcpyW(lpszPath + dwLen, lpszExtension);
02577   return TRUE;
02578 }
02579 
02580 /*************************************************************************
02581  * PathMakePrettyA   [SHLWAPI.@]
02582  *
02583  * Convert an uppercase DOS filename into lowercase.
02584  *
02585  * PARAMS
02586  *  lpszPath [I/O] Path to convert.
02587  *
02588  * RETURNS
02589  *  TRUE  If the path was an uppercase DOS path and was converted,
02590  *  FALSE Otherwise.
02591  */
02592 BOOL WINAPI PathMakePrettyA(LPSTR lpszPath)
02593 {
02594   LPSTR pszIter = lpszPath;
02595 
02596   TRACE("(%s)\n", debugstr_a(lpszPath));
02597 
02598   if (!pszIter)
02599     return FALSE;
02600 
02601   if (*pszIter)
02602   {
02603     do
02604     {
02605       if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
02606         return FALSE; /* Not DOS path */
02607       pszIter++;
02608     } while (*pszIter);
02609     pszIter = lpszPath + 1;
02610     while (*pszIter)
02611     {
02612       *pszIter = tolower(*pszIter);
02613       pszIter++;
02614     }
02615   }
02616   return TRUE;
02617 }
02618 
02619 /*************************************************************************
02620  * PathMakePrettyW   [SHLWAPI.@]
02621  *
02622  * See PathMakePrettyA.
02623  */
02624 BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath)
02625 {
02626   LPWSTR pszIter = lpszPath;
02627 
02628   TRACE("(%s)\n", debugstr_w(lpszPath));
02629 
02630   if (!pszIter)
02631     return FALSE;
02632 
02633   if (*pszIter)
02634   {
02635     do
02636     {
02637       if (islowerW(*pszIter))
02638         return FALSE; /* Not DOS path */
02639       pszIter++;
02640     } while (*pszIter);
02641     pszIter = lpszPath + 1;
02642     while (*pszIter)
02643     {
02644       *pszIter = tolowerW(*pszIter);
02645       pszIter++;
02646     }
02647   }
02648   return TRUE;
02649 }
02650 
02651 /*************************************************************************
02652  * PathCommonPrefixA   [SHLWAPI.@]
02653  *
02654  * Determine the length of the common prefix between two paths.
02655  *
02656  * PARAMS
02657  *  lpszFile1 [I] First path for comparison
02658  *  lpszFile2 [I] Second path for comparison
02659  *  achPath   [O] Destination for common prefix string
02660  *
02661  * RETURNS
02662  *  The length of the common prefix. This is 0 if there is no common
02663  *  prefix between the paths or if any parameters are invalid. If the prefix
02664  *  is non-zero and achPath is not NULL, achPath is filled with the common
02665  *  part of the prefix and NUL terminated.
02666  *
02667  * NOTES
02668  *  A common prefix of 2 is always returned as 3. It is thus possible for
02669  *  the length returned to be invalid (i.e. Longer than one or both of the
02670  *  strings given as parameters). This Win32 behaviour has been implemented
02671  *  here, and cannot be changed (fixed?) without breaking other SHLWAPI calls.
02672  *  To work around this when using this function, always check that the byte
02673  *  at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix.
02674  */
02675 int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath)
02676 {
02677   size_t iLen = 0;
02678   LPCSTR lpszIter1 = lpszFile1;
02679   LPCSTR lpszIter2 = lpszFile2;
02680 
02681   TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath);
02682 
02683   if (achPath)
02684     *achPath = '\0';
02685 
02686   if (!lpszFile1 || !lpszFile2)
02687     return 0;
02688 
02689   /* Handle roots first */
02690   if (PathIsUNCA(lpszFile1))
02691   {
02692     if (!PathIsUNCA(lpszFile2))
02693       return 0;
02694     lpszIter1 += 2;
02695     lpszIter2 += 2;
02696   }
02697   else if (PathIsUNCA(lpszFile2))
02698       return 0; /* Know already lpszFile1 is not UNC */
02699 
02700   do
02701   {
02702     /* Update len */
02703     if ((!*lpszIter1 || *lpszIter1 == '\\') &&
02704         (!*lpszIter2 || *lpszIter2 == '\\'))
02705       iLen = lpszIter1 - lpszFile1; /* Common to this point */
02706 
02707     if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2)))
02708       break; /* Strings differ at this point */
02709 
02710     lpszIter1++;
02711     lpszIter2++;
02712   } while (1);
02713 
02714   if (iLen == 2)
02715     iLen++; /* Feature/Bug compatible with Win32 */
02716 
02717   if (iLen && achPath)
02718   {
02719     memcpy(achPath,lpszFile1,iLen);
02720     achPath[iLen] = '\0';
02721   }
02722   return iLen;
02723 }
02724 
02725 /*************************************************************************
02726  * PathCommonPrefixW   [SHLWAPI.@]
02727  *
02728  * See PathCommonPrefixA.
02729  */
02730 int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath)
02731 {
02732   size_t iLen = 0;
02733   LPCWSTR lpszIter1 = lpszFile1;
02734   LPCWSTR lpszIter2 = lpszFile2;
02735 
02736   TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath);
02737 
02738   if (achPath)
02739     *achPath = '\0';
02740 
02741   if (!lpszFile1 || !lpszFile2)
02742     return 0;
02743 
02744   /* Handle roots first */
02745   if (PathIsUNCW(lpszFile1))
02746   {
02747     if (!PathIsUNCW(lpszFile2))
02748       return 0;
02749     lpszIter1 += 2;
02750     lpszIter2 += 2;
02751   }
02752   else if (PathIsUNCW(lpszFile2))
02753       return 0; /* Know already lpszFile1 is not UNC */
02754 
02755   do
02756   {
02757     /* Update len */
02758     if ((!*lpszIter1 || *lpszIter1 == '\\') &&
02759         (!*lpszIter2 || *lpszIter2 == '\\'))
02760       iLen = lpszIter1 - lpszFile1; /* Common to this point */
02761 
02762     if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2)))
02763       break; /* Strings differ at this point */
02764 
02765     lpszIter1++;
02766     lpszIter2++;
02767   } while (1);
02768 
02769   if (iLen == 2)
02770     iLen++; /* Feature/Bug compatible with Win32 */
02771 
02772   if (iLen && achPath)
02773   {
02774     memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR));
02775     achPath[iLen] = '\0';
02776   }
02777   return iLen;
02778 }
02779 
02780 /*************************************************************************
02781  * PathCompactPathA   [SHLWAPI.@]
02782  *
02783  * Make a path fit into a given width when printed to a DC.
02784  *
02785  * PARAMS
02786  *  hDc      [I]   Destination DC
02787  *  lpszPath [I/O] Path to be printed to hDc
02788  *  dx       [I]   Desired width
02789  *
02790  * RETURNS
02791  *  TRUE  If the path was modified/went well.
02792  *  FALSE Otherwise.
02793  */
02794 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
02795 {
02796   BOOL bRet = FALSE;
02797 
02798   TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx);
02799 
02800   if (lpszPath)
02801   {
02802     WCHAR szPath[MAX_PATH];
02803     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
02804     bRet = PathCompactPathW(hDC, szPath, dx);
02805     WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
02806   }
02807   return bRet;
02808 }
02809 
02810 /*************************************************************************
02811  * PathCompactPathW   [SHLWAPI.@]
02812  *
02813  * See PathCompactPathA.
02814  */
02815 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
02816 {
02817   static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
02818   BOOL bRet = TRUE;
02819   HDC hdc = 0;
02820   WCHAR buff[MAX_PATH];
02821   SIZE size;
02822   DWORD dwLen;
02823 
02824   TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx);
02825 
02826   if (!lpszPath)
02827     return FALSE;
02828 
02829   if (!hDC)
02830     hdc = hDC = GetDC(0);
02831 
02832   /* Get the length of the whole path */
02833   dwLen = strlenW(lpszPath);
02834   GetTextExtentPointW(hDC, lpszPath, dwLen, &size);
02835 
02836   if ((UINT)size.cx > dx)
02837   {
02838     /* Path too big, must reduce it */
02839     LPWSTR sFile;
02840     DWORD dwEllipsesLen = 0, dwPathLen = 0;
02841 
02842     sFile = PathFindFileNameW(lpszPath);
02843     if (sFile != lpszPath) sFile--;
02844 
02845     /* Get the size of ellipses */
02846     GetTextExtentPointW(hDC, szEllipses, 3, &size);
02847     dwEllipsesLen = size.cx;
02848     /* Get the size of the file name */
02849     GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size);
02850     dwPathLen = size.cx;
02851 
02852     if (sFile != lpszPath)
02853     {
02854       LPWSTR sPath = sFile;
02855       BOOL bEllipses = FALSE;
02856 
02857       /* The path includes a file name. Include as much of the path prior to
02858        * the file name as possible, allowing for the ellipses, e.g:
02859        * c:\some very long path\filename ==> c:\some v...\filename
02860        */
02861       lstrcpynW(buff, sFile, MAX_PATH);
02862 
02863       do
02864       {
02865         DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen;
02866 
02867         GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size);
02868         dwTotalLen += size.cx;
02869         if (dwTotalLen <= dx)
02870           break;
02871         sPath--;
02872         if (!bEllipses)
02873         {
02874           bEllipses = TRUE;
02875           sPath -= 2;
02876         }
02877       } while (sPath > lpszPath);
02878 
02879       if (sPath > lpszPath)
02880       {
02881         if (bEllipses)
02882         {
02883           strcpyW(sPath, szEllipses);
02884           strcpyW(sPath+3, buff);
02885         }
02886         bRet = TRUE;
02887         goto end;
02888       }
02889       strcpyW(lpszPath, szEllipses);
02890       strcpyW(lpszPath+3, buff);
02891       bRet = FALSE;
02892       goto end;
02893     }
02894 
02895     /* Trim the path by adding ellipses to the end, e.g:
02896      * A very long file name.txt ==> A very...
02897      */
02898     dwLen = strlenW(lpszPath);
02899 
02900     if (dwLen > MAX_PATH - 3)
02901       dwLen =  MAX_PATH - 3;
02902     lstrcpynW(buff, sFile, dwLen);
02903 
02904     do {
02905       dwLen--;
02906       GetTextExtentPointW(hDC, buff, dwLen, &size);
02907     } while (dwLen && size.cx + dwEllipsesLen > dx);
02908 
02909    if (!dwLen)
02910    {
02911      DWORD dwWritten = 0;
02912 
02913      dwEllipsesLen /= 3; /* Size of a single '.' */
02914 
02915      /* Write as much of the Ellipses string as possible */
02916      while (dwWritten + dwEllipsesLen < dx && dwLen < 3)
02917      {
02918        *lpszPath++ = '.';
02919        dwWritten += dwEllipsesLen;
02920        dwLen++;
02921      }
02922      *lpszPath = '\0';
02923      bRet = FALSE;
02924    }
02925    else
02926    {
02927      strcpyW(buff + dwLen, szEllipses);
02928      strcpyW(lpszPath, buff);
02929     }
02930   }
02931 
02932 end:
02933   if (hdc)
02934     ReleaseDC(0, hdc);
02935 
02936   return bRet;
02937 }
02938 
02939 /*************************************************************************
02940  * PathGetCharTypeA   [SHLWAPI.@]
02941  *
02942  * Categorise a character from a file path.
02943  *
02944  * PARAMS
02945  *  ch [I] Character to get the type of
02946  *
02947  * RETURNS
02948  *  A set of GCT_ bit flags (from "shlwapi.h") indicating the character type.
02949  */
02950 UINT WINAPI PathGetCharTypeA(UCHAR ch)
02951 {
02952   return PathGetCharTypeW(ch);
02953 }
02954 
02955 /*************************************************************************
02956  * PathGetCharTypeW   [SHLWAPI.@]
02957  *
02958  * See PathGetCharTypeA.
02959  */
02960 UINT WINAPI PathGetCharTypeW(WCHAR ch)
02961 {
02962   UINT flags = 0;
02963 
02964   TRACE("(%d)\n", ch);
02965 
02966   if (!ch || ch < ' ' || ch == '<' || ch == '>' ||
02967       ch == '"' || ch == '|' || ch == '/')
02968     flags = GCT_INVALID; /* Invalid */
02969   else if (ch == '*' || ch=='?')
02970     flags = GCT_WILD; /* Wildchars */
02971   else if ((ch == '\\') || (ch == ':'))
02972     return GCT_SEPARATOR; /* Path separators */
02973   else
02974   {
02975      if (ch < 126)
02976      {
02977        if ((ch & 0x1 && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' ||
02978             ch == '.' || ch == '@' || ch == '^' ||
02979             ch == '\'' || ch == 130 || ch == '`')
02980          flags |= GCT_SHORTCHAR; /* All these are valid for DOS */
02981      }
02982      else
02983        flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */
02984      flags |= GCT_LFNCHAR; /* Valid for long file names */
02985   }
02986   return flags;
02987 }
02988 
02989 /*************************************************************************
02990  * SHLWAPI_UseSystemForSystemFolders
02991  *
02992  * Internal helper for PathMakeSystemFolderW.
02993  */
02994 static BOOL SHLWAPI_UseSystemForSystemFolders(void)
02995 {
02996   static BOOL bCheckedReg = FALSE;
02997   static BOOL bUseSystemForSystemFolders = FALSE;
02998 
02999   if (!bCheckedReg)
03000   {
03001     bCheckedReg = TRUE;
03002 
03003     /* Key tells Win what file attributes to use on system folders */
03004     if (SHGetValueA(HKEY_LOCAL_MACHINE,
03005         "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
03006         "UseSystemForSystemFolders", 0, 0, 0))
03007       bUseSystemForSystemFolders = TRUE;
03008   }
03009   return bUseSystemForSystemFolders;
03010 }
03011 
03012 /*************************************************************************
03013  * PathMakeSystemFolderA   [SHLWAPI.@]
03014  *
03015  * Set system folder attribute for a path.
03016  *
03017  * PARAMS
03018  *  lpszPath [I] The path to turn into a system folder
03019  *
03020  * RETURNS
03021  *  TRUE  If the path was changed to/already was a system folder
03022  *  FALSE If the path is invalid or SetFileAttributesA() fails
03023  */
03024 BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath)
03025 {
03026   BOOL bRet = FALSE;
03027 
03028   TRACE("(%s)\n", debugstr_a(lpszPath));
03029 
03030   if (lpszPath && *lpszPath)
03031   {
03032     WCHAR szPath[MAX_PATH];
03033     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
03034     bRet = PathMakeSystemFolderW(szPath);
03035   }
03036   return bRet;
03037 }
03038 
03039 /*************************************************************************
03040  * PathMakeSystemFolderW   [SHLWAPI.@]
03041  *
03042  * See PathMakeSystemFolderA.
03043  */
03044 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath)
03045 {
03046   DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr;
03047   WCHAR buff[MAX_PATH];
03048 
03049   TRACE("(%s)\n", debugstr_w(lpszPath));
03050 
03051   if (!lpszPath || !*lpszPath)
03052     return FALSE;
03053 
03054   /* If the directory is already a system directory, don't do anything */
03055   GetSystemDirectoryW(buff, MAX_PATH);
03056   if (!strcmpW(buff, lpszPath))
03057     return TRUE;
03058 
03059   GetWindowsDirectoryW(buff, MAX_PATH);
03060   if (!strcmpW(buff, lpszPath))
03061     return TRUE;
03062 
03063   /* "UseSystemForSystemFolders" Tells Win what attributes to use */
03064   if (SHLWAPI_UseSystemForSystemFolders())
03065     dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM;
03066 
03067   if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES)
03068     return FALSE;
03069 
03070   /* Change file attributes to system attributes */
03071   dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY);
03072   return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr);
03073 }
03074 
03075 /*************************************************************************
03076  * PathRenameExtensionA   [SHLWAPI.@]
03077  *
03078  * Swap the file extension in a path with another extension.
03079  *
03080  * PARAMS
03081  *  lpszPath [I/O] Path to swap the extension in
03082  *  lpszExt  [I]   The new extension
03083  *
03084  * RETURNS
03085  *  TRUE  if lpszPath was modified,
03086  *  FALSE if lpszPath or lpszExt is NULL, or the new path is too long
03087  */
03088 BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt)
03089 {
03090   LPSTR lpszExtension;
03091 
03092   TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt));
03093 
03094   lpszExtension = PathFindExtensionA(lpszPath);
03095 
03096   if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH))
03097     return FALSE;
03098 
03099   strcpy(lpszExtension, lpszExt);
03100   return TRUE;
03101 }
03102 
03103 /*************************************************************************
03104  * PathRenameExtensionW   [SHLWAPI.@]
03105  *
03106  * See PathRenameExtensionA.
03107  */
03108 BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt)
03109 {
03110   LPWSTR lpszExtension;
03111 
03112   TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt));
03113 
03114   lpszExtension = PathFindExtensionW(lpszPath);
03115 
03116   if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH))
03117     return FALSE;
03118 
03119   strcpyW(lpszExtension, lpszExt);
03120   return TRUE;
03121 }
03122 
03123 /*************************************************************************
03124  * PathSearchAndQualifyA   [SHLWAPI.@]
03125  *
03126  * Determine if a given path is correct and fully qualified.
03127  *
03128  * PARAMS
03129  *  lpszPath [I] Path to check
03130  *  lpszBuf  [O] Output for correct path
03131  *  cchBuf   [I] Size of lpszBuf
03132  *
03133  * RETURNS
03134  *  Unknown.
03135  */
03136 BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf)
03137 {
03138     TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
03139 
03140     if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
03141         return TRUE;
03142     return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL);
03143 }
03144 
03145 /*************************************************************************
03146  * PathSearchAndQualifyW   [SHLWAPI.@]
03147  *
03148  * See PathSearchAndQualifyA.
03149  */
03150 BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf)
03151 {
03152     TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
03153 
03154     if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL))
03155         return TRUE;
03156     return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL);
03157 }
03158 
03159 /*************************************************************************
03160  * PathSkipRootA   [SHLWAPI.@]
03161  *
03162  * Return the portion of a path following the drive letter or mount point.
03163  *
03164  * PARAMS
03165  *  lpszPath [I] The path to skip on
03166  *
03167  * RETURNS
03168  *  Success: A pointer to the next character after the root.
03169  *  Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string.
03170  */
03171 LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath)
03172 {
03173   TRACE("(%s)\n", debugstr_a(lpszPath));
03174 
03175   if (!lpszPath || !*lpszPath)
03176     return NULL;
03177 
03178   if (*lpszPath == '\\' && lpszPath[1] == '\\')
03179   {
03180     /* Network share: skip share server and mount point */
03181     lpszPath += 2;
03182     if ((lpszPath = StrChrA(lpszPath, '\\')) &&
03183         (lpszPath = StrChrA(lpszPath + 1, '\\')))
03184       lpszPath++;
03185     return (LPSTR)lpszPath;
03186   }
03187 
03188   if (IsDBCSLeadByte(*lpszPath))
03189     return NULL;
03190 
03191   /* Check x:\ */
03192   if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
03193     return (LPSTR)lpszPath + 3;
03194   return NULL;
03195 }
03196 
03197 /*************************************************************************
03198  * PathSkipRootW   [SHLWAPI.@]
03199  *
03200  * See PathSkipRootA.
03201  */
03202 LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath)
03203 {
03204   TRACE("(%s)\n", debugstr_w(lpszPath));
03205 
03206   if (!lpszPath || !*lpszPath)
03207     return NULL;
03208 
03209   if (*lpszPath == '\\' && lpszPath[1] == '\\')
03210   {
03211     /* Network share: skip share server and mount point */
03212     lpszPath += 2;
03213     if ((lpszPath = StrChrW(lpszPath, '\\')) &&
03214         (lpszPath = StrChrW(lpszPath + 1, '\\')))
03215      lpszPath++;
03216     return (LPWSTR)lpszPath;
03217   }
03218 
03219   /* Check x:\ */
03220   if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
03221     return (LPWSTR)lpszPath + 3;
03222   return NULL;
03223 }
03224 
03225 /*************************************************************************
03226  * PathCreateFromUrlA   [SHLWAPI.@]
03227  *
03228  * See PathCreateFromUrlW
03229  */
03230 HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath,
03231                                   LPDWORD pcchPath, DWORD dwReserved)
03232 {
03233     WCHAR bufW[MAX_PATH];
03234     WCHAR *pathW = bufW;
03235     UNICODE_STRING urlW;
03236     HRESULT ret;
03237     DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA;
03238 
03239     if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl))
03240         return E_INVALIDARG;
03241     if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) {
03242         pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR));
03243         ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved);
03244     }
03245     if(ret == S_OK) {
03246         RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR));
03247         if(*pcchPath > lenA) {
03248             RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR));
03249             pszPath[lenA] = 0;
03250             *pcchPath = lenA;
03251         } else {
03252             *pcchPath = lenA + 1;
03253             ret = E_POINTER;
03254         }
03255     }
03256     if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW);
03257     RtlFreeUnicodeString(&urlW);
03258     return ret;
03259 }
03260 
03261 /*************************************************************************
03262  * PathCreateFromUrlW   [SHLWAPI.@]
03263  *
03264  * Create a path from a URL
03265  *
03266  * PARAMS
03267  *  lpszUrl  [I] URL to convert into a path
03268  *  lpszPath [O] Output buffer for the resulting Path
03269  *  pcchPath [I] Length of lpszPath
03270  *  dwFlags  [I] Flags controlling the conversion
03271  *
03272  * RETURNS
03273  *  Success: S_OK. lpszPath contains the URL in path format,
03274  *  Failure: An HRESULT error code such as E_INVALIDARG.
03275  */
03276 HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath,
03277                                   LPDWORD pcchPath, DWORD dwReserved)
03278 {
03279     static const WCHAR file_colon[] = { 'f','i','l','e',':',0 };
03280     HRESULT hr;
03281     DWORD nslashes = 0;
03282     WCHAR *ptr;
03283 
03284     TRACE("(%s,%p,%p,0x%08x)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved);
03285 
03286     if (!pszUrl || !pszPath || !pcchPath || !*pcchPath)
03287         return E_INVALIDARG;
03288 
03289 
03290     if (strncmpW(pszUrl, file_colon, 5))
03291         return E_INVALIDARG;
03292     pszUrl += 5;
03293 
03294     while(*pszUrl == '/' || *pszUrl == '\\') {
03295         nslashes++;
03296         pszUrl++;
03297     }
03298 
03299     if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\'))
03300         nslashes = 0;
03301 
03302     switch(nslashes) {
03303     case 2:
03304         pszUrl -= 2;
03305         break;
03306     case 0:
03307         break;
03308     default:
03309         pszUrl -= 1;
03310         break;
03311     }
03312 
03313     hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0);
03314     if(hr != S_OK) return hr;
03315 
03316     for(ptr = pszPath; *ptr; ptr++)
03317         if(*ptr == '/') *ptr = '\\';
03318 
03319     while(*pszPath == '\\')
03320         pszPath++;
03321  
03322     if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */
03323         pszPath[1] = ':';
03324 
03325     if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */
03326         ptr++;
03327         if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') {
03328             memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR));
03329             (*pcchPath)--;
03330         }
03331     }
03332 
03333     TRACE("Returning %s\n",debugstr_w(pszPath));
03334 
03335     return hr;
03336 }
03337 
03338 /*************************************************************************
03339  * PathRelativePathToA   [SHLWAPI.@]
03340  *
03341  * Create a relative path from one path to another.
03342  *
03343  * PARAMS
03344  *  lpszPath   [O] Destination for relative path
03345  *  lpszFrom   [I] Source path
03346  *  dwAttrFrom [I] File attribute of source path
03347  *  lpszTo     [I] Destination path
03348  *  dwAttrTo   [I] File attributes of destination path
03349  *
03350  * RETURNS
03351  *  TRUE  If a relative path can be formed. lpszPath contains the new path
03352  *  FALSE If the paths are not relative or any parameters are invalid
03353  *
03354  * NOTES
03355  *  lpszTo should be at least MAX_PATH in length.
03356  *
03357  *  Calling this function with relative paths for lpszFrom or lpszTo may
03358  *  give erroneous results.
03359  *
03360  *  The Win32 version of this function contains a bug where the lpszTo string
03361  *  may be referenced 1 byte beyond the end of the string. As a result random
03362  *  garbage may be written to the output path, depending on what lies beyond
03363  *  the last byte of the string. This bug occurs because of the behaviour of
03364  *  PathCommonPrefix() (see notes for that function), and no workaround seems
03365  *  possible with Win32.
03366  *
03367  *  This bug has been fixed here, so for example the relative path from "\\"
03368  *  to "\\" is correctly determined as "." in this implementation.
03369  */
03370 BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom,
03371                                 LPCSTR lpszTo, DWORD dwAttrTo)
03372 {
03373   BOOL bRet = FALSE;
03374 
03375   TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_a(lpszFrom),
03376         dwAttrFrom, debugstr_a(lpszTo), dwAttrTo);
03377 
03378   if(lpszPath && lpszFrom && lpszTo)
03379   {
03380     WCHAR szPath[MAX_PATH];
03381     WCHAR szFrom[MAX_PATH];
03382     WCHAR szTo[MAX_PATH];
03383     MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH);
03384     MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH);
03385     bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo);
03386     WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0);
03387   }
03388   return bRet;
03389 }
03390 
03391 /*************************************************************************
03392  * PathRelativePathToW   [SHLWAPI.@]
03393  *
03394  * See PathRelativePathToA.
03395  */
03396 BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom,
03397                                 LPCWSTR lpszTo, DWORD dwAttrTo)
03398 {
03399   static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' };
03400   static const WCHAR szPrevDir[] = { '.', '.', '\0' };
03401   WCHAR szFrom[MAX_PATH];
03402   WCHAR szTo[MAX_PATH];
03403   DWORD dwLen;
03404 
03405   TRACE("(%p,%s,0x%08x,%s,0x%08x)\n", lpszPath, debugstr_w(lpszFrom),
03406         dwAttrFrom, debugstr_w(lpszTo), dwAttrTo);
03407 
03408   if(!lpszPath || !lpszFrom || !lpszTo)
03409     return FALSE;
03410 
03411   *lpszPath = '\0';
03412   lstrcpynW(szFrom, lpszFrom, MAX_PATH);
03413   lstrcpynW(szTo, lpszTo, MAX_PATH);
03414 
03415   if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
03416     PathRemoveFileSpecW(szFrom);
03417   if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
03418     PathRemoveFileSpecW(szTo);
03419 
03420   /* Paths can only be relative if they have a common root */
03421   if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0)))
03422     return FALSE;
03423 
03424   /* Strip off lpszFrom components to the root, by adding "..\" */
03425   lpszFrom = szFrom + dwLen;
03426   if (!*lpszFrom)
03427   {
03428     lpszPath[0] = '.';
03429     lpszPath[1] = '\0';
03430   }
03431   if (*lpszFrom == '\\')
03432     lpszFrom++;
03433 
03434   while (*lpszFrom)
03435   {
03436     lpszFrom = PathFindNextComponentW(lpszFrom);
03437     strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir);
03438   }
03439 
03440   /* From the root add the components of lpszTo */
03441   lpszTo += dwLen;
03442   /* We check lpszTo[-1] to avoid skipping end of string. See the notes for
03443    * this function.
03444    */
03445   if (*lpszTo && lpszTo[-1])
03446   {
03447     if (*lpszTo != '\\')
03448       lpszTo--;
03449     dwLen = strlenW(lpszPath);
03450     if (dwLen + strlenW(lpszTo) >= MAX_PATH)
03451     {
03452       *lpszPath = '\0';
03453       return FALSE;
03454     }
03455     strcpyW(lpszPath + dwLen, lpszTo);
03456   }
03457   return TRUE;
03458 }
03459 
03460 /*************************************************************************
03461  * PathUnmakeSystemFolderA   [SHLWAPI.@]
03462  *
03463  * Remove the system folder attributes from a path.
03464  *
03465  * PARAMS
03466  *  lpszPath [I] The path to remove attributes from
03467  *
03468  * RETURNS
03469  *  Success: TRUE.
03470  *  Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling
03471  *           SetFileAttributesA() fails.
03472  */
03473 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath)
03474 {
03475   DWORD dwAttr;
03476 
03477   TRACE("(%s)\n", debugstr_a(lpszPath));
03478 
03479   if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
03480       !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
03481     return FALSE;
03482 
03483   dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
03484   return SetFileAttributesA(lpszPath, dwAttr);
03485 }
03486 
03487 /*************************************************************************
03488  * PathUnmakeSystemFolderW   [SHLWAPI.@]
03489  *
03490  * See PathUnmakeSystemFolderA.
03491  */
03492 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath)
03493 {
03494   DWORD dwAttr;
03495 
03496   TRACE("(%s)\n", debugstr_w(lpszPath));
03497 
03498   if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES ||
03499     !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
03500     return FALSE;
03501 
03502   dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
03503   return SetFileAttributesW(lpszPath, dwAttr);
03504 }
03505 
03506 
03507 /*************************************************************************
03508  * PathSetDlgItemPathA   [SHLWAPI.@]
03509  *
03510  * Set the text of a dialog item to a path, shrinking the path to fit
03511  * if it is too big for the item.
03512  *
03513  * PARAMS
03514  *  hDlg     [I] Dialog handle
03515  *  id       [I] ID of item in the dialog
03516  *  lpszPath [I] Path to set as the items text
03517  *
03518  * RETURNS
03519  *  Nothing.
03520  *
03521  * NOTES
03522  *  If lpszPath is NULL, a blank string ("") is set (i.e. The previous
03523  *  window text is erased).
03524  */
03525 VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath)
03526 {
03527   WCHAR szPath[MAX_PATH];
03528 
03529   TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath));
03530 
03531   if (lpszPath)
03532     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
03533   else
03534     szPath[0] = '\0';
03535   PathSetDlgItemPathW(hDlg, id, szPath);
03536 }
03537 
03538 /*************************************************************************
03539  * PathSetDlgItemPathW   [SHLWAPI.@]
03540  *
03541  * See PathSetDlgItemPathA.
03542  */
03543 VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath)
03544 {
03545   WCHAR path[MAX_PATH + 1];
03546   HWND hwItem;
03547   RECT rect;
03548   HDC hdc;
03549   HGDIOBJ hPrevObj;
03550 
03551   TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath));
03552 
03553   if (!(hwItem = GetDlgItem(hDlg, id)))
03554     return;
03555 
03556   if (lpszPath)
03557     lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR));
03558   else
03559     path[0] = '\0';
03560 
03561   GetClientRect(hwItem, &rect);
03562   hdc = GetDC(hDlg);
03563   hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0));
03564 
03565   if (hPrevObj)
03566   {
03567     PathCompactPathW(hdc, path, rect.right);
03568     SelectObject(hdc, hPrevObj);
03569   }
03570 
03571   ReleaseDC(hDlg, hdc);
03572   SetWindowTextW(hwItem, path);
03573 }
03574 
03575 /*************************************************************************
03576  * PathIsNetworkPathA [SHLWAPI.@]
03577  *
03578  * Determine if the given path is a network path.
03579  *
03580  * PARAMS
03581  *  lpszPath [I] Path to check
03582  *
03583  * RETURNS
03584  *  TRUE  If lpszPath is a UNC share or mapped network drive, or
03585  *  FALSE If lpszPath is a local drive or cannot be determined
03586  */
03587 BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath)
03588 {
03589   int dwDriveNum;
03590 
03591   TRACE("(%s)\n",debugstr_a(lpszPath));
03592 
03593   if (!lpszPath)
03594     return FALSE;
03595   if (*lpszPath == '\\' && lpszPath[1] == '\\')
03596     return TRUE;
03597   dwDriveNum = PathGetDriveNumberA(lpszPath);
03598   if (dwDriveNum == -1)
03599     return FALSE;
03600   GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
03601   return pIsNetDrive(dwDriveNum);
03602 }
03603 
03604 /*************************************************************************
03605  * PathIsNetworkPathW [SHLWAPI.@]
03606  *
03607  * See PathIsNetworkPathA.
03608  */
03609 BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath)
03610 {
03611   int dwDriveNum;
03612 
03613   TRACE("(%s)\n", debugstr_w(lpszPath));
03614 
03615   if (!lpszPath)
03616     return FALSE;
03617   if (*lpszPath == '\\' && lpszPath[1] == '\\')
03618     return TRUE;
03619   dwDriveNum = PathGetDriveNumberW(lpszPath);
03620   if (dwDriveNum == -1)
03621     return FALSE;
03622   GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
03623   return pIsNetDrive(dwDriveNum);
03624 }
03625 
03626 /*************************************************************************
03627  * PathIsLFNFileSpecA [SHLWAPI.@]
03628  *
03629  * Determine if the given path is a long file name
03630  *
03631  * PARAMS
03632  *  lpszPath [I] Path to check
03633  *
03634  * RETURNS
03635  *  TRUE  If path is a long file name,
03636  *  FALSE If path is a valid DOS short file name
03637  */
03638 BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath)
03639 {
03640   DWORD dwNameLen = 0, dwExtLen = 0;
03641 
03642   TRACE("(%s)\n",debugstr_a(lpszPath));
03643 
03644   if (!lpszPath)
03645     return FALSE;
03646 
03647   while (*lpszPath)
03648   {
03649     if (*lpszPath == ' ')
03650       return TRUE; /* DOS names cannot have spaces */
03651     if (*lpszPath == '.')
03652     {
03653       if (dwExtLen)
03654         return TRUE; /* DOS names have only one dot */
03655       dwExtLen = 1;
03656     }
03657     else if (dwExtLen)
03658     {
03659       dwExtLen++;
03660       if (dwExtLen > 4)
03661         return TRUE; /* DOS extensions are <= 3 chars*/
03662     }
03663     else
03664     {
03665       dwNameLen++;
03666       if (dwNameLen > 8)
03667         return TRUE; /* DOS names are <= 8 chars */
03668     }
03669     lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1;
03670   }
03671   return FALSE; /* Valid DOS path */
03672 }
03673 
03674 /*************************************************************************
03675  * PathIsLFNFileSpecW [SHLWAPI.@]
03676  *
03677  * See PathIsLFNFileSpecA.
03678  */
03679 BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath)
03680 {
03681   DWORD dwNameLen = 0, dwExtLen = 0;
03682 
03683   TRACE("(%s)\n",debugstr_w(lpszPath));
03684 
03685   if (!lpszPath)
03686     return FALSE;
03687 
03688   while (*lpszPath)
03689   {
03690     if (*lpszPath == ' ')
03691       return TRUE; /* DOS names cannot have spaces */
03692     if (*lpszPath == '.')
03693     {
03694       if (dwExtLen)
03695         return TRUE; /* DOS names have only one dot */
03696       dwExtLen = 1;
03697     }
03698     else if (dwExtLen)
03699     {
03700       dwExtLen++;
03701       if (dwExtLen > 4)
03702         return TRUE; /* DOS extensions are <= 3 chars*/
03703     }
03704     else
03705     {
03706       dwNameLen++;
03707       if (dwNameLen > 8)
03708         return TRUE; /* DOS names are <= 8 chars */
03709     }
03710     lpszPath++;
03711   }
03712   return FALSE; /* Valid DOS path */
03713 }
03714 
03715 /*************************************************************************
03716  * PathIsDirectoryEmptyA [SHLWAPI.@]
03717  *
03718  * Determine if a given directory is empty.
03719  *
03720  * PARAMS
03721  *  lpszPath [I] Directory to check
03722  *
03723  * RETURNS
03724  *  TRUE  If the directory exists and contains no files,
03725  *  FALSE Otherwise
03726  */
03727 BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath)
03728 {
03729   BOOL bRet = FALSE;
03730 
03731   TRACE("(%s)\n",debugstr_a(lpszPath));
03732 
03733   if (lpszPath)
03734   {
03735     WCHAR szPath[MAX_PATH];
03736     MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH);
03737     bRet = PathIsDirectoryEmptyW(szPath);
03738   }
03739   return bRet;
03740 }
03741 
03742 /*************************************************************************
03743  * PathIsDirectoryEmptyW [SHLWAPI.@]
03744  *
03745  * See PathIsDirectoryEmptyA.
03746  */
03747 BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
03748 {
03749   static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' };
03750   WCHAR szSearch[MAX_PATH];
03751   DWORD dwLen;
03752   HANDLE hfind;
03753   BOOL retVal = FALSE;
03754   WIN32_FIND_DATAW find_data;
03755 
03756   TRACE("(%s)\n",debugstr_w(lpszPath));
03757 
03758   if (!lpszPath || !PathIsDirectoryW(lpszPath))
03759       return FALSE;
03760 
03761   lstrcpynW(szSearch, lpszPath, MAX_PATH);
03762   PathAddBackslashW(szSearch);
03763   dwLen = strlenW(szSearch);
03764   if (dwLen > MAX_PATH - 4)
03765     return FALSE;
03766 
03767   strcpyW(szSearch + dwLen, szAllFiles);
03768   hfind = FindFirstFileW(szSearch, &find_data);
03769 
03770   if (hfind != INVALID_HANDLE_VALUE &&
03771       find_data.cFileName[0] == '.' &&
03772       find_data.cFileName[1] == '.')
03773   {
03774     /* The only directory entry should be the parent */
03775     if (!FindNextFileW(hfind, &find_data))
03776       retVal = TRUE;
03777     FindClose(hfind);
03778   }
03779   return retVal;
03780 }
03781 
03782 
03783 /*************************************************************************
03784  * PathFindSuffixArrayA [SHLWAPI.@]
03785  *
03786  * Find a suffix string in an array of suffix strings
03787  *
03788  * PARAMS
03789  *  lpszSuffix [I] Suffix string to search for
03790  *  lppszArray [I] Array of suffix strings to search
03791  *  dwCount    [I] Number of elements in lppszArray
03792  *
03793  * RETURNS
03794  *  Success: The index of the position of lpszSuffix in lppszArray
03795  *  Failure: 0, if any parameters are invalid or lpszSuffix is not found
03796  *
03797  * NOTES
03798  *  The search is case sensitive.
03799  *  The match is made against the end of the suffix string, so for example:
03800  *  lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not.
03801  */
03802 LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
03803 {
03804   size_t dwLen;
03805   int dwRet = 0;
03806 
03807   TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount);
03808 
03809   if (lpszSuffix && lppszArray && dwCount > 0)
03810   {
03811     dwLen = strlen(lpszSuffix);
03812 
03813     while (dwRet < dwCount)
03814     {
03815       size_t dwCompareLen = strlen(*lppszArray);
03816       if (dwCompareLen < dwLen)
03817       {
03818         if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
03819           return *lppszArray; /* Found */
03820       }
03821       dwRet++;
03822       lppszArray++;
03823     }
03824   }
03825   return NULL;
03826 }
03827 
03828 /*************************************************************************
03829  * PathFindSuffixArrayW [SHLWAPI.@]
03830  *
03831  * See PathFindSuffixArrayA.
03832  */
03833 LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
03834 {
03835   size_t dwLen;
03836   int dwRet = 0;
03837 
03838   TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount);
03839 
03840   if (lpszSuffix && lppszArray && dwCount > 0)
03841   {
03842     dwLen = strlenW(lpszSuffix);
03843 
03844     while (dwRet < dwCount)
03845     {
03846       size_t dwCompareLen = strlenW(*lppszArray);
03847       if (dwCompareLen < dwLen)
03848       {
03849         if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
03850           return *lppszArray; /* Found */
03851       }
03852       dwRet++;
03853       lppszArray++;
03854     }
03855   }
03856   return NULL;
03857 }
03858 
03859 /*************************************************************************
03860  * PathUndecorateA [SHLWAPI.@]
03861  *
03862  * Undecorate a file path
03863  *
03864  * PARAMS
03865  *  lpszPath [I/O] Path to remove any decoration from
03866  *
03867  * RETURNS
03868  *  Nothing
03869  *
03870  * NOTES
03871  *  A decorations form is "path[n].ext" where "n" is an optional decimal number.
03872  */
03873 VOID WINAPI PathUndecorateA(LPSTR lpszPath)
03874 {
03875   TRACE("(%s)\n",debugstr_a(lpszPath));
03876 
03877   if (lpszPath)
03878   {
03879     LPSTR lpszExt = PathFindExtensionA(lpszPath);
03880     if (lpszExt > lpszPath && lpszExt[-1] == ']')
03881     {
03882       LPSTR lpszSkip = lpszExt - 2;
03883       if (*lpszSkip == '[')
03884         lpszSkip++;  /* [] (no number) */
03885       else
03886         while (lpszSkip > lpszPath && isdigit(lpszSkip[-1]))
03887           lpszSkip--;
03888       if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
03889       {
03890         /* remove the [n] */
03891         lpszSkip--;
03892         while (*lpszExt)
03893           *lpszSkip++ = *lpszExt++;
03894         *lpszSkip = '\0';
03895       }
03896     }
03897   }
03898 }
03899 
03900 /*************************************************************************
03901  * PathUndecorateW [SHLWAPI.@]
03902  *
03903  * See PathUndecorateA.
03904  */
03905 VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
03906 {
03907   TRACE("(%s)\n",debugstr_w(lpszPath));
03908 
03909   if (lpszPath)
03910   {
03911     LPWSTR lpszExt = PathFindExtensionW(lpszPath);
03912     if (lpszExt > lpszPath && lpszExt[-1] == ']')
03913     {
03914       LPWSTR lpszSkip = lpszExt - 2;
03915       if (*lpszSkip == '[')
03916         lpszSkip++; /* [] (no number) */
03917       else
03918         while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1]))
03919           lpszSkip--;
03920       if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
03921       {
03922         /* remove the [n] */
03923         lpszSkip--;
03924         while (*lpszExt)
03925           *lpszSkip++ = *lpszExt++;
03926         *lpszSkip = '\0';
03927       }
03928     }
03929   }
03930 }
03931 
03932 /*************************************************************************
03933  * PathUnExpandEnvStringsA [SHLWAPI.@]
03934  *
03935  * Substitute folder names in a path with their corresponding environment
03936  * strings.
03937  *
03938  * PARAMS
03939  *  pszPath  [I] Buffer containing the path to unexpand.
03940  *  pszBuf   [O] Buffer to receive the unexpanded path.
03941  *  cchBuf   [I] Size of pszBuf in characters.
03942  *
03943  * RETURNS
03944  *  Success: TRUE
03945  *  Failure: FALSE
03946  */
03947 BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf)
03948 {
03949     FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf);
03950     return FALSE;
03951 }
03952 
03953 /*************************************************************************
03954  * PathUnExpandEnvStringsW [SHLWAPI.@]
03955  *
03956  * Unicode version of PathUnExpandEnvStringsA.
03957  */
03958 BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf)
03959 {
03960     FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
03961     return FALSE;
03962 }
03963 
03964 /*************************************************************************
03965  * @     [SHLWAPI.440]
03966  *
03967  * Find localised or default web content in "%WINDOWS%\web\".
03968  *
03969  * PARAMS
03970  *  lpszFile  [I] File name containing content to look for
03971  *  lpszPath  [O] Buffer to contain the full path to the file
03972  *  dwPathLen [I] Length of lpszPath
03973  *
03974  * RETURNS
03975  *  Success: S_OK. lpszPath contains the full path to the content.
03976  *  Failure: E_FAIL. The content does not exist or lpszPath is too short.
03977  */
03978 HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen)
03979 {
03980   WCHAR szFile[MAX_PATH], szPath[MAX_PATH];
03981   HRESULT hRet;
03982 
03983   TRACE("(%s,%p,%d)\n", lpszFile, lpszPath, dwPathLen);
03984 
03985   MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH);
03986   szPath[0] = '\0';
03987   hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen);
03988   WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0);
03989   return hRet;
03990 }
03991 
03992 /*************************************************************************
03993  * @     [SHLWAPI.441]
03994  *
03995  * Unicode version of SHGetWebFolderFilePathA.
03996  */
03997 HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD dwPathLen)
03998 {
03999   static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'};
04000   static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'};
04001 #define szWebLen (sizeof(szWeb)/sizeof(WCHAR))
04002 #define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR))
04003   DWORD dwLen, dwFileLen;
04004   LANGID lidSystem, lidUser;
04005 
04006   TRACE("(%s,%p,%d)\n", debugstr_w(lpszFile), lpszPath, dwPathLen);
04007 
04008   /* Get base directory for web content */
04009   dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen);
04010   if (dwLen > 0 && lpszPath[dwLen-1] == '\\')
04011     dwLen--;
04012 
04013   dwFileLen = strlenW(lpszFile);
04014 
04015   if (dwLen + dwFileLen + szWebLen >= dwPathLen)
04016     return E_FAIL; /* lpszPath too short */
04017 
04018   strcpyW(lpszPath+dwLen, szWeb);
04019   dwLen += szWebLen;
04020   dwPathLen = dwPathLen - dwLen; /* Remaining space */
04021 
04022   lidSystem = GetSystemDefaultUILanguage();
04023   lidUser = GetUserDefaultUILanguage();
04024 
04025   if (lidSystem != lidUser)
04026   {
04027     if (dwFileLen + szWebMuiLen < dwPathLen)
04028     {
04029       /* Use localised content in the users UI language if present */
04030       wsprintfW(lpszPath + dwLen, szWebMui, lidUser);
04031       strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile);
04032       if (PathFileExistsW(lpszPath))
04033         return S_OK;
04034     }
04035   }
04036 
04037   /* Fall back to OS default installed content */
04038   strcpyW(lpszPath + dwLen, lpszFile);
04039   if (PathFileExistsW(lpszPath))
04040     return S_OK;
04041   return E_FAIL;
04042 }
04043 
04044 #define PATH_CHAR_CLASS_LETTER      0x00000001
04045 #define PATH_CHAR_CLASS_ASTERIX     0x00000002
04046 #define PATH_CHAR_CLASS_DOT         0x00000004
04047 #define PATH_CHAR_CLASS_BACKSLASH   0x00000008
04048 #define PATH_CHAR_CLASS_COLON       0x00000010
04049 #define PATH_CHAR_CLASS_SEMICOLON   0x00000020
04050 #define PATH_CHAR_CLASS_COMMA       0x00000040
04051 #define PATH_CHAR_CLASS_SPACE       0x00000080
04052 #define PATH_CHAR_CLASS_OTHER_VALID 0x00000100
04053 #define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200
04054 
04055 #define PATH_CHAR_CLASS_INVALID     0x00000000
04056 #define PATH_CHAR_CLASS_ANY         0xffffffff
04057 
04058 static const DWORD SHELL_charclass[] =
04059 {
04060     /* 0x00 */  PATH_CHAR_CLASS_INVALID,      /* 0x01 */  PATH_CHAR_CLASS_INVALID,
04061     /* 0x02 */  PATH_CHAR_CLASS_INVALID,      /* 0x03 */  PATH_CHAR_CLASS_INVALID,
04062     /* 0x04 */  PATH_CHAR_CLASS_INVALID,      /* 0x05 */  PATH_CHAR_CLASS_INVALID,
04063     /* 0x06 */  PATH_CHAR_CLASS_INVALID,      /* 0x07 */  PATH_CHAR_CLASS_INVALID,
04064     /* 0x08 */  PATH_CHAR_CLASS_INVALID,      /* 0x09 */  PATH_CHAR_CLASS_INVALID,
04065     /* 0x0a */  PATH_CHAR_CLASS_INVALID,      /* 0x0b */  PATH_CHAR_CLASS_INVALID,
04066     /* 0x0c */  PATH_CHAR_CLASS_INVALID,      /* 0x0d */  PATH_CHAR_CLASS_INVALID,
04067     /* 0x0e */  PATH_CHAR_CLASS_INVALID,      /* 0x0f */  PATH_CHAR_CLASS_INVALID,
04068     /* 0x10 */  PATH_CHAR_CLASS_INVALID,      /* 0x11 */  PATH_CHAR_CLASS_INVALID,
04069     /* 0x12 */  PATH_CHAR_CLASS_INVALID,      /* 0x13 */  PATH_CHAR_CLASS_INVALID,
04070     /* 0x14 */  PATH_CHAR_CLASS_INVALID,      /* 0x15 */  PATH_CHAR_CLASS_INVALID,
04071     /* 0x16 */  PATH_CHAR_CLASS_INVALID,      /* 0x17 */  PATH_CHAR_CLASS_INVALID,
04072     /* 0x18 */  PATH_CHAR_CLASS_INVALID,      /* 0x19 */  PATH_CHAR_CLASS_INVALID,
04073     /* 0x1a */  PATH_CHAR_CLASS_INVALID,      /* 0x1b */  PATH_CHAR_CLASS_INVALID,
04074     /* 0x1c */  PATH_CHAR_CLASS_INVALID,      /* 0x1d */  PATH_CHAR_CLASS_INVALID,
04075     /* 0x1e */  PATH_CHAR_CLASS_INVALID,      /* 0x1f */  PATH_CHAR_CLASS_INVALID,
04076     /* ' '  */  PATH_CHAR_CLASS_SPACE,        /* '!'  */  PATH_CHAR_CLASS_OTHER_VALID,
04077     /* '"'  */  PATH_CHAR_CLASS_DOUBLEQUOTE,  /* '#'  */  PATH_CHAR_CLASS_OTHER_VALID,
04078     /* '$'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '%'  */  PATH_CHAR_CLASS_OTHER_VALID,
04079     /* '&'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '\'' */  PATH_CHAR_CLASS_OTHER_VALID,
04080     /* '('  */  PATH_CHAR_CLASS_OTHER_VALID,  /* ')'  */  PATH_CHAR_CLASS_OTHER_VALID,
04081     /* '*'  */  PATH_CHAR_CLASS_ASTERIX,      /* '+'  */  PATH_CHAR_CLASS_OTHER_VALID,
04082     /* ','  */  PATH_CHAR_CLASS_COMMA,        /* '-'  */  PATH_CHAR_CLASS_OTHER_VALID,
04083     /* '.'  */  PATH_CHAR_CLASS_DOT,          /* '/'  */  PATH_CHAR_CLASS_INVALID,
04084     /* '0'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '1'  */  PATH_CHAR_CLASS_OTHER_VALID,
04085     /* '2'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '3'  */  PATH_CHAR_CLASS_OTHER_VALID,
04086     /* '4'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '5'  */  PATH_CHAR_CLASS_OTHER_VALID,
04087     /* '6'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '7'  */  PATH_CHAR_CLASS_OTHER_VALID,
04088     /* '8'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '9'  */  PATH_CHAR_CLASS_OTHER_VALID,
04089     /* ':'  */  PATH_CHAR_CLASS_COLON,        /* ';'  */  PATH_CHAR_CLASS_SEMICOLON,
04090     /* '<'  */  PATH_CHAR_CLASS_INVALID,      /* '='  */  PATH_CHAR_CLASS_OTHER_VALID,
04091     /* '>'  */  PATH_CHAR_CLASS_INVALID,      /* '?'  */  PATH_CHAR_CLASS_LETTER,
04092     /* '@'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* 'A'  */  PATH_CHAR_CLASS_ANY,
04093     /* 'B'  */  PATH_CHAR_CLASS_ANY,          /* 'C'  */  PATH_CHAR_CLASS_ANY,
04094     /* 'D'  */  PATH_CHAR_CLASS_ANY,          /* 'E'  */  PATH_CHAR_CLASS_ANY,
04095     /* 'F'  */  PATH_CHAR_CLASS_ANY,          /* 'G'  */  PATH_CHAR_CLASS_ANY,
04096     /* 'H'  */  PATH_CHAR_CLASS_ANY,          /* 'I'  */  PATH_CHAR_CLASS_ANY,
04097     /* 'J'  */  PATH_CHAR_CLASS_ANY,          /* 'K'  */  PATH_CHAR_CLASS_ANY,
04098     /* 'L'  */  PATH_CHAR_CLASS_ANY,          /* 'M'  */  PATH_CHAR_CLASS_ANY,
04099     /* 'N'  */  PATH_CHAR_CLASS_ANY,          /* 'O'  */  PATH_CHAR_CLASS_ANY,
04100     /* 'P'  */  PATH_CHAR_CLASS_ANY,          /* 'Q'  */  PATH_CHAR_CLASS_ANY,
04101     /* 'R'  */  PATH_CHAR_CLASS_ANY,          /* 'S'  */  PATH_CHAR_CLASS_ANY,
04102     /* 'T'  */  PATH_CHAR_CLASS_ANY,          /* 'U'  */  PATH_CHAR_CLASS_ANY,
04103     /* 'V'  */  PATH_CHAR_CLASS_ANY,          /* 'W'  */  PATH_CHAR_CLASS_ANY,
04104     /* 'X'  */  PATH_CHAR_CLASS_ANY,          /* 'Y'  */  PATH_CHAR_CLASS_ANY,
04105     /* 'Z'  */  PATH_CHAR_CLASS_ANY,          /* '['  */  PATH_CHAR_CLASS_OTHER_VALID,
04106     /* '\\' */  PATH_CHAR_CLASS_BACKSLASH,    /* ']'  */  PATH_CHAR_CLASS_OTHER_VALID,
04107     /* '^'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* '_'  */  PATH_CHAR_CLASS_OTHER_VALID,
04108     /* '`'  */  PATH_CHAR_CLASS_OTHER_VALID,  /* 'a'  */  PATH_CHAR_CLASS_ANY,
04109     /* 'b'  */  PATH_CHAR_CLASS_ANY,          /* 'c'  */  PATH_CHAR_CLASS_ANY,
04110     /* 'd'  */  PATH_CHAR_CLASS_ANY,          /* 'e'  */  PATH_CHAR_CLASS_ANY,
04111     /* 'f'  */  PATH_CHAR_CLASS_ANY,          /* 'g'  */  PATH_CHAR_CLASS_ANY,
04112     /* 'h'  */  PATH_CHAR_CLASS_ANY,          /* 'i'  */  PATH_CHAR_CLASS_ANY,
04113     /* 'j'  */  PATH_CHAR_CLASS_ANY,          /* 'k'  */  PATH_CHAR_CLASS_ANY,
04114     /* 'l'  */  PATH_CHAR_CLASS_ANY,          /* 'm'  */  PATH_CHAR_CLASS_ANY,
04115     /* 'n'  */  PATH_CHAR_CLASS_ANY,          /* 'o'  */  PATH_CHAR_CLASS_ANY,
04116     /* 'p'  */  PATH_CHAR_CLASS_ANY,          /* 'q'  */  PATH_CHAR_CLASS_ANY,
04117     /* 'r'  */  PATH_CHAR_CLASS_ANY,          /* 's'  */  PATH_CHAR_CLASS_ANY,
04118     /* 't'  */  PATH_CHAR_CLASS_ANY,          /* 'u'  */  PATH_CHAR_CLASS_ANY,
04119     /* 'v'  */  PATH_CHAR_CLASS_ANY,          /* 'w'  */  PATH_CHAR_CLASS_ANY,
04120     /* 'x'  */  PATH_CHAR_CLASS_ANY,          /* 'y'  */  PATH_CHAR_CLASS_ANY,
04121     /* 'z'  */  PATH_CHAR_CLASS_ANY,          /* '{'  */  PATH_CHAR_CLASS_OTHER_VALID,
04122     /* '|'  */  PATH_CHAR_CLASS_INVALID,      /* '}'  */  PATH_CHAR_CLASS_OTHER_VALID,
04123     /* '~'  */  PATH_CHAR_CLASS_OTHER_VALID
04124 };
04125 
04126 /*************************************************************************
04127  * @     [SHLWAPI.455]
04128  *
04129  * Check if an ASCII char is of a certain class
04130  */
04131 BOOL WINAPI PathIsValidCharA( char c, DWORD class )
04132 {
04133     if ((unsigned)c > 0x7e)
04134         return class & PATH_CHAR_CLASS_OTHER_VALID;
04135 
04136     return class & SHELL_charclass[(unsigned)c];
04137 }
04138 
04139 /*************************************************************************
04140  * @     [SHLWAPI.456]
04141  *
04142  * Check if a Unicode char is of a certain class
04143  */
04144 BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class )
04145 {
04146     if (c > 0x7e)
04147         return class & PATH_CHAR_CLASS_OTHER_VALID;
04148 
04149     return class & SHELL_charclass[c];
04150 }

Generated on Mon May 28 2012 04:18:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.