Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- .../api-ms-win-core-path-l1-1-0.spec | 2 +- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/path.c | 30 +++++++ dlls/kernelbase/tests/path.c | 78 +++++++++++++++++++ include/pathcch.h | 1 + 5 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec index d874f8c802..53f7b987ca 100644 --- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec +++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec @@ -17,6 +17,6 @@ @ stub PathCchRemoveFileSpec @ stdcall PathCchRenameExtension(wstr long wstr) kernelbase.PathCchRenameExtension @ stub PathCchSkipRoot -@ stub PathCchStripPrefix +@ stdcall PathCchStripPrefix(wstr long) kernelbase.PathCchStripPrefix @ stub PathCchStripToRoot @ stdcall PathIsUNCEx(wstr ptr) kernelbase.PathIsUNCEx diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index b3b28872af..8f4136eb6b 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1046,7 +1046,7 @@ # @ stub PathCchRemoveFileSpec @ stdcall PathCchRenameExtension(wstr long wstr) # @ stub PathCchSkipRoot -# @ stub PathCchStripPrefix +@ stdcall PathCchStripPrefix(wstr long) # @ stub PathCchStripToRoot @ stdcall PathCombineA(ptr str str) shlwapi.PathCombineA @ stdcall PathCombineW(ptr wstr wstr) shlwapi.PathCombineW diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index 5f11e11962..366efa41e1 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -44,6 +44,12 @@ static BOOL is_prefixed_unc(const WCHAR *string) return !memicmpW(string, prefixed_unc, ARRAY_SIZE(prefixed_unc)); }
+static BOOL is_prefixed_disk(const WCHAR *string) +{ + static const WCHAR prefix[] = {'\', '\', '?', '\'}; + return !memcmp(string, prefix, sizeof(prefix)) && isalphaW(string[4]) && string[5] == ':'; +} + HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size) { return PathCchAddBackslashEx(path, size, NULL, NULL); @@ -190,6 +196,30 @@ HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *ext return FAILED(hr) ? hr : S_OK; }
+HRESULT WINAPI PathCchStripPrefix(WCHAR *path, SIZE_T size) +{ + TRACE("%s %lu\n", wine_dbgstr_w(path), size); + + if (!path || !size || size > PATHCCH_MAX_CCH) return E_INVALIDARG; + + if (is_prefixed_unc(path)) + { + /* \?\UNC\a -> \a */ + if (size < strlenW(path + 8) + 3) return E_INVALIDARG; + strcpyW(path + 2, path + 8); + return S_OK; + } + else if (is_prefixed_disk(path)) + { + /* \?\C:\ -> C:\ */ + if (size < strlenW(path + 4) + 1) return E_INVALIDARG; + strcpyW(path, path + 4); + return S_OK; + } + else + return S_FALSE; +} + BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server) { const WCHAR *result = NULL; diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c index 8bd23191b0..af15e83d60 100644 --- a/dlls/kernelbase/tests/path.c +++ b/dlls/kernelbase/tests/path.c @@ -37,6 +37,7 @@ HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension); HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size); HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); +HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size); BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server);
static const struct @@ -633,6 +634,81 @@ static void test_PathCchRenameExtension(void) } }
+struct stripprefix_test +{ + const CHAR *path; + const CHAR *stripped_path; + HRESULT hr; + SIZE_T size; +}; + +static const struct stripprefix_test stripprefix_tests[] = +{ + {"\\?\UNC\", "\\", S_OK}, + {"\\?\UNC\a", "\\a", S_OK}, + {"\\?\C:", "C:", S_OK}, + {"\\?\C:\", "C:\", S_OK}, + {"\\?\C:\a", "C:\a", S_OK}, + {"\\?\unc\", "\\", S_OK}, + {"\\?\c:\", "c:\", S_OK}, + + {"\", "\", S_FALSE}, + {"\\", "\\", S_FALSE}, + {"\\a", "\\a", S_FALSE}, + {"\\a\", "\\a\", S_FALSE}, + {"\\?\a", "\\?\a", S_FALSE}, + {"\\?\UNC", "\\?\UNC", S_FALSE}, + {"\\?\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\", + "\\?\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\", S_FALSE}, + + /* Size Tests */ + {"C:\", NULL, E_INVALIDARG, PATHCCH_MAX_CCH + 1}, + {"C:\", "C:\", S_FALSE, PATHCCH_MAX_CCH}, + /* Size < original path actual length + 1, read beyond size */ + {"\\?\C:\", "C:\", S_OK, ARRAY_SIZE("\\?\C:\") - 1}, + /* Size < stripped path length + 1 */ + {"\\?\C:\", NULL, E_INVALIDARG, ARRAY_SIZE("C:\") - 1}, + {"\\?\UNC\", NULL, E_INVALIDARG, ARRAY_SIZE("\\") - 1} +}; + +static void test_PathCchStripPrefix(void) +{ + WCHAR pathW[PATHCCH_MAX_CCH + 1] = {0}; + CHAR stripped_pathA[PATHCCH_MAX_CCH]; + SIZE_T size; + HRESULT hr; + INT i; + + if (!pPathCchStripPrefix) + { + win_skip("PathCchStripPrefix(() is not available.\n"); + return; + } + + /* Null arguments */ + hr = pPathCchStripPrefix(NULL, PATHCCH_MAX_CCH); + ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); + + hr = pPathCchStripPrefix(pathW, 0); + ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr); + + for (i = 0; i < ARRAY_SIZE(stripprefix_tests); i++) + { + const struct stripprefix_test *t = stripprefix_tests + i; + + MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); + size = t->size ? t->size : PATHCCH_MAX_CCH; + hr = pPathCchStripPrefix(pathW, size); + ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr); + if (SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, pathW, -1, stripped_pathA, ARRAY_SIZE(stripped_pathA), NULL, NULL); + ok(!lstrcmpA(stripped_pathA, t->stripped_path), "path %s expect stripped path %s, got %s\n", t->path, + t->stripped_path, stripped_pathA); + } + } +} + struct isuncex_test { const CHAR *path; @@ -713,6 +789,7 @@ START_TEST(path) pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension"); pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension"); pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension"); + pPathCchStripPrefix = (void *)GetProcAddress(hmod, "PathCchStripPrefix"); pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx");
test_PathCchCombineEx(); @@ -722,5 +799,6 @@ START_TEST(path) test_PathCchFindExtension(); test_PathCchRemoveExtension(); test_PathCchRenameExtension(); + test_PathCchStripPrefix(); test_PathIsUNCEx(); } diff --git a/include/pathcch.h b/include/pathcch.h index 6973d6dda2..1ff9e24648 100644 --- a/include/pathcch.h +++ b/include/pathcch.h @@ -32,4 +32,5 @@ HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, con HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension); HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size); HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension); +HRESULT WINAPI PathCchStripPrefix(WCHAR *path, SIZE_T size); BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server);