OSDN Git Service

2004-06-25 Artem B. Bityuckiy <dedekind@oktetlabs.ru>
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / iconv / ces / table.c
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
59 static ucs2_t
60 _EXFUN(find_code_size, (ucs2_t code, _CONST __uint16_t *tblp));
61
62 static __inline ucs2_t
63 _EXFUN(find_code_speed, (ucs2_t code, _CONST __uint16_t *tblp));
64
65 static __inline ucs2_t
66 _EXFUN(find_code_speed_8bit, (ucs2_t code, _CONST unsigned char *tblp));
67
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));
71 #endif
72
73 /*
74  * Interface data and functions implementation.
75  */
76 static size_t
77 _DEFUN(table_close, (rptr, data),
78                     struct _reent *rptr _AND
79                     _VOID_PTR data)
80 {
81   _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
82
83   if (ccsp->type == TABLE_EXTERNAL)
84     _free_r (rptr, (_VOID_PTR)ccsp->tbl);
85
86   _free_r( rptr, (_VOID_PTR)ccsp);
87   return 0;
88 }
89
90 #if defined (ICONV_FROM_UCS_CES_TABLE)
91 static _VOID_PTR
92 _DEFUN(table_init_from_ucs, (rptr, encoding),
93                             struct _reent *rptr _AND
94                             _CONST char *encoding)
95 {
96   int i;
97   _CONST iconv_ccs_t *biccsp = NULL;
98   iconv_ccs_desc_t *ccsp;
99   
100   for (i = 0; _iconv_ccs[i] != NULL; i++)
101     if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
102       {
103         biccsp = _iconv_ccs[i]; 
104         break;
105       }
106
107   if (biccsp != NULL)
108     {
109       if (biccsp->from_ucs == NULL
110           || (ccsp = (iconv_ccs_desc_t *)
111                      _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
112         return NULL;
113
114       ccsp->type = TABLE_BUILTIN;
115       ccsp->bits = biccsp->bits;
116       ccsp->optimization = biccsp->from_ucs_type;
117       ccsp->tbl = biccsp->from_ucs;
118       
119       return (_VOID_PTR)ccsp;
120     }
121     
122 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
123   return (_VOID_PTR)load_file (rptr, encoding, 1);
124 #else
125   return NULL;
126 #endif
127 }
128
129 static size_t
130 _DEFUN(table_convert_from_ucs, (data, in, outbuf, outbytesleft),
131                                _VOID_PTR data         _AND
132                                ucs4_t in              _AND
133                                unsigned char **outbuf _AND
134                                size_t *outbytesleft)
135 {
136   _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
137   ucs2_t code;
138
139   if (in > 0xFFFF || in == INVALC)
140     return (size_t)ICONV_CES_INVALID_CHARACTER;
141
142   if (ccsp->bits == TABLE_8BIT)
143     {
144       code = find_code_speed_8bit ((ucs2_t)in,
145                                   (_CONST unsigned char *)ccsp->tbl);
146       if (code == INVALC)
147         return (size_t)ICONV_CES_INVALID_CHARACTER;
148       **outbuf = (unsigned char)code;
149       *outbuf += 1;
150       *outbytesleft -= 1;
151       return 1; 
152     }
153   else if (ccsp->optimization == TABLE_SPEED_OPTIMIZED)
154     code = find_code_speed ((ucs2_t)in, ccsp->tbl);
155   else
156     code = find_code_size ((ucs2_t)in, ccsp->tbl);
157
158   if (code == INVALC)
159     return (size_t)ICONV_CES_INVALID_CHARACTER;
160
161   if (*outbytesleft < 2)
162     return (size_t)ICONV_CES_NOSPACE;
163   
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;
167   *outbuf += 2;
168   *outbytesleft -= 2;
169   return 2; 
170 }
171 #endif /* ICONV_FROM_UCS_CES_TABLE */
172
173 #if defined (ICONV_TO_UCS_CES_TABLE)
174 static _VOID_PTR
175 _DEFUN(table_init_to_ucs, (rptr, encoding),
176                           struct _reent *rptr _AND
177                           _CONST char *encoding)
178 {
179   int i;
180   _CONST iconv_ccs_t *biccsp = NULL;
181   iconv_ccs_desc_t *ccsp;
182   
183   for (i = 0; _iconv_ccs[i] != NULL; i++)
184     if (strcmp (_iconv_ccs[i]->name, encoding) == 0)
185       {
186         biccsp = _iconv_ccs[i]; 
187         break;
188       }
189
190   if (biccsp != NULL)
191     {
192       if (biccsp->to_ucs == NULL
193           || (ccsp = (iconv_ccs_desc_t *)
194                      _malloc_r (rptr, sizeof (iconv_ccs_desc_t))) == NULL)
195         return NULL;
196
197       ccsp->type = TABLE_BUILTIN;
198       ccsp->bits = biccsp->bits;
199       ccsp->optimization = biccsp->to_ucs_type;
200       ccsp->tbl = biccsp->to_ucs;
201       
202       return (_VOID_PTR)ccsp;
203     }
204   
205 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
206   return (_VOID_PTR)load_file (rptr, encoding, 0);
207 #else
208   return NULL;
209 #endif
210 }
211
212 static ucs4_t
213 _DEFUN(table_convert_to_ucs, (data, inbuf, inbytesleft),
214                              _VOID_PTR data               _AND
215                              _CONST unsigned char **inbuf _AND
216                              size_t *inbytesleft)
217 {
218   _CONST iconv_ccs_desc_t *ccsp = (iconv_ccs_desc_t *)data;
219   ucs2_t ucs;
220   
221   if (ccsp->bits == TABLE_8BIT)
222     {
223       if (*inbytesleft < 1)
224         return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
225   
226       ucs = (ucs2_t)ccsp->tbl[**inbuf];
227       
228       if (ucs == INVALC)
229         return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
230          
231       *inbytesleft -= 1;
232       *inbuf += 1;
233       return (ucs4_t)ucs; 
234     }
235
236   if (*inbytesleft < 2)
237     return (ucs4_t)ICONV_CES_BAD_SEQUENCE;
238
239   if (ccsp->optimization == TABLE_SIZE_OPTIMIZED)
240     ucs = find_code_size((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
241                          ccsp->tbl);
242   else
243     ucs = find_code_speed((ucs2_t)**inbuf << 8 | (ucs2_t)*(*inbuf + 1),
244                           ccsp->tbl);
245
246   if (ucs == INVALC)
247     return (ucs4_t)ICONV_CES_INVALID_CHARACTER;
248
249   *inbuf += 2;
250   *inbytesleft -= 2;
251   return (ucs4_t)ucs; 
252 }
253 #endif /* ICONV_TO_UCS_CES_TABLE */
254
255 static int
256 _DEFUN(table_get_mb_cur_max, (data),
257                              _VOID_PTR data)
258 {
259   return ((iconv_ccs_desc_t *)data)->bits/8;
260 }
261
262
263 #if defined (ICONV_TO_UCS_CES_TABLE)
264 _CONST iconv_to_ucs_ces_handlers_t
265 _iconv_to_ucs_ces_handlers_table = 
266 {
267   table_init_to_ucs,
268   table_close,
269   table_get_mb_cur_max,
270   NULL,
271   NULL,
272   NULL,
273   table_convert_to_ucs
274 };
275 #endif /* ICONV_FROM_UCS_CES_TABLE */
276
277 #if defined (ICONV_FROM_UCS_CES_TABLE)
278 _CONST iconv_from_ucs_ces_handlers_t
279 _iconv_from_ucs_ces_handlers_table =
280 {
281   table_init_from_ucs,
282   table_close,
283   table_get_mb_cur_max,
284   NULL,
285   NULL,
286   NULL,
287   table_convert_from_ucs
288 };
289 #endif /* ICONV_TO_UCS_CES_TABLE */
290
291 /*
292  * Supplementary functions.
293  */
294
295 /*
296  * find_code_speed - find code in 16 bit speed-optimized table.
297  *
298  * PARAMETERS:
299  *     ucs2_t code - code whose mapping to find.
300  *     _CONST __uint16_t *tblp - table pointer.
301  *
302  * RETURN:
303  *     Code that corresponds to 'code'.
304  */
305 static __inline ucs2_t
306 _DEFUN(find_code_speed, (code, tblp),
307                         ucs2_t code _AND
308                         _CONST __uint16_t *tblp)
309 {
310   int idx = tblp[code >> 8];
311
312   if (idx == INVBLK)
313     return (ucs2_t)INVALC;
314
315   return (ucs2_t)tblp[(code & 0x00FF) + idx];
316 }
317
318 /*
319  * find_code_speed_8bit - find code in 8 bit speed-optimized table.
320  *
321  * PARAMETERS:
322  *     ucs2_t code - code whose mapping to find.
323  *     _CONST __uint16_t *tblp - table pointer.
324  *
325  * RETURN:
326  *     Code that corresponds to 'code'.
327  */
328 static __inline ucs2_t
329 _DEFUN(find_code_speed_8bit, (code, tblp),
330                              ucs2_t code _AND
331                              _CONST unsigned char *tblp)
332 {
333   int idx;
334   unsigned char ccs;
335
336   if (code == ((ucs2_t *)tblp)[0])
337     return (ucs2_t)0xFF;
338  
339   idx = ((ucs2_t *)tblp)[1 + (code >> 8)];
340   
341   if (idx == INVBLK)
342     return (ucs2_t)INVALC;
343
344   ccs = tblp[(code & 0x00FF) + idx];
345
346   return ccs == 0xFF ? (ucs2_t)INVALC : (ucs2_t)ccs;
347 }
348
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])
353 /* Range offset */
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)
357
358 /*
359  * find_code_size - find code in 16 bit size-optimized table.
360  *
361  * PARAMETERS:
362  *     ucs2_t code - code whose mapping to find.
363  *     _CONST __uint16_t *tblp - table pointer.
364  *
365  * RETURN:
366  *     Code that corresponds to 'code'.
367  */
368 static ucs2_t
369 _DEFUN(find_code_size, (code, tblp),
370                        ucs2_t code _AND
371                        _CONST __uint16_t *tblp)
372 {
373   int first, last, cur, center;
374
375   if (tblp[RANGES_NUM_INDEX] > 0)
376     {
377       first = 0;
378       last = tblp[RANGES_NUM_INDEX] - 1;
379  
380       do
381         {
382           center = (last - first)/2;
383           cur = center + first;
384           
385           if (code > RANGE_RIGHT (cur))
386             first = cur;
387           else if (code < RANGE_LEFT (cur))
388             last = cur;
389           else
390             return (ucs2_t)tblp[RANGE_INDEX (cur) + code - RANGE_LEFT (cur)];
391         } while (center > 0);
392
393         if (last - first == 1)
394           {
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)];
401           }
402     }
403   
404   if (tblp[UNRANGED_NUM_INDEX] > 0)
405     {
406       first = 0;
407       last = tblp[UNRANGED_NUM_INDEX] - 1;
408  
409       do
410         {
411           int c;
412
413           center = (last - first)/2;
414           cur = center + first;
415           c = tblp[UNRANGED_INDEX (cur)];
416  
417           if (code > c)
418             first = cur;
419           else if (code < c)
420             last = cur;
421           else
422             return (ucs2_t)tblp[UNRANGED_INDEX (cur) + 1];
423         } while (center > 0);
424
425         if (last - first == 1)
426           {
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];
431           }
432     }
433
434   return (ucs2_t)INVALC;
435 }
436
437 #ifdef _ICONV_ENABLE_EXTERNAL_CCS
438
439 #define _16BIT_ELT(offset) \
440     ICONV_BETOHS(*((__uint16_t *)(buf + (offset))))
441 #define _32BIT_ELT(offset) \
442     ICONV_BETOHL(*((__uint32_t *)(buf + (offset))))
443
444 /*
445  * load_file - load conversion table from external file and initialize
446  *             iconv_ccs_desc_t object.
447  *
448  * PARAMETERS:
449  *    struct _reent *rptr - reent structure of current thread/process.
450  *    _CONST char *name - encoding name.
451  *    int direction - conversion direction.
452  *
453  * DESCRIPTION:
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"
457  *    table.
458  *
459  * RETURN:
460  *    iconv_ccs_desc_t * pointer is success, NULL if failure.
461  */
462 static _CONST iconv_ccs_desc_t *
463 _DEFUN(load_file, (rptr, name, direction), 
464                   struct _reent *rptr _AND
465                   _CONST char *name   _AND
466                   int direction)
467 {
468   int fd;
469   _CONST unsigned char *buf;
470   int tbllen, hdrlen;
471   off_t off;
472   _CONST char *fname;
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;
478   
479   nmlen = strlen(name);
480   
481   hdrlen = nmlen + EXTTABLE_HEADER_LEN + alignment;
482
483   if ((fname = _iconv_nls_construct_filename (rptr, name, ICONV_SUBDIR,
484                                               ICONV_DATA_EXT)) == NULL)
485     return NULL;
486   
487   if ((fd = _open_r (rptr, fname, O_RDONLY, S_IRUSR)) == -1)
488     goto error1;
489   
490   if ((buf = (_CONST unsigned char *)_malloc_r (rptr, hdrlen)) == NULL)
491     goto error2;
492
493   if (_read_r (rptr, fd, (_VOID_PTR)buf, hdrlen) != hdrlen)
494     goto error3;
495
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 */
500
501   if ((ccsp = (iconv_ccs_desc_t *)
502            _calloc_r (rptr, 1, sizeof (iconv_ccs_desc_t))) == NULL)
503     goto error3;
504   
505   ccsp->bits = _16BIT_ELT (EXTTABLE_BITS_OFF);
506   ccsp->type = TABLE_EXTERNAL;
507
508   /* Add 4-byte alignment to name length */
509   nmlen += alignment;
510
511   if (ccsp->bits == TABLE_8BIT)
512     {
513       if (direction == 0) /* Load "To UCS" table */
514         {
515           off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
516           tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
517         }
518       else /* Load "From UCS" table */
519         {
520           off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
521           tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
522         }
523     }
524   else if (ccsp->bits == TABLE_16BIT)
525     {
526       if (direction == 0) /* Load "To UCS" table */
527         {
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);
531 #else
532           off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_OFF);
533           tbllen = _32BIT_ELT (nmlen + EXTTABLE_TO_SPEED_LEN_OFF);
534 #endif
535         }
536       else /* Load "From UCS" table */
537         {
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);
541 #else
542           off = (off_t)_32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_OFF);
543           tbllen = _32BIT_ELT (nmlen + EXTTABLE_FROM_SPEED_LEN_OFF);
544 #endif
545         }
546 #ifdef TABLE_USE_SIZE_OPTIMIZATION
547       ccsp->optimization = TABLE_SIZE_OPTIMIZED; 
548 #else
549       ccsp->optimization = TABLE_SPEED_OPTIMIZED;
550 #endif
551     }
552   else
553     goto error4; /* Bad file */
554
555   if (off == EXTTABLE_NO_TABLE)
556     goto error4; /* No correspondent table in file */
557
558   if ((ccsp->tbl = (ucs2_t *)_malloc_r (rptr, tbllen)) == NULL)
559     goto error4;
560
561   if (_lseek_r (rptr, fd, off, SEEK_SET) == (off_t)-1
562       || _read_r (rptr, fd, (_VOID_PTR)ccsp->tbl, tbllen) != tbllen)
563     goto error5;
564
565   goto normal_exit;
566
567 error5:
568   _free_r (rptr, (_VOID_PTR)ccsp->tbl);
569   ccsp->tbl = NULL;
570 error4:
571   _free_r (rptr, (_VOID_PTR)ccsp);
572   ccsp = NULL;
573 error3:
574 normal_exit:
575   _free_r (rptr, (_VOID_PTR)buf);
576 error2:
577   if (_close_r (rptr, fd) == -1)
578     {
579       if (ccsp != NULL)
580         {
581           if (ccsp->tbl != NULL)
582             _free_r (rptr, (_VOID_PTR)ccsp->tbl);
583           _free_r (rptr, (_VOID_PTR)ccsp);
584         }
585       ccsp = NULL;
586     }
587 error1:
588   _free_r (rptr, (_VOID_PTR)fname);
589   return ccsp;
590 }
591 #endif
592
593 #endif /* ICONV_TO_UCS_CES_TABLE || ICONV_FROM_UCS_CES_TABLE */
594