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 1997-2004 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <euc.h>
31 #include "japanese.h"
32 #include "jfp_iconv_unicode.h"
33 
34 #ifdef RFC1468_MODE
35 #define	JFP_U2E_ICONV_RFC1468
36 #else
37 #define	JFP_U2E_ICONV
38 #endif
39 #include "jfp_ucs2_to_euc16.h"
40 
41 #define	DEF_SINGLE	'?'
42 
43 /*
44  * struct _cv_state; to keep status
45  */
46 struct _icv_state {
47 	int	_st_cset;
48 };
49 
50 void *
_icv_open(void)51 _icv_open(void)
52 {
53 	struct _icv_state *st;
54 
55 	if ((st = (struct _icv_state *)
56 		malloc(sizeof (struct _icv_state))) == NULL)
57 		return ((void *)-1);
58 
59 	st->_st_cset = CS_0;
60 
61 	return (st);
62 }
63 
64 void
_icv_close(void * cd)65 _icv_close(void *cd)
66 {
67 	if (cd == NULL) {
68 		errno = EBADF;
69 	} else {
70 		free(cd);
71 	}
72 	return;
73 }
74 
75 size_t
_icv_iconv(void * cd,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)76 _icv_iconv(void *cd, char **inbuf, size_t *inbytesleft,
77 				char **outbuf, size_t *outbytesleft)
78 {
79 	unsigned char	ic;
80 	size_t		rv = (size_t)0;
81 	unsigned int	ucs4;
82 	unsigned short	euc16;
83 
84 	struct _icv_state	*st = (struct _icv_state *)cd;
85 	int			cset;
86 
87 	unsigned char	*ip;
88         size_t		ileft;
89 	char		*op;
90         size_t		oleft;
91 
92 	/*
93 	 * If inbuf and/or *inbuf are NULL, reset conversion descriptor
94 	 * and put escape sequence if needed.
95 	 */
96 	if ((inbuf == NULL) || (*inbuf == NULL)) {
97 		if (st->_st_cset != CS_0) {
98 			if ((outbuf != NULL) && (*outbuf != NULL)
99 					&& (outbytesleft != NULL)) {
100 				op = (char *)*outbuf;
101 				oleft = *outbytesleft;
102 				NPUT(ESC, "RESET-SEQ-ESC");
103 				NPUT(SBTOG0_1, "RESET-SEQ-1");
104 				NPUT(F_X0201_RM, "RESET-SEQ-2");
105 				*outbuf = (char *)op;
106 				*outbytesleft = oleft;
107 			}
108 			st->_st_cset = CS_0;
109 		}
110 		return ((size_t)0);
111 	}
112 
113 	cset = st->_st_cset;
114 
115 	ip = (unsigned char *)*inbuf;
116 	ileft = *inbytesleft;
117 	op = *outbuf;
118 	oleft = *outbytesleft;
119 
120 	while (ileft != 0) {
121 		if (utf8_ucs(&ucs4, &ip, &ileft) == (size_t)-1) {
122 			/* errno has been set in utf8_ucs() */
123 			rv = (size_t)-1;
124 			goto ret;
125 		}
126 
127 		if (ucs4 > 0xffff) {
128 			/* non-BMP */
129 			if (cset != CS_0) {
130 				NPUT(ESC, "CS0-SEQ-ESC");
131 				NPUT(SBTOG0_1, "CS0-SEQ-1");
132 				NPUT(F_X0201_RM, "CS0-SEQ-2");
133 				cset = CS_0;
134 			}
135 			ic = (unsigned char)DEF_SINGLE;
136 			NPUT(ic, "DEF for non-BMP(replaced)");
137 		} else {
138 			euc16 = _jfp_ucs2_to_euc16((unsigned short)ucs4);
139 
140 			switch (euc16 & 0x8080) {
141 			case 0x0000:	/* CS0 */
142 				if (cset != CS_0) {
143 					NPUT(ESC, "CS0-SEQ-ESC");
144 					NPUT(SBTOG0_1, "CS0-SEQ-1");
145 					NPUT(F_X0201_RM, "CS0-SEQ-2");
146 					cset = CS_0;
147 				}
148 				ic = (unsigned char)euc16;
149 				NPUT(ic, "CS0-1");
150 				break;
151 			case 0x8080:	/* CS1 */
152 				if (cset != CS_1) {
153 					NPUT(ESC, "CS1-SEQ-ESC");
154 					NPUT(MBTOG0_1, "CS1-SEQ-1");
155 					NPUT(F_X0208_83_90, "CS1-SEQ-2");
156 					cset = CS_1;
157 				}
158 				ic = (unsigned char)((euc16 >> 8) & CMASK);
159 				NPUT(ic, "CS1-1");
160 				ic = (unsigned char)(euc16 & CMASK);
161 				NPUT(ic, "CS1-2");
162 				break;
163 			case 0x0080:	/* CS2 */
164 #ifdef  RFC1468_MODE	/* Substitute JIS X 0208 for JIS X 0201 Katakana */
165 				if (cset != CS_1) {
166 					NPUT(ESC, "CS2-SEQ-ESC(fullsized)");
167 					NPUT(MBTOG0_1, "CS2-SEQ-1(fullsized)");
168 					NPUT(F_X0208_83_90,
169 						"CS2-SEQ-2(fullsized)");
170 					cset = CS_1;
171 				}
172 				euc16 = halfkana2zenkakuj[euc16 - 0xa1];
173 				ic = (unsigned char)((euc16 >> 8) & CMASK);
174 				NPUT(ic, "CS2-1(fullsized)");
175 				ic = (unsigned char)(euc16 & CMASK);
176 				NPUT(ic, "CS2-2(fullsized)");
177 #else   /* ISO-2022-JP.UIOSF */
178 				if (cset != CS_2) {
179 					NPUT(ESC, "CS2-SEQ-ESC");
180 					NPUT(SBTOG0_1, "CS2-SEQ-1");
181 					NPUT(F_X0201_KN, "CS2-SEQ-2");
182 					cset = CS_2;
183 				}
184 				ic = (unsigned char)euc16;
185 				NPUT(ic & CMASK, "CS2-1");
186 #endif  /* RFC1468_MODE */
187 				break;
188 			case 0x8000:	/* CS3 */
189 				if (cset != CS_3) {
190 					NPUT(ESC, "CS3-SEQ-ESC");
191 					NPUT(MBTOG0_1, "CS3-SEQ-1");
192 					NPUT(MBTOG0_2, "CS3-SEQ-2");
193 					NPUT(F_X0212_90, "CS3-SEQ-3");
194 					cset = CS_3;
195 				}
196 				ic = (unsigned char)((euc16 >> 8) & CMASK);
197 				NPUT(ic, "CS3-1");
198 				ic = (unsigned char)(euc16 & CMASK);
199 				NPUT(ic, "CS3-2");
200 				break;
201 			}
202 		}
203 
204 		/*
205 		 * One character successfully converted so update
206 		 * values outside of this function's stack.
207 		 */
208 		*inbuf = (char *)ip;
209 		*inbytesleft = ileft;
210 		*outbuf = op;
211 		*outbytesleft = oleft;
212 
213 		st->_st_cset = cset;
214 	}
215 
216 ret:
217 
218 #if	defined(DEBUG)
219 	if (rv == (size_t)-1) {
220 		fprintf(stderr, "DEBUG: errno=%d: %s\n", errno, debugmsg);
221 	}
222 #endif	/* DEBUG */
223 
224 	/*
225 	 * Return value for successful return is not defined by XPG
226 	 * so return same as *inbytesleft as existing codes do.
227 	 */
228 	return ((rv == (size_t)-1) ? rv : *inbytesleft);
229 }
230