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) 1996 by Sun Microsystems, Inc.
23  */
24 
25 
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <widec.h>
29 #include "common_han.h"
30 #include "euc_utf_api.h"
31 
32 #define	ESC		0x1B
33 #define	SO		0x0E
34 #define	SI		0x0F
35 
36 typedef struct __conv_desc {
37 	enum { NOT_DEFINED_YET, KSC5601 }	designator;
38 	enum { ASCII, HANGUL }	state;
39 } _conv_desc;
40 
41 /****  _ I C V _ O P E N  ****/
42 
_icv_open()43 void* _icv_open()
44 {
45 	_conv_desc* cd = (_conv_desc*)malloc(sizeof(_conv_desc));
46 
47 	if (cd == (_conv_desc*)NULL)
48 	{
49 		errno = ENOMEM;
50 		return((void*)-1);
51 	}
52 
53 	cd->designator = NOT_DEFINED_YET;
54 	cd->state = ASCII;
55 
56 	return((void*)cd);
57 }  /* end of int _icv_open(). */
58 
59 
60 /****  _ I C V _ C L O S E  ****/
61 
_icv_close(_conv_desc * cd)62 void _icv_close(_conv_desc* cd)
63 {
64 	if (!cd)
65 		errno = EBADF;
66 	else
67 		free((void*)cd);
68 }  /* end of void _icv_close(_conv_desc*). */
69 
70 
71 /****  _ I C V _ I C O N V  ****/
72 
_icv_iconv(_conv_desc * cd,char ** inbuf,size_t * inbufleft,char ** outbuf,size_t * outbufleft)73 size_t _icv_iconv(_conv_desc* cd, char** inbuf, size_t* inbufleft,
74 			char** outbuf, size_t* outbufleft)
75 {
76 	size_t		ret_val = 0;
77 	unsigned char*	ib;
78 	unsigned char*	ob;
79 	unsigned char*	ibtail;
80 	unsigned char*	obtail;
81 
82 	if (!cd)
83 	{
84 		errno = EBADF;
85 		return((size_t)-1);
86 	}
87 
88 	if (!inbuf || !(*inbuf))
89 	{
90 		cd->designator = NOT_DEFINED_YET;
91 		cd->state = ASCII;
92 		return((size_t)0);
93 	}
94 
95 	ib = (unsigned char*)*inbuf;
96 	ob = (unsigned char*)*outbuf;
97 	ibtail = ib + *inbufleft;
98 	obtail = ob + *outbufleft;
99 
100 	while (ib < ibtail)
101 	{
102 		if (cd->designator == KSC5601)
103 		{
104 			hcode_type euc_code, utf_code;
105 
106 			if (*ib == SI)
107 			{
108 				cd->state = ASCII;
109 				ib++;
110 				continue;
111 			}
112 			else if (*ib == SO)
113 			{
114 				cd->state = HANGUL;
115 				ib++;
116 				continue;
117 			}
118 			else if ((*ib == ' ' && cd->state == HANGUL) ||
119 				 cd->state == ASCII)
120 			{
121 				if (ob >= obtail)
122 				{
123 					errno = E2BIG;
124 					ret_val = (size_t)-1;
125 					break;
126 				}
127 				*ob++ = *ib++;
128 				continue;
129 			}
130 
131 			/* Pure KS C 5601 Wansung code */
132 			if ((ibtail - ib) < 2)
133 			{
134 				errno = EINVAL;
135 				ret_val = (size_t)-1;
136 				break;
137 			}
138 
139 			if (*ib < 0x21 || *ib > 0x7E || *(ib + 1) < 0x21 ||
140 			    *(ib + 1) == 0x7F)
141 			{
142 				errno = EILSEQ;
143 				ret_val = (size_t)-1;
144 				break;
145 			}
146 
147 			euc_code.code = 0;
148 			euc_code.byte.byte3 = *ib;
149 			euc_code.byte.byte4 = *(ib + 1);
150 			euc_code.wansung.msb1 = 1;
151 			euc_code.wansung.msb2 = 1;
152 
153 			utf_code = _wansung_to_utf8(euc_code);
154 
155 			if (utf_code.code != 0)
156 			{
157 				if ((obtail - ob) < 3)
158 					{
159 						errno = E2BIG;
160 						ret_val = (size_t)-1;
161 						break;
162 					}
163 				/* UTF8 code from 2 bytes is always 3 bytes */
164 				*ob++ = (char)utf_code.byte.byte2;
165 				*ob++ = (char)utf_code.byte.byte3;
166 				*ob++ = (char)utf_code.byte.byte4;
167 			}
168 			else  /* FAILED - this means input char isn't belong to
169 			       *	  input codeset. */
170 			{
171 				errno = EILSEQ;
172 				ret_val = (size_t)-1;
173 				break;
174 			}
175 			ib += 2;
176 
177 		}
178 		else
179 		{
180 			if (*ib == ESC)
181 			{
182 				if ((ibtail - ib) < 4)
183 				{
184 					errno = EINVAL;
185 					ret_val = (size_t)-1;
186 					break;
187 				}
188 
189 				if (*(ib + 1) == '$' && *(ib + 2) == ')' &&
190 				    *(ib + 3) == 'C')
191 				{
192 					cd->designator = KSC5601;
193 					ib += 4;
194 					continue;
195 				}
196 			}
197 
198 			if (ob >= obtail)
199 			{
200 				errno = E2BIG;
201 				ret_val = (size_t)-1;
202 				break;
203 			}
204 			*ob++ = *ib++;
205 		}
206 	}
207 
208 	*inbuf = (char*)ib;
209 	*inbufleft = ibtail - ib;
210 	*outbuf = (char*)ob;
211 	*outbufleft = obtail - ob;
212 
213 	return(ret_val);
214 }  /* end of size_t _icv_iconv(_conv_desc*, char**, size_t*, char**, size_t*).*/
215