Module: wine Branch: master Commit: 86941c44d90fd449c9411ea8679b8ac615a49aab URL: https://source.winehq.org/git/wine.git/?a=commit;h=86941c44d90fd449c9411ea86...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Jun 2 10:10:44 2022 +0200
kernelbase: Add a helper function to map an entire buffer to half width.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/kernel32/tests/locale.c | 6 +++ dlls/kernelbase/locale.c | 98 ++++++++++++++++++-------------------------- 2 files changed, 45 insertions(+), 59 deletions(-)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c index 87c12430dac..4e86da2be34 100644 --- a/dlls/kernel32/tests/locale.c +++ b/dlls/kernel32/tests/locale.c @@ -2515,6 +2515,12 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f ret2 = func_ptr(LCMAP_HALFWIDTH | LCMAP_KATAKANA, japanese_text, -1, NULL, 0); ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
+ /* LCMAP_HALFWIDTH | LCMAP_HIRAGANA maps to Hiragana first */ + ret = func_ptr(LCMAP_HALFWIDTH | LCMAP_HIRAGANA, japanese_text, -1, buf, ARRAY_SIZE(buf)); + ret2 = func_ptr(LCMAP_HALFWIDTH, hiragana_text, -1, buf2, ARRAY_SIZE(buf2)); + ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2); + ok(!lstrcmpW(buf, buf2), "%s string compare mismatch %s vs %s\n", func_name, debugstr_w(buf), debugstr_w(buf2)); + /* test buffer overflow */ SetLastError(0xdeadbeef); ret = func_ptr(LCMAP_UPPERCASE, diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c index a0e4a74658f..9283c17e926 100644 --- a/dlls/kernelbase/locale.c +++ b/dlls/kernelbase/locale.c @@ -3902,7 +3902,7 @@ static int find_substring( const struct sortguid *sortid, DWORD flags, const WCH
/* map buffer to full-width katakana */ -static int map_to_fullwidth( const WCHAR *src, int srclen, WCHAR *dst, int dstlen ) +static int map_to_fullwidth( const USHORT *table, const WCHAR *src, int srclen, WCHAR *dst, int dstlen ) { int pos;
@@ -3945,13 +3945,13 @@ static int map_to_fullwidth( const WCHAR *src, int srclen, WCHAR *dst, int dstle break; } } - if (pos < dstlen) dst[pos] = wch; + if (pos < dstlen) dst[pos] = table ? casemap( table, wch ) : wch; } return pos; }
-/* map single full-width character to single or double half-width characters. */ -static int map_to_halfwidth( WCHAR c, WCHAR *dst, int dstlen ) +/* map full-width characters to single or double half-width characters. */ +static int map_to_halfwidth( const USHORT *table, const WCHAR *src, int srclen, WCHAR *dst, int dstlen ) { static const BYTE katakana_map[] = { @@ -3967,20 +3967,30 @@ static int map_to_halfwidth( WCHAR c, WCHAR *dst, int dstlen ) 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x08, /* U+30f0- */ 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x01 /* U+30f8- */ }; - USHORT shift = c - 0x30ac; - BYTE k; + int pos;
- if (shift < ARRAY_SIZE(katakana_map) && (k = katakana_map[shift])) + for (pos = 0; srclen; src++, srclen--) { - if (dstlen >= 2) + WCHAR ch = table ? casemap( table, *src ) : *src; + USHORT shift = ch - 0x30ac; + BYTE k; + + if (shift < ARRAY_SIZE(katakana_map) && (k = katakana_map[shift])) + { + if (pos < dstlen - 1) + { + dst[pos] = casemap( charmaps[CHARMAP_HALFWIDTH], ch - k ); + dst[pos + 1] = (k == 2) ? 0xff9f : 0xff9e; + } + pos += 2; + } + else { - dst[0] = casemap( charmaps[CHARMAP_HALFWIDTH], c - k ); - dst[1] = (k == 2) ? 0xff9f : 0xff9e; + if (pos < dstlen) dst[pos] = casemap( charmaps[CHARMAP_HALFWIDTH], ch ); + pos++; } - return 2; } - if (dstlen >= 1) dst[0] = casemap( charmaps[CHARMAP_HALFWIDTH], c ); - return 1; + return pos; }
@@ -6386,17 +6396,12 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co } else if (flags & LCMAP_FULLWIDTH) { - len = map_to_fullwidth( src, srclen, NULL, 0 ); + len = map_to_fullwidth( NULL, src, srclen, NULL, 0 ); } else if (flags & LCMAP_HALFWIDTH) { - for (len = 0; srclen; src++, srclen--, len++) - { - WCHAR wch = *src; - /* map Hiragana to Katakana before decomposition if needed */ - if (flags & LCMAP_KATAKANA) wch = casemap( charmaps[CHARMAP_KATAKANA], wch ); - if (map_to_halfwidth( wch, NULL, 0 ) == 2) len++; - } + len = map_to_halfwidth( (flags & LCMAP_KATAKANA) ? charmaps[CHARMAP_KATAKANA] : NULL, + src, srclen, NULL, 0 ); } else len = srclen; return len; @@ -6434,47 +6439,27 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co
if (flags & (LCMAP_FULLWIDTH | LCMAP_HALFWIDTH | LCMAP_HIRAGANA | LCMAP_KATAKANA)) { - if (flags & LCMAP_FULLWIDTH) - { - len = map_to_fullwidth( src, srclen, dst, dstlen ); - if (dstlen && dstlen < len) - { - SetLastError( ERROR_INSUFFICIENT_BUFFER ); - return 0; - } - srclen = len; - src = dst; - } - for (len = dstlen, dst_ptr = dst; len && srclen; src++, srclen--, len--, dst_ptr++) - { - WCHAR wch = *src; + const USHORT *table = NULL;
- if (flags & LCMAP_KATAKANA) wch = casemap( charmaps[CHARMAP_KATAKANA], wch ); - else if (flags & LCMAP_HIRAGANA) wch = casemap( charmaps[CHARMAP_HIRAGANA], wch ); + if (flags & LCMAP_KATAKANA) table = charmaps[CHARMAP_KATAKANA]; + else if (flags & LCMAP_HIRAGANA) table = charmaps[CHARMAP_HIRAGANA];
- if (flags & LCMAP_HALFWIDTH) - { - /* map full-width character to half-width one, - e.g. U+30A2 -> U+FF71, U+30D7 -> U+FF8C U+FF9F. */ - if (map_to_halfwidth(wch, dst_ptr, len) == 2) - { - len--; - dst_ptr++; - if (!len) break; - } - } - else *dst_ptr = wch; - } - if (srclen) + if (flags & LCMAP_FULLWIDTH) + len = map_to_fullwidth( table, src, srclen, dst, dstlen ); + else if (flags & LCMAP_HALFWIDTH) + len = map_to_halfwidth( table, src, srclen, dst, dstlen ); + else + len = casemap_string( table, src, srclen, dst, dstlen ); + + if (dstlen && dstlen < len) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); return 0; } - len = dst_ptr - dst; - if (!(flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE)) || srclen) goto done; - srclen = dst_ptr - dst; src = dst; + srclen = len; } + else len = 0;
if (flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE)) { @@ -6482,11 +6467,6 @@ INT WINAPI DECLSPEC_HOTPATCH LCMapStringEx( const WCHAR *locale, DWORD flags, co table = table + 2 + (flags & LCMAP_LOWERCASE ? table[1] : 0); len = casemap_string( table, src, srclen, dst, dstlen ); } - else - { - len = srclen; - memcpy( dst, src, min( srclen, dstlen ) * sizeof(WCHAR) ); - }
done: if (dstlen && dstlen < len)