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) 1994 by Sun Microsystems, Inc.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28
29 #define MSB 0x80
30
31 #define NON_ID_CHAR_BYTE1 0x21 /* non-identified character */
32 #define NON_ID_CHAR_BYTE2 0x75 /* non-identified character */
33
34 #define gbk_2nd_byte(v) ( (v) >= 0x40 && (v) <= 0xfe && (v) != 0x7f )
35 #define gbk4_2nd_byte(v) ( (v) >= 0x30 && (v) <= 0x39 )
36 #define gbk4_3rd_byte(v) ( (v) >= 0x81 && (v) <= 0xfe )
37 #define gbk4_4th_byte(v) gbk4_2nd_byte(v)
38
39 enum _GSTATE { G0, G1, G2, G3, G4};
40
41
42 typedef struct _icv_state {
43 char _lastc;
44 short _gstate;
45 } _iconv_st;
46
47 /*
48 * Open; called from iconv_open()
49 */
50 void *
_icv_open()51 _icv_open()
52 {
53 _iconv_st *st;
54
55 if ((st = (_iconv_st *)malloc(sizeof(_iconv_st))) == NULL) {
56 errno = ENOMEM;
57 return ((void *) -1);
58 }
59
60 st->_gstate = G0;
61 return ((void *)st);
62 }
63
64
65 /*
66 * Close; called from iconv_close()
67 */
68 void
_icv_close(_iconv_st * st)69 _icv_close(_iconv_st *st)
70 {
71 if (st == NULL)
72 errno = EBADF;
73 else
74 free(st);
75 }
76
77
78 /*
79 * Actual conversion; called from iconv()
80 */
81 /*=======================================================================
82 * 30-39
83 * |--------------------------|
84 * +----------------|--------------------+ |
85 * V MSB | MSB ascii | | 81-fe
86 * +-> G0 ------------> G1 ------> G2 -------+ G3------G4
87 * | ascii (~{) ^ MSB | |(~}) 30-39 |
88 * +----+ +----------+ ---------------------
89 *=======================================================================*/
90 size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)91 _icv_iconv(_iconv_st *st, char **inbuf, size_t*inbytesleft,
92 char **outbuf, size_t*outbytesleft)
93 {
94 if (st == NULL) {
95 errno = EBADF;
96 return -1;
97 }
98 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
99 st->_gstate = G0;
100 return 0;
101 }
102
103 errno = 0;
104
105 while (*inbytesleft > 0 && *outbytesleft > 0) {
106 switch (st->_gstate) {
107 case G0:
108 if ( **inbuf & MSB ) {
109 if(*outbytesleft >=2) {
110 **outbuf = '~';
111 *(*outbuf+1) = '{';
112 (*outbuf) += 2, (*outbytesleft) -= 2;
113 st->_lastc = **inbuf;
114 st->_gstate = G1;
115 } else {
116 errno = E2BIG;
117 return (size_t)-1;
118 }
119
120 } else {
121 **outbuf = **inbuf;
122 (*outbuf)++, (*outbytesleft)--;
123 if (**inbuf == '~') {
124 **outbuf = '~';
125 (*outbuf)++, (*outbytesleft)--;
126 }
127 }
128 break;
129 case G1:
130 if ( gbk4_2nd_byte((unsigned char) **inbuf )) {
131 st->_lastc = **inbuf;
132 st->_gstate = G3;
133 } else if ( **inbuf & MSB ) {
134 if(*outbytesleft >=2) {
135 **outbuf = st->_lastc - 0x80;
136 *(*outbuf+1) = **inbuf - 0x80;
137 (*outbuf) += 2, (*outbytesleft) -= 2;
138 st->_gstate = G2;
139 } else {
140 errno = E2BIG;
141 return (size_t)-1;
142 }
143 } else if ( gbk_2nd_byte((unsigned char ) **inbuf )) {
144 if ( *outbytesleft >= 2 ) {
145 **outbuf = NON_ID_CHAR_BYTE1;
146 *(*outbuf +1) = NON_ID_CHAR_BYTE2;
147 (*outbuf) += 2, (*outbytesleft) -= 2;
148 st->_gstate = G2;
149 } else {
150 errno = E2BIG;
151 return (size_t)-1;
152 }
153 } else {
154 errno = EILSEQ;
155 return (size_t)-1;
156 }
157 break;
158 case G2:
159 if ( **inbuf & MSB ) {
160 st->_lastc = **inbuf;
161 st->_gstate = G1;
162 } else {
163 if(*outbytesleft >=3) {
164 **outbuf = '~';
165 *(*outbuf+1) = '}';
166 *(*outbuf+2) = **inbuf;
167 (*outbuf) += 3, (*outbytesleft) -= 3;
168 st->_gstate = G0;
169 }else {
170 errno = E2BIG;
171 return (size_t)-1;
172 }
173
174 }
175 break;
176 case G3:
177 if ( gbk4_3rd_byte( (unsigned char)**inbuf )) {
178 st->_lastc = **inbuf;
179 st->_gstate = G4;
180 } else {
181 errno = EILSEQ;
182 return (size_t)-1;
183 }
184 break;
185 case G4:
186 if ( gbk4_4th_byte( (unsigned char) **inbuf )) {
187 if ( *outbytesleft >= 2 ) {
188 **outbuf = NON_ID_CHAR_BYTE1;
189 *(*outbuf +1) = NON_ID_CHAR_BYTE2;
190 (*outbuf) += 2, (*outbytesleft) -= 2;
191 st->_gstate = G2;
192 } else {
193 errno = E2BIG;
194 return (size_t)-1;
195 }
196 } else {
197 errno = EILSEQ;
198 return (size_t)-1;
199 }
200 break;
201 default:
202 errno = EILSEQ;
203 return (size_t)-1;
204 }
205
206 (*inbuf)++, (*inbytesleft)--;
207 if (errno)
208 return -1;
209 }
210
211 if (st->_gstate != G0 && st->_gstate != G2 && *inbytesleft == 0) {
212 errno = EINVAL;
213 return (size_t)-1;
214 }
215
216 if (*inbytesleft > 0 && *outbytesleft == 0) {
217 errno = E2BIG;
218 return -1;
219 }
220 return (*inbytesleft);
221 }
222