xref: /titanic_52/usr/src/lib/iconv_modules/zh/common/zh_TW-big5p%zh_HK.hkscs.c (revision 91e1e26ac6a73ce959289cf7d3d96c4baedbe0b8)
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  */
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  */
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 
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  */
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 
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  */
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