Cygwin: access: Fix X_OK behaviour for backup operators and admins
[newlib-cygwin.git] / newlib / libc / iconv / lib / ucsconv.c
blob502aa440a99b4bb9b52b0f7e86ae00c0f7143313
1 /*
2 * Copyright (c) 2003-2004, Artem B. Bityuckiy
3 * Copyright (c) 1999,2000, Konstantin Chuguev. All rights reserved.
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.
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.
26 #include <_ansi.h>
27 #include <reent.h>
28 #include <sys/types.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "local.h"
33 #include "conv.h"
34 #include "ucsconv.h"
36 static int fake_data;
38 static int
39 find_encoding_name (const char *searchee,
40 const char **names);
44 * UCS-based conversion interface functions implementation.
47 static void *
48 ucs_based_conversion_open (struct _reent *rptr,
49 const char *to,
50 const char *from)
52 iconv_ucs_conversion_t *uc;
53 const iconv_to_ucs_ces_t *to_ucs_bices;
54 const iconv_from_ucs_ces_t *from_ucs_bices;
56 uc = (iconv_ucs_conversion_t *)
57 _calloc_r (rptr, 1, sizeof (iconv_ucs_conversion_t));
58 if (uc == NULL)
59 return NULL;
61 /*
62 * Find CES converter for "from" encoding ("from" source encoding corresponds
63 * to "to_ucs" CES converter).
65 for (to_ucs_bices = &_iconv_to_ucs_ces[0];
66 to_ucs_bices->names != NULL;
67 to_ucs_bices++)
69 if (find_encoding_name (from, to_ucs_bices->names) == 0)
70 break;
73 /*
74 * Find CES converter for "to" encoding ("to" source encoding corresponds
75 * to "from_ucs" CES converter).
77 for (from_ucs_bices = &_iconv_from_ucs_ces[0];
78 from_ucs_bices->names != NULL;
79 from_ucs_bices++)
81 if (find_encoding_name (to, from_ucs_bices->names) == 0)
82 break;
85 if (to_ucs_bices->names == NULL || from_ucs_bices->names == NULL)
86 goto error;
88 uc->to_ucs.handlers = to_ucs_bices->handlers;
89 uc->from_ucs.handlers = from_ucs_bices->handlers;
91 /* Initialize "to UCS" CES converter */
92 if (to_ucs_bices->handlers->init != NULL)
94 uc->to_ucs.data = to_ucs_bices->handlers->init (rptr, from);
95 if (uc->to_ucs.data == NULL)
96 goto error;
98 else
99 uc->to_ucs.data = (void *)&fake_data;
102 /* Initialize "from UCS" CES converter */
103 if (from_ucs_bices->handlers->init != NULL)
105 uc->from_ucs.data = from_ucs_bices->handlers->init (rptr, to);
106 if (uc->from_ucs.data == NULL)
107 goto error;
109 else
110 uc->from_ucs.data = (void *)&fake_data;
112 return uc;
114 error:
115 if (uc->to_ucs.data != NULL && uc->to_ucs.handlers->close != NULL)
116 uc->to_ucs.handlers->close (rptr, uc->to_ucs.data);
118 _free_r (rptr, (void *)uc);
120 return NULL;
124 static size_t
125 ucs_based_conversion_close (struct _reent *rptr,
126 void *data)
128 iconv_ucs_conversion_t *uc;
129 size_t res = 0;
131 uc = (iconv_ucs_conversion_t *)data;
133 if (uc->from_ucs.handlers->close != NULL)
134 res = uc->from_ucs.handlers->close (rptr, uc->from_ucs.data);
135 if (uc->to_ucs.handlers->close != NULL)
136 res |= uc->to_ucs.handlers->close (rptr, uc->to_ucs.data);
138 _free_r (rptr, (void *)data);
140 return res;
144 static size_t
145 ucs_based_conversion_convert (struct _reent *rptr,
146 void *data,
147 const unsigned char **inbuf,
148 size_t *inbytesleft,
149 unsigned char **outbuf,
150 size_t *outbytesleft,
151 int flags)
153 unsigned char outbuf1[ICONV_MB_LEN_MAX];
154 unsigned char *poutbuf1;
155 size_t res = 0;
156 iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
158 while (*inbytesleft > 0)
160 register size_t bytes;
161 register ucs4_t ch;
162 const unsigned char *inbuf_save = *inbuf;
163 size_t inbyteslef_save = *inbytesleft;
165 if (*outbytesleft == 0)
167 _REENT_ERRNO (rptr) = E2BIG;
168 return (size_t)-1;
171 ch = uc->to_ucs.handlers->convert_to_ucs (uc->to_ucs.data,
172 inbuf, inbytesleft);
174 if (ch == (ucs4_t)ICONV_CES_BAD_SEQUENCE)
176 _REENT_ERRNO (rptr) = EINVAL;
177 return (size_t)-1;
180 if (ch == (ucs4_t)ICONV_CES_INVALID_CHARACTER)
182 _REENT_ERRNO (rptr) = EILSEQ;
183 return (size_t)-1;
186 if (flags & ICONV_DONT_SAVE_BIT)
188 poutbuf1 = &outbuf1[0];
189 outbuf = &poutbuf1;
192 bytes = uc->from_ucs.handlers->convert_from_ucs (uc->from_ucs.data, ch,
193 outbuf, outbytesleft);
195 if (bytes == (size_t)ICONV_CES_NOSPACE)
197 *inbuf = inbuf_save;
198 *inbytesleft = inbyteslef_save;
199 _REENT_ERRNO (rptr) = E2BIG;
200 return (size_t)-1;
202 else if (bytes == (size_t)ICONV_CES_INVALID_CHARACTER)
204 if (flags & ICONV_FAIL_BIT)
206 /* Generate error */
207 _REENT_ERRNO (rptr) = EILSEQ;
208 return (size_t)-1;
211 * For this case SUSv3 stands: "if iconv() encounters a character in the
212 * input buffer that is valid, but for which an identical character does
213 * not exist in the target encoding, iconv() shall perform an
214 * implementation-defined conversion on this character".
215 * Don't generate error, just write default character.
217 bytes = uc->from_ucs.handlers->convert_from_ucs (
218 uc->from_ucs.data,
219 (ucs4_t)DEFAULT_CHARACTER,
220 outbuf,
221 outbytesleft);
222 if ((__int32_t)bytes < 0)
224 _REENT_ERRNO (rptr) = E2BIG;
225 return (size_t)-1;
228 res += 1;
232 return res;
236 static int
237 ucs_based_conversion_get_mb_cur_max (void *data,
238 int direction)
240 iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
242 if (direction == 0)
243 return uc->to_ucs.handlers->get_mb_cur_max (uc->to_ucs.data);
244 else
245 return uc->from_ucs.handlers->get_mb_cur_max (uc->from_ucs.data);
249 static void
250 ucs_based_conversion_get_state (void *data,
251 mbstate_t *state,
252 int direction)
254 iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
255 mbstate_t nullstate = ICONV_ZERO_MB_STATE_T;
257 if (direction == 0)
259 if (uc->to_ucs.handlers->get_state != NULL)
260 uc->to_ucs.handlers->get_state (uc->to_ucs.data, state);
261 else
262 *state = nullstate; /* internal copy */
264 else
266 if (uc->from_ucs.handlers->get_state != NULL)
267 uc->from_ucs.handlers->get_state (uc->from_ucs.data, state);
268 else
269 *state = nullstate; /* internal copy */
272 return;
276 static int
277 ucs_based_conversion_set_state (void *data,
278 mbstate_t *state,
279 int direction)
281 iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
283 if (direction == 0)
285 if (uc->to_ucs.handlers->set_state != NULL)
286 return uc->to_ucs.handlers->set_state (uc->to_ucs.data, state);
288 else
290 if (uc->from_ucs.handlers->set_state != NULL)
291 return uc->from_ucs.handlers->set_state (uc->from_ucs.data, state);
294 return 0;
297 static int
298 ucs_based_conversion_is_stateful (void *data,
299 int direction)
301 iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
303 if (direction == 0)
305 if (uc->to_ucs.handlers->is_stateful != NULL)
306 return uc->to_ucs.handlers->is_stateful (uc->to_ucs.data);
308 else
310 if (uc->from_ucs.handlers->is_stateful != NULL)
311 return uc->from_ucs.handlers->is_stateful (uc->from_ucs.data);
314 return 0;
318 /* UCS-based conversion definition object */
319 const iconv_conversion_handlers_t
320 _iconv_ucs_conversion_handlers =
322 ucs_based_conversion_open,
323 ucs_based_conversion_close,
324 ucs_based_conversion_convert,
325 ucs_based_conversion_get_state,
326 ucs_based_conversion_set_state,
327 ucs_based_conversion_get_mb_cur_max,
328 ucs_based_conversion_is_stateful
333 * Supplementary functions.
336 static int
337 find_encoding_name (const char *searchee,
338 const char **names)
340 const char *p;
342 for (p = *names; p != NULL; p = *(names++))
343 if (strcmp (p, searchee) == 0)
344 return 0;
346 return -1;