8 #include "locale_impl.h"
20 #define SHIFT_JIS 0321
27 /* Definitions of charmaps. Each charmap consists of:
28 * 1. Empty-string-terminated list of null-terminated aliases.
29 * 2. Special type code or number of elided entries.
30 * 3. Character table (size determined by field 2). */
32 static const unsigned char charmaps
[] =
35 "ucs2\0ucs2be\0\0\304"
37 "utf16\0utf16be\0\0\302"
39 "ucs4\0ucs4be\0utf32\0utf32be\0\0\300"
40 "ucs4le\0utf32le\0\0\303"
41 "ascii\0usascii\0iso646\0iso646us\0\0\307"
43 "shiftjis\0sjis\0\0\321"
47 "big5\0bigfive\0cp950\0big5hkscs\0\0\340"
48 "euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
49 #include "codepages.h"
52 static const unsigned short legacy_chars
[] = {
53 #include "legacychars.h"
56 static const unsigned short jis0208
[84][94] = {
60 static const unsigned short gb18030
[126][190] = {
64 static const unsigned short big5
[89][157] = {
68 static const unsigned short hkscs
[] = {
72 static const unsigned short ksc
[93][94] = {
76 static int fuzzycmp(const unsigned char *a
, const unsigned char *b
)
78 for (; *a
&& *b
; a
++, b
++) {
79 while (*a
&& (*a
|32U)-'a'>26 && *a
-'0'>10U) a
++;
80 if ((*a
|32U) != *b
) return 1;
85 static size_t find_charmap(const void *name
)
87 const unsigned char *s
;
88 if (!*(char *)name
) name
=charmaps
; /* "utf8" */
89 for (s
=charmaps
; *s
; ) {
90 if (!fuzzycmp(name
, s
)) {
91 for (; *s
; s
+=strlen((void *)s
)+1);
94 s
+= strlen((void *)s
)+1;
96 if (s
[1] > 0200) s
+=2;
97 else s
+=2+(128U-s
[1])/4*5;
103 iconv_t
iconv_open(const char *to
, const char *from
)
107 if ((t
= find_charmap(to
))==-1
108 || (f
= find_charmap(from
))==-1
109 || (charmaps
[t
] >= 0320)) {
114 return (void *)(f
<<16 | t
);
117 int iconv_close(iconv_t cd
)
122 static unsigned get_16(const unsigned char *s
, int e
)
125 return s
[e
]<<8 | s
[1-e
];
128 static void put_16(unsigned char *s
, unsigned c
, int e
)
135 static unsigned get_32(const unsigned char *s
, int e
)
138 return s
[e
]+0U<<24 | s
[e
^1]<<16 | s
[e
^2]<<8 | s
[e
^3];
141 static void put_32(unsigned char *s
, unsigned c
, int e
)
150 /* Adapt as needed */
151 #define mbrtowc_utf8 mbrtowc
152 #define wctomb_utf8 wctomb
154 size_t iconv(iconv_t cd0
, char **restrict in
, size_t *restrict inb
, char **restrict out
, size_t *restrict outb
)
157 unsigned long cd
= (unsigned long)cd0
;
158 unsigned to
= cd
& 0xffff;
159 unsigned from
= cd
>> 16;
160 const unsigned char *map
= charmaps
+from
+1;
161 const unsigned char *tomap
= charmaps
+to
+1;
167 unsigned char type
= map
[-1];
168 unsigned char totype
= tomap
[-1];
169 locale_t
*ploc
= &CURRENT_LOCALE
, loc
= *ploc
;
171 if (!in
|| !*in
|| !*inb
) return 0;
175 for (; *inb
; *in
+=l
, *inb
-=l
) {
176 c
= *(unsigned char *)*in
;
179 if (c
>= 128 || type
-UTF_32BE
< 7U) switch (type
) {
181 l
= mbrtowc_utf8(&wc
, *in
, *inb
, &st
);
183 else if (l
== (size_t)-1) goto ilseq
;
184 else if (l
== (size_t)-2) goto starved
;
191 if (*inb
< l
) goto starved
;
197 if (*inb
< 4) goto starved
;
198 c
= get_32((void *)*in
, type
);
200 if (c
-0xd800u
< 0x800u
|| c
>= 0x110000u
) goto ilseq
;
207 if (*inb
< 2) goto starved
;
208 c
= get_16((void *)*in
, type
);
209 if ((unsigned)(c
-0xdc00) < 0x400) goto ilseq
;
210 if ((unsigned)(c
-0xd800) < 0x400) {
211 if (type
-UCS2BE
< 2U) goto ilseq
;
213 if (*inb
< 4) goto starved
;
214 d
= get_16((void *)(*in
+ 2), type
);
215 if ((unsigned)(d
-0xdc00) >= 0x400) goto ilseq
;
216 c
= ((c
-0xd7c0)<<10) + (d
-0xdc00);
220 if (c
-0xa1 <= 0xdf-0xa1) {
225 if (*inb
< 2) goto starved
;
226 d
= *((unsigned char *)*in
+ 1);
227 if (c
-129 <= 159-129) c
-= 129;
228 else if (c
-224 <= 239-224) c
-= 193;
231 if (d
-64 <= 158-64) {
232 if (d
==127) goto ilseq
;
235 } else if (d
-159 <= 252-159) {
244 if (*inb
< 2) goto starved
;
245 d
= *((unsigned char *)*in
+ 1);
248 if (c
-0xa1 > 0xdf-0xa1) goto ilseq
;
254 if (c
>= 84 || d
>= 94) goto ilseq
;
259 if (c
< 0xa1) goto ilseq
;
263 if (c
>= 126) goto ilseq
;
265 if (*inb
< 2) goto starved
;
266 d
= *((unsigned char *)*in
+ 1);
267 if (d
< 0xa1 && type
== GB2312
) goto ilseq
;
268 if (d
-0x40>=191 || d
==127) {
269 if (d
-'0'>9 || type
!= GB18030
)
272 if (*inb
< 4) goto starved
;
273 c
= (10*c
+ d
-'0') * 1260;
274 d
= *((unsigned char *)*in
+ 2);
275 if (d
-0x81>126) goto ilseq
;
277 d
= *((unsigned char *)*in
+ 3);
278 if (d
-'0'>9) goto ilseq
;
283 for (int i
=0; i
<126; i
++)
284 for (int j
=0; j
<190; j
++)
285 if (gb18030
[i
][j
]-d
<= c
-d
)
298 if (*inb
< 2) goto starved
;
299 d
= *((unsigned char *)*in
+ 1);
300 if (d
-0x40>=0xff-0x40 || d
-0x7f<0xa1-0x7f) goto ilseq
;
302 if (d
> 0x3e) d
-= 0x22;
303 if (c
-0xa1>=0xfa-0xa1) {
304 if (c
-0x87>=0xff-0x87) goto ilseq
;
305 if (c
< 0xa1) c
-= 0x87;
306 else c
-= 0x87 + (0xfa-0xa1);
307 c
= (hkscs
[4867+(c
*157+d
)/16]>>(c
*157+d
)%16)%2<<17
309 /* A few HKSCS characters map to pairs of UCS
310 * characters. These are mapped to surrogate
311 * range in the hkscs table then hard-coded
312 * here. Ugly, yes. */
314 if (totype
-0300U > 8) k
= 2;
315 else k
= "\10\4\4\10\4\4\10\2\4"[totype
-0300];
316 if (k
> *outb
) goto toobig
;
317 x
+= iconv((iconv_t
)(uintptr_t)to
,
318 &(char *){"\303\212\314\204"
322 +c
%256}, &(size_t){4},
330 c
= big5
[c
][d
]|(c
==0x27&&(d
==0x3a||d
==0x3c||d
==0x42))<<17;
335 if (*inb
< 2) goto starved
;
336 d
= *((unsigned char *)*in
+ 1);
339 if (c
>= 93 || d
>= 94) {
342 if (c
>= 93 || c
>=0xc6-0x81 && d
>0x52)
344 if (d
-'A'<26) d
= d
-'A';
345 else if (d
-'a'<26) d
= d
-'a'+26;
346 else if (d
-0x81<0xff-0x81) d
= d
-0x81+52;
348 if (c
< 0x20) c
= 178*c
+ d
;
349 else c
= 178*0x20 + 84*(c
-0x20) + d
;
351 for (d
=0xac00; d
<=c
; ) {
353 for (int i
=0; i
<93; i
++)
354 for (int j
=0; j
<94; j
++)
355 if (ksc
[i
][j
]-d
<= c
-d
)
366 if (c
< 128+type
) break;
368 c
= legacy_chars
[ map
[c
*5/4]>>2*c
%8 |
369 map
[c
*5/4+1]<<8-2*c
%8 & 1023 ];
370 if (!c
) c
= *(unsigned char *)*in
;
371 if (c
==1) goto ilseq
;
376 if (*outb
< sizeof(wchar_t)) goto toobig
;
377 *(wchar_t *)*out
= c
;
378 *out
+= sizeof(wchar_t);
379 *outb
-= sizeof(wchar_t);
384 k
= wctomb_utf8(tmp
, c
);
385 if (*outb
< k
) goto toobig
;
386 memcpy(*out
, tmp
, k
);
387 } else k
= wctomb_utf8(*out
, c
);
392 if (c
> 0x7f) subst
: x
++, c
='*';
394 if (*outb
< 1) goto toobig
;
395 if (c
< 128+totype
) {
402 for (c
=0; c
<128-totype
; c
++) {
403 if (d
== legacy_chars
[ tomap
[c
*5/4]>>2*c
%8 |
404 tomap
[c
*5/4+1]<<8-2*c
%8 & 1023 ]) {
414 if (c
< 0x10000 || type
-UCS2BE
< 2U) {
415 if (c
>= 0x10000) c
= 0xFFFD;
416 if (*outb
< 2) goto toobig
;
417 put_16((void *)*out
, c
, totype
);
422 if (*outb
< 4) goto toobig
;
424 put_16((void *)*out
, (c
>>10)|0xd800, totype
);
425 put_16((void *)(*out
+ 2), (c
&0x3ff)|0xdc00, totype
);
431 if (*outb
< 4) goto toobig
;
432 put_32((void *)*out
, c
, totype
);