]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libiconv_modules/mapper_std/citrus_mapper_std.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libiconv_modules / mapper_std / citrus_mapper_std.c
1 /* $FreeBSD$ */
2 /*      $NetBSD: citrus_mapper_std.c,v 1.10 2011/11/19 18:48:39 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                         free(rc->rc_src_rowcol);
179                         rc->rc_src_rowcol = NULL;
180                         return (ret);
181                 }
182                 ++rc->rc_src_rowcol_len, ++lz;
183         }
184         m = be32toh(rcx->rcx_src_col_begin);
185         n = be32toh(rcx->rcx_src_col_end);
186
187         return (set_linear_zone(lz, m, n));
188 }
189
190 static __inline int
191 rowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc,
192     struct _region *r)
193 {
194         const struct _citrus_mapper_std_rowcol_info_x *rcx;
195         struct _citrus_mapper_std_linear_zone *lz;
196         size_t i;
197         uint32_t m, n;
198         int ret;
199
200         rcx = _region_head(r);
201
202         rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
203         rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
204
205         m = be32toh(rcx->rcx_src_rowcol_bits);
206         n = 1 << (m - 1);
207         n |= n - 1;
208         rc->rc_src_rowcol_bits = m;
209         rc->rc_src_rowcol_mask = n;
210
211         rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len);
212         if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX)
213                 return (EFTYPE);
214         rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len *
215             sizeof(*rc->rc_src_rowcol));
216         if (rc->rc_src_rowcol == NULL)
217                 return (ENOMEM);
218         for (i = 0, lz = rc->rc_src_rowcol;
219             i < rc->rc_src_rowcol_len; ++i, ++lz) {
220                 m = be32toh(rcx->rcx_src_rowcol[i].begin),
221                 n = be32toh(rcx->rcx_src_rowcol[i].end);
222                 ret = set_linear_zone(lz, m, n);
223                 if (ret != 0) {
224                         free(rc->rc_src_rowcol);
225                         rc->rc_src_rowcol = NULL;
226                         return (ret);
227                 }
228         }
229         return (0);
230 }
231
232 static void
233 rowcol_uninit(struct _citrus_mapper_std *ms)
234 {
235         struct _citrus_mapper_std_rowcol *rc;
236
237         rc = &ms->ms_rowcol;
238         free(rc->rc_src_rowcol);
239 }
240
241 static int
242 rowcol_init(struct _citrus_mapper_std *ms)
243 {
244         struct _citrus_mapper_std_linear_zone *lz;
245         struct _citrus_mapper_std_rowcol *rc;
246         const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix;
247         struct _region r;
248         uint64_t table_size;
249         size_t i;
250         int ret;
251
252         ms->ms_convert = &rowcol_convert;
253         ms->ms_uninit = &rowcol_uninit;
254         rc = &ms->ms_rowcol;
255
256         /* get table region */
257         ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE,
258             &rc->rc_table, NULL);
259         if (ret) {
260                 if (ret == ENOENT)
261                         ret = EFTYPE;
262                 return (ret);
263         }
264
265         /* get table information */
266         ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL);
267         if (ret) {
268                 if (ret == ENOENT)
269                         ret = EFTYPE;
270                 return (ret);
271         }
272         switch (_region_size(&r)) {
273         case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE:
274                 ret = rowcol_parse_variable_compat(rc, &r);
275                 break;
276         case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE:
277                 ret = rowcol_parse_variable(rc, &r);
278                 break;
279         default:
280                 return (EFTYPE);
281         }
282         if (ret != 0)
283                 return (ret);
284         /* sanity check */
285         switch (rc->rc_src_rowcol_bits) {
286         case 8: case 16: case 32:
287                 if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits)
288                         break;
289         /*FALLTHROUGH*/
290         default:
291                 return (EFTYPE);
292         }
293
294         /* ilseq extension */
295         rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
296         rc->rc_dst_ilseq = rc->rc_dst_invalid;
297         ret = _db_lookup_by_s(ms->ms_db,
298             _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL);
299         if (ret && ret != ENOENT)
300                 return (ret);
301         if (_region_size(&r) < sizeof(*eix))
302                 return (EFTYPE);
303         if (ret == 0) {
304                 eix = _region_head(&r);
305                 rc->rc_oob_mode = be32toh(eix->eix_oob_mode);
306                 rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq);
307         }
308
309         /* calcurate expected table size */
310         i = rc->rc_src_rowcol_len;
311         lz = &rc->rc_src_rowcol[--i];
312         table_size = lz->width;
313         while (i > 0) {
314                 lz = &rc->rc_src_rowcol[--i];
315                 table_size *= lz->width;
316         }
317         table_size *= rc->rc_dst_unit_bits/8;
318
319         if (table_size > UINT32_MAX ||
320             _region_size(&rc->rc_table) < table_size)
321                 return (EFTYPE);
322
323         return (0);
324 }
325
326 typedef int (*initfunc_t)(struct _citrus_mapper_std *);
327 static const struct {
328         initfunc_t                       t_init;
329         const char                      *t_name;
330 } types[] = {
331         { &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL },
332 };
333 #define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0])))
334
335 static int
336 /*ARGSUSED*/
337 _citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused,
338     struct _citrus_mapper * __restrict cm, const char * __restrict curdir,
339     const void * __restrict var, size_t lenvar,
340     struct _citrus_mapper_traits * __restrict mt, size_t lenmt)
341 {
342         struct _citrus_mapper_std *ms;
343         char path[PATH_MAX];
344         const char *type;
345         int id, ret;
346
347         /* set traits */
348         if (lenmt < sizeof(*mt)) {
349                 ret = EINVAL;
350                 goto err0;
351         }
352         mt->mt_src_max = mt->mt_dst_max = 1;    /* 1:1 converter */
353         mt->mt_state_size = 0;                  /* stateless */
354
355         /* alloc mapper std structure */
356         ms = malloc(sizeof(*ms));
357         if (ms == NULL) {
358                 ret = errno;
359                 goto err0;
360         }
361
362         /* open mapper file */
363         snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar,
364             (const char *)var);
365         ret = _map_file(&ms->ms_file, path);
366         if (ret)
367                 goto err1;
368
369         ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC,
370             &_db_hash_std, NULL);
371         if (ret)
372                 goto err2;
373
374         /* get mapper type */
375         ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE,
376             &type, NULL);
377         if (ret) {
378                 if (ret == ENOENT)
379                         ret = EFTYPE;
380                 goto err3;
381         }
382         for (id = 0; id < NUM_OF_TYPES; id++)
383                 if (_bcs_strcasecmp(type, types[id].t_name) == 0)
384                         break;
385
386         if (id == NUM_OF_TYPES)
387                 goto err3;
388
389         /* init the per-type structure */
390         ret = (*types[id].t_init)(ms);
391         if (ret)
392                 goto err3;
393
394         cm->cm_closure = ms;
395
396         return (0);
397
398 err3:
399         _db_close(ms->ms_db);
400 err2:
401         _unmap_file(&ms->ms_file);
402 err1:
403         free(ms);
404 err0:
405         return (ret);
406 }
407
408 static void
409 /*ARGSUSED*/
410 _citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm)
411 {
412         struct _citrus_mapper_std *ms;
413
414         ms = cm->cm_closure;
415         if (ms->ms_uninit)
416                 (*ms->ms_uninit)(ms);
417         _db_close(ms->ms_db);
418         _unmap_file(&ms->ms_file);
419         free(ms);
420 }
421
422 static void
423 /*ARGSUSED*/
424 _citrus_mapper_std_mapper_init_state(void)
425 {
426
427 }
428
429 static int
430 /*ARGSUSED*/
431 _citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm,
432     _index_t * __restrict dst, _index_t src, void * __restrict ps)
433 {
434         struct _citrus_mapper_std *ms;
435
436         ms = cm->cm_closure;
437         return ((*ms->ms_convert)(ms, dst, src, ps));
438 }