1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright(c) 2001 Sun Microsystems, Inc.
23  * All rights reserved.
24  */
25 #include <stdio.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <strings.h>
29 #include <stdlib.h>
30 #include "ea-iscii.h"
31 
32 #define MSB          0x80
33 #define REPLACE_CHAR '?'
34 
35 typedef enum { SPACE, ASCII, ISCII } CONTEXT;
36 
37 typedef struct _icv_state {
38     CONTEXT context;
39 } _iconv_st;
40 
41 static uchar
traverse_table(Entry * entry,int num,uchar iscii,uchar * type)42 traverse_table(Entry *entry , int num, uchar iscii, uchar *type)
43 {
44     int   i = 0;
45     uchar ea_iscii=0;
46 
47     *type = 0;
48 
49     for ( ; i < num; ++i) {
50         Entry en = entry[i];
51 
52 	if ( iscii < en.iscii ) break;
53 
54         if ( en.count == NUKTA || en.count == MATRA || en.count ==
55              COMBINED_MATRA_NUKTA ) {
56 	     if ( iscii == en.iscii ) {
57                  *type = en.count;
58                  ea_iscii = en.ea_iscii;
59                  break;
60              }
61         } else {
62              if ( iscii >= en.iscii && iscii < en.iscii + en.count ) {
63                  ea_iscii = (iscii - en.iscii) + en.ea_iscii;
64                  break;
65              }
66         }
67     }
68 
69     return ea_iscii;
70 }
71 
72 void *
_icv_open()73 _icv_open()
74 {
75     _iconv_st *st;
76 
77     if ((st = (_iconv_st*)malloc(sizeof(_iconv_st))) == NULL) {
78         errno = ENOMEM;
79         return ((void*)-1);
80     }
81 
82     bzero(st, sizeof(_iconv_st));
83 
84     return ((void*)st);
85 }
86 
87 /*
88  * Close; called from iconv_close()
89  */
90 void
_icv_close(_iconv_st * st)91 _icv_close(_iconv_st *st)
92 {
93     if (!st)
94         errno = EBADF;
95     else
96         free(st);
97 }
98 
99 size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)100 _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
101        char **outbuf, size_t *outbytesleft)
102 {
103     if (st == NULL) {
104         errno = EBADF;
105         return ((size_t) -1);
106     }
107 
108     if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
109         return ((size_t)0);
110     }
111 
112     /* a state machine for interpreting ISCII code */
113     while (*inbytesleft > 0 && *outbytesleft > 0) {
114         uchar c = (uchar)**inbuf;
115 
116         if ( c & MSB ) {
117 
118              uchar type, ea_iscii;
119 
120              if ( st->context != ISCII ) {
121 
122                  if ( st->context != SPACE ) {
123                     /* force to insert ' ' between ASCII and ISCII */
124                     **outbuf = 0x20;
125                     (*outbuf)++;
126                     (*outbytesleft)--;
127                     st->context = SPACE;
128                  }
129 
130                  if ( *outbytesleft < 1 ) {
131                      errno = E2BIG;
132                      /* don't advance */
133                      return (size_t)-1;
134                  }
135 
136                  st->context = ISCII;
137                  **outbuf = LEADING_BYTE;
138                  (*outbuf)++;
139                  (*outbytesleft)--;
140              }
141 
142              if ((ea_iscii = traverse_table(isc_eaiscii_tbl,
143 			sizeof(isc_eaiscii_tbl)/sizeof(Entry), c, &type ))) {
144                  switch ( type ) {
145                  case MATRA:
146                       if ( *outbytesleft < 2 ) {
147                          errno = E2BIG;
148                          return (size_t)-1;
149                       }
150 
151                       **outbuf = FIRST_VOWEL;
152                       *(*outbuf+1) = ea_iscii;
153                       (*outbuf) += 2;
154                       (*outbytesleft) -= 2;
155                       break;
156                  case NUKTA:
157                       if ( *outbytesleft < 2 ) {
158                          errno = E2BIG;
159                          return (size_t)-1;
160                       }
161 
162                       **outbuf = ea_iscii;
163                       *(*outbuf+1) = NUKTA_VALUE;
164                       (*outbuf) += 2;
165                       (*outbytesleft) -= 2;
166                       break;
167                  case COMBINED_MATRA_NUKTA:
168                       if ( *outbytesleft < 3 ) {
169                          errno = E2BIG;
170                          return (size_t)-1;
171                       }
172 
173                       **outbuf = FIRST_VOWEL;
174                       *(*outbuf+1) = ea_iscii;
175                       *(*outbuf+2) = NUKTA_VALUE;
176                       (*outbuf) += 3;
177                       (*outbytesleft) -= 3;
178                       break;
179                  case 0:
180                       if ( *outbytesleft < 1 ) {
181                          errno = E2BIG;
182                          return (size_t)-1;
183                       }
184 
185                       **outbuf = ea_iscii;
186                       (*outbuf)++;
187                       (*outbytesleft)--;
188                       break;
189                  }
190              } else { /* REPLACE_CHAR */
191                  if ( *outbytesleft < 1 ) {
192                     errno = E2BIG;
193                     return (size_t)-1;
194                  }
195 
196                  **outbuf = REPLACE_CHAR;
197                  (*outbuf)++;
198                  (*outbytesleft)--;
199              }
200         } else { /* ASCII */
201              if ( st->context == ISCII && !isspace(c) ) {
202                  /* force to insert ' ' between ASCII and ISCII */
203                  **outbuf = 0x20;
204                  (*outbuf)++;
205                  (*outbytesleft)--;
206                  st->context = SPACE;
207              }
208 
209              if ( *outbytesleft < 1 ) {
210                 errno = E2BIG;
211                 return (size_t)-1;
212              }
213 
214              **outbuf = c;
215              (*outbuf)++;
216              (*outbytesleft)--;
217 
218              st->context = ASCII;
219              if ( isspace(c) )
220                   st->context = SPACE;
221         }
222 
223         (*inbuf)++;
224         (*inbytesleft)--;
225     }
226 
227     if ( *inbytesleft > 0 && *outbytesleft == 0 ) {
228          errno = E2BIG;
229          return ((size_t)-1);
230     }
231 
232     return ((size_t)(*inbytesleft));
233 }
234