Alexandre Julliard : kernelbase: Implement ResolveLocaleName().
Alexandre Julliard
julliard at winehq.org
Mon May 2 16:02:10 CDT 2022
Module: wine
Branch: master
Commit: ea1eae646dd8aceb5078a8675e32be65c53da304
URL: https://source.winehq.org/git/wine.git/?a=commit;h=ea1eae646dd8aceb5078a8675e32be65c53da304
Author: Alexandre Julliard <julliard at winehq.org>
Date: Mon May 2 14:12:10 2022 +0200
kernelbase: Implement ResolveLocaleName().
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/kernel32/tests/locale.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
dlls/kernelbase/locale.c | 37 ++++++++++++++++++++--
2 files changed, 108 insertions(+), 3 deletions(-)
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;
}
More information about the wine-cvs
mailing list