[PATCH] kernelbase: Duplicate some path handling functions from shlwapi.
Nikolay Sivov
nsivov at codeweavers.com
Tue May 14 05:30:35 CDT 2019
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/kernelbase/kernelbase.spec | 54 +--
dlls/kernelbase/path.c | 753 ++++++++++++++++++++++++++++++++
2 files changed, 780 insertions(+), 27 deletions(-)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 7151bbae3c..d1bcea5593 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -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
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 5331f373c2..a72ff8e694 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -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);
+}
--
2.20.1
More information about the wine-devel
mailing list