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) 2001 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 <errno.h>
28*16d86563SAlexander Pyhalov #include <stdlib.h>
29*16d86563SAlexander Pyhalov #include <strings.h>
30*16d86563SAlexander Pyhalov #include "iscii.h"
31*16d86563SAlexander Pyhalov 
32*16d86563SAlexander Pyhalov #define MSB        0x80    /* most significant bit */
33*16d86563SAlexander Pyhalov #define ONEBYTE    0xff    /* right most byte */
34*16d86563SAlexander Pyhalov 
35*16d86563SAlexander Pyhalov #define REPLACE_CHAR1  0xEF     /* invalid conversion character */
36*16d86563SAlexander Pyhalov #define REPLACE_CHAR2  0xBF
37*16d86563SAlexander Pyhalov #define REPLACE_CHAR3  0xBD
38*16d86563SAlexander Pyhalov 
39*16d86563SAlexander Pyhalov #define UTF8_SET1B(b,v)      \
40*16d86563SAlexander Pyhalov     (b[0]=(v&0x7f))
41*16d86563SAlexander Pyhalov 
42*16d86563SAlexander Pyhalov #define UTF8_SET2B(b,v)      \
43*16d86563SAlexander Pyhalov     (b[0]=(0xc0|((v>>6)&0x1f))); \
44*16d86563SAlexander Pyhalov     (b[1]=(0x80|((v&0x3f))))
45*16d86563SAlexander Pyhalov 
46*16d86563SAlexander Pyhalov #define UTF8_SET3B(b,v)      \
47*16d86563SAlexander Pyhalov     (b[0]=(0xe0|((v>>12)&0xf))); \
48*16d86563SAlexander Pyhalov     (b[1]=(0x80|((v>>6)&0x3f))); \
49*16d86563SAlexander Pyhalov     (b[2]=(0x80|((v&0x3f))))
50*16d86563SAlexander Pyhalov 
51*16d86563SAlexander Pyhalov typedef struct _icv_state {
52*16d86563SAlexander Pyhalov      char    keepc[3];    /* keepc[0] is attr, keepc[1] and keepc[2] are lookup-ed */
53*16d86563SAlexander Pyhalov      short   pState;      /* Previous State */
54*16d86563SAlexander Pyhalov      int    _errno;
55*16d86563SAlexander Pyhalov } _iconv_st;
56*16d86563SAlexander Pyhalov 
57*16d86563SAlexander Pyhalov enum _CSTATE { S_BASIC, S_ATR, S_EXT, S_NONE };
58*16d86563SAlexander Pyhalov 
59*16d86563SAlexander Pyhalov #define have_nukta(isc_type) ( nukta_type[isc_type] != NULL )
60*16d86563SAlexander Pyhalov #define have_EXT(isc_type) ( EXT_type[isc_type] != NULL )
61*16d86563SAlexander Pyhalov #define FIRST_CHAR  0xA0
62*16d86563SAlexander Pyhalov 
63*16d86563SAlexander Pyhalov static int copy_to_outbuf(ucs_t uniid, char *buf, size_t buflen);
64*16d86563SAlexander Pyhalov 
65*16d86563SAlexander Pyhalov static ucs_t
get_nukta(uchar iscii,int type)66*16d86563SAlexander Pyhalov get_nukta(uchar iscii, int type)
67*16d86563SAlexander Pyhalov {
68*16d86563SAlexander Pyhalov     int indx = iscii - FIRST_CHAR;
69*16d86563SAlexander Pyhalov     int *iscii_nukta = nukta_type[type];
70*16d86563SAlexander Pyhalov 
71*16d86563SAlexander Pyhalov     return ((indx >= 0) ? iscii_nukta[indx] : 0 );
72*16d86563SAlexander Pyhalov }
73*16d86563SAlexander Pyhalov 
74*16d86563SAlexander Pyhalov static ucs_t
get_EXT(uchar iscii,int type)75*16d86563SAlexander Pyhalov get_EXT(uchar iscii, int type)
76*16d86563SAlexander Pyhalov {
77*16d86563SAlexander Pyhalov     int indx = iscii - FIRST_CHAR;
78*16d86563SAlexander Pyhalov     int *iscii_EXT = EXT_type[type];
79*16d86563SAlexander Pyhalov 
80*16d86563SAlexander Pyhalov     return ((indx >= 0) ? iscii_EXT[indx] : 0 );
81*16d86563SAlexander Pyhalov }
82*16d86563SAlexander Pyhalov 
83*16d86563SAlexander Pyhalov static ucs_t
traverse_table(Entry * entry,int num,uchar iscii)84*16d86563SAlexander Pyhalov traverse_table(Entry *entry, int num,  uchar iscii)
85*16d86563SAlexander Pyhalov {
86*16d86563SAlexander Pyhalov     int i=0;
87*16d86563SAlexander Pyhalov     ucs_t retucs=0;
88*16d86563SAlexander Pyhalov 
89*16d86563SAlexander Pyhalov     for ( ; i < num; ++i ) {
90*16d86563SAlexander Pyhalov         Entry en = entry[i];
91*16d86563SAlexander Pyhalov 
92*16d86563SAlexander Pyhalov         if ( iscii < en.iscii ) break;
93*16d86563SAlexander Pyhalov         if ( iscii >= en.iscii && iscii < en.iscii + en.count ) {
94*16d86563SAlexander Pyhalov              retucs = en.ucs + ( iscii - en.iscii );
95*16d86563SAlexander Pyhalov              break;
96*16d86563SAlexander Pyhalov         }
97*16d86563SAlexander Pyhalov     }
98*16d86563SAlexander Pyhalov 
99*16d86563SAlexander Pyhalov     return retucs;
100*16d86563SAlexander Pyhalov }
101*16d86563SAlexander Pyhalov 
102*16d86563SAlexander Pyhalov /*
103*16d86563SAlexander Pyhalov  * the copy_to_outbuf has to be called before the st->keepc needs to changed.
104*16d86563SAlexander Pyhalov  * if E2BIG error, keep st->keepc. Will flush it at the beginning of next
105*16d86563SAlexander Pyhalov  * _icv_iconv() invocation
106*16d86563SAlexander Pyhalov  */
107*16d86563SAlexander Pyhalov int
iscii_to_utf8(_iconv_st * st,char * buf,size_t buflen)108*16d86563SAlexander Pyhalov iscii_to_utf8(_iconv_st *st, char *buf, size_t buflen)
109*16d86563SAlexander Pyhalov {
110*16d86563SAlexander Pyhalov #define DEV_ATR 0x42
111*16d86563SAlexander Pyhalov     ucs_t uniid;
112*16d86563SAlexander Pyhalov     int   nBytes=0;
113*16d86563SAlexander Pyhalov     ISCII isc_type = isc_TYPE[st->keepc[0] - DEV_ATR];
114*16d86563SAlexander Pyhalov     Entries en = iscii_table[isc_type];
115*16d86563SAlexander Pyhalov     /* unsigned int  keepc0 = (unsigned int) (st->keepc[0] & ONEBYTE); */
116*16d86563SAlexander Pyhalov     unsigned int  keepc1 = (unsigned int) (st->keepc[1] & ONEBYTE);
117*16d86563SAlexander Pyhalov     unsigned int  keepc2 = (unsigned int) (st->keepc[2] & ONEBYTE);
118*16d86563SAlexander Pyhalov 
119*16d86563SAlexander Pyhalov     if (keepc1 == 0xFF) { /* FFFD */
120*16d86563SAlexander Pyhalov         if ( buflen < 3 ) {
121*16d86563SAlexander Pyhalov             errno = E2BIG;
122*16d86563SAlexander Pyhalov             return 0;
123*16d86563SAlexander Pyhalov         }
124*16d86563SAlexander Pyhalov 
125*16d86563SAlexander Pyhalov         *buf = (char)REPLACE_CHAR1;
126*16d86563SAlexander Pyhalov         *(buf+1) = (char)REPLACE_CHAR2;
127*16d86563SAlexander Pyhalov         *(buf+2) = (char)REPLACE_CHAR3;
128*16d86563SAlexander Pyhalov         return (3);
129*16d86563SAlexander Pyhalov     }
130*16d86563SAlexander Pyhalov 
131*16d86563SAlexander Pyhalov     if (keepc2 == 0) { /* Flush Single Character */
132*16d86563SAlexander Pyhalov 
133*16d86563SAlexander Pyhalov         if (keepc1 & MSB) {    /* ISCII - Non-Ascii Codepoints */
134*16d86563SAlexander Pyhalov             uniid = traverse_table(en.entry, en.items, keepc1);
135*16d86563SAlexander Pyhalov         } else  /* ASCII */
136*16d86563SAlexander Pyhalov             uniid = keepc1;
137*16d86563SAlexander Pyhalov 
138*16d86563SAlexander Pyhalov         if ( (nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
139*16d86563SAlexander Pyhalov         st->keepc[1] = 0;
140*16d86563SAlexander Pyhalov 
141*16d86563SAlexander Pyhalov     } else {
142*16d86563SAlexander Pyhalov         /* keepc[1] and keepc[2] != 0 */
143*16d86563SAlexander Pyhalov         if (keepc1 & MSB) {
144*16d86563SAlexander Pyhalov 
145*16d86563SAlexander Pyhalov 	    switch (keepc1)
146*16d86563SAlexander Pyhalov 	     {
147*16d86563SAlexander Pyhalov 	      case ISC_ext:
148*16d86563SAlexander Pyhalov 
149*16d86563SAlexander Pyhalov 		if ( have_EXT(isc_type) && is_valid_ext_code(keepc2) )
150*16d86563SAlexander Pyhalov 		  {  /* EXT only supported in Devanagari script */
151*16d86563SAlexander Pyhalov 
152*16d86563SAlexander Pyhalov                      uniid = get_EXT(keepc2, isc_type);
153*16d86563SAlexander Pyhalov                      if ((nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
154*16d86563SAlexander Pyhalov 		  }
155*16d86563SAlexander Pyhalov 		else
156*16d86563SAlexander Pyhalov 		     errno = EILSEQ;
157*16d86563SAlexander Pyhalov 
158*16d86563SAlexander Pyhalov 	        st->keepc[1] = st->keepc[2] = 0;
159*16d86563SAlexander Pyhalov 		break;
160*16d86563SAlexander Pyhalov 	      case ISC_halant:
161*16d86563SAlexander Pyhalov                 /* test whether there has enough space to hold the converted bytes */
162*16d86563SAlexander Pyhalov                 if ((keepc2 == ISC_halant || keepc2 == ISC_nukta) && buflen < 6 )
163*16d86563SAlexander Pyhalov                     goto E2big;
164*16d86563SAlexander Pyhalov 
165*16d86563SAlexander Pyhalov                 uniid = traverse_table(en.entry, en.items, keepc1);
166*16d86563SAlexander Pyhalov                 if ((nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
167*16d86563SAlexander Pyhalov                 st->keepc[1] = st->keepc[2];
168*16d86563SAlexander Pyhalov 
169*16d86563SAlexander Pyhalov                 if ( keepc2 == ISC_halant || keepc2 == ISC_nukta )
170*16d86563SAlexander Pyhalov                   {
171*16d86563SAlexander Pyhalov                      int nbytes_2 = 0;
172*16d86563SAlexander Pyhalov                      if (keepc2 == ISC_halant) uniid = UNI_ZWNJ; /* explicit Halant */
173*16d86563SAlexander Pyhalov                      if (keepc2 == ISC_nukta) uniid = UNI_ZWJ; /* soft Halant */
174*16d86563SAlexander Pyhalov 
175*16d86563SAlexander Pyhalov                      if ((nbytes_2 = copy_to_outbuf(uniid, buf+nBytes, buflen)) == 0) goto E2big;
176*16d86563SAlexander Pyhalov                      st->keepc[1] = st->keepc[2] = 0;
177*16d86563SAlexander Pyhalov 
178*16d86563SAlexander Pyhalov                      nBytes += nbytes_2;
179*16d86563SAlexander Pyhalov                   }
180*16d86563SAlexander Pyhalov 
181*16d86563SAlexander Pyhalov                 break;
182*16d86563SAlexander Pyhalov 	      case ISC_danda:
183*16d86563SAlexander Pyhalov 		if ( isc_type == DEV && keepc2 == ISC_danda )
184*16d86563SAlexander Pyhalov 		  { /* only in Devanagari script, it works */
185*16d86563SAlexander Pyhalov 		     uniid = UNI_DOUBLE_DANDA;
186*16d86563SAlexander Pyhalov                      if ((nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
187*16d86563SAlexander Pyhalov                      st->keepc[1] = st->keepc[2] = 0;
188*16d86563SAlexander Pyhalov 
189*16d86563SAlexander Pyhalov 		     break;
190*16d86563SAlexander Pyhalov 		  }
191*16d86563SAlexander Pyhalov 
192*16d86563SAlexander Pyhalov 		/* fall into default case, convert the DANDA if it isn't DOUBLE_DANDA */
193*16d86563SAlexander Pyhalov 		/* FALLTHRU */
194*16d86563SAlexander Pyhalov 	      default:
195*16d86563SAlexander Pyhalov 
196*16d86563SAlexander Pyhalov 		uniid = traverse_table(en.entry, en.items, keepc1);
197*16d86563SAlexander Pyhalov 
198*16d86563SAlexander Pyhalov                 if ( have_nukta(isc_type) &&  keepc2 == ISC_nukta) {
199*16d86563SAlexander Pyhalov 		    /* then try to test whether it is Nukta Cases */
200*16d86563SAlexander Pyhalov                     int    ucs;
201*16d86563SAlexander Pyhalov 
202*16d86563SAlexander Pyhalov                     if (( ucs = get_nukta(keepc1, isc_type)) != 0 ) {
203*16d86563SAlexander Pyhalov 
204*16d86563SAlexander Pyhalov                        uniid = ucs;
205*16d86563SAlexander Pyhalov 
206*16d86563SAlexander Pyhalov                        if ( (nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
207*16d86563SAlexander Pyhalov                        st->keepc[1] = st->keepc[2] = 0;
208*16d86563SAlexander Pyhalov                     } else {
209*16d86563SAlexander Pyhalov                        if ( (nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
210*16d86563SAlexander Pyhalov                        st->keepc[1] = st->keepc[2];
211*16d86563SAlexander Pyhalov                     }
212*16d86563SAlexander Pyhalov                 } else {
213*16d86563SAlexander Pyhalov                     if ( (nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
214*16d86563SAlexander Pyhalov                     st->keepc[1] = st->keepc[2];
215*16d86563SAlexander Pyhalov                 }
216*16d86563SAlexander Pyhalov 		break;
217*16d86563SAlexander Pyhalov 	     } /* end of switch */
218*16d86563SAlexander Pyhalov         } else { /* ASCII */
219*16d86563SAlexander Pyhalov             uniid = keepc1;
220*16d86563SAlexander Pyhalov             if ( (nBytes = copy_to_outbuf(uniid, buf, buflen)) == 0) goto E2big;
221*16d86563SAlexander Pyhalov             st->keepc[1] = st->keepc[2];
222*16d86563SAlexander Pyhalov         }
223*16d86563SAlexander Pyhalov         st->keepc[2] = 0;
224*16d86563SAlexander Pyhalov     }
225*16d86563SAlexander Pyhalov 
226*16d86563SAlexander Pyhalov E2big:
227*16d86563SAlexander Pyhalov     return nBytes;
228*16d86563SAlexander Pyhalov }
229*16d86563SAlexander Pyhalov 
230*16d86563SAlexander Pyhalov static int
copy_to_outbuf(ucs_t uniid,char * buf,size_t buflen)231*16d86563SAlexander Pyhalov copy_to_outbuf(ucs_t uniid, char *buf, size_t buflen)
232*16d86563SAlexander Pyhalov {
233*16d86563SAlexander Pyhalov     if (uniid > 0) {
234*16d86563SAlexander Pyhalov         if (uniid <= 0x7f) {
235*16d86563SAlexander Pyhalov             if (buflen < 1) {
236*16d86563SAlexander Pyhalov                 errno = E2BIG;
237*16d86563SAlexander Pyhalov                 return(0);
238*16d86563SAlexander Pyhalov             }
239*16d86563SAlexander Pyhalov             UTF8_SET1B(buf, uniid);
240*16d86563SAlexander Pyhalov             return (1);
241*16d86563SAlexander Pyhalov         }
242*16d86563SAlexander Pyhalov 
243*16d86563SAlexander Pyhalov         if (uniid >= 0x80 && uniid <= 0x7ff) {
244*16d86563SAlexander Pyhalov             if (buflen < 2) {
245*16d86563SAlexander Pyhalov                 errno = E2BIG;
246*16d86563SAlexander Pyhalov                 return(0);
247*16d86563SAlexander Pyhalov             }
248*16d86563SAlexander Pyhalov             UTF8_SET2B(buf, uniid);
249*16d86563SAlexander Pyhalov             return (2);
250*16d86563SAlexander Pyhalov         }
251*16d86563SAlexander Pyhalov 
252*16d86563SAlexander Pyhalov         if (uniid >= 0x800 && uniid <= 0xffff) {
253*16d86563SAlexander Pyhalov             if (buflen < 3) {
254*16d86563SAlexander Pyhalov                 errno = E2BIG;
255*16d86563SAlexander Pyhalov                 return(0);
256*16d86563SAlexander Pyhalov             }
257*16d86563SAlexander Pyhalov             UTF8_SET3B(buf, uniid);
258*16d86563SAlexander Pyhalov             return (3);
259*16d86563SAlexander Pyhalov         }
260*16d86563SAlexander Pyhalov     } else { /* Replacement Character */
261*16d86563SAlexander Pyhalov         if ( buflen < 3 ) {
262*16d86563SAlexander Pyhalov             errno = E2BIG;
263*16d86563SAlexander Pyhalov             return 0;
264*16d86563SAlexander Pyhalov         }
265*16d86563SAlexander Pyhalov 
266*16d86563SAlexander Pyhalov         *buf = (char)REPLACE_CHAR1;
267*16d86563SAlexander Pyhalov         *(buf+1) = (char)REPLACE_CHAR2;
268*16d86563SAlexander Pyhalov         *(buf+2) = (char)REPLACE_CHAR3;
269*16d86563SAlexander Pyhalov         return (3);
270*16d86563SAlexander Pyhalov     }
271*16d86563SAlexander Pyhalov 
272*16d86563SAlexander Pyhalov     /* This code shouldn't be reached */
273*16d86563SAlexander Pyhalov     return (0);
274*16d86563SAlexander Pyhalov }
275*16d86563SAlexander Pyhalov 
276*16d86563SAlexander Pyhalov /*
277*16d86563SAlexander Pyhalov  * Open; called from iconv_open()
278*16d86563SAlexander Pyhalov  */
279*16d86563SAlexander Pyhalov void *
_icv_open()280*16d86563SAlexander Pyhalov _icv_open()
281*16d86563SAlexander Pyhalov {
282*16d86563SAlexander Pyhalov     _iconv_st *st;
283*16d86563SAlexander Pyhalov 
284*16d86563SAlexander Pyhalov     if ((st = (_iconv_st*)malloc(sizeof(_iconv_st))) == NULL) {
285*16d86563SAlexander Pyhalov         errno = ENOMEM;
286*16d86563SAlexander Pyhalov         return ((void*)-1);
287*16d86563SAlexander Pyhalov     }
288*16d86563SAlexander Pyhalov 
289*16d86563SAlexander Pyhalov     bzero(st, sizeof(_iconv_st));
290*16d86563SAlexander Pyhalov     st->keepc[0] = DEV_ATR;
291*16d86563SAlexander Pyhalov     st->pState = S_BASIC;
292*16d86563SAlexander Pyhalov 
293*16d86563SAlexander Pyhalov     return ((void*)st);
294*16d86563SAlexander Pyhalov }
295*16d86563SAlexander Pyhalov 
296*16d86563SAlexander Pyhalov /*
297*16d86563SAlexander Pyhalov  * Close; called from iconv_close()
298*16d86563SAlexander Pyhalov  */
299*16d86563SAlexander Pyhalov void
_icv_close(_iconv_st * st)300*16d86563SAlexander Pyhalov _icv_close(_iconv_st *st)
301*16d86563SAlexander Pyhalov {
302*16d86563SAlexander Pyhalov     if (!st)
303*16d86563SAlexander Pyhalov         errno = EBADF;
304*16d86563SAlexander Pyhalov     else
305*16d86563SAlexander Pyhalov         free(st);
306*16d86563SAlexander Pyhalov }
307*16d86563SAlexander Pyhalov 
308*16d86563SAlexander Pyhalov /*
309*16d86563SAlexander Pyhalov  * Conversion routine; called from iconv()
310*16d86563SAlexander Pyhalov  */
311*16d86563SAlexander Pyhalov size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)312*16d86563SAlexander Pyhalov _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
313*16d86563SAlexander Pyhalov        char **outbuf, size_t *outbytesleft)
314*16d86563SAlexander Pyhalov {
315*16d86563SAlexander Pyhalov     int   n;
316*16d86563SAlexander Pyhalov     short curState;
317*16d86563SAlexander Pyhalov 
318*16d86563SAlexander Pyhalov     if (st == NULL) {
319*16d86563SAlexander Pyhalov         errno = EBADF;
320*16d86563SAlexander Pyhalov         return ((size_t) -1);
321*16d86563SAlexander Pyhalov     }
322*16d86563SAlexander Pyhalov 
323*16d86563SAlexander Pyhalov     if (inbuf == NULL || *inbuf == NULL) { /* Reset request */
324*16d86563SAlexander Pyhalov         st->keepc[0] = DEV_ATR;
325*16d86563SAlexander Pyhalov         st->pState = S_BASIC;
326*16d86563SAlexander Pyhalov         st->_errno = 0;
327*16d86563SAlexander Pyhalov         return ((size_t)0);
328*16d86563SAlexander Pyhalov     }
329*16d86563SAlexander Pyhalov 
330*16d86563SAlexander Pyhalov     /* flush if possible */
331*16d86563SAlexander Pyhalov     if ( st->_errno == E2BIG ) {
332*16d86563SAlexander Pyhalov         n = iscii_to_utf8(st, *outbuf, *outbytesleft);
333*16d86563SAlexander Pyhalov         (*outbuf) += n;
334*16d86563SAlexander Pyhalov         (*outbytesleft) -= n;
335*16d86563SAlexander Pyhalov     }
336*16d86563SAlexander Pyhalov 
337*16d86563SAlexander Pyhalov     st->_errno = errno = 0; /* reset internal and external errno */
338*16d86563SAlexander Pyhalov 
339*16d86563SAlexander Pyhalov     /* a state machine for interpreting ISCII code */
340*16d86563SAlexander Pyhalov     while (*inbytesleft > 0 && *outbytesleft > 0) {
341*16d86563SAlexander Pyhalov         unsigned int curChar = (unsigned int)(**inbuf & ONEBYTE);
342*16d86563SAlexander Pyhalov         unsigned int prevChar = (unsigned int)(st->keepc[1] & ONEBYTE);
343*16d86563SAlexander Pyhalov 
344*16d86563SAlexander Pyhalov         if (curChar == ISC_ext)
345*16d86563SAlexander Pyhalov             curState = S_EXT;
346*16d86563SAlexander Pyhalov         else if (curChar == ISC_atr)
347*16d86563SAlexander Pyhalov             curState = S_ATR;
348*16d86563SAlexander Pyhalov         else
349*16d86563SAlexander Pyhalov             curState = S_BASIC;
350*16d86563SAlexander Pyhalov 
351*16d86563SAlexander Pyhalov         switch (curState) {
352*16d86563SAlexander Pyhalov         case S_BASIC:
353*16d86563SAlexander Pyhalov             if (prevChar == 0)
354*16d86563SAlexander Pyhalov                 st->keepc[1] = curChar;
355*16d86563SAlexander Pyhalov             else
356*16d86563SAlexander Pyhalov                 st->keepc[2] = curChar;
357*16d86563SAlexander Pyhalov 
358*16d86563SAlexander Pyhalov             if (st->pState == S_ATR) {
359*16d86563SAlexander Pyhalov                 /* clear the keepc[1], which is part of attribute */
360*16d86563SAlexander Pyhalov                 st->keepc[1] = 0;
361*16d86563SAlexander Pyhalov                 /* change the attribute for Indian Script Fonts */
362*16d86563SAlexander Pyhalov                 if ((curChar >= 0x42) && (curChar <= 0x4b) && curChar != 0x46) {
363*16d86563SAlexander Pyhalov                     st->keepc[0] = curChar;
364*16d86563SAlexander Pyhalov                 }
365*16d86563SAlexander Pyhalov                 /* other attributes such as display attributes would be ignored */
366*16d86563SAlexander Pyhalov             } else { /* Handle Cases and Flush */
367*16d86563SAlexander Pyhalov 
368*16d86563SAlexander Pyhalov                 if ((curChar > 0 && curChar <= 0x7f) || prevChar != 0) {
369*16d86563SAlexander Pyhalov                     n=iscii_to_utf8(st, *outbuf, *outbytesleft);
370*16d86563SAlexander Pyhalov                     if (n > 0) {
371*16d86563SAlexander Pyhalov                         (*outbuf) += n;
372*16d86563SAlexander Pyhalov                         (*outbytesleft) -= n;
373*16d86563SAlexander Pyhalov                     } else   /* don't return immediately, need advance the *inbuf */
374*16d86563SAlexander Pyhalov                          st->_errno = errno;
375*16d86563SAlexander Pyhalov                 }
376*16d86563SAlexander Pyhalov             }
377*16d86563SAlexander Pyhalov             break;
378*16d86563SAlexander Pyhalov         case S_ATR:
379*16d86563SAlexander Pyhalov         case S_EXT: /* Do nothing */
380*16d86563SAlexander Pyhalov             if (st->pState == S_BASIC) { /* Flush */
381*16d86563SAlexander Pyhalov                 if ( st->keepc[1] == 0 )
382*16d86563SAlexander Pyhalov                  {
383*16d86563SAlexander Pyhalov                    if (curState == S_EXT) st->keepc[1] = ISC_ext;
384*16d86563SAlexander Pyhalov                    break;
385*16d86563SAlexander Pyhalov                  }
386*16d86563SAlexander Pyhalov                 n = iscii_to_utf8(st, *outbuf, *outbytesleft);
387*16d86563SAlexander Pyhalov                 if (n > 0) {
388*16d86563SAlexander Pyhalov                     (*outbuf) += n;
389*16d86563SAlexander Pyhalov                     (*outbytesleft) -= n;
390*16d86563SAlexander Pyhalov                 } else /* don't return immediately */
391*16d86563SAlexander Pyhalov                     st->_errno = errno;
392*16d86563SAlexander Pyhalov 
393*16d86563SAlexander Pyhalov                 if (curState == S_EXT) st->keepc[1] = ISC_ext;
394*16d86563SAlexander Pyhalov             } else {
395*16d86563SAlexander Pyhalov                 errno = EILSEQ;
396*16d86563SAlexander Pyhalov                 return (size_t)-1;
397*16d86563SAlexander Pyhalov             }
398*16d86563SAlexander Pyhalov 
399*16d86563SAlexander Pyhalov             break;
400*16d86563SAlexander Pyhalov         default:  /* should never come here */
401*16d86563SAlexander Pyhalov             st->_errno = errno = EILSEQ;
402*16d86563SAlexander Pyhalov             st->pState = S_BASIC;    /* reset state */
403*16d86563SAlexander Pyhalov             break;
404*16d86563SAlexander Pyhalov         }
405*16d86563SAlexander Pyhalov 
406*16d86563SAlexander Pyhalov         st->pState = curState;
407*16d86563SAlexander Pyhalov 
408*16d86563SAlexander Pyhalov         (*inbuf)++;
409*16d86563SAlexander Pyhalov         (*inbytesleft)--;
410*16d86563SAlexander Pyhalov 
411*16d86563SAlexander Pyhalov         if (errno)
412*16d86563SAlexander Pyhalov             return(size_t)-1;
413*16d86563SAlexander Pyhalov     }
414*16d86563SAlexander Pyhalov 
415*16d86563SAlexander Pyhalov     if (*inbytesleft > 0 && *outbytesleft == 0) {
416*16d86563SAlexander Pyhalov         /* in this case, the st->_errno is zero */
417*16d86563SAlexander Pyhalov         errno = E2BIG;
418*16d86563SAlexander Pyhalov         return(size_t)-1;
419*16d86563SAlexander Pyhalov     }
420*16d86563SAlexander Pyhalov 
421*16d86563SAlexander Pyhalov     return (size_t)(*inbytesleft);
422*16d86563SAlexander Pyhalov }
423