[PATCH v2 2/3] tools/make_unicode: Implement canonical composition for use in normalization.

Brendan McGrath brendan at redmandi.com
Sat Dec 1 20:35:10 CST 2018


From: Sergio Gómez Del Real <sdelreal at codeweavers.com>

Signed-off-by: Sergio Gómez Del Real <sdelreal at codeweavers.com>
---
 libs/port/compose.c   |  55 +++
 libs/port/decompose.c | 969 ++++++++++++++++++++++++++++++++++++++++++
 tools/make_unicode    | 302 ++++++++++++-
 3 files changed, 1325 insertions(+), 1 deletion(-)

diff --git a/libs/port/compose.c b/libs/port/compose.c
index 06f6062d247b..3168ab5e0fad 100644
--- a/libs/port/compose.c
+++ b/libs/port/compose.c
@@ -380,6 +380,8 @@ static const WCHAR table[0x85e] =
     0x30d8, 0x30da, 0x30db, 0x30dd
 };
 
+#include "decompose.c"
+
 static inline int binary_search( WCHAR ch, int low, int high )
 {
     while (low <= high)
@@ -403,3 +405,56 @@ WCHAR DECLSPEC_HIDDEN wine_compose( const WCHAR *str )
         count = table[2 * pos + 3];
     }
 }
+
+static inline int is_blocked(WCHAR *ptr1, WCHAR *ptr2)
+{
+    if (ptr1 >= ptr2) return -1;
+
+    while (++ptr1 < ptr2)
+    {
+        const WCHAR *map1, *map2;
+        map1 = unicode_table_lookup( *ptr1, 0, idx1_comb, 8, idx2_comb, 4,
+                                     offsets_comb, 4, data_comb, 0 );
+        map2 = unicode_table_lookup( *ptr2, 0, idx1_comb, 8, idx2_comb, 4,
+                                     offsets_comb, 4, data_comb, 0 );
+        if (*map1 == 0 || *map2 <= *map1) return 1;
+    }
+    return 0;
+}
+
+static inline int is_fullexcl(WCHAR ch)
+{
+    const WCHAR *map = unicode_table_lookup( ch, 0, idx1_fullcomp, 8, idx2_fullcomp,
+                                             4, offsets_fullcomp, 4, data_fullcomp, 0 );
+    return (int)*map;
+}
+
+int unicode_canonical_composition( WCHAR *str, int strlen )
+{
+    int i, j;
+    WCHAR dum[3] = {0};
+
+    if (strlen == 0) strlen = strlenW( str );
+
+    for (i = 1; i < strlen; i++)
+    {
+        WCHAR *ptr_comp = str+i-1, comp;
+        if (str[i] == 0) break;
+        while (ptr_comp - str > 0)
+        {
+            if (is_starter( *ptr_comp )) break;
+            --ptr_comp;
+        }
+        if (!is_starter( *ptr_comp ) || is_blocked( ptr_comp, str+i )) continue;
+        dum[0] = *ptr_comp;
+        dum[1] = str[i];
+        comp = wine_compose( dum );
+        if (!comp || is_fullexcl( comp )) continue;
+        *ptr_comp = comp;
+        for (j = i; j < strlen-1; j++) str[j] = str[j+1];
+        strlen--;
+        i--;
+    }
+
+    return strlen;
+}
diff --git a/libs/port/decompose.c b/libs/port/decompose.c
index 311b706901e7..e9dca86fecec 100644
--- a/libs/port/decompose.c
+++ b/libs/port/decompose.c
@@ -2994,6 +2994,926 @@ static const USHORT offsets_decomp[11040] =
     0x0000, 0x21c9, 0x0000, 0x21cb, 0x0000, 0x21cd, 0x0000, 0x0000
 };
 
