Alexandre Julliard : kernelbase: Add support for high Unicode planes in LCMapStringEx().

Alexandre Julliard julliard at winehq.org
Mon Jun 6 16:10:30 CDT 2022


Module: wine
Branch: master
Commit: 91cd07310607b12a0b2dd7b47cf59ac566b3fc7c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=91cd07310607b12a0b2dd7b47cf59ac566b3fc7c

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Jun  6 14:38:47 2022 +0200

kernelbase: Add support for high Unicode planes in LCMapStringEx().

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/kernelbase/locale.c | 103 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 84 insertions(+), 19 deletions(-)

diff --git a/dlls/kernelbase/locale.c b/dlls/kernelbase/locale.c
index ac4dc188345..4b00ed90408 100644
--- a/dlls/kernelbase/locale.c
+++ b/dlls/kernelbase/locale.c
@@ -1992,6 +1992,36 @@ static inline WCHAR casemap( const USHORT *table, WCHAR ch )
 }
 
 
+static inline unsigned int casemap_high( const USHORT *table, WCHAR high, WCHAR low )
+{
+    unsigned int off = table[table[256 + (high - 0xd800)] + ((low >> 5) & 0x1f)] + 2 * (low & 0x1f);
+    return 0x10000 + ((high - 0xd800) << 10) + (low - 0xdc00) + MAKELONG( table[off], table[off+1] );
+}
+
+
+static inline BOOL table_has_high_planes( const USHORT *table )
+{
+    return table[0] >= 0x500;
+}
+
+
+static inline int put_utf16( WCHAR *dst, int pos, int dstlen, unsigned int ch )
+{
+    if (ch >= 0x10000)
+    {
+        if (pos < dstlen - 1)
+        {
+            ch -= 0x10000;
+            dst[pos] = 0xd800 | (ch >> 10);
+            dst[pos + 1] = 0xdc00 | (ch & 0x3ff);
+        }
+        return 2;
+    }
+    if (pos < dstlen) dst[pos] = ch;
+    return 1;
+}
+
+
 static inline WORD get_char_type( DWORD type, WCHAR ch )
 {
     const BYTE *ptr = sort.ctype_idx + ((const WORD *)sort.ctype_idx)[ch >> 8];
@@ -2008,11 +2038,37 @@ static inline void map_byterev( const WCHAR *src, int len, WCHAR *dst )
 
 static int casemap_string( const USHORT *table, const WCHAR *src, int srclen, WCHAR *dst, int dstlen )
 {
-    int pos, ret = srclen;
+    if (table_has_high_planes( table ))
+    {
+        unsigned int ch;
+        int pos = 0;
 
-    for (pos = 0; pos < dstlen && srclen; pos++, src++, srclen--)
-        dst[pos] = casemap( table, *src );
-    return ret;
+        while (srclen)
+        {
+            if (srclen > 1 && IS_SURROGATE_PAIR( src[0], src[1] ))
+            {
+                ch = casemap_high( table, src[0], src[1] );
+                src += 2;
+                srclen -= 2;
+            }
+            else
+            {
+                ch = casemap( table, *src );
+                src++;
+                srclen--;
+            }
+            pos += put_utf16( dst, pos, dstlen, ch );
+        }
+        return pos;
+    }
+    else
+    {
+        int pos, ret = srclen;
+
+        for (pos = 0; pos < dstlen && srclen; pos++, src++, srclen--)
+            dst[pos] = casemap( table, *src );
+        return ret;
+    }
 }
 
 
@@ -3912,16 +3968,29 @@ static int find_substring( const struct sortguid *sortid, DWORD flags, const WCH
 /* map buffer to full-width katakana */
 static int map_to_fullwidth( const USHORT *table, const WCHAR *src, int srclen, WCHAR *dst, int dstlen )
 {
-    int pos;
+    int pos, len;
 
-    for (pos = 0; srclen; pos++, src++, srclen--)
+    for (pos = 0; srclen; pos++, src += len, srclen -= len)
     {
-        WCHAR wch = casemap( charmaps[CHARMAP_FULLWIDTH], *src );
+        unsigned int wch = casemap( charmaps[CHARMAP_FULLWIDTH], *src );
+
+        len = 1;
         if (srclen > 1)
         {
-            switch (src[1])
+            if (table_has_high_planes( charmaps[CHARMAP_FULLWIDTH] ) && IS_SURROGATE_PAIR( src[0], src[1] ))
+            {
+                len = 2;
+                wch = casemap_high( charmaps[CHARMAP_FULLWIDTH], src[0], src[1] );
+                if (wch >= 0x10000)
+                {
+                    put_utf16( dst, pos, dstlen, wch );
+                    pos++;
+                    continue;
+                }
+            }
+            else if (src[1] == 0xff9e)  /* dakuten (voiced sound) */
             {
-            case 0xff9e:  /* dakuten (voiced sound) */
+                len = 2;
                 if ((*src >= 0xff76 && *src <= 0xff84) ||
                     (*src >= 0xff8a && *src <= 0xff8e) ||
                     *src == 0x30fd)
@@ -3937,22 +4006,18 @@ static int map_to_fullwidth( const USHORT *table, const WCHAR *src, int srclen,
                 else if (*src == 0xff66)
                     wch = 0x30fa; /* KATAKANA LETTER VO */
                 else
-                    break;
-                src++;
-                srclen--;
-                break;
-            case 0xff9f:  /* handakuten (semi-voiced sound) */
+                    len = 1;
+            }
+            else if (src[1] == 0xff9f)  /* handakuten (semi-voiced sound) */
+            {
                 if (*src >= 0xff8a && *src <= 0xff8e)
                 {
                     wch += 2;
-                    src++;
-                    srclen--;
+                    len = 2;
                 }
-                break;
-            default:
-                break;
             }
         }
+
         if (pos < dstlen) dst[pos] = table ? casemap( table, wch ) : wch;
     }
     return pos;




More information about the wine-cvs mailing list