From: Brendan McGrath Subject: [PATCH v2 3/3] kernel32: Implement NormalizeString API function. Message-Id: <20181202023511.31914-3-brendan@redmandi.com> Date: Sun, 2 Dec 2018 13:35:11 +1100 In-Reply-To: <20181202023511.31914-1-brendan@redmandi.com> References: <20181202023511.31914-1-brendan@redmandi.com> From: Sergio Gómez Del Real Signed-off-by: Sergio Gómez Del Real --- 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