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 #include <stdio.h>
26*16d86563SAlexander Pyhalov #include <errno.h>
27*16d86563SAlexander Pyhalov #include <stdlib.h>
28*16d86563SAlexander Pyhalov #include <strings.h>
29*16d86563SAlexander Pyhalov #include <sys/types.h>
30*16d86563SAlexander Pyhalov #include "iscii.h"
31*16d86563SAlexander Pyhalov #include "common_defs.h"
32*16d86563SAlexander Pyhalov 
33*16d86563SAlexander Pyhalov #define MSB          0x80    /* most significant bit */
34*16d86563SAlexander Pyhalov #define ONEBYTE      0xff    /* right most byte */
35*16d86563SAlexander Pyhalov 
36*16d86563SAlexander Pyhalov #define REPLACE_CHAR '?'
37*16d86563SAlexander Pyhalov 
38*16d86563SAlexander Pyhalov #define utf8_len(Ch) (Ch < 0x80 ? 1 : (Ch  < 0xe0 ? 2 : (Ch < 0xf0 ? 3 : (Ch < 0xf8 ? 4 : (Ch < 0xfc ? 5 : 6)))))
39*16d86563SAlexander Pyhalov 
40*16d86563SAlexander Pyhalov #define analyze_utf8(Ch, Mask, nBytes) \
41*16d86563SAlexander Pyhalov     if (Ch < 128) { \
42*16d86563SAlexander Pyhalov         nBytes = 1; \
43*16d86563SAlexander Pyhalov         Mask = 0x7f; \
44*16d86563SAlexander Pyhalov       } else if ((Ch & 0xe0) == 0xc0) { \
45*16d86563SAlexander Pyhalov         nBytes = 2; \
46*16d86563SAlexander Pyhalov         Mask = 0x1f; \
47*16d86563SAlexander Pyhalov     } else if ((Ch & 0xf0) == 0xe0) { \
48*16d86563SAlexander Pyhalov         nBytes = 3; \
49*16d86563SAlexander Pyhalov         Mask = 0x0f; \
50*16d86563SAlexander Pyhalov     } else if ((Ch & 0xf8) == 0xf0) { \
51*16d86563SAlexander Pyhalov         nBytes = 4; \
52*16d86563SAlexander Pyhalov         Mask = 0x07; \
53*16d86563SAlexander Pyhalov     } else if ((Ch & 0xfc) == 0xf8) { \
54*16d86563SAlexander Pyhalov         nBytes = 5; \
55*16d86563SAlexander Pyhalov         Mask = 0x03; \
56*16d86563SAlexander Pyhalov     } else if ((Ch & 0xfe) == 0xfc) { \
57*16d86563SAlexander Pyhalov         nBytes = 6; \
58*16d86563SAlexander Pyhalov         Mask = 0x01; \
59*16d86563SAlexander Pyhalov     } else \
60*16d86563SAlexander Pyhalov         nBytes = -1;
61*16d86563SAlexander Pyhalov 
62*16d86563SAlexander Pyhalov #define ucs2_from_utf8(mUCS, Ch, Ct, Mask, Len)   \
63*16d86563SAlexander Pyhalov     (mUCS) = (Ch)[0] & (Mask); \
64*16d86563SAlexander Pyhalov     for ((Ct) = 1; (Ct) < (Len); ++(Ct))  { \
65*16d86563SAlexander Pyhalov         if ( ( (Ch)[(Ct)] & 0xc0) != 0x80) { \
66*16d86563SAlexander Pyhalov              (mUCS) = -1; \
67*16d86563SAlexander Pyhalov             break; \
68*16d86563SAlexander Pyhalov         } \
69*16d86563SAlexander Pyhalov         (mUCS) <<= 6; \
70*16d86563SAlexander Pyhalov         (mUCS) |= ((Ch)[(Ct)] & 0x3f); \
71*16d86563SAlexander Pyhalov     } \
72*16d86563SAlexander Pyhalov 
73*16d86563SAlexander Pyhalov 
74*16d86563SAlexander Pyhalov typedef struct _icv_state {
75*16d86563SAlexander Pyhalov     char    aATR;
76*16d86563SAlexander Pyhalov     uchar_t   keepc[4];
77*16d86563SAlexander Pyhalov     int     halant_context; /* preceded by the Halant character or not */
78*16d86563SAlexander Pyhalov     int     _ustate;
79*16d86563SAlexander Pyhalov     int     _errno;
80*16d86563SAlexander Pyhalov } _iconv_st;
81*16d86563SAlexander Pyhalov 
82*16d86563SAlexander Pyhalov enum _CSTATE { U0, U1, U2, U3, U4, U5, U6 };
83*16d86563SAlexander Pyhalov 
84*16d86563SAlexander Pyhalov /*
85*16d86563SAlexander Pyhalov  * Open; called from iconv_open()
86*16d86563SAlexander Pyhalov  */
87*16d86563SAlexander Pyhalov void *
_icv_open()88*16d86563SAlexander Pyhalov _icv_open()
89*16d86563SAlexander Pyhalov {
90*16d86563SAlexander Pyhalov     _iconv_st *st;
91*16d86563SAlexander Pyhalov 
92*16d86563SAlexander Pyhalov     if ((st = (_iconv_st*)malloc(sizeof(_iconv_st))) == NULL) {
93*16d86563SAlexander Pyhalov         errno = ENOMEM;
94*16d86563SAlexander Pyhalov         return ((void*)-1);
95*16d86563SAlexander Pyhalov     }
96*16d86563SAlexander Pyhalov 
97*16d86563SAlexander Pyhalov     bzero(st, sizeof(_iconv_st));
98*16d86563SAlexander Pyhalov     st->aATR = 0x42; /* Devanagiri */
99*16d86563SAlexander Pyhalov 
100*16d86563SAlexander Pyhalov     return ((void*)st);
101*16d86563SAlexander Pyhalov }
102*16d86563SAlexander Pyhalov 
103*16d86563SAlexander Pyhalov typedef enum { t_NONE, t_NUKTA, t_EXT, t_HALANT, t_DOUBLE_DANDA } Type;
104*16d86563SAlexander Pyhalov 
105*16d86563SAlexander Pyhalov static int
traverse_table(Entry * entry,int num,ucs_t ucs,Type * type)106*16d86563SAlexander Pyhalov traverse_table(Entry *entry, int num,  ucs_t ucs, Type *type)
107*16d86563SAlexander Pyhalov {
108*16d86563SAlexander Pyhalov     int i=0;
109*16d86563SAlexander Pyhalov     int retc=0;
110*16d86563SAlexander Pyhalov 
111*16d86563SAlexander Pyhalov     *type = t_NONE;
112*16d86563SAlexander Pyhalov 
113*16d86563SAlexander Pyhalov     for ( ; i < num; ++i ) {
114*16d86563SAlexander Pyhalov         Entry en = entry[i];
115*16d86563SAlexander Pyhalov 
116*16d86563SAlexander Pyhalov         if (en.count == NUKTA || en.count == EXT || en.count == HALANT || en.count == DOUBLE_DANDA) {
117*16d86563SAlexander Pyhalov             if ( ucs < en.ucs ) break;
118*16d86563SAlexander Pyhalov             if ( ucs == en.ucs ) { /* found */
119*16d86563SAlexander Pyhalov 	        if ( en.count == NUKTA ) *type = t_NUKTA;
120*16d86563SAlexander Pyhalov 	        if ( en.count == EXT ) *type = t_EXT;
121*16d86563SAlexander Pyhalov 	        if ( en.count == HALANT ) *type = t_HALANT;
122*16d86563SAlexander Pyhalov 	        if ( en.count == DOUBLE_DANDA ) *type = t_DOUBLE_DANDA;
123*16d86563SAlexander Pyhalov 		retc = en.iscii;
124*16d86563SAlexander Pyhalov                 break;
125*16d86563SAlexander Pyhalov             }
126*16d86563SAlexander Pyhalov         } else {
127*16d86563SAlexander Pyhalov            if ( ucs < en.ucs ) break;
128*16d86563SAlexander Pyhalov            if ( ucs >= en.ucs && ucs < en.ucs + en.count ) {
129*16d86563SAlexander Pyhalov                retc = en.iscii + ( ucs - en.ucs );
130*16d86563SAlexander Pyhalov                break;
131*16d86563SAlexander Pyhalov            }
132*16d86563SAlexander Pyhalov         }
133*16d86563SAlexander Pyhalov     }
134*16d86563SAlexander Pyhalov 
135*16d86563SAlexander Pyhalov     return retc;
136*16d86563SAlexander Pyhalov }
137*16d86563SAlexander Pyhalov 
138*16d86563SAlexander Pyhalov static int
ucs_to_iscii(ucs_t uiid,char ** outbuf,size_t * outbytesleft,int isc_type,int * halant_context)139*16d86563SAlexander Pyhalov ucs_to_iscii(ucs_t uiid, char **outbuf, size_t *outbytesleft, int isc_type, int *halant_context)
140*16d86563SAlexander Pyhalov {
141*16d86563SAlexander Pyhalov     int nBytesRet = 0 ;
142*16d86563SAlexander Pyhalov     Type type = t_NONE;
143*16d86563SAlexander Pyhalov     int iscii;
144*16d86563SAlexander Pyhalov     Entries en = unicode_table[isc_type];
145*16d86563SAlexander Pyhalov 
146*16d86563SAlexander Pyhalov     if ( *outbytesleft == 0 ) {
147*16d86563SAlexander Pyhalov         errno = E2BIG;
148*16d86563SAlexander Pyhalov         return 0;
149*16d86563SAlexander Pyhalov     }
150*16d86563SAlexander Pyhalov 
151*16d86563SAlexander Pyhalov     iscii = traverse_table(en.entry, en.items,  uiid, &type);
152*16d86563SAlexander Pyhalov     if ( iscii == 0 ) {
153*16d86563SAlexander Pyhalov         **outbuf = REPLACE_CHAR;
154*16d86563SAlexander Pyhalov         nBytesRet ++;
155*16d86563SAlexander Pyhalov     } else {
156*16d86563SAlexander Pyhalov         if ( type != t_NONE ) {
157*16d86563SAlexander Pyhalov 
158*16d86563SAlexander Pyhalov             /* buggy code */
159*16d86563SAlexander Pyhalov             if ( *outbytesleft < 2 ) {
160*16d86563SAlexander Pyhalov                 errno = E2BIG;
161*16d86563SAlexander Pyhalov                 return 0;
162*16d86563SAlexander Pyhalov             }
163*16d86563SAlexander Pyhalov 
164*16d86563SAlexander Pyhalov             switch (type)
165*16d86563SAlexander Pyhalov             {
166*16d86563SAlexander Pyhalov               case t_NUKTA:
167*16d86563SAlexander Pyhalov 		**outbuf = (uchar_t) iscii;
168*16d86563SAlexander Pyhalov 		*(*outbuf+1) = ISC_nukta;
169*16d86563SAlexander Pyhalov                 nBytesRet = 2;
170*16d86563SAlexander Pyhalov 
171*16d86563SAlexander Pyhalov 		break;
172*16d86563SAlexander Pyhalov               case t_EXT:
173*16d86563SAlexander Pyhalov                 **outbuf =  ISC_ext;
174*16d86563SAlexander Pyhalov                 *(*outbuf+1) = (uchar_t) iscii;
175*16d86563SAlexander Pyhalov                 nBytesRet = 2;
176*16d86563SAlexander Pyhalov 
177*16d86563SAlexander Pyhalov                 break;
178*16d86563SAlexander Pyhalov               case t_HALANT:
179*16d86563SAlexander Pyhalov                 if ( (uiid == UNI_ZWJ || uiid == UNI_ZWNJ) && *halant_context )
180*16d86563SAlexander Pyhalov                  {
181*16d86563SAlexander Pyhalov                    if ( uiid == UNI_ZWJ ) **outbuf = ISC_nukta; /* soft halant */
182*16d86563SAlexander Pyhalov 		   else **outbuf = ISC_halant; /* explicit halant */
183*16d86563SAlexander Pyhalov 
184*16d86563SAlexander Pyhalov 		   nBytesRet = 1;
185*16d86563SAlexander Pyhalov                  } /* consume the UNI_ZWNJ or UNI_ZWJ if *halant_context is 0 */
186*16d86563SAlexander Pyhalov 
187*16d86563SAlexander Pyhalov                 break;
188*16d86563SAlexander Pyhalov               case t_DOUBLE_DANDA:
189*16d86563SAlexander Pyhalov                 **outbuf =  ISC_danda;
190*16d86563SAlexander Pyhalov                 *(*outbuf+1) = (uchar_t) iscii;
191*16d86563SAlexander Pyhalov                 nBytesRet = 2;
192*16d86563SAlexander Pyhalov                 break;
193*16d86563SAlexander Pyhalov               case t_NONE:
194*16d86563SAlexander Pyhalov                 /* Not reached */
195*16d86563SAlexander Pyhalov                 break;
196*16d86563SAlexander Pyhalov             }
197*16d86563SAlexander Pyhalov         } else {
198*16d86563SAlexander Pyhalov             **outbuf = (uchar_t) iscii;
199*16d86563SAlexander Pyhalov             nBytesRet = 1;
200*16d86563SAlexander Pyhalov         }
201*16d86563SAlexander Pyhalov     }
202*16d86563SAlexander Pyhalov 
203*16d86563SAlexander Pyhalov     /* if iscii == ISC_halant but type == t_HALANT, set *halant_context to 0 */
204*16d86563SAlexander Pyhalov     if ( iscii == ISC_halant && type == t_NONE ) *halant_context = 1;
205*16d86563SAlexander Pyhalov     else *halant_context = 0;
206*16d86563SAlexander Pyhalov 
207*16d86563SAlexander Pyhalov     return nBytesRet;
208*16d86563SAlexander Pyhalov }
209*16d86563SAlexander Pyhalov 
210*16d86563SAlexander Pyhalov /*
211*16d86563SAlexander Pyhalov  * Close; called from iconv_close()
212*16d86563SAlexander Pyhalov  */
213*16d86563SAlexander Pyhalov void
_icv_close(_iconv_st * st)214*16d86563SAlexander Pyhalov _icv_close(_iconv_st *st)
215*16d86563SAlexander Pyhalov {
216*16d86563SAlexander Pyhalov     if (!st)
217*16d86563SAlexander Pyhalov         errno = EBADF;
218*16d86563SAlexander Pyhalov     else
219*16d86563SAlexander Pyhalov         free(st);
220*16d86563SAlexander Pyhalov }
221*16d86563SAlexander Pyhalov 
222*16d86563SAlexander Pyhalov /*
223*16d86563SAlexander Pyhalov  * Conversion routine; called from iconv()
224*16d86563SAlexander Pyhalov  */
225*16d86563SAlexander Pyhalov size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)226*16d86563SAlexander Pyhalov _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
227*16d86563SAlexander Pyhalov        char **outbuf, size_t *outbytesleft)
228*16d86563SAlexander Pyhalov {
229*16d86563SAlexander Pyhalov     int n=0;
230*16d86563SAlexander Pyhalov 
231*16d86563SAlexander Pyhalov     if (st == NULL)    {
232*16d86563SAlexander Pyhalov         errno = EBADF;
233*16d86563SAlexander Pyhalov         return ((size_t) -1);
234*16d86563SAlexander Pyhalov     }
235*16d86563SAlexander Pyhalov 
236*16d86563SAlexander Pyhalov 
237*16d86563SAlexander Pyhalov     if (inbuf == NULL || *inbuf == NULL) {  /* Reset request. */
238*16d86563SAlexander Pyhalov         st->aATR = 0x42; /* Devangiri */
239*16d86563SAlexander Pyhalov         st->_ustate = U0;
240*16d86563SAlexander Pyhalov         st->_errno = 0;
241*16d86563SAlexander Pyhalov         return ((size_t) 0);
242*16d86563SAlexander Pyhalov     }
243*16d86563SAlexander Pyhalov 
244*16d86563SAlexander Pyhalov     st->_errno = errno = 0;
245*16d86563SAlexander Pyhalov 
246*16d86563SAlexander Pyhalov     while (*inbytesleft > 0 && *outbytesleft > 0) {
247*16d86563SAlexander Pyhalov 
248*16d86563SAlexander Pyhalov         uchar_t first_byte;
249*16d86563SAlexander Pyhalov 
250*16d86563SAlexander Pyhalov         switch ( st->_ustate ) {
251*16d86563SAlexander Pyhalov         case U0:
252*16d86563SAlexander Pyhalov             if ((**inbuf & MSB) == 0) {     /* ASCII */
253*16d86563SAlexander Pyhalov                 **outbuf = **inbuf;
254*16d86563SAlexander Pyhalov                 (*outbuf)++; (*outbytesleft)--;
255*16d86563SAlexander Pyhalov             } else if ((**inbuf & 0xe0) == 0xc0) { /* 0xc2..0xdf */
256*16d86563SAlexander Pyhalov 
257*16d86563SAlexander Pyhalov 	        /* invalid sequence if the first byte is either 0xc0 or 0xc1 */
258*16d86563SAlexander Pyhalov 	        if ( number_of_bytes_in_utf8_char[((uchar_t) **inbuf)] == ICV_TYPE_ILLEGAL_CHAR )
259*16d86563SAlexander Pyhalov 		   errno = EILSEQ;
260*16d86563SAlexander Pyhalov 	        else {
261*16d86563SAlexander Pyhalov                    st->_ustate = U1;
262*16d86563SAlexander Pyhalov                    st->keepc[0] = **inbuf;
263*16d86563SAlexander Pyhalov 		}
264*16d86563SAlexander Pyhalov             } else if ((**inbuf & 0xf0) == 0xe0) {
265*16d86563SAlexander Pyhalov                 st->_ustate = U2;
266*16d86563SAlexander Pyhalov                 st->keepc[0] = **inbuf;
267*16d86563SAlexander Pyhalov             } else {
268*16d86563SAlexander Pyhalov 	        /* four bytes of UTF-8 sequences */
269*16d86563SAlexander Pyhalov 	        if ( number_of_bytes_in_utf8_char[((uchar_t) **inbuf)] == ICV_TYPE_ILLEGAL_CHAR )
270*16d86563SAlexander Pyhalov                    errno = EILSEQ;
271*16d86563SAlexander Pyhalov 	        else {
272*16d86563SAlexander Pyhalov 		   st->_ustate = U4;
273*16d86563SAlexander Pyhalov 		   st->keepc[0] = **inbuf;
274*16d86563SAlexander Pyhalov 		}
275*16d86563SAlexander Pyhalov             }
276*16d86563SAlexander Pyhalov             break;
277*16d86563SAlexander Pyhalov         case U1:
278*16d86563SAlexander Pyhalov             if ((**inbuf & 0xc0) == MSB) { /* U+0080 -- U+07FF */
279*16d86563SAlexander Pyhalov                 **outbuf = REPLACE_CHAR;
280*16d86563SAlexander Pyhalov                 (*outbuf)++;
281*16d86563SAlexander Pyhalov                 (*outbytesleft)--;
282*16d86563SAlexander Pyhalov                 st->_ustate = U0;
283*16d86563SAlexander Pyhalov             } else {
284*16d86563SAlexander Pyhalov                 errno = EILSEQ;
285*16d86563SAlexander Pyhalov             }
286*16d86563SAlexander Pyhalov             break;
287*16d86563SAlexander Pyhalov         case U2:
288*16d86563SAlexander Pyhalov 
289*16d86563SAlexander Pyhalov 	    first_byte = st->keepc[0];
290*16d86563SAlexander Pyhalov 
291*16d86563SAlexander Pyhalov 	    /* if the first byte is 0xed, it is illegal sequence if the second
292*16d86563SAlexander Pyhalov 	     * one is between 0xa0 and 0xbf because surrogate section is ill-formed
293*16d86563SAlexander Pyhalov 	     */
294*16d86563SAlexander Pyhalov 	    if (((uchar_t) **inbuf) < valid_min_2nd_byte[first_byte] ||
295*16d86563SAlexander Pyhalov 		((uchar_t) **inbuf) > valid_max_2nd_byte[first_byte] )
296*16d86563SAlexander Pyhalov 	        errno = EILSEQ;
297*16d86563SAlexander Pyhalov             else {
298*16d86563SAlexander Pyhalov                 st->_ustate = U3;
299*16d86563SAlexander Pyhalov                 st->keepc[1] = **inbuf;
300*16d86563SAlexander Pyhalov             }
301*16d86563SAlexander Pyhalov 	    break;
302*16d86563SAlexander Pyhalov         case U3:
303*16d86563SAlexander Pyhalov             if ((**inbuf & 0xc0) == MSB) {
304*16d86563SAlexander Pyhalov                 unsigned char    mChar = st->keepc[0];
305*16d86563SAlexander Pyhalov                 ucs_t    ucsid = 0;
306*16d86563SAlexander Pyhalov                 int     i=0, mask=0, len=0;
307*16d86563SAlexander Pyhalov                 ISCII   isc_type;
308*16d86563SAlexander Pyhalov 
309*16d86563SAlexander Pyhalov                 st->keepc[2] = **inbuf;
310*16d86563SAlexander Pyhalov 
311*16d86563SAlexander Pyhalov                 analyze_utf8(mChar, mask, len);
312*16d86563SAlexander Pyhalov 
313*16d86563SAlexander Pyhalov                 ucs2_from_utf8(ucsid, (char *)&st->keepc[0], i, mask, len);
314*16d86563SAlexander Pyhalov 
315*16d86563SAlexander Pyhalov 	        /* 0xfffe and 0xffff should not be allowed */
316*16d86563SAlexander Pyhalov 	        if ( ucsid == 0xFFFE || ucsid == 0xFFFF )
317*16d86563SAlexander Pyhalov 		  {
318*16d86563SAlexander Pyhalov 		     errno = EILSEQ;
319*16d86563SAlexander Pyhalov 		     break;
320*16d86563SAlexander Pyhalov 		  }
321*16d86563SAlexander Pyhalov 
322*16d86563SAlexander Pyhalov                 get_script_types(ucsid, isc_type);
323*16d86563SAlexander Pyhalov                 if ( isc_type != NUM_ISCII && st->aATR != aTRs[isc_type] ) {
324*16d86563SAlexander Pyhalov                     if ( *outbytesleft < 2 ) {
325*16d86563SAlexander Pyhalov                         errno = E2BIG;
326*16d86563SAlexander Pyhalov                         return (size_t)-1;
327*16d86563SAlexander Pyhalov                     }
328*16d86563SAlexander Pyhalov 
329*16d86563SAlexander Pyhalov                     **outbuf = (uchar_t)ISC_atr;
330*16d86563SAlexander Pyhalov                     (*outbuf)++;
331*16d86563SAlexander Pyhalov                     **outbuf = aTRs[isc_type];
332*16d86563SAlexander Pyhalov                     (*outbuf)++;
333*16d86563SAlexander Pyhalov                     (*outbytesleft)-=2;
334*16d86563SAlexander Pyhalov                     st->aATR = aTRs[isc_type];
335*16d86563SAlexander Pyhalov                 }
336*16d86563SAlexander Pyhalov 
337*16d86563SAlexander Pyhalov                 /* UNI_INV, UNI_ZWJ, UNI_ZWNJ would occur within any India Script as
338*16d86563SAlexander Pyhalov                    Consonant invisible, explicit halant and soft halant */
339*16d86563SAlexander Pyhalov                 if ( ucsid == UNI_INV || ucsid == UNI_ZWNJ || ucsid == UNI_ZWJ )
340*16d86563SAlexander Pyhalov                    isc_type = isc_TYPE[ st->aATR - 0x42 ];
341*16d86563SAlexander Pyhalov 
342*16d86563SAlexander Pyhalov                 if ( isc_type == NUM_ISCII ) {
343*16d86563SAlexander Pyhalov                     if ( *outbytesleft < 1 ) {
344*16d86563SAlexander Pyhalov                         errno = E2BIG;
345*16d86563SAlexander Pyhalov                         return (size_t)-1;
346*16d86563SAlexander Pyhalov                     }
347*16d86563SAlexander Pyhalov 
348*16d86563SAlexander Pyhalov                     **outbuf = REPLACE_CHAR;
349*16d86563SAlexander Pyhalov                     (*outbuf)++;
350*16d86563SAlexander Pyhalov                     (*outbytesleft)--;
351*16d86563SAlexander Pyhalov                 } else {
352*16d86563SAlexander Pyhalov                     n = ucs_to_iscii(ucsid, outbuf, outbytesleft, isc_type, &st->halant_context);
353*16d86563SAlexander Pyhalov                     if ( n > 0 ) {
354*16d86563SAlexander Pyhalov                         (*outbuf) += n;
355*16d86563SAlexander Pyhalov                         (*outbytesleft) -= n;
356*16d86563SAlexander Pyhalov                     } else if ( errno == E2BIG ) {
357*16d86563SAlexander Pyhalov 		        /* n == 0 if the ZWJ or ZWNJ has been consumed without error */
358*16d86563SAlexander Pyhalov                         st->_errno = errno;
359*16d86563SAlexander Pyhalov                         errno = E2BIG;
360*16d86563SAlexander Pyhalov                         return (size_t)-1;
361*16d86563SAlexander Pyhalov                     }
362*16d86563SAlexander Pyhalov                 }
363*16d86563SAlexander Pyhalov             } else {
364*16d86563SAlexander Pyhalov                 errno = EILSEQ;
365*16d86563SAlexander Pyhalov                 return (size_t)-1;
366*16d86563SAlexander Pyhalov             }
367*16d86563SAlexander Pyhalov             st->_ustate = U0;
368*16d86563SAlexander Pyhalov             break;
369*16d86563SAlexander Pyhalov 	case U4:
370*16d86563SAlexander Pyhalov 
371*16d86563SAlexander Pyhalov 	    first_byte = st->keepc[0];
372*16d86563SAlexander Pyhalov 
373*16d86563SAlexander Pyhalov 	    /* if the first byte is 0xf0, it is illegal sequence if
374*16d86563SAlexander Pyhalov 	     * the second one is between 0x80 and 0x8f
375*16d86563SAlexander Pyhalov 	     * for Four-Byte UTF: U+10000..U+10FFFF
376*16d86563SAlexander Pyhalov 	     */
377*16d86563SAlexander Pyhalov 	    if (((uchar_t) **inbuf) < valid_min_2nd_byte[first_byte] ||
378*16d86563SAlexander Pyhalov 		((uchar_t) **inbuf) > valid_max_2nd_byte[first_byte] )
379*16d86563SAlexander Pyhalov 	        errno = EILSEQ;
380*16d86563SAlexander Pyhalov 	    else {
381*16d86563SAlexander Pyhalov 	        st->_ustate = U5;
382*16d86563SAlexander Pyhalov 	        st->keepc[1] = **inbuf;
383*16d86563SAlexander Pyhalov 	    }
384*16d86563SAlexander Pyhalov 	    break;
385*16d86563SAlexander Pyhalov 	case U5:
386*16d86563SAlexander Pyhalov 	    if ((**inbuf & 0xc0) == MSB) /* 0x80..0xbf */
387*16d86563SAlexander Pyhalov 	     {
388*16d86563SAlexander Pyhalov 		st->_ustate = U6;
389*16d86563SAlexander Pyhalov 		st->keepc[2] = **inbuf;
390*16d86563SAlexander Pyhalov 	     }
391*16d86563SAlexander Pyhalov 	    else
392*16d86563SAlexander Pyhalov 	        errno = EILSEQ;
393*16d86563SAlexander Pyhalov 	    break;
394*16d86563SAlexander Pyhalov 	case U6:
395*16d86563SAlexander Pyhalov 	    if ((**inbuf & 0xc0) == MSB) /* 0x80..0xbf */
396*16d86563SAlexander Pyhalov 	     {
397*16d86563SAlexander Pyhalov 		st->keepc[3] = **inbuf;
398*16d86563SAlexander Pyhalov 		st->_ustate = U0;
399*16d86563SAlexander Pyhalov 
400*16d86563SAlexander Pyhalov 		/* replace with REPLACE_CHAR */
401*16d86563SAlexander Pyhalov 		**outbuf = REPLACE_CHAR;
402*16d86563SAlexander Pyhalov                 (*outbuf)++;
403*16d86563SAlexander Pyhalov                 (*outbytesleft)--;
404*16d86563SAlexander Pyhalov 	     }
405*16d86563SAlexander Pyhalov 	    else
406*16d86563SAlexander Pyhalov 	        errno = EILSEQ;
407*16d86563SAlexander Pyhalov 	    break;
408*16d86563SAlexander Pyhalov         }
409*16d86563SAlexander Pyhalov 
410*16d86563SAlexander Pyhalov         if (errno)
411*16d86563SAlexander Pyhalov             break;
412*16d86563SAlexander Pyhalov 
413*16d86563SAlexander Pyhalov         (*inbuf)++;
414*16d86563SAlexander Pyhalov         (*inbytesleft)--;
415*16d86563SAlexander Pyhalov        }    /* end of while loop */
416*16d86563SAlexander Pyhalov 
417*16d86563SAlexander Pyhalov     if (errno) return (size_t) -1;
418*16d86563SAlexander Pyhalov 
419*16d86563SAlexander Pyhalov     if (*inbytesleft == 0 && st->_ustate != U0) {
420*16d86563SAlexander Pyhalov         errno = EINVAL;
421*16d86563SAlexander Pyhalov         return (size_t)-1;
422*16d86563SAlexander Pyhalov     }
423*16d86563SAlexander Pyhalov 
424*16d86563SAlexander Pyhalov     if (*inbytesleft > 0 && *outbytesleft == 0) {
425*16d86563SAlexander Pyhalov         errno = E2BIG;
426*16d86563SAlexander Pyhalov         return((size_t)-1);
427*16d86563SAlexander Pyhalov     }
428*16d86563SAlexander Pyhalov 
429*16d86563SAlexander Pyhalov     return (size_t)(*inbytesleft);
430*16d86563SAlexander Pyhalov }
431