[PATCH v3 1/3] kernel32: Handle GEO_ID and GEO_NAME in GetGeoInfoW(), fix UN format.

João Diogo Ferreira devilj at outlook.pt
Sun Nov 24 10:16:14 CST 2019


UN codes are always formatted in groups of three digits in Windows.
Also added more geotypes to the list of known unhandled cases.

Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
V3: Fix test failure on older Windows versions.
V2: Don't use compound arguments in function call, and PROPERLY handle
GEO_NATION.
Supersedes: 174374

V3: Fix test failure on older Windows versions.

Signed-off-by: João Diogo Craveiro Ferreira <devilj at outlook.pt>
---
 dlls/kernel32/locale.c       | 48 ++++++++++++++++++++++++---
 dlls/kernel32/tests/locale.c | 63 ++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index a5ec6593b0..4a2795cd1c 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -3130,6 +3130,33 @@ BOOL WINAPI SetUserGeoID(GEOID geoid)
 
 /******************************************************************************
  *           GetGeoInfoW (KERNEL32.@)
+ *
+ * Retrieves information about a geographic location by its GeoID.
+ *
+ * PARAMS
+ *   geoid    [I] The GeoID of the location of interest.
+ *   geotype  [I] The type of information to be retrieved (SYSGEOTYPE enum from "winnls.h").
+ *   data     [O] The output buffer to store the information.
+ *   data_len [I] The length of the buffer, measured in WCHARs and including the null terminator.
+ *   lang     [I] Language identifier. Must be 0 unless geotype is GEO_RFC1766 or GEO_LCID.
+ *
+ * RETURNS
+ *   Success: The number of WCHARs (including null) written to the buffer -or-
+ *            if no buffer was provided, the minimum length required to hold the full data.
+ *   Failure: Zero. Call GetLastError() to determine the cause.
+ *
+ * NOTES
+ *   On failure, GetLastError() will return one of the following values:
+ *     - ERROR_INVALID_PARAMETER: the GeoID provided was invalid.
+ *     - ERROR_INVALID_FLAGS: the specified geotype was invalid.
+ *     - ERROR_INSUFFICIENT_BUFFER: the provided buffer was too small to hold the full data.
+ *     - ERROR_CALL_NOT_IMPLEMENTED: (Wine implementation) we don't handle that geotype yet.
+ *
+ *   The list of available GeoIDs can be retrieved with EnumSystemGeoID().
+ *
+ * TODO
+ *   Currently, we only handle the following geotypes: GEO_ID, GEO_NATION, GEO_ISO_UN_NUMBER,
+ *   GEO_ISO2, GEO_ISO3, GEO_PARENT and GEO_NAME.
  */
 INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len, LANGID lang)
 {
@@ -3137,7 +3164,9 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
     WCHAR buffW[12];
     const WCHAR *str = buffW;
     int len;
-    static const WCHAR fmtW[] = {'%','d',0};
+    static const WCHAR xx[] = {'X','X',0};
+    static const WCHAR id_fmtW[] = {'%','d',0};
+    static const WCHAR un_fmtW[] = {'%','0','3','d',0};
 
     TRACE("%d %d %p %d %d\n", geoid, geotype, data, data_len, lang);
 
@@ -3148,13 +3177,15 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
 
     switch (geotype) {
     case GEO_NATION:
-        sprintfW(buffW, fmtW, ptr->id);
+        if (ptr->kind != LOCATION_NATION) return 0;
+    case GEO_ID:
+        sprintfW(buffW, id_fmtW, ptr->id);
         break;
     case GEO_ISO_UN_NUMBER:
-        sprintfW(buffW, fmtW, ptr->uncode);
+        sprintfW(buffW, un_fmtW, ptr->uncode);
         break;
     case GEO_PARENT:
-        sprintfW(buffW, fmtW, ptr->parent);
+        sprintfW(buffW, id_fmtW, ptr->parent);
         break;
     case GEO_ISO2:
         str = ptr->iso2W;
@@ -3162,6 +3193,12 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
     case GEO_ISO3:
         str = ptr->iso3W;
         break;
+    case GEO_NAME:
+        if (ptr->uncode && !strcmpW(xx, ptr->iso2W))
+            sprintfW(buffW, un_fmtW, ptr->uncode);
+        else
+            str = ptr->iso2W;
+        break;
     case GEO_RFC1766:
     case GEO_LCID:
     case GEO_FRIENDLYNAME:
@@ -3170,6 +3207,9 @@ INT WINAPI GetGeoInfoW(GEOID geoid, GEOTYPE geotype, LPWSTR data, int data_len,
     case GEO_OFFICIALLANGUAGES:
     case GEO_LATITUDE:
     case GEO_LONGITUDE:
+    case GEO_DIALINGCODE:
+    case GEO_CURRENCYCODE:
+    case GEO_CURRENCYSYMBOL:
         FIXME("type %d is not supported\n", geotype);
         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
         return 0;
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 0e2c3496a9..b501976228 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -4892,6 +4892,31 @@ static void test_GetGeoInfo(void)
     ok(ret == 4, "got %d\n", ret);
     ok(!strcmp(buffA, "203"), "got %s\n", buffA);
 
+    /* GEO_NATION should fail when the location is of type LOCATION_REGION */
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(39070, GEO_NATION, buffA, 20, 0);
+    ok(ret == 0, "expected 0, got %d\n", ret);
+    ok(*buffA == 0, "expected empty string, got %s\n", buffA);
+
+    /* GEO_ID should return an ID for all location types */
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(203, GEO_ID, buffA, 20, 0);
+    if (!ret)
+        win_skip("GEO_ID not supported.\n");
+    else
+    {
+        ok(ret == 4, "got %d\n", ret);
+        ok(!strcmp(buffA, "203"), "got %s\n", buffA); /* LOCATION_NATION */
+
+        ret = pGetGeoInfoA(47610, GEO_ID, buffA, 20, 0); /* LOCATION_REGION */
+        ok(ret == 6, "got %d\n", ret);
+        ok(!strcmp(buffA, "47610"), "got %s\n", buffA);
+
+        ret = pGetGeoInfoA(333, GEO_ID, buffA, 20, 0); /* LOCATION_BOTH */
+        ok(ret == 4, "got %d\n", ret);
+        ok(!strcmp(buffA, "333"), "got %s\n", buffA);
+    }
+
     /* GEO_PARENT */
     buffA[0] = 0;
     ret = pGetGeoInfoA(203, GEO_PARENT, buffA, 20, 0);
@@ -4911,6 +4936,44 @@ static void test_GetGeoInfo(void)
     {
         ok(ret == 4, "got %d\n", ret);
         ok(!strcmp(buffA, "643"), "got %s\n", buffA);
+
+        /* GEO_ISO_UN_NUMBER should always be zero-padded */
+        buffA[0] = 0;
+        ret = pGetGeoInfoA(27114, GEO_ISO_UN_NUMBER, buffA, 20, 0);
+        ok(ret == 4, "got %d\n", ret);
+        ok(!strcmp(buffA, "009"), "got %s\n", buffA);
+
+        /* We're on Windows 8 or newer. GEO_NATION should fail with LOCATION_BOTH IDs. */
+        buffA[0] = 0;
+        ret = pGetGeoInfoA(333, GEO_NATION, buffA, 20, 0);
+        ok(ret == 0, "got %d\n", ret);
+        ok(*buffA == 0, "got %s\n", buffA);
+    }
+
+    buffA[0] = 0;
+    ret = pGetGeoInfoA(193, GEO_NAME, buffA, 20, 0); /* LOCATION_NATION */
+    if (ret == 0)
+        win_skip("GEO_NAME not supported.\n");
+    else
+    {
+        ok(ret == 3, "expected ret == 3, got %d\n", ret);
+        ok(!strcmp(buffA, "PT"), "expected PT, got %s\n", buffA);
+
+        buffA[0] = 0;
+        ret = pGetGeoInfoA(39070, GEO_NAME, buffA, 20, 0); /* LOCATION_REGION */
+        ok(ret == 4, "expected ret == 4, got %d\n", ret);
+        ok(!strcmp(buffA, "001"), "expected 001, got %s\n", buffA);
+
+        buffA[0] = 0;
+        ret = pGetGeoInfoA(333, GEO_NAME, buffA, 20, 0); /* LOCATION_BOTH */
+        ok(ret == 3, "expected ret == 3, got %d\n", ret);
+        ok(!strcmp(buffA, "AN"), "expected AN, got %s\n", buffA);
+
+        /* Special areas like Johnston Atoll should have geo name "XX" */
+        buffA[0] = 0;
+        ret = pGetGeoInfoA(127, GEO_NAME, buffA, 20, 0);
+        ok(ret == 3, "expected ret == 3, got %d\n", ret);
+        ok(!strcmp(buffA, "XX"), "expected XX, got %s\n", buffA);
     }
 
     /* try invalid type value */
-- 
2.24.0



More information about the wine-devel mailing list