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