+static const WCHAR data_comb[670] =
+{
+    0x0000, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0232, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0232, 0x0216, 0x0220, 0x0220, 0x0220,
+    0x0220, 0x0220, 0x0202, 0x0202, 0x0220, 0x0220, 0x0220, 0x0220,
+    0x0202, 0x0202, 0x0220, 0x0220, 0x0220, 0x0220, 0x0220, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0220, 0x0220, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0220, 0x0220, 0x0220, 0x0220, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0240, 0x0230,
+    0x0220, 0x0220, 0x0220, 0x0230, 0x0230, 0x0230, 0x0220, 0x0220,
+    0x0230, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220, 0x0220, 0x0230,
+    0x0232, 0x0220, 0x0220, 0x0230, 0x0233, 0x0234, 0x0234, 0x0233,
+    0x0234, 0x0234, 0x0233, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0220, 0x0230, 0x0230, 0x0230, 0x0222, 0x0220,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0220, 0x0230, 0x0230, 0x0220, 0x0230,
+    0x0230, 0x0222, 0x0228, 0x0230, 0x0010, 0x0011, 0x0012, 0x0013,
+    0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x0019, 0x0020,
+    0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0230, 0x0220, 0x0018,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0030, 0x0031, 0x0032, 0x0027, 0x0028, 0x0029, 0x0030, 0x0031,
+    0x0032, 0x0033, 0x0034, 0x0230, 0x0230, 0x0220, 0x0220, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230, 0x0220,
+    0x0035, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230, 0x0230,
+    0x0220, 0x0230, 0x0230, 0x0220, 0x0036, 0x0230, 0x0220, 0x0230,
+    0x0230, 0x0220, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220, 0x0230,
+    0x0220, 0x0220, 0x0230, 0x0220, 0x0230, 0x0230, 0x0230, 0x0220,
+    0x0230, 0x0220, 0x0230, 0x0220, 0x0230, 0x0220, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220,
+    0x0230, 0x0220, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0220, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230, 0x0220,
+    0x0230, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220, 0x0027, 0x0028,
+    0x0029, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230, 0x0220,
+    0x0220, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0007, 0x0009,
+    0x0230, 0x0220, 0x0230, 0x0230, 0x0007, 0x0009, 0x0230, 0x0007,
+    0x0009, 0x0007, 0x0009, 0x0007, 0x0009, 0x0009, 0x0009, 0x0084,
+    0x0091, 0x0007, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0103,
+    0x0103, 0x0009, 0x0107, 0x0107, 0x0107, 0x0107, 0x0118, 0x0118,
+    0x0122, 0x0122, 0x0122, 0x0122, 0x0220, 0x0220, 0x0220, 0x0220,
+    0x0216, 0x0129, 0x0130, 0x0132, 0x0130, 0x0130, 0x0130, 0x0130,
+    0x0130, 0x0230, 0x0230, 0x0009, 0x0230, 0x0230, 0x0220, 0x0007,
+    0x0009, 0x0009, 0x0220, 0x0230, 0x0230, 0x0230, 0x0009, 0x0009,
+    0x0009, 0x0230, 0x0228, 0x0222, 0x0230, 0x0220, 0x0230, 0x0220,
+    0x0009, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0220, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0220, 0x0220, 0x0230, 0x0230, 0x0220,
+    0x0007, 0x0009, 0x0230, 0x0220, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0009, 0x0009, 0x0007, 0x0009, 0x0009,
+    0x0007, 0x0230, 0x0230, 0x0230, 0x0001, 0x0220, 0x0220, 0x0220,
+    0x0220, 0x0220, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220, 0x0220,
+    0x0230, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0220, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230,
+    0x0230, 0x0234, 0x0214, 0x0220, 0x0202, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0232, 0x0228, 0x0228, 0x0220, 0x0230, 0x0233,
+    0x0220, 0x0230, 0x0220, 0x0230, 0x0230, 0x0001, 0x0001, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0001, 0x0001, 0x0001, 0x0230, 0x0230,
+    0x0230, 0x0001, 0x0001, 0x0230, 0x0220, 0x0230, 0x0001, 0x0001,
+    0x0220, 0x0220, 0x0220, 0x0220, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0009, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0218, 0x0228, 0x0232, 0x0222, 0x0224, 0x0224, 0x0008,
+    0x0008, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0009, 0x0009, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220, 0x0009,
+    0x0007, 0x0009, 0x0230, 0x0230, 0x0230, 0x0220, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0009, 0x0009, 0x0026, 0x0230, 0x0230,
+    0x0230, 0x0230, 0x0230, 0x0230, 0x0230, 0x0220, 0x0220, 0x0220,
+    0x0220, 0x0220, 0x0220, 0x0220, 0x0230, 0x0230
+};
+
+static const BYTE idx1_comb[255] =
+{
+    0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+    0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
+    0x0e, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10,
+    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0x00,
+    0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x18, 0x19, 0x00, 0x00,
+    0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00,
+    0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x21
+};
+
+static const USHORT idx2_comb[544] =
+{
+    /* all-zero 256-char blocks get mapped to here */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x01 */
+    0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x02 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x03 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0009, 0x000a, 0x000b, 0x000c, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x04 */
+    0x0000, 0x000d, 0x0000, 0x0000, 0x000e, 0x000f, 0x0000, 0x0010,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0011, 0x0012, 0x0000,
+    /* sub-index 0x05 */
+    0x0000, 0x0013, 0x0000, 0x0014, 0x0015, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0016, 0x0017,
+    /* sub-index 0x06 */
+    0x0000, 0x0018, 0x0019, 0x0000, 0x0000, 0x001a, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001b, 0x001c, 0x001d,
+    /* sub-index 0x07 */
+    0x0000, 0x0000, 0x0000, 0x001e, 0x001f, 0x0020, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0021, 0x0022, 0x0000, 0x0000, 0x0023,
+    /* sub-index 0x08 */
+    0x0000, 0x0000, 0x0000, 0x0024, 0x0025, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0026, 0x0027, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x09 */
+    0x0000, 0x0000, 0x0000, 0x0028, 0x0029, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x002a, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0a */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x002b, 0x002c, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x002d, 0x002e, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0b */
+    0x0000, 0x0000, 0x0000, 0x002f, 0x0030, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0031, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0c */
+    0x0000, 0x0000, 0x0000, 0x0032, 0x0033, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0034, 0x0035, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0d */
+    0x0000, 0x0036, 0x0000, 0x0037, 0x0000, 0x0000, 0x0000, 0x0038,
+    0x0039, 0x0000, 0x0000, 0x0000, 0x003a, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0e */
+    0x0000, 0x0000, 0x0000, 0x003b, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x003c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x003d, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x10 */
+    0x0000, 0x003e, 0x0000, 0x003f, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0040, 0x0000, 0x0000,
+    /* sub-index 0x11 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0041, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x12 */
+    0x0000, 0x0000, 0x0000, 0x0042, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x13 */
+    0x0000, 0x0043, 0x0000, 0x0000, 0x0000, 0x0000, 0x0044, 0x0045,
+    0x0000, 0x0000, 0x0000, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x14 */
+    0x0000, 0x0000, 0x0000, 0x0047, 0x0048, 0x0000, 0x0049, 0x004a,
+    0x0000, 0x0000, 0x004b, 0x0000, 0x0000, 0x0000, 0x004c, 0x004d,
+    /* sub-index 0x15 */
+    0x0000, 0x0000, 0x0000, 0x004e, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x004f, 0x0050, 0x0051,
+    /* sub-index 0x16 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0052, 0x0053, 0x0054, 0x0055,
+    /* sub-index 0x17 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0056, 0x0057, 0x0058,
+    /* sub-index 0x18 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0059, 0x005a,
+    /* sub-index 0x19 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x005b,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x005c, 0x005d,
+    /* sub-index 0x1a */
+    0x0000, 0x0000, 0x005e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x005f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x1b */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0060, 0x0061,
+    0x0000, 0x0062, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0063,
+    /* sub-index 0x1c */
+    0x0064, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0065, 0x0000, 0x0066, 0x0067,
+    /* sub-index 0x1d */
+    0x0000, 0x0000, 0x0068, 0x0000, 0x0000, 0x0069, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x006a, 0x006b, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x1e */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x006c, 0x006d, 0x0000, 0x0000, 0x006e,
+    /* sub-index 0x1f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x006f, 0x0000,
+    /* sub-index 0x20 */
+    0x0000, 0x0070, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x21 */
+    0x0000, 0x0000, 0x0071, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+static const USHORT offsets_comb[1824] =
+{
+    /* all-zero 16-char blocks get mapped to here */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0300 .. 0x030f */
+    0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
+    0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010,
+    /* 0x0310 .. 0x031f */
+    0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018,
+    0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020,
+    /* 0x0320 .. 0x032f */
+    0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028,
+    0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030,
+    /* 0x0330 .. 0x033f */
+    0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038,
+    0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040,
+    /* 0x0340 .. 0x034f */
+    0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048,
+    0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0000,
+    /* 0x0350 .. 0x035f */
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    /* 0x0360 .. 0x036f */
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    /* 0x0480 .. 0x048f */
+    0x0000, 0x0000, 0x0000, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0590 .. 0x059f */
+    0x0000, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b,
+    0x007c, 0x007d, 0x007e, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083,
+    /* 0x05a0 .. 0x05af */
+    0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b,
+    0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093,
+    /* 0x05b0 .. 0x05bf */
+    0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b,
+    0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x0000, 0x00a2,
+    /* 0x05c0 .. 0x05cf */
+    0x0000, 0x00a3, 0x00a4, 0x0000, 0x00a5, 0x00a6, 0x0000, 0x00a7,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0610 .. 0x061f */
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0640 .. 0x064f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    /* 0x0650 .. 0x065f */
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    /* 0x0670 .. 0x067f */
+    0x00c8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x06d0 .. 0x06df */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00c9, 0x00ca,
+    0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x0000, 0x0000, 0x00d0,
+    /* 0x06e0 .. 0x06ef */
+    0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x0000, 0x0000, 0x00d6,
+    0x00d7, 0x0000, 0x00d8, 0x00d9, 0x00da, 0x00db, 0x0000, 0x0000,
+    /* 0x0710 .. 0x071f */
+    0x0000, 0x00dc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0730 .. 0x073f */
+    0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4,
+    0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec,
+    /* 0x0740 .. 0x074f */
+    0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4,
+    0x00f5, 0x00f6, 0x00f7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x07e0 .. 0x07ef */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc,
+    /* 0x07f0 .. 0x07ff */
+    0x00fd, 0x00fe, 0x00ff, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0101, 0x0000, 0x0000,
+    /* 0x0810 .. 0x081f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0103,
+    0x0104, 0x0105, 0x0000, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a,
+    /* 0x0820 .. 0x082f */
+    0x010b, 0x010c, 0x010d, 0x010e, 0x0000, 0x010f, 0x0110, 0x0111,
+    0x0000, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0000, 0x0000,
+    /* 0x0850 .. 0x085f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0117, 0x0118, 0x0119, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x08d0 .. 0x08df */
+    0x0000, 0x0000, 0x0000, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e,
+    0x011f, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126,
+    /* 0x08e0 .. 0x08ef */
+    0x0127, 0x0128, 0x0000, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d,
+    0x012e, 0x012f, 0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135,
+    /* 0x08f0 .. 0x08ff */
+    0x0136, 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d,
+    0x013e, 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145,
+    /* 0x0930 .. 0x093f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0146, 0x0000, 0x0000, 0x0000,
+    /* 0x0940 .. 0x094f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0147, 0x0000, 0x0000,
+    /* 0x0950 .. 0x095f */
+    0x0000, 0x0148, 0x0149, 0x014a, 0x014b, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x09b0 .. 0x09bf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x014c, 0x0000, 0x0000, 0x0000,
+    /* 0x09c0 .. 0x09cf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014d, 0x0000, 0x0000,
+    /* 0x09f0 .. 0x09ff */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014e, 0x0000,
+    /* 0x0a30 .. 0x0a3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x014f, 0x0000, 0x0000, 0x0000,
+    /* 0x0a40 .. 0x0a4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0150, 0x0000, 0x0000,
+    /* 0x0ab0 .. 0x0abf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0151, 0x0000, 0x0000, 0x0000,
+    /* 0x0ac0 .. 0x0acf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0152, 0x0000, 0x0000,
+    /* 0x0b30 .. 0x0b3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0153, 0x0000, 0x0000, 0x0000,
+    /* 0x0b40 .. 0x0b4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0154, 0x0000, 0x0000,
+    /* 0x0bc0 .. 0x0bcf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0155, 0x0000, 0x0000,
+    /* 0x0c40 .. 0x0c4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0156, 0x0000, 0x0000,
+    /* 0x0c50 .. 0x0c5f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0157, 0x0158, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0cb0 .. 0x0cbf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0159, 0x0000, 0x0000, 0x0000,
+    /* 0x0cc0 .. 0x0ccf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x015a, 0x0000, 0x0000,
+    /* 0x0d30 .. 0x0d3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x015b, 0x015c, 0x0000, 0x0000, 0x0000,
+    /* 0x0d40 .. 0x0d4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x015d, 0x0000, 0x0000,
+    /* 0x0dc0 .. 0x0dcf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x015e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0e30 .. 0x0e3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x015f, 0x0160, 0x0161, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0e40 .. 0x0e4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0162, 0x0163, 0x0164, 0x0165, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0eb0 .. 0x0ebf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0166, 0x0167, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0ec0 .. 0x0ecf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0168, 0x0169, 0x016a, 0x016b, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f10 .. 0x0f1f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x016c, 0x016d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f30 .. 0x0f3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016e, 0x0000, 0x016f,
+    0x0000, 0x0170, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f70 .. 0x0f7f */
+    0x0000, 0x0171, 0x0172, 0x0000, 0x0173, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0174, 0x0175, 0x0176, 0x0177, 0x0000, 0x0000,
+    /* 0x0f80 .. 0x0f8f */
+    0x0178, 0x0000, 0x0179, 0x017a, 0x017b, 0x0000, 0x017c, 0x017d,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0fc0 .. 0x0fcf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017e, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1030 .. 0x103f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x017f,
+    0x0000, 0x0180, 0x0181, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1080 .. 0x108f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0000,
+    /* 0x1350 .. 0x135f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0183, 0x0184, 0x0185,
+    /* 0x1710 .. 0x171f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0186, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1730 .. 0x173f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0187, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x17d0 .. 0x17df */
+    0x0000, 0x0000, 0x0188, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0189, 0x0000, 0x0000,
+    /* 0x18a0 .. 0x18af */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x018a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1930 .. 0x193f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x018b, 0x018c, 0x018d, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1a10 .. 0x1a1f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x018e,
+    0x018f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1a60 .. 0x1a6f */
+    0x0190, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1a70 .. 0x1a7f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0191, 0x0192, 0x0193,
+    0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0000, 0x0000, 0x0199,
+    /* 0x1ab0 .. 0x1abf */
+    0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f, 0x01a0, 0x01a1,
+    0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7, 0x0000, 0x0000,
+    /* 0x1b30 .. 0x1b3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x01a8, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1b40 .. 0x1b4f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x01a9, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1b60 .. 0x1b6f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae,
+    /* 0x1b70 .. 0x1b7f */
+    0x01af, 0x01b0, 0x01b1, 0x01b2, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1ba0 .. 0x1baf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x01b3, 0x01b4, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1be0 .. 0x1bef */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01b5, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1bf0 .. 0x1bff */
+    0x0000, 0x0000, 0x01b6, 0x01b7, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1c30 .. 0x1c3f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01b8,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1cd0 .. 0x1cdf */
+    0x01b9, 0x01ba, 0x01bb, 0x0000, 0x01bc, 0x01bd, 0x01be, 0x01bf,
+    0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c6, 0x01c7,
+    /* 0x1ce0 .. 0x1cef */
+    0x01c8, 0x0000, 0x01c9, 0x01ca, 0x01cb, 0x01cc, 0x01cd, 0x01ce,
+    0x01cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x01d0, 0x0000, 0x0000,
+    /* 0x1cf0 .. 0x1cff */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x01d1, 0x0000, 0x0000, 0x0000,
+    0x01d2, 0x01d3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1dc0 .. 0x1dcf */
+    0x01d4, 0x01d5, 0x01d6, 0x01d7, 0x01d8, 0x01d9, 0x01da, 0x01db,
+    0x01dc, 0x01dd, 0x01de, 0x01df, 0x01e0, 0x01e1, 0x01e2, 0x01e3,
+    /* 0x1dd0 .. 0x1ddf */
+    0x01e4, 0x01e5, 0x01e6, 0x01e7, 0x01e8, 0x01e9, 0x01ea, 0x01eb,
+    0x01ec, 0x01ed, 0x01ee, 0x01ef, 0x01f0, 0x01f1, 0x01f2, 0x01f3,
+    /* 0x1de0 .. 0x1def */
+    0x01f4, 0x01f5, 0x01f6, 0x01f7, 0x01f8, 0x01f9, 0x01fa, 0x01fb,
+    0x01fc, 0x01fd, 0x01fe, 0x01ff, 0x0200, 0x0201, 0x0202, 0x0203,
+    /* 0x1df0 .. 0x1dff */
+    0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209, 0x020a, 0x020b,
+    0x020c, 0x020d, 0x0000, 0x020e, 0x020f, 0x0210, 0x0211, 0x0212,
+    /* 0x20d0 .. 0x20df */
+    0x0213, 0x0214, 0x0215, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a,
+    0x021b, 0x021c, 0x021d, 0x021e, 0x021f, 0x0000, 0x0000, 0x0000,
+    /* 0x20e0 .. 0x20ef */
+    0x0000, 0x0220, 0x0000, 0x0000, 0x0000, 0x0221, 0x0222, 0x0223,
+    0x0224, 0x0225, 0x0226, 0x0227, 0x0228, 0x0229, 0x022a, 0x022b,
+    /* 0x20f0 .. 0x20ff */
+    0x022c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x2ce0 .. 0x2cef */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x022d,
+    /* 0x2cf0 .. 0x2cff */
+    0x022e, 0x022f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x2d70 .. 0x2d7f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0230,
+    /* 0x2de0 .. 0x2def */
+    0x0231, 0x0232, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, 0x0238,
+    0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, 0x0240,
+    /* 0x2df0 .. 0x2dff */
+    0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0248,
+    0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, 0x0250,
+    /* 0x3020 .. 0x302f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256,
+    /* 0x3090 .. 0x309f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0257, 0x0258, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa660 .. 0xa66f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0259,
+    /* 0xa670 .. 0xa67f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x025a, 0x025b, 0x025c, 0x025d,
+    0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, 0x0000, 0x0000,
+    /* 0xa690 .. 0xa69f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0264, 0x0265,
+    /* 0xa6f0 .. 0xa6ff */
+    0x0266, 0x0267, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa800 .. 0xa80f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0268, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa8c0 .. 0xa8cf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0269, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa8e0 .. 0xa8ef */
+    0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, 0x0270, 0x0271,
+    0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279,
+    /* 0xa8f0 .. 0xa8ff */
+    0x027a, 0x027b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa920 .. 0xa92f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x027c, 0x027d, 0x027e, 0x0000, 0x0000,
+    /* 0xa950 .. 0xa95f */
+    0x0000, 0x0000, 0x0000, 0x027f, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa9b0 .. 0xa9bf */
+    0x0000, 0x0000, 0x0000, 0x0280, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xa9c0 .. 0xa9cf */
+    0x0281, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xaab0 .. 0xaabf */
+    0x0282, 0x0000, 0x0283, 0x0284, 0x0285, 0x0000, 0x0000, 0x0286,
+    0x0287, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0288, 0x0289,
+    /* 0xaac0 .. 0xaacf */
+    0x0000, 0x028a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xaaf0 .. 0xaaff */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x028b, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xabe0 .. 0xabef */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x028c, 0x0000, 0x0000,
+    /* 0xfb10 .. 0xfb1f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x028d, 0x0000,
+    /* 0xfe20 .. 0xfe2f */
+    0x028e, 0x028f, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295,
+    0x0296, 0x0297, 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d
+};
+
+const WCHAR data_fullcomp[566] =
+{
+    0x0000, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
+    0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001
+};
+
+const BYTE idx1_fullcomp[252] =
+{
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x05,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+    0x07, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0b, 0x0c, 0x0d
+};
+
+const USHORT idx2_fullcomp[224] =
+{
+    /* all-zero 256-char blocks get mapped to here */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x01 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0002,
+    0x0003, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x02 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0005, 0x0000, 0x0000,
+    /* sub-index 0x03 */
+    0x0000, 0x0000, 0x0000, 0x0006, 0x0000, 0x0007, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x04 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0008, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x05 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0009, 0x000a, 0x000b, 0x000c,
+    0x000d, 0x000e, 0x000f, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x06 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0011,
+    0x0000, 0x0000, 0x0000, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016,
+    /* sub-index 0x07 */
+    0x0017, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x08 */
+    0x0000, 0x0000, 0x0018, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x09 */
+    0x0000, 0x0000, 0x0019, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* sub-index 0x0a */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001a, 0x0000, 0x0000,
+    /* sub-index 0x0b */
+    0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022,
+    0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a,
+    /* sub-index 0x0c */
+    0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032,
+    0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0000, 0x0000,
+    /* sub-index 0x0d */
+    0x0000, 0x0039, 0x003a, 0x003b, 0x003c, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+const USHORT offsets_fullcomp[976] =
+{
+    /* all-zero 16-char blocks get mapped to here */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0340 .. 0x034f */
+    0x0001, 0x0002, 0x0000, 0x0003, 0x0004, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0370 .. 0x037f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0005, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0006, 0x0000,
+    /* 0x0380 .. 0x038f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0007,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0950 .. 0x095f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    /* 0x09d0 .. 0x09df */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0011, 0x0000, 0x0012,
+    /* 0x0a30 .. 0x0a3f */
+    0x0000, 0x0000, 0x0000, 0x0013, 0x0000, 0x0000, 0x0014, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0a50 .. 0x0a5f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0015, 0x0016, 0x0017, 0x0000, 0x0000, 0x0018, 0x0000,
+    /* 0x0b50 .. 0x0b5f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0019, 0x001a, 0x0000, 0x0000,
+    /* 0x0f40 .. 0x0f4f */
+    0x0000, 0x0000, 0x0000, 0x001b, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x001c, 0x0000, 0x0000,
+    /* 0x0f50 .. 0x0f5f */
+    0x0000, 0x0000, 0x001d, 0x0000, 0x0000, 0x0000, 0x0000, 0x001e,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x001f, 0x0000, 0x0000, 0x0000,
+    /* 0x0f60 .. 0x0f6f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f70 .. 0x0f7f */
+    0x0000, 0x0000, 0x0000, 0x0021, 0x0000, 0x0022, 0x0023, 0x0000,
+    0x0024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f80 .. 0x0f8f */
+    0x0000, 0x0025, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x0f90 .. 0x0f9f */
+    0x0000, 0x0000, 0x0000, 0x0026, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0027, 0x0000, 0x0000,
+    /* 0x0fa0 .. 0x0faf */
+    0x0000, 0x0000, 0x0028, 0x0000, 0x0000, 0x0000, 0x0000, 0x0029,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x002a, 0x0000, 0x0000, 0x0000,
+    /* 0x0fb0 .. 0x0fbf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x002b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1f70 .. 0x1f7f */
+    0x0000, 0x002c, 0x0000, 0x002d, 0x0000, 0x002e, 0x0000, 0x002f,
+    0x0000, 0x0030, 0x0000, 0x0031, 0x0000, 0x0032, 0x0000, 0x0000,
+    /* 0x1fb0 .. 0x1fbf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0033, 0x0000, 0x0000, 0x0034, 0x0000,
+    /* 0x1fc0 .. 0x1fcf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0035, 0x0000, 0x0036, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1fd0 .. 0x1fdf */
+    0x0000, 0x0000, 0x0000, 0x0037, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0038, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x1fe0 .. 0x1fef */
+    0x0000, 0x0000, 0x0000, 0x0039, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x003a, 0x0000, 0x0000, 0x003b, 0x003c,
+    /* 0x1ff0 .. 0x1fff */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x003d, 0x0000, 0x003e, 0x0000, 0x003f, 0x0000, 0x0000,
+    /* 0x2000 .. 0x200f */
+    0x0040, 0x0041, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x2120 .. 0x212f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0042, 0x0000,
+    0x0000, 0x0000, 0x0043, 0x0044, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x2320 .. 0x232f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0045, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0x2ad0 .. 0x2adf */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0047, 0x0000, 0x0000, 0x0000,
+    /* 0xf900 .. 0xf90f */
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    /* 0xf910 .. 0xf91f */
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    /* 0xf920 .. 0xf92f */
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    /* 0xf930 .. 0xf93f */
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    /* 0xf940 .. 0xf94f */
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    /* 0xf950 .. 0xf95f */
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    /* 0xf960 .. 0xf96f */
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    /* 0xf970 .. 0xf97f */
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    /* 0xf980 .. 0xf98f */
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    /* 0xf990 .. 0xf99f */
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    /* 0xf9a0 .. 0xf9af */
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    /* 0xf9b0 .. 0xf9bf */
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
+    0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
+    /* 0xf9c0 .. 0xf9cf */
+    0x0108, 0x0109, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e, 0x010f,
+    0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
+    /* 0xf9d0 .. 0xf9df */
+    0x0118, 0x0119, 0x011a, 0x011b, 0x011c, 0x011d, 0x011e, 0x011f,
+    0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0126, 0x0127,
+    /* 0xf9e0 .. 0xf9ef */
+    0x0128, 0x0129, 0x012a, 0x012b, 0x012c, 0x012d, 0x012e, 0x012f,
+    0x0130, 0x0131, 0x0132, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
+    /* 0xf9f0 .. 0xf9ff */
+    0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e, 0x013f,
+    0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
+    /* 0xfa00 .. 0xfa0f */
+    0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x014e, 0x014f,
+    0x0150, 0x0151, 0x0152, 0x0153, 0x0154, 0x0155, 0x0000, 0x0000,
+    /* 0xfa10 .. 0xfa1f */
+    0x0156, 0x0000, 0x0157, 0x0000, 0x0000, 0x0158, 0x0159, 0x015a,
+    0x015b, 0x015c, 0x015d, 0x015e, 0x015f, 0x0160, 0x0161, 0x0000,
+    /* 0xfa20 .. 0xfa2f */
+    0x0162, 0x0000, 0x0163, 0x0000, 0x0000, 0x0164, 0x0165, 0x0000,
+    0x0000, 0x0000, 0x0166, 0x0167, 0x0168, 0x0169, 0x016a, 0x016b,
+    /* 0xfa30 .. 0xfa3f */
+    0x016c, 0x016d, 0x016e, 0x016f, 0x0170, 0x0171, 0x0172, 0x0173,
+    0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017a, 0x017b,
+    /* 0xfa40 .. 0xfa4f */
+    0x017c, 0x017d, 0x017e, 0x017f, 0x0180, 0x0181, 0x0182, 0x0183,
+    0x0184, 0x0185, 0x0186, 0x0187, 0x0188, 0x0189, 0x018a, 0x018b,
+    /* 0xfa50 .. 0xfa5f */
+    0x018c, 0x018d, 0x018e, 0x018f, 0x0190, 0x0191, 0x0192, 0x0193,
+    0x0194, 0x0195, 0x0196, 0x0197, 0x0198, 0x0199, 0x019a, 0x019b,
+    /* 0xfa60 .. 0xfa6f */
+    0x019c, 0x019d, 0x019e, 0x019f, 0x01a0, 0x01a1, 0x01a2, 0x01a3,
+    0x01a4, 0x01a5, 0x01a6, 0x01a7, 0x01a8, 0x01a9, 0x0000, 0x0000,
+    /* 0xfa70 .. 0xfa7f */
+    0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x01af, 0x01b0, 0x01b1,
+    0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7, 0x01b8, 0x01b9,
+    /* 0xfa80 .. 0xfa8f */
+    0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf, 0x01c0, 0x01c1,
+    0x01c2, 0x01c3, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9,
+    /* 0xfa90 .. 0xfa9f */
+    0x01ca, 0x01cb, 0x01cc, 0x01cd, 0x01ce, 0x01cf, 0x01d0, 0x01d1,
+    0x01d2, 0x01d3, 0x01d4, 0x01d5, 0x01d6, 0x01d7, 0x01d8, 0x01d9,
+    /* 0xfaa0 .. 0xfaaf */
+    0x01da, 0x01db, 0x01dc, 0x01dd, 0x01de, 0x01df, 0x01e0, 0x01e1,
+    0x01e2, 0x01e3, 0x01e4, 0x01e5, 0x01e6, 0x01e7, 0x01e8, 0x01e9,
+    /* 0xfab0 .. 0xfabf */
+    0x01ea, 0x01eb, 0x01ec, 0x01ed, 0x01ee, 0x01ef, 0x01f0, 0x01f1,
+    0x01f2, 0x01f3, 0x01f4, 0x01f5, 0x01f6, 0x01f7, 0x01f8, 0x01f9,
+    /* 0xfac0 .. 0xfacf */
+    0x01fa, 0x01fb, 0x01fc, 0x01fd, 0x01fe, 0x01ff, 0x0200, 0x0201,
+    0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
+    /* 0xfad0 .. 0xfadf */
+    0x020a, 0x020b, 0x020c, 0x020d, 0x020e, 0x020f, 0x0210, 0x0211,
+    0x0212, 0x0213, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* 0xfb10 .. 0xfb1f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0214, 0x0000, 0x0215,
+    /* 0xfb20 .. 0xfb2f */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0216, 0x0217, 0x0218, 0x0219, 0x021a, 0x021b,
+    /* 0xfb30 .. 0xfb3f */
+    0x021c, 0x021d, 0x021e, 0x021f, 0x0220, 0x0221, 0x0222, 0x0000,
+    0x0223, 0x0224, 0x0225, 0x0226, 0x0227, 0x0000, 0x0228, 0x0000,
+    /* 0xfb40 .. 0xfb4f */
+    0x0229, 0x022a, 0x0000, 0x022b, 0x022c, 0x0000, 0x022d, 0x022e,
+    0x022f, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234, 0x0235, 0x0000
+};
+
 static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
                                           const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
                                           UINT scale_off, const WCHAR *data, UINT scale_data )
@@ -3009,6 +3929,20 @@ static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1,
     return &data[d];
 }
 
