xref: /reactos/dll/win32/kernel32/winnls/string/fold.c (revision 7f3e00c5)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * String folding
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * Copyright 2003 Jon Griffiths
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21*7f3e00c5SAmine Khaldi #include "wine/unicode.h"
22c2c66affSColin Finck 
to_unicode_digit(WCHAR ch)23c2c66affSColin Finck static inline WCHAR to_unicode_digit( WCHAR ch )
24c2c66affSColin Finck {
25*7f3e00c5SAmine Khaldi     extern const WCHAR wine_digitmap[] DECLSPEC_HIDDEN;
26c2c66affSColin Finck     return ch + wine_digitmap[wine_digitmap[ch >> 8] + (ch & 0xff)];
27c2c66affSColin Finck }
28c2c66affSColin Finck 
to_unicode_native(WCHAR ch)29c2c66affSColin Finck static inline WCHAR to_unicode_native( WCHAR ch )
30c2c66affSColin Finck {
31*7f3e00c5SAmine Khaldi     extern const WCHAR wine_compatmap[] DECLSPEC_HIDDEN;
32c2c66affSColin Finck     return ch + wine_compatmap[wine_compatmap[ch >> 8] + (ch & 0xff)];
33c2c66affSColin Finck }
34c2c66affSColin Finck 
35c2c66affSColin Finck static const WCHAR wine_ligatures[] =
36c2c66affSColin Finck {
37c2c66affSColin Finck     0x00c6, 0x00de, 0x00df, 0x00e6, 0x00fe, 0x0132, 0x0133, 0x0152,
38c2c66affSColin Finck     0x0153, 0x01c4, 0x01c5, 0x01c6, 0x01c7, 0x01c8, 0x01c9, 0x01ca,
39c2c66affSColin Finck     0x01cb, 0x01cc, 0x01e2, 0x01e3, 0x01f1, 0x01f2, 0x01f3, 0x01fc,
40c2c66affSColin Finck     0x01fd, 0x05f0, 0x05f1, 0x05f2, 0xfb00, 0xfb01, 0xfb02, 0xfb03,
41c2c66affSColin Finck     0xfb04, 0xfb05, 0xfb06
42c2c66affSColin Finck };
43c2c66affSColin Finck 
44c2c66affSColin Finck /* Unicode expanded ligatures */
45c2c66affSColin Finck static const WCHAR wine_expanded_ligatures[][4] =
46c2c66affSColin Finck {
47c2c66affSColin Finck     { 'A','E','\0',1 },
48c2c66affSColin Finck     { 'T','H','\0',1 },
49c2c66affSColin Finck     { 's','s','\0',1 },
50c2c66affSColin Finck     { 'a','e','\0',1 },
51c2c66affSColin Finck     { 't','h','\0',1 },
52c2c66affSColin Finck     { 'I','J','\0',1 },
53c2c66affSColin Finck     { 'i','j','\0',1 },
54c2c66affSColin Finck     { 'O','E','\0',1 },
55c2c66affSColin Finck     { 'o','e','\0',1 },
56c2c66affSColin Finck     { 'D',0x017d,'\0',1 },
57c2c66affSColin Finck     { 'D',0x017e,'\0',1 },
58c2c66affSColin Finck     { 'd',0x017e,'\0',1 },
59c2c66affSColin Finck     { 'L','J','\0',1 },
60c2c66affSColin Finck     { 'L','j','\0',1 },
61c2c66affSColin Finck     { 'l','j','\0',1 },
62c2c66affSColin Finck     { 'N','J','\0',1 },
63c2c66affSColin Finck     { 'N','j','\0',1 },
64c2c66affSColin Finck     { 'n','j','\0',1 },
65c2c66affSColin Finck     { 0x0100,0x0112,'\0',1 },
66c2c66affSColin Finck     { 0x0101,0x0113,'\0',1 },
67c2c66affSColin Finck     { 'D','Z','\0',1 },
68c2c66affSColin Finck     { 'D','z','\0',1 },
69c2c66affSColin Finck     { 'd','z','\0',1 },
70c2c66affSColin Finck     { 0x00c1,0x00c9,'\0',1 },
71c2c66affSColin Finck     { 0x00e1,0x00e9,'\0',1 },
72c2c66affSColin Finck     { 0x05d5,0x05d5,'\0',1 },
73c2c66affSColin Finck     { 0x05d5,0x05d9,'\0',1 },
74c2c66affSColin Finck     { 0x05d9,0x05d9,'\0',1 },
75c2c66affSColin Finck     { 'f','f','\0',1 },
76c2c66affSColin Finck     { 'f','i','\0',1 },
77c2c66affSColin Finck     { 'f','l','\0',1 },
78c2c66affSColin Finck     { 'f','f','i',2 },
79c2c66affSColin Finck     { 'f','f','l',2 },
80c2c66affSColin Finck     { 0x017f,'t','\0',1 },
81c2c66affSColin Finck     { 's','t','\0',1 }
82c2c66affSColin Finck };
83c2c66affSColin Finck 
get_ligature_len(WCHAR wc)84c2c66affSColin Finck static inline int get_ligature_len( WCHAR wc )
85c2c66affSColin Finck {
86c2c66affSColin Finck     int low = 0, high = sizeof(wine_ligatures)/sizeof(WCHAR) -1;
87c2c66affSColin Finck     while (low <= high)
88c2c66affSColin Finck     {
89c2c66affSColin Finck         int pos = (low + high) / 2;
90c2c66affSColin Finck         if (wine_ligatures[pos] < wc)
91c2c66affSColin Finck             low = pos + 1;
92c2c66affSColin Finck         else if (wine_ligatures[pos] > wc)
93c2c66affSColin Finck             high = pos - 1;
94c2c66affSColin Finck         else
95c2c66affSColin Finck             return wine_expanded_ligatures[pos][3];
96c2c66affSColin Finck     }
97c2c66affSColin Finck     return 0;
98c2c66affSColin Finck }
99c2c66affSColin Finck 
get_ligature(WCHAR wc)100c2c66affSColin Finck static inline const WCHAR* get_ligature( WCHAR wc )
101c2c66affSColin Finck {
102c2c66affSColin Finck     static const WCHAR empty_ligature[] = { '\0','\0','\0', 0 };
103c2c66affSColin Finck     int low = 0, high = sizeof(wine_ligatures)/sizeof(WCHAR) -1;
104c2c66affSColin Finck     while (low <= high)
105c2c66affSColin Finck     {
106c2c66affSColin Finck         int pos = (low + high) / 2;
107c2c66affSColin Finck         if (wine_ligatures[pos] < wc)
108c2c66affSColin Finck             low = pos + 1;
109c2c66affSColin Finck         else if (wine_ligatures[pos] > wc)
110c2c66affSColin Finck             high = pos - 1;
111c2c66affSColin Finck         else
112c2c66affSColin Finck             return wine_expanded_ligatures[pos];
113c2c66affSColin Finck     }
114c2c66affSColin Finck     return empty_ligature;
115c2c66affSColin Finck }
116c2c66affSColin Finck 
117c2c66affSColin Finck /* fold a unicode string */
wine_fold_string(int flags,const WCHAR * src,int srclen,WCHAR * dst,int dstlen)118c2c66affSColin Finck int wine_fold_string( int flags, const WCHAR *src, int srclen, WCHAR *dst, int dstlen )
119c2c66affSColin Finck {
120c2c66affSColin Finck     WCHAR *dstbase = dst;
121c2c66affSColin Finck     const WCHAR *expand;
122c2c66affSColin Finck     int i;
123c2c66affSColin Finck 
124c2c66affSColin Finck     if (srclen == -1)
125c2c66affSColin Finck         srclen = strlenW(src) + 1; /* Include terminating NUL in count */
126c2c66affSColin Finck 
127c2c66affSColin Finck     if (!dstlen)
128c2c66affSColin Finck     {
129c2c66affSColin Finck         /* Calculate the required size for dst */
130c2c66affSColin Finck         dstlen = srclen;
131c2c66affSColin Finck 
132c2c66affSColin Finck         if (flags & MAP_EXPAND_LIGATURES)
133c2c66affSColin Finck         {
134c2c66affSColin Finck             while (srclen--)
135c2c66affSColin Finck             {
136c2c66affSColin Finck                 dstlen += get_ligature_len(*src);
137c2c66affSColin Finck                 src++;
138c2c66affSColin Finck             }
139c2c66affSColin Finck         }
140c2c66affSColin Finck         else if (flags & MAP_COMPOSITE)
141c2c66affSColin Finck         {
142c2c66affSColin Finck             /* FIXME */
143c2c66affSColin Finck         }
144c2c66affSColin Finck         else if (flags & MAP_PRECOMPOSED)
145c2c66affSColin Finck         {
146c2c66affSColin Finck             /* FIXME */
147c2c66affSColin Finck         }
148c2c66affSColin Finck         return dstlen;
149c2c66affSColin Finck     }
150c2c66affSColin Finck 
151c2c66affSColin Finck     if (srclen > dstlen)
152c2c66affSColin Finck         return 0;
153c2c66affSColin Finck 
154c2c66affSColin Finck     dstlen -= srclen;
155c2c66affSColin Finck 
156c2c66affSColin Finck     /* Actually perform the mapping(s) specified */
157c2c66affSColin Finck     for (i = 0; i < srclen; i++)
158c2c66affSColin Finck     {
159c2c66affSColin Finck         WCHAR ch = *src;
160c2c66affSColin Finck 
161c2c66affSColin Finck         if (flags & MAP_EXPAND_LIGATURES)
162c2c66affSColin Finck         {
163c2c66affSColin Finck             expand = get_ligature(ch);
164c2c66affSColin Finck             if (expand[0])
165c2c66affSColin Finck             {
166c2c66affSColin Finck                 if (!dstlen--)
167c2c66affSColin Finck                     return 0;
168c2c66affSColin Finck                 dst[0] = expand[0];
169c2c66affSColin Finck                 if (expand[2])
170c2c66affSColin Finck                 {
171c2c66affSColin Finck                     if (!dstlen--)
172c2c66affSColin Finck                         return 0;
173c2c66affSColin Finck                     *++dst = expand[1];
174c2c66affSColin Finck                     ch = expand[2];
175c2c66affSColin Finck                 }
176c2c66affSColin Finck                 else
177c2c66affSColin Finck                     ch = expand[1];
178c2c66affSColin Finck                 dst++;
179c2c66affSColin Finck             }
180c2c66affSColin Finck         }
181c2c66affSColin Finck         else if (flags & MAP_COMPOSITE)
182c2c66affSColin Finck         {
183c2c66affSColin Finck             /* FIXME */
184c2c66affSColin Finck         }
185c2c66affSColin Finck         else if (flags & MAP_PRECOMPOSED)
186c2c66affSColin Finck         {
187c2c66affSColin Finck             /* FIXME */
188c2c66affSColin Finck         }
189c2c66affSColin Finck         if (flags & MAP_FOLDDIGITS)
190c2c66affSColin Finck             ch = to_unicode_digit(ch);
191c2c66affSColin Finck         if (flags & MAP_FOLDCZONE)
192c2c66affSColin Finck             ch = to_unicode_native(ch);
193c2c66affSColin Finck 
194c2c66affSColin Finck         *dst++ = ch;
195c2c66affSColin Finck         src++;
196c2c66affSColin Finck     }
197c2c66affSColin Finck     return dst - dstbase;
198c2c66affSColin Finck }
199