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 
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 	enum { NDY, KSC5601 }	designator;
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->designator = NDY;
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 		cd->designator = NDY;
103 		cd->state = ASCII;
104 		return((size_t)0);
105 	}
106 
107 	ib = (unsigned char*)*inbuf;
108 	ob = (unsigned char*)*outbuf;
109 	ibtail = ib + *inbufleft;
110 	obtail = ob + *outbufleft;
111 
112 	while (ib < ibtail)
113 	{
114 		if (cd->designator == NDY)
115 		{
116 			if (*ib == ESC)
117 			{
118 				if ((ibtail - ib) < 4)
119 				{
120 					errno = EINVAL;
121 					ret_val = (size_t)-1;
122 					break;
123 				}
124 
125 				if (*(ib + 1) == '$' && *(ib + 2) == ')' &&
126 				    *(ib + 3) == 'C')
127 				{
128 					cd->designator = KSC5601;
129 					ib += 4;
130 					continue;
131 				}
132 			}
133 
134 			if (ob >= obtail)
135 			{
136 				errno = E2BIG;
137 				ret_val = (size_t)-1;
138 				break;
139 			}
140 			*ob++ = *ib++;
141 		}
142 		else
143 		{
144 			if (*ib == SI)
145 			{
146 				cd->state = ASCII;
147 				ib++;
148 				continue;
149 			}
150 			else if (*ib == SO)
151 			{
152 				cd->state = WANSUNG;
153 				ib++;
154 				continue;
155 			}
156 			else if ((*ib == ' ' && cd->state == WANSUNG) ||
157 				 cd->state == ASCII)
158 			{
159 				if (ob >= obtail)
160 				{
161 					errno = E2BIG;
162 					ret_val = (size_t)-1;
163 					break;
164 				}
165 				*ob++ = *ib++;
166 				continue;
167 			}
168 
169 			/* Pure KS C 5601 Wansung code */
170 			if ((ibtail - ib) < 2)
171 			{
172 				errno = EINVAL;
173 				ret_val = (size_t)-1;
174 				break;
175 			}
176 
177 			if (*ib < 0x21 || *ib > 0x7D || *(ib + 1) < 0x21 ||
178 			    *(ib + 1) == 0x7F)
179 			{
180 				errno = EILSEQ;
181 				ret_val = (size_t)-1;
182 				break;
183 			}
184 
185 			if ((obtail - ob) < 2)
186 			{
187 				errno = E2BIG;
188 				ret_val = (size_t)-1;
189 				break;
190 			}
191 			*ob++ = *ib++ | 0x80;
192 			*ob++ = *ib++ | 0x80;
193 		}
194 	}
195 
196 	*inbuf = (char*)ib;
197 	*inbufleft = ibtail - ib;
198 	*outbuf = (char*)ob;
199 	*outbufleft = obtail - ob;
200 
201 	return(ret_val);
202 }  /* end of size_t _icv_iconv(_conv_desc*, char**, size_t*, char**, size_t*).*/
203 
204 void *
_cv_open()205 _cv_open()
206 {
207 	struct _cv_state *st;
208 
209 	if ((st = (struct _cv_state *)malloc(sizeof(struct _cv_state))) == NULL)
210 		return ((void *)-1);
211 
212 	st->_st_status = SHIFT_IN;
213 	st->_gstate = _nostate;
214 
215 	return (st);
216 }
217 
218 void
_cv_close(struct _cv_state * st)219 _cv_close(struct _cv_state *st)
220 {
221 	free(st);
222 }
223 
224 
225 size_t
_cv_enconv(struct _cv_state * st,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)226 _cv_enconv(struct _cv_state *st, char **inbuf, size_t*inbytesleft,
227 				char **outbuf, size_t*outbytesleft)
228 {
229 	if (inbuf == NULL || *inbuf == NULL) { /* Reset request. */
230 		st->_st_status = SHIFT_IN;
231 		st->_gstate = _nostate;
232 		/*
233 		 * Note that no shift sequence is needed for
234 		 * the target encoding.
235 		 */
236 		return (0);
237 	}
238 
239 	if ( st->_gstate == _nostate )
240 		st->_gstate = _g0;
241 
242 	while (*inbytesleft > 0 && *outbytesleft > 0) {
243 	    if ( st->_gstate == _g1 ) {
244 		if (**inbuf == SO) {
245 			st->_st_status = SHIFT_OUT;
246 		} else if (**inbuf == SI) {
247 			st->_st_status = SHIFT_IN;
248 		} else {
249 		    if (st->_st_status == SHIFT_OUT) {
250 			while (*inbytesleft > 0 && *outbytesleft > 0 &&
251 							**inbuf != SI ) {
252 			    **outbuf = (**inbuf == ' ') ? ' ' : (MSB | **inbuf);
253 			    (*outbuf)++, (*outbytesleft)--;
254 			    (*inbuf)++, (*inbytesleft)--;
255 			}
256 			continue;
257 		    } else {
258 			**outbuf = **inbuf;
259 			(*outbuf)++, (*outbytesleft)--;
260 		    }
261 		}
262 	    } else {
263 		char	*temp;
264 
265 		temp = *inbuf;
266 
267 		if ( *inbytesleft >= 4 && temp[0] == ESC && temp[1] == '$'
268 				&& temp[2] == ')' && temp[3] == 'C' ) {
269 		    st->_gstate = _g1;
270 		    *inbuf += 4;
271 		    *inbytesleft -= 4;
272 		    continue;
273 		} else {
274 		    **outbuf = **inbuf;
275 		    (*outbuf)++, (*outbytesleft)--;
276 		}
277 	    }
278 
279 	    (*inbuf)++, (*inbytesleft)--;
280 	}
281 	return (*inbytesleft);
282 }
283