+static inline int reorderable_pair( WCHAR ch1, WCHAR ch2 )
+{
+    const WCHAR *cc1, *cc2;
+
+    if (ch1 == 0 || ch2 == 0) return 0;
+
+    cc1 = unicode_table_lookup( ch1, 0, idx1_comb, 8, idx2_comb, 4,
+                                offsets_comb, 4, data_comb, 0 );
+    cc2 = unicode_table_lookup( ch2, 0, idx1_comb, 8, idx2_comb, 4,
+                                offsets_comb, 4, data_comb, 0 );
+    if (*cc2 < *cc1) return 1;
+    else return 0;
+}
+
 static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
 {
     int total_decomp = 0;
@@ -3072,3 +4006,38 @@ int wine_unicode_decompose_string( int compat, const WCHAR *src,
 
     return dstpos;
 }
+
+int is_starter( WCHAR ch )
+{
+    const WCHAR *map = unicode_table_lookup( ch, 0, idx1_comb, 8, idx2_comb, 4,
+                                             offsets_comb, 4, data_comb, 0 );
+    return (*map == 0) ? 1 : 0;
+}
+
+void unicode_canon_order( WCHAR *str, int strlen )
+{
+    int i, j, m;
+    int sublen = 0, tot_sublen = 0;
+    WCHAR *substr = str;
+
+    for (m = 1; m <= strlen; m++)
+    {
+        if (m == strlen || is_starter( str[m] )) sublen = m - tot_sublen;
+        else continue;
+
+        for (i = 0; i < sublen; i++)
+        {
+            for (j = 1; j < sublen; j++)
+            {
+                if (reorderable_pair( substr[j-1], substr[j] ))
+                {
+                    WCHAR swp = substr[j-1];
+                    substr[j-1] = substr[j];
+                    substr[j] = swp;
+                }
+            }
+        }
+        tot_sublen += m;
+        substr = str+m;
+    }
+}
diff --git a/tools/make_unicode b/tools/make_unicode
index 2aa063bff624..4b1c46fde23c 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -360,6 +360,8 @@ my @joining_table = ();
 my @direction_table = ();
 my @decomp_table = ();
 my @compose_table = ();
+my @comb_class_table = ();
+my @full_comp_table = ();
 my $default_char;
 my $default_wchar;
 
@@ -470,6 +472,11 @@ sub READ_DEFAULTS($)
             }
         }
 
