[PATCH] kernelbase: Add most of path API from shlwapi.

Nikolay Sivov nsivov at codeweavers.com
Tue May 21 06:22:19 CDT 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/kernelbase/kernelbase.spec |  38 +--
 dlls/kernelbase/path.c          | 422 ++++++++++++++++++++++++++++++++
 2 files changed, 441 insertions(+), 19 deletions(-)

diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 46163150c1..874db20c9c 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -1056,14 +1056,14 @@
 @ 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 PathFileExistsA(str)
+@ stdcall PathFileExistsW(wstr)
 @ stdcall PathFindExtensionA(str)
 @ stdcall PathFindExtensionW(wstr)
 @ stdcall PathFindFileNameA(str)
 @ stdcall PathFindFileNameW(wstr)
-@ stdcall PathFindNextComponentA(str) shlwapi.PathFindNextComponentA
-@ stdcall PathFindNextComponentW(wstr) shlwapi.PathFindNextComponentW
+@ stdcall PathFindNextComponentA(str)
+@ stdcall PathFindNextComponentW(wstr)
 @ stdcall PathGetArgsA(str)
 @ stdcall PathGetArgsW(wstr)
 @ stdcall PathGetCharTypeA(long)
@@ -1080,8 +1080,8 @@
 @ stdcall PathIsRelativeW(wstr)
 @ stdcall PathIsRootA(str)
 @ stdcall PathIsRootW(wstr)
-@ stdcall PathIsSameRootA(str str) shlwapi.PathIsSameRootA
-@ stdcall PathIsSameRootW(wstr wstr) shlwapi.PathIsSameRootW
+@ stdcall PathIsSameRootA(str str)
+@ stdcall PathIsSameRootW(wstr wstr)
 @ stdcall PathIsUNCA(str)
 @ stdcall PathIsUNCEx(wstr ptr)
 @ stdcall PathIsUNCServerA(str)
@@ -1093,16 +1093,16 @@
 @ stdcall PathIsURLW(wstr) shlwapi.PathIsURLW
 @ stdcall PathIsValidCharA(long long)
 @ stdcall PathIsValidCharW(long long)
-@ stdcall PathMatchSpecA(str str) shlwapi.PathMatchSpecA
+@ stdcall PathMatchSpecA(str str)
 # @ stub PathMatchSpecExA
 # @ stub PathMatchSpecExW
-@ stdcall PathMatchSpecW(wstr wstr) shlwapi.PathMatchSpecW
+@ stdcall PathMatchSpecW(wstr wstr)
 @ stdcall PathParseIconLocationA(str) shlwapi.PathParseIconLocationA
 @ stdcall PathParseIconLocationW(wstr) shlwapi.PathParseIconLocationW
-@ stdcall PathQuoteSpacesA(str) shlwapi.PathQuoteSpacesA
-@ stdcall PathQuoteSpacesW(wstr) shlwapi.PathQuoteSpacesW
-@ stdcall PathRelativePathToA(ptr str long str long) shlwapi.PathRelativePathToA
-@ stdcall PathRelativePathToW(ptr wstr long wstr long) shlwapi.PathRelativePathToW
+@ stdcall PathQuoteSpacesA(str)
+@ stdcall PathQuoteSpacesW(wstr)
+@ stdcall PathRelativePathToA(ptr str long str long)
+@ stdcall PathRelativePathToW(ptr wstr long wstr long)
 @ stdcall PathRemoveBackslashA(str)
 @ stdcall PathRemoveBackslashW(wstr)
 @ stdcall PathRemoveBlanksA(str)
@@ -1113,13 +1113,13 @@
 @ stdcall PathRemoveFileSpecW(wstr)
 @ stdcall PathRenameExtensionA(str str)
 @ stdcall PathRenameExtensionW(wstr wstr)
-@ stdcall PathSearchAndQualifyA(str ptr long) shlwapi.PathSearchAndQualifyA
-@ stdcall PathSearchAndQualifyW(wstr ptr long) shlwapi.PathSearchAndQualifyW
-@ stdcall PathSkipRootA(str) shlwapi.PathSkipRootA
-@ stdcall PathSkipRootW(wstr) shlwapi.PathSkipRootW
-@ stdcall PathStripPathA(str) shlwapi.PathStripPathA
-@ stdcall PathStripPathW(wstr) shlwapi.PathStripPathW
-@ stdcall PathStripToRootA(str) shlwapi.PathStripToRootA
+@ stdcall PathSearchAndQualifyA(str ptr long)
+@ stdcall PathSearchAndQualifyW(wstr ptr long)
+@ stdcall PathSkipRootA(str)
+@ stdcall PathSkipRootW(wstr)
+@ stdcall PathStripPathA(str)
+@ stdcall PathStripPathW(wstr)
+@ stdcall PathStripToRootA(str)
 @ stdcall PathStripToRootW(wstr)
 @ stdcall PathUnExpandEnvStringsA(str ptr long) shlwapi.PathUnExpandEnvStringsA
 @ stdcall PathUnExpandEnvStringsW(wstr ptr long) shlwapi.PathUnExpandEnvStringsW
diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c
index 49af28effe..ca951cfd3f 100644
--- a/dlls/kernelbase/path.c
+++ b/dlls/kernelbase/path.c
@@ -2176,3 +2176,425 @@ BOOL WINAPI PathIsValidCharW(WCHAR c, DWORD class)
 
     return class & path_charclass[c];
 }
+
+char * WINAPI PathFindNextComponentA(const char *path)
+{
+    char *slash;
+
+    TRACE("%s\n", wine_dbgstr_a(path));
+
+    if (!path || !*path)
+        return NULL;
+
+    if ((slash = StrChrA(path, '\\')))
+    {
+        if (slash[1] == '\\')
+            slash++;
+        return slash + 1;
+    }
+
+    return (char *)path + strlen(path);
+}
+
+WCHAR * WINAPI PathFindNextComponentW(const WCHAR *path)
+{
+    WCHAR *slash;
+
+    TRACE("%s\n", wine_dbgstr_w(path));
+
+    if (!path || !*path)
+        return NULL;
+
+    if ((slash = StrChrW(path, '\\')))
+    {
+        if (slash[1] == '\\')
+            slash++;
+        return slash + 1;
+    }
+
+    return (WCHAR *)path + strlenW(path);
+}
+
+char * WINAPI PathSkipRootA(const char *path)
+{
+    TRACE("%s\n", wine_dbgstr_a(path));
+
+    if (!path || !*path)
+        return NULL;
+
+    if (*path == '\\' && path[1] == '\\')
+    {
+        /* Network share: skip share server and mount point */
+        path += 2;
+        if ((path = StrChrA(path, '\\')) && (path = StrChrA(path + 1, '\\')))
+            path++;
+        return (char *)path;
+    }
+
+    if (IsDBCSLeadByte(*path))
+        return NULL;
+
+    /* Check x:\ */
+    if (path[0] && path[1] == ':' && path[2] == '\\')
+        return (char *)path + 3;
+
+    return NULL;
+}
+
+WCHAR * WINAPI PathSkipRootW(const WCHAR *path)
+{
+    TRACE("%s\n", wine_dbgstr_w(path));
+
+    if (!path || !*path)
+        return NULL;
+
+    if (*path == '\\' && path[1] == '\\')
+    {
+        /* Network share: skip share server and mount point */
+        path += 2;
+        if ((path = StrChrW(path, '\\')) && (path = StrChrW(path + 1, '\\')))
+            path++;
+        return (WCHAR *)path;
+    }
+
+    /* Check x:\ */
+    if (path[0] && path[1] == ':' && path[2] == '\\')
+        return (WCHAR *)path + 3;
+
+    return NULL;
+}
+
+void WINAPI PathStripPathA(char *path)
+{
+    TRACE("%s\n", wine_dbgstr_a(path));
+
+    if (path)
+    {
+        char *filename = PathFindFileNameA(path);
+        if (filename != path)
+            RtlMoveMemory(path, filename, strlen(filename) + 1);
+    }
+}
+
+void WINAPI PathStripPathW(WCHAR *path)
+{
+    WCHAR *filename;
+
+    TRACE("%s\n", wine_dbgstr_w(path));
+    filename = PathFindFileNameW(path);
+    if (filename != path)
+        RtlMoveMemory(path, filename, (strlenW(filename) + 1) * sizeof(WCHAR));
+}
+
+BOOL WINAPI PathSearchAndQualifyA(const char *path, char *buffer, UINT length)
+{
+    TRACE("%s, %p, %u\n", wine_dbgstr_a(path), buffer, length);
+
+    if (SearchPathA(NULL, path, NULL, length, buffer, NULL))
+        return TRUE;
+
+    return !!GetFullPathNameA(path, length, buffer, NULL);
+}
+
+BOOL WINAPI PathSearchAndQualifyW(const WCHAR *path, WCHAR *buffer, UINT length)
+{
+    TRACE("%s, %p, %u\n", wine_dbgstr_w(path), buffer, length);
+
+    if (SearchPathW(NULL, path, NULL, length, buffer, NULL))
+        return TRUE;
+    return !!GetFullPathNameW(path, length, buffer, NULL);
+}
+
+BOOL WINAPI PathRelativePathToA(char *path, const char *from, DWORD attributes_from, const char *to,
+        DWORD attributes_to)
+{
+    WCHAR pathW[MAX_PATH], fromW[MAX_PATH], toW[MAX_PATH];
+    BOOL ret;
+
+    TRACE("%p, %s, %#x, %s, %#x\n", path, wine_dbgstr_a(from), attributes_from, wine_dbgstr_a(to), attributes_to);
+
+    if (!path || !from || !to)
+        return FALSE;
+
+    MultiByteToWideChar(CP_ACP, 0, from, -1, fromW, ARRAY_SIZE(fromW));
+    MultiByteToWideChar(CP_ACP, 0, to, -1, toW, ARRAY_SIZE(toW));
+    ret = PathRelativePathToW(pathW, fromW, attributes_from, toW, attributes_to);
+    WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, MAX_PATH, 0, 0);
+
+    return ret;
+}
+
+BOOL WINAPI PathRelativePathToW(WCHAR *path, const WCHAR *from, DWORD attributes_from, const WCHAR *to,
+        DWORD attributes_to)
+{
+    static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' };
+    static const WCHAR szPrevDir[] = { '.', '.', '\0' };
+    WCHAR fromW[MAX_PATH], toW[MAX_PATH];
+    DWORD len;
+
+    TRACE("%p, %s, %#x, %s, %#x\n", path, wine_dbgstr_w(from), attributes_from, wine_dbgstr_w(to), attributes_to);
+
+    if (!path || !from || !to)
+        return FALSE;
+
+    *path = '\0';
+    lstrcpynW(fromW, from, ARRAY_SIZE(fromW));
+    lstrcpynW(toW, to, ARRAY_SIZE(toW));
+
+    if (!(attributes_from & FILE_ATTRIBUTE_DIRECTORY))
+        PathRemoveFileSpecW(fromW);
+    if (!(attributes_to & FILE_ATTRIBUTE_DIRECTORY))
+        PathRemoveFileSpecW(toW);
+
+    /* Paths can only be relative if they have a common root */
+    if (!(len = PathCommonPrefixW(fromW, toW, 0)))
+        return FALSE;
+
+    /* Strip off 'from' components to the root, by adding "..\" */
+    from = fromW + len;
+    if (!*from)
+    {
+        path[0] = '.';
+        path[1] = '\0';
+    }
+    if (*from == '\\')
+        from++;
+
+    while (*from)
+    {
+        from = PathFindNextComponentW(from);
+        strcatW(path, *from ? szPrevDirSlash : szPrevDir);
+    }
+
+    /* From the root add the components of 'to' */
+    to += len;
+    /* We check to[-1] to avoid skipping end of string. See the notes for this function. */
+    if (*to && to[-1])
+    {
+        if (*to != '\\')
+            to--;
+        len = strlenW(path);
+        if (len + strlenW(to) >= MAX_PATH)
+        {
+            *path = '\0';
+            return FALSE;
+        }
+        strcpyW(path + len, to);
+    }
+
+    return TRUE;
+}
+
+static BOOL path_match_maskA(const char *name, const char *mask)
+{
+    while (*name && *mask && *mask != ';')
+    {
+        if (*mask == '*')
+        {
+            do
+            {
+                if (path_match_maskA(name, mask + 1))
+                    return TRUE;  /* try substrings */
+            } while (*name++);
+            return FALSE;
+        }
+
+        if (toupper(*mask) != toupper(*name) && *mask != '?')
+            return FALSE;
+
+        name = CharNextA(name);
+        mask = CharNextA(mask);
+    }
+
+    if (!*name)
+    {
+        while (*mask == '*')
+            mask++;
+        if (!*mask || *mask == ';')
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+BOOL WINAPI PathMatchSpecA(const char *path, const char *mask)
+{
+    TRACE("%s, %s\n", wine_dbgstr_a(path), wine_dbgstr_a(mask));
+
+    if (!lstrcmpA(mask, "*.*"))
+        return TRUE; /* Matches every path */
+
+    while (*mask)
+    {
+        while (*mask == ' ')
+            mask++; /* Eat leading spaces */
+
+        if (path_match_maskA(path, mask))
+            return TRUE; /* Matches the current mask */
+
+        while (*mask && *mask != ';')
+            mask = CharNextA(mask); /* masks separated by ';' */
+
+        if (*mask == ';')
+            mask++;
+    }
+
+    return FALSE;
+}
+
+static BOOL path_match_maskW(const WCHAR *name, const WCHAR *mask)
+{
+    while (*name && *mask && *mask != ';')
+    {
+        if (*mask == '*')
+        {
+            do
+            {
+                if (path_match_maskW(name, mask + 1))
+                    return TRUE;  /* try substrings */
+            } while (*name++);
+            return FALSE;
+        }
+
+        if (toupperW(*mask) != toupperW(*name) && *mask != '?')
+            return FALSE;
+
+        name++;
+        mask++;
+    }
+
+    if (!*name)
+    {
+        while (*mask == '*')
+            mask++;
+        if (!*mask || *mask == ';')
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+BOOL WINAPI PathMatchSpecW(const WCHAR *path, const WCHAR *mask)
+{
+    static const WCHAR maskallW[] = {'*','.','*',0};
+
+    TRACE("%s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(mask));
+
+    if (!lstrcmpW(mask, maskallW))
+        return TRUE; /* Matches every path */
+
+    while (*mask)
+    {
+        while (*mask == ' ')
+            mask++; /* Eat leading spaces */
+
+        if (path_match_maskW(path, mask))
+            return TRUE; /* Matches the current path */
+
+        while (*mask && *mask != ';')
+            mask++; /* masks separated by ';' */
+
+        if (*mask == ';')
+            mask++;
+    }
+
+    return FALSE;
+}
+
+void WINAPI PathQuoteSpacesA(char *path)
+{
+    TRACE("%s\n", wine_dbgstr_a(path));
+
+    if (path && StrChrA(path, ' '))
+    {
+        size_t len = strlen(path) + 1;
+
+        if (len + 2 < MAX_PATH)
+        {
+            memmove(path + 1, path, len);
+            path[0] = '"';
+            path[len] = '"';
+            path[len + 1] = '\0';
+        }
+    }
+}
+
+void WINAPI PathQuoteSpacesW(WCHAR *path)
+{
+    TRACE("%s\n", wine_dbgstr_w(path));
+
+    if (path && StrChrW(path, ' '))
+    {
+        int len = strlenW(path) + 1;
+
+        if (len + 2 < MAX_PATH)
+        {
+            memmove(path + 1, path, len * sizeof(WCHAR));
+            path[0] = '"';
+            path[len] = '"';
+            path[len + 1] = '\0';
+        }
+    }
+}
+
+BOOL WINAPI PathIsSameRootA(const char *path1, const char *path2)
+{
+    const char *start;
+    int len;
+
+    TRACE("%s, %s\n", wine_dbgstr_a(path1), wine_dbgstr_a(path2));
+
+    if (!path1 || !path2 || !(start = PathSkipRootA(path1)))
+        return FALSE;
+
+    len = PathCommonPrefixA(path1, path2, NULL) + 1;
+    return start - path1 <= len;
+}
+
+BOOL WINAPI PathIsSameRootW(const WCHAR *path1, const WCHAR *path2)
+{
+    const WCHAR *start;
+    int len;
+
+    TRACE("%s, %s\n", wine_dbgstr_w(path1), wine_dbgstr_w(path2));
+
+    if (!path1 || !path2 || !(start = PathSkipRootW(path1)))
+        return FALSE;
+
+    len = PathCommonPrefixW(path1, path2, NULL) + 1;
+    return start - path1 <= len;
+}
+
+BOOL WINAPI PathFileExistsA(const char *path)
+{
+    UINT prev_mode;
+    DWORD attrs;
+
+    TRACE("%s\n", wine_dbgstr_a(path));
+
+    if (!path)
+        return FALSE;
+
+    /* Prevent a dialog box if path is on a disk that has been ejected. */
+    prev_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+    attrs = GetFileAttributesA(path);
+    SetErrorMode(prev_mode);
+    return attrs != INVALID_FILE_ATTRIBUTES;
+}
+
+BOOL WINAPI PathFileExistsW(const WCHAR *path)
+{
+    UINT prev_mode;
+    DWORD attrs;
+
+    TRACE("%s\n", wine_dbgstr_w(path));
+
+    if (!path)
+        return FALSE;
+
+    prev_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+    attrs = GetFileAttributesW(path);
+    SetErrorMode(prev_mode);
+    return attrs != INVALID_FILE_ATTRIBUTES;
+}
-- 
2.20.1




More information about the wine-devel mailing list