xref: /illumos-gate/usr/src/lib/iconv_modules/zh/common/zh_CN.iso2022-CN%UTF-8.c (revision 16d8656330ae5622ec32e5007f62145ebafdc50f)
1*16d86563SAlexander Pyhalov /*
2*16d86563SAlexander Pyhalov  * CDDL HEADER START
3*16d86563SAlexander Pyhalov  *
4*16d86563SAlexander Pyhalov  * The contents of this file are subject to the terms of the
5*16d86563SAlexander Pyhalov  * Common Development and Distribution License (the "License").
6*16d86563SAlexander Pyhalov  * You may not use this file except in compliance with the License.
7*16d86563SAlexander Pyhalov  *
8*16d86563SAlexander Pyhalov  * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
9*16d86563SAlexander Pyhalov  * or http://www.opensolaris.org/os/licensing.
10*16d86563SAlexander Pyhalov  * See the License for the specific language governing permissions
11*16d86563SAlexander Pyhalov  * and limitations under the License.
12*16d86563SAlexander Pyhalov  *
13*16d86563SAlexander Pyhalov  * When distributing Covered Code, include this CDDL HEADER in each
14*16d86563SAlexander Pyhalov  * file and include the License file at src/OPENSOLARIS.LICENSE.
15*16d86563SAlexander Pyhalov  * If applicable, add the following below this CDDL HEADER, with the
16*16d86563SAlexander Pyhalov  * fields enclosed by brackets "[]" replaced with your own identifying
17*16d86563SAlexander Pyhalov  * information: Portions Copyright [yyyy] [name of copyright owner]
18*16d86563SAlexander Pyhalov  *
19*16d86563SAlexander Pyhalov  * CDDL HEADER END
20*16d86563SAlexander Pyhalov  */
21*16d86563SAlexander Pyhalov /*
22*16d86563SAlexander Pyhalov  * Copyright (c) 1995, by Sun Microsystems, Inc.
23*16d86563SAlexander Pyhalov  * All rights reserved.
24*16d86563SAlexander Pyhalov  */
25*16d86563SAlexander Pyhalov 
26*16d86563SAlexander Pyhalov #include <stdio.h>
27*16d86563SAlexander Pyhalov #include <stdlib.h>
28*16d86563SAlexander Pyhalov #include <strings.h>
29*16d86563SAlexander Pyhalov #include <errno.h>
30*16d86563SAlexander Pyhalov #ifdef DEBUG
31*16d86563SAlexander Pyhalov #include <sys/fcntl.h>
32*16d86563SAlexander Pyhalov #include <sys/stat.h>
33*16d86563SAlexander Pyhalov #endif
34*16d86563SAlexander Pyhalov #include <gb2312_unicode.h>
35*16d86563SAlexander Pyhalov #include <cns11643_unicode_CN.h>	/* CNS 11643 to Unicode mapping table */
36*16d86563SAlexander Pyhalov 
37*16d86563SAlexander Pyhalov #define UTF8_NON_ID_CHAR1 0xEF
38*16d86563SAlexander Pyhalov #define UTF8_NON_ID_CHAR2 0xBF
39*16d86563SAlexander Pyhalov #define UTF8_NON_ID_CHAR3 0xBD
40*16d86563SAlexander Pyhalov 
41*16d86563SAlexander Pyhalov #define MSB 	0x80	/* most significant bit */
42*16d86563SAlexander Pyhalov #define MBYTE	0x8e	/* multi-byte (4 byte character) */
43*16d86563SAlexander Pyhalov #define PMASK	0xa0	/* plane number mask */
44*16d86563SAlexander Pyhalov #define ONEBYTE 0xff	/* right most byte */
45*16d86563SAlexander Pyhalov #define MSB_OFF 0x7f	/* mask off MBS */
46*16d86563SAlexander Pyhalov 
47*16d86563SAlexander Pyhalov #define SI	0x0f		/* shift in */
48*16d86563SAlexander Pyhalov #define SO	0x0e		/* shift out */
49*16d86563SAlexander Pyhalov #define ESC 0x1b		/* escape */
50*16d86563SAlexander Pyhalov #define SS2	0x4e		/* SS2 shift out */
51*16d86563SAlexander Pyhalov #define SS3 0x4f		/* SS3 shift out */
52*16d86563SAlexander Pyhalov #define NON_ID_CHAR_BYTE1	0xA1	/* non-identified character */
53*16d86563SAlexander Pyhalov #define NON_ID_CHAR_BYTE2	0xF5	/* non-identified character */
54*16d86563SAlexander Pyhalov 
55*16d86563SAlexander Pyhalov typedef struct _icv_state {
56*16d86563SAlexander Pyhalov 	char	_buf[10];
57*16d86563SAlexander Pyhalov 	size_t	_bufcont;
58*16d86563SAlexander Pyhalov 	char	_keepc[4];	/* maximum # byte of CNS11643 code */
59*16d86563SAlexander Pyhalov 	short	_gstate;		/* state machine id */
60*16d86563SAlexander Pyhalov 	short	_istate;		/* state for shift in/out */
61*16d86563SAlexander Pyhalov 	int		_plane;		/* plane number for Chinese character */
62*16d86563SAlexander Pyhalov 	int		_last_plane;	/* last charactor's plane # */
63*16d86563SAlexander Pyhalov 	int 	_errno;		/* internal errno */
64*16d86563SAlexander Pyhalov } _iconv_st;
65*16d86563SAlexander Pyhalov 
66*16d86563SAlexander Pyhalov enum _GSTATE    { G0, G1, G2, G3, G4, G5, G6, G7, G8, G9, \
67*16d86563SAlexander Pyhalov 				  G10,G11,G12,G13,G14,G15,G16,G17,G18,G19, \
68*16d86563SAlexander Pyhalov 				  G20,G21,G22,G23,G24,G25,G26,G27,G28,G29 };
69*16d86563SAlexander Pyhalov 
70*16d86563SAlexander Pyhalov enum _ISTATE	{ IN, OUT };
71*16d86563SAlexander Pyhalov 
72*16d86563SAlexander Pyhalov 
73*16d86563SAlexander Pyhalov int iso_gb_to_utf(_iconv_st * st, char* buf, size_t buflen);
74*16d86563SAlexander Pyhalov int iso_cns_to_utf(_iconv_st * st, char* buf, size_t buflen);
75*16d86563SAlexander Pyhalov int iso_cns_to_utf(_iconv_st * st, char* buf, size_t buflen);
76*16d86563SAlexander Pyhalov int binsearch(unsigned long x, table_t v[], int n);
77*16d86563SAlexander Pyhalov int flush_buf(_iconv_st * st, char ** outbuf, size_t * outbytesleft);
78*16d86563SAlexander Pyhalov 
flush_buf(_iconv_st * st,char ** outbuf,size_t * outbytesleft)79*16d86563SAlexander Pyhalov int flush_buf(_iconv_st * st, char ** outbuf, size_t * outbytesleft) {
80*16d86563SAlexander Pyhalov 	if (!st->_bufcont)
81*16d86563SAlexander Pyhalov 		return 0;
82*16d86563SAlexander Pyhalov 	if (st->_bufcont > *outbytesleft) {
83*16d86563SAlexander Pyhalov 		st->_errno = E2BIG;
84*16d86563SAlexander Pyhalov 		return -1;
85*16d86563SAlexander Pyhalov 	}
86*16d86563SAlexander Pyhalov 	if (st->_istate != IN) {
87*16d86563SAlexander Pyhalov 		st->_errno = EILSEQ;
88*16d86563SAlexander Pyhalov 		return -1;
89*16d86563SAlexander Pyhalov 	}
90*16d86563SAlexander Pyhalov 	strncpy(st->_buf, *outbuf, st->_bufcont);
91*16d86563SAlexander Pyhalov 	(*outbuf)+=(st->_bufcont);
92*16d86563SAlexander Pyhalov 	(*outbytesleft)-=(st->_bufcont);
93*16d86563SAlexander Pyhalov 	st->_bufcont = 0;
94*16d86563SAlexander Pyhalov 	return st->_bufcont;
95*16d86563SAlexander Pyhalov }
96*16d86563SAlexander Pyhalov 
97*16d86563SAlexander Pyhalov /*
98*16d86563SAlexander Pyhalov  * Open; called from iconv_open()
99*16d86563SAlexander Pyhalov  */
100*16d86563SAlexander Pyhalov void *
_icv_open()101*16d86563SAlexander Pyhalov _icv_open()
102*16d86563SAlexander Pyhalov {
103*16d86563SAlexander Pyhalov 	_iconv_st *st;
104*16d86563SAlexander Pyhalov 
105*16d86563SAlexander Pyhalov 	if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) {
106*16d86563SAlexander Pyhalov 		errno = ENOMEM;
107*16d86563SAlexander Pyhalov 		return ((void *) -1);
108*16d86563SAlexander Pyhalov 	}
109*16d86563SAlexander Pyhalov 
110*16d86563SAlexander Pyhalov 	st->_gstate = G0;
111*16d86563SAlexander Pyhalov 	st->_istate = IN;
112*16d86563SAlexander Pyhalov 	st->_last_plane = st->_plane = -1;
113*16d86563SAlexander Pyhalov 	st->_errno = 0;
114*16d86563SAlexander Pyhalov 	st->_bufcont = 0;
115*16d86563SAlexander Pyhalov 
116*16d86563SAlexander Pyhalov 	return ((void *) st);
117*16d86563SAlexander Pyhalov }
118*16d86563SAlexander Pyhalov 
119*16d86563SAlexander Pyhalov /*
120*16d86563SAlexander Pyhalov  * Close; called from iconv_close()
121*16d86563SAlexander Pyhalov  */
122*16d86563SAlexander Pyhalov void
_icv_close(_iconv_st * st)123*16d86563SAlexander Pyhalov _icv_close(_iconv_st *st)
124*16d86563SAlexander Pyhalov {
125*16d86563SAlexander Pyhalov 	if (st == NULL)
126*16d86563SAlexander Pyhalov 		errno = EBADF;
127*16d86563SAlexander Pyhalov 	else
128*16d86563SAlexander Pyhalov 		free(st);
129*16d86563SAlexander Pyhalov }
130*16d86563SAlexander Pyhalov 
131*16d86563SAlexander Pyhalov /*
132*16d86563SAlexander Pyhalov  * Actual conversion; called from iconv()
133*16d86563SAlexander Pyhalov  */
134*16d86563SAlexander Pyhalov /*=========================================================================
135*16d86563SAlexander Pyhalov  *
136*16d86563SAlexander Pyhalov  *             State Machine for interpreting ISO 2022-7 code
137*16d86563SAlexander Pyhalov  *
138*16d86563SAlexander Pyhalov  *=========================================================================
139*16d86563SAlexander Pyhalov  *
140*16d86563SAlexander Pyhalov  *                                                        plane 2 - 16
141*16d86563SAlexander Pyhalov  *                                                    +---------->-------+
142*16d86563SAlexander Pyhalov  *                                    plane           ^                  |
143*16d86563SAlexander Pyhalov  *            ESC      $       )      number     SO   | plane 1          v
144*16d86563SAlexander Pyhalov  *    +-> G0 ----> G1 ---> G2 ---> G3 ------> G4 --> G5 -------> G6     G7
145*16d86563SAlexander Pyhalov  *    |   | ascii  | ascii | ascii |    ascii |   SI | |          |      |
146*16d86563SAlexander Pyhalov  *    +----------------------------+    <-----+------+ +------<---+------+
147*16d86563SAlexander Pyhalov  *    ^                                 |
148*16d86563SAlexander Pyhalov  *    |              ascii              v
149*16d86563SAlexander Pyhalov  *    +---------<-------------<---------+
150*16d86563SAlexander Pyhalov  *
151*16d86563SAlexander Pyhalov  *=========================================================================*/
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)152*16d86563SAlexander Pyhalov size_t _icv_iconv(_iconv_st *st, \
153*16d86563SAlexander Pyhalov 					char **inbuf, size_t *inbytesleft, \
154*16d86563SAlexander Pyhalov 					char **outbuf, size_t *outbytesleft) {
155*16d86563SAlexander Pyhalov 	int		n;
156*16d86563SAlexander Pyhalov 	char	c;
157*16d86563SAlexander Pyhalov 
158*16d86563SAlexander Pyhalov 	if (st == NULL) {
159*16d86563SAlexander Pyhalov 		errno = EBADF;
160*16d86563SAlexander Pyhalov 		return ((size_t) -1);
161*16d86563SAlexander Pyhalov 	}
162*16d86563SAlexander Pyhalov 
163*16d86563SAlexander Pyhalov 	if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
164*16d86563SAlexander Pyhalov 		st->_gstate = G0;
165*16d86563SAlexander Pyhalov 		st->_istate = IN;
166*16d86563SAlexander Pyhalov 		st->_errno = 0;
167*16d86563SAlexander Pyhalov 		st->_plane = st->_last_plane = -1;
168*16d86563SAlexander Pyhalov 		return ((size_t) 0);
169*16d86563SAlexander Pyhalov 	}
170*16d86563SAlexander Pyhalov 
171*16d86563SAlexander Pyhalov 	errno = st->_errno = 0;	/* reset internal and external errno */
172*16d86563SAlexander Pyhalov 
173*16d86563SAlexander Pyhalov 	/* a state machine for interpreting ISO 2022-7 code */
174*16d86563SAlexander Pyhalov 	while (*inbytesleft > 0 && *outbytesleft > 0) {
175*16d86563SAlexander Pyhalov 		switch (st->_gstate) {
176*16d86563SAlexander Pyhalov 			case G0:		/* assuming ASCII in the beginning */
177*16d86563SAlexander Pyhalov 				if (**inbuf == ESC) {
178*16d86563SAlexander Pyhalov 					st->_gstate = G1;
179*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = ESC;
180*16d86563SAlexander Pyhalov 				} else {	/* real ASCII */
181*16d86563SAlexander Pyhalov 					**outbuf = **inbuf;
182*16d86563SAlexander Pyhalov 					(*outbuf)++;
183*16d86563SAlexander Pyhalov 					(*outbytesleft)--;
184*16d86563SAlexander Pyhalov 				}
185*16d86563SAlexander Pyhalov 				break;
186*16d86563SAlexander Pyhalov 			case G1:		/* got ESC, expecting $ */
187*16d86563SAlexander Pyhalov 				if (**inbuf == '$') {
188*16d86563SAlexander Pyhalov 					st->_gstate = G2;
189*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = '$';
190*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
191*16d86563SAlexander Pyhalov 					errno = st->_errno;
192*16d86563SAlexander Pyhalov 					return (size_t)-1;
193*16d86563SAlexander Pyhalov 				} else {
194*16d86563SAlexander Pyhalov 					st->_gstate = G0;
195*16d86563SAlexander Pyhalov 					st->_errno = 0;
196*16d86563SAlexander Pyhalov 					st->_istate = IN;
197*16d86563SAlexander Pyhalov 					continue;	/* don't advance inbuf */
198*16d86563SAlexander Pyhalov 				}
199*16d86563SAlexander Pyhalov 				break;
200*16d86563SAlexander Pyhalov 			case G2:		/* got $, expecting ) * or + */
201*16d86563SAlexander Pyhalov 				if (**inbuf == ')') {
202*16d86563SAlexander Pyhalov 					st->_gstate = G3;
203*16d86563SAlexander Pyhalov 				} else if (**inbuf == '*') {
204*16d86563SAlexander Pyhalov 					st->_gstate = G12;
205*16d86563SAlexander Pyhalov 					st->_plane = 2;
206*16d86563SAlexander Pyhalov 				} else if (**inbuf == '+') {
207*16d86563SAlexander Pyhalov 					st->_gstate = G19;
208*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
209*16d86563SAlexander Pyhalov 					errno = st->_errno;
210*16d86563SAlexander Pyhalov 					return (size_t)-1;
211*16d86563SAlexander Pyhalov 				} else {
212*16d86563SAlexander Pyhalov 					st->_gstate = G0;
213*16d86563SAlexander Pyhalov 					st->_errno = 0;
214*16d86563SAlexander Pyhalov 					st->_istate = IN;
215*16d86563SAlexander Pyhalov 					continue;	/* don't advance inbuf */
216*16d86563SAlexander Pyhalov 				}
217*16d86563SAlexander Pyhalov 				st->_buf[st->_bufcont++] = **inbuf;
218*16d86563SAlexander Pyhalov 				break;
219*16d86563SAlexander Pyhalov 			case G3:	/* got ) expecting A,G,H */
220*16d86563SAlexander Pyhalov 						/* H is for the bug of and zh_TW.BIG5 */
221*16d86563SAlexander Pyhalov 				if (**inbuf == 'A') {
222*16d86563SAlexander Pyhalov 					st->_plane = 0;
223*16d86563SAlexander Pyhalov 					st->_gstate = G4;
224*16d86563SAlexander Pyhalov 				} else if (**inbuf == 'G') {
225*16d86563SAlexander Pyhalov 					st->_plane = 1;
226*16d86563SAlexander Pyhalov 					st->_gstate = G8;
227*16d86563SAlexander Pyhalov 				} else if (**inbuf == 'H') {
228*16d86563SAlexander Pyhalov 					st->_plane = 2;
229*16d86563SAlexander Pyhalov 					st->_gstate = G8;
230*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
231*16d86563SAlexander Pyhalov 					errno = st->_errno;
232*16d86563SAlexander Pyhalov 					return (size_t)-1;
233*16d86563SAlexander Pyhalov 				} else {
234*16d86563SAlexander Pyhalov 					st->_gstate = G0;
235*16d86563SAlexander Pyhalov 					st->_errno = 0;
236*16d86563SAlexander Pyhalov 					st->_istate = IN;
237*16d86563SAlexander Pyhalov 					continue;
238*16d86563SAlexander Pyhalov 				}
239*16d86563SAlexander Pyhalov 				st->_buf[st->_bufcont++] = **inbuf;
240*16d86563SAlexander Pyhalov 				break;
241*16d86563SAlexander Pyhalov 		case G4:	/* ESC $ ) A got, and SO is expected */
242*16d86563SAlexander Pyhalov 				if (**inbuf == SO) {
243*16d86563SAlexander Pyhalov 					st->_gstate = G5;
244*16d86563SAlexander Pyhalov 					st->_istate = OUT;
245*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
246*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
247*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
248*16d86563SAlexander Pyhalov 					errno = st->_errno;
249*16d86563SAlexander Pyhalov 					return (size_t)-1;
250*16d86563SAlexander Pyhalov 				} else {
251*16d86563SAlexander Pyhalov 					st->_gstate = G0;
252*16d86563SAlexander Pyhalov 					st->_errno = 0;
253*16d86563SAlexander Pyhalov 					st->_istate = IN;
254*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
255*16d86563SAlexander Pyhalov 					continue;
256*16d86563SAlexander Pyhalov 				}
257*16d86563SAlexander Pyhalov 				break;
258*16d86563SAlexander Pyhalov 		case G5:	/* SO (Shift Out) */
259*16d86563SAlexander Pyhalov 				if (**inbuf == SI) {
260*16d86563SAlexander Pyhalov 					st->_istate = IN;
261*16d86563SAlexander Pyhalov 				st->_gstate = G7;
262*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
263*16d86563SAlexander Pyhalov 				} else if (**inbuf == ESC) {
264*16d86563SAlexander Pyhalov /*
265*16d86563SAlexander Pyhalov 				&& *((*inbuf) + 1) == '$') {
266*16d86563SAlexander Pyhalov 					if (flush_buf(st, outbuf, outbytesleft) == -1) {
267*16d86563SAlexander Pyhalov 						errno = st->_errno;
268*16d86563SAlexander Pyhalov 						return (size_t)-1;
269*16d86563SAlexander Pyhalov 					}
270*16d86563SAlexander Pyhalov  */
271*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
272*16d86563SAlexander Pyhalov 					st->_gstate = G0;
273*16d86563SAlexander Pyhalov 					continue;
274*16d86563SAlexander Pyhalov 				} else {	/* Chinese Charactors */
275*16d86563SAlexander Pyhalov 					st->_keepc[0] = **inbuf;
276*16d86563SAlexander Pyhalov 					st->_gstate = G6;
277*16d86563SAlexander Pyhalov 				}
278*16d86563SAlexander Pyhalov 				break;
279*16d86563SAlexander Pyhalov 		case G6:	/* GB2312: 2nd Chinese character */
280*16d86563SAlexander Pyhalov 				st->_keepc[1] = **inbuf;
281*16d86563SAlexander Pyhalov 				n = iso_gb_to_utf(st, *outbuf, *outbytesleft);
282*16d86563SAlexander Pyhalov 				if (n > 0) {
283*16d86563SAlexander Pyhalov 					(*outbuf) += n;
284*16d86563SAlexander Pyhalov 					(*outbytesleft) -= n;
285*16d86563SAlexander Pyhalov 				} else {
286*16d86563SAlexander Pyhalov 					errno = st->_errno;
287*16d86563SAlexander Pyhalov 					return (size_t)-1;
288*16d86563SAlexander Pyhalov 				}
289*16d86563SAlexander Pyhalov 				st->_gstate = G5;
290*16d86563SAlexander Pyhalov 				break;
291*16d86563SAlexander Pyhalov 			case G7:	/* Shift in */
292*16d86563SAlexander Pyhalov 				if (**inbuf == SO) {
293*16d86563SAlexander Pyhalov 					st->_gstate = G5;
294*16d86563SAlexander Pyhalov 					st->_istate = OUT;
295*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
296*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
297*16d86563SAlexander Pyhalov 				} else if (**inbuf == ESC) {
298*16d86563SAlexander Pyhalov 				/*
299*16d86563SAlexander Pyhalov 				&& *((*inbuf) + 1) == '$') {
300*16d86563SAlexander Pyhalov 				 */
301*16d86563SAlexander Pyhalov 					st->_gstate = G0;
302*16d86563SAlexander Pyhalov 					continue;
303*16d86563SAlexander Pyhalov 				} else {
304*16d86563SAlexander Pyhalov 					**outbuf = **inbuf;
305*16d86563SAlexander Pyhalov 					(*outbuf)++;
306*16d86563SAlexander Pyhalov 					(*outbytesleft) --;
307*16d86563SAlexander Pyhalov 				}
308*16d86563SAlexander Pyhalov 				break;
309*16d86563SAlexander Pyhalov 		case G8:	/* CNS: Chinese character */
310*16d86563SAlexander Pyhalov 				if (**inbuf == SO) {
311*16d86563SAlexander Pyhalov 					st->_istate = OUT;
312*16d86563SAlexander Pyhalov 					st->_gstate = G9;
313*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
314*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
315*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
316*16d86563SAlexander Pyhalov 					errno = st->_errno;
317*16d86563SAlexander Pyhalov 					return (size_t)-1;
318*16d86563SAlexander Pyhalov 				} else {
319*16d86563SAlexander Pyhalov 					st->_gstate = G0;
320*16d86563SAlexander Pyhalov 					st->_errno = 0;
321*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
322*16d86563SAlexander Pyhalov 					st->_istate = IN;
323*16d86563SAlexander Pyhalov 					continue;
324*16d86563SAlexander Pyhalov 				}
325*16d86563SAlexander Pyhalov 				break;
326*16d86563SAlexander Pyhalov 		case G9:
327*16d86563SAlexander Pyhalov 				if (**inbuf == SI) {
328*16d86563SAlexander Pyhalov 					st->_istate = IN;
329*16d86563SAlexander Pyhalov 					st->_gstate = G11;
330*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
331*16d86563SAlexander Pyhalov 				} else if (**inbuf == ESC) {
332*16d86563SAlexander Pyhalov 				/*
333*16d86563SAlexander Pyhalov 				&& *((*inbuf) + 1) == '$') {
334*16d86563SAlexander Pyhalov 				 */
335*16d86563SAlexander Pyhalov 					if (flush_buf(st, outbuf, outbytesleft) == -1) {
336*16d86563SAlexander Pyhalov 						errno = st->_errno;
337*16d86563SAlexander Pyhalov 						return (size_t)-1;
338*16d86563SAlexander Pyhalov 					}
339*16d86563SAlexander Pyhalov 					st->_gstate = G0;
340*16d86563SAlexander Pyhalov 					continue;
341*16d86563SAlexander Pyhalov 				} else {	/* Chinese Charactor */
342*16d86563SAlexander Pyhalov 					st->_keepc[0] = **inbuf;
343*16d86563SAlexander Pyhalov 					st->_gstate = G10;
344*16d86563SAlexander Pyhalov 				}
345*16d86563SAlexander Pyhalov 				break;
346*16d86563SAlexander Pyhalov 			case G10:
347*16d86563SAlexander Pyhalov 				st->_keepc[1] = **inbuf;
348*16d86563SAlexander Pyhalov 				n = iso_cns_to_utf(st, *outbuf, *outbytesleft);
349*16d86563SAlexander Pyhalov 				if (n > 0) {
350*16d86563SAlexander Pyhalov 					(*outbuf) += n;
351*16d86563SAlexander Pyhalov 					(*outbytesleft) -= n;
352*16d86563SAlexander Pyhalov 				} else {
353*16d86563SAlexander Pyhalov 					errno = st->_errno;
354*16d86563SAlexander Pyhalov 					return (size_t)-1;
355*16d86563SAlexander Pyhalov 				}
356*16d86563SAlexander Pyhalov 				st->_gstate = G9;
357*16d86563SAlexander Pyhalov 				break;
358*16d86563SAlexander Pyhalov 			case G11:
359*16d86563SAlexander Pyhalov 				st->_bufcont = 0;
360*16d86563SAlexander Pyhalov 				if (**inbuf == SO) {
361*16d86563SAlexander Pyhalov 					st->_istate = OUT;
362*16d86563SAlexander Pyhalov 					st->_gstate = G9;
363*16d86563SAlexander Pyhalov 				} else if (**inbuf == ESC) {
364*16d86563SAlexander Pyhalov 				/*
365*16d86563SAlexander Pyhalov 				&& *((*inbuf) + 1) == '$') {
366*16d86563SAlexander Pyhalov 				 */
367*16d86563SAlexander Pyhalov 					st->_gstate = G0;
368*16d86563SAlexander Pyhalov 					continue;
369*16d86563SAlexander Pyhalov 				} else {
370*16d86563SAlexander Pyhalov 					**outbuf = **inbuf;
371*16d86563SAlexander Pyhalov 					(*outbuf)++;
372*16d86563SAlexander Pyhalov 					(*outbytesleft)--;
373*16d86563SAlexander Pyhalov 				}
374*16d86563SAlexander Pyhalov 				break;
375*16d86563SAlexander Pyhalov 			case G12:
376*16d86563SAlexander Pyhalov 				if (**inbuf == 'H') {
377*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = 'H';
378*16d86563SAlexander Pyhalov 					st->_gstate = G13;
379*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
380*16d86563SAlexander Pyhalov 					errno = st->_errno;
381*16d86563SAlexander Pyhalov 					return (size_t)-1;
382*16d86563SAlexander Pyhalov 				} else {
383*16d86563SAlexander Pyhalov 					st->_istate = IN;
384*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
385*16d86563SAlexander Pyhalov 					st->_gstate = G0;
386*16d86563SAlexander Pyhalov 					continue;
387*16d86563SAlexander Pyhalov 				}
388*16d86563SAlexander Pyhalov 				break;
389*16d86563SAlexander Pyhalov 			case G13:
390*16d86563SAlexander Pyhalov 				if (**inbuf == ESC) {
391*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = **inbuf;
392*16d86563SAlexander Pyhalov 					st->_gstate = G14;
393*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
394*16d86563SAlexander Pyhalov 					errno = st->_errno;
395*16d86563SAlexander Pyhalov 					return (size_t)-1;
396*16d86563SAlexander Pyhalov 				} else {
397*16d86563SAlexander Pyhalov 					st->_gstate = G0;
398*16d86563SAlexander Pyhalov 					st->_istate = IN;
399*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
400*16d86563SAlexander Pyhalov 					continue;
401*16d86563SAlexander Pyhalov 				}
402*16d86563SAlexander Pyhalov 				break;
403*16d86563SAlexander Pyhalov 			case G14:
404*16d86563SAlexander Pyhalov 				if (**inbuf == SS2) {
405*16d86563SAlexander Pyhalov 					st->_istate = OUT;
406*16d86563SAlexander Pyhalov 					st->_gstate = G15;
407*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
408*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane = 2;
409*16d86563SAlexander Pyhalov 				} else if (**inbuf == '$') {
410*16d86563SAlexander Pyhalov 					st->_bufcont --;
411*16d86563SAlexander Pyhalov 					if (flush_buf(st, outbuf, outbytesleft) == -1) {
412*16d86563SAlexander Pyhalov 						errno = st->_errno;
413*16d86563SAlexander Pyhalov 						return (size_t)-1;
414*16d86563SAlexander Pyhalov 					} else {
415*16d86563SAlexander Pyhalov 						st->_gstate = G1;
416*16d86563SAlexander Pyhalov 						st->_plane = st->_last_plane;
417*16d86563SAlexander Pyhalov 						st->_istate = IN;
418*16d86563SAlexander Pyhalov 						continue;
419*16d86563SAlexander Pyhalov 					}
420*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
421*16d86563SAlexander Pyhalov 					errno = st->_errno;
422*16d86563SAlexander Pyhalov 					return (size_t)-1;
423*16d86563SAlexander Pyhalov 				} else {
424*16d86563SAlexander Pyhalov 					st->_gstate = G0;
425*16d86563SAlexander Pyhalov 					st->_istate = IN;
426*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
427*16d86563SAlexander Pyhalov 					continue;
428*16d86563SAlexander Pyhalov 				}
429*16d86563SAlexander Pyhalov 				break;
430*16d86563SAlexander Pyhalov 			case G15:
431*16d86563SAlexander Pyhalov 				if (**inbuf == SI) {
432*16d86563SAlexander Pyhalov 					st->_gstate = G16;
433*16d86563SAlexander Pyhalov 					st->_istate = IN;
434*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
435*16d86563SAlexander Pyhalov 				} else if (**inbuf == ESC) {
436*16d86563SAlexander Pyhalov 				/*
437*16d86563SAlexander Pyhalov 				&& *((*inbuf) + 1) == '$') {
438*16d86563SAlexander Pyhalov 				 */
439*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
440*16d86563SAlexander Pyhalov 					st->_gstate = G0;
441*16d86563SAlexander Pyhalov 					continue;
442*16d86563SAlexander Pyhalov 				} else {
443*16d86563SAlexander Pyhalov 					st->_keepc[0] = **inbuf;
444*16d86563SAlexander Pyhalov 					st->_gstate = G18;
445*16d86563SAlexander Pyhalov 				}
446*16d86563SAlexander Pyhalov 				break;
447*16d86563SAlexander Pyhalov 			case G16:
448*16d86563SAlexander Pyhalov 				if (**inbuf == ESC) {
449*16d86563SAlexander Pyhalov 					st->_gstate = G17;
450*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = ESC;
451*16d86563SAlexander Pyhalov 				} else {
452*16d86563SAlexander Pyhalov 					**outbuf = **inbuf;
453*16d86563SAlexander Pyhalov 					(*outbuf) ++;
454*16d86563SAlexander Pyhalov 					(*outbytesleft) --;
455*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
456*16d86563SAlexander Pyhalov 				}
457*16d86563SAlexander Pyhalov 				break;
458*16d86563SAlexander Pyhalov 			case G17:
459*16d86563SAlexander Pyhalov 				if (**inbuf == '$') {
460*16d86563SAlexander Pyhalov 					st->_gstate = G1;
461*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = '$';
462*16d86563SAlexander Pyhalov 					continue;
463*16d86563SAlexander Pyhalov 				} else if (**inbuf == SS2) {
464*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
465*16d86563SAlexander Pyhalov 					st->_gstate = G15;
466*16d86563SAlexander Pyhalov 					st->_istate = OUT;
467*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
468*16d86563SAlexander Pyhalov 					errno = st->_errno;
469*16d86563SAlexander Pyhalov 					return (size_t)-1;
470*16d86563SAlexander Pyhalov 				} else {
471*16d86563SAlexander Pyhalov 					st->_gstate = G16;
472*16d86563SAlexander Pyhalov 					st->_istate = IN;
473*16d86563SAlexander Pyhalov 				}
474*16d86563SAlexander Pyhalov 				break;
475*16d86563SAlexander Pyhalov 			case G18:
476*16d86563SAlexander Pyhalov 				st->_keepc[1] = **inbuf;
477*16d86563SAlexander Pyhalov 				st->_gstate = G15;
478*16d86563SAlexander Pyhalov 				if ((n = iso_cns_to_utf(st, \
479*16d86563SAlexander Pyhalov 											*outbuf, \
480*16d86563SAlexander Pyhalov 											*outbytesleft)) > 0) {
481*16d86563SAlexander Pyhalov 					(*outbuf)+=n;
482*16d86563SAlexander Pyhalov 					(*outbytesleft)-=n;
483*16d86563SAlexander Pyhalov 				} else {
484*16d86563SAlexander Pyhalov 					errno = st->_errno;
485*16d86563SAlexander Pyhalov 					return (size_t)-1;
486*16d86563SAlexander Pyhalov 				}
487*16d86563SAlexander Pyhalov 				break;
488*16d86563SAlexander Pyhalov 			case G19:	/* Plane #: 3 - 16 */
489*16d86563SAlexander Pyhalov 				c = **inbuf;
490*16d86563SAlexander Pyhalov 				if				(c == 'I' || \
491*16d86563SAlexander Pyhalov 								c == 'J' || \
492*16d86563SAlexander Pyhalov 								c == 'K' || \
493*16d86563SAlexander Pyhalov 								c == 'L' || \
494*16d86563SAlexander Pyhalov 								c == 'M' || \
495*16d86563SAlexander Pyhalov 								c == 'N' || \
496*16d86563SAlexander Pyhalov 								c == 'O' || \
497*16d86563SAlexander Pyhalov 								c == 'P' || \
498*16d86563SAlexander Pyhalov 								c == 'Q' || \
499*16d86563SAlexander Pyhalov 								c == 'R' || \
500*16d86563SAlexander Pyhalov 								c == 'S' || \
501*16d86563SAlexander Pyhalov 								c == 'T' || \
502*16d86563SAlexander Pyhalov 								c == 'U' || \
503*16d86563SAlexander Pyhalov 								c == 'V') {
504*16d86563SAlexander Pyhalov 					st->_plane = c - 'I' + 3;
505*16d86563SAlexander Pyhalov 					st->_gstate = G20;
506*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
507*16d86563SAlexander Pyhalov 					errno = st->_errno;
508*16d86563SAlexander Pyhalov 					return (size_t)-1;
509*16d86563SAlexander Pyhalov 				} else {
510*16d86563SAlexander Pyhalov 					st->_gstate = G0;
511*16d86563SAlexander Pyhalov 					st->_errno = 0;
512*16d86563SAlexander Pyhalov 					st->_istate = IN;
513*16d86563SAlexander Pyhalov 					st->_plane = st->_last_plane;
514*16d86563SAlexander Pyhalov 					continue;
515*16d86563SAlexander Pyhalov 				}
516*16d86563SAlexander Pyhalov 				st->_buf[st->_bufcont++] = c;
517*16d86563SAlexander Pyhalov 				break;
518*16d86563SAlexander Pyhalov 			case G20:
519*16d86563SAlexander Pyhalov 				if (**inbuf == ESC) {
520*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = **inbuf;
521*16d86563SAlexander Pyhalov 					st->_gstate = G21;
522*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
523*16d86563SAlexander Pyhalov 					errno = st->_errno;
524*16d86563SAlexander Pyhalov 					return (size_t)-1;
525*16d86563SAlexander Pyhalov 				} else {
526*16d86563SAlexander Pyhalov 					st->_gstate = G0;
527*16d86563SAlexander Pyhalov 					st->_istate = IN;
528*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
529*16d86563SAlexander Pyhalov 					continue;
530*16d86563SAlexander Pyhalov 				}
531*16d86563SAlexander Pyhalov 				break;
532*16d86563SAlexander Pyhalov 			case G21:
533*16d86563SAlexander Pyhalov 				if (**inbuf == SS3) {
534*16d86563SAlexander Pyhalov 					st->_istate = OUT;
535*16d86563SAlexander Pyhalov 					st->_gstate = G22;
536*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
537*16d86563SAlexander Pyhalov 				} else if (**inbuf == '$') {
538*16d86563SAlexander Pyhalov 					st->_bufcont --;
539*16d86563SAlexander Pyhalov 					if (flush_buf(st, outbuf, outbytesleft) == -1) {
540*16d86563SAlexander Pyhalov 						errno = st->_errno;
541*16d86563SAlexander Pyhalov 						return (size_t)-1;
542*16d86563SAlexander Pyhalov 					} else {
543*16d86563SAlexander Pyhalov 						st->_istate = IN;
544*16d86563SAlexander Pyhalov 						st->_last_plane = st->_plane;
545*16d86563SAlexander Pyhalov 						st->_gstate = G1;
546*16d86563SAlexander Pyhalov 						continue;
547*16d86563SAlexander Pyhalov 					}
548*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
549*16d86563SAlexander Pyhalov 					errno = st->_errno;
550*16d86563SAlexander Pyhalov 					return (size_t)-1;
551*16d86563SAlexander Pyhalov 				} else {
552*16d86563SAlexander Pyhalov 					st->_gstate = G0;
553*16d86563SAlexander Pyhalov 					st->_istate = IN;
554*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
555*16d86563SAlexander Pyhalov 					continue;
556*16d86563SAlexander Pyhalov 				}
557*16d86563SAlexander Pyhalov 				break;
558*16d86563SAlexander Pyhalov 			case G22:
559*16d86563SAlexander Pyhalov 				if (**inbuf == SI) {
560*16d86563SAlexander Pyhalov 					st->_istate = IN;
561*16d86563SAlexander Pyhalov 					st->_gstate = G24;
562*16d86563SAlexander Pyhalov 					st->_last_plane = st->_plane;
563*16d86563SAlexander Pyhalov 				} else {
564*16d86563SAlexander Pyhalov 					st->_keepc[0] = (char)MBYTE;
565*16d86563SAlexander Pyhalov 					st->_keepc[1] = (char)(PMASK + st->_plane);
566*16d86563SAlexander Pyhalov 					st->_keepc[2] = **inbuf;
567*16d86563SAlexander Pyhalov 					st->_gstate = G23;
568*16d86563SAlexander Pyhalov 				}
569*16d86563SAlexander Pyhalov 				break;
570*16d86563SAlexander Pyhalov 			case G23:
571*16d86563SAlexander Pyhalov 				st->_keepc[3] = **inbuf;
572*16d86563SAlexander Pyhalov 				if ((n = iso_cns_to_utf(st, \
573*16d86563SAlexander Pyhalov 											*outbuf, \
574*16d86563SAlexander Pyhalov 											*outbytesleft)) > 0) {
575*16d86563SAlexander Pyhalov 					(*outbuf)+=n;
576*16d86563SAlexander Pyhalov 					(*outbytesleft-=n);
577*16d86563SAlexander Pyhalov 				} else {
578*16d86563SAlexander Pyhalov 					st->_errno = errno;
579*16d86563SAlexander Pyhalov 					return (size_t)-1;
580*16d86563SAlexander Pyhalov 				}
581*16d86563SAlexander Pyhalov 				st->_gstate = G22;
582*16d86563SAlexander Pyhalov 				break;
583*16d86563SAlexander Pyhalov 			case G24:
584*16d86563SAlexander Pyhalov 				if (**inbuf == ESC) {
585*16d86563SAlexander Pyhalov 					st->_gstate = G25;
586*16d86563SAlexander Pyhalov 					st->_buf[st->_bufcont++] = ESC;
587*16d86563SAlexander Pyhalov 				} else {
588*16d86563SAlexander Pyhalov 					**outbuf = **inbuf;
589*16d86563SAlexander Pyhalov 					(*outbuf)++;
590*16d86563SAlexander Pyhalov 					(*outbytesleft)--;
591*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
592*16d86563SAlexander Pyhalov 				}
593*16d86563SAlexander Pyhalov 				break;
594*16d86563SAlexander Pyhalov 			case G25:
595*16d86563SAlexander Pyhalov 				if (**inbuf == '$') {
596*16d86563SAlexander Pyhalov 					st->_gstate = G1;
597*16d86563SAlexander Pyhalov 					continue;
598*16d86563SAlexander Pyhalov 				} else if (**inbuf == SS3) {
599*16d86563SAlexander Pyhalov 					st->_gstate = G22;
600*16d86563SAlexander Pyhalov 					st->_bufcont = 0;
601*16d86563SAlexander Pyhalov 					st->_istate = OUT;
602*16d86563SAlexander Pyhalov 				} else if (flush_buf(st, outbuf, outbytesleft) == -1) {
603*16d86563SAlexander Pyhalov 					errno = st->_errno;
604*16d86563SAlexander Pyhalov 					return (size_t)-1;
605*16d86563SAlexander Pyhalov 				} else {
606*16d86563SAlexander Pyhalov 					st->_gstate = G24;
607*16d86563SAlexander Pyhalov 					st->_istate = IN;
608*16d86563SAlexander Pyhalov 				}
609*16d86563SAlexander Pyhalov 				break;
610*16d86563SAlexander Pyhalov 			default:			/* should never come here */
611*16d86563SAlexander Pyhalov 				st->_errno = errno = EILSEQ;
612*16d86563SAlexander Pyhalov 				st->_gstate = G0;	/* reset state */
613*16d86563SAlexander Pyhalov 				break;
614*16d86563SAlexander Pyhalov 		}	/* end of switch */
615*16d86563SAlexander Pyhalov 
616*16d86563SAlexander Pyhalov 		(*inbuf)++;
617*16d86563SAlexander Pyhalov 		(*inbytesleft)--;
618*16d86563SAlexander Pyhalov 
619*16d86563SAlexander Pyhalov 		if (st->_errno) {
620*16d86563SAlexander Pyhalov 			break;
621*16d86563SAlexander Pyhalov 		}
622*16d86563SAlexander Pyhalov 		if (errno)
623*16d86563SAlexander Pyhalov {
624*16d86563SAlexander Pyhalov 			return((size_t)(-1));
625*16d86563SAlexander Pyhalov }
626*16d86563SAlexander Pyhalov 	}
627*16d86563SAlexander Pyhalov 
628*16d86563SAlexander Pyhalov 	if (*inbytesleft > 0 && *outbytesleft == 0) {
629*16d86563SAlexander Pyhalov 		errno = E2BIG;
630*16d86563SAlexander Pyhalov 		return((size_t)(-1));
631*16d86563SAlexander Pyhalov 	}
632*16d86563SAlexander Pyhalov 	return (size_t)(*inbytesleft);
633*16d86563SAlexander Pyhalov }
634*16d86563SAlexander Pyhalov 
iso_gb_to_utf(_iconv_st * st,char * buf,size_t buflen)635*16d86563SAlexander Pyhalov int iso_gb_to_utf(_iconv_st * st, char* buf, size_t buflen)
636*16d86563SAlexander Pyhalov {
637*16d86563SAlexander Pyhalov char    in_byte1, in_byte2;
638*16d86563SAlexander Pyhalov 	int	idx;
639*16d86563SAlexander Pyhalov 	int	unicode;
640*16d86563SAlexander Pyhalov 
641*16d86563SAlexander Pyhalov 	if ( buflen < 2 ) {
642*16d86563SAlexander Pyhalov 		st->_errno = E2BIG;
643*16d86563SAlexander Pyhalov 	    return -1;
644*16d86563SAlexander Pyhalov 	}
645*16d86563SAlexander Pyhalov 
646*16d86563SAlexander Pyhalov 	in_byte1=st->_keepc[0];
647*16d86563SAlexander Pyhalov 	in_byte2=st->_keepc[1];
648*16d86563SAlexander Pyhalov 
649*16d86563SAlexander Pyhalov 	idx = (((in_byte1 & 0xff) - 0x21) * 94)  + (in_byte2 & 0xff) - 0x21;
650*16d86563SAlexander Pyhalov 	if (idx < 0 || idx > GBMAX - 1) {
651*16d86563SAlexander Pyhalov 		errno = EILSEQ;
652*16d86563SAlexander Pyhalov 		return -1;
653*16d86563SAlexander Pyhalov 	}
654*16d86563SAlexander Pyhalov 	unicode = Unicode[idx];
655*16d86563SAlexander Pyhalov 	if (unicode >= 0x0080 && unicode <= 0x07ff) {
656*16d86563SAlexander Pyhalov 	    if ( buflen < 2 ) {
657*16d86563SAlexander Pyhalov 		errno = E2BIG;
658*16d86563SAlexander Pyhalov 		return 0;
659*16d86563SAlexander Pyhalov 	    }
660*16d86563SAlexander Pyhalov 	    *buf = ((unicode >> 6) & 0x1f) | 0xc0;
661*16d86563SAlexander Pyhalov 	    *(buf+1) = (unicode & 0x3f) | MSB;
662*16d86563SAlexander Pyhalov 	    return 2;
663*16d86563SAlexander Pyhalov 	}
664*16d86563SAlexander Pyhalov 	if (unicode >= 0x0800 && unicode <= 0xffff) {
665*16d86563SAlexander Pyhalov 	    if ( buflen < 3 ) {
666*16d86563SAlexander Pyhalov 		errno = E2BIG;
667*16d86563SAlexander Pyhalov 		return 0;
668*16d86563SAlexander Pyhalov 	    }
669*16d86563SAlexander Pyhalov 	    *buf = ((unicode >> 12) & 0x0f) | 0xe0;
670*16d86563SAlexander Pyhalov 	    *(buf+1) = ((unicode >> 6) & 0x3f) | MSB;
671*16d86563SAlexander Pyhalov 	    *(buf+2) = (unicode & 0x3f) | MSB;
672*16d86563SAlexander Pyhalov 	    return 3;
673*16d86563SAlexander Pyhalov 	}
674*16d86563SAlexander Pyhalov 	if ( buflen < 3 ) {
675*16d86563SAlexander Pyhalov 	    errno = E2BIG;
676*16d86563SAlexander Pyhalov 	    return 0;
677*16d86563SAlexander Pyhalov 	}
678*16d86563SAlexander Pyhalov 
679*16d86563SAlexander Pyhalov 	*buf     = UTF8_NON_ID_CHAR1;
680*16d86563SAlexander Pyhalov 	*(buf+1) = UTF8_NON_ID_CHAR2;
681*16d86563SAlexander Pyhalov 	*(buf+2) = UTF8_NON_ID_CHAR3;
682*16d86563SAlexander Pyhalov 	return 3;
683*16d86563SAlexander Pyhalov }
684*16d86563SAlexander Pyhalov 
685*16d86563SAlexander Pyhalov /*
686*16d86563SAlexander Pyhalov  * Return: > 0 - converted with enough space in output buffer
687*16d86563SAlexander Pyhalov  *         = 0 - no space in outbuf
688*16d86563SAlexander Pyhalov  */
iso_cns_to_utf(_iconv_st * st,char * buf,size_t buflen)689*16d86563SAlexander Pyhalov int iso_cns_to_utf(_iconv_st * st, char* buf, size_t buflen) {
690*16d86563SAlexander Pyhalov 	char		cns_str[3];
691*16d86563SAlexander Pyhalov 	unsigned long	cns_val;	/* MSB mask off CNS 11643 value */
692*16d86563SAlexander Pyhalov 	int		unidx;		/* binary search index */
693*16d86563SAlexander Pyhalov 	unsigned long	utf_val;	/* unicode code */
694*16d86563SAlexander Pyhalov 
695*16d86563SAlexander Pyhalov 	if (st->_plane == 1) {
696*16d86563SAlexander Pyhalov 		cns_str[0] = st->_keepc[0] & MSB_OFF;
697*16d86563SAlexander Pyhalov 		cns_str[1] = st->_keepc[1] & MSB_OFF;
698*16d86563SAlexander Pyhalov 	} else {
699*16d86563SAlexander Pyhalov 		cns_str[0] = st->_keepc[0] & MSB_OFF;
700*16d86563SAlexander Pyhalov 		cns_str[1] = st->_keepc[1] & MSB_OFF;
701*16d86563SAlexander Pyhalov 	}
702*16d86563SAlexander Pyhalov 	cns_val = (cns_str[0] << 8) + cns_str[1];
703*16d86563SAlexander Pyhalov 	if (buflen < 2) {
704*16d86563SAlexander Pyhalov 		errno = E2BIG;
705*16d86563SAlexander Pyhalov 		return(0);
706*16d86563SAlexander Pyhalov 	}
707*16d86563SAlexander Pyhalov 
708*16d86563SAlexander Pyhalov 	switch (st->_plane) {
709*16d86563SAlexander Pyhalov 		case 1:
710*16d86563SAlexander Pyhalov 			unidx = binsearch(cns_val, cns1_utf_tab, MAX_CNS1_NUM);
711*16d86563SAlexander Pyhalov 			if (unidx >= 0)
712*16d86563SAlexander Pyhalov 				utf_val = cns1_utf_tab[unidx].value;
713*16d86563SAlexander Pyhalov 			break;
714*16d86563SAlexander Pyhalov 		case 2:
715*16d86563SAlexander Pyhalov 			unidx = binsearch(cns_val, cns2_utf_tab, MAX_CNS2_NUM);
716*16d86563SAlexander Pyhalov 			if (unidx >= 0)
717*16d86563SAlexander Pyhalov 				utf_val = cns2_utf_tab[unidx].value;
718*16d86563SAlexander Pyhalov 			break;
719*16d86563SAlexander Pyhalov 		case 3:
720*16d86563SAlexander Pyhalov 			unidx = binsearch(cns_val, cns3_utf_tab, MAX_CNS3_NUM);
721*16d86563SAlexander Pyhalov 			if (unidx >= 0)
722*16d86563SAlexander Pyhalov 				utf_val = cns3_utf_tab[unidx].value;
723*16d86563SAlexander Pyhalov 			break;
724*16d86563SAlexander Pyhalov 		default:
725*16d86563SAlexander Pyhalov 			unidx = -1;	/* no mapping from CNS to Unicode out of plane 1,2&3 */
726*16d86563SAlexander Pyhalov 			break;
727*16d86563SAlexander Pyhalov 	}
728*16d86563SAlexander Pyhalov 
729*16d86563SAlexander Pyhalov 
730*16d86563SAlexander Pyhalov 	if (unidx < 0) {	/* no match from CNS to Unicode */
731*16d86563SAlexander Pyhalov 		*buf     = UTF8_NON_ID_CHAR1;
732*16d86563SAlexander Pyhalov 		*(buf+1) = UTF8_NON_ID_CHAR2;
733*16d86563SAlexander Pyhalov 		*(buf+2) = UTF8_NON_ID_CHAR3;
734*16d86563SAlexander Pyhalov 	return 3;
735*16d86563SAlexander Pyhalov 	} else {
736*16d86563SAlexander Pyhalov 	if (utf_val >= 0x0080 && utf_val <= 0x07ff) {
737*16d86563SAlexander Pyhalov 	    if ( buflen < 2 ) {
738*16d86563SAlexander Pyhalov 		errno = E2BIG;
739*16d86563SAlexander Pyhalov 		return 0;
740*16d86563SAlexander Pyhalov 	    }
741*16d86563SAlexander Pyhalov 	    *buf = ((utf_val >> 6) & 0x1f) | 0xc0;
742*16d86563SAlexander Pyhalov 	    *(buf+1) = (utf_val & 0x3f) | MSB;
743*16d86563SAlexander Pyhalov 	    return 2;
744*16d86563SAlexander Pyhalov 	}
745*16d86563SAlexander Pyhalov 	if (utf_val >= 0x0800 && utf_val <= 0xffff) {
746*16d86563SAlexander Pyhalov 	    if ( buflen < 3 ) {
747*16d86563SAlexander Pyhalov 		errno = E2BIG;
748*16d86563SAlexander Pyhalov 		return 0;
749*16d86563SAlexander Pyhalov 	    }
750*16d86563SAlexander Pyhalov 	    *buf = ((utf_val >> 12) & 0x0f) | 0xe0;
751*16d86563SAlexander Pyhalov 	    *(buf+1) = ((utf_val >> 6) & 0x3f) | MSB;
752*16d86563SAlexander Pyhalov 	    *(buf+2) = (utf_val & 0x3f) | MSB;
753*16d86563SAlexander Pyhalov 	    return 3;
754*16d86563SAlexander Pyhalov 	}
755*16d86563SAlexander Pyhalov 	if ( buflen < 3 ) {
756*16d86563SAlexander Pyhalov 	    errno = E2BIG;
757*16d86563SAlexander Pyhalov 	    return 0;
758*16d86563SAlexander Pyhalov 	}
759*16d86563SAlexander Pyhalov 
760*16d86563SAlexander Pyhalov 	*buf     = UTF8_NON_ID_CHAR1;
761*16d86563SAlexander Pyhalov 	*(buf+1) = UTF8_NON_ID_CHAR2;
762*16d86563SAlexander Pyhalov 	*(buf+2) = UTF8_NON_ID_CHAR3;
763*16d86563SAlexander Pyhalov 	return 3;
764*16d86563SAlexander Pyhalov 	}
765*16d86563SAlexander Pyhalov 
766*16d86563SAlexander Pyhalov }
767*16d86563SAlexander Pyhalov 
768*16d86563SAlexander Pyhalov /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
binsearch(unsigned long x,table_t v[],int n)769*16d86563SAlexander Pyhalov int binsearch(unsigned long x, table_t v[], int n)
770*16d86563SAlexander Pyhalov {
771*16d86563SAlexander Pyhalov 	int low, high, mid;
772*16d86563SAlexander Pyhalov 
773*16d86563SAlexander Pyhalov 	low = 0;
774*16d86563SAlexander Pyhalov 	high = n - 1;
775*16d86563SAlexander Pyhalov 	while (low <= high) {
776*16d86563SAlexander Pyhalov 		mid = (low + high) / 2;
777*16d86563SAlexander Pyhalov 		if (x < v[mid].key)
778*16d86563SAlexander Pyhalov 			high = mid - 1;
779*16d86563SAlexander Pyhalov 		else if (x > v[mid].key)
780*16d86563SAlexander Pyhalov 			low = mid + 1;
781*16d86563SAlexander Pyhalov 		else	/* found match */
782*16d86563SAlexander Pyhalov 			return mid;
783*16d86563SAlexander Pyhalov 	}
784*16d86563SAlexander Pyhalov 	return (-1);	/* no match */
785*16d86563SAlexander Pyhalov }
786*16d86563SAlexander Pyhalov 
787*16d86563SAlexander Pyhalov 
788*16d86563SAlexander Pyhalov #ifdef DEBUG
main(int argc,char ** argv)789*16d86563SAlexander Pyhalov main(int argc, char ** argv) {
790*16d86563SAlexander Pyhalov 	char *inbuf, *outbuf, *in_tmp, *out_tmp;
791*16d86563SAlexander Pyhalov 	size_t inbytesleft, outbytesleft;
792*16d86563SAlexander Pyhalov 	int fd;
793*16d86563SAlexander Pyhalov 	int i;
794*16d86563SAlexander Pyhalov 	struct stat s;
795*16d86563SAlexander Pyhalov 	_iconv_st * st;
796*16d86563SAlexander Pyhalov 	if (argc < 2) {
797*16d86563SAlexander Pyhalov 		fprintf(stderr, "Usage: %s input\n", argv[0]);
798*16d86563SAlexander Pyhalov 		exit(-1);
799*16d86563SAlexander Pyhalov 	}
800*16d86563SAlexander Pyhalov 	if ((fd = open(argv[1], O_RDONLY)) == -1) {
801*16d86563SAlexander Pyhalov 		perror("open");
802*16d86563SAlexander Pyhalov 		exit(-2);
803*16d86563SAlexander Pyhalov 	}
804*16d86563SAlexander Pyhalov 	if (fstat(fd, &s) == -1) {
805*16d86563SAlexander Pyhalov 		perror("stat");
806*16d86563SAlexander Pyhalov 		exit(-3);
807*16d86563SAlexander Pyhalov 	}
808*16d86563SAlexander Pyhalov 	inbytesleft = outbytesleft = s.st_size;
809*16d86563SAlexander Pyhalov 	in_tmp = inbuf = (char *)malloc(inbytesleft);
810*16d86563SAlexander Pyhalov 	out_tmp = outbuf = (char *)malloc(outbytesleft);
811*16d86563SAlexander Pyhalov 	if (!inbuf || !outbuf) {
812*16d86563SAlexander Pyhalov 		perror("malloc");
813*16d86563SAlexander Pyhalov 		exit(-1);
814*16d86563SAlexander Pyhalov 	}
815*16d86563SAlexander Pyhalov 	if (read(fd, inbuf, inbytesleft) != inbytesleft) {
816*16d86563SAlexander Pyhalov 		perror("read");
817*16d86563SAlexander Pyhalov 		exit(-4);
818*16d86563SAlexander Pyhalov 	}
819*16d86563SAlexander Pyhalov 	for (i = 0; i < inbytesleft; i++)
820*16d86563SAlexander Pyhalov 		fprintf(stderr, "%x\t", *(inbuf+i));
821*16d86563SAlexander Pyhalov 	fprintf(stderr, "\n");
822*16d86563SAlexander Pyhalov 	st = (_iconv_st *)_icv_open();
823*16d86563SAlexander Pyhalov 	if (st == (_iconv_st *) -1) {
824*16d86563SAlexander Pyhalov 		perror("_icv_open");
825*16d86563SAlexander Pyhalov 		exit(-1);
826*16d86563SAlexander Pyhalov 	}
827*16d86563SAlexander Pyhalov 	if (_icv_iconv(st, \
828*16d86563SAlexander Pyhalov 				&inbuf, &inbytesleft, \
829*16d86563SAlexander Pyhalov 				&outbuf, &outbytesleft) == -1) {
830*16d86563SAlexander Pyhalov 		perror("icv_iconv");
831*16d86563SAlexander Pyhalov 		fprintf(stderr, "\ninbytesleft = %d\n", inbytesleft);
832*16d86563SAlexander Pyhalov 		exit(-2);
833*16d86563SAlexander Pyhalov 	}
834*16d86563SAlexander Pyhalov 	if (write(1, out_tmp, s.st_size - outbytesleft) == -1) {
835*16d86563SAlexander Pyhalov 		perror("write");
836*16d86563SAlexander Pyhalov 		exit(-1);
837*16d86563SAlexander Pyhalov 	}
838*16d86563SAlexander Pyhalov 	free(in_tmp);
839*16d86563SAlexander Pyhalov 	free(out_tmp);
840*16d86563SAlexander Pyhalov 	close(fd);
841*16d86563SAlexander Pyhalov 	_icv_close(st);
842*16d86563SAlexander Pyhalov }
843*16d86563SAlexander Pyhalov #endif
844