+        if ($comb != 0)
+        {
+            $comb_class_table[$src] = (hex $comb);
+        }
+
         next if $decomp eq "";  # no decomposition, skip it
 
         # store decomposition table
@@ -562,6 +569,25 @@ sub READ_DEFAULTS($)
         my $flag = $ctype{$cat};
         foreach my $i (@{$special_categories{$cat}}) { $category_table[$i] |= $flag; }
     }
+
+    my $UNICODE_DERIVED = open_data_file( $UNIDATA, "DerivedNormalizationProps.txt" );
+    while (<$UNICODE_DERIVED>)
+    {
+        next unless (/^([0-9a-fA-F.]+)\s+;\s+Full_Composition_Exclusion/);
+        my ($first, $last) = split /\.\./,$1;
+        $first = hex $first;
+        if (defined $last)
+        {
+            $last = hex $last;
+            while ($last gt $first)
+            {
+                $full_comp_table[$last] = 1;
+                $last--;
+            }
+        }
+        $full_comp_table[$first] = 1;
+    }
+    close $UNICODE_DERIVED;
 }
 
 
@@ -2255,6 +2281,8 @@ sub dump_compose_table($)
     }
     print OUTPUT "\n};\n\n";
     print OUTPUT <<"EOF";
+#include "decompose.c"
+
 static inline int binary_search( WCHAR ch, int low, int high )
 {
     while (low <= high)
@@ -2278,6 +2306,59 @@ WCHAR DECLSPEC_HIDDEN wine_compose( const WCHAR *str )
         count = table[2 * pos + 3];
     }
 }
