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) 1995 by Sun Microsystems, Inc.
23  * All Rights Reserved.
24  */
25 
26 
27 #include <stdio.h>
28 #include <libintl.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include "ktable.h"
32 #include "hangulcode.h"
33 
34 #define MSB 0x80
35 #define	MSB_OFF	0x7f
36 
37 struct _cv_state {
38 	int _st_status;
39 	int _gstate;
40 };
41 
42 enum _GSTATE { _nostate, _g0, _g1};
43 
44 enum SHIFT_STAT {SHIFT_IN, SHIFT_OUT};
45 
46 
47 typedef struct __conv_desc {
48 	char			designated;
49 	enum { ASCII, WANSUNG }	state;
50 } _conv_desc;
51 
52 
53 /****  _ I C V _ O P E N  ****/
54 
_icv_open()55 void* _icv_open()
56 {
57 	_conv_desc* cd = (_conv_desc*)malloc(sizeof(_conv_desc));
58 
59 	if (cd == (_conv_desc*)NULL)
60 	{
61 		errno = ENOMEM;
62 		return((void*)-1);
63 	}
64 
65 	cd->designated = 0;
66 	cd->state = ASCII;
67 
68 	return((void*)cd);
69 }  /* end of int _icv_open(). */
70 
71 
72 /****  _ I C V _ C L O S E  ****/
73 
_icv_close(_conv_desc * cd)74 void _icv_close(_conv_desc* cd)
75 {
76 	if (!cd)
77 		errno = EBADF;
78 	else
79 		free((void*)cd);
80 }  /* end of void _icv_close(_conv_desc*). */
81 
82 
83 /****  _ I C V _ I C O N V  ****/
84 
_icv_iconv(_conv_desc * cd,char ** inbuf,size_t * inbufleft,char ** outbuf,size_t * outbufleft)85 size_t _icv_iconv(_conv_desc* cd, char** inbuf, size_t* inbufleft,
86 			char** outbuf, size_t* outbufleft)
87 {
88 	size_t		ret_val = 0;
89 	unsigned char*	ib;
90 	unsigned char*	ob;
91 	unsigned char*	ibtail;
92 	unsigned char*	obtail;
93 
94 	if (!cd)
95 	{
96 		errno = EBADF;
97 		return((size_t)-1);
98 	}
99 
100 	if (!inbuf || !(*inbuf))
101 	{
102 		if (cd->state == WANSUNG)
103 		{
104 			if (outbufleft && *outbufleft >= 1 && outbuf && *outbuf)
105 			{
106 				**outbuf = SI;
107 				(*outbuf)++;
108 				(*outbufleft)--;
109 			}
110 			else
111 			{
112 				errno = E2BIG;
113 				return((size_t)-1);
114 			}
115 		}
116 
117 		cd->designated = 0;
118 		cd->state = ASCII;
119 		return((size_t)0);
120 	}
121 
122 	ib = (unsigned char*)*inbuf;
123 	ob = (unsigned char*)*outbuf;
124 	ibtail = ib + *inbufleft;
125 	obtail = ob + *outbufleft;
126 
127 	while (ib < ibtail)
128 	{
129 		if (!(*ib & 0x80))		/* 7 bits */
130 		{
131 			if (cd->state == WANSUNG)
132 			{
133 				if (ob >= obtail)
134 				{
135 					errno = E2BIG;
136 					ret_val = (size_t)-1;
137 					break;
138 				}
139 				*ob++ = SI;
140 				cd->state = ASCII;
141 			}
142 			if (ob >= obtail)
143 			{
144 				errno = E2BIG;
145 				ret_val = (size_t)-1;
146 				break;
147 			}
148 			*ob++ = *ib++;
149 		}
150 		else
151 		{
152 			if ((ibtail - ib) < 2)
153 			{
154 				errno = EINVAL;
155 				ret_val = (size_t)-1;
156 				break;
157 			}
158 
159 			if (!cd->designated)
160 			{
161 				if ((obtail - ob) < 4)
162 				{
163 					errno = E2BIG;
164 					ret_val = (size_t)-1;
165 					break;
166 				}
167 				*ob++ = ESC;  *ob++ = '$';
168 				*ob++ = ')'; *ob++ = 'C';
169 				cd->designated = 1;
170 			}
171 			if (cd->state == ASCII)
172 			{
173 				if (ob >= obtail)
174 				{
175 					errno = E2BIG;
176 					ret_val = (size_t)-1;
177 					break;
178 				}
179 				*ob++ = SO;
180 				cd->state = WANSUNG;
181 			}
182 
183 			if ((obtail - ob) < 2)
184 			{
185 				errno = E2BIG;
186 				ret_val = (size_t)-1;
187 				break;
188 			}
189 			*ob++ = *ib++ & 0x7F;
190 			*ob++ = *ib++ & 0x7F;
191 		}
192 	}
193 
194 	*inbuf = (char*)ib;
195 	*inbufleft = ibtail - ib;
196 	*outbuf = (char*)ob;
197 	*outbufleft = obtail - ob;
198 
199 	return(ret_val);
200 }  /* end of size_t _icv_iconv(_conv_desc*, char**, size_t*, char**, size_t*).*/
201 
202 void *
_cv_open()203 _cv_open()
204 {
205 	struct _cv_state *st;
206 
207 	if ((st = (struct _cv_state *)malloc(sizeof(struct _cv_state))) == NULL)
208 		return ((void *)-1);
209 
210 	st->_st_status = SHIFT_IN;
211 	st->_gstate = _nostate;
212 
213 	return (st);
214 }
215 
216 void
_cv_close(struct _cv_state * st)217 _cv_close(struct _cv_state *st)
218 {
219 	free(st);
220 }
221 
222 
223 size_t
_cv_enconv(struct _cv_state * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)224 _cv_enconv(struct _cv_state *st, char **inbuf, size_t*inbytesleft,
225 				char **outbuf, size_t*outbytesleft)
226 {
227 	if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
228 		if (st->_st_status == SHIFT_OUT && *outbytesleft > 0)
229 		{
230 		    **outbuf = SI;
231 		    (*outbytesleft)--;
232 		    (*outbuf)++;
233 		}
234 		st->_st_status = SHIFT_IN;
235 		st->_gstate = _nostate;
236 		/*
237 		 * Note that no shift sequence is needed for
238 		 * thetarget encoding.
239 		 */
240 		return (0);
241 	}
242 
243 	if ( st->_gstate == _nostate )
244 		st->_gstate = _g0;
245 
246 	while (*inbytesleft > 0 && *outbytesleft > 0) {
247 	    if ( **inbuf & MSB ) {
248 		if (st->_st_status == SHIFT_IN ) {
249 		    if ( st->_gstate == _g0 ) {
250 			/*
251 			 * Check the outbytesleft : enough to hold ESC sequence
252 			 */
253 			if ( *outbytesleft < 4 ) {
254 			    break;
255 			}
256 
257 			st->_gstate = _g1;
258 
259 			**outbuf = ESC;
260 			(*outbuf)++, (*outbytesleft)--;
261 			**outbuf = '$';
262 			(*outbuf)++, (*outbytesleft)--;
263 			**outbuf = ')';
264 			(*outbuf)++, (*outbytesleft)--;
265 			**outbuf = 'C';
266 			(*outbuf)++, (*outbytesleft)--;
267 
268 			if ( *outbytesleft <= 0 )
269 			    break;
270 		    }
271 
272 		    st->_st_status = SHIFT_OUT;
273 		    **outbuf = SO;
274 		    (*outbuf)++, (*outbytesleft)--;
275 
276 		    if ( *outbytesleft <= 0 )
277 			break;
278 		}
279 
280 		**outbuf = **inbuf & MSB_OFF;
281 		(*outbuf)++, (*outbytesleft)--;
282 
283 	    } else {
284 		if (st->_st_status == SHIFT_OUT) {
285 		    st->_st_status = SHIFT_IN;
286 		    **outbuf = SI;
287 		    (*outbuf)++, (*outbytesleft)--;
288 
289 		    if ( *outbytesleft <= 0 )
290 			break;
291 		}
292 
293 		**outbuf = **inbuf;
294                (*outbuf)++, (*outbytesleft)--;
295 
296 	    }
297 
298 	    (*inbuf)++, (*inbytesleft)--;
299 	}
300 	return (*inbytesleft);
301 }
302