Things were about to get pretty chaotic without these handy helpers.
New constant: * geoname_uncode_fmtW: format string for UN codes in GeoNames.
Registry helper functions: * create_geo_regkey * Renamed create_registry_key to create_intl_regkey.
Geoinfo helper functions: * get_geoinfoptr_by_str: find geoinfo by GEOTYPE (ISO2 or UNCODE currently) * get_geoinfoptr_by_name: parse geoname and find geoinfo; * Renamed get_geoinfo_dataptr to get_geoinfoptr_by_id.
I also removed NLS_RegOpenKey() as it was no longer in use.
Signed-off-by: João Diogo Craveiro Ferreira devilj@outlook.pt --- dlls/kernel32/locale.c | 173 +++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 51 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index 2ac1694cdc..b582324978 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -645,11 +645,11 @@ static BOOL is_genitive_name_supported( LCTYPE lctype ) }
/*********************************************************************** - * create_registry_key + * create_intl_regkey * * Create the Control Panel\International registry key. */ -static inline HANDLE create_registry_key(void) +static inline HANDLE create_intl_regkey(void) { static const WCHAR cplW[] = {'C','o','n','t','r','o','l',' ','P','a','n','e','l',0}; static const WCHAR intlW[] = {'I','n','t','e','r','n','a','t','i','o','n','a','l',0}; @@ -678,6 +678,37 @@ static inline HANDLE create_registry_key(void) return hkey; }
+/*********************************************************************** + * create_geo_regkey + * + * Create the Control Panel\International\Geo registry key. + */ + +static inline HANDLE create_geo_regkey(void) +{ + static const WCHAR geoW[] = {'G','e','o',0}; + UNICODE_STRING name; + OBJECT_ATTRIBUTES attr; + HANDLE intl_key, hkey; + + if (!(intl_key = create_intl_regkey())) + return 0; + + attr.Length = sizeof(attr); + attr.RootDirectory = intl_key; + attr.ObjectName = &name; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + RtlInitUnicodeString(&name, geoW); + + if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) + hkey = 0; + + NtClose(intl_key); + return hkey; +} +
/* update the registry settings for a given locale parameter */ /* return TRUE if an update was needed */ @@ -790,7 +821,7 @@ void LOCALE_InitRegistry(void) HANDLE hkey; LCID lcid = GetUserDefaultLCID();
- if (!(hkey = create_registry_key())) + if (!(hkey = create_intl_regkey())) return; /* don't do anything if we can't create the registry key */
locale_update_registry( hkey, localeW, lcid_LC_MESSAGES, lc_messages_values, @@ -1240,7 +1271,7 @@ static INT get_registry_locale_info( struct registry_value *registry_value, LPWS
if (!registry_value->cached_value) { - if (!(hkey = create_registry_key())) + if (!(hkey = create_intl_regkey())) { RtlLeaveCriticalSection( &cache_section ); return -1; @@ -1686,7 +1717,7 @@ BOOL WINAPI SetLocaleInfoW( LCID lcid, LCTYPE lctype, LPCWSTR data ) /* FIXME: profile functions should map to registry */ WriteProfileStringW( intlW, value->name, data );
- if (!(hkey = create_registry_key())) return FALSE; + if (!(hkey = create_intl_regkey())) return FALSE; RtlInitUnicodeString( &valueW, value->name ); status = NtSetValueKey( hkey, &valueW, 0, REG_SZ, data, (strlenW(data)+1)*sizeof(WCHAR) );
@@ -3593,21 +3624,6 @@ void LOCALE_Init(void) setlocale(LC_NUMERIC, "C"); /* FIXME: oleaut32 depends on this */ }
-static HANDLE NLS_RegOpenKey(HANDLE hRootKey, LPCWSTR szKeyName) -{ - UNICODE_STRING keyName; - OBJECT_ATTRIBUTES attr; - HANDLE hkey; - - RtlInitUnicodeString( &keyName, szKeyName ); - InitializeObjectAttributes(&attr, &keyName, 0, hRootKey, NULL); - - if (NtOpenKey( &hkey, KEY_READ, &attr ) != STATUS_SUCCESS) - hkey = 0; - - return hkey; -} - /****************************************************************************** * EnumSystemLanguageGroupsA (KERNEL32.@) */ @@ -3969,7 +3985,14 @@ static const struct geoinfo_t geoinfodata[] = { { 161832257, {'X','X',0}, {'X','X',0}, 10026358, 419, LOCATION_REGION }, /* Latin America and the Caribbean */ };
-static const struct geoinfo_t *get_geoinfo_dataptr(GEOID geoid) +static const WCHAR geoname_uncode_fmtW[] = {'%','0','3','i',0}; + +/****************************************************************************** + * get_geoinfoptr_by_id + * + * Returns a pointer to a geoinfo struct by finding its GeoID. + */ +static const struct geoinfo_t *get_geoinfoptr_by_id(GEOID geoid) { int min, max;
@@ -3994,18 +4017,88 @@ static const struct geoinfo_t *get_geoinfo_dataptr(GEOID geoid) return NULL; }
+/****************************************************************************** + * get_geoinfoptr_by_str + * + * Returns a pointer to a geoinfo struct by + * matching a string to the specified geotype. + */ + +static const struct geoinfo_t *get_geoinfoptr_by_str(const WCHAR *str, GEOTYPE geotype) +{ + int num; + + if (!str) + return NULL; + + switch (geotype) + { + case GEO_ISO2: + for (int i = 0; i < ARRAY_SIZE(geoinfodata); i++) + if (!(strcmpW(geoinfodata[i].iso2W, str))) return &geoinfodata[i]; + break; + case GEO_ISO_UN_NUMBER: + if (!(num = atoiW(str))) return NULL; + for (int i = 0; i < ARRAY_SIZE(geoinfodata); i++) + if (num == geoinfodata[i].uncode) return &geoinfodata[i]; + break; + } + return NULL; +} + +/****************************************************************************** + * get_geoinfoptr_by_geoname + * + * Automatically parse and fix a geoname and + * return a pointer to the matching geoinfo struct. + */ + +static inline const struct geoinfo_t *get_geoinfoptr_by_name(const WCHAR *name) +{ + WCHAR buffer[3]; + int written = 0, len = 0; + + /* Check if str is a 2-letter country code (and make it uppercase) */ + for (int i = 0; i <= 2; i++) + if ((name[i] <= 127 && isalphaW(name[i]))) + { + buffer[i] = toupperW(name[i]); + written++; + } + else + { + if (!name[i]) + { + buffer[i] = 0; + len = i; + } + break; + } + if (written == 2 && len == 2) + return get_geoinfoptr_by_str(buffer, GEO_ISO2); + + /* Now check if it's a numerical code, up to three digits */ + for (int i = 0; i <= 3; i++) + if (isdigitW(name[i])) continue; + else if (!name[i]) + return get_geoinfoptr_by_str(name, GEO_ISO_UN_NUMBER); + else + break; + + return NULL; +} + /****************************************************************************** * GetUserGeoID (KERNEL32.@) */ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass ) { GEOID ret = GEOID_NOT_AVAILABLE; - static const WCHAR geoW[] = {'G','e','o',0}; static const WCHAR nationW[] = {'N','a','t','i','o','n',0}; static const WCHAR regionW[] = {'R','e','g','i','o','n',0}; WCHAR bufferW[40], *end; DWORD count; - HANDLE hkey, hSubkey = 0; + HANDLE hkey; UNICODE_STRING keyW; const KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)bufferW; count = sizeof(bufferW); @@ -4017,17 +4110,13 @@ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass ) else return ret;
- if (!(hkey = create_registry_key())) return ret; + if (!(hkey = create_geo_regkey())) return ret;
- if ((hSubkey = NLS_RegOpenKey(hkey, geoW))) - { - if((NtQueryValueKey(hSubkey, &keyW, KeyValuePartialInformation, + if((NtQueryValueKey(hkey, &keyW, KeyValuePartialInformation, bufferW, count, &count) == STATUS_SUCCESS ) && info->DataLength) ret = strtolW((LPCWSTR)info->Data, &end, 10); - }
NtClose(hkey); - if (hSubkey) NtClose(hSubkey); return ret; }
@@ -4036,14 +4125,12 @@ GEOID WINAPI GetUserGeoID( GEOCLASS GeoClass ) */ BOOL WINAPI SetUserGeoID( GEOID GeoID ) { - const struct geoinfo_t *geoinfo = get_geoinfo_dataptr(GeoID); - static const WCHAR geoW[] = {'G','e','o',0}; + const struct geoinfo_t *geoinfo = get_geoinfoptr_by_id(GeoID); static const WCHAR nationW[] = {'N','a','t','i','o','n',0}; static const WCHAR regionW[] = {'R','e','g','i','o','n',0}; static const WCHAR formatW[] = {'%','i',0}; - UNICODE_STRING nameW,keyW; + UNICODE_STRING keyW; WCHAR bufferW[10]; - OBJECT_ATTRIBUTES attr; HANDLE hkey;
if (!geoinfo) @@ -4051,35 +4138,19 @@ BOOL WINAPI SetUserGeoID( GEOID GeoID ) SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!(hkey = create_registry_key())) + if (!(hkey = create_geo_regkey())) { SetLastError(ERROR_INTERNAL_ERROR); return FALSE; }
- attr.Length = sizeof(attr); - attr.RootDirectory = hkey; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - RtlInitUnicodeString( &nameW, geoW ); - if (geoinfo->kind == LOCATION_NATION) RtlInitUnicodeString( &keyW, nationW ); else RtlInitUnicodeString( &keyW, regionW );
- if (NtCreateKey( &hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS) - { - NtClose(attr.RootDirectory); - SetLastError(ERROR_INTERNAL_ERROR); - return FALSE; - } - sprintfW(bufferW, formatW, geoinfo->id); NtSetValueKey(hkey, &keyW, 0, REG_SZ, bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)); - NtClose(attr.RootDirectory); NtClose(hkey); return TRUE; } @@ -4097,7 +4168,7 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
TRACE("%d %d %p %d %d\n", geoid, geotype, data, data_len, lang);
- if (!(ptr = get_geoinfo_dataptr(geoid))) { + if (!(ptr = get_geoinfoptr_by_id(geoid))) { SetLastError(ERROR_INVALID_PARAMETER); return 0; }
Hi,
While running your changed tests, 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=58228
Your paranoid android.
=== debian10 (32 bit WoW report) ===
kernel32: comm.c:919: Test failed: OutQueue should not be empty
=== debian10 (64 bit WoW report) ===
kernel32: debugger.c:320: Test failed: GetThreadContext failed: 5 debugger.c:320: Test failed: GetThreadContext failed: 5 debugger.c:320: Test failed: GetThreadContext failed: 5 debugger.c:320: Test failed: GetThreadContext failed: 5