+
+static inline int is_blocked(WCHAR *ptr1, WCHAR *ptr2)
+{
+    if (ptr1 >= ptr2) return -1;
+
+    while (++ptr1 < ptr2)
+    {
+        const WCHAR *map1, *map2;
+        map1 = unicode_table_lookup( *ptr1, 0, idx1_comb, 8, idx2_comb, 4,
+                                     offsets_comb, 4, data_comb, 0 );
+        map2 = unicode_table_lookup( *ptr2, 0, idx1_comb, 8, idx2_comb, 4,
+                                     offsets_comb, 4, data_comb, 0 );
+        if (*map1 == 0 || *map2 <= *map1) return 1;
+    }
+    return 0;
+}
+
+static inline int is_fullexcl(WCHAR ch)
+{
+    const WCHAR *map = unicode_table_lookup( ch, 0, idx1_fullcomp, 8, idx2_fullcomp,
+                                             4, offsets_fullcomp, 4, data_fullcomp, 0 );
+    return (int)*map;
+}
+
+int unicode_canonical_composition( WCHAR *str, int strlen )
+{
+    int i, j;
+    WCHAR dum[3] = {0};
+
+    if (strlen == 0) strlen = strlenW( str );
+
+    for (i = 1; i < strlen; i++)
+    {
+        WCHAR *ptr_comp = str+i-1, comp;
+        if (str[i] == 0) break;
+        while (ptr_comp - str > 0)
+        {
+            if (is_starter( *ptr_comp )) break;
+            --ptr_comp;
+        }
+        if (!is_starter( *ptr_comp ) || is_blocked( ptr_comp, str+i )) continue;
+        dum[0] = *ptr_comp;
+        dum[1] = str[i];
+        comp = wine_compose( dum );
+        if (!comp || is_fullexcl( comp )) continue;
+        *ptr_comp = comp;
+        for (j = i; j < strlen-1; j++) str[j] = str[j+1];
+        strlen--;
+        i--;
+    }
+
+    return strlen;
+}
 EOF
     close OUTPUT;
     save_file($filename);
