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 d874f8c8027..53f7b987ca4 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 b3b28872af6..8f4136eb6bc 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 4aa39b4ae37..d0ec7e027cc 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -44,6 +44,12 @@ static BOOL is_prefixed_unc(const WCHAR *string) return !strncmpiW(string, prefixed_unc, ARRAY_SIZE(prefixed_unc)); } +static BOOL is_prefixed_disk(const WCHAR *string) +{ + static const WCHAR prefix[] = {'\\', '\\', '?', '\\'}; + return !strncmpW(string, prefix, ARRAY_SIZE(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 3f7925df98a..5fc3cc8398b 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 6973d6dda20..1ff9e246481 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);