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) 2001 Sun Microsystems, Inc.
23 * All rights reserved.
24 */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <big5hk_gb18030.h>
29
30 #define NON_ID_CHAR '_' /* non-identifier charactor */
31 #define MSB 0x80
32 #define ONEBYTE 0xff
33 #define gbk_4th_byte(v) ( ((v) >= 0x30) && ((v) <= 0x39) )
34
35 typedef struct _icv_state {
36 char keepc[2]; /* maximum # byte of HKSCS charactor */
37 short cstate;
38 int _errno; /* internal errno */
39 } _iconv_st;
40
41 enum _CSTATE { C0, C1 };
42
43 int binsearch(unsigned long x, table_t table[], int n);
44 int hkscs_2nd_byte(char inbuf);
45 int hkscs_to_gbk2k(char keepc[], char *buf, size_t buflen);
46
47 /*
48 * Open; called from iconv_open()
49 */
_icv_open()50 void * _icv_open() {
51 _iconv_st * st;
52
53 if ((st = (_iconv_st *) malloc(sizeof(_iconv_st))) == NULL) {
54 errno = ENOMEM;
55 return ((void *) -1);
56 }
57
58 st->cstate = C0;
59 st->_errno = 0;
60
61 return ((void *) st);
62 }
63
64 /*
65 * Close; called from iconv_close()
66 */
_icv_close(_iconv_st * st)67 void _icv_close(_iconv_st * st) {
68 if (!st)
69 errno = EBADF;
70 else
71 free(st);
72 }
73
74 /*
75 * Actual conversion; called from iconv()
76 */
77
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)78 size_t _icv_iconv(_iconv_st * st, char **inbuf, size_t *inbytesleft,
79 char ** outbuf, size_t *outbytesleft) {
80 int n;
81 if (st == NULL) {
82 errno = EBADF;
83 return ((size_t) -1);
84 }
85
86 if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
87 st->cstate = C0;
88 st->_errno = 0;
89 return ((size_t) 0);
90 }
91
92 errno = st->_errno = 0;
93
94 while (*inbytesleft > 0 && *outbytesleft > 0) {
95 switch (st->cstate) {
96 case C0:
97 if (**inbuf & MSB) { /* hkscs charactor */
98 st->keepc[0] = (**inbuf);
99 st->cstate = C1;
100 } else { /* ASCII */
101 **outbuf = **inbuf;
102 (*outbuf)++;
103 (*outbytesleft)--;
104 }
105 break;
106 case C1: /* hkscs charactor 2nd byte */
107 if (hkscs_2nd_byte(**inbuf) == 0) {
108 st->keepc[1] = (**inbuf);
109 n = hkscs_to_gbk2k(st->keepc, *outbuf, *outbytesleft);
110 if (n > 0) {
111 (*outbuf) += n;
112 (*outbytesleft) -= n;
113
114 st->cstate = C0;
115 } else {
116 st->_errno = errno = E2BIG;
117 }
118 } else { /* illegal input */
119 st->_errno = errno =EILSEQ;
120 }
121 break;
122 default:
123 st->_errno = errno = EILSEQ;
124 st->cstate = C0;
125 break;
126 }
127
128 if (st->_errno) break;
129
130 (*inbuf) ++;
131 (*inbytesleft)--;
132
133 }
134
135 if (errno) return ((size_t) -1);
136
137 if (*inbytesleft == 0 && st->cstate != C0) {
138 errno = EINVAL;
139 return ((size_t) -1);
140 }
141
142 if (*inbytesleft > 0 && *outbytesleft == 0) {
143 errno = E2BIG;
144 return (size_t)-1;
145 }
146
147 return (size_t)(*inbytesleft);
148 }
149
150 /*
151 * Test whether inbuf is a valid character for
152 * 2nd byte of HKSCS charactor:
153 * Return: 0 --- valid HKSCS 2nd byte
154 * 1 --- invalid HKSCS 2nd byte
155 */
hkscs_2nd_byte(inbuf)156 int hkscs_2nd_byte(inbuf)
157 char inbuf;
158 {
159 unsigned int buf = (unsigned int)(inbuf & ONEBYTE);
160
161 if ((buf >= 0x40) && (buf <= 0xfe))
162 return 0;
163 return 1;
164 }
165
166 /*
167 * hkscs_to_gbk2k: Convert hkscs to gbk.
168 * Return: >0 --- converted with enough space in output buffer
169 * =0 --- no space in outbuf
170 */
171
hkscs_to_gbk2k(char keepc[],char * buf,size_t buflen)172 int hkscs_to_gbk2k(char keepc[], char *buf, size_t buflen) {
173
174 unsigned long gbk_val;
175 int index, len;
176 unsigned long hkscs_val;
177
178 if (buflen < 2) {
179 errno = E2BIG;
180 return 0;
181 }
182
183 hkscs_val = ((keepc[0] & ONEBYTE) << 8) + (keepc[1] & ONEBYTE);
184 index = binsearch(hkscs_val, hkscs_gbk2k_tab, MAX_HKSCS_NUM);
185 if (index >= 0) {
186 char c;
187
188 gbk_val = hkscs_gbk2k_tab[index].value;
189 c = gbk_val & ONEBYTE;
190 if ( gbk_4th_byte( (unsigned char)c ) ) {
191
192 if ( buflen < 4 ) {
193 errno = E2BIG;
194 return 0;
195 }
196
197 *buf = ( gbk_val >> 24) & ONEBYTE;
198 *(buf + 1) = (gbk_val >> 16) & ONEBYTE;
199 *(buf + 2) = (gbk_val >> 8) & ONEBYTE;
200 *(buf + 3) = c;
201
202 len = 4;
203 } else {
204 *buf = (gbk_val >> 8) & ONEBYTE;
205 *(buf + 1) = c;
206
207 len = 2;
208 }
209 } else {
210 *buf = *(buf + 1) = (char)NON_ID_CHAR;
211 len = 2;
212 }
213 return len;
214 }
215
216 /*
217 * binsearch()
218 */
binsearch(unsigned long x,table_t table[],int n)219 int binsearch(unsigned long x, table_t table[], int n) {
220 int low, high, mid;
221
222 low = 0;
223 high = n - 1;
224 while (low <= high) {
225 mid = (low + high) >> 1;
226 if (x < table[mid].key)
227 high = mid - 1;
228 else if (x > table[mid].key)
229 low = mid + 1;
230 else
231 return mid;
232 }
233 return -1;
234 }
235