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
38 SYNOPSIS
39 #include <iconv.h>
40 iconv_t iconv_open (const char *<[to]>, const char *<[from]>);
41 int iconv_close (iconv_t <[cd]>);
42 size_t iconv (iconv_t <[cd]>, char **restrict <[inbuf]>,
43 size_t *restrict <[inbytesleft]>,
44 char **restrict <[outbuf]>,
45 size_t *restrict <[outbytesleft]>);
46
47 DESCRIPTION
48 The function <<iconv>> converts characters from <[in]> which are in one
49 encoding to characters of another encoding, outputting them to <[out]>.
50 The value <[inleft]> specifies the number of input bytes to convert whereas
51 the value <[outleft]> specifies the size remaining in the <[out]> buffer.
52 The conversion descriptor <[cd]> specifies the conversion being performed
53 and is created via <<iconv_open>>.
54
55 An <<iconv>> conversion stops if: the input bytes are exhausted, the output
56 buffer is full, an invalid input character sequence occurs, or the
57 conversion specifier is invalid.
58
59 The function <<iconv_open>> is used to specify a conversion from one
60 encoding: <[from]> to another: <[to]>. The result of the call is
61 to create a conversion specifier that can be used with <<iconv>>.
62
63 The function <<iconv_close>> is used to close a conversion specifier after
64 it is no longer needed.
65
66 RETURNS
67 The <<iconv>> function returns the number of non-identical conversions
68 performed. If an error occurs, (size_t)-1 is returned and <<errno>>
69 is set appropriately. The values of <[inleft]>, <[in]>, <[out]>,
70 and <[outleft]> are modified to indicate how much input was processed
71 and how much output was created.
72
73 The <<iconv_open>> function returns either a valid conversion specifier
74 or (iconv_t)-1 to indicate failure. If failure occurs, <<errno>> is set
75 appropriately.
76
77 The <<iconv_close>> function returns 0 on success or -1 on failure.
78 If failure occurs <<errno>> is set appropriately.
79
80 PORTABILITY
81 <<iconv>>, <<iconv_open>>, and <<iconv_close>> are non-ANSI and are specified
82 by the Single Unix specification.
83
84 No supporting OS subroutine calls are required.
85 */
86 #include <sys/types.h>
87 #include <errno.h>
88 #include <string.h>
89 #include <stdlib.h>
90 #include <iconv.h>
91 #include <wchar.h>
92 #include <sys/iconvnls.h>
93 #include "local.h"
94 #include "conv.h"
95 #include "ucsconv.h"
96
97 /*
98 * iconv interface functions as specified by Single Unix specification.
99 */
100
101 iconv_t
iconv_open(const char * to,const char * from)102 iconv_open (
103 const char *to,
104 const char *from)
105 {
106 iconv_conversion_t *ic;
107
108 if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
109 return (iconv_t)-1;
110
111 if ((to = (const char *)_iconv_resolve_encoding_name (to)) == NULL)
112 return (iconv_t)-1;
113
114 if ((from = (const char *)_iconv_resolve_encoding_name (from)) == NULL)
115 {
116 free ((void *)to);
117 return (iconv_t)-1;
118 }
119
120 ic = (iconv_conversion_t *)malloc (sizeof (iconv_conversion_t));
121 if (ic == NULL)
122 return (iconv_t)-1;
123
124 /* Select which conversion type to use */
125 if (strcmp (from, to) == 0)
126 {
127 /* Use null conversion */
128 ic->handlers = &_iconv_null_conversion_handlers;
129 ic->data = ic->handlers->open (to, from);
130 }
131 else
132 {
133 /* Use UCS-based conversion */
134 ic->handlers = &_iconv_ucs_conversion_handlers;
135 ic->data = ic->handlers->open (to, from);
136 }
137
138 free ((void *)to);
139 free ((void *)from);
140
141 if (ic->data == NULL)
142 {
143 free ((void *)ic);
144 return (iconv_t)-1;
145 }
146
147 return (void *)ic;
148 }
149
150 size_t
iconv(iconv_t cd,char ** __restrict inbuf,size_t * __restrict inbytesleft,char ** __restrict outbuf,size_t * __restrict outbytesleft)151 iconv (iconv_t cd,
152 char **__restrict inbuf,
153 size_t *__restrict inbytesleft,
154 char **__restrict outbuf,
155 size_t *__restrict outbytesleft)
156 {
157 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
158
159 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
160 || (ic->handlers != &_iconv_null_conversion_handlers
161 && ic->handlers != &_iconv_ucs_conversion_handlers))
162 {
163 _REENT_ERRNO (rptr) = EBADF;
164 return (size_t)-1;
165 }
166
167 if (inbuf == NULL || *inbuf == NULL)
168 {
169 mbstate_t state_null = ICONV_ZERO_MB_STATE_T;
170
171 if (!ic->handlers->is_stateful(ic->data, 1))
172 return (size_t)0;
173
174 if (outbuf == NULL || *outbuf == NULL)
175 {
176 /* Reset shift state */
177 ic->handlers->set_state (ic->data, &state_null, 1);
178
179 return (size_t)0;
180 }
181
182 if (outbytesleft != NULL)
183 {
184 mbstate_t state_save = ICONV_ZERO_MB_STATE_T;
185
186 /* Save current shift state */
187 ic->handlers->get_state (ic->data, &state_save, 1);
188
189 /* Reset shift state */
190 ic->handlers->set_state (ic->data, &state_null, 1);
191
192 /* Get initial shift state sequence and it's length */
193 ic->handlers->get_state (ic->data, &state_null, 1);
194
195 if (*outbytesleft >= (size_t) state_null.__count)
196 {
197 memcpy ((void *)(*outbuf), (void *)&state_null, state_null.__count);
198
199 *outbuf += state_null.__count;
200 *outbytesleft -= state_null.__count;
201
202 return (size_t)0;
203 }
204
205 /* Restore shift state if output buffer is too small */
206 ic->handlers->set_state (ic->data, &state_save, 1);
207 }
208
209 _REENT_ERRNO (rptr) = E2BIG;
210 return (size_t)-1;
211 }
212
213 if (*inbytesleft == 0)
214 {
215 _REENT_ERRNO (rptr) = EINVAL;
216 return (size_t)-1;
217 }
218
219 if (*outbytesleft == 0 || *outbuf == NULL)
220 {
221 _REENT_ERRNO (rptr) = E2BIG;
222 return (size_t)-1;
223 }
224
225 return ic->handlers->convert (
226 ic->data,
227 (const unsigned char**)inbuf,
228 inbytesleft,
229 (unsigned char**)outbuf,
230 outbytesleft,
231 0);
232 }
233
234
235 int
iconv_close(iconv_t cd)236 iconv_close (iconv_t cd)
237 {
238 int res;
239 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
240
241 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
242 || (ic->handlers != &_iconv_null_conversion_handlers
243 && ic->handlers != &_iconv_ucs_conversion_handlers))
244 {
245 _REENT_ERRNO (rptr) = EBADF;
246 return -1;
247 }
248
249 res = (int)ic->handlers->close (ic->data);
250
251 free ((void *)cd);
252
253 return res;
254 }
255