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) 1998 Sun Microsystems, Inc.
23 * All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30 #define SI 0x0f
31 #define SO 0x0e
32 #define MSB 0x80
33 #define MSB_OFF 0x7f
34 #define ESC 0x1b
35
36 #define NON_ID_CHAR '_'
37
38 enum _GSTATE { G0, G1, G2, G3 };
39
40 typedef struct _icv_state {
41 char _lastc;
42 short _gstate;
43 } _iconv_st;
44
45
46 int gb_to_iso(char in_byte1, char in_byte2, char *buf, int buflen);
47
48 /*
49 * Open; called from iconv_open()
50 */
51 void *
_icv_open()52 _icv_open()
53 {
54 _iconv_st *st;
55
56 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) {
57 errno = ENOMEM;
58 return ((void *) -1);
59 }
60
61 st->_gstate = G0;
62 return ((void *)st);
63 }
64
65
66 /*
67 * Close; called from iconv_close()
68 */
69 void
_icv_close(_iconv_st * st)70 _icv_close(_iconv_st *st)
71 {
72 if (st == NULL)
73 errno = EBADF;
74 else
75 free(st);
76 }
77
78
79 /*
80 * Actual conversion; called from iconv()
81 *
82 * +----------------------------------+
83 * MSB V MSB ascii MSB | (SO)
84 * +-> G0 ------------> G1 ------> G2 ------------> G3 ----+
85 * | ascii (ESC,SO) ^ MSB | (SI) ^ ascii |
86 * +----+ +----------+ +-------+
87 */
88 size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)89 _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
90 char **outbuf, size_t *outbytesleft)
91 {
92 int n;
93
94 if (st == NULL) {
95 errno = EBADF;
96 return (size_t)-1;
97 }
98 if (inbuf == NULL || *inbuf == NULL) { /* Reset request */
99 if (st->_gstate == G1) {
100 if (outbytesleft && *outbytesleft >= 1
101 && outbuf && *outbuf) {
102 **outbuf = SI;
103 (*outbuf)++;
104 (*outbytesleft)--;
105 } else {
106 errno = E2BIG;
107 return((size_t)-1);
108 }
109 }
110 st->_gstate = G0;
111 return (size_t)0;
112 }
113
114 errno = 0;
115
116 while (*inbytesleft > 0 && *outbytesleft > 0) {
117 switch (st->_gstate) {
118 case G0:
119 if (**inbuf & MSB) {
120 if (*outbytesleft < 5) {
121 errno = E2BIG;
122 return (size_t)-1;
123 }
124 **outbuf = ESC;
125 *(*outbuf+1) = '$';
126 *(*outbuf+2) = ')';
127 *(*outbuf+3) = 'A';
128 *(*outbuf+4) = SO;
129 (*outbuf) += 5, (*outbytesleft) -= 5;
130 st->_lastc = **inbuf;
131 st->_gstate = G1;
132 } else { /* ASCII */
133 **outbuf = **inbuf;
134 (*outbuf)++, (*outbytesleft)--;
135 }
136 break;
137 case G1:
138 if (**inbuf & MSB) {
139 n = gb_to_iso(st->_lastc, **inbuf, *outbuf, *outbytesleft);
140 if (n > 0) {
141 (*outbuf) += n, (*outbytesleft) -= n;
142 st->_gstate = G2;
143 } else {
144 errno = E2BIG;
145 return (size_t)-1;
146 }
147 } else {
148 errno = EILSEQ;
149 }
150 break;
151 case G2:
152 if (**inbuf & MSB) {
153 st->_lastc = **inbuf;
154 st->_gstate = G1;
155 } else {
156 if (*outbytesleft < 2) {
157 errno = E2BIG;
158 return (size_t)-1;
159 }
160 **outbuf = SI;
161 *(*outbuf+1) = **inbuf;
162 (*outbuf) += 2, (*outbytesleft) -= 2;
163 st->_gstate = G3;
164 }
165 break;
166 case G3:
167 if (**inbuf & MSB) {
168 **outbuf = SO;
169 st->_lastc = **inbuf;
170 st->_gstate = G1;
171 } else {
172 **outbuf = **inbuf;
173 }
174 (*outbuf)++, (*outbytesleft)--;
175 break;
176 }
177
178 (*inbuf)++, (*inbytesleft)--;
179 if (errno)
180 return (size_t)-1;
181 }
182
183 if (*inbytesleft > 0 && *outbytesleft == 0) {
184 errno = E2BIG;
185 return (size_t)-1;
186 }
187 return ((size_t)(*inbytesleft));
188 }
189
190
191 /*
192 * return: > 0 - converted with enough space
193 * = 0 - no space in outbuf
194 */
195 int
gb_to_iso(in_byte1,in_byte2,buf,buflen)196 gb_to_iso(in_byte1, in_byte2, buf, buflen)
197 char in_byte1, in_byte2;
198 char *buf;
199 int buflen;
200 {
201 if ( buflen < 2 )
202 return 0;
203 *buf = in_byte1 & MSB_OFF;
204 *(buf+1) = in_byte2 & MSB_OFF;
205 return 2;
206 }
207
208
209 /*
210 * ====================================================================
211 * enconv functions
212 * ====================================================================
213 */
214
215 typedef struct _enconv_st {
216 char _lastc;
217 short _gstate;
218 } _enconv_st;
219
220
221 /*
222 * Open; called from enconv_open()
223 */
224 void *
_cv_open()225 _cv_open()
226 {
227 _enconv_st *st;
228
229 if ((st = (_enconv_st *)malloc(sizeof(_enconv_st))) == NULL) {
230 return ((void *) -1);
231 }
232
233 st->_gstate = G0;
234 return ((void *)st);
235 }
236
237
238 /*
239 * Close; called from enconv_close()
240 */
241 void
_cv_close(_enconv_st * st)242 _cv_close(_enconv_st *st)
243 {
244 if (st != NULL)
245 free(st);
246 }
247
248
249 /*
250 * Actual conversion; called from enconv()
251 *
252 * +----------------------------------+
253 * MSB V MSB ascii MSB | (SO)
254 * +-> G0 ------------> G1 ------> G2 ------------> G3 ----+
255 * | ascii (ESC,SO) ^ MSB | (SI) ^ ascii |
256 * +----+ +----------+ +-------+
257 */
258 size_t
_cv_enconv(_enconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)259 _cv_enconv(_enconv_st *st, char **inbuf, size_t *inbytesleft,
260 char **outbuf, size_t *outbytesleft)
261 {
262 int n;
263
264 if (st == NULL) {
265 return -1;
266 }
267 if (inbuf == NULL || *inbuf == NULL) { /* Reset request */
268 st->_gstate = G0;
269 return 0;
270 }
271
272 while (*inbytesleft > 0 && *outbytesleft > 0) {
273 switch (st->_gstate) {
274 case G0:
275 if (**inbuf & MSB) {
276 if (*outbytesleft < 5) {
277 return (*inbytesleft);
278 }
279 **outbuf = ESC;
280 *(*outbuf+1) = '$';
281 *(*outbuf+2) = ')';
282 *(*outbuf+3) = 'A';
283 *(*outbuf+4) = SO;
284 (*outbuf) += 5, (*outbytesleft) -= 5;
285 st->_lastc = **inbuf;
286 st->_gstate = G1;
287 } else { /* ASCII */
288 **outbuf = **inbuf;
289 (*outbuf)++, (*outbytesleft)--;
290 }
291 break;
292 case G1:
293 if (**inbuf & MSB) {
294 n = gb_to_iso(st->_lastc, **inbuf, *outbuf, *outbytesleft);
295 if (n > 0) {
296 (*outbuf) += n, (*outbytesleft) -= n;
297 st->_gstate = G2;
298 } else {
299 (*inbuf)++, (*inbytesleft)--;
300 return (*inbytesleft);
301 }
302 }
303 break;
304 case G2:
305 if (**inbuf & MSB) {
306 st->_lastc = **inbuf;
307 st->_gstate = G1;
308 } else {
309 if (*outbytesleft < 2) {
310 return (*inbytesleft);
311 }
312 **outbuf = SI;
313 *(*outbuf+1) = **inbuf;
314 (*outbuf) += 2, (*outbytesleft) -= 2;
315 st->_gstate = G3;
316 }
317 break;
318 case G3:
319 if (**inbuf & MSB) {
320 **outbuf = SO;
321 st->_lastc = **inbuf;
322 st->_gstate = G1;
323 } else {
324 **outbuf = **inbuf;
325 }
326 (*outbuf)++, (*outbytesleft)--;
327 break;
328 }
329
330 (*inbuf)++, (*inbytesleft)--;
331 }
332
333 return (*inbytesleft);
334 }
335