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 <_ansi.h>
87 #include <sys/types.h>
88 #include <errno.h>
89 #include <string.h>
90 #include <stdlib.h>
91 #include <iconv.h>
92 #include <wchar.h>
93 #include <sys/iconvnls.h>
94 #include "local.h"
95 #include "conv.h"
96 #include "ucsconv.h"
97
98 /*
99 * iconv interface functions as specified by Single Unix specification.
100 */
101
102 #ifndef _REENT_ONLY
103 iconv_t
iconv_open(const char * to,const char * from)104 iconv_open (
105 const char *to,
106 const char *from)
107 {
108 iconv_conversion_t *ic;
109
110 if (to == NULL || from == NULL || *to == '\0' || *from == '\0')
111 return (iconv_t)-1;
112
113 if ((to = (const char *)_iconv_resolve_encoding_name (to)) == NULL)
114 return (iconv_t)-1;
115
116 if ((from = (const char *)_iconv_resolve_encoding_name (from)) == NULL)
117 {
118 free ((void *)to);
119 return (iconv_t)-1;
120 }
121
122 ic = (iconv_conversion_t *)malloc (sizeof (iconv_conversion_t));
123 if (ic == NULL)
124 return (iconv_t)-1;
125
126 /* Select which conversion type to use */
127 if (strcmp (from, to) == 0)
128 {
129 /* Use null conversion */
130 ic->handlers = &_iconv_null_conversion_handlers;
131 ic->data = ic->handlers->open (to, from);
132 }
133 else
134 {
135 /* Use UCS-based conversion */
136 ic->handlers = &_iconv_ucs_conversion_handlers;
137 ic->data = ic->handlers->open (to, from);
138 }
139
140 free ((void *)to);
141 free ((void *)from);
142
143 if (ic->data == NULL)
144 {
145 free ((void *)ic);
146 return (iconv_t)-1;
147 }
148
149 return (void *)ic;
150 }
151
152
153 size_t
iconv(iconv_t cd,const char ** __restrict inbuf,size_t * __restrict inbytesleft,char ** __restrict outbuf,size_t * __restrict outbytesleft)154 iconv (iconv_t cd,
155 const char **__restrict inbuf,
156 size_t *__restrict inbytesleft,
157 char **__restrict outbuf,
158 size_t *__restrict outbytesleft)
159 {
160 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
161
162 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
163 || (ic->handlers != &_iconv_null_conversion_handlers
164 && ic->handlers != &_iconv_ucs_conversion_handlers))
165 {
166 _REENT_ERRNO (rptr) = EBADF;
167 return (size_t)-1;
168 }
169
170 if (inbuf == NULL || *inbuf == NULL)
171 {
172 mbstate_t state_null = ICONV_ZERO_MB_STATE_T;
173
174 if (!ic->handlers->is_stateful(ic->data, 1))
175 return (size_t)0;
176
177 if (outbuf == NULL || *outbuf == NULL)
178 {
179 /* Reset shift state */
180 ic->handlers->set_state (ic->data, &state_null, 1);
181
182 return (size_t)0;
183 }
184
185 if (outbytesleft != NULL)
186 {
187 mbstate_t state_save = ICONV_ZERO_MB_STATE_T;
188
189 /* Save current shift state */
190 ic->handlers->get_state (ic->data, &state_save, 1);
191
192 /* Reset shift state */
193 ic->handlers->set_state (ic->data, &state_null, 1);
194
195 /* Get initial shift state sequence and it's length */
196 ic->handlers->get_state (ic->data, &state_null, 1);
197
198 if (*outbytesleft >= (size_t) state_null.__count)
199 {
200 memcpy ((void *)(*outbuf), (void *)&state_null, state_null.__count);
201
202 *outbuf += state_null.__count;
203 *outbytesleft -= state_null.__count;
204
205 return (size_t)0;
206 }
207
208 /* Restore shift state if output buffer is too small */
209 ic->handlers->set_state (ic->data, &state_save, 1);
210 }
211
212 _REENT_ERRNO (rptr) = E2BIG;
213 return (size_t)-1;
214 }
215
216 if (*inbytesleft == 0)
217 {
218 _REENT_ERRNO (rptr) = EINVAL;
219 return (size_t)-1;
220 }
221
222 if (*outbytesleft == 0 || *outbuf == NULL)
223 {
224 _REENT_ERRNO (rptr) = E2BIG;
225 return (size_t)-1;
226 }
227
228 return ic->handlers->convert (
229 ic->data,
230 (const unsigned char**)inbuf,
231 inbytesleft,
232 (unsigned char**)outbuf,
233 outbytesleft,
234 0);
235 }
236
237
238 int
iconv_close(iconv_t cd)239 iconv_close (iconv_t cd)
240 {
241 int res;
242 iconv_conversion_t *ic = (iconv_conversion_t *)cd;
243
244 if ((void *)cd == NULL || cd == (iconv_t)-1 || ic->data == NULL
245 || (ic->handlers != &_iconv_null_conversion_handlers
246 && ic->handlers != &_iconv_ucs_conversion_handlers))
247 {
248 _REENT_ERRNO (rptr) = EBADF;
249 return -1;
250 }
251
252 res = (int)ic->handlers->close (ic->data);
253
254 free ((void *)cd);
255
256 return res;
257 }
258 #endif /* !_REENT_ONLY */
259