source: trunk/libs/newlib/src/newlib/libc/iconv/ces/table.c @ 444

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

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

File size: 15.6 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 "cesbi.h"
27
28#if defined (ICONV_TO_UCS_CES_TABLE) \
29 || defined (ICONV_FROM_UCS_CES_TABLE)
30 
31#include <_ansi.h>
32#include <reent.h>
33#include <newlib.h>
34#include <sys/types.h>
35#include <string.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <sys/iconvnls.h>
40#include "../lib/endian.h"
41#include "../lib/local.h"
42#include "../lib/ucsconv.h"
43#include "../ccs/ccs.h"
44
45/*
46 * Table-based CES converter is implemented here.  Table-based CES converter
47 * deals with encodings with "null" CES, like KOI8-R. In this case it is
48 * possible to implement one generic algorithm which works with different
49 * CCS tables.
50 *
51 * Table-based CES converter deals with CCS tables placed into iconv/ccs
52 * subdirectory. First, converter tries to find needed CCS table among
53 * linked-in tables. If not found, it tries to load it from external file
54 * (only if corespondent capability was enabled in Newlib configuration).
55 *
56 * 16 bit encodings are assumed to be Big Endian.
57 */
58
59static ucs2_t
60find_code_size (ucs2_t code, const __uint16_t *tblp);
61
62static __inline ucs2_t
63find_code_speed (ucs2_t code, const __uint16_t *tblp);
64
65static __inline ucs2_t
66find_code_speed_8bit (ucs2_t code, const unsigned char *tblp);
67
68#ifdef _ICONV_ENABLE_EXTERNAL_CCS
69static const iconv_ccs_desc_t *
70load_file (struct _reent *rptr, const char *name, int direction);
71#endif
72
73/*
74 * Interface data and functions implementation.
75 */
76static size_t
77table_close (struct _reent *rptr,
78                    void *data)
79{
80  const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
81
82  if (ccsp->type == TABLE_EXTERNAL)
83    _free_r (rptr, (void *)ccsp->tbl);
84
85  _free_r( rptr, (void *)ccsp);
86  return 0;
87}
88
89#if defined (ICONV_FROM_UCS_CES_TABLE)
90static void *
91table_init_from_ucs (struct _reent *rptr,
92                            const char *encoding)
93{
94  int i;
95  const iconv_ccs_t *biccsp = NULL;
96  iconv_ccs_desc_t *ccsp;
97 
98  for (i = 0; _iconv_ccs[i] != NULL; i++)
99    if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
100      {
101        biccsp = _iconv_ccs[i]; 
102        break;
103      }
104
105  if (biccsp != NULL)
106    {
107      if (biccsp->from_ucs == NULL
108          || (ccsp = (iconv_ccs_desc_t *)
109                     _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
110        return NULL;
111
112      ccsp->type = TABLE_BUILTIN;
113      ccsp->bits = biccsp->bits;
114      ccsp->optimization = biccsp->from_ucs_type;
115      ccsp->tbl = biccsp->from_ucs;
116     
117      return (void *)ccsp;
118    }
119   
120#ifdef _ICONV_ENABLE_EXTERNAL_CCS
121  return (void *)load_file (rptr, encoding, 1);
122#else
123  return NULL;
124#endif
125}
126
127static size_t
128table_convert_from_ucs (void *data,
129                               ucs4_t in,
130                               unsigned char **outbuf,
131                               size_t *outbytesleft)
132{
133  const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
134  ucs2_t code;
135
136  if (in > 0xFFFF || in == INVALC)
137    return (size_t)ICONV_CES_INVALID_CHARACTER;
138
139  if (ccsp->bits == TABLE_8BIT)
140    {
141      code = find_code_speed_8bit ((ucs2_t)in,
142                                  (const unsigned char *)ccsp->tbl);
143      if (code == INVALC)
144        return (size_t)ICONV_CES_INVALID_CHARACTER;
145      **outbuf = (unsigned char)code;
146      *outbuf += 1;
147      *outbytesleft -= 1;
148      return 1; 
149    }
150  else if (ccsp->optimization == TABLE_SPEED_OPTIMIZED)
151    code = find_code_speed ((ucs2_t)in, ccsp->tbl);
152  else
153    code = find_code_size ((ucs2_t)in, ccsp->tbl);
154
155  if (code == INVALC)
156    return (size_t)ICONV_CES_INVALID_CHARACTER;
157
158  if (*outbytesleft < 2)
159    return (size_t)ICONV_CES_NOSPACE;
160 
161  /* We can't store whole word since **outbuf may be not 2-byte aligned */
162  **outbuf = (unsigned char)((ucs2_t)code >> 8);
163  *(*outbuf + 1) = (unsigned char)code;
164  *outbuf += 2;
165  *outbytesleft -= 2;
166  return 2; 
167}
168#endif /* ICONV_FROM_UCS_CES_TABLE */
169
170#if defined (ICONV_TO_UCS_CES_TABLE)
171static void *
172table_init_to_ucs (struct _reent *rptr,
173                          const char *encoding)
174{
175  int i;
176  const iconv_ccs_t *biccsp = NULL;
177  iconv_ccs_desc_t *ccsp;
178 
179  for (i = 0; _iconv_ccs[i] != NULL; i++)
180    if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
181      {
182        biccsp = _iconv_ccs[i]; 
183        break;
184      }
185
186  if (biccsp != NULL)
187    {
188      if (biccsp->to_ucs == NULL
189          || (ccsp = (iconv_ccs_desc_t *)
190                     _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
191        return NULL;
192
193      ccsp->type = TABLE_BUILTIN;
194      ccsp->bits = biccsp->bits;
195      ccsp->optimization = biccsp->to_ucs_type;
196      ccsp->tbl = biccsp->to_ucs;
197     
198      return (void *)ccsp;
199    }
200 
201#ifdef _ICONV_ENABLE_EXTERNAL_CCS
202  return (void *)load_file (rptr, encoding, 0);
203#else
204  return NULL;
205#endif
206}
207
208static ucs4_t
209table_convert_to_ucs (void *data,
210                             const unsigned char **inbuf,
211                             size_t *inbytesleft)
212{
213  const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
214  ucs2_t ucs;
215 
216  if (ccsp->bits == TABLE_8BIT)
217    {
218      if (*inbytesleft < 1)
219        return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
220 
221      ucs = (ucs2_t)ccsp->tbl[**inbuf];
222     
223      if (ucs == INVALC)
224        return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
225         
226      *inbytesleft -= 1;
227      *inbuf += 1;
228      return (ucs4_t)ucs; 
229    }
230
231  if (*inbytesleft < 2)
232    return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
233
234  if (ccsp->optimization == TABLE_SIZE_OPTIMIZED)
235    ucs = find_code_size((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
236                         ccsp->tbl);
237  else
238    ucs = find_code_speed((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
239                          ccsp->tbl);
240
241  if (ucs == INVALC)
242    return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
243
244  *inbuf += 2;
245  *inbytesleft -= 2;
246  return (ucs4_t)ucs; 
247}
248#endif /* ICONV_TO_UCS_CES_TABLE */
249
250static int
251table_get_mb_cur_max (void *data)
252{
253  return ((iconv_ccs_desc_t *)data)->bits/8;
254}
255
256
257#if defined (ICONV_TO_UCS_CES_TABLE)
258const iconv_to_ucs_ces_handlers_t
259_iconv_to_ucs_ces_handlers_table = 
260{
261  table_init_to_ucs,
262  table_close,
263  table_get_mb_cur_max,
264  NULL,
265  NULL,
266  NULL,
267  table_convert_to_ucs
268};
269#endif /* ICONV_FROM_UCS_CES_TABLE */
270
271#if defined (ICONV_FROM_UCS_CES_TABLE)
272const iconv_from_ucs_ces_handlers_t
273_iconv_from_ucs_ces_handlers_table =
274{
275  table_init_from_ucs,
276  table_close,
277  table_get_mb_cur_max,
278  NULL,
279  NULL,
280  NULL,
281  table_convert_from_ucs
282};
283#endif /* ICONV_TO_UCS_CES_TABLE */
284
285/*
286 * Supplementary functions.
287 */
288
289/*
290 * find_code_speed - find code in 16 bit speed-optimized table.
291 *
292 * PARAMETERS:
293 *     ucs2_t code - code whose mapping to find.
294 *     const __uint16_t *tblp - table pointer.
295 *
296 * RETURN:
297 *     Code that corresponds to 'code'.
298 */
299static __inline ucs2_t
300find_code_speed (ucs2_t code,
301                        const __uint16_t *tblp)
302{
303  int idx = tblp[code >> 8];
304
305  if (idx == INVBLK)
306    return (ucs2_t)INVALC;
307
308  return (ucs2_t)tblp[(code & 0x00FF) + idx];
309}
310
311/*
312 * find_code_speed_8bit - find code in 8 bit speed-optimized table.
313 *
314 * PARAMETERS:
315 *     ucs2_t code - code whose mapping to find.
316 *     const __uint16_t *tblp - table pointer.
317 *
318 * RETURN:
319 *     Code that corresponds to 'code'.
320 */
321static __inline ucs2_t
322find_code_speed_8bit (ucs2_t code,
323                             const unsigned char *tblp)
324{
325  int idx;
326  unsigned char ccs;
327
328  if (code == ((ucs2_t *)tblp)[0])
329    return (ucs2_t)0xFF;
330 
331  idx = ((ucs2_t *)tblp)[1 + (code >> 8)];
332 
333  if (idx == INVBLK)
334    return (ucs2_t)INVALC;
335
336  ccs = tblp[(code & 0x00FF) + idx];
337
338  return ccs == 0xFF ? (ucs2_t)INVALC : (ucs2_t)ccs;
339}
340
341/* Left range boundary */
342#define RANGE_LEFT(n)     (tblp[FIRST_RANGE_INDEX + (n)*3 + 0])
343/* Right range boundary */
344#define RANGE_RIGHT(n)    (tblp[FIRST_RANGE_INDEX + (n)*3 + 1])
345/* Range offset */
346#define RANGE_INDEX(n)    (tblp[FIRST_RANGE_INDEX + (n)*3 + 2])
347/* Un-ranged offset */
348#define UNRANGED_INDEX(n) (tblp[FIRST_UNRANGED_INDEX_INDEX] + (n)*2)
349
350/*
351 * find_code_size - find code in 16 bit size-optimized table.
352 *
353 * PARAMETERS:
354 *     ucs2_t code - code whose mapping to find.
355 *     const __uint16_t *tblp - table pointer.
356 *
357 * RETURN:
358 *     Code that corresponds to 'code'.
359 */
360static ucs2_t
361find_code_size (ucs2_t code,
362                       const __uint16_t *tblp)
363{
364  int first, last, cur, center;
365
366  if (tblp[RANGES_NUM_INDEX] > 0)
367    {
368      first = 0;
369      last = tblp[RANGES_NUM_INDEX] - 1;
370 
371      do
372        {
373          center = (last - first)/2;
374          cur = center + first;
375         
376          if (code > RANGE_RIGHT (cur))
377            first = cur;
378          else if (code < RANGE_LEFT (cur))
379            last = cur;
380          else
381            return (ucs2_t)tblp[RANGE_INDEX (cur) + code - RANGE_LEFT (cur)];
382        } while (center > 0);
383
384        if (last - first == 1)
385          {
386            if (code >= RANGE_LEFT (first) && code <= RANGE_RIGHT (first))
387              return (ucs2_t)tblp[RANGE_INDEX (first)
388                                  + code - RANGE_LEFT (first)];
389            if (code >= RANGE_LEFT (last) && code <= RANGE_RIGHT (last))
390              return (ucs2_t)tblp[RANGE_INDEX (last)
391                                  + code - RANGE_LEFT (last)];
392          }
393    }
394 
395  if (tblp[UNRANGED_NUM_INDEX] > 0)
396    {
397      first = 0;
398      last = tblp[UNRANGED_NUM_INDEX] - 1;
399 
400      do
401        {
402          int c;
403
404          center = (last - first)/2;
405          cur = center + first;
406          c = tblp[UNRANGED_INDEX (cur)];
407 
408          if (code > c)
409            first = cur;
410          else if (code < c)
411            last = cur;
412          else
413            return (ucs2_t)tblp[UNRANGED_INDEX (cur) + 1];
414        } while (center > 0);
415
416        if (last - first == 1)
417          {
418            if (code == tblp[UNRANGED_INDEX (first)])
419              return (ucs2_t)tblp[UNRANGED_INDEX (first) + 1];
420            if (code == tblp[UNRANGED_INDEX (last)])
421              return (ucs2_t)tblp[UNRANGED_INDEX (last) + 1];
422          }
423    }
424
425  return (ucs2_t)INVALC;
426}
427
428#ifdef _ICONV_ENABLE_EXTERNAL_CCS
429
430#define _16BIT_ELT(offset) \
431    ICONV_BETOHS(*((__uint16_t *)(buf + (offset))))
432#define _32BIT_ELT(offset) \
433    ICONV_BETOHL(*((__uint32_t *)(buf + (offset))))
434
435/*
436 * load_file - load conversion table from external file and initialize
437 *             iconv_ccs_desc_t object.
438 *
439 * PARAMETERS:
440 *    struct _reent *rptr - reent structure of current thread/process.
441 *    const char *name - encoding name.
442 *    int direction - conversion direction.
443 *
444 * DESCRIPTION:
445 *    Loads conversion table of appropriate endianess from external file
446 *    and initializes 'iconv_ccs_desc_t' table description structure.
447 *    If 'direction' is 0 - load "To UCS" table, else load "From UCS"
448 *    table.
449 *
450 * RETURN:
451 *    iconv_ccs_desc_t * pointer is success, NULL if failure.
452 */
453static const iconv_ccs_desc_t *
454load_file (struct _reent *rptr,
455                  const char *name,
456                  int direction)
457{
458  int fd;
459  const unsigned char *buf;
460  int tbllen, hdrlen;
461  off_t off;
462  const char *fname;
463  iconv_ccs_desc_t *ccsp = NULL;
464  int nmlen = strlen(name);
465  /* Since CCS table name length can vary - it is aligned (by adding extra
466   * bytes to it's end) to 4-byte boundary. */
467  int alignment = nmlen & 3 ? 4 - (nmlen & 3) : 0;
468 
469  nmlen = strlen(name);
470 
471  hdrlen = nmlen + EXTTABLE_HEADER_LEN + alignment;
472
473  if ((fname = _iconv_nls_construct_filename (rptr, name, ICONV_SUBDIR,
474                                              ICONV_DATA_EXT)) == NULL)
475    return NULL;
476 
477  if ((fd = _open_r (rptr, fname, O_RDONLY, S_IRUSR)) == -1)
478    goto error1;
479 
480  if ((buf = (const unsigned char *)_malloc_r (rptr, hdrlen)) == NULL)
481    goto error2;
482
483  if (_read_r (rptr, fd, (void *)buf, hdrlen) != hdrlen)
484    goto error3;
485
486  if (_16BIT_ELT (EXTTABLE_VERSION_OFF) != TABLE_VERSION_1
487      || _32BIT_ELT (EXTTABLE_CCSNAME_LEN_OFF) != nmlen
488      || strncmp (buf + EXTTABLE_CCSNAME_OFF, name, nmlen) != 0)
489    goto error3; /* Bad file */
490
491  if ((ccsp = (iconv_ccs_desc_t *)
492           _calloc_r (rptr, 1, sizeof (iconv_ccs_desc_t))) == NULL)
493    goto error3;
494 
495  ccsp->bits = _16BIT_ELT (EXTTABLE_BITS_OFF);
496  ccsp->type = TABLE_EXTERNAL;
497
498  /* Add 4-byte alignment to name length */
499  nmlen += alignment;
500
501  if (ccsp->bits == TABLE_8BIT)
502    {
503      if (direction == 0) /* Load "To UCS" table */
504        {
505          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
506          tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
507        }
508      else /* Load "From UCS" table */
509        {
510          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
511          tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
512        }
513    }
514  else if (ccsp->bits == TABLE_16BIT)
515    {
516      if (direction == 0) /* Load "To UCS" table */
517        {
518#ifdef TABLE_USE_SIZE_OPTIMIZATION
519          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SIZE_OFF);
520          tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SIZE_LEN_OFF);
521#else
522          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
523          tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
524#endif
525        }
526      else /* Load "From UCS" table */
527        {
528#ifdef TABLE_USE_SIZE_OPTIMIZATION
529          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SIZE_OFF);
530          tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SIZE_LEN_OFF);
531#else
532          off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
533          tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
534#endif
535        }
536#ifdef TABLE_USE_SIZE_OPTIMIZATION
537      ccsp->optimization = TABLE_SIZE_OPTIMIZED; 
538#else
539      ccsp->optimization = TABLE_SPEED_OPTIMIZED;
540#endif
541    }
542  else
543    goto error4; /* Bad file */
544
545  if (off == EXTTABLE_NO_TABLE)
546    goto error4; /* No correspondent table in file */
547
548  if ((ccsp->tbl = (ucs2_t *)_malloc_r (rptr, tbllen)) == NULL)
549    goto error4;
550
551  if (_lseek_r (rptr, fd, off, SEEK_SET) == (off_t)-1
552      || _read_r (rptr, fd, (void *)ccsp->tbl, tbllen) != tbllen)
553    goto error5;
554
555  goto normal_exit;
556
557error5:
558  _free_r (rptr, (void *)ccsp->tbl);
559  ccsp->tbl = NULL;
560error4:
561  _free_r (rptr, (void *)ccsp);
562  ccsp = NULL;
563error3:
564normal_exit:
565  _free_r (rptr, (void *)buf);
566error2:
567  if (_close_r (rptr, fd) == -1)
568    {
569      if (ccsp != NULL)
570        {
571          if (ccsp->tbl != NULL)
572            _free_r (rptr, (void *)ccsp->tbl);
573          _free_r (rptr, (void *)ccsp);
574        }
575      ccsp = NULL;
576    }
577error1:
578  _free_r (rptr, (void *)fname);
579  return ccsp;
580}
581#endif
582
583#endif /* ICONV_TO_UCS_CES_TABLE || ICONV_FROM_UCS_CES_TABLE */
584
Note: See TracBrowser for help on using the repository browser.