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 1994-2003 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <euc.h>
31 #include "japanese.h"
32 
33 
34 /*
35  * struct _cv_state; to keep status
36  */
37 struct _icv_state {
38 	int	_st_cset;
39 	int	_st_cset_sav;
40 };
41 
42 void *
43 _icv_open()
44 {
45 	struct _icv_state *st;
46 
47 	if ((st = (struct _icv_state *)malloc(sizeof (struct _icv_state)))
48 									== NULL)
49 		return ((void *)ERR_RETURN);
50 
51 	st->_st_cset = st->_st_cset_sav = CS_0;
52 
53 	return (st);
54 }
55 
56 void
57 _icv_close(struct _icv_state *st)
58 {
59 	free(st);
60 }
61 
62 size_t
63 _icv_iconv(struct _icv_state *st, char **inbuf, size_t *inbytesleft,
64 				char **outbuf, size_t *outbytesleft)
65 {
66 	int cset;
67 	int stat = ST_INIT;
68 	unsigned char *op;
69 	char *ip, ic;
70 	size_t ileft, oleft;
71 	size_t retval;
72 
73 	/*
74 	 * If inbuf and/or *inbuf are NULL, reset conversion descriptor
75 	 * and put escape sequence if needed.
76 	 */
77 	if ((inbuf == NULL) || (*inbuf == NULL)) {
78 		st->_st_cset_sav = st->_st_cset = CS_0;
79 		return ((size_t)0);
80 	}
81 
82 	cset = st->_st_cset;
83 
84 	ip = *inbuf;
85 	op = (unsigned char *)*outbuf;
86 	ileft = *inbytesleft;
87 	oleft = *outbytesleft;
88 
89 	/*
90 	 * Main loop; basically 1 loop per 1 input byte
91 	 */
92 
93 	while ((int)ileft > 0) {
94 		GET(ic);
95 		if (stat == ST_INIT) {
96 			goto text;
97 		}
98 
99 		/*
100 		 *  Half way of Kanji or ESC sequence
101 		 */
102 		if ((stat == ST_INCS1) || (stat == ST_INCS3)) {
103 			stat = ST_INIT;
104 			PUT(ic | CMSB);
105 			continue;
106 		} else if (stat == ST_ESC) {
107 			if (ic == MBTOG0_1) {
108 				if ((int)ileft > 0) {
109 					stat = ST_MBTOG0_1;
110 					continue;
111 				} else {
112 					UNGET();
113 					UNGET();
114 					errno = EINVAL;
115 					retval = (size_t)ERR_RETURN;
116 					goto ret;
117 				}
118 			} else if (ic == SBTOG0_1) {
119 				if ((int)ileft > 0) {
120 					stat = ST_SBTOG0;
121 					continue;
122 				} else {
123 					UNGET();
124 					UNGET();
125 					errno = EINVAL;
126 					retval = (size_t)ERR_RETURN;
127 					goto ret;
128 				}
129 			} else if (ic == X208REV_1) {
130 				if ((int)ileft > 0) {
131 					stat = ST_208REV_1;
132 					continue;
133 				} else {
134 					UNGET();
135 					UNGET();
136 					errno = EINVAL;
137 					retval = (size_t)ERR_RETURN;
138 					goto ret;
139 				}
140 			} else {
141 				UNGET();
142 				UNGET();
143 				errno = EILSEQ;
144 				retval = (size_t)ERR_RETURN;
145 				goto ret;
146 			}
147 		} else if (stat == ST_MBTOG0_1) {
148 			if ((ic == F_X0208_83_90) || (ic == F_X0208_78)) {
149 				stat = ST_INIT;
150 				st->_st_cset_sav = cset = CS_1;
151 				continue;
152 			} else if (ic == F_X0212_90) {
153 				stat = ST_INIT;
154 				st->_st_cset_sav = cset = CS_3;
155 				continue;
156 			} else if (ic == MBTOG0_2) {
157 				if ((int)ileft > 0) {
158 					stat = ST_MBTOG0_2;
159 					continue;
160 				} else {
161 					UNGET();
162 					UNGET();
163 					UNGET();
164 					errno = EINVAL;
165 					retval = (size_t)ERR_RETURN;
166 					goto ret;
167 				}
168 			} else {
169 				UNGET();
170 				UNGET();
171 				UNGET();
172 				errno = EILSEQ;
173 				retval = (size_t)ERR_RETURN;
174 				goto ret;
175 			}
176 		} else if (stat == ST_MBTOG0_2) {
177 			if ((ic == F_X0208_83_90) || (ic == F_X0208_78)) {
178 				stat = ST_INIT;
179 				st->_st_cset_sav = cset = CS_1;
180 				continue;
181 			} else if (ic == F_X0212_90) {
182 				stat = ST_INIT;
183 				st->_st_cset_sav = cset = CS_3;
184 				continue;
185 			} else {
186 				UNGET();
187 				UNGET();
188 				UNGET();
189 				UNGET();
190 				errno = EILSEQ;
191 				retval = (size_t)ERR_RETURN;
192 				goto ret;
193 			}
194 		} else if (stat == ST_SBTOG0) {
195 			if ((ic == F_ASCII) ||
196 				(ic == F_X0201_RM) ||
197 				(ic == F_ISO646)) {
198 				stat = ST_INIT;
199 				st->_st_cset_sav = cset = CS_0;
200 				continue;
201 			} else if (ic == F_X0201_KN) {
202 				cset = CS_2;
203 				stat = ST_INIT;
204 				continue;
205 			} else {
206 				UNGET();
207 				UNGET();
208 				UNGET();
209 				errno = EILSEQ;
210 				retval = (size_t)ERR_RETURN;
211 				goto ret;
212 			}
213 		} else if (stat == ST_208REV_1) {
214 			if (ic == X208REV_2) {
215 				if ((int)ileft > 0) {
216 					stat = ST_208REV_2;
217 					continue;
218 				} else {
219 					UNGET();
220 					UNGET();
221 					UNGET();
222 					errno = EINVAL;
223 					retval = (size_t)ERR_RETURN;
224 					goto ret;
225 				}
226 			} else {
227 				UNGET();
228 				UNGET();
229 				UNGET();
230 				errno = EILSEQ;
231 				retval = (size_t)ERR_RETURN;
232 				goto ret;
233 			}
234 		} else if (stat == ST_208REV_2) {
235 			if (ic == ESC) {
236 				if ((int)ileft > 0) {
237 					stat = ST_REV_AFT_ESC;
238 					continue;
239 				} else {
240 					UNGET();
241 					UNGET();
242 					UNGET();
243 					UNGET();
244 					errno = EINVAL;
245 					retval = (size_t)ERR_RETURN;
246 					goto ret;
247 				}
248 			} else {
249 				UNGET();
250 				UNGET();
251 				UNGET();
252 				UNGET();
253 				errno = EILSEQ;
254 				retval = (size_t)ERR_RETURN;
255 				goto ret;
256 			}
257 		} else if (stat == ST_REV_AFT_ESC) {
258 			if (ic == MBTOG0_1) {
259 				if ((int)ileft > 0) {
260 					stat = ST_REV_AFT_MBTOG0_1;
261 					continue;
262 				} else {
263 					UNGET();
264 					UNGET();
265 					UNGET();
266 					UNGET();
267 					UNGET();
268 					errno = EINVAL;
269 					retval = (size_t)ERR_RETURN;
270 					goto ret;
271 				}
272 			} else {
273 				UNGET();
274 				UNGET();
275 				UNGET();
276 				UNGET();
277 				UNGET();
278 				errno = EILSEQ;
279 				retval = (size_t)ERR_RETURN;
280 				goto ret;
281 			}
282 		} else if (stat == ST_REV_AFT_MBTOG0_1) {
283 			if (ic == F_X0208_83_90) {
284 				stat = ST_INIT;
285 				st->_st_cset_sav = cset = CS_1;
286 				continue;
287 			} else if (ic == MBTOG0_2) {
288 				if ((int)ileft > 0) {
289 					stat = ST_REV_AFT_MBTOG0_2;
290 					continue;
291 				} else {
292 					UNGET();
293 					UNGET();
294 					UNGET();
295 					UNGET();
296 					UNGET();
297 					UNGET();
298 					errno = EINVAL;
299 					retval = (size_t)ERR_RETURN;
300 					goto ret;
301 				}
302 			} else {
303 				UNGET();
304 				UNGET();
305 				UNGET();
306 				UNGET();
307 				UNGET();
308 				UNGET();
309 				errno = EILSEQ;
310 				retval = (size_t)ERR_RETURN;
311 				goto ret;
312 			}
313 		} else if (stat == ST_REV_AFT_MBTOG0_2) {
314 			if (ic == F_X0208_83_90) {
315 				stat = ST_INIT;
316 				st->_st_cset_sav = cset = CS_1;
317 				continue;
318 			} else {
319 				UNGET();
320 				UNGET();
321 				UNGET();
322 				UNGET();
323 				UNGET();
324 				UNGET();
325 				UNGET();
326 				errno = EILSEQ;
327 				retval = (size_t)ERR_RETURN;
328 				goto ret;
329 			}
330 		}
331 text:
332 		/*
333 		 * Break through chars or ESC sequence
334 		 */
335 		if (ic == ESC) {
336 			if ((int)ileft > 0) {
337 				stat = ST_ESC;
338 				continue;
339 			} else {
340 				UNGET();
341 				errno = EINVAL;
342 				retval = (size_t)ERR_RETURN;
343 				goto ret;
344 			}
345 		} else if (ic == SO) {
346 			cset = CS_2;
347 			stat = ST_INIT;
348 			continue;
349 		} else if (ic == SI) {
350 			cset = st->_st_cset_sav;
351 			stat = ST_INIT;
352 			continue;
353 		}
354 		if (!(ic & CMSB)) {
355 			if (cset == CS_0) {
356 				if (oleft < EUCW0) {
357 					UNGET();
358 					errno = E2BIG;
359 					retval = (size_t)ERR_RETURN;
360 					goto ret;
361 				}
362 				PUT(ic);
363 				continue;
364 			} else if (cset == CS_2) {
365 				if (oleft < (EUCW2 + SEQ_SS)) {
366 					UNGET();
367 					errno = E2BIG;
368 					retval = (size_t)ERR_RETURN;
369 					goto ret;
370 				}
371 				PUT(SS2);
372 				PUT(ic | CMSB);
373 				continue;
374 			} else if (cset == CS_3) {
375 				if ((int)ileft > 0) {
376 					if (oleft < (EUCW3 + SEQ_SS)) {
377 						UNGET();
378 						errno = E2BIG;
379 						retval = (size_t)ERR_RETURN;
380 						goto ret;
381 					}
382 					stat = ST_INCS3;
383 					PUT(SS3);
384 					PUT(ic | CMSB);
385 					continue;
386 				} else {
387 					UNGET();
388 					errno = EINVAL;
389 					retval = (size_t)ERR_RETURN;
390 					goto ret;
391 				}
392 			} else {
393 				if ((int)ileft > 0) {
394 					if (oleft < EUCW1) {
395 						UNGET();
396 						errno = E2BIG;
397 						retval = (size_t)ERR_RETURN;
398 						goto ret;
399 					}
400 					stat = ST_INCS1;
401 					PUT(ic | CMSB);
402 					continue;
403 				} else {
404 					UNGET();
405 					errno = EINVAL;
406 					retval = (size_t)ERR_RETURN;
407 					goto ret;
408 				}
409 			}
410 		} else {
411 			if (oleft < UNKNOWNW) {
412 				UNGET();
413 				errno = E2BIG;
414 				retval = (size_t)ERR_RETURN;
415 				goto ret;
416 			}
417 			PUT(ic);
418 			continue;
419 		}
420 	}
421 	retval = ileft;
422 ret:
423 	*inbuf = ip;
424 	*inbytesleft = ileft;
425 	*outbuf = (char *)op;
426 	*outbytesleft = oleft;
427 	st->_st_cset = cset;
428 
429 	return (retval);
430 }
431