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(a)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;
}
--
2.23.0