Cygwin: Add new APIs tc[gs]etwinsize()
[newlib-cygwin.git] / newlib / libc / iconv / ces / table.c
blobc8ef218a1e935bebfebc289f0c7d7e18230885ca
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 "cesbi.h"
28 #if defined (ICONV_TO_UCS_CES_TABLE) \
29 || defined (ICONV_FROM_UCS_CES_TABLE)
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"
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.
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.
59 static ucs2_t
60 find_code_size (ucs2_t code, const __uint16_t *tblp);
62 static __inline ucs2_t
63 find_code_speed (ucs2_t code, const __uint16_t *tblp);
65 static __inline ucs2_t
66 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 load_file (struct _reent *rptr, const char *name, int direction);
71 #endif
74 * Interface data and functions implementation.
76 static size_t
77 table_close (struct _reent *rptr,
78 void *data)
80 const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
82 if (ccsp->type == TABLE_EXTERNAL)
83 _free_r (rptr, (void *)ccsp->tbl);
85 _free_r( rptr, (void *)ccsp);
86 return 0;
89 #if defined (ICONV_FROM_UCS_CES_TABLE)
90 static void *
91 table_init_from_ucs (struct _reent *rptr,
92 const char *encoding)
94 int i;
95 const iconv_ccs_t *biccsp = NULL;
96 iconv_ccs_desc_t *ccsp;
98 for (i = 0; _iconv_ccs[i] != NULL; i++)
99 if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
101 biccsp = _iconv_ccs[i];
102 break;
105 if (biccsp != NULL)
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;
112 ccsp->type = TABLE_BUILTIN;
113 ccsp->bits = biccsp->bits;
114 ccsp->optimization = biccsp->from_ucs_type;
115 ccsp->tbl = biccsp->from_ucs;
117 return (void *)ccsp;
120 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
121 return (void *)load_file (rptr, encoding, 1);
122 #else
123 return NULL;
124 #endif
127 static size_t
128 table_convert_from_ucs (void *data,
129 ucs4_t in,
130 unsigned char **outbuf,
131 size_t *outbytesleft)
133 const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
134 ucs2_t code;
136 if (in > 0xFFFF || in == INVALC)
137 return (size_t)ICONV_CES_INVALID_CHARACTER;
139 if (ccsp->bits == TABLE_8BIT)
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;
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);
155 if (code == INVALC)
156 return (size_t)ICONV_CES_INVALID_CHARACTER;
158 if (*outbytesleft < 2)
159 return (size_t)ICONV_CES_NOSPACE;
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;
168 #endif /* ICONV_FROM_UCS_CES_TABLE */
170 #if defined (ICONV_TO_UCS_CES_TABLE)
171 static void *
172 table_init_to_ucs (struct _reent *rptr,
173 const char *encoding)
175 int i;
176 const iconv_ccs_t *biccsp = NULL;
177 iconv_ccs_desc_t *ccsp;
179 for (i = 0; _iconv_ccs[i] != NULL; i++)
180 if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
182 biccsp = _iconv_ccs[i];
183 break;
186 if (biccsp != NULL)
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;
193 ccsp->type = TABLE_BUILTIN;
194 ccsp->bits = biccsp->bits;
195 ccsp->optimization = biccsp->to_ucs_type;
196 ccsp->tbl = biccsp->to_ucs;
198 return (void *)ccsp;
201 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
202 return (void *)load_file (rptr, encoding, 0);
203 #else
204 return NULL;
205 #endif
208 static ucs4_t
209 table_convert_to_ucs (void *data,
210 const unsigned char **inbuf,
211 size_t *inbytesleft)
213 const iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
214 ucs2_t ucs;
216 if (ccsp->bits == TABLE_8BIT)
218 if (*inbytesleft < 1)
219 return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
221 ucs = (ucs2_t)ccsp->tbl[**inbuf];
223 if (ucs == INVALC)
224 return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
226 *inbytesleft -= 1;
227 *inbuf += 1;
228 return (ucs4_t)ucs;
231 if (*inbytesleft < 2)
232 return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
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);
241 if (ucs == INVALC)
242 return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
244 *inbuf += 2;
245 *inbytesleft -= 2;
246 return (ucs4_t)ucs;
248 #endif /* ICONV_TO_UCS_CES_TABLE */
250 static int
251 table_get_mb_cur_max (void *data)
253 return ((iconv_ccs_desc_t *)data)->bits/8;
257 #if defined (ICONV_TO_UCS_CES_TABLE)
258 const iconv_to_ucs_ces_handlers_t
259 _iconv_to_ucs_ces_handlers_table =
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
269 #endif /* ICONV_FROM_UCS_CES_TABLE */
271 #if defined (ICONV_FROM_UCS_CES_TABLE)
272 const iconv_from_ucs_ces_handlers_t
273 _iconv_from_ucs_ces_handlers_table =
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
283 #endif /* ICONV_TO_UCS_CES_TABLE */
286 * Supplementary functions.
290 * find_code_speed - find code in 16 bit speed-optimized table.
292 * PARAMETERS:
293 * ucs2_t code - code whose mapping to find.
294 * const __uint16_t *tblp - table pointer.
296 * RETURN:
297 * Code that corresponds to 'code'.
299 static __inline ucs2_t
300 find_code_speed (ucs2_t code,
301 const __uint16_t *tblp)
303 int idx = tblp[code >> 8];
305 if (idx == INVBLK)
306 return (ucs2_t)INVALC;
308 return (ucs2_t)tblp[(code & 0x00FF) + idx];
312 * find_code_speed_8bit - find code in 8 bit speed-optimized table.
314 * PARAMETERS:
315 * ucs2_t code - code whose mapping to find.
316 * const __uint16_t *tblp - table pointer.
318 * RETURN:
319 * Code that corresponds to 'code'.
321 static __inline ucs2_t
322 find_code_speed_8bit (ucs2_t code,
323 const unsigned char *tblp)
325 int idx;
326 unsigned char ccs;
328 if (code == ((ucs2_t *)tblp)[0])
329 return (ucs2_t)0xFF;
331 idx = ((ucs2_t *)tblp)[1 + (code >> 8)];
333 if (idx == INVBLK)
334 return (ucs2_t)INVALC;
336 ccs = tblp[(code & 0x00FF) + idx];
338 return ccs == 0xFF ? (ucs2_t)INVALC : (ucs2_t)ccs;
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)
351 * find_code_size - find code in 16 bit size-optimized table.
353 * PARAMETERS:
354 * ucs2_t code - code whose mapping to find.
355 * const __uint16_t *tblp - table pointer.
357 * RETURN:
358 * Code that corresponds to 'code'.
360 static ucs2_t
361 find_code_size (ucs2_t code,
362 const __uint16_t *tblp)
364 int first, last, cur, center;
366 if (tblp[RANGES_NUM_INDEX] > 0)
368 first = 0;
369 last = tblp[RANGES_NUM_INDEX] - 1;
373 center = (last - first)/2;
374 cur = center + first;
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);
384 if (last - first == 1)
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)];
395 if (tblp[UNRANGED_NUM_INDEX] > 0)
397 first = 0;
398 last = tblp[UNRANGED_NUM_INDEX] - 1;
402 int c;
404 center = (last - first)/2;
405 cur = center + first;
406 c = tblp[UNRANGED_INDEX (cur)];
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);
416 if (last - first == 1)
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];
425 return (ucs2_t)INVALC;
428 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
430 #define _16BIT_ELT(offset) \
431 ICONV_BETOHS(*((__uint16_t *)(buf + (offset))))
432 #define _32BIT_ELT(offset) \
433 ICONV_BETOHL(*((__uint32_t *)(buf + (offset))))
436 * load_file - load conversion table from external file and initialize
437 * iconv_ccs_desc_t object.
439 * PARAMETERS:
440 * struct _reent *rptr - reent structure of current thread/process.
441 * const char *name - encoding name.
442 * int direction - conversion direction.
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.
450 * RETURN:
451 * iconv_ccs_desc_t * pointer is success, NULL if failure.
453 static const iconv_ccs_desc_t *
454 load_file (struct _reent *rptr,
455 const char *name,
456 int direction)
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;
469 nmlen = strlen(name);
471 hdrlen = nmlen + EXTTABLE_HEADER_LEN + alignment;
473 if ((fname = _iconv_nls_construct_filename (rptr, name, ICONV_SUBDIR,
474 ICONV_DATA_EXT)) == NULL)
475 return NULL;
477 if ((fd = _open_r (rptr, fname, O_RDONLY, S_IRUSR)) == -1)
478 goto error1;
480 if ((buf = (const unsigned char *)_malloc_r (rptr, hdrlen)) == NULL)
481 goto error2;
483 if (_read_r (rptr, fd, (void *)buf, hdrlen) != hdrlen)
484 goto error3;
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 */
491 if ((ccsp = (iconv_ccs_desc_t *)
492 _calloc_r (rptr, 1, sizeof (iconv_ccs_desc_t))) == NULL)
493 goto error3;
495 ccsp->bits = _16BIT_ELT (EXTTABLE_BITS_OFF);
496 ccsp->type = TABLE_EXTERNAL;
498 /* Add 4-byte alignment to name length */
499 nmlen += alignment;
501 if (ccsp->bits == TABLE_8BIT)
503 if (direction == 0) /* Load "To UCS" table */
505 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
506 tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
508 else /* Load "From UCS" table */
510 off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
511 tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
514 else if (ccsp->bits == TABLE_16BIT)
516 if (direction == 0) /* Load "To UCS" table */
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
526 else /* Load "From UCS" table */
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
536 #ifdef TABLE_USE_SIZE_OPTIMIZATION
537 ccsp->optimization = TABLE_SIZE_OPTIMIZED;
538 #else
539 ccsp->optimization = TABLE_SPEED_OPTIMIZED;
540 #endif
542 else
543 goto error4; /* Bad file */
545 if (off == EXTTABLE_NO_TABLE)
546 goto error4; /* No correspondent table in file */
548 if ((ccsp->tbl = (ucs2_t *)_malloc_r (rptr, tbllen)) == NULL)
549 goto error4;
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;
555 goto normal_exit;
557 error5:
558 _free_r (rptr, (void *)ccsp->tbl);
559 ccsp->tbl = NULL;
560 error4:
561 _free_r (rptr, (void *)ccsp);
562 ccsp = NULL;
563 error3:
564 normal_exit:
565 _free_r (rptr, (void *)buf);
566 error2:
567 if (_close_r (rptr, fd) == -1)
569 if (ccsp != NULL)
571 if (ccsp->tbl != NULL)
572 _free_r (rptr, (void *)ccsp->tbl);
573 _free_r (rptr, (void *)ccsp);
575 ccsp = NULL;
577 error1:
578 _free_r (rptr, (void *)fname);
579 return ccsp;
581 #endif
583 #endif /* ICONV_TO_UCS_CES_TABLE || ICONV_FROM_UCS_CES_TABLE */