1 /*
2 * Copyright (c) 2003-2004, Artem B. Bityuckiy
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25 #include <_ansi.h>
26 #include <newlib.h>
27 #include <sys/types.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/iconvnls.h>
31 #ifdef _MB_CAPABLE
32 #include <wchar.h>
33 #include <iconv.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <errno.h>
37 #include "local.h"
38 #include "conv.h"
39 #include "ucsconv.h"
40 #include "iconvnls.h"
41 #endif
42
43 /*
44 * _iconv_nls_construct_filename -- constructs full file name.
45 *
46 * PARAMETERS:
47 * const char *file - the name of file.
48 * const char *dir - the name of subdirectory;
49 * const char *ext - file extension.
50 *
51 * DESCRIPTION:
52 * Function constructs patch to icionv-related file.
53 * 'file' shouldn't be NULL. Doesn't use extension if 'ext' is NULL.
54 *
55 * RETURN:
56 * The pointer to file name if success, In case of error returns NULL
57 * and sets current thread's/process's errno.
58 */
59 const char *
_iconv_nls_construct_filename(const char * file,const char * dir,const char * ext)60 _iconv_nls_construct_filename (
61 const char *file,
62 const char *dir,
63 const char *ext)
64 {
65 int len1, len2, len3;
66 char *path;
67 char *p;
68 int dirlen = strlen (dir);
69
70 if ((path = getenv (NLS_ENVVAR_NAME)) == NULL || *path == '\0')
71 path = ICONV_DEFAULT_NLSPATH;
72
73 len1 = strlen (path);
74 len2 = strlen (file);
75 len3 = ext ? strlen (ext) : 0;
76
77 if ((p = malloc (len1 + dirlen + len2 + len3 + 3)) == NULL)
78 return (const char *)NULL;
79
80 memcpy (p, path, len1);
81 if (p[len1 - 1] != '/')
82 p[len1++] = '/';
83 memcpy (p + len1, dir, dirlen);
84 len1 += dirlen;
85 p[len1++] = '/';
86 memcpy (p + len1, file, len2);
87 len1 += len2;
88 if (ext != NULL)
89 {
90 memcpy (p + len1, ext, len3);
91 len1 += len3;
92 }
93 p[len1] = '\0';
94
95 return (const char *)p;
96 }
97
98
99 #ifdef _MB_CAPABLE
100 /*
101 * _iconv_nls_get_mb_cur_max -- return encoding's maximum length
102 * of a multi-byte character.
103 *
104 * PARAMETERS:
105 * iconv_t cd - opened iconv conversion descriptor;
106 * int direction - "from encoding" or "to encoding" direction.
107 *
108 * DESCRIPTION:
109 * Return maximum length of a multi-byte character in one of 'cd's
110 * encoding. Return "from" encoding's value if 'direction' is 0 and
111 * "to" encoding's value if 'direction' isn't 0.
112 */
113 int
_iconv_nls_get_mb_cur_max(iconv_t cd,int direction)114 _iconv_nls_get_mb_cur_max (iconv_t cd,
115 int direction)
116 {
117 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
118
119 return ic->handlers->get_mb_cur_max (ic->data, direction);
120 }
121
122 /*
123 * _iconv_nls_is_stateful -- is encoding stateful?
124 *
125 * PARAMETERS:
126 * iconv_t cd - opened iconv conversion descriptor;
127 * int direction - "from encoding" or "to encoding" direction.
128 *
129 * DESCRIPTION:
130 * Returns 0 if encoding is stateless or 1 if stateful.
131 * Tests "from" encoding if 'direction' is 0 and
132 * "to" encoding's value if 'direction' isn't 0.
133
134 */
135 int
_iconv_nls_is_stateful(iconv_t cd,int direction)136 _iconv_nls_is_stateful (iconv_t cd,
137 int direction)
138 {
139 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
140
141 return ic->handlers->is_stateful (ic->data, direction);
142 }
143
144 /*
145 * _iconv_nls_conv - special version of iconv for NLS.
146 *
147 * PARAMETERS:
148 * Same as _iconv_r.
149 *
150 * DESCRIPTION:
151 * Function behaves as _iconv_r but:
152 * 1. Don't handle reset/return shift states queries
153 * (like iconv does when 'inbuf' == NULL, etc);
154 * 2. Don't save result if 'outbuf' == NULL or
155 * '*outbuf' == NULL;
156 * 3. Don't perform default conversion if there is no character
157 * in "to" encoding that corresponds to character from "from"
158 * encoding.
159 *
160 * RETURN:
161 * Same as _iconv_r.
162 */
163 size_t
_iconv_nls_conv(iconv_t cd,const char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft)164 _iconv_nls_conv (
165 iconv_t cd,
166 const char **inbuf,
167 size_t *inbytesleft,
168 char **outbuf,
169 size_t *outbytesleft)
170 {
171 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
172 int flags = ICONV_FAIL_BIT;
173
174 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
175 || (ic->handlers != &_iconv_null_conversion_handlers
176 && ic->handlers != &_iconv_ucs_conversion_handlers))
177 {
178 _REENT_ERRNO (rptr) = EBADF;
179 return (size_t)-1;
180 }
181
182 if (inbytesleft == NULL || *inbytesleft == 0)
183 return (size_t)0;
184
185 if (outbuf == NULL || *outbuf == NULL)
186 flags |= ICONV_DONT_SAVE_BIT;
187
188 if (outbytesleft == NULL || *outbytesleft == 0)
189 {
190 _REENT_ERRNO (rptr) = E2BIG;
191 return (size_t)-1;
192 }
193
194 return ic->handlers->convert (
195 ic->data,
196 (const unsigned char**)inbuf,
197 inbytesleft,
198 (unsigned char**)outbuf,
199 outbytesleft,
200 flags);
201 }
202
203 /*
204 * _iconv_nls_get_state -- get encoding's current shift state value.
205 *
206 * PARAMETERS:
207 * iconv_t cd - iconv descriptor;
208 * mbstate_t *ps - where to save shift state;
209 * int direction - "from" encoding if 0, "to" encoding if 1.
210 *
211 * DESCRIPTION:
212 * Save encoding's current shift state to 'ps'. Save "from" encoding's
213 * shift state if 'direction' is 0 and "to" encodings's shift state
214 * if 'direction' isn't 0.
215 */
216 void
_iconv_nls_get_state(iconv_t cd,mbstate_t * ps,int direction)217 _iconv_nls_get_state (iconv_t cd,
218 mbstate_t *ps,
219 int direction)
220 {
221 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
222
223 ic->handlers->get_state (ic->data, ps, direction);
224
225 return;
226 }
227
228 /*
229 * _iconv_nls_set_state -- set encoding's current shift state value.
230 *
231 * PARAMETERS:
232 * iconv_t cd - iconv descriptor;
233 * mbstate_t *ps - where to save shift state.
234 * int direction - "from" encoding if 0, "to" encoding if 1.
235 *
236 * DESCRIPTION:
237 * Set encoding's current shift state.
238 *
239 * RETURN:
240 * 0 if success, -1 if failure.
241 */
242 int
_iconv_nls_set_state(iconv_t cd,mbstate_t * ps,int direction)243 _iconv_nls_set_state (iconv_t cd,
244 mbstate_t *ps,
245 int direction)
246 {
247 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
248
249 return ic->handlers->set_state (ic->data, ps, direction);
250 }
251
252 /* Same as iconv_open() but don't perform name resolving */
253 static iconv_t
iconv_open1(const char * to,const char * from)254 iconv_open1 (
255 const char *to,
256 const char *from)
257 {
258 iconv_conversion_t *ic;
259
260 if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
261 return (iconv_t)-1;
262
263 ic = (iconv_conversion_t *)malloc (sizeof (iconv_conversion_t));
264 if (ic == NULL)
265 return (iconv_t)-1;
266
267 /* Select which conversion type to use */
268 if (strcmp (from, to) == 0)
269 {
270 /* Use null conversion */
271 ic->handlers = &_iconv_null_conversion_handlers;
272 ic->data = ic->handlers->open (to, from);
273 }
274 else
275 {
276 /* Use UCS-based conversion */
277 ic->handlers = &_iconv_ucs_conversion_handlers;
278 ic->data = ic->handlers->open (to, from);
279 }
280
281 if (ic->data == NULL)
282 {
283 free ((void *)ic);
284 return (iconv_t)-1;
285 }
286
287 return (void *)ic;
288 }
289
290 /*
291 * _iconv_nls_open - open iconv descriptors for NLS.
292 *
293 * PARAMETERS:
294 * const char *encoding - encoding name;
295 * iconv_t *tomb - wchar -> encoding iconv descriptor pointer;
296 * iconv_t *towc - encoding -> wchar iconv descriptor pointer;
297 * int flag - perform encoding name resolving flag.
298 *
299 * DESCRIPTION:
300 * Opens two iconv descriptors for 'encoding' -> wchar and
301 * wchar -> 'encoding' iconv conversions. Function is used when locale or
302 * wide-oriented stream is opened. If 'flag' is 0, don't perform encoding
303 * name resolving ('encoding' must not be alias in this case).
304 *
305 * RETURN:
306 * If successful - return 0, else set errno and return -1.
307 */
308 int
_iconv_nls_open(const char * encoding,iconv_t * tomb,iconv_t * towc,int flag)309 _iconv_nls_open (
310 const char *encoding,
311 iconv_t *tomb,
312 iconv_t *towc,
313 int flag)
314 {
315 const char *wchar_encoding;
316
317 if (sizeof (wchar_t) > 2 && WCHAR_MAX > 0xFFFF)
318 wchar_encoding = "ucs_4_internal";
319 else if (sizeof (wchar_t) > 1 && WCHAR_MAX > 0xFF)
320 wchar_encoding = "ucs_2_internal";
321 else
322 wchar_encoding = ""; /* This shuldn't happen */
323
324 if (flag)
325 {
326 if ((*towc = iconv_open (wchar_encoding, encoding)) == (iconv_t)-1)
327 return -1;
328
329 if ((*tomb = iconv_open (encoding, wchar_encoding)) == (iconv_t)-1)
330 {
331 iconv_close (*towc);
332 return -1;
333 }
334 }
335 else
336 {
337 if ((*towc = iconv_open1 (wchar_encoding, encoding)) == (iconv_t)-1)
338 return -1;
339
340 if ((*tomb = iconv_open1 (encoding, wchar_encoding)) == (iconv_t)-1)
341 {
342 iconv_close (*towc);
343 return -1;
344 }
345 }
346
347 return 0;
348 }
349
350 #endif /* _MB_CAPABLE */
351
352