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