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