kernelbase: Add most of path API from shlwapi.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d4c96034d0
commit
1cef84a124
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue