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