OSDN Git Service

2004-06-25 Artem B. Bityuckiy <dedekind@oktetlabs.ru>
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / iconv / lib / iconv.c
1 /*
2  * Copyright (c) 2003-2004, Artem B. Bityuckiy
3  * Copyright (c) 1999,2000, Konstantin Chuguev. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28 FUNCTION
29 <<iconv>>, <<iconv_open>>, <<iconv_close>>---charset conversion routines
30
31 INDEX
32         iconv
33 INDEX
34         iconv_open
35 INDEX
36         iconv_close
37 INDEX
38         _iconv_r
39 INDEX
40         _iconv_open_r
41 INDEX
42         _iconv_close_r
43
44 ANSI_SYNOPSIS
45         #include <iconv.h>
46         iconv_t iconv_open (const char *<[to]>, const char *<[from]>);
47         int iconv_close (iconv_t <[cd]>);
48         size_t iconv (iconv_t <[cd]>, const char **<[inbuf]>, 
49                       size_t *<[inbytesleft]>, 
50                       char **<[outbuf]>, size_t *<[outbytesleft]>),
51
52         iconv_t _iconv_open_r (struct _reent *<[rptr]>, 
53                                const char *<[to]>, const char *<[from]>);
54         int _iconv_close_r (struct _reent *<[rptr]>, iconv_t <[cd]>);
55         size_t _iconv_r (struct _reent *<[rptr]>,
56                          iconv_t <[cd]>, const char **<[inbuf]>, 
57                          size_t *<[inbytesleft]>, 
58                          char **<[outbuf]>, size_t *<[outbytesleft]>),
59
60 TRAD_SYNOPSIS
61         #include <iconv.h>
62         size_t iconv (<[cd]>, <[in]>, <[inleft]>, <[out]>, <[outleft]>)
63         iconv_t <[cd]>;
64         const char **<[in]>;
65         size_t *<[inleft]>; 
66         char **<[out]>;
67         size_t *<[outleft]>);
68
69         #include <iconv.h>
70         iconv_t iconv_open (<[to]>, <[from]>);
71         const char *<[to]>;
72         const char *<[from]>;
73
74         #include <iconv.h>
75         int iconv_close (<[cd]>);
76         iconv_t <[cd]>;
77
78         #include <iconv.h>
79         size_t _iconv_r (<[rptr]>, <[cd]>, <[in]>, <[inleft]>, <[out]>, <[outleft]>)
80         struct _reent *<[rptr]>;
81         iconv_t <[cd]>;
82         const char **<[in]>;
83         size_t *<[inleft]>; 
84         char **<[out]>;
85         size_t *<[outleft]>);
86
87         #include <iconv.h>
88         iconv_t _iconv_open_r (<[rptr]>, <[to]>, <[from]>);
89         struct _reent *<[rptr]>;
90         const char *<[to]>;
91         const char *<[from]>;
92
93         #include <iconv.h>
94         int iconv_close (<[rptr]>, <[cd]>);
95         struct _reent *<[rptr]>;
96         iconv_t <[cd]>;
97
98 DESCRIPTION
99 The function <<iconv>> converts characters from <[in]> which are in one
100 character set and converts them to characters of another character set,
101 outputting them to <[out]>.  The value <[inleft]> specifies the number
102 of input bytes to convert whereas the value <[outleft]> specifies the
103 size remaining in the <[out]> buffer.  The conversion descriptor <[cd]>
104 specifies the conversion being performed and is created via <<iconv_open>>.
105
106 An <<iconv>> conversion stops if: the input bytes are exhausted, the output
107 buffer is full, an invalid input character sequence occurs, or the
108 conversion specifier is invalid.
109
110 The function <<iconv_open>> is used to specify a conversion from one
111 character set: <[from]> to another: <[to]>.  The result of the call is
112 to create a conversion specifier that can be used with <<iconv>>.
113
114 The function <<iconv_close>> is used to close a conversion specifier after
115 it is no longer needed.
116
117 The <<_iconv_r>>, <<_iconv_open_r>>, and <<_iconv_close_r>> functions are
118 reentrant versions of <<iconv>>, <<iconv_open>>, and <<iconv_close>>,
119 respectively.  An additional reentrancy struct pointer: <[rptr]> is passed
120 to properly set <<errno>>.
121
122 RETURNS
123 The <<iconv>> function returns the number of non-identical conversions
124 performed.  If an error occurs, (size_t)-1 is returned and <<errno>>
125 is set appropriately.  The values of <[inleft]>, <[in]>, <[out]>,
126 and <[outleft]> are modified to indicate how much input was processed
127 and how much output was created.
128
129 The <<iconv_open>> function returns either a valid conversion specifier
130 or (iconv_t)-1 to indicate failure.  If failure occurs, <<errno>> is set
131 appropriately.
132
133 The <<iconv_close>> function returns 0 on success or -1 on failure.
134 If failure occurs <<errno>> is set appropriately.
135
136 PORTABILITY
137 <<iconv>>, <<iconv_open>>, and <<iconv_close>> are non-ANSI and are specified
138 by the Single Unix specification.
139
140 No supporting OS subroutine calls are required.
141 */
142 #include <_ansi.h>
143 #include <reent.h>
144 #include <sys/types.h>
145 #include <errno.h>
146 #include <string.h>
147 #include <stdlib.h>
148 #include <iconv.h>
149 #include <wchar.h>
150 #include <sys/iconvnls.h>
151 #include "local.h"
152 #include "conv.h"
153 #include "ucsconv.h"
154
155 /*
156  * iconv interface functions as specified by Single Unix specification.
157  */
158
159 iconv_t
160 _DEFUN(iconv_open, (to, from), 
161                    _CONST char *to _AND
162                    _CONST char *from)
163 {
164   return _iconv_open_r (_REENT, to, from);
165 }
166
167
168 size_t
169 _DEFUN(iconv, (cd, inbuf, inbytesleft, outbuf, outbytesleft),
170               iconv_t cd          _AND
171               _CONST char **inbuf _AND
172               size_t *inbytesleft _AND
173               char **outbuf       _AND
174               size_t *outbytesleft)
175 {
176     return _iconv_r (_REENT, cd, inbuf, inbytesleft, outbuf, outbytesleft);
177 }
178
179
180 int
181 _DEFUN(iconv_close, (cd), iconv_t cd)
182 {
183     return _iconv_close_r (_REENT, cd);
184 }
185
186
187 #ifndef _REENT_ONLY
188 iconv_t
189 _DEFUN(_iconv_open_r, (rptr, to, from),
190                       struct _reent *rptr _AND
191                       _CONST char *to     _AND
192                       _CONST char *from)
193 {
194   iconv_conversion_t *ic;
195     
196   if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
197     return (iconv_t)-1;
198
199   if ((to = (_CONST char *)_iconv_resolve_encoding_name (rptr, to)) == NULL)
200     return (iconv_t)-1;
201
202   if ((from = (_CONST char *)_iconv_resolve_encoding_name (rptr, from)) == NULL)
203     {
204       _free_r (rptr, (_VOID_PTR)to);
205       return (iconv_t)-1;
206     }
207
208   ic = (iconv_conversion_t *)_malloc_r (rptr, sizeof (iconv_conversion_t));
209   if (ic == NULL)
210     return (iconv_t)-1;
211
212   /* Select which conversion type to use */
213   if (strcmp (from, to) == 0)
214     {
215       /* Use null conversion */
216       ic->handlers = &_iconv_null_conversion_handlers;
217       ic->data = ic->handlers->open (rptr, to, from);
218     }
219   else  
220     {
221       /* Use UCS-based conversion */
222       ic->handlers = &_iconv_ucs_conversion_handlers;
223       ic->data = ic->handlers->open (rptr, to, from);
224     }
225
226   _free_r (rptr, (_VOID_PTR)to);
227   _free_r (rptr, (_VOID_PTR)from);
228
229   if (ic->data == NULL)
230     {
231       _free_r (rptr, (_VOID_PTR)ic);
232       return (iconv_t)-1;
233     }
234
235   return (_VOID_PTR)ic;
236 }
237
238
239 size_t
240 _DEFUN(_iconv_r, (rptr, cd, inbuf, inbytesleft, outbuf, outbytesleft),
241                  struct _reent *rptr _AND
242                  iconv_t cd          _AND
243                  _CONST char **inbuf _AND
244                  size_t *inbytesleft _AND
245                  char **outbuf       _AND
246                  size_t *outbytesleft)
247 {
248   iconv_conversion_t *ic = (iconv_conversion_t *)cd;
249
250   if ((_VOID_PTR)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
251        || (ic->handlers != &_iconv_null_conversion_handlers
252            && ic->handlers != &_iconv_ucs_conversion_handlers))
253     {
254       __errno_r (rptr) = EBADF;
255       return (size_t)-1;
256     }
257
258   if (inbuf == NULL || *inbuf == NULL)
259     {
260       mbstate_t state_null = ICONV_ZERO_MB_STATE_T;
261       
262       if (!ic->handlers->is_stateful(ic->data, 1))
263         return (size_t)0;
264       
265       if (outbuf == NULL || *outbuf == NULL)
266         {
267           /* Reset shift state */
268           ic->handlers->set_state (ic->data, &state_null, 1);
269           
270           return (size_t)0;
271         }
272        
273       if (outbytesleft != NULL)
274         {
275           mbstate_t state_save = ICONV_ZERO_MB_STATE_T;
276           
277           /* Save current shift state */          
278           ic->handlers->get_state (ic->data, &state_save, 1);
279           
280           /* Reset shift state */
281           ic->handlers->set_state (ic->data, &state_null, 1);
282
283           /* Get initial shift state sequence and it's length */
284           ic->handlers->get_state (ic->data, &state_null, 1);
285           
286           if (*outbytesleft >= state_null.__count)
287             {
288               memcpy ((_VOID_PTR)(*outbuf), (_VOID_PTR)&state_null, state_null.__count);
289               
290               *outbuf += state_null.__count;
291               *outbytesleft -= state_null.__count;
292
293               return (size_t)0;
294             }
295
296            /* Restore shift state if output buffer is too small */
297            ic->handlers->set_state (ic->data, &state_save, 1);
298         }
299        
300       __errno_r (rptr) = E2BIG;
301       return (size_t)-1;
302     }
303   
304   if (*inbytesleft == 0)
305     {
306       __errno_r (rptr) = EINVAL;
307       return (size_t)-1;
308     }
309    
310   if (*outbytesleft == 0 || *outbuf == NULL)
311     {
312       __errno_r (rptr) = E2BIG;
313       return (size_t)-1;
314     }
315
316   return ic->handlers->convert (rptr,
317                                 ic->data,
318                                 (_CONST unsigned char**)inbuf,
319                                 inbytesleft,
320                                 (unsigned char**)outbuf,
321                                 outbytesleft,
322                                 0);
323 }
324
325
326 int
327 _DEFUN(_iconv_close_r, (rptr, cd),
328                        struct _reent *rptr _AND
329                        iconv_t cd)
330 {
331   int res;
332   iconv_conversion_t *ic = (iconv_conversion_t *)cd;
333   
334   if ((_VOID_PTR)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
335        || (ic->handlers != &_iconv_null_conversion_handlers
336            && ic->handlers != &_iconv_ucs_conversion_handlers))
337     {
338       __errno_r (rptr) = EBADF;
339       return -1;
340     }
341
342   res = (int)ic->handlers->close (rptr, ic->data);
343   
344   _free_r (rptr, (_VOID_PTR)cd);
345
346   return res;
347 }
348 #endif /* !_REENT_ONLY */
349