kernelbase: Duplicate some path handling functions from shlwapi.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7c02ab5ed1
commit
44ac5af07a
|
@ -1020,16 +1020,16 @@
|
|||
# @ stub ParseApplicationUserModelId
|
||||
@ stdcall ParseURLA(str ptr) shlwapi.ParseURLA
|
||||
@ stdcall ParseURLW(wstr ptr) shlwapi.ParseURLW
|
||||
@ stdcall PathAddBackslashA(str) shlwapi.PathAddBackslashA
|
||||
@ stdcall PathAddBackslashW(wstr) shlwapi.PathAddBackslashW
|
||||
@ stdcall PathAddExtensionA(str str) shlwapi.PathAddExtensionA
|
||||
@ stdcall PathAddExtensionW(wstr wstr) shlwapi.PathAddExtensionW
|
||||
@ stdcall PathAddBackslashA(str)
|
||||
@ stdcall PathAddBackslashW(wstr)
|
||||
@ stdcall PathAddExtensionA(str str)
|
||||
@ stdcall PathAddExtensionW(wstr wstr)
|
||||
@ stdcall PathAllocCanonicalize(wstr long ptr)
|
||||
@ stdcall PathAllocCombine(wstr wstr long ptr)
|
||||
@ stdcall PathAppendA(str str) shlwapi.PathAppendA
|
||||
@ stdcall PathAppendW(wstr wstr) shlwapi.PathAppendW
|
||||
@ stdcall PathCanonicalizeA(ptr str) shlwapi.PathCanonicalizeA
|
||||
@ stdcall PathCanonicalizeW(ptr wstr) shlwapi.PathCanonicalizeW
|
||||
@ stdcall PathAppendA(str str)
|
||||
@ stdcall PathAppendW(wstr wstr)
|
||||
@ stdcall PathCanonicalizeA(ptr str)
|
||||
@ stdcall PathCanonicalizeW(ptr wstr)
|
||||
@ stdcall PathCchAddBackslash(wstr long)
|
||||
@ stdcall PathCchAddBackslashEx(wstr long ptr ptr)
|
||||
@ stdcall PathCchAddExtension(wstr long wstr)
|
||||
|
@ -1049,17 +1049,17 @@
|
|||
@ stdcall PathCchSkipRoot(wstr ptr)
|
||||
@ stdcall PathCchStripPrefix(wstr long)
|
||||
@ stdcall PathCchStripToRoot(wstr long)
|
||||
@ stdcall PathCombineA(ptr str str) shlwapi.PathCombineA
|
||||
@ stdcall PathCombineW(ptr wstr wstr) shlwapi.PathCombineW
|
||||
@ stdcall PathCommonPrefixA(str str ptr) shlwapi.PathCommonPrefixA
|
||||
@ stdcall PathCommonPrefixW(wstr wstr ptr) shlwapi.PathCommonPrefixW
|
||||
@ stdcall PathCombineA(ptr str str)
|
||||
@ stdcall PathCombineW(ptr wstr wstr)
|
||||
@ stdcall PathCommonPrefixA(str str ptr)
|
||||
@ stdcall PathCommonPrefixW(wstr wstr ptr)
|
||||
@ stdcall PathCreateFromUrlA(str ptr ptr long) shlwapi.PathCreateFromUrlA
|
||||
@ stdcall PathCreateFromUrlAlloc(wstr ptr long) shlwapi.PathCreateFromUrlAlloc
|
||||
@ stdcall PathCreateFromUrlW(wstr ptr ptr long) shlwapi.PathCreateFromUrlW
|
||||
@ stdcall PathFileExistsA(str) shlwapi.PathFileExistsA
|
||||
@ stdcall PathFileExistsW(wstr) shlwapi.PathFileExistsW
|
||||
@ stdcall PathFindExtensionA(str) shlwapi.PathFindExtensionA
|
||||
@ stdcall PathFindExtensionW(wstr) shlwapi.PathFindExtensionW
|
||||
@ stdcall PathFindExtensionA(str)
|
||||
@ stdcall PathFindExtensionW(wstr)
|
||||
@ stdcall PathFindFileNameA(str) shlwapi.PathFindFileNameA
|
||||
@ stdcall PathFindFileNameW(wstr) shlwapi.PathFindFileNameW
|
||||
@ stdcall PathFindNextComponentA(str) shlwapi.PathFindNextComponentA
|
||||
|
@ -1074,21 +1074,21 @@
|
|||
@ stdcall PathIsFileSpecW(wstr) shlwapi.PathIsFileSpecW
|
||||
@ stdcall PathIsLFNFileSpecA(str) shlwapi.PathIsLFNFileSpecA
|
||||
@ stdcall PathIsLFNFileSpecW(wstr) shlwapi.PathIsLFNFileSpecW
|
||||
@ stdcall PathIsPrefixA(str str) shlwapi.PathIsPrefixA
|
||||
@ stdcall PathIsPrefixW(wstr wstr) shlwapi.PathIsPrefixW
|
||||
@ stdcall PathIsRelativeA(str) shlwapi.PathIsRelativeA
|
||||
@ stdcall PathIsRelativeW(wstr) shlwapi.PathIsRelativeW
|
||||
@ stdcall PathIsRootA(str) shlwapi.PathIsRootA
|
||||
@ stdcall PathIsRootW(wstr) shlwapi.PathIsRootW
|
||||
@ stdcall PathIsPrefixA(str str)
|
||||
@ stdcall PathIsPrefixW(wstr wstr)
|
||||
@ stdcall PathIsRelativeA(str)
|
||||
@ stdcall PathIsRelativeW(wstr)
|
||||
@ stdcall PathIsRootA(str)
|
||||
@ stdcall PathIsRootW(wstr)
|
||||
@ stdcall PathIsSameRootA(str str) shlwapi.PathIsSameRootA
|
||||
@ stdcall PathIsSameRootW(wstr wstr) shlwapi.PathIsSameRootW
|
||||
@ stdcall PathIsUNCA(str) shlwapi.PathIsUNCA
|
||||
@ stdcall PathIsUNCA(str)
|
||||
@ stdcall PathIsUNCEx(wstr ptr)
|
||||
@ stdcall PathIsUNCServerA(str) shlwapi.PathIsUNCServerA
|
||||
@ stdcall PathIsUNCServerShareA(str) shlwapi.PathIsUNCServerShareA
|
||||
@ stdcall PathIsUNCServerShareW(wstr) shlwapi.PathIsUNCServerShareW
|
||||
@ stdcall PathIsUNCServerShareA(str)
|
||||
@ stdcall PathIsUNCServerShareW(wstr)
|
||||
@ stdcall PathIsUNCServerW(wstr) shlwapi.PathIsUNCServerW
|
||||
@ stdcall PathIsUNCW(wstr) shlwapi.PathIsUNCW
|
||||
@ stdcall PathIsUNCW(wstr)
|
||||
@ stdcall PathIsURLA(str) shlwapi.PathIsURLA
|
||||
@ stdcall PathIsURLW(wstr) shlwapi.PathIsURLW
|
||||
@ stdcall PathIsValidCharA(long long) shlwapi.PathIsValidCharA
|
||||
|
@ -1109,8 +1109,8 @@
|
|||
@ stdcall PathRemoveBlanksW(wstr) shlwapi.PathRemoveBlanksW
|
||||
@ stdcall PathRemoveExtensionA(str) shlwapi.PathRemoveExtensionA
|
||||
@ stdcall PathRemoveExtensionW(wstr) shlwapi.PathRemoveExtensionW
|
||||
@ stdcall PathRemoveFileSpecA(str) shlwapi.PathRemoveFileSpecA
|
||||
@ stdcall PathRemoveFileSpecW(wstr) shlwapi.PathRemoveFileSpecW
|
||||
@ stdcall PathRemoveFileSpecA(str)
|
||||
@ stdcall PathRemoveFileSpecW(wstr)
|
||||
@ stdcall PathRenameExtensionA(str str) shlwapi.PathRenameExtensionA
|
||||
@ stdcall PathRenameExtensionW(wstr wstr) shlwapi.PathRenameExtensionW
|
||||
@ stdcall PathSearchAndQualifyA(str ptr long) shlwapi.PathSearchAndQualifyA
|
||||
|
@ -1120,7 +1120,7 @@
|
|||
@ stdcall PathStripPathA(str) shlwapi.PathStripPathA
|
||||
@ stdcall PathStripPathW(wstr) shlwapi.PathStripPathW
|
||||
@ stdcall PathStripToRootA(str) shlwapi.PathStripToRootA
|
||||
@ stdcall PathStripToRootW(wstr) shlwapi.PathStripToRootW
|
||||
@ stdcall PathStripToRootW(wstr)
|
||||
@ stdcall PathUnExpandEnvStringsA(str ptr long) shlwapi.PathUnExpandEnvStringsA
|
||||
@ stdcall PathUnExpandEnvStringsW(wstr ptr long) shlwapi.PathUnExpandEnvStringsW
|
||||
@ stdcall PathUnquoteSpacesA(str) shlwapi.PathUnquoteSpacesA
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(path);
|
||||
|
||||
char *char_next(const char *ptr)
|
||||
{
|
||||
if (!*ptr) return (LPSTR)ptr;
|
||||
if (IsDBCSLeadByte( ptr[0] ) && ptr[1]) return (LPSTR)(ptr + 2);
|
||||
return (LPSTR)(ptr + 1);
|
||||
}
|
||||
|
||||
static SIZE_T strnlenW(const WCHAR *string, SIZE_T maxlen)
|
||||
{
|
||||
SIZE_T i;
|
||||
|
@ -865,3 +872,749 @@ BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server)
|
|||
if (server) *server = result;
|
||||
return !!result;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsUNCA(const char *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
return path && (path[0] == '\\') && (path[1] == '\\');
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsUNCW(const WCHAR *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
return path && (path[0] == '\\') && (path[1] == '\\');
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsRelativeA(const char *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (!path || !*path || IsDBCSLeadByte(*path))
|
||||
return TRUE;
|
||||
|
||||
return !(*path == '\\' || (*path && path[1] == ':'));
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsRelativeW(const WCHAR *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (!path || !*path)
|
||||
return TRUE;
|
||||
|
||||
return !(*path == '\\' || (*path && path[1] == ':'));
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsUNCServerShareA(const char *path)
|
||||
{
|
||||
BOOL seen_slash = FALSE;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (path && *path++ == '\\' && *path++ == '\\')
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (seen_slash)
|
||||
return FALSE;
|
||||
seen_slash = TRUE;
|
||||
}
|
||||
|
||||
path = char_next(path);
|
||||
}
|
||||
}
|
||||
|
||||
return seen_slash;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsUNCServerShareW(const WCHAR *path)
|
||||
{
|
||||
BOOL seen_slash = FALSE;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (path && *path++ == '\\' && *path++ == '\\')
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (seen_slash)
|
||||
return FALSE;
|
||||
seen_slash = TRUE;
|
||||
}
|
||||
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
return seen_slash;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsRootA(const char *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (!path || !*path)
|
||||
return FALSE;
|
||||
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (!path[1])
|
||||
return TRUE; /* \ */
|
||||
else if (path[1] == '\\')
|
||||
{
|
||||
BOOL seen_slash = FALSE;
|
||||
path += 2;
|
||||
|
||||
/* Check for UNC root path */
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (seen_slash)
|
||||
return FALSE;
|
||||
seen_slash = TRUE;
|
||||
}
|
||||
|
||||
path = char_next(path);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (path[1] == ':' && path[2] == '\\' && path[3] == '\0')
|
||||
return TRUE; /* X:\ */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsRootW(const WCHAR *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (!path || !*path)
|
||||
return FALSE;
|
||||
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (!path[1])
|
||||
return TRUE; /* \ */
|
||||
else if (path[1] == '\\')
|
||||
{
|
||||
BOOL seen_slash = FALSE;
|
||||
|
||||
path += 2;
|
||||
/* Check for UNC root path */
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
{
|
||||
if (seen_slash)
|
||||
return FALSE;
|
||||
seen_slash = TRUE;
|
||||
}
|
||||
path++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (path[1] == ':' && path[2] == '\\' && path[3] == '\0')
|
||||
return TRUE; /* X:\ */
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathRemoveFileSpecA(char *path)
|
||||
{
|
||||
char *filespec = path;
|
||||
BOOL modified = FALSE;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
/* Skip directory or UNC path */
|
||||
if (*path == '\\')
|
||||
filespec = ++path;
|
||||
if (*path == '\\')
|
||||
filespec = ++path;
|
||||
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
filespec = path; /* Skip dir */
|
||||
else if (*path == ':')
|
||||
{
|
||||
filespec = ++path; /* Skip drive */
|
||||
if (*path == '\\')
|
||||
filespec++;
|
||||
}
|
||||
if (!(path = char_next(path)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (*filespec)
|
||||
{
|
||||
*filespec = '\0';
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathRemoveFileSpecW(WCHAR *path)
|
||||
{
|
||||
WCHAR *filespec = path;
|
||||
BOOL modified = FALSE;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
/* Skip directory or UNC path */
|
||||
if (*path == '\\')
|
||||
filespec = ++path;
|
||||
if (*path == '\\')
|
||||
filespec = ++path;
|
||||
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\')
|
||||
filespec = path; /* Skip dir */
|
||||
else if (*path == ':')
|
||||
{
|
||||
filespec = ++path; /* Skip drive */
|
||||
if (*path == '\\')
|
||||
filespec++;
|
||||
}
|
||||
|
||||
path++;
|
||||
}
|
||||
|
||||
if (*filespec)
|
||||
{
|
||||
*filespec = '\0';
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathStripToRootA(char *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
while (!PathIsRootA(path))
|
||||
if (!PathRemoveFileSpecA(path))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathStripToRootW(WCHAR *path)
|
||||
{
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
while (!PathIsRootW(path))
|
||||
if (!PathRemoveFileSpecW(path))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LPSTR WINAPI PathAddBackslashA(char *path)
|
||||
{
|
||||
unsigned int len;
|
||||
char *prev = path;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (!path || (len = strlen(path)) >= MAX_PATH)
|
||||
return NULL;
|
||||
|
||||
if (len)
|
||||
{
|
||||
do
|
||||
{
|
||||
path = char_next(prev);
|
||||
if (*path)
|
||||
prev = path;
|
||||
} while (*path);
|
||||
|
||||
if (*prev != '\\')
|
||||
{
|
||||
*path++ = '\\';
|
||||
*path = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
LPWSTR WINAPI PathAddBackslashW(WCHAR *path)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (!path || (len = strlenW(path)) >= MAX_PATH)
|
||||
return NULL;
|
||||
|
||||
if (len)
|
||||
{
|
||||
path += len;
|
||||
if (path[-1] != '\\')
|
||||
{
|
||||
*path++ = '\\';
|
||||
*path = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
LPSTR WINAPI PathFindExtensionA(const char *path)
|
||||
{
|
||||
const char *lastpoint = NULL;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_a(path));
|
||||
|
||||
if (path)
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\' || *path == ' ')
|
||||
lastpoint = NULL;
|
||||
else if (*path == '.')
|
||||
lastpoint = path;
|
||||
path = char_next(path);
|
||||
}
|
||||
}
|
||||
|
||||
return (LPSTR)(lastpoint ? lastpoint : path);
|
||||
}
|
||||
|
||||
LPWSTR WINAPI PathFindExtensionW(const WCHAR *path)
|
||||
{
|
||||
const WCHAR *lastpoint = NULL;
|
||||
|
||||
TRACE("%s\n", wine_dbgstr_w(path));
|
||||
|
||||
if (path)
|
||||
{
|
||||
while (*path)
|
||||
{
|
||||
if (*path == '\\' || *path == ' ')
|
||||
lastpoint = NULL;
|
||||
else if (*path == '.')
|
||||
lastpoint = path;
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
return (LPWSTR)(lastpoint ? lastpoint : path);
|
||||
}
|
||||
|
||||
BOOL WINAPI PathAddExtensionA(char *path, const char *ext)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(ext));
|
||||
|
||||
if (!path || !ext || *(PathFindExtensionA(path)))
|
||||
return FALSE;
|
||||
|
||||
len = strlen(path);
|
||||
if (len + strlen(ext) >= MAX_PATH)
|
||||
return FALSE;
|
||||
|
||||
strcpy(path + len, ext);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathAddExtensionW(WCHAR *path, const WCHAR *ext)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(ext));
|
||||
|
||||
if (!path || !ext || *(PathFindExtensionW(path)))
|
||||
return FALSE;
|
||||
|
||||
len = strlenW(path);
|
||||
if (len + strlenW(ext) >= MAX_PATH)
|
||||
return FALSE;
|
||||
|
||||
strcpyW(path + len, ext);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathCanonicalizeW(WCHAR *buffer, const WCHAR *path)
|
||||
{
|
||||
const WCHAR *src = path;
|
||||
WCHAR *dst = buffer;
|
||||
|
||||
TRACE("%p, %s\n", buffer, wine_dbgstr_w(path));
|
||||
|
||||
if (dst)
|
||||
*dst = '\0';
|
||||
|
||||
if (!dst || !path)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!*path)
|
||||
{
|
||||
*buffer++ = '\\';
|
||||
*buffer = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Copy path root */
|
||||
if (*src == '\\')
|
||||
{
|
||||
*dst++ = *src++;
|
||||
}
|
||||
else if (*src && src[1] == ':')
|
||||
{
|
||||
/* X:\ */
|
||||
*dst++ = *src++;
|
||||
*dst++ = *src++;
|
||||
if (*src == '\\')
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
/* Canonicalize the rest of the path */
|
||||
while (*src)
|
||||
{
|
||||
if (*src == '.')
|
||||
{
|
||||
if (src[1] == '\\' && (src == path || src[-1] == '\\' || src[-1] == ':'))
|
||||
{
|
||||
src += 2; /* Skip .\ */
|
||||
}
|
||||
else if (src[1] == '.' && (dst == buffer || dst[-1] == '\\'))
|
||||
{
|
||||
/* \.. backs up a directory, over the root if it has no \ following X:.
|
||||
* .. is ignored if it would remove a UNC server name or initial \\
|
||||
*/
|
||||
if (dst != buffer)
|
||||
{
|
||||
*dst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */
|
||||
if (dst > buffer + 1 && dst[-1] == '\\' && (dst[-2] != '\\' || dst > buffer + 2))
|
||||
{
|
||||
if (dst[-2] == ':' && (dst > buffer + 3 || dst[-3] == ':'))
|
||||
{
|
||||
dst -= 2;
|
||||
while (dst > buffer && *dst != '\\')
|
||||
dst--;
|
||||
if (*dst == '\\')
|
||||
dst++; /* Reset to last '\' */
|
||||
else
|
||||
dst = buffer; /* Start path again from new root */
|
||||
}
|
||||
else if (dst[-2] != ':' && !PathIsUNCServerShareW(buffer))
|
||||
dst -= 2;
|
||||
}
|
||||
while (dst > buffer && *dst != '\\')
|
||||
dst--;
|
||||
if (dst == buffer)
|
||||
{
|
||||
*dst++ = '\\';
|
||||
src++;
|
||||
}
|
||||
}
|
||||
src += 2; /* Skip .. in src path */
|
||||
}
|
||||
else
|
||||
*dst++ = *src++;
|
||||
}
|
||||
else
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
/* Append \ to naked drive specs */
|
||||
if (dst - buffer == 2 && dst[-1] == ':')
|
||||
*dst++ = '\\';
|
||||
*dst++ = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathCanonicalizeA(char *buffer, const char *path)
|
||||
{
|
||||
WCHAR pathW[MAX_PATH], bufferW[MAX_PATH];
|
||||
BOOL ret;
|
||||
int len;
|
||||
|
||||
TRACE("%p, %s\n", buffer, wine_dbgstr_a(path));
|
||||
|
||||
if (buffer)
|
||||
*buffer = '\0';
|
||||
|
||||
if (!buffer || !path)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
len = MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, ARRAY_SIZE(pathW));
|
||||
if (!len)
|
||||
return FALSE;
|
||||
|
||||
ret = PathCanonicalizeW(bufferW, pathW);
|
||||
WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, 0, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
WCHAR * WINAPI PathCombineW(WCHAR *dst, const WCHAR *dir, const WCHAR *file)
|
||||
{
|
||||
BOOL use_both = FALSE, strip = FALSE;
|
||||
WCHAR tmp[MAX_PATH];
|
||||
|
||||
TRACE("%p, %s, %s\n", dst, wine_dbgstr_w(dir), wine_dbgstr_w(file));
|
||||
|
||||
/* Invalid parameters */
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
if (!dir && !file)
|
||||
{
|
||||
dst[0] = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((!file || !*file) && dir)
|
||||
{
|
||||
/* Use dir only */
|
||||
lstrcpynW(tmp, dir, ARRAY_SIZE(tmp));
|
||||
}
|
||||
else if (!dir || !*dir || !PathIsRelativeW(file))
|
||||
{
|
||||
if (!dir || !*dir || *file != '\\' || PathIsUNCW(file))
|
||||
{
|
||||
/* Use file only */
|
||||
lstrcpynW(tmp, file, ARRAY_SIZE(tmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
use_both = TRUE;
|
||||
strip = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
use_both = TRUE;
|
||||
|
||||
if (use_both)
|
||||
{
|
||||
lstrcpynW(tmp, dir, ARRAY_SIZE(tmp));
|
||||
if (strip)
|
||||
{
|
||||
PathStripToRootW(tmp);
|
||||
file++; /* Skip '\' */
|
||||
}
|
||||
|
||||
if (!PathAddBackslashW(tmp) || strlenW(tmp) + strlenW(file) >= MAX_PATH)
|
||||
{
|
||||
dst[0] = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcatW(tmp, file);
|
||||
}
|
||||
|
||||
PathCanonicalizeW(dst, tmp);
|
||||
return dst;
|
||||
}
|
||||
|
||||
LPSTR WINAPI PathCombineA(char *dst, const char *dir, const char *file)
|
||||
{
|
||||
WCHAR dstW[MAX_PATH], dirW[MAX_PATH], fileW[MAX_PATH];
|
||||
|
||||
TRACE("%p, %s, %s\n", dst, wine_dbgstr_a(dir), wine_dbgstr_a(file));
|
||||
|
||||
/* Invalid parameters */
|
||||
if (!dst)
|
||||
return NULL;
|
||||
|
||||
dst[0] = 0;
|
||||
|
||||
if (!dir && !file)
|
||||
return NULL;
|
||||
|
||||
if (dir && !MultiByteToWideChar(CP_ACP, 0, dir, -1, dirW, ARRAY_SIZE(dirW)))
|
||||
return NULL;
|
||||
|
||||
if (file && !MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, ARRAY_SIZE(fileW)))
|
||||
return NULL;
|
||||
|
||||
if (PathCombineW(dstW, dir ? dirW : NULL, file ? fileW : NULL))
|
||||
if (WideCharToMultiByte(CP_ACP, 0, dstW, -1, dst, MAX_PATH, 0, 0))
|
||||
return dst;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathAppendA(char *path, const char *append)
|
||||
{
|
||||
TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(append));
|
||||
|
||||
if (path && append)
|
||||
{
|
||||
if (!PathIsUNCA(append))
|
||||
while (*append == '\\')
|
||||
append++;
|
||||
|
||||
if (PathCombineA(path, path, append))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathAppendW(WCHAR *path, const WCHAR *append)
|
||||
{
|
||||
TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(append));
|
||||
|
||||
if (path && append)
|
||||
{
|
||||
if (!PathIsUNCW(append))
|
||||
while (*append == '\\')
|
||||
append++;
|
||||
|
||||
if (PathCombineW(path, path, append))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int WINAPI PathCommonPrefixA(const char *file1, const char *file2, char *path)
|
||||
{
|
||||
const char *iter1 = file1;
|
||||
const char *iter2 = file2;
|
||||
unsigned int len = 0;
|
||||
|
||||
TRACE("%s, %s, %p.\n", wine_dbgstr_a(file1), wine_dbgstr_a(file2), path);
|
||||
|
||||
if (path)
|
||||
*path = '\0';
|
||||
|
||||
if (!file1 || !file2)
|
||||
return 0;
|
||||
|
||||
/* Handle roots first */
|
||||
if (PathIsUNCA(file1))
|
||||
{
|
||||
if (!PathIsUNCA(file2))
|
||||
return 0;
|
||||
iter1 += 2;
|
||||
iter2 += 2;
|
||||
}
|
||||
else if (PathIsUNCA(file2))
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Update len */
|
||||
if ((!*iter1 || *iter1 == '\\') && (!*iter2 || *iter2 == '\\'))
|
||||
len = iter1 - file1; /* Common to this point */
|
||||
|
||||
if (!*iter1 || (tolower(*iter1) != tolower(*iter2)))
|
||||
break; /* Strings differ at this point */
|
||||
|
||||
iter1++;
|
||||
iter2++;
|
||||
}
|
||||
|
||||
if (len == 2)
|
||||
len++; /* Feature/Bug compatible with Win32 */
|
||||
|
||||
if (len && path)
|
||||
{
|
||||
memcpy(path, file1, len);
|
||||
path[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int WINAPI PathCommonPrefixW(const WCHAR *file1, const WCHAR *file2, WCHAR *path)
|
||||
{
|
||||
const WCHAR *iter1 = file1;
|
||||
const WCHAR *iter2 = file2;
|
||||
unsigned int len = 0;
|
||||
|
||||
TRACE("%s, %s, %p\n", wine_dbgstr_w(file1), wine_dbgstr_w(file2), path);
|
||||
|
||||
if (path)
|
||||
*path = '\0';
|
||||
|
||||
if (!file1 || !file2)
|
||||
return 0;
|
||||
|
||||
/* Handle roots first */
|
||||
if (PathIsUNCW(file1))
|
||||
{
|
||||
if (!PathIsUNCW(file2))
|
||||
return 0;
|
||||
iter1 += 2;
|
||||
iter2 += 2;
|
||||
}
|
||||
else if (PathIsUNCW(file2))
|
||||
return 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Update len */
|
||||
if ((!*iter1 || *iter1 == '\\') && (!*iter2 || *iter2 == '\\'))
|
||||
len = iter1 - file1; /* Common to this point */
|
||||
|
||||
if (!*iter1 || (tolowerW(*iter1) != tolowerW(*iter2)))
|
||||
break; /* Strings differ at this point */
|
||||
|
||||
iter1++;
|
||||
iter2++;
|
||||
}
|
||||
|
||||
if (len == 2)
|
||||
len++; /* Feature/Bug compatible with Win32 */
|
||||
|
||||
if (len && path)
|
||||
{
|
||||
memcpy(path, file1, len * sizeof(WCHAR));
|
||||
path[len] = '\0';
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsPrefixA(const char *prefix, const char *path)
|
||||
{
|
||||
TRACE("%s, %s\n", wine_dbgstr_a(prefix), wine_dbgstr_a(path));
|
||||
|
||||
return prefix && path && PathCommonPrefixA(path, prefix, NULL) == (int)strlen(prefix);
|
||||
}
|
||||
|
||||
BOOL WINAPI PathIsPrefixW(const WCHAR *prefix, const WCHAR *path)
|
||||
{
|
||||
TRACE("%s, %s\n", wine_dbgstr_w(prefix), wine_dbgstr_w(path));
|
||||
|
||||
return prefix && path && PathCommonPrefixW(path, prefix, NULL) == (int)strlenW(prefix);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue