[PATCH v2 3/3] kernel32: Implement NormalizeString API function.

Brendan McGrath brendan at redmandi.com
Sat Dec 1 20:35:11 CST 2018


From: Sergio Gómez Del Real <sdelreal at codeweavers.com>

Signed-off-by: Sergio Gómez Del Real <sdelreal at codeweavers.com>
---
 dlls/kernel32/locale.c       | 88 ++++++++++++++++++++++++++++++++++--
 dlls/kernel32/tests/locale.c | 44 ++++++++----------
 2 files changed, 103 insertions(+), 29 deletions(-)

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index e62b849d0917..68ece5e3e4aa 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -5358,15 +5358,93 @@ INT WINAPI GetUserDefaultLocaleName(LPWSTR localename, int buffersize)
     return LCIDToLocaleName(userlcid, localename, buffersize, 0);
 }
 
+static inline int is_valid_norm(NORM_FORM norm)
+{
+   if (norm == NormalizationC || norm == NormalizationD ||
+       norm == NormalizationKC || norm == NormalizationKD)
+       return 1;
+   else
+       return 0;
+}
+
 /******************************************************************************
  *           NormalizeString (KERNEL32.@)
+ *
+ * Normalizes a string according to a Unicode Normalization Form.
+ *
+ * PARAMS
+ *  norm       [I] Normalization Form
+ *  src        [I] Source string to normalize
+ *  srclen     [I] Length of source string (if -1, source string is null-terminated)
+ *  dst        [O] Buffer to write normalized source string (can be NULL)
+ *  dstlen     [I] Length of dst string (can be 0)
+ *
+ * RETURNS
+ *  Success: If dstlen is 0, return size needed, else return size of normalized string.
+ *  Failure: ret <= 0. Use GetLastError to determine error.
  */
-INT WINAPI NormalizeString(NORM_FORM NormForm, LPCWSTR lpSrcString, INT cwSrcLength,
-                           LPWSTR lpDstString, INT cwDstLength)
+INT WINAPI NormalizeString(NORM_FORM norm, LPCWSTR src, INT srclen,
+                           LPWSTR dst, INT dstlen)
 {
-    FIXME("%x %p %d %p %d\n", NormForm, lpSrcString, cwSrcLength, lpDstString, cwDstLength);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return 0;
+    extern int wine_unicode_decompose_string( int compat, const WCHAR *src,
+                                              int srclen, WCHAR *dst, int dstlen );
+    extern int unicode_canonical_composition( WCHAR *str, UINT strlen );
+    extern void unicode_canon_order( WCHAR *str, int strlen );
+
+    WCHAR *decomp = NULL;
+    INT compat = 0;
+    INT needed_len;
+
+    if (src == NULL || !is_valid_norm( norm ))
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
+
+    if (norm == NormalizationKC || norm == NormalizationKD) compat++;
+
+    if (srclen == -1) srclen = strlenW( src ) + 1;
+
+    needed_len = wine_unicode_decompose_string( compat, src, srclen, NULL, 0 );
+
+    if (needed_len < 0)
+    {
+        SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+        return needed_len;
+    }
+
+    if (norm == NormalizationC || norm == NormalizationKC)
+    {
+        decomp = HeapAlloc( GetProcessHeap(), 0, needed_len * sizeof( WCHAR ) );
+        wine_unicode_decompose_string( compat, src, srclen, decomp, needed_len );
+        unicode_canon_order( decomp, needed_len );
+        needed_len = unicode_canonical_composition( decomp, needed_len );
+    }
+
+    if (dstlen < needed_len && dstlen > 0)
+    {
+        if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return -1;
+    }
+    else if (dstlen <= 0)
+    {
+        if (decomp) HeapFree(GetProcessHeap(), 0, decomp);
+        return needed_len;
+    }
+
+    if (norm == NormalizationC || norm == NormalizationKC)
+    {
+        memcpy( dst, decomp, sizeof(WCHAR) * needed_len );
+        HeapFree(GetProcessHeap(), 0, decomp);
+        return needed_len;
+    }
+    else
+    {
+        int decomp_len = wine_unicode_decompose_string( compat, src, srclen, dst, needed_len );
+        unicode_canon_order( dst, needed_len );
+        return decomp_len;
+    }
 }
 
 /******************************************************************************
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 3357d0db9e34..f5d54e065c97 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -5725,10 +5725,8 @@ static void test_NormalizeString(void)
         return;
     }
 
-    todo_wine {
-        dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
-        ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER\n");
-    }
+    dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, 1 );
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Should have failed with ERROR_INSUFFICIENT_BUFFER");
 
     /*
      * For each string, first test passing -1 as srclen to NormalizeString,
@@ -5742,26 +5740,24 @@ static void test_NormalizeString(void)
 
         for (i = 0; i < 4; i++)
         {
-            todo_wine {
-                dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
-                if (dstlen)
-                {
-                    dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
-                    ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
-                       dstlen, strlenW( ptest->expected[i] )+1);
-                    str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
-                    ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
-                }
-
-                dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
-                if (dstlen)
-                {
-                    dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
-                    ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
-                       dstlen, strlenW( ptest->expected[i] ));
-                    str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
-                    ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
-                }
+            dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, NULL, 0 );
+            if (dstlen)
+            {
+                dstlen = pNormalizeString( norm_forms[i], ptest->str, -1, dst, dstlen );
+                ok(dstlen == strlenW( ptest->expected[i] )+1, "Copied length differed: was %d, should be %d\n",
+                   dstlen, strlenW( ptest->expected[i] )+1);
+                str_cmp = strncmpW( ptest->expected[i], dst, dstlen+1 );
+                ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
+            }
+
+            dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), NULL, 0 );
+            if (dstlen)
+            {
+                dstlen = pNormalizeString( norm_forms[i], ptest->str, strlenW(ptest->str), dst, dstlen );
+                ok(dstlen == strlenW( ptest->expected[i] ), "Copied length differed: was %d, should be %d\n",
+                   dstlen, strlenW( ptest->expected[i] ));
+                str_cmp = strncmpW( ptest->expected[i], dst, dstlen );
+                ok( str_cmp == 0, "test failed: returned value was %d\n", str_cmp );
             }
         }
         ptest++;
-- 
2.17.1




More information about the wine-devel mailing list