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
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
28 #if defined (ICONV_TO_UCS_CES_TABLE) \
29 || defined (ICONV_FROM_UCS_CES_TABLE)
34 #include <sys/types.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"
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
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).
56 * 16 bit encodings are assumed to be Big Endian.
60 _EXFUN(find_code_size, (ucs2_t code, _CONST __uint16_t *tblp));
62 static __inline ucs2_t
63 _EXFUN(find_code_speed, (ucs2_t code, _CONST __uint16_t *tblp));
65 static __inline ucs2_t
66 _EXFUN(find_code_speed_8bit, (ucs2_t code, _CONST unsigned char *tblp));
68 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
69 static _CONST iconv_ccs_desc_t *
70 _EXFUN(load_file, (struct _reent *rptr, _CONST char *name, int direction));
74 * Interface data and functions implementation.
77 _DEFUN(table_close, (rptr, data),
78 struct _reent *rptr _AND
81 _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
83 if (ccsp->type == TABLE_EXTERNAL)
84 _free_r (rptr, (_VOID_PTR)ccsp->tbl);
86 _free_r( rptr, (_VOID_PTR)ccsp);
90 #if defined (ICONV_FROM_UCS_CES_TABLE)
92 _DEFUN(table_init_from_ucs, (rptr, encoding),
93 struct _reent *rptr _AND
94 _CONST char *encoding)
97 _CONST iconv_ccs_t *biccsp = NULL;
98 iconv_ccs_desc_t *ccsp;
100 for (i = 0; _iconv_ccs[i] != NULL; i++)
101 if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
103 biccsp = _iconv_ccs[i];
109 if (biccsp->from_ucs == NULL
110 || (ccsp = (iconv_ccs_desc_t *)
111 _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
114 ccsp->type = TABLE_BUILTIN;
115 ccsp->bits = biccsp->bits;
116 ccsp->optimization = biccsp->from_ucs_type;
117 ccsp->tbl = biccsp->from_ucs;
119 return (_VOID_PTR)ccsp;
122 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
123 return (_VOID_PTR)load_file (rptr, encoding, 1);
130 _DEFUN(table_convert_from_ucs, (data, in, outbuf, outbytesleft),
133 unsigned char **outbuf _AND
134 size_t *outbytesleft)
136 _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
139 if (in > 0xFFFF || in == INVALC)
140 return (size_t)ICONV_CES_INVALID_CHARACTER;
142 if (ccsp->bits == TABLE_8BIT)
144 code = find_code_speed_8bit ((ucs2_t)in,
145 (_CONST unsigned char *)ccsp->tbl);
147 return (size_t)ICONV_CES_INVALID_CHARACTER;
148 **outbuf = (unsigned char)code;
153 else if (ccsp->optimization == TABLE_SPEED_OPTIMIZED)
154 code = find_code_speed ((ucs2_t)in, ccsp->tbl);
156 code = find_code_size ((ucs2_t)in, ccsp->tbl);
159 return (size_t)ICONV_CES_INVALID_CHARACTER;
161 if (*outbytesleft < 2)
162 return (size_t)ICONV_CES_NOSPACE;
164 /* We can't store whole word since **outbuf may be not 2-byte aligned */
165 **outbuf = (unsigned char)((ucs2_t)code >> 8);
166 *(*outbuf + 1) = (unsigned char)code;
171 #endif /* ICONV_FROM_UCS_CES_TABLE */
173 #if defined (ICONV_TO_UCS_CES_TABLE)
175 _DEFUN(table_init_to_ucs, (rptr, encoding),
176 struct _reent *rptr _AND
177 _CONST char *encoding)
180 _CONST iconv_ccs_t *biccsp = NULL;
181 iconv_ccs_desc_t *ccsp;
183 for (i = 0; _iconv_ccs[i] != NULL; i++)
184 if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
186 biccsp = _iconv_ccs[i];
192 if (biccsp->to_ucs == NULL
193 || (ccsp = (iconv_ccs_desc_t *)
194 _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
197 ccsp->type = TABLE_BUILTIN;
198 ccsp->bits = biccsp->bits;
199 ccsp->optimization = biccsp->to_ucs_type;
200 ccsp->tbl = biccsp->to_ucs;
202 return (_VOID_PTR)ccsp;
205 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
206 return (_VOID_PTR)load_file (rptr, encoding, 0);
213 _DEFUN(table_convert_to_ucs, (data, inbuf, inbytesleft),
215 _CONST unsigned char **inbuf _AND
218 _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
221 if (ccsp->bits == TABLE_8BIT)
223 if (*inbytesleft < 1)
224 return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
226 ucs = (ucs2_t)ccsp->tbl[**inbuf];
229 return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
236 if (*inbytesleft < 2)
237 return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
239 if (ccsp->optimization == TABLE_SIZE_OPTIMIZED)
240 ucs = find_code_size((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
243 ucs = find_code_speed((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
247 return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
253 #endif /* ICONV_TO_UCS_CES_TABLE */
256 _DEFUN(table_get_mb_cur_max, (data),
259 return ((iconv_ccs_desc_t *)data)->bits/8;
263 #if defined (ICONV_TO_UCS_CES_TABLE)
264 _CONST iconv_to_ucs_ces_handlers_t
265 _iconv_to_ucs_ces_handlers_table =
269 table_get_mb_cur_max,
275 #endif /* ICONV_FROM_UCS_CES_TABLE */
277 #if defined (ICONV_FROM_UCS_CES_TABLE)
278 _CONST iconv_from_ucs_ces_handlers_t
279 _iconv_from_ucs_ces_handlers_table =
283 table_get_mb_cur_max,
287 table_convert_from_ucs
289 #endif /* ICONV_TO_UCS_CES_TABLE */
292 * Supplementary functions.
296 * find_code_speed - find code in 16 bit speed-optimized table.
299 * ucs2_t code - code whose mapping to find.
300 * _CONST __uint16_t *tblp - table pointer.
303 * Code that corresponds to 'code'.
305 static __inline ucs2_t
306 _DEFUN(find_code_speed, (code, tblp),
308 _CONST __uint16_t *tblp)
310 int idx = tblp[code >> 8];
313 return (ucs2_t)INVALC;
315 return (ucs2_t)tblp[(code & 0x00FF) + idx];
319 * find_code_speed_8bit - find code in 8 bit speed-optimized table.
322 * ucs2_t code - code whose mapping to find.
323 * _CONST __uint16_t *tblp - table pointer.
326 * Code that corresponds to 'code'.
328 static __inline ucs2_t
329 _DEFUN(find_code_speed_8bit, (code, tblp),
331 _CONST unsigned char *tblp)
336 if (code == ((ucs2_t *)tblp)[0])
339 idx = ((ucs2_t *)tblp)[1 + (code >> 8)];
342 return (ucs2_t)INVALC;
344 ccs = tblp[(code & 0x00FF) + idx];
346 return ccs == 0xFF ? (ucs2_t)INVALC : (ucs2_t)ccs;
349 /* Left range boundary */
350 #define RANGE_LEFT(n) (tblp[FIRST_RANGE_INDEX + (n)*3 + 0])
351 /* Right range boundary */
352 #define RANGE_RIGHT(n) (tblp[FIRST_RANGE_INDEX + (n)*3 + 1])
354 #define RANGE_INDEX(n) (tblp[FIRST_RANGE_INDEX + (n)*3 + 2])
355 /* Un-ranged offset */
356 #define UNRANGED_INDEX(n) (tblp[FIRST_UNRANGED_INDEX_INDEX] + (n)*2)
359 * find_code_size - find code in 16 bit size-optimized table.
362 * ucs2_t code - code whose mapping to find.
363 * _CONST __uint16_t *tblp - table pointer.
366 * Code that corresponds to 'code'.
369 _DEFUN(find_code_size, (code, tblp),
371 _CONST __uint16_t *tblp)
373 int first, last, cur, center;
375 if (tblp[RANGES_NUM_INDEX] > 0)
378 last = tblp[RANGES_NUM_INDEX] - 1;
382 center = (last - first)/2;
383 cur = center + first;
385 if (code > RANGE_RIGHT (cur))
387 else if (code < RANGE_LEFT (cur))
390 return (ucs2_t)tblp[RANGE_INDEX (cur) + code - RANGE_LEFT (cur)];
391 } while (center > 0);
393 if (last - first == 1)
395 if (code >= RANGE_LEFT (first) && code <= RANGE_RIGHT (first))
396 return (ucs2_t)tblp[RANGE_INDEX (first)
397 + code - RANGE_LEFT (first)];
398 if (code >= RANGE_LEFT (last) && code <= RANGE_RIGHT (last))
399 return (ucs2_t)tblp[RANGE_INDEX (last)
400 + code - RANGE_LEFT (last)];
404 if (tblp[UNRANGED_NUM_INDEX] > 0)
407 last = tblp[UNRANGED_NUM_INDEX] - 1;
413 center = (last - first)/2;
414 cur = center + first;
415 c = tblp[UNRANGED_INDEX (cur)];
422 return (ucs2_t)tblp[UNRANGED_INDEX (cur) + 1];
423 } while (center > 0);
425 if (last - first == 1)
427 if (code == tblp[UNRANGED_INDEX (first)])
428 return (ucs2_t)tblp[UNRANGED_INDEX (first) + 1];
429 if (code == tblp[UNRANGED_INDEX (last)])
430 return (ucs2_t)tblp[UNRANGED_INDEX (last) + 1];
434 return (ucs2_t)INVALC;
437 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
439 #define _16BIT_ELT(offset) \
440 ICONV_BETOHS(*((__uint16_t *)(buf + (offset))))
441 #define _32BIT_ELT(offset) \
442 ICONV_BETOHL(*((__uint32_t *)(buf + (offset))))
445 * load_file - load conversion table from external file and initialize
446 * iconv_ccs_desc_t object.
449 * struct _reent *rptr - reent structure of current thread/process.
450 * _CONST char *name - encoding name.
451 * int direction - conversion direction.
454 * Loads conversion table of appropriate endianess from external file
455 * and initializes 'iconv_ccs_desc_t' table description structure.
456 * If 'direction' is 0 - load "To UCS" table, else load "From UCS"
460 * iconv_ccs_desc_t * pointer is success, NULL if failure.
462 static _CONST iconv_ccs_desc_t *
463 _DEFUN(load_file, (rptr, name, direction),
464 struct _reent *rptr _AND
465 _CONST char *name _AND
469 _CONST unsigned char *buf;
473 iconv_ccs_desc_t *ccsp = NULL;
474 int nmlen = strlen(name);
475 /* Since CCS table name length can vary - it is aligned (by adding extra
476 * bytes to it's end) to 4-byte boundary. */
477 int alignment = nmlen & 3 ? 4 - (nmlen & 3) : 0;
479 nmlen = strlen(name);
481 hdrlen = nmlen + EXTTABLE_HEADER_LEN + alignment;
483 if ((fname = _iconv_nls_construct_filename (rptr, name, ICONV_SUBDIR,
484 ICONV_DATA_EXT)) == NULL)
487 if ((fd = _open_r (rptr, fname, O_RDONLY, S_IRUSR)) == -1)
490 if ((buf = (_CONST unsigned char *)_malloc_r (rptr, hdrlen)) == NULL)
493 if (_read_r (rptr, fd, (_VOID_PTR)buf, hdrlen) != hdrlen)
496 if (_16BIT_ELT (EXTTABLE_VERSION_OFF) != TABLE_VERSION_1
497 || _32BIT_ELT (EXTTABLE_CCSNAME_LEN_OFF) != nmlen
498 || strncmp (buf + EXTTABLE_CCSNAME_OFF, name, nmlen) != 0)
499 goto error3; /* Bad file */
501 if ((ccsp = (iconv_ccs_desc_t *)
502 _calloc_r (rptr, 1, sizeof (iconv_ccs_desc_t))) == NULL)
505 ccsp->bits = _16BIT_ELT (EXTTABLE_BITS_OFF);
506 ccsp->type = TABLE_EXTERNAL;
508 /* Add 4-byte alignment to name length */
511 if (ccsp->bits == TABLE_8BIT)
513 if (direction == 0) /* Load "To UCS" table */
515 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
516 tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
518 else /* Load "From UCS" table */
520 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
521 tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
524 else if (ccsp->bits == TABLE_16BIT)
526 if (direction == 0) /* Load "To UCS" table */
528 #ifdef TABLE_USE_SIZE_OPTIMIZATION
529 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SIZE_OFF);
530 tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SIZE_LEN_OFF);
532 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
533 tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
536 else /* Load "From UCS" table */
538 #ifdef TABLE_USE_SIZE_OPTIMIZATION
539 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SIZE_OFF);
540 tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SIZE_LEN_OFF);
542 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
543 tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
546 #ifdef TABLE_USE_SIZE_OPTIMIZATION
547 ccsp->optimization = TABLE_SIZE_OPTIMIZED;
549 ccsp->optimization = TABLE_SPEED_OPTIMIZED;
553 goto error4; /* Bad file */
555 if (off == EXTTABLE_NO_TABLE)
556 goto error4; /* No correspondent table in file */
558 if ((ccsp->tbl = (ucs2_t *)_malloc_r (rptr, tbllen)) == NULL)
561 if (_lseek_r (rptr, fd, off, SEEK_SET) == (off_t)-1
562 || _read_r (rptr, fd, (_VOID_PTR)ccsp->tbl, tbllen) != tbllen)
568 _free_r (rptr, (_VOID_PTR)ccsp->tbl);
571 _free_r (rptr, (_VOID_PTR)ccsp);
575 _free_r (rptr, (_VOID_PTR)buf);
577 if (_close_r (rptr, fd) == -1)
581 if (ccsp->tbl != NULL)
582 _free_r (rptr, (_VOID_PTR)ccsp->tbl);
583 _free_r (rptr, (_VOID_PTR)ccsp);
588 _free_r (rptr, (_VOID_PTR)fname);
593 #endif /* ICONV_TO_UCS_CES_TABLE || ICONV_FROM_UCS_CES_TABLE */