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

Sergio Gómez Del Real sdelreal at codeweavers.com
Wed Apr 4 11:52:10 CDT 2018


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

diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index c5eeabfbbe..4b0a7902f8 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -5355,13 +5355,69 @@ INT WINAPI GetUserDefaultLocaleName(LPWSTR localename, int buffersize)
 
 /******************************************************************************
  *           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 unsigned int wine_unicode_decompose_string( int compat, const WCHAR *src,
+                                                       int srclen, WCHAR *dst, int dstlen );
+    extern unsigned int unicode_canonical_composition( WCHAR *str, UINT strlen );
+    extern void unicode_canon_order( WCHAR *str, int strlen );
+
+    WCHAR *decomp = NULL;
+    INT compat = 0;
+    UINT needed_len;
+
+    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 (norm == NormalizationC || norm == NormalizationKC)
+    {
+        decomp = HeapAlloc( GetProcessHeap(), 0, needed_len*sizeof(WCHAR)+1 );
+        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)
+    {
+        lstrcpynW( dst, decomp, 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 d8f51d32fa..531752cd43 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -36,6 +36,8 @@
 #include "winerror.h"
 #include "winnls.h"
 
+#include "normalization_tests.h"
+
 static const WCHAR upper_case[] = {'\t','J','U','S','T','!',' ','A',',',' ','T','E','S','T',';',' ','S','T','R','I','N','G',' ','1','/','*','+','-','.','\r','\n',0};
 static const WCHAR lower_case[] = {'\t','j','u','s','t','!',' ','a',',',' ','t','e','s','t',';',' ','s','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
 static const WCHAR title_case[] = {'\t','J','u','s','t','!',' ','A',',',' ','T','e','s','t',';',' ','S','t','r','i','n','g',' ','1','/','*','+','-','.','\r','\n',0};
@@ -104,6 +106,7 @@ static BOOL (WINAPI *pGetUserPreferredUILanguages)(DWORD, ULONG*, WCHAR*, ULONG*
 static WCHAR (WINAPI *pRtlUpcaseUnicodeChar)(WCHAR);
 static INT (WINAPI *pGetNumberFormatEx)(LPCWSTR, DWORD, LPCWSTR, const NUMBERFMTW *, LPWSTR, int);
 static INT (WINAPI *pFindNLSStringEx)(LPCWSTR, DWORD, LPCWSTR, INT, LPCWSTR, INT, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
+static INT (WINAPI *pNormalizeString)(NORM_FORM, LPCWSTR, INT, LPWSTR, INT);
 
 static void InitFunctionPointers(void)
 {
@@ -137,6 +140,7 @@ static void InitFunctionPointers(void)
   X(GetUserPreferredUILanguages);
   X(GetNumberFormatEx);
   X(FindNLSStringEx);
+  X(NormalizeString);
 
   mod = GetModuleHandleA("ntdll");
   X(RtlUpcaseUnicodeChar);
@@ -5444,6 +5448,89 @@ static void test_FindNLSStringEx(void)
     }
 }
 
+static void test_NormalizeString(void)
+{
+    struct test_data_normal test_arr[] =
+    {
+        { part0_str1, part0_nfc1, part0_nfd1, part0_nfkc1, part0_nfkd1 },
+        { part0_str2, part0_nfc2, part0_nfd2, part0_nfkc2, part0_nfkd2 },
+        { part0_str3, part0_nfc3, part0_nfd3, part0_nfkc3, part0_nfkd3 },
+        { part0_str4, part0_nfc4, part0_nfd4, part0_nfkc4, part0_nfkd4 },
+        { part0_str5, part0_nfc5, part0_nfd5, part0_nfkc5, part0_nfkd5 },
+        { part0_str6, part0_nfc6, part0_nfd6, part0_nfkc6, part0_nfkd6 },
+        { part0_str8, part0_nfc8, part0_nfd8, part0_nfkc8, part0_nfkd8 },
+        { part0_str9, part0_nfc9, part0_nfd9, part0_nfkc9, part0_nfkd9 },
+        { part0_str10, part0_nfc10, part0_nfd10, part0_nfkc10, part0_nfkd10 },
+        { part0_str11, part0_nfc11, part0_nfd11, part0_nfkc11, part0_nfkd11 },
+        { part0_str12, part0_nfc12, part0_nfd12, part0_nfkc12, part0_nfkd12 },
+        { part1_str1, part1_nfc1, part1_nfd1, part1_nfkc1, part1_nfkd1 },
+        { part1_str2, part1_nfc2, part1_nfd2, part1_nfkc2, part1_nfkd2 },
+        { part1_str3, part1_nfc3, part1_nfd3, part1_nfkc3, part1_nfkd3 },
+        { part1_str4, part1_nfc4, part1_nfd4, part1_nfkc4, part1_nfkd4 },
+        { part1_str5, part1_nfc5, part1_nfd5, part1_nfkc5, part1_nfkd5 },
+        { part1_str6, part1_nfc6, part1_nfd6, part1_nfkc6, part1_nfkd6 },
+        { part1_str7, part1_nfc7, part1_nfd7, part1_nfkc7, part1_nfkd7 },
+        { part1_str8, part1_nfc8, part1_nfd8, part1_nfkc8, part1_nfkd8 },
+        { part1_str9, part1_nfc9, part1_nfd9, part1_nfkc9, part1_nfkd9 },
+        { part1_str10, part1_nfc10, part1_nfd10, part1_nfkc10, part1_nfkd10 },
+        { part1_str11, part1_nfc11, part1_nfd11, part1_nfkc11, part1_nfkd11 },
+        { 0 }
+    };
+
+    struct test_data_normal *ptest = test_arr;
+
+    if (!pFindNLSStringEx)
+    {
+        win_skip("NormalizeString is not available.\n");
+        return;
+    }
+
+    while (ptest->str != 0)
+    {
+        WCHAR *dst;
+        int str_cmp;
+        int dstlen;
+
+        dstlen = pNormalizeString( NormalizationD, ptest->str, -1, NULL, 0 );
+        dst = HeapAlloc(GetProcessHeap(), 0, dstlen * sizeof(WCHAR) + 1);
+        dstlen = pNormalizeString( NormalizationD, ptest->str, -1, dst, dstlen );
+        ok(dstlen == strlenW(ptest->nfd)+1, "Copied length differed: was %d, should be %d\n",
+           dstlen, strlenW(ptest->nfd)+1);
+        str_cmp = strncmpW(ptest->nfd, dst, dstlen + 1);
+        ok(str_cmp == 0, "NFD test failed: returned value was %d\n", str_cmp);
+        HeapFree(GetProcessHeap(), 0, dst);
+
+        dstlen = pNormalizeString( NormalizationC, ptest->str, -1, NULL, 0 );
+        dst = HeapAlloc(GetProcessHeap(), 0, dstlen * sizeof(WCHAR) + 1);
+        dstlen = pNormalizeString( NormalizationC, ptest->str, -1, dst, dstlen );
+        ok(dstlen == strlenW(ptest->nfc)+1, "Copied length differed: was %d, should be %d\n",
+           dstlen, strlenW(ptest->nfc)+1);
+        str_cmp = strncmpW(ptest->nfc, dst, dstlen + 1);
+        ok(str_cmp == 0, "NFC test failed: returned value was %d\n", str_cmp);
+        HeapFree(GetProcessHeap(), 0, dst);
+
+        dstlen = pNormalizeString( NormalizationKD, ptest->str, -1, NULL, 0 );
+        dst = HeapAlloc(GetProcessHeap(), 0, dstlen * sizeof(WCHAR) + 1);
+        dstlen = pNormalizeString( NormalizationKD, ptest->str, -1, dst, dstlen );
+        ok(dstlen == strlenW(ptest->nfkd)+1, "Copied length differed: was %d, should be %d\n",
+           dstlen, strlenW(ptest->nfkd)+1);
+        str_cmp = strncmpW(ptest->nfkd, dst, dstlen + 1);
+        ok(str_cmp == 0, "NFKD test failed: returned value was %d\n", str_cmp);
+        HeapFree(GetProcessHeap(), 0, dst);
+
+        dstlen = pNormalizeString( NormalizationKC, ptest->str, -1, NULL, 0 );
+        dst = HeapAlloc(GetProcessHeap(), 0, dstlen * sizeof(WCHAR) + 1);
+        dstlen = pNormalizeString( NormalizationKC, ptest->str, -1, dst, dstlen );
+        ok(dstlen == strlenW(ptest->nfkc)+1, "Copied length differed: was %d, should be %d\n",
+           dstlen, strlenW(ptest->nfkc)+1);
+        str_cmp = strncmpW(ptest->nfkc, dst, dstlen + 1);
+        ok(str_cmp == 0, "NFKC test failed: returned value was %d\n", str_cmp);
+        HeapFree(GetProcessHeap(), 0, dst);
+
+        ptest++;
+    }
+}
+
 START_TEST(locale)
 {
   InitFunctionPointers();
@@ -5491,6 +5578,7 @@ START_TEST(locale)
   test_GetThreadPreferredUILanguages();
   test_GetUserPreferredUILanguages();
   test_FindNLSStringEx();
+  test_NormalizeString();
   /* this requires collation table patch to make it MS compatible */
   if (0) test_sorting();
 }
-- 
2.14.1




More information about the wine-devel mailing list