[PATCH] kernelbase: Implement ResolveLocaleName

David Curtiss david.curtiss at ni.com
Tue Aug 10 17:16:08 CDT 2021


Signed-off-by: David Curtiss <david.curtiss at ni.com>
---
 dlls/kernel32/tests/locale.c | 94 +++++++++++++++++++++++++++++++++++-
 dlls/kernelbase/locale.c     | 44 +++++++++++++++--
 2 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 75c86bbaf21..7c5f00f91c7 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -87,6 +87,7 @@ static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT
 static LANGID (WINAPI *pSetThreadUILanguage)(LANGID);
 static LANGID (WINAPI *pGetThreadUILanguage)(VOID);
 static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT);
+static INT (WINAPI *pResolveLocaleName)(LPCWSTR, LPWSTR, INT);
 static INT (WINAPI *pFindStringOrdinal)(DWORD, LPCWSTR lpStringSource, INT, LPCWSTR, INT, BOOL);
 static BOOL (WINAPI *pGetNLSVersion)(NLS_FUNCTION,LCID,NLSVERSIONINFO*);
 static BOOL (WINAPI *pGetNLSVersionEx)(NLS_FUNCTION,LPCWSTR,NLSVERSIONINFOEX*);
@@ -135,6 +136,7 @@ static void InitFunctionPointers(void)
   X(SetThreadUILanguage);
   X(GetThreadUILanguage);
   X(NormalizeString);
+  X(ResolveLocaleName);
   X(FindStringOrdinal);
   X(GetNLSVersion);
   X(GetNLSVersionEx);
@@ -1903,7 +1905,7 @@ static void test_CompareStringA(void)
 
     ret = lstrcmpA(NULL, "");
     ok (ret == -1 || broken(ret == -2) /* win9x */, "lstrcmpA(NULL, \"\") should return -1, got %d\n", ret);
- 
+
 
     if (0) { /* this requires collation table patch to make it MS compatible */
     ret = CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, "'o", -1, "-o", -1 );
@@ -6522,6 +6524,95 @@ static void test_NormalizeString(void)
     }
 }
 
+static void test_ResolveLocaleName(void)
+{
+    INT ret;
+    WCHAR buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE], Alternate[BUFFER_SIZE];
+    INT buffer_size = BUFFER_SIZE;
+
+    if (!pResolveLocaleName)
+    {
+        win_skip( "ResolveLocaleName not available\n" );
+        return;
+    }
+
+    /* already-valid cases */
+    STRINGSW("fr-FR","fr-FR");
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    STRINGSW("fr-BE","fr-BE");
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    /* just-resolve cases */
+    STRINGSW("fr","fr-FR");
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    /* truncate-and-resolve cases */
+    STRINGSW("fr-aaa-BE","fr-FR");
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    STRINGSW("fr-BE_aaa","fr-BE"); /* old Windows gives fr-FR; new gives fr-BE */
+    MultiByteToWideChar(CP_ACP,0,"fr-FR",-1,Alternate,ARRAY_SIZE(Alternate));
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW;
+    ok(wcsncmp(buffer, Expected, lstrlenW(Expected)) == 0
+       || wcsncmp(buffer, Alternate, lstrlenW(Alternate)) == 0,
+       "Bad conversion\n");
+
+    STRINGSW("fr-BE-x-y-z","fr-BE");
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    /* just-big-enough buffer size */
+    STRINGSW("fr","fr-FR");
+    buffer_size = lstrlenW(Expected) + 1;
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    buffer_size = BUFFER_SIZE; /* restore normal value */
+
+    /* unknown locales return empty string */
+    STRINGSW("xx-XX",""); /* unknown locale */
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    STRINGSW("xx",""); /* unknown locale, no hyphen */
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    STRINGSW("-en-US",""); /* string is empty after truncated */
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    EXPECT_LENW; EXPECT_EQW;
+
+    /* when no output buffer, returns required buffer size */
+    STRINGSW("en-US","en-US");
+    ret = pResolveLocaleName(input, NULL, buffer_size);
+    EXPECT_LENW;
+
+    STRINGSW("en-US-x-y-z","en-US");
+    ret = pResolveLocaleName(input, NULL, buffer_size);
+    EXPECT_LENW;
+
+    /* buffer-size error cases */
+    STRINGSW("fr","");
+    buffer_size = 5; /* too small to hold "fr-FR\0" */
+    ret = pResolveLocaleName(input, buffer, buffer_size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+        "Expected ret == 0 w/ error %d, got %d (%s), error %d\n",
+        ERROR_INSUFFICIENT_BUFFER, ret, wine_dbgstr_w(buffer), GetLastError());
+
+    /* null-input error cases */
+    STRINGSW("en-US","");
+    ret = pResolveLocaleName(NULL, buffer, buffer_size);
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+        "Expected ret == 0 w/ error %d, got %d (%s), error %d\n",
+        ERROR_INSUFFICIENT_BUFFER, ret, wine_dbgstr_w(buffer), GetLastError());
+}
+
 static void test_SpecialCasing(void)
 {
     int ret, i;
@@ -7180,6 +7271,7 @@ START_TEST(locale)
   test_FindStringOrdinal();
   test_SetThreadUILanguage();
   test_NormalizeString();
+  test_ResolveLocaleName();
   test_SpecialCasing();
   test_NLSVersion();
   test_geo_name();
diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c
index 89b35775053..3fe311b0728 100644
--- a/dlls/kernelbase/locale.c
+++ b/dlls/kernelbase/locale.c
@@ -5623,10 +5623,48 @@ 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;
+    WCHAR local_buffer[LOCALE_NAME_MAX_LENGTH];
+    WCHAR *output_buffer = buffer ? buffer : local_buffer;
+    WCHAR *p = 0;
+    INT new_len;
 
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return 0;
+    if (!name)
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return 0;
+    }
+
+    TRACE( "(%s, %p, %d)\n", debugstr_w(name), buffer, len );
+
+    for (;;)
+    {
+        lcid = LocaleNameToLCID( p ? local_buffer : name, 0 );
+        if (lcid) break;
+
+        if (!p) /* first loop iteration */
+        {
+            lstrcpynW( local_buffer, name, LOCALE_NAME_MAX_LENGTH );
+            local_buffer[LOCALE_NAME_MAX_LENGTH - 1] = L'\0';
+            p = local_buffer + lstrlenW( local_buffer );
+        }
+        if (p == local_buffer)
+        {
+            /* fail-safe in case LocaleNameToLCID doesn't recognize "" */
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return 0;
+        }
+
+        for (--p; p > local_buffer; --p)
+        {
+            if (*p == L'-' || *p == L'_') break;
+        }
+        *p = L'\0';
+    }
+    new_len = LCIDToLocaleName( lcid, output_buffer, len, 0 );
+
+    TRACE( "(%s, %p, %d) returning %d %s\n", debugstr_w(name), buffer, len, new_len, debugstr_w(output_buffer) );
+    return new_len;
 }
 
 
-- 
2.32.0.windows.2




More information about the wine-devel mailing list