[PATCH 04/12] kernel32: Add new Geo helper functions and constants.

João Diogo Ferreira devilj at outlook.pt
Tue Oct 22 12:43:33 CDT 2019


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 at 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



More information about the wine-devel mailing list