xref: /aosp_15_r20/external/musl/src/locale/iconv.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
1*c9945492SAndroid Build Coastguard Worker #include <iconv.h>
2*c9945492SAndroid Build Coastguard Worker #include <errno.h>
3*c9945492SAndroid Build Coastguard Worker #include <wchar.h>
4*c9945492SAndroid Build Coastguard Worker #include <string.h>
5*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
6*c9945492SAndroid Build Coastguard Worker #include <limits.h>
7*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
8*c9945492SAndroid Build Coastguard Worker #include "locale_impl.h"
9*c9945492SAndroid Build Coastguard Worker 
10*c9945492SAndroid Build Coastguard Worker #define UTF_32BE    0300
11*c9945492SAndroid Build Coastguard Worker #define UTF_16LE    0301
12*c9945492SAndroid Build Coastguard Worker #define UTF_16BE    0302
13*c9945492SAndroid Build Coastguard Worker #define UTF_32LE    0303
14*c9945492SAndroid Build Coastguard Worker #define UCS2BE      0304
15*c9945492SAndroid Build Coastguard Worker #define UCS2LE      0305
16*c9945492SAndroid Build Coastguard Worker #define WCHAR_T     0306
17*c9945492SAndroid Build Coastguard Worker #define US_ASCII    0307
18*c9945492SAndroid Build Coastguard Worker #define UTF_8       0310
19*c9945492SAndroid Build Coastguard Worker #define UTF_16      0312
20*c9945492SAndroid Build Coastguard Worker #define UTF_32      0313
21*c9945492SAndroid Build Coastguard Worker #define UCS2        0314
22*c9945492SAndroid Build Coastguard Worker #define EUC_JP      0320
23*c9945492SAndroid Build Coastguard Worker #define SHIFT_JIS   0321
24*c9945492SAndroid Build Coastguard Worker #define ISO2022_JP  0322
25*c9945492SAndroid Build Coastguard Worker #define GB18030     0330
26*c9945492SAndroid Build Coastguard Worker #define GBK         0331
27*c9945492SAndroid Build Coastguard Worker #define GB2312      0332
28*c9945492SAndroid Build Coastguard Worker #define BIG5        0340
29*c9945492SAndroid Build Coastguard Worker #define EUC_KR      0350
30*c9945492SAndroid Build Coastguard Worker 
31*c9945492SAndroid Build Coastguard Worker /* Definitions of charmaps. Each charmap consists of:
32*c9945492SAndroid Build Coastguard Worker  * 1. Empty-string-terminated list of null-terminated aliases.
33*c9945492SAndroid Build Coastguard Worker  * 2. Special type code or number of elided quads of entries.
34*c9945492SAndroid Build Coastguard Worker  * 3. Character table (size determined by field 2), consisting
35*c9945492SAndroid Build Coastguard Worker  *    of 5 bytes for every 4 characters, interpreted as 10-bit
36*c9945492SAndroid Build Coastguard Worker  *    indices into the legacy_chars table. */
37*c9945492SAndroid Build Coastguard Worker 
38*c9945492SAndroid Build Coastguard Worker static const unsigned char charmaps[] =
39*c9945492SAndroid Build Coastguard Worker "utf8\0char\0\0\310"
40*c9945492SAndroid Build Coastguard Worker "wchart\0\0\306"
41*c9945492SAndroid Build Coastguard Worker "ucs2be\0\0\304"
42*c9945492SAndroid Build Coastguard Worker "ucs2le\0\0\305"
43*c9945492SAndroid Build Coastguard Worker "utf16be\0\0\302"
44*c9945492SAndroid Build Coastguard Worker "utf16le\0\0\301"
45*c9945492SAndroid Build Coastguard Worker "ucs4be\0utf32be\0\0\300"
46*c9945492SAndroid Build Coastguard Worker "ucs4le\0utf32le\0\0\303"
47*c9945492SAndroid Build Coastguard Worker "ascii\0usascii\0iso646\0iso646us\0\0\307"
48*c9945492SAndroid Build Coastguard Worker "utf16\0\0\312"
49*c9945492SAndroid Build Coastguard Worker "ucs4\0utf32\0\0\313"
50*c9945492SAndroid Build Coastguard Worker "ucs2\0\0\314"
51*c9945492SAndroid Build Coastguard Worker "eucjp\0\0\320"
52*c9945492SAndroid Build Coastguard Worker "shiftjis\0sjis\0cp932\0\0\321"
53*c9945492SAndroid Build Coastguard Worker "iso2022jp\0\0\322"
54*c9945492SAndroid Build Coastguard Worker "gb18030\0\0\330"
55*c9945492SAndroid Build Coastguard Worker "gbk\0cp936\0windows936\0\0\331"
56*c9945492SAndroid Build Coastguard Worker "gb2312\0\0\332"
57*c9945492SAndroid Build Coastguard Worker "big5\0bigfive\0cp950\0big5hkscs\0\0\340"
58*c9945492SAndroid Build Coastguard Worker "euckr\0ksc5601\0ksx1001\0cp949\0\0\350"
59*c9945492SAndroid Build Coastguard Worker #include "codepages.h"
60*c9945492SAndroid Build Coastguard Worker ;
61*c9945492SAndroid Build Coastguard Worker 
62*c9945492SAndroid Build Coastguard Worker /* Table of characters that appear in legacy 8-bit codepages,
63*c9945492SAndroid Build Coastguard Worker  * limited to 1024 slots (10 bit indices). The first 256 entries
64*c9945492SAndroid Build Coastguard Worker  * are elided since those characters are obviously all included. */
65*c9945492SAndroid Build Coastguard Worker static const unsigned short legacy_chars[] = {
66*c9945492SAndroid Build Coastguard Worker #include "legacychars.h"
67*c9945492SAndroid Build Coastguard Worker };
68*c9945492SAndroid Build Coastguard Worker 
69*c9945492SAndroid Build Coastguard Worker static const unsigned short jis0208[84][94] = {
70*c9945492SAndroid Build Coastguard Worker #include "jis0208.h"
71*c9945492SAndroid Build Coastguard Worker };
72*c9945492SAndroid Build Coastguard Worker 
73*c9945492SAndroid Build Coastguard Worker static const unsigned short gb18030[126][190] = {
74*c9945492SAndroid Build Coastguard Worker #include "gb18030.h"
75*c9945492SAndroid Build Coastguard Worker };
76*c9945492SAndroid Build Coastguard Worker 
77*c9945492SAndroid Build Coastguard Worker static const unsigned short big5[89][157] = {
78*c9945492SAndroid Build Coastguard Worker #include "big5.h"
79*c9945492SAndroid Build Coastguard Worker };
80*c9945492SAndroid Build Coastguard Worker 
81*c9945492SAndroid Build Coastguard Worker static const unsigned short hkscs[] = {
82*c9945492SAndroid Build Coastguard Worker #include "hkscs.h"
83*c9945492SAndroid Build Coastguard Worker };
84*c9945492SAndroid Build Coastguard Worker 
85*c9945492SAndroid Build Coastguard Worker static const unsigned short ksc[93][94] = {
86*c9945492SAndroid Build Coastguard Worker #include "ksc.h"
87*c9945492SAndroid Build Coastguard Worker };
88*c9945492SAndroid Build Coastguard Worker 
89*c9945492SAndroid Build Coastguard Worker static const unsigned short rev_jis[] = {
90*c9945492SAndroid Build Coastguard Worker #include "revjis.h"
91*c9945492SAndroid Build Coastguard Worker };
92*c9945492SAndroid Build Coastguard Worker 
fuzzycmp(const unsigned char * a,const unsigned char * b)93*c9945492SAndroid Build Coastguard Worker static int fuzzycmp(const unsigned char *a, const unsigned char *b)
94*c9945492SAndroid Build Coastguard Worker {
95*c9945492SAndroid Build Coastguard Worker 	for (; *a && *b; a++, b++) {
96*c9945492SAndroid Build Coastguard Worker 		while (*a && (*a|32U)-'a'>26 && *a-'0'>10U) a++;
97*c9945492SAndroid Build Coastguard Worker 		if ((*a|32U) != *b) return 1;
98*c9945492SAndroid Build Coastguard Worker 	}
99*c9945492SAndroid Build Coastguard Worker 	return *a != *b;
100*c9945492SAndroid Build Coastguard Worker }
101*c9945492SAndroid Build Coastguard Worker 
find_charmap(const void * name)102*c9945492SAndroid Build Coastguard Worker static size_t find_charmap(const void *name)
103*c9945492SAndroid Build Coastguard Worker {
104*c9945492SAndroid Build Coastguard Worker 	const unsigned char *s;
105*c9945492SAndroid Build Coastguard Worker 	if (!*(char *)name) name=charmaps; /* "utf8" */
106*c9945492SAndroid Build Coastguard Worker 	for (s=charmaps; *s; ) {
107*c9945492SAndroid Build Coastguard Worker 		if (!fuzzycmp(name, s)) {
108*c9945492SAndroid Build Coastguard Worker 			for (; *s; s+=strlen((void *)s)+1);
109*c9945492SAndroid Build Coastguard Worker 			return s+1-charmaps;
110*c9945492SAndroid Build Coastguard Worker 		}
111*c9945492SAndroid Build Coastguard Worker 		s += strlen((void *)s)+1;
112*c9945492SAndroid Build Coastguard Worker 		if (!*s) {
113*c9945492SAndroid Build Coastguard Worker 			if (s[1] > 0200) s+=2;
114*c9945492SAndroid Build Coastguard Worker 			else s+=2+(64U-s[1])*5;
115*c9945492SAndroid Build Coastguard Worker 		}
116*c9945492SAndroid Build Coastguard Worker 	}
117*c9945492SAndroid Build Coastguard Worker 	return -1;
118*c9945492SAndroid Build Coastguard Worker }
119*c9945492SAndroid Build Coastguard Worker 
120*c9945492SAndroid Build Coastguard Worker struct stateful_cd {
121*c9945492SAndroid Build Coastguard Worker 	iconv_t base_cd;
122*c9945492SAndroid Build Coastguard Worker 	unsigned state;
123*c9945492SAndroid Build Coastguard Worker };
124*c9945492SAndroid Build Coastguard Worker 
combine_to_from(size_t t,size_t f)125*c9945492SAndroid Build Coastguard Worker static iconv_t combine_to_from(size_t t, size_t f)
126*c9945492SAndroid Build Coastguard Worker {
127*c9945492SAndroid Build Coastguard Worker 	return (void *)(f<<16 | t<<1 | 1);
128*c9945492SAndroid Build Coastguard Worker }
129*c9945492SAndroid Build Coastguard Worker 
extract_from(iconv_t cd)130*c9945492SAndroid Build Coastguard Worker static size_t extract_from(iconv_t cd)
131*c9945492SAndroid Build Coastguard Worker {
132*c9945492SAndroid Build Coastguard Worker 	return (size_t)cd >> 16;
133*c9945492SAndroid Build Coastguard Worker }
134*c9945492SAndroid Build Coastguard Worker 
extract_to(iconv_t cd)135*c9945492SAndroid Build Coastguard Worker static size_t extract_to(iconv_t cd)
136*c9945492SAndroid Build Coastguard Worker {
137*c9945492SAndroid Build Coastguard Worker 	return (size_t)cd >> 1 & 0x7fff;
138*c9945492SAndroid Build Coastguard Worker }
139*c9945492SAndroid Build Coastguard Worker 
iconv_open(const char * to,const char * from)140*c9945492SAndroid Build Coastguard Worker iconv_t iconv_open(const char *to, const char *from)
141*c9945492SAndroid Build Coastguard Worker {
142*c9945492SAndroid Build Coastguard Worker 	size_t f, t;
143*c9945492SAndroid Build Coastguard Worker 	struct stateful_cd *scd;
144*c9945492SAndroid Build Coastguard Worker 
145*c9945492SAndroid Build Coastguard Worker 	if ((t = find_charmap(to))==-1
146*c9945492SAndroid Build Coastguard Worker 	 || (f = find_charmap(from))==-1
147*c9945492SAndroid Build Coastguard Worker 	 || (charmaps[t] >= 0330)) {
148*c9945492SAndroid Build Coastguard Worker 		errno = EINVAL;
149*c9945492SAndroid Build Coastguard Worker 		return (iconv_t)-1;
150*c9945492SAndroid Build Coastguard Worker 	}
151*c9945492SAndroid Build Coastguard Worker 	iconv_t cd = combine_to_from(t, f);
152*c9945492SAndroid Build Coastguard Worker 
153*c9945492SAndroid Build Coastguard Worker 	switch (charmaps[f]) {
154*c9945492SAndroid Build Coastguard Worker 	case UTF_16:
155*c9945492SAndroid Build Coastguard Worker 	case UTF_32:
156*c9945492SAndroid Build Coastguard Worker 	case UCS2:
157*c9945492SAndroid Build Coastguard Worker 	case ISO2022_JP:
158*c9945492SAndroid Build Coastguard Worker 		scd = malloc(sizeof *scd);
159*c9945492SAndroid Build Coastguard Worker 		if (!scd) return (iconv_t)-1;
160*c9945492SAndroid Build Coastguard Worker 		scd->base_cd = cd;
161*c9945492SAndroid Build Coastguard Worker 		scd->state = 0;
162*c9945492SAndroid Build Coastguard Worker 		cd = (iconv_t)scd;
163*c9945492SAndroid Build Coastguard Worker 	}
164*c9945492SAndroid Build Coastguard Worker 
165*c9945492SAndroid Build Coastguard Worker 	return cd;
166*c9945492SAndroid Build Coastguard Worker }
167*c9945492SAndroid Build Coastguard Worker 
get_16(const unsigned char * s,int e)168*c9945492SAndroid Build Coastguard Worker static unsigned get_16(const unsigned char *s, int e)
169*c9945492SAndroid Build Coastguard Worker {
170*c9945492SAndroid Build Coastguard Worker 	e &= 1;
171*c9945492SAndroid Build Coastguard Worker 	return s[e]<<8 | s[1-e];
172*c9945492SAndroid Build Coastguard Worker }
173*c9945492SAndroid Build Coastguard Worker 
put_16(unsigned char * s,unsigned c,int e)174*c9945492SAndroid Build Coastguard Worker static void put_16(unsigned char *s, unsigned c, int e)
175*c9945492SAndroid Build Coastguard Worker {
176*c9945492SAndroid Build Coastguard Worker 	e &= 1;
177*c9945492SAndroid Build Coastguard Worker 	s[e] = c>>8;
178*c9945492SAndroid Build Coastguard Worker 	s[1-e] = c;
179*c9945492SAndroid Build Coastguard Worker }
180*c9945492SAndroid Build Coastguard Worker 
get_32(const unsigned char * s,int e)181*c9945492SAndroid Build Coastguard Worker static unsigned get_32(const unsigned char *s, int e)
182*c9945492SAndroid Build Coastguard Worker {
183*c9945492SAndroid Build Coastguard Worker 	e &= 3;
184*c9945492SAndroid Build Coastguard Worker 	return s[e]+0U<<24 | s[e^1]<<16 | s[e^2]<<8 | s[e^3];
185*c9945492SAndroid Build Coastguard Worker }
186*c9945492SAndroid Build Coastguard Worker 
put_32(unsigned char * s,unsigned c,int e)187*c9945492SAndroid Build Coastguard Worker static void put_32(unsigned char *s, unsigned c, int e)
188*c9945492SAndroid Build Coastguard Worker {
189*c9945492SAndroid Build Coastguard Worker 	e &= 3;
190*c9945492SAndroid Build Coastguard Worker 	s[e^0] = c>>24;
191*c9945492SAndroid Build Coastguard Worker 	s[e^1] = c>>16;
192*c9945492SAndroid Build Coastguard Worker 	s[e^2] = c>>8;
193*c9945492SAndroid Build Coastguard Worker 	s[e^3] = c;
194*c9945492SAndroid Build Coastguard Worker }
195*c9945492SAndroid Build Coastguard Worker 
196*c9945492SAndroid Build Coastguard Worker /* Adapt as needed */
197*c9945492SAndroid Build Coastguard Worker #define mbrtowc_utf8 mbrtowc
198*c9945492SAndroid Build Coastguard Worker #define wctomb_utf8 wctomb
199*c9945492SAndroid Build Coastguard Worker 
legacy_map(const unsigned char * map,unsigned c)200*c9945492SAndroid Build Coastguard Worker static unsigned legacy_map(const unsigned char *map, unsigned c)
201*c9945492SAndroid Build Coastguard Worker {
202*c9945492SAndroid Build Coastguard Worker 	if (c < 4*map[-1]) return c;
203*c9945492SAndroid Build Coastguard Worker 	unsigned x = c - 4*map[-1];
204*c9945492SAndroid Build Coastguard Worker 	x = map[x*5/4]>>2*x%8 | map[x*5/4+1]<<8-2*x%8 & 1023;
205*c9945492SAndroid Build Coastguard Worker 	return x < 256 ? x : legacy_chars[x-256];
206*c9945492SAndroid Build Coastguard Worker }
207*c9945492SAndroid Build Coastguard Worker 
uni_to_jis(unsigned c)208*c9945492SAndroid Build Coastguard Worker static unsigned uni_to_jis(unsigned c)
209*c9945492SAndroid Build Coastguard Worker {
210*c9945492SAndroid Build Coastguard Worker 	unsigned nel = sizeof rev_jis / sizeof *rev_jis;
211*c9945492SAndroid Build Coastguard Worker 	unsigned d, j, i, b = 0;
212*c9945492SAndroid Build Coastguard Worker 	for (;;) {
213*c9945492SAndroid Build Coastguard Worker 		i = nel/2;
214*c9945492SAndroid Build Coastguard Worker 		j = rev_jis[b+i];
215*c9945492SAndroid Build Coastguard Worker 		d = jis0208[j/256][j%256];
216*c9945492SAndroid Build Coastguard Worker 		if (d==c) return j + 0x2121;
217*c9945492SAndroid Build Coastguard Worker 		else if (nel == 1) return 0;
218*c9945492SAndroid Build Coastguard Worker 		else if (c < d)
219*c9945492SAndroid Build Coastguard Worker 			nel /= 2;
220*c9945492SAndroid Build Coastguard Worker 		else {
221*c9945492SAndroid Build Coastguard Worker 			b += i;
222*c9945492SAndroid Build Coastguard Worker 			nel -= nel/2;
223*c9945492SAndroid Build Coastguard Worker 		}
224*c9945492SAndroid Build Coastguard Worker 	}
225*c9945492SAndroid Build Coastguard Worker }
226*c9945492SAndroid Build Coastguard Worker 
iconv(iconv_t cd,char ** restrict in,size_t * restrict inb,char ** restrict out,size_t * restrict outb)227*c9945492SAndroid Build Coastguard Worker size_t iconv(iconv_t cd, char **restrict in, size_t *restrict inb, char **restrict out, size_t *restrict outb)
228*c9945492SAndroid Build Coastguard Worker {
229*c9945492SAndroid Build Coastguard Worker 	size_t x=0;
230*c9945492SAndroid Build Coastguard Worker 	struct stateful_cd *scd=0;
231*c9945492SAndroid Build Coastguard Worker 	if (!((size_t)cd & 1)) {
232*c9945492SAndroid Build Coastguard Worker 		scd = (void *)cd;
233*c9945492SAndroid Build Coastguard Worker 		cd = scd->base_cd;
234*c9945492SAndroid Build Coastguard Worker 	}
235*c9945492SAndroid Build Coastguard Worker 	unsigned to = extract_to(cd);
236*c9945492SAndroid Build Coastguard Worker 	unsigned from = extract_from(cd);
237*c9945492SAndroid Build Coastguard Worker 	const unsigned char *map = charmaps+from+1;
238*c9945492SAndroid Build Coastguard Worker 	const unsigned char *tomap = charmaps+to+1;
239*c9945492SAndroid Build Coastguard Worker 	mbstate_t st = {0};
240*c9945492SAndroid Build Coastguard Worker 	wchar_t wc;
241*c9945492SAndroid Build Coastguard Worker 	unsigned c, d;
242*c9945492SAndroid Build Coastguard Worker 	size_t k, l;
243*c9945492SAndroid Build Coastguard Worker 	int err;
244*c9945492SAndroid Build Coastguard Worker 	unsigned char type = map[-1];
245*c9945492SAndroid Build Coastguard Worker 	unsigned char totype = tomap[-1];
246*c9945492SAndroid Build Coastguard Worker 	locale_t *ploc = &CURRENT_LOCALE, loc = *ploc;
247*c9945492SAndroid Build Coastguard Worker 
248*c9945492SAndroid Build Coastguard Worker 	if (!in || !*in || !*inb) return 0;
249*c9945492SAndroid Build Coastguard Worker 
250*c9945492SAndroid Build Coastguard Worker 	*ploc = UTF8_LOCALE;
251*c9945492SAndroid Build Coastguard Worker 
252*c9945492SAndroid Build Coastguard Worker 	for (; *inb; *in+=l, *inb-=l) {
253*c9945492SAndroid Build Coastguard Worker 		c = *(unsigned char *)*in;
254*c9945492SAndroid Build Coastguard Worker 		l = 1;
255*c9945492SAndroid Build Coastguard Worker 
256*c9945492SAndroid Build Coastguard Worker 		switch (type) {
257*c9945492SAndroid Build Coastguard Worker 		case UTF_8:
258*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
259*c9945492SAndroid Build Coastguard Worker 			l = mbrtowc_utf8(&wc, *in, *inb, &st);
260*c9945492SAndroid Build Coastguard Worker 			if (l == (size_t)-1) goto ilseq;
261*c9945492SAndroid Build Coastguard Worker 			if (l == (size_t)-2) goto starved;
262*c9945492SAndroid Build Coastguard Worker 			c = wc;
263*c9945492SAndroid Build Coastguard Worker 			break;
264*c9945492SAndroid Build Coastguard Worker 		case US_ASCII:
265*c9945492SAndroid Build Coastguard Worker 			if (c >= 128) goto ilseq;
266*c9945492SAndroid Build Coastguard Worker 			break;
267*c9945492SAndroid Build Coastguard Worker 		case WCHAR_T:
268*c9945492SAndroid Build Coastguard Worker 			l = sizeof(wchar_t);
269*c9945492SAndroid Build Coastguard Worker 			if (*inb < l) goto starved;
270*c9945492SAndroid Build Coastguard Worker 			c = *(wchar_t *)*in;
271*c9945492SAndroid Build Coastguard Worker 			if (0) {
272*c9945492SAndroid Build Coastguard Worker 		case UTF_32BE:
273*c9945492SAndroid Build Coastguard Worker 		case UTF_32LE:
274*c9945492SAndroid Build Coastguard Worker 			l = 4;
275*c9945492SAndroid Build Coastguard Worker 			if (*inb < 4) goto starved;
276*c9945492SAndroid Build Coastguard Worker 			c = get_32((void *)*in, type);
277*c9945492SAndroid Build Coastguard Worker 			}
278*c9945492SAndroid Build Coastguard Worker 			if (c-0xd800u < 0x800u || c >= 0x110000u) goto ilseq;
279*c9945492SAndroid Build Coastguard Worker 			break;
280*c9945492SAndroid Build Coastguard Worker 		case UCS2BE:
281*c9945492SAndroid Build Coastguard Worker 		case UCS2LE:
282*c9945492SAndroid Build Coastguard Worker 		case UTF_16BE:
283*c9945492SAndroid Build Coastguard Worker 		case UTF_16LE:
284*c9945492SAndroid Build Coastguard Worker 			l = 2;
285*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
286*c9945492SAndroid Build Coastguard Worker 			c = get_16((void *)*in, type);
287*c9945492SAndroid Build Coastguard Worker 			if ((unsigned)(c-0xdc00) < 0x400) goto ilseq;
288*c9945492SAndroid Build Coastguard Worker 			if ((unsigned)(c-0xd800) < 0x400) {
289*c9945492SAndroid Build Coastguard Worker 				if (type-UCS2BE < 2U) goto ilseq;
290*c9945492SAndroid Build Coastguard Worker 				l = 4;
291*c9945492SAndroid Build Coastguard Worker 				if (*inb < 4) goto starved;
292*c9945492SAndroid Build Coastguard Worker 				d = get_16((void *)(*in + 2), type);
293*c9945492SAndroid Build Coastguard Worker 				if ((unsigned)(d-0xdc00) >= 0x400) goto ilseq;
294*c9945492SAndroid Build Coastguard Worker 				c = ((c-0xd7c0)<<10) + (d-0xdc00);
295*c9945492SAndroid Build Coastguard Worker 			}
296*c9945492SAndroid Build Coastguard Worker 			break;
297*c9945492SAndroid Build Coastguard Worker 		case UCS2:
298*c9945492SAndroid Build Coastguard Worker 		case UTF_16:
299*c9945492SAndroid Build Coastguard Worker 			l = 0;
300*c9945492SAndroid Build Coastguard Worker 			if (!scd->state) {
301*c9945492SAndroid Build Coastguard Worker 				if (*inb < 2) goto starved;
302*c9945492SAndroid Build Coastguard Worker 				c = get_16((void *)*in, 0);
303*c9945492SAndroid Build Coastguard Worker 				scd->state = type==UCS2
304*c9945492SAndroid Build Coastguard Worker 					? c==0xfffe ? UCS2LE : UCS2BE
305*c9945492SAndroid Build Coastguard Worker 					: c==0xfffe ? UTF_16LE : UTF_16BE;
306*c9945492SAndroid Build Coastguard Worker 				if (c == 0xfffe || c == 0xfeff)
307*c9945492SAndroid Build Coastguard Worker 					l = 2;
308*c9945492SAndroid Build Coastguard Worker 			}
309*c9945492SAndroid Build Coastguard Worker 			type = scd->state;
310*c9945492SAndroid Build Coastguard Worker 			continue;
311*c9945492SAndroid Build Coastguard Worker 		case UTF_32:
312*c9945492SAndroid Build Coastguard Worker 			l = 0;
313*c9945492SAndroid Build Coastguard Worker 			if (!scd->state) {
314*c9945492SAndroid Build Coastguard Worker 				if (*inb < 4) goto starved;
315*c9945492SAndroid Build Coastguard Worker 				c = get_32((void *)*in, 0);
316*c9945492SAndroid Build Coastguard Worker 				scd->state = c==0xfffe0000 ? UTF_32LE : UTF_32BE;
317*c9945492SAndroid Build Coastguard Worker 				if (c == 0xfffe0000 || c == 0xfeff)
318*c9945492SAndroid Build Coastguard Worker 					l = 4;
319*c9945492SAndroid Build Coastguard Worker 			}
320*c9945492SAndroid Build Coastguard Worker 			type = scd->state;
321*c9945492SAndroid Build Coastguard Worker 			continue;
322*c9945492SAndroid Build Coastguard Worker 		case SHIFT_JIS:
323*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
324*c9945492SAndroid Build Coastguard Worker 			if (c-0xa1 <= 0xdf-0xa1) {
325*c9945492SAndroid Build Coastguard Worker 				c += 0xff61-0xa1;
326*c9945492SAndroid Build Coastguard Worker 				break;
327*c9945492SAndroid Build Coastguard Worker 			}
328*c9945492SAndroid Build Coastguard Worker 			l = 2;
329*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
330*c9945492SAndroid Build Coastguard Worker 			d = *((unsigned char *)*in + 1);
331*c9945492SAndroid Build Coastguard Worker 			if (c-129 <= 159-129) c -= 129;
332*c9945492SAndroid Build Coastguard Worker 			else if (c-224 <= 239-224) c -= 193;
333*c9945492SAndroid Build Coastguard Worker 			else goto ilseq;
334*c9945492SAndroid Build Coastguard Worker 			c *= 2;
335*c9945492SAndroid Build Coastguard Worker 			if (d-64 <= 158-64) {
336*c9945492SAndroid Build Coastguard Worker 				if (d==127) goto ilseq;
337*c9945492SAndroid Build Coastguard Worker 				if (d>127) d--;
338*c9945492SAndroid Build Coastguard Worker 				d -= 64;
339*c9945492SAndroid Build Coastguard Worker 			} else if (d-159 <= 252-159) {
340*c9945492SAndroid Build Coastguard Worker 				c++;
341*c9945492SAndroid Build Coastguard Worker 				d -= 159;
342*c9945492SAndroid Build Coastguard Worker 			}
343*c9945492SAndroid Build Coastguard Worker 			if (c>=84) goto ilseq;
344*c9945492SAndroid Build Coastguard Worker 			c = jis0208[c][d];
345*c9945492SAndroid Build Coastguard Worker 			if (!c) goto ilseq;
346*c9945492SAndroid Build Coastguard Worker 			break;
347*c9945492SAndroid Build Coastguard Worker 		case EUC_JP:
348*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
349*c9945492SAndroid Build Coastguard Worker 			l = 2;
350*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
351*c9945492SAndroid Build Coastguard Worker 			d = *((unsigned char *)*in + 1);
352*c9945492SAndroid Build Coastguard Worker 			if (c==0x8e) {
353*c9945492SAndroid Build Coastguard Worker 				c = d;
354*c9945492SAndroid Build Coastguard Worker 				if (c-0xa1 > 0xdf-0xa1) goto ilseq;
355*c9945492SAndroid Build Coastguard Worker 				c += 0xff61 - 0xa1;
356*c9945492SAndroid Build Coastguard Worker 				break;
357*c9945492SAndroid Build Coastguard Worker 			}
358*c9945492SAndroid Build Coastguard Worker 			c -= 0xa1;
359*c9945492SAndroid Build Coastguard Worker 			d -= 0xa1;
360*c9945492SAndroid Build Coastguard Worker 			if (c >= 84 || d >= 94) goto ilseq;
361*c9945492SAndroid Build Coastguard Worker 			c = jis0208[c][d];
362*c9945492SAndroid Build Coastguard Worker 			if (!c) goto ilseq;
363*c9945492SAndroid Build Coastguard Worker 			break;
364*c9945492SAndroid Build Coastguard Worker 		case ISO2022_JP:
365*c9945492SAndroid Build Coastguard Worker 			if (c >= 128) goto ilseq;
366*c9945492SAndroid Build Coastguard Worker 			if (c == '\033') {
367*c9945492SAndroid Build Coastguard Worker 				l = 3;
368*c9945492SAndroid Build Coastguard Worker 				if (*inb < 3) goto starved;
369*c9945492SAndroid Build Coastguard Worker 				c = *((unsigned char *)*in + 1);
370*c9945492SAndroid Build Coastguard Worker 				d = *((unsigned char *)*in + 2);
371*c9945492SAndroid Build Coastguard Worker 				if (c != '(' && c != '$') goto ilseq;
372*c9945492SAndroid Build Coastguard Worker 				switch (128*(c=='$') + d) {
373*c9945492SAndroid Build Coastguard Worker 				case 'B': scd->state=0; continue;
374*c9945492SAndroid Build Coastguard Worker 				case 'J': scd->state=1; continue;
375*c9945492SAndroid Build Coastguard Worker 				case 'I': scd->state=4; continue;
376*c9945492SAndroid Build Coastguard Worker 				case 128+'@': scd->state=2; continue;
377*c9945492SAndroid Build Coastguard Worker 				case 128+'B': scd->state=3; continue;
378*c9945492SAndroid Build Coastguard Worker 				}
379*c9945492SAndroid Build Coastguard Worker 				goto ilseq;
380*c9945492SAndroid Build Coastguard Worker 			}
381*c9945492SAndroid Build Coastguard Worker 			switch (scd->state) {
382*c9945492SAndroid Build Coastguard Worker 			case 1:
383*c9945492SAndroid Build Coastguard Worker 				if (c=='\\') c = 0xa5;
384*c9945492SAndroid Build Coastguard Worker 				if (c=='~') c = 0x203e;
385*c9945492SAndroid Build Coastguard Worker 				break;
386*c9945492SAndroid Build Coastguard Worker 			case 2:
387*c9945492SAndroid Build Coastguard Worker 			case 3:
388*c9945492SAndroid Build Coastguard Worker 				l = 2;
389*c9945492SAndroid Build Coastguard Worker 				if (*inb < 2) goto starved;
390*c9945492SAndroid Build Coastguard Worker 				d = *((unsigned char *)*in + 1);
391*c9945492SAndroid Build Coastguard Worker 				c -= 0x21;
392*c9945492SAndroid Build Coastguard Worker 				d -= 0x21;
393*c9945492SAndroid Build Coastguard Worker 				if (c >= 84 || d >= 94) goto ilseq;
394*c9945492SAndroid Build Coastguard Worker 				c = jis0208[c][d];
395*c9945492SAndroid Build Coastguard Worker 				if (!c) goto ilseq;
396*c9945492SAndroid Build Coastguard Worker 				break;
397*c9945492SAndroid Build Coastguard Worker 			case 4:
398*c9945492SAndroid Build Coastguard Worker 				if (c-0x60 < 0x1f) goto ilseq;
399*c9945492SAndroid Build Coastguard Worker 				if (c-0x21 < 0x5e) c += 0xff61-0x21;
400*c9945492SAndroid Build Coastguard Worker 				break;
401*c9945492SAndroid Build Coastguard Worker 			}
402*c9945492SAndroid Build Coastguard Worker 			break;
403*c9945492SAndroid Build Coastguard Worker 		case GB2312:
404*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
405*c9945492SAndroid Build Coastguard Worker 			if (c < 0xa1) goto ilseq;
406*c9945492SAndroid Build Coastguard Worker 		case GBK:
407*c9945492SAndroid Build Coastguard Worker 			if (c == 128) {
408*c9945492SAndroid Build Coastguard Worker 				c = 0x20ac;
409*c9945492SAndroid Build Coastguard Worker 				break;
410*c9945492SAndroid Build Coastguard Worker 			}
411*c9945492SAndroid Build Coastguard Worker 		case GB18030:
412*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
413*c9945492SAndroid Build Coastguard Worker 			c -= 0x81;
414*c9945492SAndroid Build Coastguard Worker 			if (c >= 126) goto ilseq;
415*c9945492SAndroid Build Coastguard Worker 			l = 2;
416*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
417*c9945492SAndroid Build Coastguard Worker 			d = *((unsigned char *)*in + 1);
418*c9945492SAndroid Build Coastguard Worker 			if (d < 0xa1 && type == GB2312) goto ilseq;
419*c9945492SAndroid Build Coastguard Worker 			if (d-0x40>=191 || d==127) {
420*c9945492SAndroid Build Coastguard Worker 				if (d-'0'>9 || type != GB18030)
421*c9945492SAndroid Build Coastguard Worker 					goto ilseq;
422*c9945492SAndroid Build Coastguard Worker 				l = 4;
423*c9945492SAndroid Build Coastguard Worker 				if (*inb < 4) goto starved;
424*c9945492SAndroid Build Coastguard Worker 				c = (10*c + d-'0') * 1260;
425*c9945492SAndroid Build Coastguard Worker 				d = *((unsigned char *)*in + 2);
426*c9945492SAndroid Build Coastguard Worker 				if (d-0x81>126) goto ilseq;
427*c9945492SAndroid Build Coastguard Worker 				c += 10*(d-0x81);
428*c9945492SAndroid Build Coastguard Worker 				d = *((unsigned char *)*in + 3);
429*c9945492SAndroid Build Coastguard Worker 				if (d-'0'>9) goto ilseq;
430*c9945492SAndroid Build Coastguard Worker 				c += d-'0';
431*c9945492SAndroid Build Coastguard Worker 				c += 128;
432*c9945492SAndroid Build Coastguard Worker 				for (d=0; d<=c; ) {
433*c9945492SAndroid Build Coastguard Worker 					k = 0;
434*c9945492SAndroid Build Coastguard Worker 					for (int i=0; i<126; i++)
435*c9945492SAndroid Build Coastguard Worker 						for (int j=0; j<190; j++)
436*c9945492SAndroid Build Coastguard Worker 							if (gb18030[i][j]-d <= c-d)
437*c9945492SAndroid Build Coastguard Worker 								k++;
438*c9945492SAndroid Build Coastguard Worker 					d = c+1;
439*c9945492SAndroid Build Coastguard Worker 					c += k;
440*c9945492SAndroid Build Coastguard Worker 				}
441*c9945492SAndroid Build Coastguard Worker 				break;
442*c9945492SAndroid Build Coastguard Worker 			}
443*c9945492SAndroid Build Coastguard Worker 			d -= 0x40;
444*c9945492SAndroid Build Coastguard Worker 			if (d>63) d--;
445*c9945492SAndroid Build Coastguard Worker 			c = gb18030[c][d];
446*c9945492SAndroid Build Coastguard Worker 			break;
447*c9945492SAndroid Build Coastguard Worker 		case BIG5:
448*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
449*c9945492SAndroid Build Coastguard Worker 			l = 2;
450*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
451*c9945492SAndroid Build Coastguard Worker 			d = *((unsigned char *)*in + 1);
452*c9945492SAndroid Build Coastguard Worker 			if (d-0x40>=0xff-0x40 || d-0x7f<0xa1-0x7f) goto ilseq;
453*c9945492SAndroid Build Coastguard Worker 			d -= 0x40;
454*c9945492SAndroid Build Coastguard Worker 			if (d > 0x3e) d -= 0x22;
455*c9945492SAndroid Build Coastguard Worker 			if (c-0xa1>=0xfa-0xa1) {
456*c9945492SAndroid Build Coastguard Worker 				if (c-0x87>=0xff-0x87) goto ilseq;
457*c9945492SAndroid Build Coastguard Worker 				if (c < 0xa1) c -= 0x87;
458*c9945492SAndroid Build Coastguard Worker 				else c -= 0x87 + (0xfa-0xa1);
459*c9945492SAndroid Build Coastguard Worker 				c = (hkscs[4867+(c*157+d)/16]>>(c*157+d)%16)%2<<17
460*c9945492SAndroid Build Coastguard Worker 					| hkscs[c*157+d];
461*c9945492SAndroid Build Coastguard Worker 				/* A few HKSCS characters map to pairs of UCS
462*c9945492SAndroid Build Coastguard Worker 				 * characters. These are mapped to surrogate
463*c9945492SAndroid Build Coastguard Worker 				 * range in the hkscs table then hard-coded
464*c9945492SAndroid Build Coastguard Worker 				 * here. Ugly, yes. */
465*c9945492SAndroid Build Coastguard Worker 				if (c/256 == 0xdc) {
466*c9945492SAndroid Build Coastguard Worker 					union {
467*c9945492SAndroid Build Coastguard Worker 						char c[8];
468*c9945492SAndroid Build Coastguard Worker 						wchar_t wc[2];
469*c9945492SAndroid Build Coastguard Worker 					} tmp;
470*c9945492SAndroid Build Coastguard Worker 					char *ptmp = tmp.c;
471*c9945492SAndroid Build Coastguard Worker 					size_t tmpx = iconv(combine_to_from(to, find_charmap("utf8")),
472*c9945492SAndroid Build Coastguard Worker 						&(char *){"\303\212\314\204"
473*c9945492SAndroid Build Coastguard Worker 						"\303\212\314\214"
474*c9945492SAndroid Build Coastguard Worker 						"\303\252\314\204"
475*c9945492SAndroid Build Coastguard Worker 						"\303\252\314\214"
476*c9945492SAndroid Build Coastguard Worker 						+c%256}, &(size_t){4},
477*c9945492SAndroid Build Coastguard Worker 						&ptmp, &(size_t){sizeof tmp});
478*c9945492SAndroid Build Coastguard Worker 					size_t tmplen = ptmp - tmp.c;
479*c9945492SAndroid Build Coastguard Worker 					if (tmplen > *outb) goto toobig;
480*c9945492SAndroid Build Coastguard Worker 					if (tmpx) x++;
481*c9945492SAndroid Build Coastguard Worker 					memcpy(*out, &tmp, tmplen);
482*c9945492SAndroid Build Coastguard Worker 					*out += tmplen;
483*c9945492SAndroid Build Coastguard Worker 					*outb -= tmplen;
484*c9945492SAndroid Build Coastguard Worker 					continue;
485*c9945492SAndroid Build Coastguard Worker 				}
486*c9945492SAndroid Build Coastguard Worker 				if (!c) goto ilseq;
487*c9945492SAndroid Build Coastguard Worker 				break;
488*c9945492SAndroid Build Coastguard Worker 			}
489*c9945492SAndroid Build Coastguard Worker 			c -= 0xa1;
490*c9945492SAndroid Build Coastguard Worker 			c = big5[c][d]|(c==0x27&&(d==0x3a||d==0x3c||d==0x42))<<17;
491*c9945492SAndroid Build Coastguard Worker 			if (!c) goto ilseq;
492*c9945492SAndroid Build Coastguard Worker 			break;
493*c9945492SAndroid Build Coastguard Worker 		case EUC_KR:
494*c9945492SAndroid Build Coastguard Worker 			if (c < 128) break;
495*c9945492SAndroid Build Coastguard Worker 			l = 2;
496*c9945492SAndroid Build Coastguard Worker 			if (*inb < 2) goto starved;
497*c9945492SAndroid Build Coastguard Worker 			d = *((unsigned char *)*in + 1);
498*c9945492SAndroid Build Coastguard Worker 			c -= 0xa1;
499*c9945492SAndroid Build Coastguard Worker 			d -= 0xa1;
500*c9945492SAndroid Build Coastguard Worker 			if (c >= 93 || d >= 94) {
501*c9945492SAndroid Build Coastguard Worker 				c += (0xa1-0x81);
502*c9945492SAndroid Build Coastguard Worker 				d += 0xa1;
503*c9945492SAndroid Build Coastguard Worker 				if (c >= 93 || c>=0xc6-0x81 && d>0x52)
504*c9945492SAndroid Build Coastguard Worker 					goto ilseq;
505*c9945492SAndroid Build Coastguard Worker 				if (d-'A'<26) d = d-'A';
506*c9945492SAndroid Build Coastguard Worker 				else if (d-'a'<26) d = d-'a'+26;
507*c9945492SAndroid Build Coastguard Worker 				else if (d-0x81<0xff-0x81) d = d-0x81+52;
508*c9945492SAndroid Build Coastguard Worker 				else goto ilseq;
509*c9945492SAndroid Build Coastguard Worker 				if (c < 0x20) c = 178*c + d;
510*c9945492SAndroid Build Coastguard Worker 				else c = 178*0x20 + 84*(c-0x20) + d;
511*c9945492SAndroid Build Coastguard Worker 				c += 0xac00;
512*c9945492SAndroid Build Coastguard Worker 				for (d=0xac00; d<=c; ) {
513*c9945492SAndroid Build Coastguard Worker 					k = 0;
514*c9945492SAndroid Build Coastguard Worker 					for (int i=0; i<93; i++)
515*c9945492SAndroid Build Coastguard Worker 						for (int j=0; j<94; j++)
516*c9945492SAndroid Build Coastguard Worker 							if (ksc[i][j]-d <= c-d)
517*c9945492SAndroid Build Coastguard Worker 								k++;
518*c9945492SAndroid Build Coastguard Worker 					d = c+1;
519*c9945492SAndroid Build Coastguard Worker 					c += k;
520*c9945492SAndroid Build Coastguard Worker 				}
521*c9945492SAndroid Build Coastguard Worker 				break;
522*c9945492SAndroid Build Coastguard Worker 			}
523*c9945492SAndroid Build Coastguard Worker 			c = ksc[c][d];
524*c9945492SAndroid Build Coastguard Worker 			if (!c) goto ilseq;
525*c9945492SAndroid Build Coastguard Worker 			break;
526*c9945492SAndroid Build Coastguard Worker 		default:
527*c9945492SAndroid Build Coastguard Worker 			if (!c) break;
528*c9945492SAndroid Build Coastguard Worker 			c = legacy_map(map, c);
529*c9945492SAndroid Build Coastguard Worker 			if (!c) goto ilseq;
530*c9945492SAndroid Build Coastguard Worker 		}
531*c9945492SAndroid Build Coastguard Worker 
532*c9945492SAndroid Build Coastguard Worker 		switch (totype) {
533*c9945492SAndroid Build Coastguard Worker 		case WCHAR_T:
534*c9945492SAndroid Build Coastguard Worker 			if (*outb < sizeof(wchar_t)) goto toobig;
535*c9945492SAndroid Build Coastguard Worker 			*(wchar_t *)*out = c;
536*c9945492SAndroid Build Coastguard Worker 			*out += sizeof(wchar_t);
537*c9945492SAndroid Build Coastguard Worker 			*outb -= sizeof(wchar_t);
538*c9945492SAndroid Build Coastguard Worker 			break;
539*c9945492SAndroid Build Coastguard Worker 		case UTF_8:
540*c9945492SAndroid Build Coastguard Worker 			if (*outb < 4) {
541*c9945492SAndroid Build Coastguard Worker 				char tmp[4];
542*c9945492SAndroid Build Coastguard Worker 				k = wctomb_utf8(tmp, c);
543*c9945492SAndroid Build Coastguard Worker 				if (*outb < k) goto toobig;
544*c9945492SAndroid Build Coastguard Worker 				memcpy(*out, tmp, k);
545*c9945492SAndroid Build Coastguard Worker 			} else k = wctomb_utf8(*out, c);
546*c9945492SAndroid Build Coastguard Worker 			*out += k;
547*c9945492SAndroid Build Coastguard Worker 			*outb -= k;
548*c9945492SAndroid Build Coastguard Worker 			break;
549*c9945492SAndroid Build Coastguard Worker 		case US_ASCII:
550*c9945492SAndroid Build Coastguard Worker 			if (c > 0x7f) subst: x++, c='*';
551*c9945492SAndroid Build Coastguard Worker 		default:
552*c9945492SAndroid Build Coastguard Worker 			if (*outb < 1) goto toobig;
553*c9945492SAndroid Build Coastguard Worker 			if (c<256 && c==legacy_map(tomap, c)) {
554*c9945492SAndroid Build Coastguard Worker 			revout:
555*c9945492SAndroid Build Coastguard Worker 				if (*outb < 1) goto toobig;
556*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = c;
557*c9945492SAndroid Build Coastguard Worker 				*outb -= 1;
558*c9945492SAndroid Build Coastguard Worker 				break;
559*c9945492SAndroid Build Coastguard Worker 			}
560*c9945492SAndroid Build Coastguard Worker 			d = c;
561*c9945492SAndroid Build Coastguard Worker 			for (c=4*totype; c<256; c++) {
562*c9945492SAndroid Build Coastguard Worker 				if (d == legacy_map(tomap, c)) {
563*c9945492SAndroid Build Coastguard Worker 					goto revout;
564*c9945492SAndroid Build Coastguard Worker 				}
565*c9945492SAndroid Build Coastguard Worker 			}
566*c9945492SAndroid Build Coastguard Worker 			goto subst;
567*c9945492SAndroid Build Coastguard Worker 		case SHIFT_JIS:
568*c9945492SAndroid Build Coastguard Worker 			if (c < 128) goto revout;
569*c9945492SAndroid Build Coastguard Worker 			if (c == 0xa5) {
570*c9945492SAndroid Build Coastguard Worker 				x++;
571*c9945492SAndroid Build Coastguard Worker 				c = '\\';
572*c9945492SAndroid Build Coastguard Worker 				goto revout;
573*c9945492SAndroid Build Coastguard Worker 			}
574*c9945492SAndroid Build Coastguard Worker 			if (c == 0x203e) {
575*c9945492SAndroid Build Coastguard Worker 				x++;
576*c9945492SAndroid Build Coastguard Worker 				c = '~';
577*c9945492SAndroid Build Coastguard Worker 				goto revout;
578*c9945492SAndroid Build Coastguard Worker 			}
579*c9945492SAndroid Build Coastguard Worker 			if (c-0xff61 <= 0xdf-0xa1) {
580*c9945492SAndroid Build Coastguard Worker 				c += 0xa1 - 0xff61;
581*c9945492SAndroid Build Coastguard Worker 				goto revout;
582*c9945492SAndroid Build Coastguard Worker 			}
583*c9945492SAndroid Build Coastguard Worker 			c = uni_to_jis(c);
584*c9945492SAndroid Build Coastguard Worker 			if (!c) goto subst;
585*c9945492SAndroid Build Coastguard Worker 			if (*outb < 2) goto toobig;
586*c9945492SAndroid Build Coastguard Worker 			d = c%256;
587*c9945492SAndroid Build Coastguard Worker 			c = c/256;
588*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = (c+1)/2 + (c<95 ? 112 : 176);
589*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = c%2 ? d + 31 + d/96 : d + 126;
590*c9945492SAndroid Build Coastguard Worker 			*outb -= 2;
591*c9945492SAndroid Build Coastguard Worker 			break;
592*c9945492SAndroid Build Coastguard Worker 		case EUC_JP:
593*c9945492SAndroid Build Coastguard Worker 			if (c < 128) goto revout;
594*c9945492SAndroid Build Coastguard Worker 			if (c-0xff61 <= 0xdf-0xa1) {
595*c9945492SAndroid Build Coastguard Worker 				c += 0x0e00 + 0x21 - 0xff61;
596*c9945492SAndroid Build Coastguard Worker 			} else {
597*c9945492SAndroid Build Coastguard Worker 				c = uni_to_jis(c);
598*c9945492SAndroid Build Coastguard Worker 			}
599*c9945492SAndroid Build Coastguard Worker 			if (!c) goto subst;
600*c9945492SAndroid Build Coastguard Worker 			if (*outb < 2) goto toobig;
601*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = c/256 + 0x80;
602*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = c%256 + 0x80;
603*c9945492SAndroid Build Coastguard Worker 			*outb -= 2;
604*c9945492SAndroid Build Coastguard Worker 			break;
605*c9945492SAndroid Build Coastguard Worker 		case ISO2022_JP:
606*c9945492SAndroid Build Coastguard Worker 			if (c < 128) goto revout;
607*c9945492SAndroid Build Coastguard Worker 			if (c-0xff61 <= 0xdf-0xa1 || c==0xa5 || c==0x203e) {
608*c9945492SAndroid Build Coastguard Worker 				if (*outb < 7) goto toobig;
609*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = '\033';
610*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = '(';
611*c9945492SAndroid Build Coastguard Worker 				if (c==0xa5) {
612*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = 'J';
613*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = '\\';
614*c9945492SAndroid Build Coastguard Worker 				} else if (c==0x203e) {
615*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = 'J';
616*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = '~';
617*c9945492SAndroid Build Coastguard Worker 				} else {
618*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = 'I';
619*c9945492SAndroid Build Coastguard Worker 					*(*out)++ = c-0xff61+0x21;
620*c9945492SAndroid Build Coastguard Worker 				}
621*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = '\033';
622*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = '(';
623*c9945492SAndroid Build Coastguard Worker 				*(*out)++ = 'B';
624*c9945492SAndroid Build Coastguard Worker 				*outb -= 7;
625*c9945492SAndroid Build Coastguard Worker 				break;
626*c9945492SAndroid Build Coastguard Worker 			}
627*c9945492SAndroid Build Coastguard Worker 			c = uni_to_jis(c);
628*c9945492SAndroid Build Coastguard Worker 			if (!c) goto subst;
629*c9945492SAndroid Build Coastguard Worker 			if (*outb < 8) goto toobig;
630*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = '\033';
631*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = '$';
632*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = 'B';
633*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = c/256;
634*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = c%256;
635*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = '\033';
636*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = '(';
637*c9945492SAndroid Build Coastguard Worker 			*(*out)++ = 'B';
638*c9945492SAndroid Build Coastguard Worker 			*outb -= 8;
639*c9945492SAndroid Build Coastguard Worker 			break;
640*c9945492SAndroid Build Coastguard Worker 		case UCS2:
641*c9945492SAndroid Build Coastguard Worker 			totype = UCS2BE;
642*c9945492SAndroid Build Coastguard Worker 		case UCS2BE:
643*c9945492SAndroid Build Coastguard Worker 		case UCS2LE:
644*c9945492SAndroid Build Coastguard Worker 		case UTF_16:
645*c9945492SAndroid Build Coastguard Worker 		case UTF_16BE:
646*c9945492SAndroid Build Coastguard Worker 		case UTF_16LE:
647*c9945492SAndroid Build Coastguard Worker 			if (c < 0x10000 || totype-UCS2BE < 2U) {
648*c9945492SAndroid Build Coastguard Worker 				if (c >= 0x10000) c = 0xFFFD;
649*c9945492SAndroid Build Coastguard Worker 				if (*outb < 2) goto toobig;
650*c9945492SAndroid Build Coastguard Worker 				put_16((void *)*out, c, totype);
651*c9945492SAndroid Build Coastguard Worker 				*out += 2;
652*c9945492SAndroid Build Coastguard Worker 				*outb -= 2;
653*c9945492SAndroid Build Coastguard Worker 				break;
654*c9945492SAndroid Build Coastguard Worker 			}
655*c9945492SAndroid Build Coastguard Worker 			if (*outb < 4) goto toobig;
656*c9945492SAndroid Build Coastguard Worker 			c -= 0x10000;
657*c9945492SAndroid Build Coastguard Worker 			put_16((void *)*out, (c>>10)|0xd800, totype);
658*c9945492SAndroid Build Coastguard Worker 			put_16((void *)(*out + 2), (c&0x3ff)|0xdc00, totype);
659*c9945492SAndroid Build Coastguard Worker 			*out += 4;
660*c9945492SAndroid Build Coastguard Worker 			*outb -= 4;
661*c9945492SAndroid Build Coastguard Worker 			break;
662*c9945492SAndroid Build Coastguard Worker 		case UTF_32:
663*c9945492SAndroid Build Coastguard Worker 			totype = UTF_32BE;
664*c9945492SAndroid Build Coastguard Worker 		case UTF_32BE:
665*c9945492SAndroid Build Coastguard Worker 		case UTF_32LE:
666*c9945492SAndroid Build Coastguard Worker 			if (*outb < 4) goto toobig;
667*c9945492SAndroid Build Coastguard Worker 			put_32((void *)*out, c, totype);
668*c9945492SAndroid Build Coastguard Worker 			*out += 4;
669*c9945492SAndroid Build Coastguard Worker 			*outb -= 4;
670*c9945492SAndroid Build Coastguard Worker 			break;
671*c9945492SAndroid Build Coastguard Worker 		}
672*c9945492SAndroid Build Coastguard Worker 	}
673*c9945492SAndroid Build Coastguard Worker 	*ploc = loc;
674*c9945492SAndroid Build Coastguard Worker 	return x;
675*c9945492SAndroid Build Coastguard Worker ilseq:
676*c9945492SAndroid Build Coastguard Worker 	err = EILSEQ;
677*c9945492SAndroid Build Coastguard Worker 	x = -1;
678*c9945492SAndroid Build Coastguard Worker 	goto end;
679*c9945492SAndroid Build Coastguard Worker toobig:
680*c9945492SAndroid Build Coastguard Worker 	err = E2BIG;
681*c9945492SAndroid Build Coastguard Worker 	x = -1;
682*c9945492SAndroid Build Coastguard Worker 	goto end;
683*c9945492SAndroid Build Coastguard Worker starved:
684*c9945492SAndroid Build Coastguard Worker 	err = EINVAL;
685*c9945492SAndroid Build Coastguard Worker 	x = -1;
686*c9945492SAndroid Build Coastguard Worker end:
687*c9945492SAndroid Build Coastguard Worker 	errno = err;
688*c9945492SAndroid Build Coastguard Worker 	*ploc = loc;
689*c9945492SAndroid Build Coastguard Worker 	return x;
690*c9945492SAndroid Build Coastguard Worker }
691