@@ -2346,13 +2427,21 @@ sub dump_decompose_table($)
     my %nfd_lookup = ();
     my %nfkd_lookup = ();
     my %decomp_lookup = ();
+    my %comb_lookup = ();
+    my %fullcomp_lookup = ();
     my @decomp_data = (0);
+    my @comb_data = (0);
+    my @full_comp_data = (0);
     my $pos = 1;
+    my $pos_comb = 1;
+    my $pos_fullcomp = 1;
     my $lastchar_decomp;
+    my $lastchar_comb;
+    my $lastchar_fullcomp;
 
     for (my $i = 0; $i < $utflim; $i++)
     {
-        next unless defined $decomp_table[$i];
+        next unless defined $decomp_table[$i] || defined $comb_class_table[$i] || defined $full_comp_table[$i];
 
         if (defined $decomp_table[$i])
         {
@@ -2406,6 +2495,20 @@ sub dump_decompose_table($)
                 $pos += @nfkd;
             }
         }
+        if (defined $comb_class_table[$i])
+        {
+            push @comb_data, $comb_class_table[$i];
+            $lastchar_comb = $i;
+            $comb_lookup{$i} = $pos_comb;
+            $pos_comb++;
+        }
+        if (defined $full_comp_table[$i])
+        {
+            push @full_comp_data, $full_comp_table[$i];
+            $lastchar_fullcomp = $i;
+            $fullcomp_lookup{$i} = $pos_fullcomp;
+            $pos_fullcomp++;
+        }
     }
 
     printf OUTPUT "static const UINT last_decomposable = 0x%x;\n\n", $lastchar_decomp;
