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 cb10d89773c..287c5d61d96 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 @@ -1,7 +1,7 @@ @ stub PathAllocCanonicalize @ stub PathAllocCombine -@ stub PathCchAddBackslash -@ stub PathCchAddBackslashEx +@ stdcall PathCchAddBackslash(wstr long) kernelbase.PathCchAddBackslash +@ stdcall PathCchAddBackslashEx(wstr long ptr ptr) kernelbase.PathCchAddBackslashEx @ stub PathCchAddExtension @ stub PathCchAppend @ stub PathCchAppendEx diff --git a/dlls/kernelbase/Makefile.in b/dlls/kernelbase/Makefile.in index 74df98ce2d5..a7db45e4c1d 100644 --- a/dlls/kernelbase/Makefile.in +++ b/dlls/kernelbase/Makefile.in @@ -1,4 +1,5 @@ MODULE = kernelbase.dll C_SRCS = \ - main.c + main.c \ + path.c diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index aa67372cf5c..eafe5ab9dda 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1029,8 +1029,8 @@ @ stdcall PathAppendW(wstr wstr) shlwapi.PathAppendW @ stdcall PathCanonicalizeA(ptr str) shlwapi.PathCanonicalizeA @ stdcall PathCanonicalizeW(ptr wstr) shlwapi.PathCanonicalizeW -# @ stub PathCchAddBackslash -# @ stub PathCchAddBackslashEx +@ stdcall PathCchAddBackslash(wstr long) +@ stdcall PathCchAddBackslashEx(wstr long ptr ptr) # @ stub PathCchAddExtension # @ stub PathCchAppend # @ stub PathCchAppendEx diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c new file mode 100644 index 00000000000..373c34e9795 --- /dev/null +++ b/dlls/kernelbase/path.c @@ -0,0 +1,67 @@ +/* + * Copyright 2018 Nikolay Sivov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "pathcch.h" +#include "strsafe.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(path); + +HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size) +{ + return PathCchAddBackslashEx(path, size, NULL, NULL); +} + +HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **endptr, SIZE_T *remaining) +{ + BOOL needs_termination; + SIZE_T length; + + TRACE("%s, %lu, %p, %p\n", debugstr_w(path), size, endptr, remaining); + + length = strlenW(path); + needs_termination = size && length && path[length - 1] != '\\'; + + if (length >= (needs_termination ? size - 1 : size)) + { + if (endptr) *endptr = NULL; + if (remaining) *remaining = 0; + return STRSAFE_E_INSUFFICIENT_BUFFER; + } + + if (!needs_termination) + { + if (endptr) *endptr = path + length; + if (remaining) *remaining = size - length; + return S_FALSE; + } + + path[length++] = '\\'; + path[length] = 0; + + if (endptr) *endptr = path + length; + if (remaining) *remaining = size - length; + + return S_OK; +} diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c index fbe1d3be2f5..47c77b8c341 100644 --- a/dlls/kernelbase/tests/path.c +++ b/dlls/kernelbase/tests/path.c @@ -29,6 +29,8 @@ #include "wine/test.h" +HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size); +HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining); HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags); static const struct @@ -113,11 +115,145 @@ static void test_PathCchCombineEx(void) } } +struct addbackslash_test +{ + const char *path; + const char *result; + HRESULT hr; + SIZE_T size; + SIZE_T remaining; +}; + +static const struct addbackslash_test addbackslash_tests[] = +{ + { "C:", "C:\\", S_OK, MAX_PATH, MAX_PATH - 3 }, + { "a.txt", "a.txt\\", S_OK, MAX_PATH, MAX_PATH - 6 }, + { "a/b", "a/b\\", S_OK, MAX_PATH, MAX_PATH - 4 }, + + { "C:\\", "C:\\", S_FALSE, MAX_PATH, MAX_PATH - 3 }, + { "C:\\", "C:\\", S_FALSE, 4, 1 }, + + { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 }, + { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 1 }, + { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 }, + { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 0 }, + { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 }, + { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 }, +}; + +static void test_PathCchAddBackslash(void) +{ + WCHAR pathW[MAX_PATH]; + unsigned int i; + HRESULT hr; + + if (!pPathCchAddBackslash) + { + win_skip("PathCchAddBackslash() is not availale.\n"); + return; + } + + pathW[0] = 0; + hr = pPathCchAddBackslash(pathW, 0); + ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + + pathW[0] = 0; + hr = pPathCchAddBackslash(pathW, 1); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + + pathW[0] = 0; + hr = pPathCchAddBackslash(pathW, 2); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + + for (i = 0; i < sizeof(addbackslash_tests)/sizeof(addbackslash_tests[0]); i++) + { + const struct addbackslash_test *test = &addbackslash_tests[i]; + char path[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, sizeof(pathW)/sizeof(pathW[0])); + hr = pPathCchAddBackslash(pathW, test->size); + ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); + + WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, sizeof(path)/sizeof(path[0]), NULL, NULL); + ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path); + } +} + +static void test_PathCchAddBackslashEx(void) +{ + WCHAR pathW[MAX_PATH]; + SIZE_T remaining; + unsigned int i; + HRESULT hr; + WCHAR *ptrW; + + if (!pPathCchAddBackslashEx) + { + win_skip("PathCchAddBackslashEx() is not availale.\n"); + return; + } + + pathW[0] = 0; + hr = pPathCchAddBackslashEx(pathW, 0, NULL, NULL); + ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + + pathW[0] = 0; + ptrW = (void *)0xdeadbeef; + remaining = 123; + hr = pPathCchAddBackslashEx(pathW, 1, &ptrW, &remaining); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + ok(ptrW == pathW, "Unexpected endptr %p.\n", ptrW); + ok(remaining == 1, "Unexpected remaining size.\n"); + + pathW[0] = 0; + hr = pPathCchAddBackslashEx(pathW, 2, NULL, NULL); + ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); + ok(pathW[0] == 0, "Unexpected path.\n"); + + for (i = 0; i < sizeof(addbackslash_tests)/sizeof(addbackslash_tests[0]); i++) + { + const struct addbackslash_test *test = &addbackslash_tests[i]; + char path[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, sizeof(pathW)/sizeof(pathW[0])); + hr = pPathCchAddBackslashEx(pathW, test->size, NULL, NULL); + ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); + + WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, sizeof(path)/sizeof(path[0]), NULL, NULL); + ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path); + + ptrW = (void *)0xdeadbeef; + remaining = 123; + MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, sizeof(pathW)/sizeof(pathW[0])); + hr = pPathCchAddBackslashEx(pathW, test->size, &ptrW, &remaining); + ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr); + if (SUCCEEDED(hr)) + { + ok(ptrW == (pathW + lstrlenW(pathW)), "%u: unexpected end pointer.\n", i); + ok(remaining == test->remaining, "%u: unexpected remaining buffer length.\n", i); + } + else + { + ok(ptrW == NULL, "%u: unexpecred end pointer.\n", i); + ok(remaining == 0, "%u: unexpected remaining buffer length.\n", i); + } + } +} + START_TEST(path) { HMODULE hmod = LoadLibraryA("kernelbase.dll"); pPathCchCombineEx = (void *)GetProcAddress(hmod, "PathCchCombineEx"); + pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash"); + pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx"); test_PathCchCombineEx(); + test_PathCchAddBackslash(); + test_PathCchAddBackslashEx(); } diff --git a/include/pathcch.h b/include/pathcch.h index 8831c5238d2..2b2aed4c8f9 100644 --- a/include/pathcch.h +++ b/include/pathcch.h @@ -23,4 +23,6 @@ #define PATHCCH_DO_NOT_NORMALIZE_SEGMENTS 0x08 #define PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH 0x10 +HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size); +HRESULT WINAPI PathCchAddBackslashEx(WCHAR *path, SIZE_T size, WCHAR **end, SIZE_T *remaining); HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags); diff --git a/tools/make_specfiles b/tools/make_specfiles index 1e8a894277e..e9bc1f4d8d7 100755 --- a/tools/make_specfiles +++ b/tools/make_specfiles @@ -303,6 +303,7 @@ my @dll_groups = [ "kernelbase", "api-ms-win-appmodel-runtime-l1-1-2", + "api-ms-win-core-path-l1-1-0", "api-ms-win-core-quirks-l1-1-0", "api-ms-win-security-grouppolicy-l1-1-0", ],