Akihiro Sagawa : kernel32: Implement LCMAP_HALFWIDTH.
Alexandre Julliard
julliard at winehq.org
Mon Oct 3 14:07:18 CDT 2016
Module: wine
Branch: master
Commit: 429ca40fc89df38342a28047cf387ade9e2a05dc
URL: http://source.winehq.org/git/wine.git/?a=commit;h=429ca40fc89df38342a28047cf387ade9e2a05dc
Author: Akihiro Sagawa <sagawa.aki at gmail.com>
Date: Mon Oct 3 00:06:57 2016 +0900
kernel32: Implement LCMAP_HALFWIDTH.
Signed-off-by: Akihiro Sagawa <sagawa.aki at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/kernel32/locale.c | 121 ++++++++++++++++++++++++++++++++++++++++++-
dlls/kernel32/tests/locale.c | 10 ++--
2 files changed, 126 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c
index 92435c8..8c5736b 100644
--- a/dlls/kernel32/locale.c
+++ b/dlls/kernel32/locale.c
@@ -3227,6 +3227,100 @@ static INT map_to_fullwidth( LPCWSTR src, INT srclen, LPWSTR dst )
return 1;
}
+/* decompose a full-width katakana character into one or two half-width characters. */
+static INT decompose_katakana( WCHAR c, LPWSTR dst, INT dstlen )
+{
+ const static BYTE katakana_map[] = {
+ /* */ 0x9e, 0x9f, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* U+3099- */
+ 0x00, 0x67, 0x71, 0x68, 0x72, 0x69, 0x73, 0x6a, /* U+30a1- */
+ 0x74, 0x6b, 0x75, 0x76, 0x01, 0x77, 0x01, 0x78, /* U+30a8- */
+ 0x01, 0x79, 0x01, 0x7a, 0x01, 0x7b, 0x01, 0x7c, /* U+30b0- */
+ 0x01, 0x7d, 0x01, 0x7e, 0x01, 0x7f, 0x01, 0x80, /* U+30b8- */
+ 0x01, 0x81, 0x01, 0x6f, 0x82, 0x01, 0x83, 0x01, /* U+30c0- */
+ 0x84, 0x01, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, /* U+30c8- */
+ 0x01, 0x02, 0x8b, 0x01, 0x02, 0x8c, 0x01, 0x02, /* U+30d0- */
+ 0x8d, 0x01, 0x02, 0x8e, 0x01, 0x02, 0x8f, 0x90, /* U+30d8- */
+ 0x91, 0x92, 0x93, 0x6c, 0x94, 0x6d, 0x95, 0x6e, /* U+30e0- */
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x00, 0x9c, /* U+30e8- */
+ 0x00, 0x00, 0x66, 0x9d, 0x4e, 0x00, 0x00, 0x08, /* U+30f0- */
+ 0x58, 0x58, 0x08, 0x65, 0x70, 0x00, 0x51 /* U+30f8- */
+ };
+ INT len = 0, shift = c - 0x3099;
+ BYTE k;
+
+ if (shift < 0 || shift >= sizeof(katakana_map)/sizeof(katakana_map[0]))
+ return 0;
+
+ k = katakana_map[shift];
+
+ if (!k)
+ {
+ if (dstlen > 0)
+ *dst = c;
+ len++;
+ }
+ else if (k > 0x60)
+ {
+ if (dstlen > 0)
+ *dst = k | 0xff00;
+ len++;
+ }
+ else
+ {
+ if (dstlen >= 2)
+ {
+ dst[0] = (k > 0x50) ? (c - (k & 0xf)) : (katakana_map[shift - k] | 0xff00);
+ dst[1] = (k == 2) ? 0xff9f : 0xff9e;
+ }
+ len += 2;
+ }
+ return len;
+}
+
+/* map single full-width character to single or double half-width characters. */
+static INT map_to_halfwidth(WCHAR c, LPWSTR dst, INT dstlen)
+{
+ INT n = decompose_katakana(c, dst, dstlen);
+ if (n > 0)
+ return n;
+
+ if (c == 0x3000)
+ *dst = ' ';
+ else if (c == 0x3001)
+ *dst = 0xff64;
+ else if (c == 0x3002)
+ *dst = 0xff61;
+ else if (c == 0x300c || c == 0x300d)
+ *dst = (c - 0x300c) + 0xff62;
+ else if (c >= 0x3131 && c <= 0x3163)
+ {
+ *dst = c - 0x3131 + 0xffa1;
+ if (*dst >= 0xffbf) *dst += 3;
+ if (*dst >= 0xffc8) *dst += 2;
+ if (*dst >= 0xffd0) *dst += 2;
+ if (*dst >= 0xffd8) *dst += 2;
+ }
+ else if (c == 0x3164)
+ *dst = 0xffa0;
+ else if (c == 0x2019)
+ *dst = '\'';
+ else if (c == 0x201d)
+ *dst = '"';
+ else if (c > 0xff00 && c < 0xff5f && c != 0xff3c)
+ *dst = c - 0xff00 + 0x20;
+ else if (c >= 0xffe0 && c <= 0xffe6)
+ {
+ const static WCHAR misc_symbol_map[] = {
+ 0x00a2, 0x00a3, 0x00ac, 0x00af, 0x00a6, 0x00a5, 0x20a9
+ };
+ *dst = misc_symbol_map[c - 0xffe0];
+ }
+ else
+ *dst = c;
+
+ return 1;
+}
+
/*************************************************************************
* LCMapStringEx (KERNEL32.@)
*
@@ -3310,7 +3404,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 | LCMAP_FULLWIDTH)) &&
+ ((flags & (LCMAP_HIRAGANA | LCMAP_KATAKANA | LCMAP_HALFWIDTH | LCMAP_FULLWIDTH)) &&
(flags & (LCMAP_SIMPLIFIED_CHINESE | LCMAP_TRADITIONAL_CHINESE))))
{
SetLastError(ERROR_INVALID_FLAGS);
@@ -3349,6 +3443,12 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
}
}
}
+ else if (flags & LCMAP_HALFWIDTH)
+ {
+ for (len = 0; srclen; src++, srclen--, len++)
+ if (decompose_katakana(*src, NULL, 0) == 2)
+ len++;
+ }
else
len = srclen;
return len;
@@ -3407,7 +3507,24 @@ INT WINAPI LCMapStringEx(LPCWSTR name, DWORD flags, LPCWSTR src, INT srclen, LPW
wch == 0x30FD || wch == 0x30FE)
wch -= 0x60;
}
- *dst_ptr = wch;
+
+ 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, dstlen) == 2)
+ {
+ dstlen--;
+ dst_ptr++;
+ if (!dstlen)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ }
+ }
+ else
+ *dst_ptr = wch;
}
if (!(flags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE)))
goto done;
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 0f55de0..dd946a2 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -2218,6 +2218,10 @@ static const DWORD lcmap_invalid_flags[] = {
LCMAP_FULLWIDTH | NORM_IGNORESYMBOLS,
LCMAP_FULLWIDTH | LCMAP_SIMPLIFIED_CHINESE,
LCMAP_FULLWIDTH | LCMAP_TRADITIONAL_CHINESE,
+ LCMAP_HALFWIDTH | NORM_IGNORENONSPACE,
+ LCMAP_HALFWIDTH | NORM_IGNORESYMBOLS,
+ LCMAP_HALFWIDTH | LCMAP_SIMPLIFIED_CHINESE,
+ LCMAP_HALFWIDTH | LCMAP_TRADITIONAL_CHINESE,
};
static void test_LCMapStringA(void)
@@ -2486,9 +2490,9 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
/* test LCMAP_HALFWIDTH */
ret = func_ptr(LCMAP_HALFWIDTH,
japanese_text, -1, buf, sizeof(buf)/sizeof(WCHAR));
- todo_wine ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
+ ok(ret == lstrlenW(halfwidth_text) + 1, "%s ret %d, error %d, expected value %d\n", func_name,
ret, GetLastError(), lstrlenW(halfwidth_text) + 1);
- todo_wine ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
+ ok(!lstrcmpW(buf, halfwidth_text), "%s string compare mismatch\n", func_name);
ret2 = func_ptr(LCMAP_HALFWIDTH, japanese_text, -1, NULL, 0);
ok(ret == ret2, "%s ret %d, expected value %d\n", func_name, ret, ret2);
@@ -2505,7 +2509,7 @@ static void test_lcmapstring_unicode(lcmapstring_wrapper func_ptr, const char *f
buf[0] = 0x30ac;
SetLastError(0xdeadbeef);
ret = func_ptr(LCMAP_HALFWIDTH, buf, 1, buf2, 1);
- todo_wine ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"%s should return 0 and ERROR_INSUFFICIENT_BUFFER, got %d\n", func_name, ret);
/* LCMAP_UPPERCASE or LCMAP_LOWERCASE should accept src == dst */
More information about the wine-cvs
mailing list