Ignore:
Timestamp:
Jun 7, 2002, 10:02:20 AM (23 years ago)
Author:
sandervl
Message:

resynced with latest Wine

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/shlwapi/path.c

    r8047 r8584  
    11/*
    22 * Path Functions
     3 *
     4 * Copyright 1999, 2000 Juergen Schmied
     5 * Copyright 2001, 2002 Jon Griffiths
     6 *
     7 * This library is free software; you can redistribute it and/or
     8 * modify it under the terms of the GNU Lesser General Public
     9 * License as published by the Free Software Foundation; either
     10 * version 2.1 of the License, or (at your option) any later version.
     11 *
     12 * This library is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 * Lesser General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU Lesser General Public
     18 * License along with this library; if not, write to the Free Software
     19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    320 */
    421
     
    1532#define NO_SHLWAPI_STREAM
    1633#include "shlwapi.h"
    17 #include "debugtools.h"
     34#include "wine/debug.h"
    1835#include "ordinal.h"
    1936
    20 DEFAULT_DEBUG_CHANNEL(shell);
    21 
    22 INT __cdecl _wtoi(LPWSTR string);
    23 
    24 #define isSlash(x) ((x)=='\\' || (x)=='/')
    25 /*
    26         ########## Combining and Constructing paths ##########
     37WINE_DEFAULT_DEBUG_CHANNEL(shell);
     38
     39/* function pointers for GET_FUNC macro; these need to be global because of gcc bug */
     40#ifdef __WIN32OS2__
     41static BOOL (* WINAPI pIsNetDrive)(DWORD);
     42#else
     43static BOOL (WINAPI *pIsNetDrive)(DWORD);
     44#endif
     45
     46/*************************************************************************
     47 * PathAppendA    [SHLWAPI.@]
     48 *
     49 * Append one path to another.
     50 *
     51 * PARAMS
     52 *  lpszPath   [O] Initial part of path
     53 *  lpszAppend [I] Path to append
     54 *
     55 * RETURNS
     56 *  Success: TRUE. lpszPath contains the newly created path.
     57 *  Failure: FALSE, if either path is NULL, or PathCombineA fails.
     58 *
     59 * NOTES
     60 *  lpszAppend must contain at least one backslash ('\') if not NULL.
     61 *  Because PathCombineA is used to join the paths, the resulting
     62 *  path is also canonicalized.
     63 */
     64BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend)
     65{
     66  TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend));
     67
     68  if (lpszPath && lpszAppend)
     69  {
     70    while (*lpszAppend == '\\')
     71      lpszAppend++;
     72    if (PathCombineA(lpszPath, lpszPath, lpszAppend))
     73      return TRUE;
     74  }
     75  return FALSE;
     76}
     77
     78/*************************************************************************
     79 * PathAppendW    [SHLWAPI.@]
     80 *
     81 * See PathAppendA.
     82 */
     83BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
     84{
     85  TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend));
     86
     87  if (lpszPath && lpszAppend)
     88  {
     89    while (*lpszAppend == '\\')
     90      lpszAppend++;
     91    if (PathCombineW(lpszPath, lpszPath, lpszAppend))
     92      return TRUE;
     93  }
     94  return FALSE;
     95}
     96
     97/*************************************************************************
     98 * PathCombineA         [SHLWAPI.@]
     99 *
     100 * Combine two paths together.
     101 *
     102 * PARAMS
     103 *  lpszDest [O] Destination for combined path
     104 *  lpszDir  [I] Directory path
     105 *  liszFile [I] File path
     106 *
     107 * RETURNS
     108 *  Success: The output path
     109 *  Failure: NULL, if inputs are invalid.
     110 *
     111 * NOTES
     112 *  lpszDest should be at least MAX_PATH in size, and may point to the same
     113 *  memory location as lpszDir. The combined path is canonicalised.
     114 */
     115LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile)
     116{
     117  TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile));
     118
     119  if (!lpszDest || (!lpszDir && !lpszFile))
     120    return NULL; /* Invalid parameters */
     121  else
     122  {
     123    WCHAR szDest[MAX_PATH];
     124    WCHAR szDir[MAX_PATH];
     125    WCHAR szFile[MAX_PATH];
     126    if (lpszDir)
     127      MultiByteToWideChar(0,0,lpszDir,-1,szDir,MAX_PATH);
     128    if (lpszFile)
     129      MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH);
     130    PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL);
     131    WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0);
     132  }
     133  return lpszDest;
     134}
     135
     136/*************************************************************************
     137 * PathCombineW          [SHLWAPI.@]
     138 *
     139 * See PathCombineA.
     140 */
     141LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile)
     142{
     143  WCHAR szTemp[MAX_PATH];
     144  BOOL bUseBoth = FALSE, bStrip = FALSE;
     145
     146  TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile));
     147
     148  if (!lpszDest || (!lpszDir && !lpszFile))
     149    return lpszDest; /* Invalid parameters */
     150
     151  if (!lpszFile || !*lpszFile)
     152  {
     153    /* Use dir only */
     154    strncpyW(szTemp, lpszDir, MAX_PATH);
     155  }
     156  else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile))
     157  {
     158    if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile))
     159    {
     160      /* Use file only */
     161      strncpyW(szTemp, lpszFile, MAX_PATH);
     162    }
     163    else
     164    {
     165      bUseBoth = TRUE;
     166      bStrip = TRUE;
     167    }
     168  }
     169  else
     170    bUseBoth = TRUE;
     171
     172  if (bUseBoth)
     173  {
     174    strncpyW(szTemp, lpszDir, MAX_PATH);
     175    if (bStrip)
     176    {
     177      PathStripToRootW(szTemp);
     178      lpszFile++; /* Skip '\' */
     179    }
     180    if (!PathAddBackslashW(szTemp))
     181      return NULL;
     182    if (strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH)
     183      return NULL;
     184    strcatW(szTemp, lpszFile);
     185  }
     186
     187  PathCanonicalizeW(lpszDest, szTemp);
     188  return lpszDest;
     189}
     190
     191/*************************************************************************
     192 * PathAddBackslashA    [SHLWAPI.@]
     193 *
     194 * Append a backslash ('\') to a path if one doesn't exist.
     195 *
     196 * PARAMS
     197 *  lpszPath [O] The path to append a backslash to.
     198 *
     199 * RETURNS
     200 *  Success: The position of the last backslash in the path.
     201 *  Failure: NULL, if lpszPath is NULL or the path is too large.
     202 */
     203LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
     204{
     205  int iLen;
     206
     207  TRACE("(%s)\n",debugstr_a(lpszPath));
     208
     209  if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH)
     210    return NULL;
     211
     212  if (iLen)
     213  {
     214    lpszPath += iLen;
     215    if (lpszPath[-1] != '\\')
     216    {
     217     *lpszPath++ = '\\';
     218     *lpszPath = '\0';
     219    }
     220  }
     221  return lpszPath;
     222}
     223
     224/*************************************************************************
     225 * PathAddBackslashW  [SHLWAPI.@]
     226 *
     227 * See PathAddBackslashA.
     228 */
     229LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath )
     230{
     231  int iLen;
     232
     233  TRACE("(%s)\n",debugstr_w(lpszPath));
     234
     235  if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH)
     236    return NULL;
     237
     238  if (iLen)
     239  {
     240    lpszPath += iLen;
     241    if (lpszPath[-1] != '\\')
     242    {
     243      *lpszPath++ = '\\';
     244      *lpszPath = '\0';
     245    }
     246  }
     247  return lpszPath;
     248}
     249
     250/*************************************************************************
     251 * PathBuildRootA    [SHLWAPI.@]
     252 *
     253 * Create a root drive string (e.g. "A:\") from a drive number.
     254 *
     255 * PARAMS
     256 *  lpszPath [O] Destination for the drive string
     257 *
     258 * RETURNS
     259 *  lpszPath
     260 *
     261 * NOTES
     262 *  If lpszPath is NULL or drive is invalid, nothing is written to lpszPath.
     263 */
     264LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive)
     265{
     266  TRACE("(%p,%d)\n", debugstr_a(lpszPath), drive);
     267
     268  if (lpszPath && drive >= 0 && drive < 26)
     269  {
     270    lpszPath[0] = 'A' + drive;
     271    lpszPath[1] = ':';
     272    lpszPath[2] = '\\';
     273    lpszPath[3] = '\0';
     274  }
     275  return lpszPath;
     276}
     277
     278/*************************************************************************
     279 * PathBuildRootW    [SHLWAPI.@]
     280 *
     281 * See PathBuildRootA.
     282 */
     283LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive)
     284{
     285  TRACE("(%p,%d)\n",debugstr_w(lpszPath), drive);
     286
     287  if (lpszPath && drive >= 0 && drive < 26)
     288  {
     289    lpszPath[0] = 'A' + drive;
     290    lpszPath[1] = ':';
     291    lpszPath[2] = '\\';
     292    lpszPath[3] = '\0';
     293  }
     294  return lpszPath;
     295}
     296
     297/*************************************************************************
     298 * PathFindFileNameA  [SHLWAPI.@]
     299 *
     300 * Locate the start of the file name in a path
     301 *
     302 * PARAMS
     303 *  lpszPath [I] Path to search
     304 *
     305 * RETURNS
     306 *  A pointer to the first character of the file name
     307 */
     308LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
     309{
     310  LPCSTR lastSlash = lpszPath;
     311
     312  TRACE("(%s)\n",debugstr_a(lpszPath));
     313
     314  while (lpszPath && *lpszPath)
     315  {
     316    if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
     317        lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
     318      lastSlash = lpszPath + 1;
     319    lpszPath = CharNextA(lpszPath);
     320  }
     321  return (LPSTR)lastSlash;
     322}
     323
     324/*************************************************************************
     325 * PathFindFileNameW  [SHLWAPI.@]
     326 *
     327 * See PathFindFileNameA.
     328 */
     329LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
     330{
     331  LPCWSTR lastSlash = lpszPath;
     332
     333  TRACE("(%s)\n",debugstr_w(lpszPath));
     334
     335  while (lpszPath && *lpszPath)
     336  {
     337    if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
     338        lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
     339      lastSlash = lpszPath + 1;
     340    lpszPath = CharNextW(lpszPath);
     341  }
     342  return (LPWSTR)lastSlash;
     343}
     344
     345/*************************************************************************
     346 * PathFindExtensionA  [SHLWAPI.@]
     347 *
     348 * Locate the start of the file extension in a path
     349 *
     350 * PARAMS
     351 *  lpszPath [I] The path to search
     352 *
     353 * RETURNS
     354 *  A pointer to the first character of the extension, the end of
     355 *  the string if the path has no extension, or NULL If lpszPath is NULL
     356 */
     357LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath )
     358{
     359  LPCSTR lastpoint = NULL;
     360
     361  TRACE("(%s)\n", debugstr_a(lpszPath));
     362
     363  if (lpszPath)
     364  {
     365    while (*lpszPath)
     366    {
     367      if (*lpszPath == '\\' || *lpszPath==' ')
     368        lastpoint = NULL;
     369      else if (*lpszPath == '.')
     370        lastpoint = lpszPath;
     371      lpszPath = CharNextA(lpszPath);
     372    }
     373  }
     374  return (LPSTR)(lastpoint ? lastpoint : lpszPath);
     375}
     376
     377/*************************************************************************
     378 * PathFindExtensionW  [SHLWAPI.@]
     379 *
     380 * See PathFindExtensionA.
     381 */
     382LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath )
     383{
     384  LPCWSTR lastpoint = NULL;
     385
     386  TRACE("(%s)\n", debugstr_w(lpszPath));
     387
     388  if (lpszPath)
     389  {
     390    while (*lpszPath)
     391    {
     392      if (*lpszPath == '\\' || *lpszPath==' ')
     393        lastpoint = NULL;
     394      else if (*lpszPath == '.')
     395        lastpoint = lpszPath;
     396      lpszPath = CharNextW(lpszPath);
     397    }
     398  }
     399  return (LPWSTR)(lastpoint ? lastpoint : lpszPath);
     400}
     401
     402/*************************************************************************
     403 * PathGetArgsA    [SHLWAPI.@]
     404 *
     405 * Find the next argument in a string delimited by spaces.
     406 *
     407 * PARAMS
     408 *  lpszPath [I] The string to search for arguments in
     409 *
     410 * RETURNS
     411 *  The start of the next argument in lpszPath, or NULL if lpszPath is NULL
     412 *
     413 * NOTES
     414 *  Spaces in quoted strings are ignored as delimiters.
     415 */
     416LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath)
     417{
     418  BOOL bSeenQuote = FALSE;
     419
     420  TRACE("(%s)\n",debugstr_a(lpszPath));
     421
     422  if (lpszPath)
     423  {
     424    while (*lpszPath)
     425    {
     426      if ((*lpszPath==' ') && !bSeenQuote)
     427        return (LPSTR)lpszPath + 1;
     428      if (*lpszPath == '"')
     429        bSeenQuote = !bSeenQuote;
     430      lpszPath = CharNextA(lpszPath);
     431    }
     432  }
     433  return (LPSTR)lpszPath;
     434}
     435
     436/*************************************************************************
     437 * PathGetArgsW    [SHLWAPI.@]
     438 *
     439 * See PathGetArgsA.
     440 */
     441LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
     442{
     443  BOOL bSeenQuote = FALSE;
     444
     445  TRACE("(%s)\n",debugstr_w(lpszPath));
     446
     447  if (lpszPath)
     448  {
     449    while (*lpszPath)
     450    {
     451      if ((*lpszPath==' ') && !bSeenQuote)
     452        return (LPWSTR)lpszPath + 1;
     453      if (*lpszPath == '"')
     454        bSeenQuote = !bSeenQuote;
     455      lpszPath = CharNextW(lpszPath);
     456    }
     457  }
     458  return (LPWSTR)lpszPath;
     459}
     460
     461/*************************************************************************
     462 * PathGetDriveNumberA  [SHLWAPI.@]
     463 *
     464 * Return the drive number from a path
     465 *
     466 * PARAMS
     467 *  lpszPath [I] Path to get the drive number from
     468 *
     469 * RETURNS
     470 *  Success: The drive number corresponding to the drive in the path
     471 *  Failure: -1, if lpszPath contains no valid drive
     472 */
     473int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
     474{
     475  TRACE ("(%s)\n",debugstr_a(lpszPath));
     476
     477  if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' &&
     478      tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z')
     479    return tolower(*lpszPath) - 'a';
     480  return -1;
     481}
     482
     483/*************************************************************************
     484 * PathGetDriveNumberW  [SHLWAPI.@]
     485 *
     486 * See PathGetDriveNumberA.
     487 */
     488int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
     489{
     490  TRACE ("(%s)\n",debugstr_w(lpszPath));
     491
     492  if (lpszPath && lpszPath[1] == ':' &&
     493      tolowerW(*lpszPath) >= 'a' && tolowerW(*lpszPath) <= 'z')
     494    return tolowerW(*lpszPath) - 'a';
     495  return -1;
     496}
     497
     498/*************************************************************************
     499 * PathRemoveFileSpecA  [SHLWAPI.@]
     500 *
     501 * Remove the file specification from a path.
     502 *
     503 * PARAMS
     504 *  lpszPath [O] Path to remove the file spec from
     505 *
     506 * RETURNS
     507 *  TRUE  If the path was valid and modified
     508 *  FALSE Otherwise
     509 */
     510BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
     511{
     512  LPSTR lpszFileSpec = lpszPath;
     513  BOOL bModified = FALSE;
     514
     515  TRACE("(%s)\n",debugstr_a(lpszPath));
     516
     517  if(lpszPath)
     518  {
     519    /* Skip directory or UNC path */
     520    if (*lpszPath == '\\')
     521      lpszFileSpec = ++lpszPath;
     522    if (*lpszPath == '\\')
     523      lpszFileSpec = ++lpszPath;
     524
     525    while (*lpszPath)
     526    {
     527      if(*lpszPath == '\\')
     528        lpszFileSpec = lpszPath; /* Skip dir */
     529      else if(*lpszPath == ':')
     530      {
     531        lpszFileSpec = ++lpszPath; /* Skip drive */
     532        if (*lpszPath == '\\')
     533          lpszFileSpec++;
     534      }
     535      if (!(lpszPath = CharNextA(lpszPath)))
     536        break;
     537    }
     538
     539    if (*lpszFileSpec)
     540    {
     541      *lpszFileSpec = '\0';
     542      bModified = TRUE;
     543    }
     544  }
     545  return bModified;
     546}
     547
     548/*************************************************************************
     549 * PathRemoveFileSpecW  [SHLWAPI.@]
     550 *
     551 * See PathRemoveFileSpecA.
     552 */
     553BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
     554{
     555  LPWSTR lpszFileSpec = lpszPath;
     556  BOOL bModified = FALSE;
     557
     558  TRACE("(%s)\n",debugstr_w(lpszPath));
     559
     560  if(lpszPath)
     561  {
     562    /* Skip directory or UNC path */
     563    if (*lpszPath == '\\')
     564      lpszFileSpec = ++lpszPath;
     565    if (*lpszPath == '\\')
     566      lpszFileSpec = ++lpszPath;
     567
     568    while (*lpszPath)
     569    {
     570      if(*lpszPath == '\\')
     571        lpszFileSpec = lpszPath; /* Skip dir */
     572      else if(*lpszPath == ':')
     573      {
     574        lpszFileSpec = ++lpszPath; /* Skip drive */
     575        if (*lpszPath == '\\')
     576          lpszFileSpec++;
     577      }
     578      if (!(lpszPath = CharNextW(lpszPath)))
     579        break;
     580    }
     581
     582    if (*lpszFileSpec)
     583    {
     584      *lpszFileSpec = '\0';
     585      bModified = TRUE;
     586    }
     587  }
     588  return bModified;
     589}
     590
     591/*************************************************************************
     592 * PathStripPathA       [SHLWAPI.@]
     593 *
     594 * Remove the initial path from the beginning of a filename
     595 *
     596 * PARAMS
     597 *  lpszPath [O] Path to remove the initial path from
     598 *
     599 * RETURNS
     600 *  Nothing.
     601 */
     602void WINAPI PathStripPathA(LPSTR lpszPath)
     603{
     604  TRACE("(%s)\n", debugstr_a(lpszPath));
     605
     606  if (lpszPath)
     607  {
     608    LPSTR lpszFileName = PathFindFileNameA(lpszPath);
     609    if(lpszFileName)
     610      RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1);
     611  }
     612}
     613
     614/*************************************************************************
     615 * PathStripPathW       [SHLWAPI.@]
     616 *
     617 * See PathStripPathA.
     618 */
     619void WINAPI PathStripPathW(LPWSTR lpszPath)
     620{
     621  LPWSTR lpszFileName;
     622
     623  TRACE("(%s)\n", debugstr_w(lpszPath));
     624  lpszFileName = PathFindFileNameW(lpszPath);
     625  if(lpszFileName)
     626    RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR));
     627}
     628
     629/*************************************************************************
     630 * PathStripToRootA     [SHLWAPI.@]
     631 *
     632 * Reduce a path to its root.
     633 *
     634 * PARAMS
     635 *  lpszPath [O] the path to reduce
     636 *
     637 * RETURNS
     638 *  Success: TRUE if the stripped path is a root path
     639 *  Failure: FALSE if the path cannot be stripped or is NULL
     640 */
     641BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
     642{
     643  TRACE("(%s)\n", debugstr_a(lpszPath));
     644
     645  if (!lpszPath)
     646    return FALSE;
     647  while(!PathIsRootA(lpszPath))
     648    if (!PathRemoveFileSpecA(lpszPath))
     649      return FALSE;
     650  return TRUE;
     651}
     652
     653/*************************************************************************
     654 * PathStripToRootW     [SHLWAPI.@]
     655 *
     656 * See PathStripToRootA.
     657 */
     658BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
     659{
     660  TRACE("(%s)\n", debugstr_w(lpszPath));
     661
     662  if (!lpszPath)
     663    return FALSE;
     664  while(!PathIsRootW(lpszPath))
     665    if (!PathRemoveFileSpecW(lpszPath))
     666      return FALSE;
     667  return TRUE;
     668}
     669
     670/*************************************************************************
     671 * PathRemoveArgsA      [SHLWAPI.@]
     672 *
     673 * Strip space seperated arguments from a path.
     674 *
     675 * PARAMS
     676 *  lpszPath [I] Path to remove arguments from
     677 *
     678 * RETURNS
     679 *  Nothing.
     680 */
     681void WINAPI PathRemoveArgsA(LPSTR lpszPath)
     682{
     683  TRACE("(%s)\n",debugstr_a(lpszPath));
     684
     685  if(lpszPath)
     686  {
     687    LPSTR lpszArgs = PathGetArgsA(lpszPath);
     688    if (*lpszArgs)
     689      lpszArgs[-1] = '\0';
     690    else
     691    {
     692      LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
     693      if(*lpszLastChar == ' ')
     694        *lpszLastChar = '\0';
     695    }
     696  }
     697}
     698
     699/*************************************************************************
     700 * PathRemoveArgsW      [SHLWAPI.@]
     701 *
     702 * See PathRemoveArgsA.
     703 */
     704void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
     705{
     706  TRACE("(%s)\n",debugstr_w(lpszPath));
     707
     708  if(lpszPath)
     709  {
     710    LPWSTR lpszArgs = PathGetArgsW(lpszPath);
     711    if (*lpszArgs)
     712      lpszArgs[-1] = '\0';
     713    else
     714    {
     715      LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
     716      if(*lpszLastChar == ' ')
     717        *lpszLastChar = '\0';
     718    }
     719  }
     720}
     721
     722/*************************************************************************
     723 * PathRemoveExtensionA         [SHLWAPI.@]
     724 *
     725 * Remove the file extension from a path
     726 *
     727 * PARAMS
     728 *  lpszPath [O] Path to remove the extension from
     729 *
     730 * RETURNS
     731 *  Nothing.
     732 */
     733void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
     734{
     735  TRACE("(%s)\n", debugstr_a(lpszPath));
     736
     737  if (lpszPath)
     738  {
     739    lpszPath = PathFindExtensionA(lpszPath);
     740    *lpszPath = '\0';
     741  }
     742}
     743
     744/*************************************************************************
     745 * PathRemoveExtensionW         [SHLWAPI.@]
     746 *
     747 * See PathRemoveExtensionA.
    27748*/
    28 
    29 /*************************************************************************
    30  * PathAppendA          [SHLWAPI.@]
    31  *
     749void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
     750{
     751  TRACE("(%s)\n", debugstr_w(lpszPath));
     752
     753  if (lpszPath)
     754  {
     755    lpszPath = PathFindExtensionW(lpszPath);
     756    *lpszPath = '\0';
     757  }
     758}
     759
     760/*************************************************************************
     761 * PathRemoveBackslashA [SHLWAPI.@]
     762 *
     763 * Remove a trailing backslash from a path.
     764 *
     765 * PARAMS
     766 *  lpszPath [O] Path to remove backslash from
     767 *
     768 * RETURNS
     769 *  Success: A pointer to the end of the path
     770 *  Failure: NULL, if lpszPath is NULL
     771 */
     772LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
     773{
     774  LPSTR szTemp = NULL;
     775
     776  TRACE("(%s)\n", debugstr_a(lpszPath));
     777
     778  if(lpszPath)
     779  {
     780    szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
     781    if (!PathIsRootA(lpszPath) && *szTemp == '\\')
     782      *szTemp = '\0';
     783  }
     784  return szTemp;
     785}
     786
     787/*************************************************************************
     788 * PathRemoveBackslashW [SHLWAPI.@]
     789 *
     790 * See PathRemoveBackslashA.
     791 */
     792LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
     793{
     794  LPWSTR szTemp = NULL;
     795
     796  TRACE("(%s)\n", debugstr_w(lpszPath));
     797
     798  if(lpszPath)
     799  {
     800    szTemp = CharPrevW(lpszPath, lpszPath + strlenW(lpszPath));
     801    if (!PathIsRootW(lpszPath) && *szTemp == '\\')
     802      *szTemp = '\0';
     803  }
     804  return szTemp;
     805}
     806
     807/*************************************************************************
     808 * PathRemoveBlanksA [SHLWAPI.@]
     809 *
     810 * Remove Spaces from the start and end of a path.
     811 *
     812 * PARAMS
     813 *  lpszPath [O] Path to strip blanks from
     814 *
     815 * RETURNS
     816 *  Nothing.
     817 */
     818VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath)
     819{
     820  TRACE("(%s)\n", debugstr_a(lpszPath));
     821
     822  if(lpszPath && *lpszPath)
     823  {
     824    LPSTR start = lpszPath;
     825
     826    while (*lpszPath == ' ')
     827      lpszPath = CharNextA(lpszPath);
     828
     829    while(*lpszPath)
     830      *start++ = *lpszPath++;
     831
     832    if (start != lpszPath)
     833      while (start[-1] == ' ')
     834        start--;
     835    *start = '\0';
     836  }
     837}
     838
     839/*************************************************************************
     840 * PathRemoveBlanksW [SHLWAPI.@]
     841 *
     842 * See PathRemoveBlanksA.
     843 */
     844VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath)
     845{
     846  TRACE("(%s)\n", debugstr_w(lpszPath));
     847
     848  if(lpszPath && *lpszPath)
     849  {
     850    LPWSTR start = lpszPath;
     851
     852    while (*lpszPath == ' ')
     853      lpszPath++;
     854
     855    while(*lpszPath)
     856      *start++ = *lpszPath++;
     857
     858    if (start != lpszPath)
     859      while (start[-1] == ' ')
     860        start--;
     861    *start = '\0';
     862  }
     863}
     864
     865/*************************************************************************
     866 * PathQuoteSpacesA [SHLWAPI.@]
     867 *
     868 * Surround a path containg spaces in quotes.
     869 *
     870 * PARAMS
     871 *  lpszPath [O] Path to quote
     872 *
     873 * RETURNS
     874 *  Nothing.
     875 *
    32876 * NOTES
    33  *  concat path lpszPath2 onto lpszPath1
    34  *
    35  * FIXME
    36  *  the resulting path is also canonicalized
    37  */
    38 BOOL WINAPI PathAppendA(
    39         LPSTR lpszPath1,
    40         LPCSTR lpszPath2)
    41 {
    42         TRACE("%s %s\n",lpszPath1, lpszPath2);
    43         while (lpszPath2[0]=='\\') lpszPath2++;
    44         PathCombineA(lpszPath1,lpszPath1,lpszPath2);
    45         return TRUE;
    46 }
    47 
    48 /*************************************************************************
    49  * PathAppendW          [SHLWAPI.@]
    50  */
    51 BOOL WINAPI PathAppendW(
    52         LPWSTR lpszPath1,
    53         LPCWSTR lpszPath2)
    54 {
    55         TRACE("%s %s\n",debugstr_w(lpszPath1), debugstr_w(lpszPath2));
    56         while (lpszPath2[0]=='\\') lpszPath2++;
    57         PathCombineW(lpszPath1,lpszPath1,lpszPath2);
    58         return TRUE;
    59 }
    60 
    61 /*************************************************************************
    62  * PathCombineA         [SHLWAPI.@]
    63  *
     877 *  The path is not changed if it is invalid or has no spaces.
     878 */
     879VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath)
     880{
     881  TRACE("(%s)\n", debugstr_a(lpszPath));
     882
     883  if(lpszPath && StrChrA(lpszPath,' '))
     884  {
     885    int iLen = strlen(lpszPath) + 1;
     886
     887    if (iLen + 2 < MAX_PATH)
     888    {
     889      memmove(lpszPath + 1, lpszPath, iLen);
     890      lpszPath[0] = '"';
     891      lpszPath[iLen] = '"';
     892      lpszPath[iLen + 1] = '\0';
     893    }
     894  }
     895}
     896
     897/*************************************************************************
     898 * PathQuoteSpacesW [SHLWAPI.@]
     899 *
     900 * See PathQuoteSpacesA.
     901 */
     902VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
     903{
     904  TRACE("(%s)\n", debugstr_w(lpszPath));
     905
     906  if(lpszPath && StrChrW(lpszPath,' '))
     907  {
     908    int iLen = strlenW(lpszPath) + 1;
     909
     910    if (iLen + 2 < MAX_PATH)
     911    {
     912      memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR));
     913      lpszPath[0] = '"';
     914      lpszPath[iLen] = '"';
     915      lpszPath[iLen + 1] = '\0';
     916    }
     917  }
     918}
     919
     920/*************************************************************************
     921 * PathUnquoteSpacesA [SHLWAPI.@]
     922 *
     923 * Remove quotes ("") from around a path, if present.
     924 *
     925 * PARAMS
     926 *  lpszPath [O] Path to strip quotes from
     927 *
     928 * RETURNS
     929 *  Nothing
     930 *
    64931 * NOTES
    65  *  if lpszFile='.' skip it
    66  *  szDest can be equal to lpszFile. Thats why we use sTemp
    67  *
    68  * FIXME
    69  *  the resulting path is also canonicalized
    70  */
    71 LPSTR WINAPI PathCombineA(
    72         LPSTR szDest,
    73         LPCSTR lpszDir,
    74         LPCSTR lpszFile)
    75 {
    76         char sTemp[MAX_PATH];
    77         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, lpszDir, lpszFile, lpszFile);
    78        
    79        
    80         if (!lpszFile || !lpszFile[0] || (lpszFile[0]=='.' && !lpszFile[1]) )
    81         {
    82           strcpy(szDest,lpszDir);
    83           return szDest;
    84         }
    85 
    86         /*  if lpszFile is a complete path don't care about lpszDir */
    87         if (PathGetDriveNumberA(lpszFile) != -1)
    88         {
    89           strcpy(szDest,lpszFile);
    90         }
    91         else if (lpszFile[0] == '\\' )
    92         {
    93           strcpy(sTemp,lpszDir);
    94           PathStripToRootA(sTemp);
    95           strcat(sTemp,lpszFile);
    96           strcpy(szDest,sTemp);
    97         }
    98         else
    99         {
    100           strcpy(sTemp,lpszDir);
    101           PathAddBackslashA(sTemp);
    102           strcat(sTemp,lpszFile);
    103           strcpy(szDest,sTemp);
    104         }
    105         return szDest;
    106 }
    107 
    108 /*************************************************************************
    109  * PathCombineW          [SHLWAPI.@]
    110  */
    111 LPWSTR WINAPI PathCombineW(
    112         LPWSTR szDest,
    113         LPCWSTR lpszDir,
    114         LPCWSTR lpszFile)
    115 {
    116         WCHAR sTemp[MAX_PATH];
    117         TRACE("%p %p->%s %p->%s\n",szDest, lpszDir, debugstr_w(lpszDir),
    118                          lpszFile, debugstr_w(lpszFile));
    119        
    120        
    121         if (!lpszFile || !lpszFile[0] || (lpszFile[0]==(WCHAR)'.' && !lpszFile[1]) )
    122         {
    123           strcpyW(szDest,lpszDir);
    124           return szDest;
    125         }
    126 
    127         /*  if lpszFile is a complete path don't care about lpszDir */
    128         if (PathGetDriveNumberW(lpszFile) != -1)
    129         {
    130             strcpyW(szDest,lpszFile);
    131         }
    132         else if (lpszFile[0] == (WCHAR)'\\' )
    133         {
    134           strcpyW(sTemp,lpszDir);
    135           PathStripToRootW(sTemp);
    136           strcatW(sTemp,lpszFile);
    137           strcpyW(szDest,sTemp);
    138         }
    139         else
    140         {
    141           strcpyW(sTemp,lpszDir);
    142           PathAddBackslashW(sTemp);
    143           strcatW(sTemp,lpszFile);
    144           strcpyW(szDest,sTemp);
    145         }
    146         return szDest;
    147 }
    148 
    149 /*************************************************************************
    150  * PathAddBackslashA    [SHLWAPI.@]
     932 *  If the path contains a single quote only, an empty string will result.
     933 *  Otherwise quotes are only removed if they appear at the start and end
     934 *  of the path.
     935 */
     936VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath)
     937{
     938  TRACE("(%s)\n", debugstr_a(lpszPath));
     939
     940  if (lpszPath && *lpszPath == '"')
     941  {
     942    DWORD dwLen = strlen(lpszPath) - 1;
     943
     944    if (lpszPath[dwLen] == '"')
     945    {
     946      lpszPath[dwLen] = '\0';
     947      for (; *lpszPath; lpszPath++)
     948        *lpszPath = lpszPath[1];
     949    }
     950  }
     951}
     952
     953/*************************************************************************
     954 * PathUnquoteSpacesW [SHLWAPI.@]
     955 *
     956 * See PathUnquoteSpacesA.
     957 */
     958VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath)
     959{
     960  TRACE("(%s)\n", debugstr_w(lpszPath));
     961
     962  if (lpszPath && *lpszPath == '"')
     963  {
     964    DWORD dwLen = strlenW(lpszPath) - 1;
     965
     966    if (lpszPath[dwLen] == '"')
     967    {
     968      lpszPath[dwLen] = '\0';
     969      for (; *lpszPath; lpszPath++)
     970        *lpszPath = lpszPath[1];
     971    }
     972  }
     973}
     974
     975/*************************************************************************
     976 * PathParseIconLocationA  [SHLWAPI.@]
     977 *
     978 * Parse the location of an icon from a path.
     979 *
     980 * PARAMS
     981 *  lpszPath [O] The path to parse the icon location from.
     982 *
     983 * RETURNS
     984 *  Success: The number of the icon
     985 *  Failure: 0 if the path does not contain an icon location or is NULL
    151986 *
    152987 * NOTES
    153  *     append \ if there is none
    154  */
    155 LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath)
    156 {
    157         int len;
    158         TRACE("%p->%s\n",lpszPath,lpszPath);
    159 
    160         len = strlen(lpszPath);
    161         if (len && lpszPath[len-1]!='\\')
    162         {
    163           lpszPath[len]  = '\\';
    164           lpszPath[len+1]= 0x00;
    165           return lpszPath+len+1;
    166         }
    167         return lpszPath+len;
    168 }
    169 
    170 /*************************************************************************
    171  * PathAddBackslashW    [SHLWAPI.@]
    172  */
    173 LPWSTR WINAPI PathAddBackslashW(LPWSTR lpszPath)
    174 {
    175         int len;
    176         TRACE("%p->%s\n",lpszPath,debugstr_w(lpszPath));
    177 
    178         len = strlenW(lpszPath);
    179         if (len && lpszPath[len-1]!=(WCHAR)'\\')
    180         {
    181           lpszPath[len]  = (WCHAR)'\\';
    182           lpszPath[len+1]= 0x00;
    183           return lpszPath+len+1;
    184         }
    185         return lpszPath+len;
    186 }
    187 
    188 /*************************************************************************
    189  * PathBuildRootA               [SHLWAPI.@]
    190  */
    191 LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive)
    192 {
    193         TRACE("%p %i\n",lpszPath, drive);
    194 
    195         strcpy(lpszPath,"A:\\");
    196         lpszPath[0]+=drive;
    197         return lpszPath;
    198 }
    199 
    200 /*************************************************************************
    201  * PathBuildRootW               [SHLWAPI.@]
    202  */
    203 LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive)
    204 {
    205         lpszPath[0] = 'A' + drive;
    206         lpszPath[1] = ':';
    207         lpszPath[2] = '\\';
    208         lpszPath[3] = 0;
    209         TRACE("%p %i\n",debugstr_w(lpszPath), drive);
    210         return lpszPath;
    211 }
    212 
    213 /*
    214         Extracting Component Parts
    215 */
    216 
    217 /*************************************************************************
    218  * PathFindFileNameA    [SHLWAPI.@]
    219  */
    220 LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath)
    221 {
    222         LPCSTR lastSlash = lpszPath;
    223 
    224         TRACE("%s\n",lpszPath);
    225         while (*lpszPath)
    226         {
    227           if ( isSlash(lpszPath[0]) && lpszPath[1])
    228               lastSlash = lpszPath+1;
    229           lpszPath = CharNextA(lpszPath);
    230         }
    231         return (LPSTR)lastSlash;
    232 
    233 }
    234 
    235 /*************************************************************************
    236  * PathFindFileNameW    [SHLWAPI.@]
    237  */
    238 LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
    239 {
    240         LPCWSTR wslash;
    241         wslash = lpszPath;
    242 
    243         TRACE("%s\n",debugstr_w(wslash));
    244         while (lpszPath[0])
    245         {
    246           if (((lpszPath[0]=='\\') || (lpszPath[0]==':')) && lpszPath[1] && lpszPath[1]!='\\')
    247             wslash = lpszPath+1;
    248           lpszPath = CharNextW(lpszPath);
    249         }
    250         return (LPWSTR)wslash; 
    251 }
    252 
    253 /*************************************************************************
    254  * PathFindExtensionA   [SHLWAPI.@]
     988 *  The path has surrounding quotes and spaces removed regardless
     989 *  of whether the call succeeds or not.
     990 */
     991int WINAPI PathParseIconLocationA(LPSTR lpszPath)
     992{
     993  int iRet = 0;
     994  LPSTR lpszComma;
     995
     996  TRACE("(%s)\n", debugstr_a(lpszPath));
     997
     998  if (lpszPath)
     999  {
     1000    if ((lpszComma = strchr(lpszPath, ',')))
     1001    {
     1002      *lpszComma++ = '\0';
     1003      iRet = StrToIntA(lpszComma);
     1004    }
     1005    PathUnquoteSpacesA(lpszPath);
     1006    PathRemoveBlanksA(lpszPath);
     1007  }
     1008  return iRet;
     1009}
     1010
     1011/*************************************************************************
     1012 * PathParseIconLocationW  [SHLWAPI.@]
     1013 *
     1014 * See PathParseIconLocationA.
     1015 */
     1016int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
     1017{
     1018  int iRet = 0;
     1019  LPWSTR lpszComma;
     1020
     1021  TRACE("(%s)\n", debugstr_w(lpszPath));
     1022
     1023  if (lpszPath)
     1024  {
     1025    if ((lpszComma = StrChrW(lpszPath, ',')))
     1026    {
     1027      *lpszComma++ = '\0';
     1028      iRet = StrToIntW(lpszComma);
     1029    }
     1030    PathUnquoteSpacesW(lpszPath);
     1031    PathRemoveBlanksW(lpszPath);
     1032  }
     1033  return iRet;
     1034}
     1035
     1036/*************************************************************************
     1037 * SHLWAPI_PathFindLocalExeA
     1038 *
     1039 * Internal implementation of SHLWAPI_3.
     1040 */
     1041BOOL WINAPI SHLWAPI_PathFindLocalExeA (LPSTR lpszPath, DWORD dwWhich)
     1042{
     1043  BOOL bRet = FALSE;
     1044
     1045  TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich);
     1046
     1047  if (lpszPath)
     1048  {
     1049    WCHAR szPath[MAX_PATH];
     1050    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     1051    bRet = SHLWAPI_PathFindLocalExeW(szPath, dwWhich);
     1052    if (bRet)
     1053      WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
     1054  }
     1055  return bRet;
     1056}
     1057
     1058/*************************************************************************
     1059 * SHLWAPI_PathFindLocalExeW
     1060 *
     1061 * Internal implementation of SHLWAPI_4.
     1062 */
     1063BOOL WINAPI SHLWAPI_PathFindLocalExeW (LPWSTR lpszPath, DWORD dwWhich)
     1064{
     1065  static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', '0'},
     1066                                       { '.', 'c', 'o', 'm', '0'},
     1067                                       { '.', 'e', 'x', 'e', '0'},
     1068                                       { '.', 'b', 'a', 't', '0'},
     1069                                       { '.', 'l', 'n', 'k', '0'},
     1070                                       { '.', 'c', 'm', 'd', '0'},
     1071                                       { '0', '0', '0', '0', '0'} };
     1072
     1073  TRACE("(%s,%ld)\n", debugstr_w(lpszPath), dwWhich);
     1074
     1075  if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath))
     1076    return FALSE;
     1077
     1078  if (dwWhich)
     1079  {
     1080    LPCWSTR szExt = PathFindExtensionW(lpszPath);
     1081    if (!*szExt || dwWhich & 0x40)
     1082    {
     1083      int iChoose = 0;
     1084      int iLen = lstrlenW(lpszPath);
     1085      if (iLen > (MAX_PATH - 5))
     1086        return FALSE;
     1087      while (dwWhich & 0x1 && iChoose < sizeof(pszExts))
     1088      {
     1089        lstrcpyW(lpszPath + iLen, pszExts[iChoose]);
     1090        if (PathFileExistsW(lpszPath))
     1091          return TRUE;
     1092        iChoose++;
     1093        dwWhich >>= 1;
     1094      }
     1095      *(lpszPath + iLen) = (WCHAR)'\0';
     1096      return FALSE;
     1097    }
     1098  }
     1099  return PathFileExistsW(lpszPath);
     1100}
     1101
     1102/*************************************************************************
     1103 * SHLWAPI_PathFindInOtherDirs
     1104 *
     1105 * Internal helper for SHLWAPI_PathFindOnPathExA/W.
     1106 */
     1107static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich)
     1108{
     1109  static WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'};
     1110  static WCHAR szPath[] = { 'P','A','T','H','\0'};
     1111  DWORD dwLenPATH;
     1112  LPCWSTR lpszCurr;
     1113  WCHAR *lpszPATH;
     1114  WCHAR buff[MAX_PATH];
     1115
     1116  TRACE("(%s,%08lx)\n", debugstr_w(lpszFile), dwWhich);
     1117
     1118  /* Try system directories */
     1119  GetSystemDirectoryW(buff, MAX_PATH);
     1120  if (!PathAppendW(buff, lpszFile))
     1121     return FALSE;
     1122  if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1123  {
     1124    strcpyW(lpszFile, buff);
     1125    return TRUE;
     1126  }
     1127  GetWindowsDirectoryW(buff, MAX_PATH);
     1128  if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile))
     1129    return FALSE;
     1130  if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1131  {
     1132    strcpyW(lpszFile, buff);
     1133    return TRUE;
     1134  }
     1135  GetWindowsDirectoryW(buff, MAX_PATH);
     1136  if (!PathAppendW(buff, lpszFile))
     1137    return FALSE;
     1138  if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1139  {
     1140    strcpyW(lpszFile, buff);
     1141    return TRUE;
     1142  }
     1143  /* Try dirs listed in %PATH% */
     1144  dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH);
     1145
     1146  if (!dwLenPATH || !(lpszPATH = malloc((dwLenPATH + 1) * sizeof (WCHAR))))
     1147    return FALSE;
     1148
     1149  GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1);
     1150  lpszCurr = lpszPATH;
     1151  while (lpszCurr)
     1152  {
     1153    LPCWSTR lpszEnd = lpszCurr;
     1154    LPWSTR pBuff = buff;
     1155
     1156    while (*lpszEnd == ' ')
     1157      lpszEnd++;
     1158    while (*lpszEnd && *lpszEnd != ';')
     1159      *pBuff++ = *lpszEnd++;
     1160    *pBuff = '\0';
     1161
     1162    if (*lpszEnd)
     1163      lpszCurr = lpszEnd + 1;
     1164    else
     1165      lpszCurr = NULL; /* Last Path, terminate after this */
     1166
     1167    if (!PathAppendW(buff, lpszFile))
     1168      return FALSE;
     1169    if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1170    {
     1171      strcpyW(lpszFile, buff);
     1172      free(lpszPATH);
     1173      return TRUE;
     1174    }
     1175  }
     1176  free(lpszPATH);
     1177  return FALSE;
     1178}
     1179
     1180
     1181/*************************************************************************
     1182 * SHLWAPI_PathFindOnPathExA
     1183 *
     1184 * Internal implementation of SHLWAPI_5
     1185 */
     1186BOOL WINAPI SHLWAPI_PathFindOnPathExA(LPSTR lpszFile, LPCSTR *lppszOtherDirs, DWORD dwWhich)
     1187{
     1188  WCHAR szFile[MAX_PATH];
     1189  WCHAR buff[MAX_PATH];
     1190
     1191  TRACE("(%s,%p,%08lx)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich);
     1192
     1193  if (!lpszFile || !PathIsFileSpecA(lpszFile))
     1194    return FALSE;
     1195
     1196  MultiByteToWideChar(0,0,lpszFile,-1,szFile,MAX_PATH);
     1197
     1198  /* Search provided directories first */
     1199  if (lppszOtherDirs && *lppszOtherDirs)
     1200  {
     1201    WCHAR szOther[MAX_PATH];
     1202    LPCSTR *lpszOtherPath = lppszOtherDirs;
     1203
     1204    while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
     1205    {
     1206      MultiByteToWideChar(0,0,*lpszOtherPath,-1,szOther,MAX_PATH);
     1207      PathCombineW(buff, szOther, szFile);
     1208      if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1209      {
     1210        WideCharToMultiByte(0,0,buff,-1,lpszFile,MAX_PATH,0,0);
     1211        return TRUE;
     1212      }
     1213      lpszOtherPath++;
     1214    }
     1215  }
     1216  /* Not found, try system and path dirs */
     1217  if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich))
     1218  {
     1219    WideCharToMultiByte(0,0,szFile,-1,lpszFile,MAX_PATH,0,0);
     1220    return TRUE;
     1221  }
     1222  return FALSE;
     1223}
     1224
     1225/*************************************************************************
     1226 * SHLWAPI_PathFindOnPathExW
     1227 *
     1228 * Internal implementation of SHLWAPI_6.
     1229 */
     1230BOOL WINAPI SHLWAPI_PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD dwWhich)
     1231{
     1232  WCHAR buff[MAX_PATH];
     1233
     1234  TRACE("(%s,%p,%08lx)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich);
     1235
     1236  if (!lpszFile || !PathIsFileSpecW(lpszFile))
     1237    return FALSE;
     1238
     1239  /* Search provided directories first */
     1240  if (lppszOtherDirs && *lppszOtherDirs)
     1241  {
     1242    LPCWSTR *lpszOtherPath = lppszOtherDirs;
     1243    while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0])
     1244    {
     1245      PathCombineW(buff, *lpszOtherPath, lpszFile);
     1246      if (SHLWAPI_PathFindLocalExeW(buff, dwWhich))
     1247      {
     1248        strcpyW(lpszFile, buff);
     1249        return TRUE;
     1250      }
     1251      lpszOtherPath++;
     1252    }
     1253  }
     1254  /* Not found, try system and path dirs */
     1255  return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich);
     1256}
     1257
     1258/*************************************************************************
     1259 * PathFindOnPathA      [SHLWAPI.@]
     1260 *
     1261 * Search a range of paths for an executable.
     1262 *
     1263 * PARAMS
     1264 *  lpszFile       [O] File to search for
     1265 *  lppszOtherDirs [I] Other directories to look in
     1266 *
     1267 * RETURNS
     1268 *  Success: TRUE. The path to the executable is stored in lpszFile.
     1269 *  Failure: FALSE. The path to the executable is unchanged.
     1270 */
     1271BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs)
     1272{
     1273  TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs);
     1274  return SHLWAPI_PathFindOnPathExA(lpszFile, lppszOtherDirs, 0);
     1275 }
     1276
     1277/*************************************************************************
     1278 * PathFindOnPathW      [SHLWAPI.@]
     1279 *
     1280 * See PathFindOnPathA.
     1281 */
     1282BOOL WINAPI PathFindOnPathW (LPWSTR lpszFile, LPCWSTR *lppszOtherDirs)
     1283{
     1284  TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs);
     1285  return SHLWAPI_PathFindOnPathExW(lpszFile,lppszOtherDirs, 0);
     1286}
     1287
     1288/*************************************************************************
     1289 * PathCompactPathExA   [SHLWAPI.@]
     1290 *
     1291 * Compact a path.
     1292 *
     1293 * PARAMS
     1294 *  lpszDest [O] Destination for compacted path
     1295 *  lpszPath [I] Source path
     1296 *  cchMax   [I[ Size of lpszDest
     1297 *  dwFlags  [I] Compaction flags
     1298 *
     1299 * RETURNS
     1300 *  FIXME
     1301 */
     1302BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath,
     1303                               UINT cchMax, DWORD dwFlags)
     1304{
     1305  BOOL bRet = FALSE;
     1306
     1307  TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags);
     1308
     1309  if (lpszPath && lpszDest)
     1310  {
     1311    WCHAR szPath[MAX_PATH];
     1312    WCHAR szDest[MAX_PATH];
     1313
     1314    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     1315    szDest[0] = '\0';
     1316    bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags);
     1317    WideCharToMultiByte(0,0,szDest,-1,lpszDest,MAX_PATH,0,0);
     1318  }
     1319  return bRet;
     1320}
     1321
     1322/*************************************************************************
     1323 * PathCompactPathExW   [SHLWAPI.@]
     1324 *
     1325 * See PathCompactPathExA.
     1326 */
     1327BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath,
     1328                               UINT cchMax, DWORD dwFlags)
     1329{
     1330  FIXME("(%p,%s,%d,0x%08lx)-stub\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags);
     1331
     1332  if (!lpszPath)
     1333    return FALSE;
     1334
     1335  if (!lpszDest)
     1336  {
     1337    WARN("Invalid lpszDest would crash under Win32!\n");
     1338    return FALSE;
     1339  }
     1340
     1341  /* FIXME */
     1342
     1343  return FALSE;
     1344}
     1345
     1346/*************************************************************************
     1347 * PathIsRelativeA      [SHLWAPI.@]
     1348 *
     1349 * Determine if a path is a relative path.
     1350 *
     1351 * PARAMS
     1352 *  lpszPath [I] Path to check
     1353 *
     1354 * RETURNS
     1355 *  TRUE:  The path is relative, or is invalid.
     1356 *  FALSE: The path is not relative.
     1357 */
     1358BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
     1359{
     1360  TRACE("(%s)\n",debugstr_a(lpszPath));
     1361
     1362  if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath))
     1363    return TRUE;
     1364  if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
     1365    return FALSE;
     1366  return TRUE;
     1367}
     1368
     1369/*************************************************************************
     1370 *  PathIsRelativeW     [SHLWAPI.@]
     1371 *
     1372 * See PathIsRelativeA.
     1373 */
     1374BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
     1375{
     1376  TRACE("(%s)\n",debugstr_w(lpszPath));
     1377
     1378  if (!lpszPath || !*lpszPath)
     1379    return TRUE;
     1380  if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':'))
     1381    return FALSE;
     1382  return TRUE;
     1383}
     1384
     1385/*************************************************************************
     1386 * PathIsRootA          [SHLWAPI.@]
     1387 *
     1388 * Determine if a path is a root path.
     1389 *
     1390 * PARAMS
     1391 *  lpszPath [I] Path to check
     1392 *
     1393 * RETURNS
     1394 *  TRUE  If lpszPath is valid and a root path
     1395 *  FALSE Otherwise
     1396 */
     1397BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
     1398{
     1399  TRACE("(%s)\n", debugstr_a(lpszPath));
     1400
     1401  if (lpszPath && *lpszPath)
     1402  {
     1403    if (*lpszPath == '\\')
     1404    {
     1405      if (!lpszPath[1])
     1406        return TRUE; /* \ */
     1407      else if (lpszPath[1]=='\\')
     1408      {
     1409        BOOL bSeenSlash = FALSE;
     1410        lpszPath += 2;
     1411
     1412        /* Check for UNC root path */
     1413        while (*lpszPath)
     1414        {
     1415          if (*lpszPath == '\\')
     1416          {
     1417            if (bSeenSlash)
     1418              return FALSE;
     1419            bSeenSlash = TRUE;
     1420          }
     1421          lpszPath = CharNextA(lpszPath);
     1422        }
     1423        return TRUE;
     1424      }
     1425    }
     1426    else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
     1427      return TRUE; /* X:\ */
     1428  }
     1429  return FALSE;
     1430}
     1431
     1432/*************************************************************************
     1433 * PathIsRootW          [SHLWAPI.@]
     1434 *
     1435 * See PathIsRootA.
     1436 */
     1437BOOL WINAPI PathIsRootW(LPCWSTR lpszPath)
     1438{
     1439  TRACE("(%s)\n", debugstr_w(lpszPath));
     1440
     1441  if (lpszPath && *lpszPath)
     1442  {
     1443    if (*lpszPath == '\\')
     1444    {
     1445      if (!lpszPath[1])
     1446        return TRUE; /* \ */
     1447      else if (lpszPath[1]=='\\')
     1448      {
     1449        BOOL bSeenSlash = FALSE;
     1450        lpszPath += 2;
     1451
     1452        /* Check for UNC root path */
     1453        while (*lpszPath)
     1454        {
     1455          if (*lpszPath == '\\')
     1456          {
     1457            if (bSeenSlash)
     1458              return FALSE;
     1459            bSeenSlash = TRUE;
     1460          }
     1461          lpszPath = CharNextW(lpszPath);
     1462        }
     1463        return TRUE;
     1464      }
     1465    }
     1466    else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
     1467      return TRUE; /* X:\ */
     1468  }
     1469  return FALSE;
     1470}
     1471
     1472/*************************************************************************
     1473 * PathIsDirectoryA     [SHLWAPI.@]
     1474 *
     1475 * Determine if a path is a valid directory
     1476 *
     1477 * PARAMS
     1478 *  lpszPath [I] Path to check.
     1479 *
     1480 * RETURNS
     1481 *  FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes)
     1482 *  FALSE if lpszPath is invalid or not a directory.
    2551483 *
    2561484 * NOTES
    257  *     returns pointer to last . in last lpszPath component or at \0.
    258  */
    259 
    260 LPSTR WINAPI PathFindExtensionA(LPCSTR lpszPath)
    261 {
    262         LPCSTR   lastpoint = NULL;
    263 
    264         TRACE("%p %s\n",lpszPath,lpszPath);
    265 
    266         while (*lpszPath)
    267         {
    268           if (*lpszPath=='\\'||*lpszPath==' ')
    269             lastpoint=NULL;
    270           if (*lpszPath=='.')
    271             lastpoint=lpszPath;
    272           lpszPath = CharNextA(lpszPath);
    273         }
    274         return (LPSTR)(lastpoint?lastpoint:lpszPath);
    275 }
    276 
    277 /*************************************************************************
    278  * PathFindExtensionW   [SHLWAPI.@]
    279  */
    280 LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
    281 {
    282         LPCWSTR   lastpoint = NULL;
    283 
    284         TRACE("(%p %s)\n",lpszPath,debugstr_w(lpszPath));
    285 
    286         while (*lpszPath)
    287         {
    288           if (*lpszPath==(WCHAR)'\\'||*lpszPath==(WCHAR)' ')
    289             lastpoint=NULL;
    290           if (*lpszPath==(WCHAR)'.')
    291             lastpoint=lpszPath;
    292           lpszPath = CharNextW(lpszPath);
    293         }
    294         return (LPWSTR)(lastpoint?lastpoint:lpszPath);
    295 }
    296 
    297 /*************************************************************************
    298  * PathGetArgsA         [SHLWAPI.@]
    299  *
    300  * NOTES
    301  *     look for next arg in string. handle "quoted" strings
    302  *     returns pointer to argument *AFTER* the space. Or to the \0.
    303  *
    304  * FIXME
    305  *     quoting by '\'
    306  */
    307 LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath)
    308 {
    309         BOOL    qflag = FALSE;
    310 
    311         TRACE("%s\n",lpszPath);
    312 
    313         while (*lpszPath)
    314         {
    315           if ((*lpszPath==' ') && !qflag)
    316             return (LPSTR)lpszPath+1;
    317           if (*lpszPath=='"')
    318             qflag=!qflag;
    319           lpszPath = CharNextA(lpszPath);
    320         }
    321         return (LPSTR)lpszPath;
    322 }
    323 
    324 /*************************************************************************
    325  * PathGetArgsW         [SHLWAPI.@]
    326  */
    327 LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath)
    328 {
    329         BOOL    qflag = FALSE;
    330 
    331         TRACE("%s\n",debugstr_w(lpszPath));
    332 
    333         while (*lpszPath)
    334         {
    335           if ((*lpszPath==' ') && !qflag)
    336             return (LPWSTR)lpszPath+1;
    337           if (*lpszPath=='"')
    338             qflag=!qflag;
    339           lpszPath = CharNextW(lpszPath);
    340         }
    341         return (LPWSTR)lpszPath;
    342 }
    343 
    344 /*************************************************************************
    345  * PathGetDriveNumberA  [SHLWAPI.@]
    346  */
    347 int WINAPI PathGetDriveNumberA(LPCSTR lpszPath)
    348 {
    349         int chr = tolower(lpszPath[0]);
    350        
    351         TRACE ("%s\n",debugstr_a(lpszPath));
    352 
    353         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
    354         return tolower(lpszPath[0]) - 'a' ;
    355 }
    356 
    357 /*************************************************************************
    358  * PathGetDriveNumberW  [SHLWAPI.@]
    359  */
    360 int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath)
    361 {
    362         int chr = tolowerW(lpszPath[0]);
    363        
    364         TRACE ("%s\n",debugstr_w(lpszPath));
    365 
    366         if (!lpszPath || lpszPath[1]!=':' || chr < 'a' || chr > 'z') return -1;
    367         return tolowerW(lpszPath[0]) - 'a' ;
    368 }
    369 
    370 /*************************************************************************
    371  * PathRemoveFileSpecA  [SHLWAPI.@]
    372  *
    373  * NOTES
    374  *     truncates passed argument to a valid path
    375  *     returns if the string was modified or not.
    376  *     "\foo\xx\foo"-> "\foo\xx"
    377  *     "\" -> "\"
    378  *     "a:\foo" -> "a:\"
    379  */
    380 BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath)
    381 {
    382         LPSTR cutplace = lpszPath;
    383         BOOL ret = FALSE;
    384        
    385         TRACE("%s\n",lpszPath);
    386 
    387         if(lpszPath)
    388         {
    389           while (*lpszPath == '\\') cutplace = ++lpszPath;
    390          
    391           while (*lpszPath)
    392           {
    393             if(lpszPath[0] == '\\') cutplace = lpszPath;
    394          
    395             if(lpszPath[0] == ':')
    396             {
    397               cutplace = lpszPath + 1;
    398               if (lpszPath[1] == '\\') cutplace++;
    399               lpszPath++;
    400             }
    401             lpszPath = CharNextA(lpszPath);
    402             if (!lpszPath) break;
    403           }
    404          
    405           ret = (*cutplace!='\0');
    406           *cutplace = '\0';
    407         }
    408         return ret;
    409 }
    410 
    411 /*************************************************************************
    412  * PathRemoveFileSpecW  [SHLWAPI.@]
    413  */
    414 BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
    415 {
    416         LPWSTR cutplace = lpszPath;
    417         BOOL ret = FALSE;
    418 
    419         TRACE("%s\n",debugstr_w(lpszPath));
    420 
    421         if(lpszPath)
    422         {
    423           while (*lpszPath == '\\') cutplace = ++lpszPath;
    424          
    425           while (*lpszPath)
    426           {
    427             if(lpszPath[0] == '\\') cutplace = lpszPath;
    428          
    429             if(lpszPath[0] == ':')
    430             {
    431               cutplace = lpszPath + 1;
    432               if (lpszPath[1] == '\\') cutplace++;
    433               lpszPath++;
    434             }
    435             lpszPath = CharNextW(lpszPath);
    436             if (!lpszPath) break;
    437           }
    438          
    439           ret = (*cutplace!='\0');
    440           *cutplace = '\0';
    441         }
    442         return ret;
    443 }
    444 
    445 /*************************************************************************
    446  * PathStripPathA       [SHLWAPI.@]
    447  *
    448  * NOTES
    449  *  removes the path from the beginning of a filename
    450  */
    451 void WINAPI PathStripPathA(LPSTR lpszPath)
    452 {
    453         LPSTR lpszFileName = PathFindFileNameA(lpszPath);
    454 
    455         TRACE("%s\n", lpszPath);
    456 
    457         if(lpszFileName)
    458           RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1);
    459 }
    460 
    461 /*************************************************************************
    462  * PathStripPathW       [SHLWAPI.@]
    463  */
    464 void WINAPI PathStripPathW(LPWSTR lpszPath)
    465 {
    466         LPWSTR lpszFileName = PathFindFileNameW(lpszPath);
    467 
    468         TRACE("%s\n", debugstr_w(lpszPath));
    469         if(lpszFileName)
    470           RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR));
    471 }
    472 
    473 /*************************************************************************
    474  * PathStripToRootA     [SHLWAPI.@]
    475  */
    476 BOOL WINAPI PathStripToRootA(LPSTR lpszPath)
    477 {
    478         TRACE("%s\n", lpszPath);
    479 
    480         if (!lpszPath) return FALSE;
    481         while(!PathIsRootA(lpszPath))
    482           if (!PathRemoveFileSpecA(lpszPath)) return FALSE;
    483         return TRUE;
    484 }
    485 
    486 /*************************************************************************
    487  * PathStripToRootW     [SHLWAPI.@]
    488  */
    489 BOOL WINAPI PathStripToRootW(LPWSTR lpszPath)
    490 {
    491         TRACE("%s\n", debugstr_w(lpszPath));
    492 
    493         if (!lpszPath) return FALSE;
    494         while(!PathIsRootW(lpszPath))
    495           if (!PathRemoveFileSpecW(lpszPath)) return FALSE;
    496         return TRUE;
    497 }
    498 
    499 /*************************************************************************
    500  * PathRemoveArgsA      [SHLWAPI.@]
    501  *
    502  */
    503 void WINAPI PathRemoveArgsA(LPSTR lpszPath)
    504 {
    505         TRACE("%s\n",lpszPath);
    506        
    507         if(lpszPath)
    508         {
    509           LPSTR lpszArgs = PathGetArgsA(lpszPath);
    510           if (!*lpszArgs)
    511           {
    512             LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs);
    513             if(*lpszLastChar==' ') *lpszLastChar = '\0';
    514           }
    515         }
    516 }
    517 
    518 /*************************************************************************
    519  * PathRemoveArgsW      [SHLWAPI.@]
    520  */
    521 void WINAPI PathRemoveArgsW(LPWSTR lpszPath)
    522 {
    523         TRACE("%s\n", debugstr_w(lpszPath));
    524 
    525         if(lpszPath)
    526         {
    527           LPWSTR lpszArgs = PathGetArgsW(lpszPath);
    528           if (!*lpszArgs)
    529           {
    530             LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs);
    531             if(*lpszLastChar==' ') *lpszLastChar = '\0';
    532           }
    533         }
    534 }
    535 
    536 /*************************************************************************
    537  * PathRemoveExtensionA         [SHLWAPI.@]
    538  */
    539 void WINAPI PathRemoveExtensionA(LPSTR lpszPath)
    540 {
    541         LPSTR lpszExtension = PathFindExtensionA(lpszPath);
    542 
    543         TRACE("%s\n", lpszPath);
    544 
    545         if (lpszExtension) *lpszExtension='\0';
    546 }
    547 
    548 /*************************************************************************
    549  * PathRemoveExtensionW         [SHLWAPI.@]
    550  */
    551 void WINAPI PathRemoveExtensionW(LPWSTR lpszPath)
    552 {
    553         LPWSTR lpszExtension = PathFindExtensionW(lpszPath);
    554 
    555         TRACE("%s\n", debugstr_w(lpszPath));
    556 
    557         if (lpszExtension) *lpszExtension='\0';
    558 }
    559 
    560 /*************************************************************************
    561  * PathRemoveBackslashA [SHLWAPI.@]
    562  *
    563  * If the path ends in a backslash it is replaced by a NULL
    564  * and the address of the NULL is returned
    565  * Otherwise
    566  * the address of the last character is returned.
    567  *
    568  * FIXME
    569  *  "c:\": keep backslash
    570  */
    571 LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath )
    572 {
    573         int len;
    574         LPSTR szTemp = NULL;
    575        
    576         if(lpszPath)
    577         {
    578           len = strlen(lpszPath);
    579           szTemp = CharPrevA(lpszPath, lpszPath+len);
    580           if (! PathIsRootA(lpszPath))
    581           {
    582             if (*szTemp == '\\') *szTemp = '\0';
    583           }
    584         }
    585         return szTemp;
    586 }
    587 
    588 /*************************************************************************
    589  * PathRemoveBackslashW [SHLWAPI.@]
    590  */
    591 LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath )
    592 {
    593         int len;
    594         LPWSTR szTemp = NULL;
    595        
    596         if(lpszPath)
    597         {
    598           len = strlenW(lpszPath);
    599           szTemp = CharPrevW(lpszPath, lpszPath+len);
    600           if (! PathIsRootW(lpszPath))
    601           {
    602             if (*szTemp == '\\') *szTemp = '\0';
    603           }
    604         }
    605         return szTemp;
    606 }
    607 
    608 
    609 /*
    610         Path Manipulations
    611 */
    612 
    613 /*************************************************************************
    614  * PathRemoveBlanksA [SHLWAPI.@]
    615  *
    616  * NOTES
    617  *     remove spaces from beginning and end of passed string
    618  */
    619 void WINAPI PathRemoveBlanksA(LPSTR str)
    620 {
    621         LPSTR x = str;
    622 
    623         TRACE("%s\n",str);
    624 
    625         if(str)
    626         {
    627           while (*x==' ') x = CharNextA(x);
    628           if (x!=str) strcpy(str,x);
    629           x=str+strlen(str)-1;
    630           while (*x==' ') x = CharPrevA(str, x);
    631           if (*x==' ') *x='\0';
    632         }
    633 }
    634 
    635 /*************************************************************************
    636  * PathRemoveBlanksW [SHLWAPI.@]
    637  */
    638 void WINAPI PathRemoveBlanksW(LPWSTR str)
    639 {
    640         LPWSTR x = str;
    641 
    642         TRACE("%s\n",debugstr_w(str));
    643 
    644         if(str)
    645         {
    646           while (*x==' ') x = CharNextW(x);
    647           if (x!=str) strcpyW(str,x);
    648           x=str+strlenW(str)-1;
    649           while (*x==' ') x = CharPrevW(str, x);
    650           if (*x==' ') *x='\0';
    651         }
    652 }
    653 
    654 /*************************************************************************
    655  * PathQuoteSpacesA [SHLWAPI.@]
    656  *
    657  */
    658 LPSTR WINAPI PathQuoteSpacesA(LPSTR lpszPath)
    659 {
    660         TRACE("%s\n",lpszPath);
    661 
    662         if(StrChrA(lpszPath,' '))
    663         {
    664           int len = strlen(lpszPath);
    665           RtlMoveMemory(lpszPath+1, lpszPath, len);
    666           *(lpszPath++) = '"';
    667           lpszPath += len;
    668           *(lpszPath++) = '"';
    669           *(lpszPath) = '\0';
    670           return --lpszPath;
    671         }
    672         return 0;
    673 }
    674 
    675 /*************************************************************************
    676  * PathQuoteSpacesW [SHLWAPI.@]
    677  */
    678 LPWSTR WINAPI PathQuoteSpacesW(LPWSTR lpszPath)
    679 {
    680         TRACE("%s\n",debugstr_w(lpszPath));
    681 
    682         if(StrChrW(lpszPath,' '))
    683         {
    684           int len = strlenW(lpszPath);
    685           RtlMoveMemory(lpszPath+1, lpszPath, len*sizeof(WCHAR));
    686           *(lpszPath++) = '"';
    687           lpszPath += len;
    688           *(lpszPath++) = '"';
    689           *(lpszPath) = '\0';
    690           return --lpszPath;
    691         }
    692         return 0;
    693 }
    694 
    695 /*************************************************************************
    696  * PathUnquoteSpacesA [SHLWAPI.@]
    697  *
    698  * NOTES
    699  *     unquote string (remove ")
    700  */
    701 VOID WINAPI PathUnquoteSpacesA(LPSTR str)
    702 {
    703         DWORD len = strlen(str);
    704 
    705         TRACE("%s\n",str);
    706 
    707         if (*str!='"')
    708           return;
    709         if (str[len-1]!='"')
    710           return;
    711         str[len-1]='\0';
    712         strcpy(str,str+1);
    713         return;
    714 }
    715 
    716 /*************************************************************************
    717  * PathUnquoteSpacesW [SHLWAPI.@]
    718  */
    719 VOID WINAPI PathUnquoteSpacesW(LPWSTR str)
    720 {
    721         DWORD len = strlenW(str);
    722 
    723         TRACE("%s\n",debugstr_w(str));
    724 
    725         if (*str!='"')
    726           return;
    727         if (str[len-1]!='"')
    728           return;
    729         str[len-1]='\0';
    730         strcpyW(str,str+1);
    731         return;
    732 }
    733 
    734 /*************************************************************************
    735  * PathParseIconLocationA       [SHLWAPI.@]
    736  */
    737 int WINAPI PathParseIconLocationA(LPSTR lpszPath)
    738 {
    739         LPSTR lpstrComma = strchr(lpszPath, ',');
    740         int ret = 0;
    741        
    742         TRACE("%s\n", debugstr_a(lpszPath));
    743 
    744         if (lpstrComma && lpstrComma[1])
    745         {
    746           lpstrComma[0]='\0';
    747           ret = atoi(&lpstrComma[1]);
    748         }
    749        
    750         PathUnquoteSpacesA(lpszPath);
    751         return ret;
    752 }
    753 
    754 /*************************************************************************
    755  * PathParseIconLocationW       [SHLWAPI.@]
    756  */
    757 int WINAPI PathParseIconLocationW(LPWSTR lpszPath)
    758 {
    759         LPWSTR lpstrComma = strchrW(lpszPath, ',');
    760         int ret = 0;
    761        
    762         TRACE("%s\n", debugstr_w(lpszPath));
    763 
    764         if (lpstrComma && lpstrComma[1])
    765         {
    766           lpstrComma[0]='\0';
    767           ret = _wtoi(&lpstrComma[1]);
    768         }
    769         PathUnquoteSpacesW(lpszPath);
    770         return ret;
    771 }
    772 
    773 /*
    774         ########## cleaning and resolving paths ##########
    775  */
    776 
    777 /*************************************************************************
    778  * PathFindOnPathA      [SHLWAPI.@]
    779  */
    780 BOOL WINAPI PathFindOnPathA(LPSTR sFile, LPCSTR *sOtherDirs)
    781 {
    782         FIXME("%s %p\n",sFile, sOtherDirs);
    783         return FALSE;
    784 }
    785 
    786 /*************************************************************************
    787  * PathFindOnPathW      [SHLWAPI.@]
    788  */
    789 BOOL WINAPI PathFindOnPathW(LPWSTR sFile, LPCWSTR *sOtherDirs)
    790 {
    791         FIXME("%s %p\n",debugstr_w(sFile), sOtherDirs);
    792         return FALSE;
    793 }
    794 
    795 /*************************************************************************
    796  *      PathCompactPathExA   [SHLWAPI.@]
    797  */
    798 BOOL WINAPI PathCompactPathExA(
    799         LPSTR pszOut,
    800         LPCSTR pszSrc,
    801         UINT cchMax,
    802         DWORD dwFlags)
    803 {
    804         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, pszSrc, cchMax, dwFlags);
    805         return FALSE;
    806 }
    807 
    808 /*************************************************************************
    809  *      PathCompactPathExW   [SHLWAPI.@]
    810  */
    811 BOOL WINAPI PathCompactPathExW(
    812         LPWSTR pszOut,
    813         LPCWSTR pszSrc,
    814         UINT cchMax,
    815         DWORD dwFlags)
    816 {
    817         FIXME("%p %s 0x%08x 0x%08lx\n", pszOut, debugstr_w(pszSrc), cchMax, dwFlags);
    818         return FALSE;
    819 }
    820 
    821 /*
    822         ########## Path Testing ##########
    823 */
    824 
    825 /*************************************************************************
    826  * PathIsUNCA           [SHLWAPI.@]
    827  *
    828  * NOTES
    829  *     PathIsUNC(char*path);
    830  */
    831 BOOL WINAPI PathIsUNCA(LPCSTR lpszPath)
    832 {
    833         TRACE("%s\n",lpszPath);
    834 
    835         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
    836 }
    837 
    838 /*************************************************************************
    839  * PathIsUNCW           [SHLWAPI.@]
    840  */
    841 BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath)
    842 {
    843         TRACE("%s\n",debugstr_w(lpszPath));
    844 
    845         return (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'));
    846 }
    847 
    848 /*************************************************************************
    849  *  PathIsRelativeA     [SHLWAPI.@]
    850  */
    851 BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath)
    852 {
    853         TRACE("lpszPath=%s\n",lpszPath);
    854 
    855         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
    856 }
    857 
    858 /*************************************************************************
    859  *  PathIsRelativeW     [SHLWAPI.@]
    860  */
    861 BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath)
    862 {
    863         TRACE("lpszPath=%s\n",debugstr_w(lpszPath));
    864 
    865         return (lpszPath && (lpszPath[0]!='\\' && lpszPath[1]!=':'));
    866 }
    867 
    868 /*************************************************************************
    869  * PathIsRootA          [SHLWAPI.@]
    870  *
    871  * notes
    872  *  TRUE if the path points to a root directory
    873  */
    874 BOOL WINAPI PathIsRootA(LPCSTR lpszPath)
    875 {
    876         TRACE("%s\n",lpszPath);
    877 
    878         /* X:\ */
    879         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
    880           return TRUE;
    881 
    882         /* "\" */
    883         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
    884           return TRUE;
    885 
    886         /* UNC "\\<computer>\<share>" */
    887         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    888         {
    889           int foundbackslash = 0;
    890           lpszPath += 2;
    891           while (*lpszPath)
    892           {
    893             if (*lpszPath=='\\') foundbackslash++;
    894             lpszPath = CharNextA(lpszPath);
    895           }
    896           if (foundbackslash <= 1)
    897             return TRUE;
    898         }
    899         return FALSE;
    900 }
    901 
    902 /*************************************************************************
    903  * PathIsRootW          [SHLWAPI.@]
    904  */
    905 BOOL WINAPI PathIsRootW(LPCWSTR lpszPath)
    906 {
    907         TRACE("%s\n",debugstr_w(lpszPath));
    908 
    909         /* X:\ */
    910         if (lpszPath[1]==':' && lpszPath[2]=='\\' && lpszPath[3]=='\0')
    911           return TRUE;
    912 
    913         /* "\" */
    914         if (lpszPath[0]=='\\' && lpszPath[1]=='\0')
    915           return TRUE;
    916 
    917         /* UNC "\\<computer>\<share>" */
    918         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    919         {
    920           int foundbackslash = 0;
    921           lpszPath += 2;
    922           while (*lpszPath)
    923           {
    924             if (*lpszPath=='\\') foundbackslash++;
    925             lpszPath = CharNextW(lpszPath);
    926           }
    927           if (foundbackslash <= 1)
    928             return TRUE;
    929         }
    930         return FALSE;
    931 
    932 }
    933 
    934 /*************************************************************************
    935  * PathIsDirectoryA     [SHLWAPI.@]
     1485 *  Although this function is prototyped as returning a BOOL, it returns
     1486 *  FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as:
     1487 *
     1488 *  if (PathIsDirectoryA("c:\\windows\\") == TRUE)
     1489 *    ...
     1490 *
     1491 *  will always fail.
    9361492 */
    9371493BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath)
    9381494{
    939         DWORD dwAttr;
    940 
    941         TRACE("%s\n", debugstr_a(lpszPath));
    942 
    943         dwAttr = GetFileAttributesA(lpszPath);
    944         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
     1495  DWORD dwAttr;
     1496
     1497  TRACE("(%s)\n", debugstr_a(lpszPath));
     1498
     1499  if (!lpszPath || PathIsUNCServerA(lpszPath))
     1500    return FALSE;
     1501
     1502 if (PathIsUNCServerShareA(lpszPath))
     1503 {
     1504   FIXME("UNC Server Share not yet supported - FAILING\n");
     1505   return FALSE;
     1506 }
     1507
     1508  if ((dwAttr = GetFileAttributesA(lpszPath)) == -1)
     1509    return FALSE;
     1510  return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
    9451511}
    9461512
    9471513/*************************************************************************
    9481514 * PathIsDirectoryW     [SHLWAPI.@]
     1515 *
     1516 * See PathIsDirectoryA.
    9491517 */
    9501518BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
    9511519{
    952         DWORD dwAttr;
    953        
    954         TRACE("%s\n", debugstr_w(lpszPath));
    955 
    956         dwAttr = GetFileAttributesW(lpszPath);
    957         return  (dwAttr != -1) ? dwAttr & FILE_ATTRIBUTE_DIRECTORY : 0;
     1520  DWORD dwAttr;
     1521
     1522  TRACE("(%s)\n", debugstr_w(lpszPath));
     1523
     1524  if (!lpszPath || PathIsUNCServerW(lpszPath))
     1525    return FALSE;
     1526
     1527 if (PathIsUNCServerShareW(lpszPath))
     1528 {
     1529   FIXME("UNC Server Share not yet supported - FAILING\n");
     1530   return FALSE;
     1531 }
     1532
     1533  if ((dwAttr = GetFileAttributesW(lpszPath)) == -1)
     1534    return FALSE;
     1535  return dwAttr & FILE_ATTRIBUTE_DIRECTORY;
    9581536}
    9591537
    9601538/*************************************************************************
    9611539 * PathFileExistsA      [SHLWAPI.@]
    962  *
    963  * NOTES
    964  *     file_exists(char *fn);
    965  */
    966 BOOL WINAPI PathFileExistsA(LPCSTR lpszPath)
    967 {
    968         TRACE("%s\n",lpszPath);
    969         return  (GetFileAttributesA(lpszPath)!=-1);
     1540 *
     1541 * Determine if a file exists.
     1542 *
     1543 * PARAMS
     1544 *  lpszPath [I] Path to check
     1545 *
     1546 * RETURNS
     1547 *  TRUE  If the file exists and is readable
     1548 *  FALSE Otherwise
     1549 */
     1550BOOL WINAPI PathFileExistsA(LPCSTR lpszPath)
     1551{
     1552  UINT iPrevErrMode;
     1553  DWORD dwAttr;
     1554
     1555  TRACE("(%s)\n",debugstr_a(lpszPath));
     1556
     1557  if (!lpszPath)
     1558    return FALSE;
     1559
     1560  iPrevErrMode = SetErrorMode(1);
     1561  dwAttr = GetFileAttributesA(lpszPath);
     1562  SetErrorMode(iPrevErrMode);
     1563  return dwAttr == -1 ? FALSE : TRUE;
    9701564}
    9711565
    9721566/*************************************************************************
    9731567 * PathFileExistsW      [SHLWAPI.@]
    974  */
    975 BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
    976 {
    977         TRACE("%s\n",debugstr_w(lpszPath));
    978         return  (GetFileAttributesW(lpszPath)!=-1);
     1568 *
     1569 * See PathFileExistsA
     1570 */
     1571BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
     1572{
     1573  UINT iPrevErrMode;
     1574  DWORD dwAttr;
     1575
     1576  TRACE("(%s)\n",debugstr_w(lpszPath));
     1577
     1578  if (!lpszPath)
     1579    return FALSE;
     1580
     1581  iPrevErrMode = SetErrorMode(1);
     1582  dwAttr = GetFileAttributesW(lpszPath);
     1583  SetErrorMode(iPrevErrMode);
     1584  return dwAttr == -1 ? FALSE : TRUE;
    9791585}
    9801586
    9811587/*************************************************************************
    9821588 * PathMatchSingleMaskA [internal]
    983  * 
     1589 *
    9841590 * NOTES
    9851591 *     internal (used by PathMatchSpec)
     
    9871593static BOOL PathMatchSingleMaskA(LPCSTR name, LPCSTR mask)
    9881594{
    989         while (*name && *mask && *mask!=';') 
     1595        while (*name && *mask && *mask!=';')
    9901596        {
    991           if (*mask=='*') 
     1597          if (*mask=='*')
    9921598          {
    993             do 
     1599            do
    9941600            {
    9951601              if (PathMatchSingleMaskA(name,mask+1)) return 1;  /* try substrings */
     
    10011607          mask = CharNextA(mask);
    10021608        }
    1003         if (!*name) 
     1609        if (!*name)
    10041610        {
    10051611          while (*mask=='*') mask++;
     
    10141620static BOOL PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask)
    10151621{
    1016         while (*name && *mask && *mask!=';') 
     1622        while (*name && *mask && *mask!=';')
    10171623        {
    1018           if (*mask=='*') 
     1624          if (*mask=='*')
    10191625          {
    1020             do 
     1626            do
    10211627            {
    10221628              if (PathMatchSingleMaskW(name,mask+1)) return 1;  /* try substrings */
     
    10281634          mask = CharNextW(mask);
    10291635        }
    1030         if (!*name) 
     1636        if (!*name)
    10311637        {
    10321638          while (*mask=='*') mask++;
     
    10351641        return 0;
    10361642}
     1643
    10371644/*************************************************************************
    10381645 * PathMatchSpecA       [SHLWAPI.@]
    1039  *
     1646 *
     1647 * Determine if a path matches one or more search masks.
     1648 *
     1649 * PARAMS
     1650 *  lpszPath [I] Path to check
     1651 *  lpszMask [I} Search mask(s)
     1652 *
     1653 * RETURNS
     1654 *  TRUE  If lpszPath is valid and is matched
     1655 *  FALSE Otherwise
     1656 *
    10401657 * NOTES
    1041  *     used from COMDLG32
    1042  */
    1043 BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask)
     1658 *  Multiple search masks may be given if they are seperated by ";". The
     1659 *  pattern "*.*" is treated specially in that it matches all paths (for
     1660 *  backwards compatability with DOS).
     1661 */
     1662BOOL WINAPI PathMatchSpecA(LPCSTR name, LPCSTR mask)
    10441663{
    10451664        TRACE("%s %s\n",name,mask);
     
    10471666        if (!lstrcmpA( mask, "*.*" )) return 1;   /* we don't require a period */
    10481667
    1049         while (*mask) 
     1668        while (*mask)
    10501669        {
    10511670          if (PathMatchSingleMaskA(name,mask)) return 1;    /* helper function */
    10521671          while (*mask && *mask!=';') mask = CharNextA(mask);
    1053           if (*mask==';') 
     1672          if (*mask==';')
    10541673          {
    10551674            mask++;
     
    10621681/*************************************************************************
    10631682 * PathMatchSpecW       [SHLWAPI.@]
    1064  */
    1065 BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask)
     1683 *
     1684 * See PathMatchSpecA.
     1685 */
     1686BOOL WINAPI PathMatchSpecW(LPCWSTR name, LPCWSTR mask)
    10661687{
    10671688    static const WCHAR stemp[] = { '*','.','*',0 };
     
    10701691        if (!lstrcmpW( mask, stemp )) return 1;   /* we don't require a period */
    10711692
    1072         while (*mask) 
     1693        while (*mask)
    10731694        {
    10741695          if (PathMatchSingleMaskW(name,mask)) return 1;    /* helper function */
    10751696          while (*mask && *mask!=';') mask = CharNextW(mask);
    1076           if (*mask==';') 
     1697          if (*mask==';')
    10771698          {
    10781699            mask++;
     
    10861707 * PathIsSameRootA      [SHLWAPI.@]
    10871708 *
    1088  * FIXME
    1089  *  what to do with "\path" ??
     1709 * Determine if two paths share the same root.
     1710 *
     1711 * PARAMS
     1712 *  lpszPath1 [I] Source path
     1713 *  lpszPath2 [I] Path to compare with
     1714 *
     1715 * RETURNS
     1716 *  TRUE  If both paths are valid and share the same root.
     1717 *  FALSE If either path is invalid or the paths do not share the same root.
    10901718 */
    10911719BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2)
    10921720{
    1093         TRACE("%s %s\n", lpszPath1, lpszPath2);
    1094        
    1095         if (PathIsRelativeA(lpszPath1) || PathIsRelativeA(lpszPath2)) return FALSE;
    1096 
    1097         /* usual path */
    1098         if ( toupper(lpszPath1[0])==toupper(lpszPath2[0]) &&
    1099              lpszPath1[1]==':' && lpszPath2[1]==':' &&
    1100              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
    1101           return TRUE;
    1102 
    1103         /* UNC */
    1104         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
    1105             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
    1106         {
    1107           int pos=2, bsfound=0;
    1108           while (lpszPath1[pos] && lpszPath2[pos] &&
    1109                 (lpszPath1[pos] == lpszPath2[pos]))
    1110           {
    1111             if (lpszPath1[pos]=='\\') bsfound++;
    1112             if (bsfound == 2) return TRUE;
    1113             pos++; /* FIXME: use CharNext*/
    1114           }
    1115           return (lpszPath1[pos] == lpszPath2[pos]);
    1116         }
    1117         return FALSE;
     1721  LPCSTR lpszStart;
     1722  DWORD dwLen;
     1723
     1724  TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2));
     1725
     1726  if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1)))
     1727    return FALSE;
     1728
     1729  dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1;
     1730  if (lpszStart - lpszPath1 > dwLen)
     1731    return FALSE; /* Paths not common up to length of the root */
     1732  return TRUE;
    11181733}
    11191734
    11201735/*************************************************************************
    11211736 * PathIsSameRootW      [SHLWAPI.@]
     1737 *
     1738 * See PathIsSameRootA.
    11221739 */
    11231740BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2)
    11241741{
    1125         TRACE("%s %s\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
    1126        
    1127         if (PathIsRelativeW(lpszPath1) || PathIsRelativeW(lpszPath2)) return FALSE;
    1128 
    1129         /* usual path */
    1130         if ( toupperW(lpszPath1[0])==toupperW(lpszPath2[0]) &&
    1131              lpszPath1[1]==':' && lpszPath2[1]==':' &&
    1132              lpszPath1[2]=='\\' && lpszPath2[2]=='\\')
    1133           return TRUE;
    1134 
    1135         /* UNC */
    1136         if (lpszPath1[0]=='\\' && lpszPath2[0]=='\\' &&
    1137             lpszPath1[1]=='\\' && lpszPath2[1]=='\\')
    1138         {
    1139           int pos=2, bsfound=0;
    1140           while (lpszPath1[pos] && lpszPath2[pos] &&
    1141                 (lpszPath1[pos] == lpszPath2[pos]))
    1142           {
    1143             if (lpszPath1[pos]=='\\') bsfound++;
    1144             if (bsfound == 2) return TRUE;
    1145             pos++;/* FIXME: use CharNext*/
    1146           }
    1147           return (lpszPath1[pos] == lpszPath2[pos]);
    1148         }
    1149         return FALSE;
    1150 }
    1151 
    1152 /*************************************************************************
    1153  * PathIsURLA (SHLWAPI.@)
     1742  LPCWSTR lpszStart;
     1743  DWORD dwLen;
     1744
     1745  TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2));
     1746
     1747  if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1)))
     1748    return FALSE;
     1749
     1750  dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1;
     1751  if (lpszStart - lpszPath1 > dwLen)
     1752    return FALSE; /* Paths not common up to length of the root */
     1753  return TRUE;
     1754}
     1755
     1756/*************************************************************************
     1757 * PathIsURLA   [SHLWAPI.@]
     1758 *
     1759 * Check if the given path is a URL.
     1760 *
     1761 * PARAMS
     1762 *  lpszPath [I] Path to check.
     1763 *
     1764 * RETURNS
     1765 *  TRUE  if lpszPath is a URL.
     1766 *  FALSE if lpszPath is NULL or not a URL.
    11541767 */
    11551768BOOL WINAPI PathIsURLA(LPCSTR lpstrPath)
     
    11631776    base.size = 24;
    11641777    res1 = SHLWAPI_1(lpstrPath, &base);
    1165 
    1166 #ifdef __WIN32OS2__ 
    1167     // PH 2002-02-26 Fixes crash on Flask->About
    1168     // ShellExecute("..\doc\readme.html")
    1169     if (S_OK != res1)
    1170       return FALSE;
    1171 #endif
    1172  
    11731778    return (base.fcncde) ? TRUE : FALSE;
    1174 } 
    1175 
    1176 /*************************************************************************
    1177  * PathIsURLW (SHLWAPI.@)
     1779}
     1780
     1781/*************************************************************************
     1782 * PathIsURLW   [SHLWAPI.@]
    11781783 */
    11791784BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath)
     
    11871792    base.size = 24;
    11881793    res1 = SHLWAPI_2(lpstrPath, &base);
    1189  
    1190 #ifdef __WIN32OS2__ 
    1191     // PH 2002-02-26 Fixes crash on Flask->About
    1192     // ShellExecute("..\doc\readme.html")
    1193     if (S_OK != res1)
     1794    return (base.fcncde) ? TRUE : FALSE;
     1795}
     1796
     1797/*************************************************************************
     1798 * PathIsContentTypeA   [SHLWAPI.@]
     1799 *
     1800 * Determine if a file is of a registered content type.
     1801 *
     1802 * PARAMS
     1803 *  lpszPath [I] file to chack
     1804 *
     1805 * RETURNS
     1806 *  TRUE  If lpszPath is a registered content type
     1807 *  FALSE Otherwise.
     1808 */
     1809BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType)
     1810{
     1811  LPCSTR szExt;
     1812  DWORD dwDummy;
     1813  char szBuff[MAX_PATH];
     1814
     1815  TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType));
     1816
     1817  if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt &&
     1818      !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type",
     1819                   REG_NONE, szBuff, &dwDummy) &&
     1820      !strcasecmp(lpszContentType, szBuff))
     1821  {
     1822    return TRUE;
     1823  }
     1824  return FALSE;
     1825}
     1826
     1827/*************************************************************************
     1828 * PathIsContentTypeW   [SHLWAPI.@]
     1829 *
     1830 * See PathIsContentTypeA.
     1831 */
     1832BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType)
     1833{
     1834  static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' };
     1835  LPCWSTR szExt;
     1836  DWORD dwDummy;
     1837  WCHAR szBuff[MAX_PATH];
     1838
     1839  TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType));
     1840
     1841  if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt &&
     1842      !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType,
     1843                   REG_NONE, szBuff, &dwDummy) &&
     1844      !strcmpiW(lpszContentType, szBuff))
     1845  {
     1846    return TRUE;
     1847  }
     1848  return FALSE;
     1849}
     1850
     1851/*************************************************************************
     1852 * PathIsFileSpecA   [SHLWAPI.@]
     1853 *
     1854 * Determine if a path is a file specification.
     1855 *
     1856 * PARAMS
     1857 *  lpszPath [I] Path to chack
     1858 *
     1859 * RETURNS
     1860 *  TRUE  If lpszPath is a file spec (contains no directories).
     1861 *  FALSE Otherwise.
     1862 */
     1863BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath)
     1864{
     1865  TRACE("(%s)\n", debugstr_a(lpszPath));
     1866
     1867  if (!lpszPath)
     1868    return FALSE;
     1869
     1870  while (*lpszPath)
     1871  {
     1872    if (*lpszPath == '\\' || *lpszPath == ':')
    11941873      return FALSE;
    1195 #endif
    1196  
    1197     return (base.fcncde) ? TRUE : FALSE;
    1198 
    1199 
    1200 
    1201 /*************************************************************************
    1202  *      PathIsContentTypeA   [SHLWAPI.@]
    1203  */
    1204 BOOL WINAPI PathIsContentTypeA(LPCSTR pszPath, LPCSTR pszContentType)
    1205 {
    1206         FIXME("%s %s\n", pszPath, pszContentType);
    1207         return FALSE;
    1208 }
    1209 
    1210 /*************************************************************************
    1211  *      PathIsContentTypeW   [SHLWAPI.@]
    1212  */
    1213 BOOL WINAPI PathIsContentTypeW(LPCWSTR pszPath, LPCWSTR pszContentType)
    1214 {
    1215         FIXME("%s %s\n", debugstr_w(pszPath), debugstr_w(pszContentType));
    1216         return FALSE;
    1217 }
    1218 
    1219 /*************************************************************************
    1220  *      PathIsFileSpecA   [SHLWAPI.@]
    1221  */
    1222 BOOL WINAPI PathIsFileSpecA(LPCSTR pszPath)
    1223 {
    1224         FIXME("%s\n", pszPath);
    1225         return FALSE;
    1226 }
    1227 
    1228 /*************************************************************************
    1229  *      PathIsFileSpecW   [SHLWAPI.@]
    1230  */
    1231 BOOL WINAPI PathIsFileSpecW(LPCWSTR pszPath)
    1232 {
    1233         FIXME("%s\n", debugstr_w(pszPath));
    1234         return FALSE;
    1235 }
    1236 
    1237 /*************************************************************************
    1238  *      PathIsPrefixA   [SHLWAPI.@]
    1239  */
    1240 BOOL WINAPI PathIsPrefixA(LPCSTR pszPrefix, LPCSTR pszPath)
    1241 {
    1242         FIXME("%s %s\n", pszPrefix, pszPath);
    1243         return FALSE;
    1244 }
    1245 
    1246 /*************************************************************************
    1247  *      PathIsPrefixW   [SHLWAPI.@]
    1248  */
    1249 BOOL WINAPI PathIsPrefixW(LPCWSTR pszPrefix, LPCWSTR pszPath)
    1250 {
    1251         FIXME("%s %s\n", debugstr_w(pszPrefix), debugstr_w(pszPath));
    1252         return FALSE;
    1253 }
    1254 
    1255 /*************************************************************************
    1256  *      PathIsSystemFolderA   [SHLWAPI.@]
    1257  */
    1258 BOOL WINAPI PathIsSystemFolderA(LPCSTR pszPath, DWORD dwAttrb)
    1259 {
    1260         FIXME("%s 0x%08lx\n", pszPath, dwAttrb);
    1261         return FALSE;
    1262 }
    1263 
    1264 /*************************************************************************
    1265  *      PathIsSystemFolderW   [SHLWAPI.@]
    1266  */
    1267 BOOL WINAPI PathIsSystemFolderW(LPCWSTR pszPath, DWORD dwAttrb)
    1268 {
    1269         FIXME("%s 0x%08lx\n", debugstr_w(pszPath), dwAttrb);
    1270         return FALSE;
    1271 }
    1272 
    1273 /*************************************************************************
    1274  *      PathIsUNCServerA   [SHLWAPI.@]
    1275  */
    1276 BOOL WINAPI PathIsUNCServerA(
    1277         LPCSTR lpszPath)
    1278 {
    1279         TRACE("%s\n", debugstr_a(lpszPath));
    1280         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    1281         {
    1282           int foundbackslash = 0;
    1283           lpszPath += 2;
    1284           while (*lpszPath)
    1285           {
    1286             if (*lpszPath=='\\') foundbackslash++;
    1287             lpszPath = CharNextA(lpszPath);
    1288           }
    1289           if (foundbackslash == 0)
    1290             return TRUE;
    1291         }
    1292         return FALSE;
    1293 }
    1294 
    1295 /*************************************************************************
    1296  *      PathIsUNCServerW   [SHLWAPI.@]
    1297  */
    1298 BOOL WINAPI PathIsUNCServerW(
    1299         LPCWSTR lpszPath)
    1300 {
    1301         TRACE("%s\n", debugstr_w(lpszPath));
    1302         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    1303         {
    1304           int foundbackslash = 0;
    1305           lpszPath += 2;
    1306           while (*lpszPath)
    1307           {
    1308             if (*lpszPath=='\\') foundbackslash++;
    1309             lpszPath = CharNextW(lpszPath);
    1310           }
    1311           if (foundbackslash == 0)
    1312             return TRUE;
    1313         }
    1314         return FALSE;
    1315 }
    1316 
    1317 /*************************************************************************
    1318  *      PathIsUNCServerShareA   [SHLWAPI.@]
    1319  */
    1320 BOOL WINAPI PathIsUNCServerShareA(
    1321         LPCSTR lpszPath)
    1322 {
    1323         TRACE("%s\n", debugstr_a(lpszPath));
    1324         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    1325         {
    1326           int foundbackslash = 0;
    1327           lpszPath += 2;
    1328           while (*lpszPath)
    1329           {
    1330             if (*lpszPath=='\\') foundbackslash++;
    1331             lpszPath = CharNextA(lpszPath);
    1332           }
    1333           if (foundbackslash == 1)
    1334             return TRUE;
    1335         }
    1336         return FALSE;
    1337 }
    1338 
    1339 /*************************************************************************
    1340  *      PathIsUNCServerShareW   [SHLWAPI.@]
    1341  */
    1342 BOOL WINAPI PathIsUNCServerShareW(
    1343         LPCWSTR lpszPath)
    1344 {
    1345         TRACE("%s\n", debugstr_w(lpszPath));
    1346         if (lpszPath[0]=='\\' && lpszPath[1]=='\\')             
    1347         {
    1348           int foundbackslash = 0;
    1349           lpszPath += 2;
    1350           while (*lpszPath)
    1351           {
    1352             if (*lpszPath=='\\') foundbackslash++;
    1353             lpszPath = CharNextW(lpszPath);
    1354           }
    1355           if (foundbackslash == 1)
    1356             return TRUE;
    1357         }
    1358         return FALSE;
     1874    lpszPath = CharNextA(lpszPath);
     1875  }
     1876  return TRUE;
     1877}
     1878
     1879/*************************************************************************
     1880 * PathIsFileSpecW   [SHLWAPI.@]
     1881 *
     1882 * See PathIsFileSpecA.
     1883 */
     1884BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath)
     1885{
     1886  TRACE("(%s)\n", debugstr_w(lpszPath));
     1887
     1888  if (!lpszPath)
     1889    return FALSE;
     1890
     1891  while (*lpszPath)
     1892  {
     1893    if (*lpszPath == '\\' || *lpszPath == ':')
     1894      return FALSE;
     1895    lpszPath = CharNextW(lpszPath);
     1896  }
     1897  return TRUE;
     1898}
     1899
     1900/*************************************************************************
     1901 * PathIsPrefixA   [SHLWAPI.@]
     1902 *
     1903 * Determine if a path is a prefix of another.
     1904 *
     1905 * PARAMS
     1906 *  lpszPrefix [I] Prefix
     1907 *  lpszPath   [i] Path to check
     1908 *
     1909 * RETURNS
     1910 *  TRUE  If lpszPath has lpszPrefix as its prefix
     1911 *  FALSE If either path is NULL or lpszPrefix is not a prefix
     1912 */
     1913BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath)
     1914{
     1915  TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath));
     1916
     1917  if (lpszPrefix && lpszPath &&
     1918      PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == strlen(lpszPrefix))
     1919    return TRUE;
     1920  return FALSE;
     1921}
     1922
     1923/*************************************************************************
     1924 *  PathIsPrefixW   [SHLWAPI.@]
     1925 *
     1926 *  See PathIsPrefixA.
     1927 */
     1928BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath)
     1929{
     1930  TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath));
     1931
     1932  if (lpszPrefix && lpszPath &&
     1933      PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == strlenW(lpszPrefix))
     1934    return TRUE;
     1935  return FALSE;
     1936}
     1937
     1938/*************************************************************************
     1939 * PathIsSystemFolderA   [SHLWAPI.@]
     1940 *
     1941 * Determine if a path or file attributes are a system folder.
     1942 *
     1943 * PARAMS
     1944 *  lpszPath  [I] Path to check.
     1945 *  dwAttrib  [I] Attributes to check, if lpszPath is NULL.
     1946 *
     1947 * RETURNS
     1948 *  TRUE   If lpszPath or dwAttrib are a system folder.
     1949 *  FALSE  If GetFileAttributesA fails or neither parameter is a system folder.
     1950 */
     1951BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib)
     1952{
     1953  TRACE("(%s,0x%08lx)\n", debugstr_a(lpszPath), dwAttrib);
     1954
     1955  if (lpszPath && *lpszPath)
     1956    dwAttrib = GetFileAttributesA(lpszPath);
     1957
     1958  if (dwAttrib == -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
     1959      !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
     1960    return FALSE;
     1961  return TRUE;
     1962}
     1963
     1964/*************************************************************************
     1965 * PathIsSystemFolderW   [SHLWAPI.@]
     1966 *
     1967 * See PathIsSystemFolderA.
     1968 */
     1969BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib)
     1970{
     1971  TRACE("(%s,0x%08lx)\n", debugstr_w(lpszPath), dwAttrib);
     1972
     1973  if (lpszPath && *lpszPath)
     1974    dwAttrib = GetFileAttributesW(lpszPath);
     1975
     1976  if (dwAttrib == -1 || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) ||
     1977      !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
     1978    return FALSE;
     1979  return TRUE;
     1980}
     1981
     1982/*************************************************************************
     1983 * PathIsUNCA           [SHLWAPI.@]
     1984 *
     1985 * Determine if a path is in UNC format.
     1986 *
     1987 * PARAMS
     1988 *  lpszPath [I] Path to check
     1989 *
     1990 * RETURNS
     1991 *  TRUE: The path is UNC.
     1992 *  FALSE: The path is not UNC or is NULL.
     1993 */
     1994BOOL WINAPI PathIsUNCA(LPCSTR lpszPath)
     1995{
     1996  TRACE("(%s)\n",debugstr_a(lpszPath));
     1997
     1998  if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'))
     1999    return TRUE;
     2000  return FALSE;
     2001}
     2002
     2003/*************************************************************************
     2004 * PathIsUNCW           [SHLWAPI.@]
     2005 *
     2006 * See PathIsUNCA.
     2007 */
     2008BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath)
     2009{
     2010  TRACE("(%s)\n",debugstr_w(lpszPath));
     2011
     2012  if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\'))
     2013    return TRUE;
     2014  return FALSE;
     2015}
     2016
     2017/*************************************************************************
     2018 * PathIsUNCServerA   [SHLWAPI.@]
     2019 *
     2020 * Determine if a path is a UNC server name ("\\SHARENAME").
     2021 *
     2022 * PARAMS
     2023 *  lpszPath  [I] Path to check.
     2024 *
     2025 * RETURNS
     2026 *  TRUE   If lpszPath is a valid UNC server name.
     2027 *  FALSE  Otherwise.
     2028 *
     2029 * NOTES
     2030 *  This routine is bug compatible with Win32: Server names with a
     2031 *  trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly.
     2032 *  Fixing this bug may break other shlwapi functions!
     2033 */
     2034BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath)
     2035{
     2036  TRACE("(%s)\n", debugstr_a(lpszPath));
     2037
     2038  if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
     2039  {
     2040    while (*lpszPath)
     2041    {
     2042      if (*lpszPath == '\\')
     2043        return FALSE;
     2044      lpszPath = CharNextA(lpszPath);
     2045    }
     2046    return TRUE;
     2047  }
     2048  return FALSE;
     2049}
     2050
     2051/*************************************************************************
     2052 * PathIsUNCServerW   [SHLWAPI.@]
     2053 *
     2054 * See PathIsUNCServerA.
     2055 */
     2056BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath)
     2057{
     2058  TRACE("(%s)\n", debugstr_w(lpszPath));
     2059
     2060  if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
     2061  {
     2062    while (*lpszPath)
     2063    {
     2064      if (*lpszPath == '\\')
     2065        return FALSE;
     2066      lpszPath = CharNextW(lpszPath);
     2067    }
     2068    return TRUE;
     2069  }
     2070  return FALSE;
     2071}
     2072
     2073/*************************************************************************
     2074 * PathIsUNCServerShareA   [SHLWAPI.@]
     2075 *
     2076 * Determine if a path is a UNC server share ("\\SHARENAME\SHARE").
     2077 *
     2078 * PARAMS
     2079 *  lpszPath  [I] Path to check.
     2080 *
     2081 * RETURNS
     2082 *  TRUE   If lpszPath is a valid UNC server share.
     2083 *  FALSE  Otherwise.
     2084 *
     2085 * NOTES
     2086 *  This routine is bug compatible with Win32: Server shares with a
     2087 *  trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly.
     2088 *  Fixing this bug may break other shlwapi functions!
     2089 */
     2090BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath)
     2091{
     2092  TRACE("(%s)\n", debugstr_a(lpszPath));
     2093
     2094  if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
     2095  {
     2096    BOOL bSeenSlash = FALSE;
     2097    while (*lpszPath)
     2098    {
     2099      if (*lpszPath == '\\')
     2100      {
     2101        if (bSeenSlash)
     2102          return FALSE;
     2103        bSeenSlash = TRUE;
     2104      }
     2105      lpszPath = CharNextA(lpszPath);
     2106    }
     2107    return bSeenSlash;
     2108  }
     2109  return FALSE;
     2110}
     2111
     2112/*************************************************************************
     2113 * PathIsUNCServerShareW   [SHLWAPI.@]
     2114 *
     2115 * See PathIsUNCServerShareA.
     2116 */
     2117BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath)
     2118{
     2119  TRACE("(%s)\n", debugstr_w(lpszPath));
     2120
     2121  if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\')
     2122  {
     2123    BOOL bSeenSlash = FALSE;
     2124    while (*lpszPath)
     2125    {
     2126      if (*lpszPath == '\\')
     2127      {
     2128        if (bSeenSlash)
     2129          return FALSE;
     2130        bSeenSlash = TRUE;
     2131      }
     2132      lpszPath = CharNextW(lpszPath);
     2133    }
     2134    return bSeenSlash;
     2135  }
     2136  return FALSE;
    13592137}
    13602138
     
    13622140 * PathCanonicalizeA   [SHLWAPI.@]
    13632141 *
    1364  *  FIXME
    1365  *   returnvalue, use CharNext
    1366  */
    1367  
    1368 BOOL WINAPI PathCanonicalizeA(LPSTR pszBuf, LPCSTR pszPath)
    1369 {
    1370         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlen(pszPath);
    1371         BOOL bModifyed = FALSE;
    1372 
    1373         TRACE("%p %s\n", pszBuf, pszPath);
    1374        
    1375         pszBuf[OffsetDst]='\0';
    1376 
    1377         /* keep the root of the path */
    1378         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
    1379         {
    1380           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1381         }
    1382         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
    1383         {
    1384           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1385           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1386           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
    1387           {
    1388             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1389             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
    1390             {
    1391               /* C:\. */
    1392               OffsetSrc++; LenSrc--; bModifyed = TRUE;
    1393             }
    1394             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
    1395             {
    1396               /* C:\.. */
    1397               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
    1398             }
     2142 * Convert a path to its canonical form.
     2143 *
     2144 * PARAMS
     2145 *  lpszBuf  [O] Output path
     2146 *  lpszPath [I] Path to cnonicalize
     2147 *
     2148 * RETURNS
     2149 *  Success: TRUE.  lpszBuf contains the output path
     2150 *  Failure: FALSE, If input path is invalid. lpszBuf is undefined
     2151 */
     2152BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath)
     2153{
     2154  BOOL bRet = FALSE;
     2155
     2156  TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath));
     2157
     2158  if (lpszBuf)
     2159    *lpszBuf = '\0';
     2160
     2161  if (!lpszBuf || !lpszPath)
     2162    SetLastError(ERROR_INVALID_PARAMETER);
     2163  else
     2164  {
     2165    WCHAR szPath[MAX_PATH];
     2166    WCHAR szBuff[MAX_PATH];
     2167    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     2168    bRet = PathCanonicalizeW(szBuff, szPath);
     2169    WideCharToMultiByte(0,0,szBuff,-1,lpszBuf,MAX_PATH,0,0);
     2170  }
     2171  return bRet;
     2172}
     2173
     2174
     2175/*************************************************************************
     2176 * PathCanonicalizeW   [SHLWAPI.@]
     2177 *
     2178 * See PathCanonicalizeA.
     2179 */
     2180BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath)
     2181{
     2182  LPWSTR lpszDst = lpszBuf;
     2183  LPCWSTR lpszSrc = lpszPath;
     2184
     2185  TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath));
     2186
     2187  if (lpszBuf)
     2188    *lpszDst = '\0';
     2189
     2190  if (!lpszBuf || !lpszPath)
     2191  {
     2192    SetLastError(ERROR_INVALID_PARAMETER);
     2193    return FALSE;
     2194  }
     2195
     2196  if (!*lpszPath)
     2197  {
     2198    *lpszBuf++ = '\\';
     2199    *lpszBuf = '\0';
     2200    return TRUE;
     2201  }
     2202
     2203  /* Copy path root */
     2204  if (*lpszSrc == '\\')
     2205  {
     2206    *lpszDst++ = *lpszSrc++;
     2207  }
     2208  else if (*lpszSrc && lpszSrc[1] == ':')
     2209  {
     2210    /* X:\ */
     2211    *lpszDst++ = *lpszSrc++;
     2212    *lpszDst++ = *lpszSrc++;
     2213    if (*lpszSrc == '\\')
     2214      *lpszDst++ = *lpszSrc++;
     2215  }
     2216
     2217  /* Canonicalize the rest of the path */
     2218  while (*lpszSrc)
     2219  {
     2220    if (*lpszSrc == '.')
     2221    {
     2222      if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':'))
     2223      {
     2224        lpszSrc += 2; /* Skip .\ */
     2225      }
     2226      else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\'))
     2227      {
     2228        /* \.. backs up a directory, over the root if it has no \ following X:.
     2229         * .. is ignored if it would remove a UNC server name or inital \\
     2230         */
     2231        if (lpszDst != lpszBuf)
     2232        {
     2233          *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
     2234          if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' &&
     2235             (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2))
     2236          {
     2237            if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':'))
     2238            {
     2239              lpszDst -= 2;
     2240              while (lpszDst > lpszBuf && *lpszDst != '\\')
     2241                lpszDst--;
     2242              if (*lpszDst == '\\')
     2243                lpszDst++; /* Reset to last '\' */
     2244              else
     2245                lpszDst = lpszBuf; /* Start path again from new root */
     2246            }
     2247            else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf))
     2248              lpszDst -= 2;
    13992249          }
    1400         }
    1401        
    1402         /* ".\" at the beginning of the path */
    1403         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
    1404         {
    1405           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
    1406         }
    1407        
    1408         while ( LenSrc )
    1409         {
    1410           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
    1411           {
    1412             /* "\.." found, go one deeper */
    1413             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
    1414             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
    1415             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
    1416             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
    1417           }
    1418           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
    1419           {
    1420             /* "\." found, skip it */
    1421             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
    1422           }
    1423           else
    1424           {
    1425             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
    1426           }
    1427         }
    1428         pszBuf[OffsetDst] = '\0';
    1429         TRACE("-- %s %u\n", pszBuf, bModifyed);
    1430         return bModifyed;
    1431 }
    1432 
    1433 
    1434 /*************************************************************************
    1435  * PathCanonicalizeW   [SHLWAPI.@]
    1436  *
    1437  *  FIXME
    1438  *   returnvalue, use CharNext
    1439  */
    1440 BOOL WINAPI PathCanonicalizeW(LPWSTR pszBuf, LPCWSTR pszPath)
    1441 {
    1442         int OffsetMin = 0, OffsetSrc = 0, OffsetDst = 0, LenSrc = strlenW(pszPath);
    1443         BOOL bModifyed = FALSE;
    1444 
    1445         TRACE("%p %s\n", pszBuf, debugstr_w(pszPath));
    1446        
    1447         pszBuf[OffsetDst]='\0';
    1448 
    1449         /* keep the root of the path */
    1450         if( LenSrc && (pszPath[OffsetSrc]=='\\'))
    1451         {
    1452           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1453         }
    1454         else if ( (LenSrc >= 2) && (pszPath[OffsetSrc+1] == ':'))
    1455         {
    1456           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1457           pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1458           if (LenSrc && (pszPath[OffsetSrc] == '\\'))
    1459           {
    1460             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; OffsetMin++; LenSrc--;
    1461             if (LenSrc == 1 && pszPath[OffsetSrc]=='.')
    1462             {
    1463               /* C:\. */
    1464               OffsetSrc++; LenSrc--; bModifyed = TRUE;
    1465             }
    1466             else if (LenSrc == 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='.')
    1467             {
    1468               /* C:\.. */
    1469               OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
    1470             }
     2250          while (lpszDst > lpszBuf && *lpszDst != '\\')
     2251            lpszDst--;
     2252          if (lpszDst == lpszBuf)
     2253          {
     2254            *lpszDst++ = '\\';
     2255            lpszSrc++;
    14712256          }
    1472         }
    1473        
    1474         /* ".\" at the beginning of the path */
    1475         if (LenSrc >= 2 && pszPath[OffsetSrc]=='.' && pszPath[OffsetSrc+1]=='\\')
    1476         {
    1477           OffsetSrc+=2; LenSrc-=2; bModifyed = TRUE;
    1478         }
    1479        
    1480         while ( LenSrc )
    1481         {
    1482           if((LenSrc>=3) && (pszPath[OffsetSrc]=='\\') && (pszPath[OffsetSrc+1]=='.') && (pszPath[OffsetSrc+2]=='.'))
    1483           {
    1484             /* "\.." found, go one deeper */
    1485             while((OffsetDst > OffsetMin) && (pszBuf[OffsetDst]!='\\')) OffsetDst--;
    1486             OffsetSrc += 3; LenSrc -= 3; bModifyed = TRUE;
    1487             if(OffsetDst == OffsetMin && pszPath[OffsetSrc]=='\\') OffsetSrc++;
    1488             pszBuf[OffsetDst] = '\0';                   /* important for \..\.. */
    1489           }
    1490           else if(LenSrc>=2 && pszPath[OffsetSrc]=='\\' && pszPath[OffsetSrc+1]=='.' )
    1491           {
    1492             /* "\." found, skip it */
    1493             OffsetSrc += 2; LenSrc-=2; bModifyed = TRUE;
    1494           }
    1495           else
    1496           {
    1497             pszBuf[OffsetDst++] = pszPath[OffsetSrc++]; LenSrc--;
    1498           }
    1499         }
    1500         pszBuf[OffsetDst] = '\0';
    1501         TRACE("-- %s %u\n", debugstr_w(pszBuf), bModifyed);
    1502         return bModifyed;
     2257        }
     2258        lpszSrc += 2; /* Skip .. in src path */
     2259      }
     2260      else
     2261        *lpszDst++ = *lpszSrc++;
     2262    }
     2263    else
     2264      *lpszDst++ = *lpszSrc++;
     2265  }
     2266  /* Append \ to naked drive specs */
     2267  if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':')
     2268    *lpszDst++ = '\\';
     2269  *lpszDst++ = '\0';
     2270  return TRUE;
    15032271}
    15042272
     
    15062274 * PathFindNextComponentA   [SHLWAPI.@]
    15072275 *
     2276 * Find the next component in a path.
     2277 *
     2278 * PARAMS
     2279 *   lpszPath [I] Path to find next component in
     2280 *
     2281 * RETURNS
     2282 *  Success: A pointer to the next component, or the end of the string
     2283 *  Failure: NULL, If lpszPath is invalid
     2284 *
    15082285 * NOTES
    1509  * special cases:
    1510  *      ""              null
    1511  *      aa              "" (pointer to traling NULL)
    1512  *      aa\             "" (pointer to traling NULL)
    1513  *      aa\\            "" (pointer to traling NULL)
    1514  *      aa\\bb          bb
    1515  *      aa\\\bb         \bb
    1516  *      c:\aa\          "aa\"
    1517  *      \\aa            aa
    1518  *      \\aa\b          aa\b
    1519 */
    1520 LPSTR WINAPI PathFindNextComponentA(LPCSTR pszPath)
    1521 {
    1522         LPSTR pos;
    1523 
    1524         TRACE("%s\n", pszPath);
    1525 
    1526         if(!pszPath || !*pszPath) return NULL;
    1527         if(!(pos = StrChrA(pszPath, '\\')))
    1528           return (LPSTR) pszPath + strlen(pszPath);
    1529         pos++;
    1530         if(pos[0] == '\\') pos++;
    1531         return pos;
     2286 *  A 'component' is either a backslash character (\) or UNC marker (\\).
     2287 *  Because of this, relative paths (e.g "c:foo") are regarded as having
     2288 *  only one component.
     2289 */
     2290LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath)
     2291{
     2292  LPSTR lpszSlash;
     2293
     2294  TRACE("(%s)\n", debugstr_a(lpszPath));
     2295
     2296  if(!lpszPath || !*lpszPath)
     2297    return NULL;
     2298
     2299  if ((lpszSlash = StrChrA(lpszPath, '\\')))
     2300  {
     2301    if (lpszSlash[1] == '\\')
     2302      lpszSlash++;
     2303    return lpszSlash + 1;
     2304  }
     2305  return (LPSTR)lpszPath + strlen(lpszPath);
    15322306}
    15332307
    15342308/*************************************************************************
    15352309 * PathFindNextComponentW   [SHLWAPI.@]
    1536  */
    1537 LPWSTR WINAPI PathFindNextComponentW(LPCWSTR pszPath)
    1538 {
    1539         LPWSTR pos;
    1540 
    1541         TRACE("%s\n", debugstr_w(pszPath));
    1542        
    1543         if(!pszPath || !*pszPath) return NULL;
    1544         if (!(pos = StrChrW(pszPath, '\\')))
    1545           return (LPWSTR) pszPath + strlenW(pszPath);
    1546         pos++;
    1547         if(pos[0] == '\\') pos++;
    1548         return pos;
     2310 *
     2311 * See PathFindNextComponentA.
     2312 */
     2313LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath)
     2314{
     2315  LPWSTR lpszSlash;
     2316
     2317  TRACE("(%s)\n", debugstr_w(lpszPath));
     2318
     2319  if(!lpszPath || !*lpszPath)
     2320    return NULL;
     2321
     2322  if ((lpszSlash = StrChrW(lpszPath, '\\')))
     2323  {
     2324    if (lpszSlash[1] == '\\')
     2325      lpszSlash++;
     2326    return lpszSlash + 1;
     2327  }
     2328  return (LPWSTR)lpszPath + strlenW(lpszPath);
    15492329}
    15502330
     
    15522332 * PathAddExtensionA   [SHLWAPI.@]
    15532333 *
     2334 * Add a file extension to a path
     2335 *
     2336 * PARAMS
     2337 *  lpszPath      [O] Path to add extension to
     2338 *  lpszExtension [I} Extension to add to lpszPath
     2339 *
     2340 * RETURNS
     2341 *  TRUE  If the path was modified
     2342 *  FALSE If lpszPath or lpszExtension are invalid, lpszPath has an
     2343 *        extension allready, or the new path length is too big.
     2344 *
     2345 * FIXME
     2346 *  What version of shlwapi.dll adds "exe" if pszExtension is NULL? Win2k
     2347 *  does not do this, so the behaviour was removed.
     2348 */
     2349BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension)
     2350{
     2351  DWORD dwLen;
     2352
     2353  TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension));
     2354
     2355  if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath)))
     2356    return FALSE;
     2357
     2358  dwLen = strlen(lpszPath);
     2359
     2360  if (dwLen + strlen(lpszExtension) >= MAX_PATH)
     2361    return FALSE;
     2362
     2363  strcpy(lpszPath + dwLen, lpszExtension);
     2364  return TRUE;
     2365}
     2366
     2367/*************************************************************************
     2368 * PathAddExtensionW   [SHLWAPI.@]
     2369 *
     2370 * See PathAddExtensionA.
     2371 */
     2372BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension)
     2373{
     2374  DWORD dwLen;
     2375
     2376  TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension));
     2377
     2378  if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath)))
     2379    return FALSE;
     2380
     2381  dwLen = strlenW(lpszPath);
     2382
     2383  if (dwLen + strlenW(lpszExtension) >= MAX_PATH)
     2384    return FALSE;
     2385
     2386  strcpyW(lpszPath + dwLen, lpszExtension);
     2387  return TRUE;
     2388}
     2389
     2390/*************************************************************************
     2391 * PathMakePrettyA   [SHLWAPI.@]
     2392 *
     2393 * Convert an uppercase DOS filename into lowercase.
     2394 *
     2395 * PARAMS
     2396 *  lpszPath [O] Path to convert.
     2397 *
     2398 * RETURNS
     2399 *  TRUE  If the path was an uppercase DOS path and was converted
     2400 *  FALSE Otherwise.
     2401 */
     2402BOOL WINAPI PathMakePrettyA(LPSTR lpszPath)
     2403{
     2404  LPSTR pszIter = lpszPath;
     2405
     2406  TRACE("(%s)\n", debugstr_a(lpszPath));
     2407
     2408  if (!pszIter || !*pszIter)
     2409    return FALSE;
     2410
     2411  while (*pszIter)
     2412  {
     2413    if (islower(*pszIter) || IsDBCSLeadByte(*pszIter))
     2414      return FALSE; /* Not DOS path */
     2415    pszIter++;
     2416  }
     2417  pszIter = lpszPath + 1;
     2418  while (*pszIter)
     2419  {
     2420    *pszIter = tolower(*pszIter);
     2421    pszIter++;
     2422  }
     2423  return TRUE;
     2424}
     2425
     2426/*************************************************************************
     2427 * PathMakePrettyW   [SHLWAPI.@]
     2428 *
     2429 * See PathMakePrettyA
     2430 */
     2431BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath)
     2432{
     2433  LPWSTR pszIter = lpszPath;
     2434
     2435  TRACE("(%s)\n", debugstr_w(lpszPath));
     2436
     2437  if (!pszIter || !*pszIter)
     2438    return FALSE;
     2439
     2440  while (*pszIter)
     2441  {
     2442    if (islowerW(*pszIter))
     2443      return FALSE; /* Not DOS path */
     2444    pszIter++;
     2445  }
     2446  pszIter = lpszPath + 1;
     2447  while (*pszIter)
     2448  {
     2449    *pszIter = tolowerW(*pszIter);
     2450    pszIter++;
     2451  }
     2452  return TRUE;
     2453}
     2454
     2455/*************************************************************************
     2456 * PathCommonPrefixA   [SHLWAPI.@]
     2457 *
     2458 * Determine the length of the common prefix between two paths.
     2459 *
     2460 * PARAMS
     2461 *  lpszFile1 [I] First path for comparason
     2462 *  lpszFile2 [I] Second path for comparason
     2463 *  achPath   [O] Destination for common prefix string
     2464 *
     2465 * RETURNS
     2466 *  The length of the common prefix. This is 0 if there is no common
     2467 *  prefix between the paths or if any parameters are invalid. If the prefix
     2468 *  is non-zero and achPath is not NULL, achPath is filled with the common
     2469 *  part of the prefix and NUL terminated.
     2470 *
    15542471 * NOTES
    1555  *  it adds never a dot
    1556  */
    1557  
    1558 BOOL WINAPI PathAddExtensionA(
    1559         LPSTR  pszPath,
    1560         LPCSTR pszExtension)
    1561 {
    1562         if (*pszPath)
    1563         {
    1564           if (*(PathFindExtensionA(pszPath))) return FALSE;
    1565 
    1566           if (!pszExtension || *pszExtension=='\0')
    1567             strcat(pszPath, "exe");
    1568           else
    1569             strcat(pszPath, pszExtension);
    1570         }
    1571 
    1572         return TRUE;
    1573 }
    1574 
    1575 /*************************************************************************
    1576  *      PathAddExtensionW   [SHLWAPI.@]
    1577  */
    1578 BOOL WINAPI PathAddExtensionW(
    1579         LPWSTR  pszPath,
    1580         LPCWSTR pszExtension)
    1581 {
    1582         static const WCHAR ext[] = { 'e','x','e',0 };
    1583 
    1584         if (*pszPath)
    1585         {
    1586           if (*(PathFindExtensionW(pszPath))) return FALSE;
    1587 
    1588           if (!pszExtension || *pszExtension=='\0')
    1589             strcatW(pszPath, ext);
    1590           else
    1591             strcatW(pszPath, pszExtension);
    1592         }
    1593         return TRUE;
    1594 
    1595 }
    1596 
    1597 /*************************************************************************
    1598  *      PathMakePrettyA   [SHLWAPI.@]
    1599  */
    1600 BOOL WINAPI PathMakePrettyA(
    1601         LPSTR lpPath)
    1602 {
    1603         FIXME("%s\n", lpPath);
    1604         return TRUE;
    1605 }
    1606 
    1607 /*************************************************************************
    1608  *      PathMakePrettyW   [SHLWAPI.@]
    1609  */
    1610 BOOL WINAPI PathMakePrettyW(
    1611         LPWSTR lpPath)
    1612 {
    1613         FIXME("%s\n", debugstr_w(lpPath));
    1614         return TRUE;
    1615 
    1616 }
    1617 
    1618 /*************************************************************************
    1619  *      PathCommonPrefixA   [SHLWAPI.@]
    1620  */
    1621 int WINAPI PathCommonPrefixA(
    1622         LPCSTR pszFile1,
    1623         LPCSTR pszFile2,
    1624         LPSTR achPath)
    1625 {
    1626         FIXME("%s %s %p\n", pszFile1, pszFile2, achPath);
    1627         return 0;
    1628 }
    1629 
    1630 /*************************************************************************
    1631  *      PathCommonPrefixW   [SHLWAPI.@]
    1632  */
    1633 int WINAPI PathCommonPrefixW(
    1634         LPCWSTR pszFile1,
    1635         LPCWSTR pszFile2,
    1636         LPWSTR achPath)
    1637 {
    1638         FIXME("%s %s %p\n", debugstr_w(pszFile1), debugstr_w(pszFile2),achPath );
    1639         return 0;
    1640 }
    1641 
    1642 /*************************************************************************
    1643  *      PathCompactPathA   [SHLWAPI.@]
    1644  */
    1645 BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR pszPath, UINT dx)
    1646 {
    1647         FIXME("0x%08x %s 0x%08x\n", hDC, pszPath, dx);
    1648         return FALSE;
    1649 }
    1650 
    1651 /*************************************************************************
    1652  *      PathCompactPathW   [SHLWAPI.@]
    1653  */
    1654 BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR pszPath, UINT dx)
    1655 {
    1656         FIXME("0x%08x %s 0x%08x\n", hDC, debugstr_w(pszPath), dx);
    1657         return FALSE;
    1658 }
    1659 
    1660 /*************************************************************************
    1661  *      PathGetCharTypeA   [SHLWAPI.@]
     2472 *  A common prefix of 2 is always returned as 3. It is thus possible for
     2473 *  the length returned to be invalid (i.e. Longer than one or both of the
     2474 *  strings given as parameters). This Win32 behaviour has been implimented
     2475 *  here, and cannot be changed (fixed?) without breaking other SHLWAPI calls.
     2476 *  To work around this when using this function, always check that the byte
     2477 *  at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix.
     2478 */
     2479int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath)
     2480{
     2481  int iLen = 0;
     2482  LPCSTR lpszIter1 = lpszFile1;
     2483  LPCSTR lpszIter2 = lpszFile2;
     2484
     2485  TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath);
     2486
     2487  if (achPath)
     2488    *achPath = '\0';
     2489
     2490  if (!lpszFile1 || !lpszFile2)
     2491    return 0;
     2492
     2493  /* Handle roots first */
     2494  if (PathIsUNCA(lpszFile1))
     2495  {
     2496    if (!PathIsUNCA(lpszFile2))
     2497      return 0;
     2498    lpszIter1 += 2;
     2499    lpszIter2 += 2;
     2500  }
     2501  else if (PathIsUNCA(lpszFile2))
     2502      return 0; /* Know already lpszFile1 is not UNC */
     2503
     2504  do
     2505  {
     2506    /* Update len */
     2507    if ((!*lpszIter1 || *lpszIter1 == '\\') &&
     2508        (!*lpszIter2 || *lpszIter2 == '\\'))
     2509      iLen = lpszIter1 - lpszFile1; /* Common to this point */
     2510
     2511    if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2)))
     2512      break; /* Strings differ at this point */
     2513
     2514    lpszIter1++;
     2515    lpszIter2++;
     2516  } while (1);
     2517
     2518  if (iLen == 2)
     2519    iLen++; /* Feature/Bug compatable with Win32 */
     2520
     2521  if (iLen && achPath)
     2522  {
     2523    memcpy(achPath,lpszFile1,iLen);
     2524    achPath[iLen] = '\0';
     2525  }
     2526  return iLen;
     2527}
     2528
     2529/*************************************************************************
     2530 * PathCommonPrefixW   [SHLWAPI.@]
     2531 *
     2532 * See PathCommonPrefixA.
     2533 */
     2534int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath)
     2535{
     2536  int iLen = 0;
     2537  LPCWSTR lpszIter1 = lpszFile1;
     2538  LPCWSTR lpszIter2 = lpszFile2;
     2539
     2540  TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath);
     2541
     2542  if (achPath)
     2543    *achPath = '\0';
     2544
     2545  if (!lpszFile1 || !lpszFile2)
     2546    return 0;
     2547
     2548  /* Handle roots first */
     2549  if (PathIsUNCW(lpszFile1))
     2550  {
     2551    if (!PathIsUNCW(lpszFile2))
     2552      return 0;
     2553    lpszIter1 += 2;
     2554    lpszIter2 += 2;
     2555  }
     2556  else if (PathIsUNCW(lpszFile2))
     2557      return 0; /* Know already lpszFile1 is not UNC */
     2558
     2559  do
     2560  {
     2561    /* Update len */
     2562    if ((!*lpszIter1 || *lpszIter1 == '\\') &&
     2563        (!*lpszIter2 || *lpszIter2 == '\\'))
     2564      iLen = lpszIter1 - lpszFile1; /* Common to this point */
     2565
     2566    if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2)))
     2567      break; /* Strings differ at this point */
     2568
     2569    lpszIter1++;
     2570    lpszIter2++;
     2571  } while (1);
     2572
     2573  if (iLen == 2)
     2574    iLen++; /* Feature/Bug compatable with Win32 */
     2575
     2576  if (iLen && achPath)
     2577  {
     2578    memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR));
     2579    achPath[iLen] = '\0';
     2580  }
     2581  return iLen;
     2582}
     2583
     2584/*************************************************************************
     2585 * PathCompactPathA   [SHLWAPI.@]
     2586 *
     2587 * Make a path fit into a given width when printed to a DC.
     2588 *
     2589 * PARAMS
     2590 *  hDc      [I] Destination DC
     2591 *  lpszPath [O] Path to be printed to hDc
     2592 *  dx       [i] Desired width
     2593 *
     2594 * RETURNS
     2595 *  TRUE  If the path was modified.
     2596 *  FALSE Otherwise.
     2597 */
     2598BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx)
     2599{
     2600  BOOL bRet = FALSE;
     2601
     2602  TRACE("(%08x,%s,%d)\n", hDC, debugstr_a(lpszPath), dx);
     2603
     2604  if (lpszPath)
     2605  {
     2606    WCHAR szPath[MAX_PATH];
     2607    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     2608    bRet = PathCompactPathW(hDC, szPath, dx);
     2609    WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
     2610  }
     2611  return bRet;
     2612}
     2613
     2614/*************************************************************************
     2615 * PathCompactPathW   [SHLWAPI.@]
     2616 *
     2617 * See PathCompactPathA.
     2618 */
     2619BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx)
     2620{
     2621  static const WCHAR szEllipses[] = { '.', '.', '.', '\0' };
     2622  BOOL bRet = TRUE;
     2623  HDC hdc = 0;
     2624  WCHAR buff[MAX_PATH];
     2625  SIZE size;
     2626  DWORD dwLen;
     2627
     2628  TRACE("(%08x,%s,%d)\n", hDC, debugstr_w(lpszPath), dx);
     2629
     2630  if (!lpszPath)
     2631    return bRet;
     2632
     2633  if (!hDC)
     2634    hdc = hDC = GetDC(0);
     2635
     2636  /* Get the length of the whole path */
     2637  dwLen = strlenW(lpszPath);
     2638  GetTextExtentPointW(hDC, lpszPath, dwLen, &size);
     2639
     2640  if (size.cx > dx)
     2641  {
     2642    /* Path too big, must reduce it */
     2643    LPWSTR sFile;
     2644    DWORD dwEllipsesLen = 0, dwPathLen = 0;
     2645
     2646    sFile = PathFindFileNameW(lpszPath);
     2647    if (sFile != lpszPath)
     2648      sFile = CharPrevW(lpszPath, sFile);
     2649
     2650    /* Get the size of ellipses */
     2651    GetTextExtentPointW(hDC, szEllipses, 3, &size);
     2652    dwEllipsesLen = size.cx;
     2653    /* Get the size of the file name */
     2654    GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size);
     2655    dwPathLen = size.cx;
     2656
     2657    if (sFile != lpszPath)
     2658    {
     2659      LPWSTR sPath = sFile;
     2660      BOOL bEllipses = FALSE;
     2661
     2662      /* The path includes a file name. Include as much of the path prior to
     2663       * the file name as possible, allowing for the ellipses, e.g:
     2664       * c:\some very long path\filename ==> c:\some v...\filename
     2665       */
     2666      strncpyW(buff, sFile, MAX_PATH);
     2667
     2668      do
     2669      {
     2670        DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen;
     2671
     2672        GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size);
     2673        dwTotalLen += size.cx;
     2674        if (dwTotalLen <= dx)
     2675          break;
     2676        sPath = CharPrevW(lpszPath, sPath);
     2677        if (!bEllipses)
     2678        {
     2679          bEllipses = TRUE;
     2680          sPath = CharPrevW(lpszPath, sPath);
     2681          sPath = CharPrevW(lpszPath, sPath);
     2682        }
     2683      } while (sPath > lpszPath);
     2684
     2685      if (sPath > lpszPath)
     2686      {
     2687        if (bEllipses)
     2688        {
     2689          strcpyW(sPath, szEllipses);
     2690          strcpyW(sPath+3, buff);
     2691        }
     2692        if (hdc)
     2693          ReleaseDC(0, hdc);
     2694        return TRUE;
     2695      }
     2696      strcpyW(lpszPath, szEllipses);
     2697      strcpyW(lpszPath+3, buff);
     2698      return FALSE;
     2699    }
     2700
     2701    /* Trim the path by adding ellipses to the end, e.g:
     2702     * A very long file name.txt ==> A very...
     2703     */
     2704    dwLen = strlenW(lpszPath);
     2705
     2706    if (dwLen > MAX_PATH - 3)
     2707      dwLen =  MAX_PATH - 3;
     2708    strncpyW(buff, sFile, dwLen);
     2709
     2710    do {
     2711      dwLen--;
     2712      GetTextExtentPointW(hDC, buff, dwLen, &size);
     2713    } while (dwLen && size.cx + dwEllipsesLen > dx);
     2714
     2715   if (!dwLen)
     2716   {
     2717     DWORD dwWritten = 0;
     2718
     2719     dwEllipsesLen /= 3; /* Size of a single '.' */
     2720
     2721     /* Write as much of the Ellipses string as possible */
     2722     while (dwWritten + dwEllipsesLen < dx && dwLen < 3)
     2723     {
     2724       *lpszPath++ = '.';
     2725       dwWritten += dwEllipsesLen;
     2726       dwLen++;
     2727     }
     2728     *lpszPath = '\0';
     2729     bRet = FALSE;
     2730   }
     2731   else
     2732   {
     2733     strcpyW(buff + dwLen, szEllipses);
     2734     strcpyW(lpszPath, buff);
     2735    }
     2736  }
     2737
     2738  if (hdc)
     2739    ReleaseDC(0, hdc);
     2740
     2741  return bRet;
     2742}
     2743
     2744/*************************************************************************
     2745 * PathGetCharTypeA   [SHLWAPI.@]
     2746 *
     2747 * Categorise a character from a file path.
     2748 *
     2749 * PARAMS
     2750 *  ch [I] Character to get the type of
     2751 *
     2752 * RETURNS
     2753 *  A set of GCT_ bit flags (from shlwapi.h) indicating the character type.
    16622754 */
    16632755UINT WINAPI PathGetCharTypeA(UCHAR ch)
    16642756{
    1665         UINT flags = 0;
    1666 
    1667         TRACE("%c\n", ch);
    1668 
    1669         /* We could use them in filenames, but this would confuse 'ls' */
    1670         if (iscntrl(ch))
    1671             return GCT_INVALID;
    1672         if ((ch == '*') || (ch=='?'))
    1673             return GCT_WILD;
    1674         if ((ch == '\\') || (ch=='/'))
    1675             return GCT_SEPARATOR;
    1676         flags = 0;
    1677         /* all normal characters, no lower case letters */
    1678         if ((ch > ' ') && (ch < 0x7f) && !islower(ch))
    1679             flags |= GCT_SHORTCHAR;
    1680         /* All other characters are valid in long filenames, even umlauts */
    1681         return flags | GCT_LFNCHAR;
    1682 }
    1683 
    1684 /*************************************************************************
    1685  *      PathGetCharTypeW   [SHLWAPI.@]
     2757  return PathGetCharTypeW(ch);
     2758}
     2759
     2760/*************************************************************************
     2761 * PathGetCharTypeW   [SHLWAPI.@]
     2762 *
     2763 * See PathGetCharTypeA.
    16862764 */
    16872765UINT WINAPI PathGetCharTypeW(WCHAR ch)
    16882766{
    1689         FIXME("%c, using ascii version\n", ch);
    1690         return PathGetCharTypeA(ch);
    1691 }
    1692 
    1693 /*************************************************************************
    1694  *      PathMakeSystemFolderA   [SHLWAPI.@]
    1695  */
    1696 BOOL WINAPI PathMakeSystemFolderA(LPCSTR pszPath)
    1697 {
    1698         FIXME("%s\n", pszPath);
    1699         return FALSE;
    1700 }
    1701 
    1702 /*************************************************************************
    1703  *      PathMakeSystemFolderW   [SHLWAPI.@]
    1704  */
    1705 BOOL WINAPI PathMakeSystemFolderW(LPCWSTR pszPath)
    1706 {
    1707         FIXME("%s\n", debugstr_w(pszPath));
    1708         return FALSE;
    1709 }
    1710 
    1711 /*************************************************************************
    1712  *      PathRenameExtensionA   [SHLWAPI.@]
    1713  */
    1714 BOOL WINAPI PathRenameExtensionA(LPSTR pszPath, LPCSTR pszExt)
    1715 {
    1716         LPSTR pszExtension = PathFindExtensionA(pszPath);
    1717 
    1718         if (!pszExtension) return FALSE;
    1719         if (pszExtension-pszPath + strlen(pszExt) > MAX_PATH) return FALSE;
    1720 
    1721         strcpy(pszExtension, pszExt);
    1722         TRACE("%s\n", pszPath);
    1723         return TRUE;
    1724 }
    1725 
    1726 /*************************************************************************
    1727  *      PathRenameExtensionW   [SHLWAPI.@]
    1728  */
    1729 BOOL WINAPI PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt)
    1730 {
    1731         LPWSTR pszExtension = PathFindExtensionW(pszPath);
    1732 
    1733         if (!pszExtension) return FALSE;
    1734         if (pszExtension-pszPath + strlenW(pszExt) > MAX_PATH) return FALSE;
    1735 
    1736         strcpyW(pszExtension, pszExt);
    1737         TRACE("%s\n", debugstr_w(pszPath));
    1738         return TRUE;
    1739 }
    1740 
    1741 /*************************************************************************
    1742  *      PathSearchAndQualifyA   [SHLWAPI.@]
    1743  */
    1744 BOOL WINAPI PathSearchAndQualifyA(
    1745         LPCSTR pszPath,
    1746         LPSTR pszBuf,
    1747         UINT cchBuf)
    1748 {
    1749         FIXME("%s %s 0x%08x\n", pszPath, pszBuf, cchBuf);
    1750         return FALSE;
    1751 }
    1752 
    1753 /*************************************************************************
    1754  *      PathSearchAndQualifyW   [SHLWAPI.@]
    1755  */
    1756 BOOL WINAPI PathSearchAndQualifyW(
    1757         LPCWSTR pszPath,
    1758         LPWSTR pszBuf,
    1759         UINT cchBuf)
    1760 {
    1761         FIXME("%s %s 0x%08x\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf);
    1762         return FALSE;
    1763 }
    1764 
    1765 #ifndef __WIN32OS2__
    1766 /*************************************************************************
    1767  *      PathSkipRootA   [SHLWAPI.@]
    1768  */
    1769 LPSTR WINAPI PathSkipRootA(LPCSTR pszPath)
    1770 {
    1771         FIXME("%s\n", pszPath);
    1772         return (LPSTR)pszPath;
    1773 }
    1774 
    1775 /*************************************************************************
    1776  *      PathSkipRootW   [SHLWAPI.@]
    1777  */
    1778 LPWSTR WINAPI PathSkipRootW(LPCWSTR pszPath)
    1779 {
    1780         FIXME("%s\n", debugstr_w(pszPath));
    1781         return (LPWSTR)pszPath;
    1782 }
    1783 #endif
    1784 
    1785 /*************************************************************************
    1786  *      PathCreateFromUrlA   [SHLWAPI.@]
    1787  */
    1788 HRESULT WINAPI PathCreateFromUrlA(
    1789         LPCSTR pszUrl,
    1790         LPSTR pszPath,
    1791         LPDWORD pcchPath,
    1792         DWORD dwFlags)
    1793 {
     2767  UINT flags = 0;
     2768
     2769  TRACE("(%d)\n", ch);
     2770
     2771  if (!ch || ch < ' ' || ch == '<' || ch == '>' ||
     2772      ch == '"' || ch == '|' || ch == 255)
     2773    flags = GCT_INVALID; /* Invalid */
     2774  else if (ch == '*' || ch=='?')
     2775    flags = GCT_WILD; /* Wildchars */
     2776  else if ((ch == '\\') || (ch=='/') || (ch == ':'))
     2777    return GCT_SEPARATOR; /* Path separators */
     2778  else
     2779  {
     2780     if (ch < 126)
     2781     {
     2782       if (!ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' ||
     2783            ch == '.' || ch == '@' || ch == '^' ||
     2784            ch == '\'' || ch == 130 || ch == '`')
     2785         flags |= GCT_SHORTCHAR; /* All these are valid for DOS */
     2786     }
     2787     else
     2788       if (!(ch & 0x1))
     2789         flags |= GCT_SHORTCHAR; /* Bug compatable with win32 */
     2790     flags |= GCT_LFNCHAR; /* Valid for long file names */
     2791  }
     2792  return flags;
     2793}
     2794
     2795/*************************************************************************
     2796 * SHLWAPI_UseSystemForSystemFolders
     2797 *
     2798 * Internal helper for PathMakeSystemFolderW.
     2799 */
     2800static BOOL SHLWAPI_UseSystemForSystemFolders()
     2801{
     2802  static BOOL bCheckedReg = FALSE;
     2803  static BOOL bUseSystemForSystemFolders = FALSE;
     2804
     2805  if (!bCheckedReg)
     2806  {
     2807    bCheckedReg = TRUE;
     2808
     2809    /* Key tells Win what file attributes to use on system folders */
     2810    if (SHGetValueA(HKEY_LOCAL_MACHINE,
     2811        "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
     2812        "UseSystemForSystemFolders", 0, 0, 0))
     2813      bUseSystemForSystemFolders = TRUE;
     2814  }
     2815  return bUseSystemForSystemFolders;
     2816}
     2817
     2818/*************************************************************************
     2819 * PathMakeSystemFolderA   [SHLWAPI.@]
     2820 *
     2821 * Set system folder attribute for a path.
     2822 *
     2823 * PARAMS
     2824 *  lpszPath [I] The path to turn into a system folder
     2825 *
     2826 * RETURNS
     2827 *  TRUE  If the path was changed to/already was a system folder
     2828 *  FALSE If the path is invalid or SetFileAttributesA fails
     2829 */
     2830BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath)
     2831{
     2832  BOOL bRet = FALSE;
     2833
     2834  TRACE("(%s)\n", debugstr_a(lpszPath));
     2835
     2836  if (lpszPath && *lpszPath)
     2837  {
     2838    WCHAR szPath[MAX_PATH];
     2839    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     2840    bRet = PathMakeSystemFolderW(szPath);
     2841  }
     2842  return bRet;
     2843}
     2844
     2845/*************************************************************************
     2846 * PathMakeSystemFolderW   [SHLWAPI.@]
     2847 *
     2848 * See PathMakeSystemFolderA.
     2849 */
     2850BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath)
     2851{
     2852  DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr;
     2853  WCHAR buff[MAX_PATH];
     2854
     2855  TRACE("(%s)\n", debugstr_w(lpszPath));
     2856
     2857  if (!lpszPath || !*lpszPath)
     2858    return FALSE;
     2859
     2860  /* If the directory is already a system directory, dont do anything */
     2861  GetSystemDirectoryW(buff, MAX_PATH);
     2862  if (!strcmpW(buff, lpszPath))
     2863    return TRUE;
     2864
     2865  GetWindowsDirectoryW(buff, MAX_PATH);
     2866  if (!strcmpW(buff, lpszPath))
     2867    return TRUE;
     2868
     2869  /* "UseSystemForSystemFolders" Tells Win what attributes to use */
     2870  if (SHLWAPI_UseSystemForSystemFolders())
     2871    dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM;
     2872
     2873  if ((dwAttr = GetFileAttributesW(lpszPath)) == -1)
     2874    return FALSE;
     2875
     2876  /* Change file attributes to system attributes */
     2877  dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY);
     2878  return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr);
     2879}
     2880
     2881/*************************************************************************
     2882 * PathRenameExtensionA   [SHLWAPI.@]
     2883 *
     2884 * Swap the file extension in a path with another extension.
     2885 *
     2886 * PARAMS
     2887 *  pszPath [O] Path to swap the extension in
     2888 *  pszExt  [I] The new extension
     2889 *
     2890 * RETURNS
     2891 *  TRUE  if pszPath was modified
     2892 *  FALSE if pszPath or pszExt is NULL, or the new path is too long
     2893 */
     2894BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt)
     2895{
     2896  LPSTR lpszExtension;
     2897
     2898  TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt));
     2899
     2900  lpszExtension = PathFindExtensionA(lpszPath);
     2901
     2902  if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH))
     2903    return FALSE;
     2904
     2905  strcpy(lpszExtension, lpszExt);
     2906  return TRUE;
     2907}
     2908
     2909/*************************************************************************
     2910 * PathRenameExtensionW   [SHLWAPI.@]
     2911 *
     2912 * See PathRenameExtensionA.
     2913 */
     2914BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt)
     2915{
     2916  LPWSTR lpszExtension;
     2917
     2918  TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt));
     2919
     2920  lpszExtension = PathFindExtensionW(lpszPath);
     2921
     2922  if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH))
     2923    return FALSE;
     2924
     2925  strcpyW(lpszExtension, lpszExt);
     2926  return TRUE;
     2927}
     2928
     2929/*************************************************************************
     2930 * PathSearchAndQualifyA   [SHLWAPI.@]
     2931 *
     2932 * Unimplemented.
     2933 *
     2934 * PARAMS
     2935 *  lpszPath [I]
     2936 *  lpszBuf  [O]
     2937 *  cchBuf   [I] Size of lpszBuf
     2938 *
     2939 * RETURNS
     2940 *  Unknown.
     2941 */
     2942BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf)
     2943{
     2944  FIXME("(%s,%p,0x%08x)-stub\n", debugstr_a(lpszPath), lpszBuf, cchBuf);
     2945  return FALSE;
     2946}
     2947
     2948/*************************************************************************
     2949 * PathSearchAndQualifyW   [SHLWAPI.@]
     2950 *
     2951 * See PathSearchAndQualifyA
     2952 */
     2953BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf)
     2954{
     2955  FIXME("(%s,%p,0x%08x)-stub\n", debugstr_w(lpszPath), lpszBuf, cchBuf);
     2956  return FALSE;
     2957}
     2958
     2959/*************************************************************************
     2960 * PathSkipRootA   [SHLWAPI.@]
     2961 *
     2962 * Return the portion of a path following the drive letter or mount point.
     2963 *
     2964 * PARAMS
     2965 *  lpszPath [I] The path to skip on
     2966 *
     2967 * RETURNS
     2968 *  Success: A pointer to the next character after the root.
     2969 *  Failure: NULL, if lpszPath is invalid, has no root or is a MB string.
     2970 */
     2971LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath)
     2972{
     2973  TRACE("(%s)\n", debugstr_a(lpszPath));
     2974
     2975  if (!lpszPath || !*lpszPath)
     2976    return NULL;
     2977
     2978  if (*lpszPath == '\\' && lpszPath[1] == '\\')
     2979  {
     2980    /* Network share: skip share server and mount point */
     2981    lpszPath += 2;
     2982    if ((lpszPath = StrChrA(lpszPath, '\\')) &&
     2983        (lpszPath = StrChrA(lpszPath + 1, '\\')))
     2984      lpszPath++;
     2985    return (LPSTR)lpszPath;
     2986  }
     2987
     2988  if (IsDBCSLeadByte(*lpszPath))
     2989    return NULL;
     2990
     2991  /* Check x:\ */
     2992  if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
     2993    return (LPSTR)lpszPath + 3;
     2994  return NULL;
     2995}
     2996
     2997/*************************************************************************
     2998 * PathSkipRootW   [SHLWAPI.@]
     2999 *
     3000 * See PathSkipRootA.
     3001 */
     3002LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath)
     3003{
     3004  TRACE("(%s)\n", debugstr_w(lpszPath));
     3005
     3006  if (!lpszPath || !*lpszPath)
     3007    return NULL;
     3008
     3009  if (*lpszPath == '\\' && lpszPath[1] == '\\')
     3010  {
     3011    /* Network share: skip share server and mount point */
     3012    lpszPath += 2;
     3013    if ((lpszPath = StrChrW(lpszPath, '\\')) &&
     3014        (lpszPath = StrChrW(lpszPath + 1, '\\')))
     3015     lpszPath++;
     3016    return (LPWSTR)lpszPath;
     3017  }
     3018
     3019  /* Check x:\ */
     3020  if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\')
     3021    return (LPWSTR)lpszPath + 3;
     3022  return NULL;
     3023}
     3024
     3025/*************************************************************************
     3026 * PathCreateFromUrlA   [SHLWAPI.@]
     3027 *
     3028 * Create a path from a URL
     3029 *
     3030 * PARAMS
     3031 *  lpszUrl  [I] URL to convert into a path
     3032 *  lpszPath [O] Output buffer for the resulting Path
     3033 *  pcchPath [I] Length of lpszPath
     3034 *  dwFlags  [I] Flags controlling the conversion
     3035 *
     3036 * RETURNS
     3037 *  Success: S_OK. lpszPath contains the URL in path format
     3038 *  Failure: An HRESULT error code such as E_INVALIDARG.
     3039 */
     3040HRESULT WINAPI PathCreateFromUrlA(LPCSTR lpszUrl, LPSTR lpszPath,
     3041                                  LPDWORD pcchPath, DWORD dwFlags)
     3042{
     3043  FIXME("(%s,%p,%p,0x%08lx)-stub\n", debugstr_a(lpszUrl), lpszPath, pcchPath, dwFlags);
     3044
     3045  if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath)
     3046    return E_INVALIDARG;
     3047
    17943048    /* extracts thing prior to : in pszURL and checks against:
    17953049     *   https
     
    17983052     *   about  - if match returns E_INVALIDARG
    17993053     */
    1800         FIXME("%s %p %p 0x%08lx\n",
    1801           pszUrl, pszPath, pcchPath, dwFlags);
    1802         return E_INVALIDARG;
    1803 }
    1804 
    1805 /*************************************************************************
    1806  *      PathCreateFromUrlW   [SHLWAPI.@]
    1807  */
    1808 HRESULT WINAPI PathCreateFromUrlW(
    1809         LPCWSTR pszUrl,
    1810         LPWSTR pszPath,
    1811         LPDWORD pcchPath,
    1812         DWORD dwFlags)
    1813 {
    1814     /* extracts thing prior to : in pszURL and checks against:
    1815      *   https
    1816      *   shell
    1817      *   local
    1818      *   about  - if match returns E_INVALIDARG
    1819      */
    1820         FIXME("%s %p %p 0x%08lx\n",
    1821           debugstr_w(pszUrl), pszPath, pcchPath, dwFlags);
    1822         return E_INVALIDARG;
    1823 }
    1824 
    1825 /*************************************************************************
    1826  *      PathRelativePathToA   [SHLWAPI.@]
    1827  */
    1828 BOOL WINAPI PathRelativePathToA(
    1829         LPSTR pszPath,
    1830         LPCSTR pszFrom,
    1831         DWORD dwAttrFrom,
    1832         LPCSTR pszTo,
    1833         DWORD dwAttrTo)
    1834 {
    1835         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
    1836           pszPath, pszFrom, dwAttrFrom, pszTo, dwAttrTo);
    1837         return FALSE;
    1838 }
    1839 
    1840 /*************************************************************************
    1841  *      PathRelativePathToW   [SHLWAPI.@]
    1842  */
    1843 BOOL WINAPI PathRelativePathToW(
    1844         LPWSTR pszPath,
    1845         LPCWSTR pszFrom,
    1846         DWORD dwAttrFrom,
    1847         LPCWSTR pszTo,
    1848         DWORD dwAttrTo)
    1849 {
    1850         FIXME("%s %s 0x%08lx %s 0x%08lx\n",
    1851           debugstr_w(pszPath), debugstr_w(pszFrom), dwAttrFrom, debugstr_w(pszTo), dwAttrTo);
    1852         return FALSE;
    1853 }
    1854 
    1855 /*************************************************************************
    1856  *      PathUnmakeSystemFolderA   [SHLWAPI.@]
    1857  */
    1858 BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR pszPath)
    1859 {
    1860         FIXME("%s\n", pszPath);
    1861         return FALSE;
    1862 }
    1863 
    1864 /*************************************************************************
    1865  *      PathUnmakeSystemFolderW   [SHLWAPI.@]
    1866  */
    1867 BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR pszPath)
    1868 {
    1869         FIXME("%s\n", debugstr_w(pszPath));
    1870         return FALSE;
    1871 }
    1872 
    1873 /*
    1874         ########## special ##########
    1875 */
     3054
     3055  return S_OK;
     3056}
     3057
     3058/*************************************************************************
     3059 * PathCreateFromUrlW   [SHLWAPI.@]
     3060 *
     3061 * See PathCreateFromUrlA.
     3062 */
     3063HRESULT WINAPI PathCreateFromUrlW(LPCWSTR lpszUrl, LPWSTR lpszPath,
     3064                                  LPDWORD pcchPath, DWORD dwFlags)
     3065{
     3066  FIXME("(%s,%p,%p,0x%08lx)-stub\n", debugstr_w(lpszUrl), lpszPath, pcchPath, dwFlags);
     3067
     3068  if (!lpszUrl || !lpszPath || !pcchPath || !*pcchPath)
     3069    return E_INVALIDARG;
     3070
     3071  return S_OK;
     3072}
     3073
     3074/*************************************************************************
     3075 * PathRelativePathToA   [SHLWAPI.@]
     3076 *
     3077 * Create a relative path from one path to another.
     3078 *
     3079 * PARAMS
     3080 *  lpszPath   [O] Destination for relative path
     3081 *  lpszFrom   [I] Source path
     3082 *  dwAttrFrom [I] File attribute of source path
     3083 *  lpszTo     [I] Destination path
     3084 *  dwAttrTo   [I] File attributes of destination path
     3085 *
     3086 * RETURNS
     3087 *  TRUE  If a relative path can be formed. lpszPath contains the new path
     3088 *  FALSE If the paths are not relavtive or any parameters are invalid
     3089 *
     3090 * NOTES
     3091 *  lpszTo should be at least MAX_PATH in length.
     3092 *  Calling this function with relative paths for lpszFrom or lpszTo may
     3093 *  give erroneous results.
     3094 *
     3095 *  The Win32 version of this function contains a bug where the lpszTo string
     3096 *  may be referenced 1 byte beyond the end of the string. As a result random
     3097 *  garbage may be written to the output path, depending on what lies beyond
     3098 *  the last byte of the string. This bug occurs because of the behaviour of
     3099 *  PathCommonPrefix (see notes for that function), and no workaround seems
     3100 *  possible with Win32.
     3101 *  This bug has been fixed here, so for example the relative path from "\\"
     3102 *  to "\\" is correctly determined as "." in this implementation.
     3103 */
     3104BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom,
     3105                                LPCSTR lpszTo, DWORD dwAttrTo)
     3106{
     3107  BOOL bRet = FALSE;
     3108
     3109  TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_a(lpszFrom),
     3110        dwAttrFrom, debugstr_a(lpszTo), dwAttrTo);
     3111
     3112  if(lpszPath && lpszFrom && lpszTo)
     3113  {
     3114    WCHAR szPath[MAX_PATH];
     3115    WCHAR szFrom[MAX_PATH];
     3116    WCHAR szTo[MAX_PATH];
     3117    MultiByteToWideChar(0,0,lpszFrom,-1,szFrom,MAX_PATH);
     3118    MultiByteToWideChar(0,0,lpszTo,-1,szTo,MAX_PATH);
     3119    bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo);
     3120    WideCharToMultiByte(0,0,szPath,-1,lpszPath,MAX_PATH,0,0);
     3121  }
     3122  return bRet;
     3123}
     3124
     3125/*************************************************************************
     3126 * PathRelativePathToW   [SHLWAPI.@]
     3127 *
     3128 * See PathRelativePathToA.
     3129 */
     3130BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom,
     3131                                LPCWSTR lpszTo, DWORD dwAttrTo)
     3132{
     3133  static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' };
     3134  static const WCHAR szPrevDir[] = { '.', '.', '\0' };
     3135  WCHAR szFrom[MAX_PATH];
     3136  WCHAR szTo[MAX_PATH];
     3137  DWORD dwLen;
     3138
     3139  TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_w(lpszFrom),
     3140        dwAttrFrom, debugstr_w(lpszTo), dwAttrTo);
     3141
     3142  if(!lpszPath || !lpszFrom || !lpszTo)
     3143    return FALSE;
     3144
     3145  *lpszPath = '\0';
     3146  strncpyW(szFrom, lpszFrom, MAX_PATH);
     3147  strncpyW(szTo, lpszTo, MAX_PATH);
     3148
     3149  if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
     3150    PathRemoveFileSpecW(szFrom);
     3151  if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY))
     3152    PathRemoveFileSpecW(szTo);
     3153
     3154  /* Paths can only be relative if they have a common root */
     3155  if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0)))
     3156    return FALSE;
     3157
     3158  /* Strip off lpszFrom components to the root, by adding "..\" */
     3159  lpszFrom = szFrom + dwLen;
     3160  if (!*lpszFrom)
     3161  {
     3162    lpszPath[0] = '.';
     3163    lpszPath[1] = '\0';
     3164  }
     3165  if (*lpszFrom == '\\')
     3166    lpszFrom++;
     3167
     3168  while (*lpszFrom)
     3169  {
     3170    lpszFrom = PathFindNextComponentW(lpszFrom);
     3171    strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir);
     3172  }
     3173
     3174  /* From the root add the components of lpszTo */
     3175  lpszTo += dwLen;
     3176  /* We check lpszTo[-1] to avoid skipping end of string. See the notes for
     3177   * this function.
     3178   */
     3179  if (*lpszTo && lpszTo[-1])
     3180  {
     3181    if (*lpszTo != '\\')
     3182      lpszTo--;
     3183    dwLen = strlenW(lpszPath);
     3184    if (dwLen + strlenW(lpszTo) >= MAX_PATH)
     3185    {
     3186      *lpszPath = '\0';
     3187      return FALSE;
     3188    }
     3189    strcpyW(lpszPath + dwLen, lpszTo);
     3190  }
     3191  return TRUE;
     3192}
     3193
     3194/*************************************************************************
     3195 * PathUnmakeSystemFolderA   [SHLWAPI.@]
     3196 *
     3197 * Remove the system folder attributes from a path.
     3198 *
     3199 * PARAMS
     3200 *  lpszPath [I] The path to remove attributes from
     3201 *
     3202 * RETURNS
     3203 *  Success: TRUE.
     3204 *  Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling
     3205 *           SetFileAttributesA fails.
     3206 */
     3207BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath)
     3208{
     3209  DWORD dwAttr;
     3210
     3211  TRACE("(%s)\n", debugstr_a(lpszPath));
     3212
     3213  if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == -1 ||
     3214      !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
     3215    return FALSE;
     3216
     3217  dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
     3218  return SetFileAttributesA(lpszPath, dwAttr);
     3219}
     3220
     3221/*************************************************************************
     3222 * PathUnmakeSystemFolderW   [SHLWAPI.@]
     3223 *
     3224 * See PathUnmakeSystemFolderA.
     3225 */
     3226BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath)
     3227{
     3228  DWORD dwAttr;
     3229
     3230  TRACE("(%s)\n", debugstr_w(lpszPath));
     3231
     3232  if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == -1 ||
     3233    !(dwAttr & FILE_ATTRIBUTE_DIRECTORY))
     3234    return FALSE;
     3235
     3236  dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
     3237  return SetFileAttributesW(lpszPath, dwAttr);
     3238}
     3239
    18763240
    18773241/*************************************************************************
    18783242 * PathSetDlgItemPathA   [SHLWAPI.@]
    18793243 *
     3244 * Set the text of a dialog item to a path, shrinking the path to fit
     3245 * if it is too big for the item.
     3246 *
     3247 * PARAMS
     3248 *  hDlg     [I] Dialog handle
     3249 *  id       [I] ID of item in the dialog
     3250 *  lpszPath [I] Path to set as the items text
     3251 *
     3252 * RETURNS
     3253 *  Nothing.
     3254 *
    18803255 * NOTES
    1881  *  use PathCompactPath to make sure, the path fits into the control
    1882  */
    1883 BOOL WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR pszPath)
    1884 {       TRACE("%x %x %s\n",hDlg, id, pszPath);
    1885         return SetDlgItemTextA(hDlg, id, pszPath);
     3256 *  If lpszPath is NULL, a blank string ("") is set (i.e. The previous
     3257 *  window text is erased).
     3258 */
     3259VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath)
     3260{
     3261  WCHAR szPath[MAX_PATH];
     3262
     3263  TRACE("(%8x,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath));
     3264
     3265  if (lpszPath)
     3266    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     3267  else
     3268    szPath[0] = '\0';
     3269  PathSetDlgItemPathW(hDlg, id, szPath);
    18863270}
    18873271
    18883272/*************************************************************************
    18893273 * PathSetDlgItemPathW   [SHLWAPI.@]
    1890  */
    1891 BOOL WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR pszPath)
    1892 {       TRACE("%x %x %s\n",hDlg, id, debugstr_w(pszPath));
    1893         return SetDlgItemTextW(hDlg, id, pszPath);
    1894 }
     3274 *
     3275 * See PathSetDlgItemPathA.
     3276 */
     3277VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath)
     3278{
     3279  WCHAR path[MAX_PATH + 1];
     3280  HWND hwItem;
     3281  RECT rect;
     3282  HDC hdc;
     3283  HGDIOBJ hPrevObj;
     3284
     3285  TRACE("(%8x,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath));
     3286
     3287  if (!(hwItem = GetDlgItem(hDlg, id)))
     3288    return;
     3289
     3290  if (lpszPath)
     3291    strncpyW(path, lpszPath, sizeof(path));
     3292  else
     3293    path[0] = '\0';
     3294
     3295  GetClientRect(hwItem, &rect);
     3296  hdc = GetDC(hDlg);
     3297  hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0));
     3298
     3299  if (hPrevObj)
     3300  {
     3301    PathCompactPathW(hdc, path, rect.right);
     3302    SelectObject(hdc, hPrevObj);
     3303  }
     3304
     3305  ReleaseDC(hDlg, hdc);
     3306  SetWindowTextW(hwItem, path);
     3307}
     3308
     3309/*************************************************************************
     3310 * PathIsNetworkPathA [SHLWAPI.@]
     3311 *
     3312 * Determine if the given path is a network path.
     3313 *
     3314 * PARAMS
     3315 *  lpszPath [I] Path to check
     3316 *
     3317 * RETURNS
     3318 *  TRUE  If path is a UNC share or mapped network drive
     3319 *  FALSE If path is a local drive or cannot be determined
     3320 */
     3321BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath)
     3322{
     3323  DWORD dwDriveNum;
     3324
     3325  TRACE("(%s)\n",debugstr_a(lpszPath));
     3326
     3327  if (!lpszPath)
     3328    return FALSE;
     3329  if (*lpszPath == '\\' && lpszPath[1] == '\\')
     3330    return TRUE;
     3331  dwDriveNum = PathGetDriveNumberA(lpszPath);
     3332  if (dwDriveNum == -1)
     3333    return FALSE;
     3334  GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
     3335  return pIsNetDrive(dwDriveNum);
     3336}
     3337
     3338/*************************************************************************
     3339 * PathIsNetworkPathW [SHLWAPI.@]
     3340 *
     3341 * See PathIsNetworkPathA.
     3342 */
     3343BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath)
     3344{
     3345  DWORD dwDriveNum;
     3346
     3347  TRACE("(%s)\n", debugstr_w(lpszPath));
     3348
     3349  if (!lpszPath)
     3350    return FALSE;
     3351  if (*lpszPath == '\\' && lpszPath[1] == '\\')
     3352    return TRUE;
     3353  dwDriveNum = PathGetDriveNumberW(lpszPath);
     3354  if (dwDriveNum == -1)
     3355    return FALSE;
     3356  GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */
     3357  return pIsNetDrive(dwDriveNum);
     3358}
     3359
     3360/*************************************************************************
     3361 * PathIsLFNFileSpecA [SHLWAPI.@]
     3362 *
     3363 * Determine if the given path is a long file name
     3364 *
     3365 * PARAMS
     3366 *  lpszPath [I] Path to check
     3367 *
     3368 * RETURNS
     3369 *  TRUE  If path is a long file name
     3370 *  FALSE If path is a valid DOS 8.3 file name
     3371 */
     3372BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath)
     3373{
     3374  DWORD dwNameLen = 0, dwExtLen = 0;
     3375
     3376  TRACE("(%s)\n",debugstr_a(lpszPath));
     3377
     3378  if (!lpszPath)
     3379    return FALSE;
     3380
     3381  while (*lpszPath)
     3382  {
     3383    if (*lpszPath == ' ')
     3384      return TRUE; /* DOS names cannot have spaces */
     3385    if (*lpszPath == '.')
     3386    {
     3387      if (dwExtLen)
     3388        return TRUE; /* DOS names have only one dot */
     3389      dwExtLen = 1;
     3390    }
     3391    else if (dwExtLen)
     3392    {
     3393      dwExtLen++;
     3394      if (dwExtLen > 4)
     3395        return TRUE; /* DOS extensions are <= 3 chars*/
     3396    }
     3397    else
     3398    {
     3399      dwNameLen++;
     3400      if (dwNameLen > 8)
     3401        return TRUE; /* DOS names are <= 8 chars */
     3402    }
     3403    lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1;
     3404  }
     3405  return FALSE; /* Valid DOS path */
     3406}
     3407
     3408/*************************************************************************
     3409 * PathIsLFNFileSpecW [SHLWAPI.@]
     3410 *
     3411 * See PathIsLFNFileSpecA.
     3412 */
     3413BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath)
     3414{
     3415  DWORD dwNameLen = 0, dwExtLen = 0;
     3416
     3417  TRACE("(%s)\n",debugstr_w(lpszPath));
     3418
     3419  if (!lpszPath)
     3420    return FALSE;
     3421
     3422  while (*lpszPath)
     3423  {
     3424    if (*lpszPath == ' ')
     3425      return TRUE; /* DOS names cannot have spaces */
     3426    if (*lpszPath == '.')
     3427    {
     3428      if (dwExtLen)
     3429        return TRUE; /* DOS names have only one dot */
     3430      dwExtLen = 1;
     3431    }
     3432    else if (dwExtLen)
     3433    {
     3434      dwExtLen++;
     3435      if (dwExtLen > 4)
     3436        return TRUE; /* DOS extensions are <= 3 chars*/
     3437    }
     3438    else
     3439    {
     3440      dwNameLen++;
     3441      if (dwNameLen > 8)
     3442        return TRUE; /* DOS names are <= 8 chars */
     3443    }
     3444    lpszPath++;
     3445  }
     3446  return FALSE; /* Valid DOS path */
     3447}
     3448
     3449/*************************************************************************
     3450 * PathIsDirectoryEmptyA [SHLWAPI.@]
     3451 *
     3452 * Determine if a given directory is empty.
     3453 *
     3454 * PARAMS
     3455 *  lpszPath [I] Directory to check
     3456 *
     3457 * RETURNS
     3458 *  TRUE  If the directory exists and contains no files
     3459 *  FALSE Otherwise
     3460 */
     3461BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath)
     3462{
     3463  BOOL bRet = FALSE;
     3464
     3465  TRACE("(%s)\n",debugstr_a(lpszPath));
     3466
     3467  if (lpszPath)
     3468  {
     3469    WCHAR szPath[MAX_PATH];
     3470    MultiByteToWideChar(0,0,lpszPath,-1,szPath,MAX_PATH);
     3471    bRet = PathIsDirectoryEmptyW(szPath);
     3472  }
     3473  return bRet;
     3474}
     3475
     3476/*************************************************************************
     3477 * PathIsDirectoryEmptyW [SHLWAPI.@]
     3478 *
     3479 * See PathIsDirectoryEmptyA.
     3480 */
     3481BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath)
     3482{
     3483  static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' };
     3484  WCHAR szSearch[MAX_PATH];
     3485  DWORD dwLen;
     3486  HANDLE hfind;
     3487  BOOL retVal = FALSE;
     3488  WIN32_FIND_DATAW find_data;
     3489
     3490  TRACE("(%s)\n",debugstr_w(lpszPath));
     3491
     3492  if (!lpszPath || !PathIsDirectoryW(lpszPath))
     3493      return FALSE;
     3494
     3495  strncpyW(szSearch, lpszPath, MAX_PATH);
     3496  PathAddBackslashW(szSearch);
     3497  dwLen = strlenW(szSearch);
     3498  if (dwLen > MAX_PATH - 4)
     3499    return FALSE;
     3500
     3501  strcpyW(szSearch + dwLen, szAllFiles);
     3502  hfind = FindFirstFileW(szSearch, &find_data);
     3503
     3504  if (hfind != INVALID_HANDLE_VALUE &&
     3505      find_data.cFileName[0] == '.' &&
     3506      find_data.cFileName[1] == '.')
     3507  {
     3508    /* The only directory entry should be the parent */
     3509    if (!FindNextFileW(hfind, &find_data))
     3510      retVal = TRUE;
     3511    FindClose(hfind);
     3512  }
     3513  return retVal;
     3514}
     3515
     3516
     3517/*************************************************************************
     3518 * PathFindSuffixArrayA [SHLWAPI.@]
     3519 *
     3520 * Find a suffix string in an array of suffix strings
     3521 *
     3522 * PARAMS
     3523 *  lpszSuffix [I] Suffix string to search for
     3524 *  lppszArray [I] Array of suffix strings to search
     3525 *  dwCount    [I] Number of elements in lppszArray
     3526 *
     3527 * RETURNS
     3528 *  Success The index of the position of lpszSuffix in lppszArray
     3529 *  Failure 0, if any parameters are invalid or lpszSuffix is not found
     3530 *
     3531 * NOTES
     3532 *  The search is case sensitive.
     3533 *  The match is made against the end of the suffix string, so for example:
     3534 *  lpszSuffix=fooBAR matches BAR, but lpszSuffix=fooBARfoo does not.
     3535 */
     3536int WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount)
     3537{
     3538  DWORD dwLen;
     3539  int dwRet = 0;
     3540
     3541  TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount);
     3542
     3543  if (lpszSuffix && lppszArray && dwCount > 0)
     3544  {
     3545    dwLen = strlen(lpszSuffix);
     3546
     3547    while (dwRet < dwCount)
     3548    {
     3549      DWORD dwCompareLen = strlen(*lppszArray);
     3550      if (dwCompareLen < dwLen)
     3551      {
     3552        if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
     3553          return dwRet; /* Found */
     3554      }
     3555      dwRet++;
     3556      lppszArray++;
     3557    }
     3558  }
     3559  return 0;
     3560}
     3561
     3562/*************************************************************************
     3563 * PathFindSuffixArrayW [SHLWAPI.@]
     3564 *
     3565 * See PathFindSuffixArrayA.
     3566 */
     3567int WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount)
     3568{
     3569  DWORD dwLen;
     3570  int dwRet = 0;
     3571
     3572  TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount);
     3573
     3574  if (lpszSuffix && lppszArray && dwCount > 0)
     3575  {
     3576    dwLen = strlenW(lpszSuffix);
     3577
     3578    while (dwRet < dwCount)
     3579    {
     3580      DWORD dwCompareLen = strlenW(*lppszArray);
     3581      if (dwCompareLen < dwLen)
     3582      {
     3583        if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray))
     3584          return dwRet; /* Found */
     3585      }
     3586      dwRet++;
     3587      lppszArray++;
     3588    }
     3589  }
     3590  return 0;
     3591}
     3592
     3593/*************************************************************************
     3594 * PathUndecorateA [SHLWAPI.@]
     3595 *
     3596 * Undecorate a file path
     3597 *
     3598 * PARAMS
     3599 *  lpszPath [O] Path to undecorate
     3600 *
     3601 * RETURNS
     3602 *  Nothing
     3603 *
     3604 * NOTES
     3605 *  A decorations form is "path[n].ext" where n is an optional decimal number.
     3606 */
     3607VOID WINAPI PathUndecorateA(LPSTR lpszPath)
     3608{
     3609  TRACE("(%s)\n",debugstr_a(lpszPath));
     3610
     3611  if (lpszPath)
     3612  {
     3613    LPSTR lpszExt = PathFindExtensionA(lpszPath);
     3614    if (lpszExt > lpszPath && lpszExt[-1] == ']')
     3615    {
     3616      LPSTR lpszSkip = lpszExt - 2;
     3617      if (*lpszSkip == '[')
     3618        lpszSkip++;  /* [] (no number) */
     3619      else
     3620        while (lpszSkip > lpszPath && isdigit(lpszSkip[-1]))
     3621          lpszSkip--;
     3622      if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
     3623      {
     3624        /* remove the [n] */
     3625        lpszSkip--;
     3626        while (*lpszExt)
     3627          *lpszSkip++ = *lpszExt++;
     3628        *lpszSkip = '\0';
     3629      }
     3630    }
     3631  }
     3632}
     3633
     3634/*************************************************************************
     3635 * PathUndecorateW [SHLWAPI.@]
     3636 *
     3637 * See PathUndecorateA.
     3638 */
     3639VOID WINAPI PathUndecorateW(LPWSTR lpszPath)
     3640{
     3641  TRACE("(%s)\n",debugstr_w(lpszPath));
     3642
     3643  if (lpszPath)
     3644  {
     3645    LPWSTR lpszExt = PathFindExtensionW(lpszPath);
     3646    if (lpszExt > lpszPath && lpszExt[-1] == ']')
     3647    {
     3648      LPWSTR lpszSkip = lpszExt - 2;
     3649      if (*lpszSkip == '[')
     3650        lpszSkip++; /* [] (no number) */
     3651      else
     3652        while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1]))
     3653          lpszSkip--;
     3654      if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\')
     3655      {
     3656        /* remove the [n] */
     3657        lpszSkip--;
     3658        while (*lpszExt)
     3659          *lpszSkip++ = *lpszExt++;
     3660        *lpszSkip = '\0';
     3661      }
     3662    }
     3663  }
     3664}
Note: See TracChangeset for help on using the changeset viewer.