diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 65687313fbb..dc9fc7c09e6 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -72,6 +72,7 @@ static INT (WINAPI *pIdnToAscii)(DWORD, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pIdnToUnicode)(DWORD, LPCWSTR, INT, LPWSTR, INT); static INT (WINAPI *pGetLocaleInfoEx)(LPCWSTR, LCTYPE, LPWSTR, INT); static BOOL (WINAPI *pIsValidLocaleName)(LPCWSTR); +static INT (WINAPI *pResolveLocaleName)(LPCWSTR,LPWSTR,INT); static INT (WINAPI *pCompareStringOrdinal)(const WCHAR *, INT, const WCHAR *, INT, BOOL); static INT (WINAPI *pCompareStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPNLSVERSIONINFO, LPVOID, LPARAM); @@ -125,6 +126,7 @@ static void InitFunctionPointers(void) X(IdnToUnicode); X(GetLocaleInfoEx); X(IsValidLocaleName); + X(ResolveLocaleName); X(CompareStringOrdinal); X(CompareStringEx); X(GetGeoInfoA); @@ -5160,6 +5162,77 @@ static void test_IsValidLocaleName(void) ok(!ret, "RtlIsValidLocaleName should have failed\n"); } +static void test_ResolveLocaleName(void) +{ + static const struct { const WCHAR *name, *exp; BOOL broken; } tests[] = + { + { L"en-US", L"en-US" }, + { L"en", L"en-US" }, + { L"en-RR", L"en-US" }, + { L"en-na", L"en-NA", TRUE /* <= win8 */ }, + { L"EN-zz", L"en-US" }, + { L"en-US", L"en-US" }, + { L"de-DE_phoneb", L"de-DE" }, + { L"DE-de-phoneb", L"de-DE" }, + { L"fr-029", L"fr-029", TRUE /* <= win8 */ }, + { L"fr-CH_XX", L"fr-CH", TRUE /* <= win10 1809 */ }, + { L"fr-CHXX", L"fr-FR" }, + { L"zh", L"zh-CN" }, + { L"zh-Hant", L"zh-HK" }, + { L"zh-hans", L"zh-CN" }, + { L"ja-jp_radstr", L"ja-JP" }, + { L"az", L"az-Latn-AZ" }, + { L"uz", L"uz-Latn-UZ" }, + { L"uz-cyrl", L"uz-Cyrl-UZ" }, + { L"ia", L"ia-001", TRUE /* <= win10 1809 */ }, + { L"zz", L"" }, + { L"zzz-ZZZ", L"" }, + { L"zzzz", L"" }, + { L"zz+XX", NULL }, + { L"zz.XX", NULL }, + { LOCALE_NAME_INVARIANT, L"" }, + { LOCALE_NAME_SYSTEM_DEFAULT, NULL }, + }; + INT i, ret; + WCHAR buffer[LOCALE_NAME_MAX_LENGTH]; + + if (!pResolveLocaleName) + { + win_skip( "ResolveLocaleName not available\n" ); + return; + } + for (i = 0; i < ARRAY_SIZE(tests); i++) + { + SetLastError( 0xdeadbeef ); + memset( buffer, 0xcc, sizeof(buffer) ); + ret = pResolveLocaleName( tests[i].name, buffer, sizeof(buffer) ); + if (tests[i].exp) + { + ok( !wcscmp( buffer, tests[i].exp ) || broken( tests[i].broken ), + "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) ); + ok( ret == wcslen(buffer) + 1, "%s: got %u\n", debugstr_w(tests[i].name), ret ); + } + else + { + ok( !ret || broken( ret == 1 ) /* win7 */, + "%s: got %s\n", debugstr_w(tests[i].name), debugstr_w(buffer) ); + if (!ret) + ok( GetLastError() == ERROR_INVALID_PARAMETER, + "%s: wrong error %lu\n", debugstr_w(tests[i].name), GetLastError() ); + } + } + SetLastError( 0xdeadbeef ); + ret = pResolveLocaleName( L"en-US", buffer, 4 ); + ok( !ret, "got %u\n", ret ); + ok( GetLastError() == ERROR_INSUFFICIENT_BUFFER, "wrong error %lu\n", GetLastError() ); + ok( !wcscmp( buffer, L"en-" ), "got %s\n", debugstr_w(buffer) ); + + SetLastError( 0xdeadbeef ); + ret = pResolveLocaleName( L"en-US", NULL, 0 ); + ok( ret == 6, "got %u\n", ret ); + ok( GetLastError() == 0xdeadbeef, "wrong error %lu\n", GetLastError() ); +} + static void test_CompareStringOrdinal(void) { INT ret; @@ -7635,6 +7708,7 @@ START_TEST(locale) test_GetStringTypeW(); test_Idn(); test_IsValidLocaleName(); + test_ResolveLocaleName(); test_CompareStringOrdinal(); test_GetGeoInfo(); test_EnumSystemGeoID(); diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index 25ccfc5f010..b002d219d61 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -6057,10 +6057,41 @@ INT WINAPI DECLSPEC_HOTPATCH NormalizeString(NORM_FORM form, const WCHAR *src, I */ INT WINAPI DECLSPEC_HOTPATCH ResolveLocaleName( LPCWSTR name, LPWSTR buffer, INT len ) { - FIXME( "stub: %s, %p, %d\n", wine_dbgstr_w(name), buffer, len ); + LCID lcid; + UINT pos, datalen; + const NLS_LOCALE_DATA *locale = get_locale_by_name( name, &lcid ); - SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); - return 0; + if (!locale) + { + static const WCHAR valid[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + WCHAR *p, tmp[LOCALE_NAME_MAX_LENGTH]; + + if (wcsspn( name, valid ) < wcslen( name )) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return 0; + } + lstrcpynW( tmp, name, LOCALE_NAME_MAX_LENGTH ); + while (!locale) + { + for (p = tmp + wcslen(tmp) - 1; p >= tmp; p--) if (*p == '-' || *p == '_') break; + if (p <= tmp) break; + *p = 0; + locale = get_locale_by_name( tmp, &lcid ); + } + } + + pos = locale ? (locale->inotneutral ? locale->sname : locale->ssortlocale) : 0; + datalen = locale_strings[pos] + 1; + + if (!len) return datalen; + lstrcpynW( buffer, locale_strings + pos + 1, len ); + if (datalen > len) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + return 0; + } + return datalen; }