Fixes PowerShell issue at https://bugs.winehq.org/show_bug.cgi?id=41911
Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/locale.c | 107 +++++++++++++++++++++++++++++++++++++++++++ dlls/kernel32/tests/locale.c | 99 +++++++++++++++++++++++++++++++++++++++ include/winnls.h | 5 ++ 4 files changed, 212 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 60809f45fd..3a0bef93e7 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -505,7 +505,7 @@ @ stub FindNextVolumeMountPointW @ stdcall FindNextVolumeW(long ptr long) # @ stub FindNLSString -# @ stub FindNLSStringEx +@ stdcall FindNLSStringEx(wstr long wstr long wstr long ptr ptr ptr long) @ stdcall FindResourceA(long str str) @ stdcall FindResourceExA(long str str long) @ stdcall FindResourceExW(long wstr wstr long) diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index e4c323ead6..123f8b2f3e 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -5941,3 +5941,110 @@ INT WINAPI ResolveLocaleName(LPCWSTR name, LPWSTR localename, INT len) SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return 0; } + +/****************************************************************************** + * FindNLSStringEx (KERNEL32.@) + */ + +INT WINAPI FindNLSStringEx(const WCHAR *localename, DWORD flags, const WCHAR *src, + INT src_size, const WCHAR *value, INT value_size, + INT *found, LPNLSVERSIONINFO version_info, LPVOID reserved, + LPARAM sort_handle) +{ + + DWORD mask = flags; + + TRACE("%s %x %s %d %s %d %p %p %p %ld\n", wine_dbgstr_w(localename), flags, + wine_dbgstr_w(src), src_size, wine_dbgstr_w(value), value_size, found, + version_info, reserved, sort_handle); + FIXME("strings should be normalized once NormalizeString() is implemented\n"); + + if (version_info != NULL || reserved != NULL || sort_handle != 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + if (localename == NULL || !IsValidLocaleName(localename)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + if (src == NULL || src_size == 0 || src_size < -1 || + value == NULL || value_size == 0 || value_size < -1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + if ((flags & (FIND_FROMSTART | FIND_FROMEND | FIND_STARTSWITH | FIND_ENDSWITH)) == 0) + flags |= FIND_FROMSTART; + else + { + /* flags are mutually exclusive */ + mask &= (FIND_FROMSTART | FIND_FROMEND | FIND_STARTSWITH | FIND_ENDSWITH); + while ((mask & 1) == 0) + mask >>= 1; + mask >>=1; + if (mask) + { + SetLastError(ERROR_INVALID_FLAGS); + return -1; + } + } + /* caller can delegate string length, but promises to zero-end it */ + if (src_size == -1) + src_size = strlenW(src); + if (value_size == -1) + value_size = strlenW(value); + + src_size -= value_size; + if (src_size < 0) + { + SetLastError(ERROR_SUCCESS); + return -1; + } + + mask = flags & ~(FIND_FROMSTART | FIND_FROMEND | FIND_STARTSWITH | FIND_ENDSWITH); + if (flags & FIND_FROMSTART) + { + int j; + for (j = 0; j < src_size; j++) + { + if (CompareStringEx(localename, mask, src + j, value_size, value, value_size, NULL, NULL, 0) == CSTR_EQUAL) + { + if (found) + *found = value_size; + return j; + } + } + SetLastError(ERROR_SUCCESS); + return -1; + } + else if (flags & FIND_STARTSWITH) + { + if (CompareStringEx(localename, mask, src, value_size, value, value_size, NULL, NULL, 0) == CSTR_EQUAL) + { + if (found) + *found = value_size; + return 0; + } + SetLastError(ERROR_SUCCESS); + return -1; + } + else if (flags & FIND_ENDSWITH) + { + if (CompareStringEx(localename, mask, src + src_size, value_size, value, value_size, NULL, NULL, 0) == CSTR_EQUAL) + { + if (found) + *found = value_size; + return src_size; + } + SetLastError(ERROR_SUCCESS); + return -1; + } + else + { + FIXME("unsupported FINDFROMEND flag\n"); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return -1; + } +} diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index ce2f13b6dc..6d1c2578ab 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -103,6 +103,7 @@ static BOOL (WINAPI *pGetThreadPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULON static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*); static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR); static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int); +static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
static void InitFunctionPointers(void) { @@ -135,6 +136,7 @@ static void InitFunctionPointers(void) X(GetThreadPreferredUILanguages); X(GetUserPreferredUILanguages); X(GetNumberFormatEx); + X(FindNLSStringEx);
mod = GetModuleHandleA("ntdll"); X(RtlUpcaseUnicodeChar); @@ -5329,6 +5331,102 @@ static void test_GetUserPreferredUILanguages(void) HeapFree(GetProcessHeap(), 0, buffer); }
+static void test_FindNLSStringEx(void) +{ + INT res; + static WCHAR en_simpleW[] = {'S','i','m','p','l','e','T','e','s','t',0}; + static WCHAR en_pletW[] = {'p','l','e','T',0}; + static WCHAR en_simpW[] = {'S','i','m','p',0}; + static WCHAR en_testW[] = {'T','e','s','t',0}; + static WCHAR comb_s_accent1W[] = {0x1e69, 'o','u','r','c','e',0}; + static WCHAR comb_s_accent2W[] = {0x0073,0x323,0x307,'o','u','r','c','e',0}; + static WCHAR comb_q_accent1W[] = {0x0071,0x0307,0x323,'u','o','t','e',0}; + static WCHAR comb_q_accent2W[] = {0x0071,0x0323,0x307,'u','o','t','e',0}; + static WCHAR singleton_angstromW[] = {0x212b,'m','e','r','i','c','a',0}; + static WCHAR singleton_angstrom_decomW[] = {0x41,0x30a,'m','e','r','i','c','a',0}; + struct test_data { + const WCHAR *locale; + DWORD flags; + WCHAR *src; + INT src_size; + WCHAR *value; + INT val_size; + INT found; + INT expected_ret; + INT expected_found; + int todo; + }; + + static struct test_data test_arr[] = + { + { localeW, FIND_FROMSTART, en_simpleW, sizeof(en_simpleW)/sizeof(WCHAR)-1, + en_pletW, sizeof(en_pletW)/sizeof(WCHAR)-1, 0, 3, 4, 0 }, + { localeW, FIND_STARTSWITH, en_simpleW, sizeof(en_simpleW)/sizeof(WCHAR)-1, + en_simpW, sizeof(en_simpW)/sizeof(WCHAR)-1, 0, 0, 4, 0 }, + { localeW, FIND_ENDSWITH, en_simpleW, sizeof(en_simpleW)/sizeof(WCHAR)-1, + en_testW, sizeof(en_testW)/sizeof(WCHAR)-1, 0, 6, 4, 0 }, + { localeW, FIND_FROMSTART, comb_s_accent1W, sizeof(comb_s_accent1W)/sizeof(WCHAR)-1, + comb_s_accent2W, sizeof(comb_s_accent2W)/sizeof(WCHAR)-1, 0, 0, 6, 1 }, + { localeW, FIND_FROMSTART, comb_q_accent1W, sizeof(comb_q_accent1W)/sizeof(WCHAR)-1, + comb_q_accent2W, sizeof(comb_q_accent2W)/sizeof(WCHAR)-1, 0, 0, 7, 1 }, + { localeW, FIND_FROMSTART, singleton_angstromW, sizeof(singleton_angstromW)/sizeof(WCHAR)-1, + singleton_angstrom_decomW, sizeof(singleton_angstrom_decomW)/sizeof(WCHAR)-1, 0, 0, 7, 1 }, + { 0 } + }; + struct test_data *ptest; + + res = pFindNLSStringEx(invalidW, FIND_FROMSTART, fooW, 3, fooW, + 3, NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError()); + + res = pFindNLSStringEx(localeW, FIND_FROMSTART | FIND_ENDSWITH, fooW, 3, fooW, + 3, NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_FLAGS == GetLastError(), + "Expected ERROR_INVALID_FLAGS as last error; got %d\n", GetLastError()); + + res = pFindNLSStringEx(localeW, FIND_FROMSTART, NULL, 3, fooW, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError()); + + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, -5, fooW, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError()); + + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, NULL, 3, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError()); + + res = pFindNLSStringEx(localeW, FIND_FROMSTART, fooW, 3, fooW, -5, + NULL, NULL, NULL, 0); + ok(res, "Expected failure of FindNLSStringEx. Return value was %d\n", res); + ok(ERROR_INVALID_PARAMETER == GetLastError(), + "Expected ERROR_INVALID_PARAMETER as last error; got %d\n", GetLastError()); + + for (ptest = test_arr; ptest->src != NULL; ptest++) + { + todo_wine_if(ptest->todo) + { + res = pFindNLSStringEx(ptest->locale, ptest->flags, ptest->src, ptest->src_size, + ptest->value, ptest->val_size, &ptest->found, NULL, NULL, 0); + ok(res == ptest->expected_ret, + "Expected FindNLSStringEx to return %d. Returned value was %d\n", + ptest->expected_ret, res); + ok(ptest->found == ptest->expected_found, + "Expected FindNLSStringEx to output %d. Value was %d\n", + ptest->expected_found, ptest->found); + } + } +} + START_TEST(locale) { InitFunctionPointers(); @@ -5375,6 +5473,7 @@ START_TEST(locale) test_GetSystemPreferredUILanguages(); test_GetThreadPreferredUILanguages(); test_GetUserPreferredUILanguages(); + test_FindNLSStringEx(); /* this requires collation table patch to make it MS compatible */ if (0) test_sorting(); } diff --git a/include/winnls.h b/include/winnls.h index 8cb8af6e8e..ab22bc3cac 100644 --- a/include/winnls.h +++ b/include/winnls.h @@ -352,6 +352,10 @@ static const WCHAR LOCALE_NAME_SYSTEM_DEFAULT[] = {'!','s','y','s','-','d','e',' #define NORM_IGNOREKANATYPE 0x00010000 #define NORM_IGNOREWIDTH 0x00020000 #define NORM_LINGUISTIC_CASING 0x08000000 +#define FIND_STARTSWITH 0x00100000 +#define FIND_ENDSWITH 0x00200000 +#define FIND_FROMSTART 0x00400000 +#define FIND_FROMEND 0x00800000
#define CP_ACP 0 #define CP_OEMCP 1 @@ -961,6 +965,7 @@ WINBASEAPI BOOL WINAPI SetThreadLocale(LCID); WINBASEAPI LANGID WINAPI SetThreadUILanguage(LANGID); WINBASEAPI BOOL WINAPI SetUserGeoID(GEOID); WINBASEAPI INT WINAPI WideCharToMultiByte(UINT,DWORD,LPCWSTR,INT,LPSTR,INT,LPCSTR,LPBOOL); +WINBASEAPI INT WINAPI FindNLSStringEx(const WCHAR *,DWORD,const WCHAR *,INT,const WCHAR *,INT,INT *,LPNLSVERSIONINFO,void *,LPARAM);
#ifdef __cplusplus }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=36542
Your paranoid android.
=== wxppro (32 bit locale) === 09f8:locale: unhandled exception c0000005 at 00000000
=== w2003std (32 bit locale) === 05f0:locale: unhandled exception c0000005 at 00000000
=== wvistau64 (32 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== wvistau64_zh_CN (32 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== wvistau64_fr (32 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== wvistau64_he (32 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== w2008s64 (32 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== wvistau64 (64 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0
=== w2008s64 (64 bit locale) === locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 6. Value was 0 locale.c:5420: Test failed: Expected FindNLSStringEx to return 0. Returned value was -1 locale.c:5423: Test failed: Expected FindNLSStringEx to output 7. Value was 0 The previous 4 run(s) terminated abnormally