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 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
);
74 * Interface data and functions implementation.
77 table_close (struct _reent
*rptr
,
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
);
89 #if defined (ICONV_FROM_UCS_CES_TABLE)
91 table_init_from_ucs (struct _reent
*rptr
,
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
];
107 if (biccsp
->from_ucs
== NULL
108 || (ccsp
= (iconv_ccs_desc_t
*)
109 _malloc_r (rptr
, sizeof (iconv_ccs_desc_t
))) == NULL
)
112 ccsp
->type
= TABLE_BUILTIN
;
113 ccsp
->bits
= biccsp
->bits
;
114 ccsp
->optimization
= biccsp
->from_ucs_type
;
115 ccsp
->tbl
= biccsp
->from_ucs
;
120 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
121 return (void *)load_file (rptr
, encoding
, 1);
128 table_convert_from_ucs (void *data
,
130 unsigned char **outbuf
,
131 size_t *outbytesleft
)
133 const iconv_ccs_desc_t
*ccsp
= (iconv_ccs_desc_t
*)data
;
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
);
144 return (size_t)ICONV_CES_INVALID_CHARACTER
;
145 **outbuf
= (unsigned char)code
;
150 else if (ccsp
->optimization
== TABLE_SPEED_OPTIMIZED
)
151 code
= find_code_speed ((ucs2_t
)in
, ccsp
->tbl
);
153 code
= find_code_size ((ucs2_t
)in
, ccsp
->tbl
);
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
;
168 #endif /* ICONV_FROM_UCS_CES_TABLE */
170 #if defined (ICONV_TO_UCS_CES_TABLE)
172 table_init_to_ucs (struct _reent
*rptr
,
173 const char *encoding
)
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
];
188 if (biccsp
->to_ucs
== NULL
189 || (ccsp
= (iconv_ccs_desc_t
*)
190 _malloc_r (rptr
, sizeof (iconv_ccs_desc_t
))) == NULL
)
193 ccsp
->type
= TABLE_BUILTIN
;
194 ccsp
->bits
= biccsp
->bits
;
195 ccsp
->optimization
= biccsp
->to_ucs_type
;
196 ccsp
->tbl
= biccsp
->to_ucs
;
201 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
202 return (void *)load_file (rptr
, encoding
, 0);
209 table_convert_to_ucs (void *data
,
210 const unsigned char **inbuf
,
213 const iconv_ccs_desc_t
*ccsp
= (iconv_ccs_desc_t
*)data
;
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
];
224 return (ucs4_t
)ICONV_CES_INVALID_CHARACTER
;
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),
238 ucs
= find_code_speed((ucs2_t
)**inbuf
<< 8 | (ucs2_t
)*(*inbuf
+ 1),
242 return (ucs4_t
)ICONV_CES_INVALID_CHARACTER
;
248 #endif /* ICONV_TO_UCS_CES_TABLE */
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
=
263 table_get_mb_cur_max
,
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
=
277 table_get_mb_cur_max
,
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.
293 * ucs2_t code - code whose mapping to find.
294 * const __uint16_t *tblp - table pointer.
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];
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.
315 * ucs2_t code - code whose mapping to find.
316 * const __uint16_t *tblp - table pointer.
319 * Code that corresponds to 'code'.
321 static __inline ucs2_t
322 find_code_speed_8bit (ucs2_t code
,
323 const unsigned char *tblp
)
328 if (code
== ((ucs2_t
*)tblp
)[0])
331 idx
= ((ucs2_t
*)tblp
)[1 + (code
>> 8)];
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])
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.
354 * ucs2_t code - code whose mapping to find.
355 * const __uint16_t *tblp - table pointer.
358 * Code that corresponds to 'code'.
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)
369 last
= tblp
[RANGES_NUM_INDEX
] - 1;
373 center
= (last
- first
)/2;
374 cur
= center
+ first
;
376 if (code
> RANGE_RIGHT (cur
))
378 else if (code
< RANGE_LEFT (cur
))
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)
398 last
= tblp
[UNRANGED_NUM_INDEX
] - 1;
404 center
= (last
- first
)/2;
405 cur
= center
+ first
;
406 c
= tblp
[UNRANGED_INDEX (cur
)];
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.
440 * struct _reent *rptr - reent structure of current thread/process.
441 * const char *name - encoding name.
442 * int direction - conversion direction.
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"
451 * iconv_ccs_desc_t * pointer is success, NULL if failure.
453 static const iconv_ccs_desc_t
*
454 load_file (struct _reent
*rptr
,
459 const unsigned char *buf
;
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
)
477 if ((fd
= _open_r (rptr
, fname
, O_RDONLY
, S_IRUSR
)) == -1)
480 if ((buf
= (const unsigned char *)_malloc_r (rptr
, hdrlen
)) == NULL
)
483 if (_read_r (rptr
, fd
, (void *)buf
, hdrlen
) != hdrlen
)
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
)
495 ccsp
->bits
= _16BIT_ELT (EXTTABLE_BITS_OFF
);
496 ccsp
->type
= TABLE_EXTERNAL
;
498 /* Add 4-byte alignment to name length */
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
);
522 off
= (off_t
)_32BIT_ELT (nmlen
+ EXTTABLE_TO_SPEED_OFF
);
523 tbllen
= _32BIT_ELT (nmlen
+ EXTTABLE_TO_SPEED_LEN_OFF
);
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
);
532 off
= (off_t
)_32BIT_ELT (nmlen
+ EXTTABLE_FROM_SPEED_OFF
);
533 tbllen
= _32BIT_ELT (nmlen
+ EXTTABLE_FROM_SPEED_LEN_OFF
);
536 #ifdef TABLE_USE_SIZE_OPTIMIZATION
537 ccsp
->optimization
= TABLE_SIZE_OPTIMIZED
;
539 ccsp
->optimization
= TABLE_SPEED_OPTIMIZED
;
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
)
551 if (_lseek_r (rptr
, fd
, off
, SEEK_SET
) == (off_t
)-1
552 || _read_r (rptr
, fd
, (void *)ccsp
->tbl
, tbllen
) != tbllen
)
558 _free_r (rptr
, (void *)ccsp
->tbl
);
561 _free_r (rptr
, (void *)ccsp
);
565 _free_r (rptr
, (void *)buf
);
567 if (_close_r (rptr
, fd
) == -1)
571 if (ccsp
->tbl
!= NULL
)
572 _free_r (rptr
, (void *)ccsp
->tbl
);
573 _free_r (rptr
, (void *)ccsp
);
578 _free_r (rptr
, (void *)fname
);
583 #endif /* ICONV_TO_UCS_CES_TABLE || ICONV_FROM_UCS_CES_TABLE */