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