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 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * This particular file is to cover conversions from UCS-4, UCS-4BE, and
26 * UCS-4LE to UTF-32, UTF-32BE, and UTF-32LE.
27 */
28
29
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/isa_defs.h>
34
35 /* We include the ucs4_to_ucs.h at the moment. */
36 #include "ucs4_to_ucs.h"
37
38
39 void *
_icv_open()40 _icv_open()
41 {
42 ucs_ucs_state_t *cd;
43
44 cd = (ucs_ucs_state_t *)calloc(1, sizeof(ucs_ucs_state_t));
45 if (cd == (ucs_ucs_state_t *)NULL) {
46 errno = ENOMEM;
47 return((void *)-1);
48 }
49
50 #if defined(UCS_4BE)
51 cd->input.little_endian = false;
52 cd->input.bom_written = true;
53 #elif defined(UCS_4LE)
54 cd->input.little_endian = true;
55 cd->input.bom_written = true;
56 #elif defined(_LITTLE_ENDIAN)
57 cd->input.little_endian = true;
58 #endif
59
60 #if defined(UTF_32BE)
61 cd->output.little_endian = false;
62 cd->output.bom_written = true;
63 #elif defined(UTF_32LE)
64 cd->output.little_endian = true;
65 cd->output.bom_written = true;
66 #elif defined(_LITTLE_ENDIAN)
67 cd->output.little_endian = true;
68 #endif
69
70 return((void *)cd);
71 }
72
73
74 void
_icv_close(ucs_ucs_state_t * cd)75 _icv_close(ucs_ucs_state_t *cd)
76 {
77 if (! cd)
78 errno = EBADF;
79 else
80 free((void *)cd);
81 }
82
83
84 size_t
_icv_iconv(ucs_ucs_state_t * cd,char ** inbuf,size_t * inbufleft,char ** outbuf,size_t * outbufleft)85 _icv_iconv(ucs_ucs_state_t *cd, char **inbuf, size_t *inbufleft, char **outbuf,
86 size_t *outbufleft)
87 {
88 size_t ret_val = 0;
89 uchar_t *ib;
90 uchar_t *ob;
91 uchar_t *ibtail;
92 uchar_t *obtail;
93 uint_t u4;
94 signed char obsz;
95 int i;
96
97
98 if (! cd) {
99 errno = EBADF;
100 return((size_t)-1);
101 }
102
103 if (!inbuf || !(*inbuf)) {
104 #if defined(UCS_4)
105 cd->input.bom_written = false;
106 #endif
107 #if defined(UTF_32)
108 cd->output.bom_written = false;
109 #endif
110 return((size_t)0);
111 }
112
113 ib = (uchar_t *)*inbuf;
114 ob = (uchar_t *)*outbuf;
115 ibtail = ib + *inbufleft;
116 obtail = ob + *outbufleft;
117
118 #if defined(UCS_4)
119 if (! cd->input.bom_written) {
120 if ((ibtail - ib) < ICV_FETCH_UCS4_SIZE) {
121 errno = EINVAL;
122 ret_val = (size_t)-1;
123 goto need_more_input_err;
124 }
125
126 for (u4 = 0, i = 0; i < ICV_FETCH_UCS4_SIZE; i++)
127 u4 = (u4 << 8) | ((uint_t)(*(ib + i)));
128
129 if (u4 == ICV_BOM_IN_BIG_ENDIAN) {
130 ib += ICV_FETCH_UCS4_SIZE;
131 cd->input.little_endian = false;
132 } else if (u4 == ICV_BOM_IN_LITTLE_ENDIAN_UCS4) {
133 ib += ICV_FETCH_UCS4_SIZE;
134 cd->input.little_endian = true;
135 }
136 }
137 cd->input.bom_written = true;
138 #endif
139
140
141 while (ib < ibtail) {
142 if ((ibtail - ib) < ICV_FETCH_UCS4_SIZE) {
143 errno = EINVAL;
144 ret_val = (size_t)-1;
145 break;
146 }
147
148 u4 = 0;
149 if (cd->input.little_endian) {
150 for (i = ICV_FETCH_UCS4_SIZE - 1; i >= 0; i--)
151 u4 = (u4 << 8) | ((uint_t)(*(ib + i)));
152 } else {
153 for (i = 0; i < ICV_FETCH_UCS4_SIZE; i++)
154 u4 = (u4 << 8) | ((uint_t)(*(ib + i)));
155 }
156
157 if (u4 == 0x00fffe || u4 == 0x00ffff || u4 > 0x7fffffff ||
158 (u4 >= 0x00d800 && u4 <= 0x00dfff)) {
159 errno = EILSEQ;
160 ret_val = (size_t)-1;
161 goto illegal_char_err;
162 }
163
164 if (u4 > 0x10ffff) {
165 u4 = ICV_CHAR_UCS2_REPLACEMENT;
166 ret_val++;
167 }
168
169 obsz = (cd->output.bom_written) ? 2 : 4;
170 if ((obtail - ob) < obsz) {
171 errno = E2BIG;
172 ret_val = (size_t)-1;
173 break;
174 }
175
176 if (cd->output.little_endian) {
177 if (! cd->output.bom_written) {
178 *ob++ = (uchar_t)0xff;
179 *ob++ = (uchar_t)0xfe;
180 *(ushort_t *)ob = (ushort_t)0;
181 ob += 2;
182 cd->output.bom_written = true;
183 }
184 *ob++ = (uchar_t)(u4 & 0xff);
185 *ob++ = (uchar_t)((u4 >> 8) & 0xff);
186 *ob++ = (uchar_t)((u4 >> 16) & 0xff);
187 *ob++ = (uchar_t)((u4 >> 24) & 0xff);
188 } else {
189 if (! cd->output.bom_written) {
190 *(ushort_t *)ob = (ushort_t)0;
191 ob += 2;
192 *ob++ = (uchar_t)0xfe;
193 *ob++ = (uchar_t)0xff;
194 cd->output.bom_written = true;
195 }
196 *ob++ = (uchar_t)((u4 >> 24) & 0xff);
197 *ob++ = (uchar_t)((u4 >> 16) & 0xff);
198 *ob++ = (uchar_t)((u4 >> 8) & 0xff);
199 *ob++ = (uchar_t)(u4 & 0xff);
200 }
201 ib += ICV_FETCH_UCS4_SIZE;
202 }
203
204 #if defined(UCS_4)
205 need_more_input_err:
206 #endif
207 illegal_char_err:
208 *inbuf = (char *)ib;
209 *inbufleft = ibtail - ib;
210 *outbuf = (char *)ob;
211 *outbufleft = obtail - ob;
212
213 return(ret_val);
214 }
215