kernel32: Implement LCMAP_FULLWIDTH.

Signed-off-by: Akihiro Sagawa <sagawa.aki@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Akihiro Sagawa 2016-10-03 00:06:55 +09:00 committed by Alexandre Julliard
parent 410a9832d1
commit 85cff1717d
2 changed files with 179 additions and 28 deletions

View File

@ -3111,6 +3111,122 @@ BOOL WINAPI GetStringTypeExA( LCID locale, DWORD type, LPCSTR src, INT count, LP
return GetStringTypeA(locale, type, src, count, chartype);
}
/* compose a full-width katakana. return consumed source characters. */
static INT compose_katakana( LPCWSTR src, INT srclen, LPWSTR dst )
{
const static BYTE katakana_map[] = {
/* */ 0x02, 0x0c, 0x0d, 0x01, 0xfb, 0xf2, 0xa1, /* U+FF61- */
0xa3, 0xa5, 0xa7, 0xa9, 0xe3, 0xe5, 0xe7, 0xc3, /* U+FF68- */
0xfc, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xab, 0xad, /* U+FF70- */
0xaf, 0xb1, 0xb3, 0xb5, 0xb7, 0xb9, 0xbb, 0xbd, /* U+FF78- */
0xbf, 0xc1, 0xc4, 0xc6, 0xc8, 0xca, 0xcb, 0xcc, /* U+FF80- */
0xcd, 0xce, 0xcf, 0xd2, 0xd5, 0xd8, 0xdb, 0xde, /* U+FF88- */
0xdf, 0xe0, 0xe1, 0xe2, 0xe4, 0xe6, 0xe8, 0xe9, /* U+FF90- */
0xea, 0xeb, 0xec, 0xed, 0xef, 0xf3, 0x99, 0x9a, /* U+FF98- */
};
WCHAR before, dummy;
if (!dst)
dst = &dummy;
switch (*src)
{
case 0x309b: case 0x309c:
*dst = *src - 2;
return 1;
case 0x30f0: case 0x30f1: case 0x30fd:
*dst = *src;
break;
default:
{
int shift = *src - 0xff61;
if (shift < 0 || shift >= sizeof(katakana_map)/sizeof(katakana_map[0]) )
return 0;
else
*dst = katakana_map[shift] | 0x3000;
}
}
if (srclen <= 1)
return 1;
before = *dst;
/* datakuten (voiced sound) */
if (*(src + 1) == 0xff9e)
{
if ((*src >= 0xff76 && *src <= 0xff84) ||
(*src >= 0xff8a && *src <= 0xff8e) ||
*src == 0x30fd)
*dst += 1;
else if (*src == 0xff73)
*dst = 0x30f4; /* KATAKANA LETTER VU */
else if (*src == 0xff9c)
*dst = 0x30f7; /* KATAKANA LETTER VA */
else if (*src == 0x30f0)
*dst = 0x30f8; /* KATAKANA LETTER VI */
else if (*src == 0x30f1)
*dst = 0x30f9; /* KATAKANA LETTER VE */
else if (*src == 0xff66)
*dst = 0x30fa; /* KATAKANA LETTER VO */
}
/* handakuten (semi-voiced sound) */
if (*(src + 1) == 0xff9f)
if (*src >= 0xff8a && *src <= 0xff8e)
*dst += 2;
return (*dst != before) ? 2 : 1;
}
/* map one or two half-width characters to one full-width character */
static INT map_to_fullwidth( LPCWSTR src, INT srclen, LPWSTR dst )
{
INT n;
if (*src <= '~' && *src > ' ' && *src != '\\')
*dst = *src - 0x20 + 0xff00;
else if (*src == ' ')
*dst = 0x3000;
else if (*src <= 0x00af && *src >= 0x00a2)
{
const static BYTE misc_symbols_table[] = {
0xe0, 0xe1, 0x00, 0xe5, 0xe4, 0x00, 0x00, /* U+00A2- */
0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0xe3 /* U+00A9- */
};
if (misc_symbols_table[*src - 0x00a2])
*dst = misc_symbols_table[*src - 0x00a2] | 0xff00;
else
*dst = *src;
}
else if (*src == 0x20a9) /* WON SIGN */
*dst = 0xffe6;
else if ((n = compose_katakana(src, srclen, dst)) > 0)
return n;
else if (*src >= 0xffa0 && *src <= 0xffdc)
{
const static BYTE hangul_mapping_table[] = {
0x64, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* U+FFA0- */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* U+FFA8- */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* U+FFB0- */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x00, /* U+FFB8- */
0x00, 0x00, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, /* U+FFC0- */
0x00, 0x00, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, /* U+FFC8- */
0x00, 0x00, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, /* U+FFD0- */
0x00, 0x00, 0x61, 0x62, 0x63 /* U+FFD8- */
};
if (hangul_mapping_table[*src - 0xffa0])
*dst = hangul_mapping_table[*src - 0xffa0] | 0x3100;
else
*dst = *src;
}
else
*dst = *src;
return 1;
}
/*************************************************************************
* LCMapStringEx (KERNEL32.@)
*
@ -3194,7 +3310,7 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
}
if (((flags & (NORM_IGNORENONSPACE | NORM_IGNORESYMBOLS)) &&
(flags & ~(NORM_IGNORENONSPACE | NORM_IGNORESYMBOLS))) ||
((flags & (LCMAP_HIRAGANA | LCMAP_KATAKANA)) &&
((flags & (LCMAP_HIRAGANA | LCMAP_KATAKANA | LCMAP_FULLWIDTH)) &&
(flags & (LCMAP_SIMPLIFIED_CHINESE | LCMAP_TRADITIONAL_CHINESE))))
{
SetLastError(ERROR_INVALID_FLAGS);
@ -3222,6 +3338,17 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
len++;
}
}
else if (flags & LCMAP_FULLWIDTH)
{
for (len = 0; srclen; src++, srclen--, len++)
{
if (compose_katakana(src, srclen, NULL) == 2)
{
src++;
srclen--;
}
}
}
else
len = srclen;
return len;
@ -3246,6 +3373,49 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
goto done;
}
if (flags & (LCMAP_FULLWIDTH | LCMAP_HALFWIDTH | LCMAP_HIRAGANA | LCMAP_KATAKANA))
{
for (len = dstlen, dst_ptr = dst; len && srclen; src++, srclen--, len--, dst_ptr++)
{
WCHAR wch;
if (flags & LCMAP_FULLWIDTH)
{
/* map half-width character to full-width one,
e.g. U+FF71 -> U+30A2, U+FF8C U+FF9F -> U+30D7. */
if (map_to_fullwidth(src, srclen, &wch) == 2)
{
src++;
srclen--;
}
}
else
wch = *src;
if (flags & LCMAP_KATAKANA)
{
/* map hiragana to katakana, e.g. U+3041 -> U+30A1.
we can't use C3_HIRAGANA as some characters can't map to katakana */
if ((wch >= 0x3041 && wch <= 0x3096) ||
wch == 0x309D || wch == 0x309E)
wch += 0x60;
}
else if (flags & LCMAP_HIRAGANA)
{
/* map katakana to hiragana, e.g. U+30A1 -> U+3041.
we can't use C3_KATAKANA as some characters can't map to hiragana */
if ((wch >= 0x30A1 && wch <= 0x30F6) ||
wch == 0x30FD || wch == 0x30FE)
wch -= 0x60;
}
*dst_ptr = wch;
}
if (!(flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE)))
goto done;
srclen = dst_ptr - dst;
src = dst;
}
if (flags & LCMAP_UPPERCASE)
{
for (len = dstlen, dst_ptr = dst; srclen && len; src++, srclen--)
@ -3270,29 +3440,6 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
srclen -= len;
}
if (flags & LCMAP_HIRAGANA)
{
/* map katakana to hiragana, e.g. U+30A1 -> U+3041.
we can't use C3_KATAKANA as some characters can't map to hiragana */
for (len = dst_ptr - dst, dst_ptr = dst; len; len--, dst_ptr++)
{
if ((*dst_ptr >= 0x30A1 && *dst_ptr <= 0x30F6) ||
*dst_ptr == 0x30FD || *dst_ptr == 0x30FE)
*dst_ptr -= 0x60;
}
}
else if (flags & LCMAP_KATAKANA)
{
/* map hiragana to katakana, e.g. U+3041 -> U+30A1.
we can't use C3_HIRAGANA as some characters can't map to katakana */
for (len = dst_ptr - dst, dst_ptr = dst; len; len--, dst_ptr++)
{
if ((*dst_ptr >= 0x3041 && *dst_ptr <= 0x3096) ||
*dst_ptr == 0x309D || *dst_ptr == 0x309E)
*dst_ptr += 0x60;
}
}
done:
if (srclen)
{

View File

@ -2214,6 +2214,10 @@ static const DWORD lcmap_invalid_flags[] = {
LCMAP_KATAKANA | NORM_IGNORESYMBOLS,
LCMAP_KATAKANA | LCMAP_SIMPLIFIED_CHINESE,
LCMAP_KATAKANA | LCMAP_TRADITIONAL_CHINESE,
LCMAP_FULLWIDTH | NORM_IGNORENONSPACE,
LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
};
static void test_LCMapStringA(void)
@ -2461,9 +2465,9 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
/* test LCMAP_FULLWIDTH */
ret = func_ptr(LCMAP_FULLWIDTH,
halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
todo_wine ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
ok(ret == lstrlenW(japanese_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
ret, GetLastError(), lstrlenW(japanese_text) + 1);
todo_wine ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
ok(!lstrcmpW(buf, japanese_text), "%s string compare mismatch\n", func_name);
ret2 = func_ptr(LCMAP_FULLWIDTH, halfwidth_text, -1, NULL, 0);
ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret2, ret);
@ -2472,9 +2476,9 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
(half-width katakana is converted into full-wdith hiragana) */
ret = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA,
halfwidth_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
todo_wine ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
ok(ret == lstrlenW(hiragana_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
ret, GetLastError(), lstrlenW(hiragana_text) + 1);
todo_wine ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
ok(!lstrcmpW(buf, hiragana_text), "%s string compare mismatch\n", func_name);
ret2 = func_ptr(LCMAP_FULLWIDTH | LCMAP_HIRAGANA, halfwidth_text, -1, NULL, 0);
ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);