[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