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) 1995, by Sun Microsystems, Inc.
23  * All rights reserved.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include "big5_cns11643.h"	/* Big-5 to CNS 11643 mapping table */
30 #include "gb18030_big5.h"	/* GBK to Big-5 mapping table */
31 
32 #ifdef DEBUG
33 #include <sys/fcntl.h>
34 #include <sys/stat.h>
35 #endif
36 
37 #define	MSB	0x80	/* most significant bit */
38 #define	MBYTE	0x8e	/* multi-byte (4 byte character) */
39 #define	PMASK	0xa0	/* plane number mask */
40 #define ONEBYTE	0xff	/* right most byte */
41 #define MSB_OFF 0x7f    /* mask off MSB */
42 
43 #define SI      0x0f    /* shift in */
44 #define SO      0x0e    /* shift out */
45 #define SS2	0x4e	/* SS2 shift out */
46 #define SS3	0x4f	/* ss3 shift out, used so far */
47 #define ESC     0x1b    /* escape */
48 
49 #define gbk4_2nd_byte(v)  ( (v) >= 0x30 && (v) <= 0x39 )
50 #define gbk4_3rd_byte(v)  ( (v) >= 0x81 && (v) <= 0xfe )
51 #define gbk4_4th_byte(v)  gbk4_2nd_byte(v)
52 
53 /* We use plane 0 for GB2312 */
54 
55 static const char plane_char[] = "AGHIJKLMNOPQRSTUV";
56 
57 #define GET_PLANEC(i)   (plane_char[i])
58 
59 #define NON_ID_CHAR_BYTE1 0x21	/* non-identified character */
60 #define NON_ID_CHAR_BYTE2 0x75	/* non-identified character */
61 
62 typedef struct _icv_state {
63 	unsigned char	keepc[2];	/* maximum # byte of Big-5 code */
64 	short	gstate;		/* state machine id (Big-5) */
65 	short	istate;		/* state machine id (ISO) */
66 	short	plane;		/* plane no. */
67 	short	last_plane;	/* last charactor's plane no. */
68 	int	_errno;			/* internal errno */
69 } _iconv_st;
70 
71 enum _CSTATE	{ G0, G1, G2, G3 };
72 enum _ISTATE    { IN, OUT };
73 
74 
75 void get_plane_no_by_big5(_iconv_st * , int * , unsigned long *);
76 int isGB2312Char(_iconv_st * st);
77 int isBIG5Char(_iconv_st * st);
78 int binsearch_gbk_big5(unsigned int gbkcode);
79 int binsearch(unsigned long x, table_t v[], int n);
80 int gb_to_iso(_iconv_st * st, char* buf, int buflen);
81 int isGBK2(_iconv_st * st);
82 int big5_to_iso(_iconv_st * st, int unidx, unsigned long cnscode, char * buf,
83     size_t buflen);
84 
85 
isGBK2(_iconv_st * st)86 int isGBK2(_iconv_st * st) {
87 	unsigned char c0, c1;
88 
89 	c0 = st->keepc[0] & ONEBYTE;
90 	c1 = st->keepc[1] & ONEBYTE;
91 	if	(c0 >= 0x80 && c0 <= 0xfe && \
92 			c1 >= 0x40 && c1 <= 0xfe && \
93 			c1 != 0x7f)
94 		return 1;
95 	st->_errno = EILSEQ;
96 	return 0;
97 }
98 
99 /*
100  * Open; called from iconv_open()
101  */
_icv_open()102 void * _icv_open() {
103 	_iconv_st *st;
104 
105 	if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) {
106 		errno = ENOMEM;
107 		return ((void *) -1);
108 	}
109 
110 	st->gstate = G0;
111 	st->istate = IN;
112 	st->plane = st->last_plane = -1;/* give it an invalid initnumber */
113 	st->_errno = 0;
114 	return ((void *) st);
115 }
116 
117 
118 /*
119  * Close; called from iconv_close()
120  */
_icv_close(_iconv_st * st)121 void _icv_close(_iconv_st *st) {
122 	if (st == NULL)
123 		errno = EBADF;
124 	else
125 		free(st);
126 }
127 
128 
129 /*
130  *Actual conversion; called from iconv()
131  */
132 /*=======================================================
133  *
134  *   State Machine for interpreting GBK code
135  *
136  *=======================================================
137  *
138  *                                  3rd C
139  *                              G2--------> G3
140  *                              ^            |
141  *                        2nd C |      4th C |
142  *                     1st C    |            |
143  *    +--------> G0 ----------> G1           |
144  *    |    ascii |        2nd C |            |
145  *    ^          v              v            V
146  *    +----<-----+-----<--------+-----<------+
147  *
148  *=======================================================*/
149 /*
150  *	GBK2 encoding range:
151  *		High byte: 0x81 - 0xFE
152  *		Low byte:  0x40 - 0x7E, 0x80 - 0xFE
153  *
154  *	GBK4 encoding range:
155  *		The 1st byte: 0x81 - 0xFE
156  *		The 2nd byte: 0x30 - 0x39
157  *		The 3rd byte: 0x81 - 0xFE
158  *		The 4th byte: 0x30 - 0x39
159  *
160  *	We divide the GBK charset into three parts:
161  *	GB2312:
162  *		High byte: 0xb0 - 0xfe
163  *		Low byte: 0xa1 - 0xfe
164  *		Exclusive: 0xd7fa - 0xd8fe
165  *	Big5:
166  *		Plane #1:  0xA140 - 0xC8FE
167  *		Plane #2:  0xC940 - 0xFEFE
168  *	Other:
169  *		Unknow Chinese charactors
170  */
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)171 size_t _icv_iconv(      _iconv_st *st,
172 					char **inbuf,
173 					size_t *inbytesleft,
174 					char **outbuf,
175 					size_t *outbytesleft) {
176 	int	     n, unidx;
177 	unsigned long   cnscode;
178 	if (st == NULL) {
179 		errno = EBADF;
180 		return ((size_t) -1);
181 	}
182 
183 	if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
184 		if (st->gstate == G1) {
185 			if (outbytesleft && *outbytesleft >= 1 &&
186 						outbuf && *outbuf) {
187 				**outbuf = SI;
188 				(*outbuf) ++;
189 				(*outbytesleft) --;
190 			} else {
191 				errno = E2BIG;
192 				return ((size_t)-1);
193 			}
194 		}
195 		st->gstate = G0;
196 		st->istate = IN;
197 		st->plane = 0;
198 		st->last_plane = 0;
199 		st->_errno = 0;
200 		return ((size_t) 0);
201 	}
202 
203 	errno = st->_errno = 0; /* reset internal & external errno */
204 
205 	/*
206 	 *      Automatic machine starts.
207 	 */
208 	while (*inbytesleft > 0 && *outbytesleft > 0) {
209 		switch (st->gstate) {
210 			case G0:	/* beginning with ASCII*/
211 				if (**inbuf & MSB) {
212 					st->keepc[0] = (**inbuf);
213 					st->gstate = G1;
214 				} else {	/* ASCII */
215 					if (st->istate == OUT) {
216 						st->gstate = G0;
217 						st->istate = IN;
218 						if (*outbytesleft >= 2) {
219 							**outbuf = SI;
220 							(*outbuf)++;
221 							(*outbytesleft)--;
222 						} else {
223 							errno = st->_errno = E2BIG;
224 							return(size_t)(-1);
225 						}
226 						st->last_plane = st->plane;
227 					}
228 					**outbuf = **inbuf;
229 					(*outbuf)++;
230 					(*outbytesleft)--;
231 				}
232 				break;
233 			case G1:		/* Chinese characters: 2nd byte */
234 				st->keepc[1] = (**inbuf);
235 				if ( gbk4_2nd_byte((unsigned char)**inbuf) ) {
236 					st->gstate = G2;
237 				} else if (!isGBK2(st)) {
238 					errno = st->_errno;
239 					return (size_t)-1;
240 				} else if (isGB2312Char(st)) {
241 					st->plane = 0;  /* 0 is for GB2312 */
242 					if (st->last_plane == -1 || \
243 							st->plane != st->last_plane) {
244 						if (*outbytesleft < 5) {
245 							errno = st->_errno = E2BIG;
246 							return (size_t)-1;
247 						}
248 						**outbuf = ESC;
249 						*(*outbuf + 1) = '$';
250 						*(*outbuf+2) = ')';
251 						*(*outbuf+3) = 'A';
252 						*(*outbuf+4) = SO;
253 						(*outbuf) += 5;
254 						(*outbytesleft) -= 5;
255 						st->last_plane = st->plane;
256 					} else if (st->istate == IN) {
257 						**outbuf = SO;
258 						(*outbuf) += 1;
259 						(*outbytesleft) -= 1;
260 					}
261 					n = gb_to_iso(st, *outbuf, *outbytesleft);
262 					if (n > 0) {
263 						(*outbuf) += n;
264 						(*outbytesleft) -= n;
265 					} else {
266 						errno = st->_errno;
267 						return (size_t)-1;
268 					}
269 					st->istate = OUT;
270 					st->gstate = G0;
271 				} else if (isBIG5Char(st)) {
272 					get_plane_no_by_big5(st, &unidx, &cnscode);
273 					if (unidx < 0) {	/* legal Big-5; illegal CNS */
274 						goto nonindentify;
275 					}
276 
277 					if (st->last_plane != st->plane) {
278 						switch (st->plane) {
279 							case 1:
280 								if (*outbytesleft < 5) {
281 									st->_errno = errno = E2BIG;
282 									return (size_t)-1;
283 								}
284 								**outbuf = ESC;
285 								*(*outbuf + 1) = '$';
286 								*(*outbuf + 2) = ')';
287 								*(*outbuf + 3) = 'G';
288 								*(*outbuf + 4) = SO;
289 								(*outbuf) += 5;
290 								(*outbytesleft) -= 5;
291 								break;
292 							case 2:
293 								if (*outbytesleft < 6) {
294 									errno = st->_errno = E2BIG;
295 									return (size_t)-1;
296 								}
297 								**outbuf = ESC;
298 								*(*outbuf + 1) = '$';
299 								*(*outbuf + 2) = '*';
300 								*(*outbuf + 3) = 'H';
301 								*(*outbuf + 4) = ESC;
302 								*(*outbuf + 5) = SS2;
303 								(*outbuf) += 6;
304 								(*outbytesleft) -= 6;
305 								break;
306 							case 3:
307 							case 4:
308 							case 5:
309 							case 6:
310 							case 7:
311 							case 8:
312 							case 9:
313 								if (*outbytesleft < 6) {
314 									errno = st->_errno = E2BIG;
315 									return (size_t)-1;
316 								}
317 								**outbuf = ESC;
318 								*(*outbuf + 1) = '$';
319 								*(*outbuf + 2) = '+';
320 								*(*outbuf + 3) = GET_PLANEC(st->plane);
321 								*(*outbuf + 4) = ESC;
322 								*(*outbuf + 5) = SS3;
323 								(*outbuf) += 6;
324 								(*outbytesleft) -= 6;
325 								break;
326 							default:
327 								errno = st->_errno = EILSEQ;
328 								return (size_t)-1;
329 						}
330 						st->last_plane = st->plane;
331 					} else if (st->istate == IN) {
332 						switch (st->plane) {
333 							case 1:
334 								**outbuf = SO;
335 								(*outbuf) ++;
336 								(*outbytesleft)--;
337 								break;
338 							case 2:
339 								if (*outbytesleft >= 2) {
340 									**outbuf = ESC;
341 									*(*outbuf + 1) = SS2;
342 									(*outbuf) += 2;
343 									(*outbytesleft) -= 2;
344 								} else {
345 									errno = st->_errno = E2BIG;
346 									return (size_t)-1;
347 								}
348 								break;
349 							case 3:
350 							case 4:
351 							case 5:
352 							case 6:
353 							case 7:
354 							case 8:
355 							case 9:
356 								if (*outbytesleft >= 2) {
357 									**outbuf = ESC;
358 									*(*outbuf + 1) = SS3;
359 									(*outbuf) += 2;
360 									(*outbytesleft) -= 2;
361 								} else {
362 									errno = st->_errno = E2BIG;
363 									return (size_t)-1;
364 								}
365 								break;
366 							default:
367 								break;
368 						}	/* end of switch */
369 					}
370 					n = big5_to_iso(st, unidx, cnscode,
371 							*outbuf, *outbytesleft);
372 					if (n > 0) {
373 						(*outbuf) += n;
374 						(*outbytesleft) -= n;
375 					} else {
376 						errno = st->_errno;
377 						return(size_t)(-1);
378 					}
379 					st->istate = OUT;
380 					st->gstate = G0;
381 				} else {	/* Neither GB2312 nor Big5 */
382 nonindentify:				st->plane = 0;
383 					if (st->plane != st->last_plane) {
384 						if (*outbytesleft >= 7) {
385 							**outbuf = ESC;
386 							*(*outbuf + 1) = '$';
387 							*(*outbuf + 2) = ')';
388 							*(*outbuf + 3) = 'A';
389 							*(*outbuf + 4) = SO;
390 							(*outbuf) += 5;
391 							(*outbytesleft) -= 5;
392 						} else {
393 							st->_errno = errno = E2BIG;
394 							return (size_t)-1;
395 						}
396 						st->last_plane = st->plane;
397 					} else if (st->istate == IN) {
398 						if (*outbytesleft >= 3) {
399 							**outbuf = SO;
400 							(*outbuf)++;
401 							(*outbytesleft)--;
402 						} else {
403 							st->_errno = errno = E2BIG;
404 							return (size_t)-1;
405 						}
406 					}
407 
408 					if ( *outbytesleft < 2) {
409 						errno = st->_errno = E2BIG;
410 						return (size_t)-1;
411 					}
412 					**outbuf = NON_ID_CHAR_BYTE1;
413 					*(*outbuf + 1) = NON_ID_CHAR_BYTE2;
414 					(*outbuf) += 2;
415 					(*outbytesleft) -= 2;
416 					st->istate = OUT;
417 					st->gstate = G0;
418 					st->_errno = 0;
419 				}
420 				break;
421 			case G2:
422 				if ( gbk4_3rd_byte((unsigned char)**inbuf) ) {
423 					st->gstate = G3;
424 				} else {
425 					errno = st->_errno = EILSEQ;
426 					return (size_t)-1;
427 				}
428 				break;
429 			case G3:
430 				if ( gbk4_4th_byte((unsigned char)**inbuf) ) {
431 					st->plane = 0;
432 					if ( st->plane != st->last_plane ) {
433 						if (*outbytesleft >= 7) {
434 							**outbuf = ESC;
435 							*(*outbuf + 1) = '$';
436 							*(*outbuf + 2) = ')';
437 							*(*outbuf + 3) = 'A';
438 							*(*outbuf + 4) = SO;
439 							(*outbuf) += 5;
440 							(*outbytesleft) -= 5;
441 						} else {
442 							st->_errno = errno = E2BIG;
443 							return (size_t)-1;
444 						}
445 						st->last_plane = st->plane;
446 					} else if (st->istate == IN) {
447 						if (*outbytesleft >= 3) {
448 							**outbuf = SO;
449 							(*outbuf)++;
450 							(*outbytesleft)--;
451 						} else {
452 							st->_errno = errno = E2BIG;
453 							return (size_t)-1;
454 						}
455 					}
456 
457 					if ( *outbytesleft < 2) {
458 						errno = st->_errno = E2BIG;
459 						return (size_t) -1;
460 					}
461 
462 					**outbuf = NON_ID_CHAR_BYTE1;
463 					*(*outbuf + 1) = NON_ID_CHAR_BYTE2;
464 					(*outbuf) += 2;
465 					(*outbytesleft) -= 2;
466 					st->istate = OUT;
467 					st->gstate = G0;
468 					st->_errno = 0;
469 				} else {
470 					errno = st->_errno = EILSEQ;
471 					return (size_t)-1;
472 				}
473 				break;
474 			default:			/* should never come here */
475 				st->_errno = errno = EILSEQ;
476 				st->istate = IN;
477 				st->gstate = G0;	/* reset state */
478 				break;
479 		}
480 
481 		(*inbuf)++;
482 		(*inbytesleft)--;
483 
484 		if (st->_errno) {
485 			break;
486 		}
487 		if (errno)
488 			return (size_t)(-1);
489 	}
490 
491 	if (*inbytesleft == 0 && st->gstate != G0 ) {
492 		errno = EINVAL;
493 		return (size_t)-1;
494 	}
495 
496 	if (*inbytesleft > 0 && *outbytesleft == 0) {
497 		st->_errno = errno = E2BIG;
498 		return (size_t)(-1);
499 	}
500 	return (size_t)(*inbytesleft);
501 }
502 
503 
isGB2312Char(_iconv_st * st)504 int isGB2312Char(_iconv_st * st) {
505 	unsigned char buf1 = (unsigned char) (st->keepc[0] & ONEBYTE);
506 	unsigned char buf2 = (unsigned char) (st->keepc[1] & ONEBYTE);
507 
508 	if (buf2 >= 0xA1 && buf2 <= 0xFE) {
509 		if ((buf1 >= 0xA1 && buf1 <= 0xA9) || \
510 			(buf1 >= 0xB0 && buf1 <= 0xF7))
511 		    return 1;
512 	}
513 	return 0;
514 }
515 
isBIG5Char(_iconv_st * st)516 int isBIG5Char(_iconv_st * st) {
517 	unsigned int gbkcode = \
518 		(unsigned int) (((st->keepc[0] & ONEBYTE) << 8) | \
519 						(st->keepc[1] & ONEBYTE));
520 	unsigned int big5code;
521 	int idx;
522 
523 	if (gbkcode < gbk_big5_tab[0].key || \
524 			gbkcode > gbk_big5_tab[BIG5MAX-1].key) {
525 		return 0;
526 	}
527 	idx = binsearch_gbk_big5(gbkcode);
528 	if (idx < 0)
529 		return 0;
530 	else {
531 		big5code = gbk_big5_tab[idx].value;
532 		st->keepc[0] = (unsigned char)((big5code >> 8) & ONEBYTE);
533 		st->keepc[1] = (unsigned char)(big5code & ONEBYTE);
534 		return 1;
535 	}
536 }
537 
538 /*
539  * Test whether inbuf is a valid character for 2nd byte Big-5 code
540  * Return: = 0 - valid Big-5 2nd byte
541  *	 = 1 - invalid Big-5 2nd byte
542  */
big5_2nd_byte(inbuf)543 int big5_2nd_byte(inbuf)
544 char inbuf;
545 {
546 	unsigned char    buf = (unsigned char) (inbuf & ONEBYTE);
547 
548 	if ((buf >= 0x40) && (buf <= 0x7E))
549 		return (0);
550 	if ((buf >= 0xA1) && (buf <= 0xFE))
551 		return (0);
552 	return(1);
553 }
554 
555 
556 /*
557  * Get plane number by Big-5 code; i.e. plane #1 returns 1, #2 returns 2, etc.
558  * Returns -1 on error conditions
559  *
560  * Since binary search of the Big-5 to CNS table is necessary, might as well
561  * return index and CNS code matching to the unicode.
562  */
get_plane_no_by_big5(_iconv_st * st,int * unidx,unsigned long * cnscode)563 void get_plane_no_by_big5(_iconv_st * st,
564 						int * unidx,
565 						unsigned long * cnscode) {
566 	int	     ret;
567 	unsigned long   big5code;
568 
569 	big5code = (unsigned long) ((st->keepc[0] & ONEBYTE) << 8) + \
570 								(st->keepc[1] & ONEBYTE);
571 	*unidx = binsearch(big5code, big5_cns_tab, MAX_BIG5_NUM);
572 	if ((*unidx) >= 0)
573 		*cnscode = big5_cns_tab[*unidx].value;
574 	else {
575 		return; /* match from Big-5 to CNS not found */
576 	}
577 	ret = (int) (*cnscode >> 16);
578 	switch (ret) {
579 		case 0x21:      /* 0x8EA1 - G */
580 		case 0x22:      /* 0x8EA2 - H */
581 		case 0x23:      /* 0x8EA3 - I */
582 		case 0x24:      /* 0x8EA4 - J */
583 		case 0x25:      /* 0x8EA5 - K */
584 		case 0x26:      /* 0x8EA6 - L */
585 		case 0x27:      /* 0x8EA7 - M */
586 		case 0x28:      /* 0x8EA8 - N */
587 		case 0x29:      /* 0x8EA9 - O */
588 		case 0x2a:      /* 0x8EAA - P */
589 		case 0x2b:      /* 0x8EAB - Q */
590 		case 0x2c:      /* 0x8EAC - R */
591 		case 0x2d:      /* 0x8EAD - S */
592 		case 0x2f:      /* 0x8EAF - U */
593 		case 0x30:      /* 0x8EB0 - V */
594 			st->plane = ret - 0x20; /* so that we can use GET_PLANEC() */
595 			break;
596 		case 0x2e:      /* 0x8EAE - T */
597 			st->plane = 3;	  /* CNS 11643-1992 */
598 			break;
599 		default:
600 			st->_errno = EILSEQ;
601 			return;
602 	}
603 	st->_errno = 0;
604 }
605 
606 
607 /*
608  * Big-5 code --> ISO 2022-7
609  * Return: > 0 - converted with enough space in output buffer
610  *	 = 0 - no space in outbuf
611  */
big5_to_iso(_iconv_st * st,int unidx,unsigned long cnscode,char * buf,size_t buflen)612 int big5_to_iso(_iconv_st * st, int unidx,
613 				unsigned long cnscode,
614 				char * buf, size_t buflen) {
615 	unsigned long   val;	    /* CNS 11643 value */
616 
617 	if (buflen < 2) {
618 		st->_errno = E2BIG;
619 		return 0;
620 	}
621 
622 	if (unidx < 0) {	/* no match from UTF8 to CNS 11643 */
623 		st->_errno = EILSEQ;
624 		return 0;
625 	} else {
626 		val = cnscode & 0xffff;
627 		*buf = (unsigned char)((val & 0xff00) >> 8);
628 		*(buf+1) = (unsigned char)(val & 0xff);
629 	}
630 
631 	return(2);
632 }
633 
634 
635 /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
binsearch(unsigned long x,table_t v[],int n)636 int binsearch(unsigned long x, table_t v[], int n) {
637 	int low, high, mid;
638 
639 	low = 0;
640 	high = n - 1;
641 	while (low <= high) {
642 		mid = (low + high) / 2;
643 		if (x < v[mid].key)
644 			high = mid - 1;
645 		else if (x > v[mid].key)
646 			low = mid + 1;
647 		else    /* found match */
648 			return mid;
649 	}
650 	return (-1);    /* no match */
651 }
652 
653 /* binsearch_gbk_big5: find x in v[0] <= v[1] <= ... <= v[n-1] */
binsearch_gbk_big5(unsigned int c)654 int binsearch_gbk_big5(unsigned int c) {
655 	int low, high, mid;
656 	long gbkcode = (long)(c & 0xFFFF);
657 
658 	low = 0;
659 	high = BIG5MAX - 1;
660 	while (low <= high) {
661 		mid = (low + high) / 2;
662 		if (gbkcode < gbk_big5_tab[mid].key)
663 			high = mid - 1;
664 		else if (gbkcode > gbk_big5_tab[mid].key)
665 			low = mid + 1;
666 		else    /* found match */
667 			return mid;
668 	}
669 	return (-1);    /* no match */
670 }
671 
672 /*
673  * return: > 0 - converted with enough space
674  *	 = 0 - no space in outbuf
675  */
gb_to_iso(_iconv_st * st,char * buf,int buflen)676 int gb_to_iso(_iconv_st * st, char* buf, int buflen) {
677 	if ( buflen < 2 ) {
678 		st->_errno = E2BIG;
679 		return 0;
680 	}
681 	*buf = st->keepc[0] & MSB_OFF;
682 	*(buf+1) = st->keepc[1] & MSB_OFF;
683 	return 2;
684 }
685 
686 #ifdef DEBUG
main(int argc,char ** argv)687 int main(int argc, char ** argv) {
688 	_iconv_st * st;
689 	char *inbuf, *outbuf, *in_tmp, *out_tmp;
690 	size_t inlen, outlen;
691 	int fd, i;
692 	struct stat s;
693 
694 	if (argc < 2) {
695 		exit(-1);
696 	}
697 	if ((fd = open(argv[1], O_RDONLY)) == -1) {
698 		perror("open");
699 		exit(-2);
700 	}
701 	if (fstat(fd, &s) == -1) {
702 		perror("stat");
703 		exit(-2);
704 	}
705 	inlen = s.st_size;
706 	in_tmp = inbuf = (char *)malloc(inlen);
707 	out_tmp = outbuf = (char*)malloc((outlen = inlen * 3));
708 	if (!inbuf || !outbuf) {
709 		perror("malloc");
710 		exit(-1);
711 	}
712 	if (read(fd, inbuf, inlen) != inlen) {
713 		perror("read");
714 		exit(-4);
715 	}
716 	st = _icv_open();
717 	if (st == (_iconv_st *) -1) {
718 		perror("_icv_open");
719 		exit(-3);
720 	}
721 	if (_icv_iconv(st, &inbuf, &inlen, &outbuf, &outlen))
722 		perror("ERROR");
723 	fprintf(stderr, "%d bytes left\n", outlen);
724 	if (write(1, out_tmp, s.st_size * 5 - outlen) == -1) {
725 		perror("write");
726 		exit(-5);
727 	}
728 	free(in_tmp);
729 	free(out_tmp);
730 	close(fd);
731 	_icv_close(st);
732 }
733 #endif
734