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 = strlen (ext);
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