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