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