source: trunk/libs/newlib/src/newlib/libc/iconv/lib/ucsconv.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 9.5 KB
Line 
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#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"
35
36static int fake_data;
37
38static int 
39find_encoding_name (const char *searchee,
40                            const char **names);
41
42
43/*
44 * UCS-based conversion interface functions implementation.
45 */
46
47static void *
48ucs_based_conversion_open (struct _reent *rptr,
49                                  const char *to,
50                                  const char *from)
51{
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;
55 
56  uc = (iconv_ucs_conversion_t *)
57             _calloc_r (rptr, 1, sizeof (iconv_ucs_conversion_t));
58  if (uc == NULL)
59    return NULL;
60
61  /*
62   * Find CES converter for "from" encoding ("from" source encoding corresponds
63   * to "to_ucs" CES converter).
64   */
65  for (to_ucs_bices = &_iconv_to_ucs_ces[0];
66       to_ucs_bices->names != NULL;
67       to_ucs_bices++)
68    {
69      if (find_encoding_name (from, to_ucs_bices->names) == 0)
70        break;
71    }
72 
73  /*
74   * Find CES converter for "to" encoding ("to" source encoding corresponds
75   * to "from_ucs" CES converter).
76   */
77  for (from_ucs_bices = &_iconv_from_ucs_ces[0];
78       from_ucs_bices->names != NULL;
79       from_ucs_bices++)
80    {
81      if (find_encoding_name (to, from_ucs_bices->names) == 0)
82        break;
83    }
84
85  if (to_ucs_bices->names == NULL || from_ucs_bices->names == NULL)
86    goto error;
87
88  uc->to_ucs.handlers = to_ucs_bices->handlers;
89  uc->from_ucs.handlers = from_ucs_bices->handlers;
90 
91  /* Initialize "to UCS" CES converter */
92  if (to_ucs_bices->handlers->init != NULL)
93    {
94      uc->to_ucs.data = to_ucs_bices->handlers->init (rptr, from);
95      if (uc->to_ucs.data == NULL)
96        goto error;
97    }
98  else
99    uc->to_ucs.data = (void *)&fake_data;
100   
101
102  /* Initialize "from UCS" CES converter */
103  if (from_ucs_bices->handlers->init != NULL)
104    {
105      uc->from_ucs.data = from_ucs_bices->handlers->init (rptr, to);
106      if (uc->from_ucs.data == NULL)
107        goto error;
108    }
109  else
110    uc->from_ucs.data = (void *)&fake_data;
111
112  return uc;
113
114error:
115  if (uc->to_ucs.data != NULL && uc->to_ucs.handlers->close != NULL)
116    uc->to_ucs.handlers->close (rptr, uc->to_ucs.data);
117
118  _free_r (rptr, (void *)uc);
119
120  return NULL;
121}
122
123
124static size_t
125ucs_based_conversion_close (struct _reent *rptr,
126                                   void *data)
127{
128  iconv_ucs_conversion_t *uc;
129  size_t res = 0;
130
131  uc = (iconv_ucs_conversion_t *)data;
132
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);
137
138  _free_r (rptr, (void *)data);
139
140  return res;
141}
142
143
144static size_t
145ucs_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)
152{
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;
157
158  while (*inbytesleft > 0)
159    {
160      register size_t bytes;
161      register ucs4_t ch;
162      const unsigned char *inbuf_save = *inbuf;
163      size_t inbyteslef_save = *inbytesleft;
164
165      if (*outbytesleft == 0)
166        {
167          __errno_r (rptr) = E2BIG;
168          return (size_t)-1;
169        }
170
171      ch = uc->to_ucs.handlers->convert_to_ucs (uc->to_ucs.data,
172                                                inbuf, inbytesleft);
173
174      if (ch == (ucs4_t)ICONV_CES_BAD_SEQUENCE)
175        {
176          __errno_r (rptr) = EINVAL;
177          return (size_t)-1;
178        }
179
180      if (ch == (ucs4_t)ICONV_CES_INVALID_CHARACTER)
181        {
182          __errno_r (rptr) = EILSEQ;
183          return (size_t)-1;
184        }
185
186      if (flags & ICONV_DONT_SAVE_BIT)
187        {
188          poutbuf1 = &outbuf1[0];
189          outbuf = &poutbuf1;
190        }
191
192      bytes = uc->from_ucs.handlers->convert_from_ucs (uc->from_ucs.data, ch,
193                                                       outbuf, outbytesleft); 
194
195      if (bytes == (size_t)ICONV_CES_NOSPACE)
196        {
197          *inbuf = inbuf_save;
198          *inbytesleft = inbyteslef_save;
199          __errno_r (rptr) = E2BIG;
200          return (size_t)-1;
201        }
202      else if (bytes == (size_t)ICONV_CES_INVALID_CHARACTER)
203        {
204          if (flags & ICONV_FAIL_BIT)
205            {
206              /* Generate error */
207              __errno_r (rptr) = EILSEQ;
208              return (size_t)-1;
209            }
210          /*
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.
216           */
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)
223            {
224              __errno_r (rptr) = E2BIG;
225              return (size_t)-1;
226            }
227     
228          res += 1;
229        }
230    }
231
232  return res;
233}
234
235
236static int
237ucs_based_conversion_get_mb_cur_max (void *data,
238                                            int direction)
239{
240  iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
241 
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);
246}
247
248
249static void
250ucs_based_conversion_get_state (void *data,
251                                       mbstate_t *state,
252                                       int direction)
253{
254  iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
255  mbstate_t nullstate = ICONV_ZERO_MB_STATE_T;
256 
257  if (direction == 0)
258    {
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 */
263    }
264  else
265    {
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 */
270    }
271
272  return;
273}
274
275
276static int
277ucs_based_conversion_set_state (void *data,
278                                       mbstate_t *state,
279                                       int direction)
280{
281  iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
282
283  if (direction == 0)
284    {
285      if (uc->to_ucs.handlers->set_state != NULL)
286        return uc->to_ucs.handlers->set_state (uc->to_ucs.data, state);
287    }
288  else
289    {
290      if (uc->from_ucs.handlers->set_state != NULL)
291        return uc->from_ucs.handlers->set_state (uc->from_ucs.data, state);
292    }
293
294  return 0;
295}
296
297static int
298ucs_based_conversion_is_stateful (void *data,
299                                         int direction)
300{
301  iconv_ucs_conversion_t *uc = (iconv_ucs_conversion_t *)data;
302
303  if (direction == 0)
304    {
305      if (uc->to_ucs.handlers->is_stateful != NULL)
306        return uc->to_ucs.handlers->is_stateful (uc->to_ucs.data);
307    }
308  else
309    {
310      if (uc->from_ucs.handlers->is_stateful != NULL)
311        return uc->from_ucs.handlers->is_stateful (uc->from_ucs.data);
312    }
313
314  return 0;
315}
316
317
318/* UCS-based conversion definition object */
319const iconv_conversion_handlers_t
320_iconv_ucs_conversion_handlers =
321{
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
329};
330
331
332/*
333 * Supplementary functions.
334 */
335
336static int
337find_encoding_name (const char *searchee,
338                           const char **names)
339{
340  const char *p;
341
342  for (p = *names; p != NULL; p = *(names++))
343    if (strcmp (p, searchee) == 0)
344      return 0;
345
346  return -1;
347}
348
Note: See TracBrowser for help on using the repository browser.