@@ -2497,6 +2600,154 @@ sub dump_decompose_table($)
     }
     print OUTPUT "\n};\n\n";
 
+    # now for Compatibility Class
+
+    printf OUTPUT "static const WCHAR data_comb[%d] =\n", $pos_comb;
+    print OUTPUT "{\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @comb_data );
+    print OUTPUT "\n};\n\n";
+
+    my $comb_pos = 1;
+    my $comb_lim = ($lastchar_comb >> 8) + 1;
+    my @comb_filled = (0) x $comb_lim;
+    for (my $i = 0; $i < $utflim; $i++)
+    {
+        last if $i > $lastchar_comb;
+        next unless defined $comb_class_table[$i];
+        $comb_filled[$i >> 8] = $comb_pos++;
+        $i |= 255;
+    }
+    printf OUTPUT "static const BYTE idx1_comb[%d] =\n", $comb_lim;
+    print OUTPUT "{\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @comb_filled );
+    print OUTPUT "\n};\n\n";
+
+    my $sub_comb_filled_pos = 1;
+    my %sub_comb_filled = ();
+    for (my $i = 0; $i < $comb_lim; $i++)
+    {
+        next unless $comb_filled[$i];
+        for (my $j = 0; $j < 256; $j++)
+        {
+            my $idx = ($i << 8) | $j;
+            next unless defined $comb_class_table[$idx];
+            $sub_comb_filled{$idx >> 4} = $sub_comb_filled_pos++;
+            $j |= 15;
+        }
+    }
+
+    printf OUTPUT "static const USHORT idx2_comb[%d] =\n", $comb_pos * 16;
+    print OUTPUT "{\n";
+    @null_idx = (0) x 16;
+    print OUTPUT "    /* all-zero 256-char blocks get mapped to here */\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+    for (my $i = 0; $i < $comb_lim; $i++)
+    {
+        next unless $comb_filled[$i];
+        printf OUTPUT ",\n    /* sub-index 0x%02x */\n", $comb_filled[$i];
+
+        my @sub_idx;
+        for (my $j = 0; $j < 16; $j++)
+        {
+            my $idx = ($i << 4) | $j;
+            $sub_idx[$j] = $sub_comb_filled{$idx} || 0;
+        }
+        printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+    }
+    print OUTPUT "\n};\n\n";
+
+    printf OUTPUT "static const USHORT offsets_comb[%d] =\n", 16 * $sub_comb_filled_pos;
+    print OUTPUT "{\n";
+    @null_table = (0) x 16;
+    print OUTPUT "    /* all-zero 16-char blocks get mapped to here */\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+    for my $key (sort {$a <=> $b} keys %sub_comb_filled)
+    {
+        printf OUTPUT ",\n    /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+        my @sub_table;
+        for (my $j = 0; $j < 16; $j++)
+        {
+            my $idx = ($key << 4) | $j;
+            $sub_table[$j] = $comb_lookup{$idx} || 0;
+        }
+        printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+    }
+    print OUTPUT "\n};\n\n";
+
+    # now for Full Composition Exclusion
+
+    printf OUTPUT "const WCHAR data_fullcomp[%d] =\n", $pos_fullcomp;
+    print OUTPUT "{\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @full_comp_data );
+    print OUTPUT "\n};\n\n";
+
+    my $fullcomp_pos = 1;
+    my $fullcomp_lim = ($lastchar_fullcomp >> 8) + 1;
+    my @fullcomp_filled = (0) x $fullcomp_lim;
+    for (my $i = 0; $i < $utflim; $i++)
+    {
+        last if $i > $lastchar_fullcomp;
+        next unless defined $full_comp_table[$i];
+        $fullcomp_filled[$i >> 8] = $fullcomp_pos++;
+        $i |= 255;
+    }
+    printf OUTPUT "const BYTE idx1_fullcomp[%d] =\n", $fullcomp_lim;
+    print OUTPUT "{\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%02x", 0, @fullcomp_filled );
+    print OUTPUT "\n};\n\n";
+
+    my $sub_fullcomp_filled_pos = 1;
+    my %sub_fullcomp_filled = ();
+    for (my $i = 0; $i < $fullcomp_lim; $i++)
+    {
+        next unless $fullcomp_filled[$i];
+        for (my $j = 0; $j < 256; $j++)
+        {
+            my $idx = ($i << 8) | $j;
+            next unless defined $full_comp_table[$idx];
+            $sub_fullcomp_filled{$idx >> 4} = $sub_fullcomp_filled_pos++;
+            $j |= 15;
+        }
+    }
+
+    printf OUTPUT "const USHORT idx2_fullcomp[%d] =\n", $fullcomp_pos * 16;
+    print OUTPUT "{\n";
+    @null_idx = (0) x 16;
+    print OUTPUT "    /* all-zero 256-char blocks get mapped to here */\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_idx );
+    for (my $i = 0; $i < $fullcomp_lim; $i++)
+    {
+        next unless $fullcomp_filled[$i];
+        printf OUTPUT ",\n    /* sub-index 0x%02x */\n", $fullcomp_filled[$i];
+
+        my @sub_idx;
+        for (my $j = 0; $j < 16; $j++)
+        {
+            my $idx = ($i << 4) | $j;
+            $sub_idx[$j] = $sub_fullcomp_filled{$idx} || 0;
+        }
+        printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_idx );
+    }
+    print OUTPUT "\n};\n\n";
+
+    printf OUTPUT "const USHORT offsets_fullcomp[%d] =\n", 16 * $sub_fullcomp_filled_pos;
+    print OUTPUT "{\n";
+    @null_table = (0) x 16;
+    print OUTPUT "    /* all-zero 16-char blocks get mapped to here */\n";
+    printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @null_table );
+    for my $key (sort {$a <=> $b} keys %sub_fullcomp_filled)
+    {
+        printf OUTPUT ",\n    /* 0x%03x0 .. 0x%03xf */\n", $key, $key;
+        my @sub_table;
+        for (my $j = 0; $j < 16; $j++)
+        {
+            my $idx = ($key << 4) | $j;
+            $sub_table[$j] = $fullcomp_lookup{$idx} || 0;
+        }
+        printf OUTPUT "%s", DUMP_ARRAY( "0x%04x", 0, @sub_table );
+    }
+    print OUTPUT "\n};\n\n";
+
     print OUTPUT <<"EOF";
 static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1, UINT scale_idx1,
                                           const USHORT *idx2, UINT scale_idx2, const USHORT *offsets,
