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 SI 0x0f
30 #define SO 0x0e
31 #define ESC 0x1b
32 #define MSB 0x80
33
34 #define NON_ID_CHAR '_'
35
36 enum _GSTATE { G0, G1, G2, G3, G4, G5};
37
38
39 typedef struct _icv_state {
40 char _lastc;
41 short _gstate;
42 } _iconv_st;
43
44 int
45 hz2gb(char in_byte1, char in_byte2, char *buf, int buflen);
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 *
83 * ~ { Chinese
84 * +-> G0 -----> G1 ----> G2 ----> G3
85 * | | ascii | ascii |~} |
86 * +----------------------+--------+
87 *=======================================================================*/
88 size_t
_icv_iconv(_iconv_st * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)89 _icv_iconv(_iconv_st *st, char **inbuf, size_t*inbytesleft,
90 char **outbuf, size_t*outbytesleft)
91 {
92 int n;
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 == '~' ) {
109 st->_gstate = G1;
110 } else if (!((**inbuf) & MSB)) { /* ASCII */
111 **outbuf = **inbuf;
112 (*outbuf)++, (*outbytesleft)--;
113 } else {
114 errno = EILSEQ;
115 return (size_t)-1;
116 }
117 break;
118 case G1:
119 if ( **inbuf == '{' ) {
120 st->_gstate = G2;
121 } else if (**inbuf == '~') {
122 **outbuf = '~';
123 (*outbuf)++, (*outbytesleft)--;
124 st->_gstate = G0;
125 } else {
126 errno = EILSEQ;
127 return -1;
128 }
129 break;
130 case G2:
131 if ( **inbuf == '~' ) {
132 st->_gstate = G4;
133 } else {
134 st->_lastc = **inbuf;
135 st->_gstate = G3;
136 }
137 break;
138 case G3:
139 n = hz2gb(st->_lastc, **inbuf, *outbuf, *outbytesleft);
140 if (n > 0) {
141 (*outbuf) += n, (*outbytesleft) -= n;
142 } else {
143 errno = E2BIG;
144 return -1;
145 }
146 st->_gstate = G2;
147 break;
148 case G4:
149 if ( **inbuf == '}' ) {
150 st->_gstate = G0;
151 } else {
152 errno = EILSEQ;
153 return -1;
154 }
155
156 break;
157 }
158
159 (*inbuf)++, (*inbytesleft)--;
160 if (errno)
161 return -1;
162 }
163
164 if ( st->_gstate != G0 && *inbytesleft == 0 ) {
165 errno = EINVAL;
166 return (size_t)-1;
167 }
168
169 if (*inbytesleft > 0 && *outbytesleft == 0) {
170 errno = E2BIG;
171 return -1;
172 }
173 return (*inbytesleft);
174 }
175
176
177 int
hz2gb(in_byte1,in_byte2,buf,buflen)178 hz2gb(in_byte1, in_byte2, buf, buflen)
179 char in_byte1, in_byte2;
180 char *buf;
181 int buflen;
182 {
183
184 if ( buflen < 2 )
185 return 0;
186 *buf = in_byte1 | MSB;
187 *(buf+1) = in_byte2 | MSB;
188 return 2;
189 }
190