locales, libconv: Sync with FreeBSD (extensive reach)
[dragonfly.git] / lib / i18n_module / mapper_std / citrus_mapper_std.c
1 /* $FreeBSD: head/lib/libiconv_modules/mapper_std/citrus_mapper_std.c 219019 2011-02-25 00:04:39Z gabor $ */
2 /*      $NetBSD: citrus_mapper_std.c,v 1.8 2006/09/11 13:06:33 tnozaki Exp $    */
3
4 /*-
5  * Copyright (c)2003, 2006 Citrus Project,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 #include <sys/endian.h>
32 #include <sys/queue.h>
33
34 #include <assert.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "citrus_namespace.h"
43 #include "citrus_types.h"
44 #include "citrus_bcs.h"
45 #include "citrus_region.h"
46 #include "citrus_mmap.h"
47 #include "citrus_module.h"
48 #include "citrus_hash.h"
49 #include "citrus_mapper.h"
50 #include "citrus_db.h"
51 #include "citrus_db_hash.h"
52
53 #include "citrus_mapper_std.h"
54 #include "citrus_mapper_std_file.h"
55
56 /* ---------------------------------------------------------------------- */
57
58 _CITRUS_MAPPER_DECLS(mapper_std);
59 _CITRUS_MAPPER_DEF_OPS(mapper_std);
60
61
62 /* ---------------------------------------------------------------------- */
63
64 int
65 _citrus_mapper_std_mapper_getops(struct _citrus_mapper_ops *ops)
66 {
67
68         memcpy(ops, &_citrus_mapper_std_mapper_ops,
69             sizeof(_citrus_mapper_std_mapper_ops));
70
71         return (0);
72 }
73
74 /* ---------------------------------------------------------------------- */
75
76 static int
77 /*ARGSUSED*/
78 rowcol_convert(struct _citrus_mapper_std * __restrict ms,
79     _index_t * __restrict dst, _index_t src, void * __restrict ps __unused)
80 {
81         struct _citrus_mapper_std_linear_zone *lz;
82         struct _citrus_mapper_std_rowcol *rc;
83         _index_t idx = 0, n;
84         size_t i;
85         uint32_t conv;
86
87         /* ps may be unused */
88         rc = &ms->ms_rowcol;
89
90         for (i = rc->rc_src_rowcol_len * rc->rc_src_rowcol_bits,
91             lz = &rc->rc_src_rowcol[0]; i > 0; ++lz) {
92                 i -= rc->rc_src_rowcol_bits;
93                 n = (src >> i) & rc->rc_src_rowcol_mask;
94                 if (n < lz->begin || n > lz->end) {
95                         switch (rc->rc_oob_mode) {
96                         case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
97                                 *dst = rc->rc_dst_invalid;
98                                 return (_MAPPER_CONVERT_NONIDENTICAL);
99                         case _CITRUS_MAPPER_STD_OOB_ILSEQ:
100                                 return (_MAPPER_CONVERT_ILSEQ);
101                         default:
102                                 return (_MAPPER_CONVERT_FATAL);
103                         }
104                 }
105                 idx = idx * lz->width + n - lz->begin;
106         }
107         switch (rc->rc_dst_unit_bits) {
108         case 8:
109                 conv = _region_peek8(&rc->rc_table, idx);
110                 break;
111         case 16:
112                 conv = be16toh(_region_peek16(&rc->rc_table, idx*2));
113                 break;
114         case 32:
115                 conv = be32toh(_region_peek32(&rc->rc_table, idx*4));
116                 break;
117         default:
118                 return (_MAPPER_CONVERT_FATAL);
119         }
120
121         if (conv == rc->rc_dst_invalid) {
122                 *dst = rc->rc_dst_invalid;
123                 return (_MAPPER_CONVERT_NONIDENTICAL);
124         }
125         if (conv == rc->rc_dst_ilseq)
126                 return (_MAPPER_CONVERT_ILSEQ);
127
128         *dst = conv;
129
130         return (_MAPPER_CONVERT_SUCCESS);
131 }
132
133 static __inline int
134 set_linear_zone(struct _citrus_mapper_std_linear_zone *lz,
135     uint32_t begin, uint32_t end)
136 {
137
138         if (begin > end)
139                 return (EFTYPE);
140
141         lz->begin = begin;
142         lz->end = end;
143         lz->width= end - begin + 1;
144
145         return (0);
146 }
147
148 static __inline int
149 rowcol_parse_variable_compat(struct _citrus_mapper_std_rowcol *rc,
150     struct _region *r)
151 {
152         const struct _citrus_mapper_std_rowcol_info_compat_x *rcx;
153         struct _citrus_mapper_std_linear_zone *lz;
154         uint32_t m, n;
155         int ret;
156
157         rcx = _region_head(r);
158
159         rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
160         rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
161         m = be32toh(rcx->rcx_src_col_bits);
162         n = 1 << (m - 1);
163         n |= n - 1;
164         rc->rc_src_rowcol_bits = m;
165         rc->rc_src_rowcol_mask = n;
166
167         rc->rc_src_rowcol = malloc(2 *
168             sizeof(*rc->rc_src_rowcol));
169         if (rc->rc_src_rowcol == NULL)
170                 return (ENOMEM);
171         lz = rc->rc_src_rowcol;
172         rc->rc_src_rowcol_len = 1;
173         m = be32toh(rcx->rcx_src_row_begin);
174         n = be32toh(rcx->rcx_src_row_end);
175         if (m + n > 0) {
176                 ret = set_linear_zone(lz, m, n);
177                 if (ret != 0)
178                         return (ret);
179                 ++rc->rc_src_rowcol_len, ++lz;
180         }
181         m = be32toh(rcx->rcx_src_col_begin);
182         n = be32toh(rcx->rcx_src_col_end);
183
184         return (set_linear_zone(lz, m, n));
185 }
186
187 static __inline int
188 rowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc,
189     struct _region *r)
190 {
191         const struct _citrus_mapper_std_rowcol_info_x *rcx;
192         struct _citrus_mapper_std_linear_zone *lz;
193         size_t i;
194         uint32_t m, n;
195         int ret;
196
197         rcx = _region_head(r);
198
199         rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
200         rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
201
202         m = be32toh(rcx->rcx_src_rowcol_bits);
203         n = 1 << (m - 1);
204         n |= n - 1;
205         rc->rc_src_rowcol_bits = m;
206         rc->rc_src_rowcol_mask = n;
207
208         rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len);
209         if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX)
210                 return (EFTYPE);
211         rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len *
212             sizeof(*rc->rc_src_rowcol));
213         if (rc->rc_src_rowcol == NULL)
214                 return (ENOMEM);
215         for (i = 0, lz = rc->rc_src_rowcol;
216             i < rc->rc_src_rowcol_len; ++i, ++lz) {
217                 m = be32toh(rcx->rcx_src_rowcol[i].begin),
218                 n = be32toh(rcx->rcx_src_rowcol[i].end);
219                 ret = set_linear_zone(lz, m, n);
220                 if (ret != 0) {
221                         free(rc->rc_src_rowcol);
222                         rc->rc_src_rowcol = NULL;
223                         return (ret);
224                 }
225         }
226         return (0);
227 }
228
229 static void
230 rowcol_uninit(struct _citrus_mapper_std *ms)
231 {
232         struct _citrus_mapper_std_rowcol *rc;
233
234         rc = &ms->ms_rowcol;
235         free(rc->rc_src_rowcol);
236 }
237
238 static int
239 rowcol_init(struct _citrus_mapper_std *ms)
240 {
241         struct _citrus_mapper_std_linear_zone *lz;
242         struct _citrus_mapper_std_rowcol *rc;
243         const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix;
244         struct _region r;
245         uint64_t table_size;
246         size_t i;
247         int ret;
248
249         ms->ms_convert = &rowcol_convert;
250         ms->ms_uninit = &rowcol_uninit;
251         rc = &ms->ms_rowcol;
252
253         /* get table region */
254         ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE,
255             &rc->rc_table, NULL);
256         if (ret) {
257                 if (ret == ENOENT)
258                         ret = EFTYPE;
259                 return (ret);
260         }
261
262         /* get table information */
263         ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL);
264         if (ret) {
265                 if (ret == ENOENT)
266                         ret = EFTYPE;
267                 return (ret);
268         }
269         switch (_region_size(&r)) {
270         case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE:
271                 ret = rowcol_parse_variable_compat(rc, &r);
272                 break;
273         case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE:
274                 ret = rowcol_parse_variable(rc, &r);
275                 break;
276         default:
277                 return (EFTYPE);
278         }
279         if (ret != 0)
280                 return (ret);
281         /* sanity check */
282         switch (rc->rc_src_rowcol_bits) {
283         case 8: case 16: case 32:
284                 if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits)
285                         break;
286         /*FALLTHROUGH*/
287         default:
288                 return (EFTYPE);
289         }
290
291         /* ilseq extension */
292         rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
293         rc->rc_dst_ilseq = rc->rc_dst_invalid;
294         ret = _db_lookup_by_s(ms->ms_db,
295             _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL);
296         if (ret && ret != ENOENT)
297                 return (ret);
298         if (_region_size(&r) < sizeof(*eix))
299                 return (EFTYPE);
300         if (ret == 0) {
301                 eix = _region_head(&r);
302                 rc->rc_oob_mode = be32toh(eix->eix_oob_mode);
303                 rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq);
304         }
305
306         /* calcurate expected table size */
307         i = rc->rc_src_rowcol_len;
308         lz = &rc->rc_src_rowcol[--i];
309         table_size = lz->width;
310         while (i > 0) {
311                 lz = &rc->rc_src_rowcol[--i];
312                 table_size *= lz->width;
313         }
314         table_size *= rc->rc_dst_unit_bits/8;
315
316         if (table_size > UINT32_MAX ||
317             _region_size(&rc->rc_table) < table_size)
318                 return (EFTYPE);
319
320         return (0);
321 }
322
323 typedef int (*initfunc_t)(struct _citrus_mapper_std *);
324 static const struct {
325         initfunc_t                       t_init;
326         const char                      *t_name;
327 } types[] = {
328         { &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL },
329 };
330 #define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0])))
331
332 static int
333 /*ARGSUSED*/
334 _citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused,
335     struct _citrus_mapper * __restrict cm, const char * __restrict curdir,
336     const void * __restrict var, size_t lenvar,
337     struct _citrus_mapper_traits * __restrict mt, size_t lenmt)
338 {
339         struct _citrus_mapper_std *ms;
340         char path[PATH_MAX];
341         const char *type;
342         int id, ret;
343
344         /* set traits */
345         if (lenmt < sizeof(*mt)) {
346                 ret = EINVAL;
347                 goto err0;
348         }
349         mt->mt_src_max = mt->mt_dst_max = 1;    /* 1:1 converter */
350         mt->mt_state_size = 0;                  /* stateless */
351
352         /* alloc mapper std structure */
353         ms = malloc(sizeof(*ms));
354         if (ms == NULL) {
355                 ret = errno;
356                 goto err0;
357         }
358
359         /* open mapper file */
360         snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar,
361             (const char *)var);
362         ret = _map_file(&ms->ms_file, path);
363         if (ret)
364                 goto err1;
365
366         ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC,
367             &_db_hash_std, NULL);
368         if (ret)
369                 goto err2;
370
371         /* get mapper type */
372         ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE,
373             &type, NULL);
374         if (ret) {
375                 if (ret == ENOENT)
376                         ret = EFTYPE;
377                 goto err3;
378         }
379         for (id = 0; id < NUM_OF_TYPES; id++)
380                 if (_bcs_strcasecmp(type, types[id].t_name) == 0)
381                         break;
382
383         if (id == NUM_OF_TYPES)
384                 goto err3;
385
386         /* init the per-type structure */
387         ret = (*types[id].t_init)(ms);
388         if (ret)
389                 goto err3;
390
391         cm->cm_closure = ms;
392
393         return (0);
394
395 err3:
396         _db_close(ms->ms_db);
397 err2:
398         _unmap_file(&ms->ms_file);
399 err1:
400         free(ms);
401 err0:
402         return (ret);
403 }
404
405 static void
406 /*ARGSUSED*/
407 _citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm)
408 {
409         struct _citrus_mapper_std *ms;
410
411         ms = cm->cm_closure;
412         if (ms->ms_uninit)
413                 (*ms->ms_uninit)(ms);
414         _db_close(ms->ms_db);
415         _unmap_file(&ms->ms_file);
416         free(ms);
417 }
418
419 static void
420 /*ARGSUSED*/
421 _citrus_mapper_std_mapper_init_state(void)
422 {
423
424 }
425
426 static int
427 /*ARGSUSED*/
428 _citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm,
429     _index_t * __restrict dst, _index_t src, void * __restrict ps)
430 {
431         struct _citrus_mapper_std *ms;
432
433         ms = cm->cm_closure;
434         return ((*ms->ms_convert)(ms, dst, src, ps));
435 }