@@ -2513,6 +2764,20 @@ static const WCHAR *unicode_table_lookup( UINT cp, int compat, const BYTE *idx1,
     return &data[d];
 }
 
+static inline int reorderable_pair( WCHAR ch1, WCHAR ch2 )
+{
+    const WCHAR *cc1, *cc2;
+
+    if (ch1 == 0 || ch2 == 0) return 0;
+
+    cc1 = unicode_table_lookup( ch1, 0, idx1_comb, 8, idx2_comb, 4,
+                                offsets_comb, 4, data_comb, 0 );
+    cc2 = unicode_table_lookup( ch2, 0, idx1_comb, 8, idx2_comb, 4,
+                                offsets_comb, 4, data_comb, 0 );
+    if (*cc2 < *cc1) return 1;
+    else return 0;
+}
+
 static int decompose_char_recursive( int compat, UINT ch, WCHAR *dst, int dstlen )
 {
     int total_decomp = 0;
@@ -2576,6 +2841,41 @@ int wine_unicode_decompose_string( int compat, const WCHAR *src,
 
     return dstpos;
 }
+
+int is_starter( WCHAR ch )
+{
+    const WCHAR *map = unicode_table_lookup( ch, 0, idx1_comb, 8, idx2_comb, 4,
+                                             offsets_comb, 4, data_comb, 0 );
+    return (*map == 0) ? 1 : 0;
+}
+
+void unicode_canon_order( WCHAR *str, int strlen )
+{
+    int i, j, m;
+    int sublen = 0, tot_sublen = 0;
+    WCHAR *substr = str;
+
+    for (m = 1; m <= strlen; m++)
+    {
+        if (m == strlen || is_starter( str[m] )) sublen = m - tot_sublen;
+        else continue;
+
+        for (i = 0; i < sublen; i++)
+        {
+            for (j = 1; j < sublen; j++)
+            {
+                if (reorderable_pair( substr[j-1], substr[j] ))
+                {
+                    WCHAR swp = substr[j-1];
+                    substr[j-1] = substr[j];
+                    substr[j] = swp;
+                }
+            }
+        }
+        tot_sublen += m;
+        substr = str+m;
+    }
+}
 EOF
     close OUTPUT;
     save_file($filename);
-- 
2.17.1




More information about the wine-devel mailing list