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) 1997, by Sun Microsystems, Inc.
23  * All rights reserved.
24  */
25 
26 
27 /*
28    Converts From:	ISO2022-CN-EXT encoding.
29    Converts To:		Taiwanese EUC encoding ( CNS11643 )
30  */
31 
32 #include "iso2022-cn.h"
33 #include "gb2312_cns11643.h"
34 
35 
36 /* Forward reference the functions constrained to the scope of this file */
37 static int chinese_to_euc( _iconv_st*, unsigned char**, size_t*, int);
38 static int gb_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft);
39 
40 
41 extern int errno;
42 
43 
44 size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)45 _icv_iconv(_iconv_st *st, char **inbuf, size_t *inbytesleft,
46 				char **outbuf, size_t *outbytesleft)
47 {
48 	return iso2022_icv_iconv(st, inbuf, inbytesleft, (unsigned char**) outbuf, outbytesleft,
49 			chinese_to_euc);
50 }
51 
52 
53 static int
chinese_to_euc(_iconv_st * st,unsigned char ** outbuf,size_t * outbytesleft,int plane_no)54 chinese_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft, int plane_no )
55 {
56 
57 	if ( st->SSfunc == NONE && st->SOcharset == 'A') {	/* GB2312 */
58 	    return gb_to_euc(st, outbuf, outbytesleft);
59 	}
60 
61 	if ( plane_no < 0 )/* Not a CNS character */
62 	    return (1);
63 
64 	if ( plane_no >= 2) {
65 	    if ( *outbytesleft < 4 ){
66 		    st->_errno = errno = E2BIG;
67 		    return (-1);
68 	    }
69 	    /* Output the multi-byte code and plane number */
70 	    *(*outbuf)++ = (unsigned char) MBYTE;
71 	    *(*outbuf)++ = (unsigned char) (PMASK + plane_no);
72 	    (*outbytesleft) -= 2;
73 	}
74 
75 	if ( *outbytesleft < 2 ){ /* Redundant test if SS2 or SS3 character */
76 	    st->_errno = errno = E2BIG;
77 	    return (-1);
78 	}
79 
80 	*(*outbuf)++ = (unsigned char) (st->keepc[0] | MSB);
81 	*(*outbuf)++ = (unsigned char) (st->keepc[1] | MSB);
82 	(*outbytesleft) -= 2;
83 
84 	return (0);
85 }
86 
make_cns(_iconv_st * st,unsigned long cnscode,unsigned char ** outbuf,size_t * outbytesleft)87 static int make_cns(_iconv_st *st, unsigned long cnscode, unsigned char **outbuf, size_t *outbytesleft)
88 {
89 	int plane_no, ret;	/* return buffer size */
90 
91 	ret = (int) (cnscode >> 16);
92 	switch (ret) {
93 	case 0x21:	/* 0x8EA1 - G */
94 	case 0x22:	/* 0x8EA2 - H */
95 	case 0x23:	/* 0x8EA3 - I */
96 	case 0x24:	/* 0x8EA4 - J */
97 	case 0x25:	/* 0x8EA5 - K */
98 	case 0x26:	/* 0x8EA6 - L */
99 	case 0x27:	/* 0x8EA7 - M */
100 	case 0x28:	/* 0x8EA8 - N */
101 	case 0x29:	/* 0x8EA9 - O */
102 	case 0x2a:	/* 0x8EAA - P */
103 	case 0x2b:	/* 0x8EAB - Q */
104 	case 0x2c:	/* 0x8EAC - R */
105 	case 0x2d:	/* 0x8EAD - S */
106 	case 0x2f:	/* 0x8EAF - U */
107 	case 0x30:	/* 0x8EB0 - V */
108 	    plane_no =  ret - 0x20;
109 	    break;
110 	case 0x2e:	/* 0x8EAE - T */
111 	    plane_no = 3;		/* CNS 11643-1992 */
112 	    break;
113 	default:
114 	    st->_errno = errno = EILSEQ;
115 	    return (0);
116 	}
117 
118 	if ( plane_no >= 2) {
119 	    if ( *outbytesleft < 4 ){
120 		st->_errno = errno = E2BIG;
121 		return (-1);
122 	    }
123 	    /* Output the multi-byte code and plane number */
124 	    *(*outbuf)++ = (unsigned char) MBYTE;
125 	    *(*outbuf)++ = (unsigned char) (PMASK + plane_no);
126 	    (*outbytesleft) -= 2;
127 	}
128 
129 	if ( *outbytesleft < 2 ){ /* Redundant test if SS2 or SS3 character */
130 	    st->_errno = errno = E2BIG;
131 	    return (-1);
132 	}
133 
134 	*(*outbuf)++ = (unsigned char) (((cnscode >> 8) & 0xff) | MSB);
135 	*(*outbuf)++ = (unsigned char) ((cnscode & 0xff) | MSB);
136 	(*outbytesleft) -= 2;
137 
138 	return (0);
139 }
140 
141 static int
gb_cns_comp(const void * p1,const void * p2)142 gb_cns_comp(const void *p1, const void *p2)
143 {
144     gb_cns *ptr1 = (gb_cns*) p1, *ptr2 = (gb_cns*) p2;
145     long result = ptr1->gbcode - ptr2->gbcode;
146     return result == 0 ? 0 : result > 0 ? 1 : -1;
147 }
148 
149 static int
gb_to_euc(_iconv_st * st,unsigned char ** outbuf,size_t * outbytesleft)150 gb_to_euc( _iconv_st *st, unsigned char **outbuf, size_t *outbytesleft )
151 {
152 	gb_cns *ptr, key;
153 
154 	key.gbcode = (unsigned long) ((st->keepc[0] | MSB) << 8) + (st->keepc[1] | MSB);
155 	ptr = (gb_cns*) bsearch(&key, gb_cns_tab, BIG5MAX, sizeof(gb_cns), gb_cns_comp);
156 
157 	if ( ptr && ptr->cnscode > 0 )
158 	    return make_cns(st, ptr->cnscode, outbuf, outbytesleft);
159 	else
160 	    return (1);
161 }
162