citrus_mapper_std.c revision 336324
1250881Sjkim/* $FreeBSD: stable/10/lib/libiconv_modules/mapper_std/citrus_mapper_std.c 336324 2018-07-16 00:28:33Z pfg $ */
2250881Sjkim/*	$NetBSD: citrus_mapper_std.c,v 1.11 2018/06/11 18:03:38 kamil Exp $ */
3250881Sjkim
4250881Sjkim/*-
5250881Sjkim * Copyright (c)2003, 2006 Citrus Project,
6250881Sjkim * All rights reserved.
7250881Sjkim *
8250881Sjkim * Redistribution and use in source and binary forms, with or without
9250881Sjkim * modification, are permitted provided that the following conditions
10250881Sjkim * are met:
11250881Sjkim * 1. Redistributions of source code must retain the above copyright
12250881Sjkim *    notice, this list of conditions and the following disclaimer.
13250881Sjkim * 2. Redistributions in binary form must reproduce the above copyright
14250881Sjkim *    notice, this list of conditions and the following disclaimer in the
15250881Sjkim *    documentation and/or other materials provided with the distribution.
16250881Sjkim *
17250881Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18250881Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19250881Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20250881Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21250881Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22250881Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23250881Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24250881Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25250881Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26250881Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27250881Sjkim * SUCH DAMAGE.
28250881Sjkim */
29250881Sjkim
30250881Sjkim#include <sys/cdefs.h>
31250881Sjkim#include <sys/endian.h>
32250881Sjkim#include <sys/queue.h>
33250881Sjkim
34250881Sjkim#include <assert.h>
35250881Sjkim#include <errno.h>
36250881Sjkim#include <limits.h>
37250881Sjkim#include <stdint.h>
38250881Sjkim#include <stdio.h>
39250881Sjkim#include <stdlib.h>
40250881Sjkim#include <string.h>
41250881Sjkim
42250881Sjkim#include "citrus_namespace.h"
43250881Sjkim#include "citrus_types.h"
44250881Sjkim#include "citrus_bcs.h"
45250881Sjkim#include "citrus_region.h"
46250881Sjkim#include "citrus_mmap.h"
47250881Sjkim#include "citrus_module.h"
48250881Sjkim#include "citrus_hash.h"
49250881Sjkim#include "citrus_mapper.h"
50250881Sjkim#include "citrus_db.h"
51250881Sjkim#include "citrus_db_hash.h"
52250881Sjkim
53250881Sjkim#include "citrus_mapper_std.h"
54250881Sjkim#include "citrus_mapper_std_file.h"
55250881Sjkim
56250881Sjkim/* ---------------------------------------------------------------------- */
57250881Sjkim
58250881Sjkim_CITRUS_MAPPER_DECLS(mapper_std);
59250881Sjkim_CITRUS_MAPPER_DEF_OPS(mapper_std);
60250881Sjkim
61250881Sjkim
62250881Sjkim/* ---------------------------------------------------------------------- */
63250881Sjkim
64250881Sjkimint
65250881Sjkim_citrus_mapper_std_mapper_getops(struct _citrus_mapper_ops *ops)
66250881Sjkim{
67250881Sjkim
68250881Sjkim	memcpy(ops, &_citrus_mapper_std_mapper_ops,
69250881Sjkim	    sizeof(_citrus_mapper_std_mapper_ops));
70250881Sjkim
71250881Sjkim	return (0);
72250881Sjkim}
73250881Sjkim
74250881Sjkim/* ---------------------------------------------------------------------- */
75250881Sjkim
76250881Sjkimstatic int
77250881Sjkim/*ARGSUSED*/
78250881Sjkimrowcol_convert(struct _citrus_mapper_std * __restrict ms,
79250881Sjkim    _index_t * __restrict dst, _index_t src, void * __restrict ps __unused)
80250881Sjkim{
81250881Sjkim	struct _citrus_mapper_std_linear_zone *lz;
82250881Sjkim	struct _citrus_mapper_std_rowcol *rc;
83250881Sjkim	_index_t idx = 0, n;
84250881Sjkim	size_t i;
85250881Sjkim	uint32_t conv;
86250881Sjkim
87250881Sjkim	/* ps may be unused */
88250881Sjkim	rc = &ms->ms_rowcol;
89250881Sjkim
90250881Sjkim	for (i = rc->rc_src_rowcol_len * rc->rc_src_rowcol_bits,
91250881Sjkim	    lz = &rc->rc_src_rowcol[0]; i > 0; ++lz) {
92250881Sjkim		i -= rc->rc_src_rowcol_bits;
93250881Sjkim		n = (src >> i) & rc->rc_src_rowcol_mask;
94250881Sjkim		if (n < lz->begin || n > lz->end) {
95250881Sjkim			switch (rc->rc_oob_mode) {
96250881Sjkim			case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
97250881Sjkim				*dst = rc->rc_dst_invalid;
98250881Sjkim				return (_MAPPER_CONVERT_NONIDENTICAL);
99250881Sjkim			case _CITRUS_MAPPER_STD_OOB_ILSEQ:
100250881Sjkim				return (_MAPPER_CONVERT_ILSEQ);
101250881Sjkim			default:
102250881Sjkim				return (_MAPPER_CONVERT_FATAL);
103250881Sjkim			}
104250881Sjkim		}
105250881Sjkim		idx = idx * lz->width + n - lz->begin;
106250881Sjkim	}
107250881Sjkim	switch (rc->rc_dst_unit_bits) {
108250881Sjkim	case 8:
109250881Sjkim		conv = _region_peek8(&rc->rc_table, idx);
110250881Sjkim		break;
111250881Sjkim	case 16:
112250881Sjkim		conv = be16toh(_region_peek16(&rc->rc_table, idx*2));
113250881Sjkim		break;
114250881Sjkim	case 32:
115250881Sjkim		conv = be32toh(_region_peek32(&rc->rc_table, idx*4));
116250881Sjkim		break;
117250881Sjkim	default:
118250881Sjkim		return (_MAPPER_CONVERT_FATAL);
119250881Sjkim	}
120250881Sjkim
121250881Sjkim	if (conv == rc->rc_dst_invalid) {
122250881Sjkim		*dst = rc->rc_dst_invalid;
123250881Sjkim		return (_MAPPER_CONVERT_NONIDENTICAL);
124250881Sjkim	}
125250881Sjkim	if (conv == rc->rc_dst_ilseq)
126250881Sjkim		return (_MAPPER_CONVERT_ILSEQ);
127250881Sjkim
128250881Sjkim	*dst = conv;
129250881Sjkim
130250881Sjkim	return (_MAPPER_CONVERT_SUCCESS);
131250881Sjkim}
132250881Sjkim
133250881Sjkimstatic __inline int
134250881Sjkimset_linear_zone(struct _citrus_mapper_std_linear_zone *lz,
135250881Sjkim    uint32_t begin, uint32_t end)
136250881Sjkim{
137250881Sjkim
138250881Sjkim	if (begin > end)
139250881Sjkim		return (EFTYPE);
140250881Sjkim
141250881Sjkim	lz->begin = begin;
142250881Sjkim	lz->end = end;
143250881Sjkim	lz->width= end - begin + 1;
144250881Sjkim
145250881Sjkim	return (0);
146250881Sjkim}
147250881Sjkim
148250881Sjkimstatic __inline int
149250881Sjkimrowcol_parse_variable_compat(struct _citrus_mapper_std_rowcol *rc,
150250881Sjkim    struct _region *r)
151250881Sjkim{
152250881Sjkim	const struct _citrus_mapper_std_rowcol_info_compat_x *rcx;
153250881Sjkim	struct _citrus_mapper_std_linear_zone *lz;
154250881Sjkim	uint32_t m, n;
155250881Sjkim	int ret;
156250881Sjkim
157250881Sjkim	rcx = _region_head(r);
158250881Sjkim
159250881Sjkim	rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
160250881Sjkim	rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
161250881Sjkim	m = be32toh(rcx->rcx_src_col_bits);
162250881Sjkim	n = 1U << (m - 1);
163250881Sjkim	n |= n - 1;
164250881Sjkim	rc->rc_src_rowcol_bits = m;
165250881Sjkim	rc->rc_src_rowcol_mask = n;
166250881Sjkim
167250881Sjkim	rc->rc_src_rowcol = malloc(2 *
168250881Sjkim	    sizeof(*rc->rc_src_rowcol));
169250881Sjkim	if (rc->rc_src_rowcol == NULL)
170250881Sjkim		return (ENOMEM);
171250881Sjkim	lz = rc->rc_src_rowcol;
172250881Sjkim	rc->rc_src_rowcol_len = 1;
173250881Sjkim	m = be32toh(rcx->rcx_src_row_begin);
174250881Sjkim	n = be32toh(rcx->rcx_src_row_end);
175250881Sjkim	if (m + n > 0) {
176250881Sjkim		ret = set_linear_zone(lz, m, n);
177250881Sjkim		if (ret != 0) {
178250881Sjkim			free(rc->rc_src_rowcol);
179250881Sjkim			rc->rc_src_rowcol = NULL;
180250881Sjkim			return (ret);
181250881Sjkim		}
182250881Sjkim		++rc->rc_src_rowcol_len, ++lz;
183250881Sjkim	}
184250881Sjkim	m = be32toh(rcx->rcx_src_col_begin);
185250881Sjkim	n = be32toh(rcx->rcx_src_col_end);
186250881Sjkim
187250881Sjkim	return (set_linear_zone(lz, m, n));
188250881Sjkim}
189250881Sjkim
190250881Sjkimstatic __inline int
191250881Sjkimrowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc,
192250881Sjkim    struct _region *r)
193250881Sjkim{
194250881Sjkim	const struct _citrus_mapper_std_rowcol_info_x *rcx;
195250881Sjkim	struct _citrus_mapper_std_linear_zone *lz;
196250881Sjkim	size_t i;
197250881Sjkim	uint32_t m, n;
198250881Sjkim	int ret;
199250881Sjkim
200250881Sjkim	rcx = _region_head(r);
201250881Sjkim
202250881Sjkim	rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
203250881Sjkim	rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
204250881Sjkim
205250881Sjkim	m = be32toh(rcx->rcx_src_rowcol_bits);
206250881Sjkim	n = 1 << (m - 1);
207250881Sjkim	n |= n - 1;
208250881Sjkim	rc->rc_src_rowcol_bits = m;
209250881Sjkim	rc->rc_src_rowcol_mask = n;
210250881Sjkim
211250881Sjkim	rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len);
212250881Sjkim	if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX)
213250881Sjkim		return (EFTYPE);
214250881Sjkim	rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len *
215250881Sjkim	    sizeof(*rc->rc_src_rowcol));
216250881Sjkim	if (rc->rc_src_rowcol == NULL)
217250881Sjkim		return (ENOMEM);
218250881Sjkim	for (i = 0, lz = rc->rc_src_rowcol;
219250881Sjkim	    i < rc->rc_src_rowcol_len; ++i, ++lz) {
220250881Sjkim		m = be32toh(rcx->rcx_src_rowcol[i].begin),
221250881Sjkim		n = be32toh(rcx->rcx_src_rowcol[i].end);
222250881Sjkim		ret = set_linear_zone(lz, m, n);
223250881Sjkim		if (ret != 0) {
224250881Sjkim			free(rc->rc_src_rowcol);
225250881Sjkim			rc->rc_src_rowcol = NULL;
226250881Sjkim			return (ret);
227250881Sjkim		}
228250881Sjkim	}
229250881Sjkim	return (0);
230250881Sjkim}
231250881Sjkim
232250881Sjkimstatic void
233250881Sjkimrowcol_uninit(struct _citrus_mapper_std *ms)
234250881Sjkim{
235250881Sjkim	struct _citrus_mapper_std_rowcol *rc;
236250881Sjkim
237250881Sjkim	rc = &ms->ms_rowcol;
238250881Sjkim	free(rc->rc_src_rowcol);
239250881Sjkim}
240250881Sjkim
241250881Sjkimstatic int
242250881Sjkimrowcol_init(struct _citrus_mapper_std *ms)
243250881Sjkim{
244250881Sjkim	struct _citrus_mapper_std_linear_zone *lz;
245250881Sjkim	struct _citrus_mapper_std_rowcol *rc;
246250881Sjkim	const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix;
247250881Sjkim	struct _region r;
248250881Sjkim	uint64_t table_size;
249250881Sjkim	size_t i;
250250881Sjkim	int ret;
251250881Sjkim
252250881Sjkim	ms->ms_convert = &rowcol_convert;
253250881Sjkim	ms->ms_uninit = &rowcol_uninit;
254250881Sjkim	rc = &ms->ms_rowcol;
255250881Sjkim
256250881Sjkim	/* get table region */
257250881Sjkim	ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE,
258250881Sjkim	    &rc->rc_table, NULL);
259250881Sjkim	if (ret) {
260250881Sjkim		if (ret == ENOENT)
261250881Sjkim			ret = EFTYPE;
262250881Sjkim		return (ret);
263250881Sjkim	}
264250881Sjkim
265250881Sjkim	/* get table information */
266250881Sjkim	ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL);
267250881Sjkim	if (ret) {
268250881Sjkim		if (ret == ENOENT)
269250881Sjkim			ret = EFTYPE;
270250881Sjkim		return (ret);
271250881Sjkim	}
272250881Sjkim	switch (_region_size(&r)) {
273250881Sjkim	case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE:
274250881Sjkim		ret = rowcol_parse_variable_compat(rc, &r);
275250881Sjkim		break;
276250881Sjkim	case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE:
277250881Sjkim		ret = rowcol_parse_variable(rc, &r);
278250881Sjkim		break;
279250881Sjkim	default:
280250881Sjkim		return (EFTYPE);
281250881Sjkim	}
282250881Sjkim	if (ret != 0)
283250881Sjkim		return (ret);
284250881Sjkim	/* sanity check */
285250881Sjkim	switch (rc->rc_src_rowcol_bits) {
286250881Sjkim	case 8: case 16: case 32:
287250881Sjkim		if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits)
288250881Sjkim			break;
289250881Sjkim	/*FALLTHROUGH*/
290250881Sjkim	default:
291250881Sjkim		return (EFTYPE);
292250881Sjkim	}
293250881Sjkim
294250881Sjkim	/* ilseq extension */
295250881Sjkim	rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
296250881Sjkim	rc->rc_dst_ilseq = rc->rc_dst_invalid;
297250881Sjkim	ret = _db_lookup_by_s(ms->ms_db,
298250881Sjkim	    _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL);
299250881Sjkim	if (ret && ret != ENOENT)
300250881Sjkim		return (ret);
301250881Sjkim	if (_region_size(&r) < sizeof(*eix))
302250881Sjkim		return (EFTYPE);
303250881Sjkim	if (ret == 0) {
304250881Sjkim		eix = _region_head(&r);
305250881Sjkim		rc->rc_oob_mode = be32toh(eix->eix_oob_mode);
306250881Sjkim		rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq);
307250881Sjkim	}
308250881Sjkim
309250881Sjkim	/* calcurate expected table size */
310250881Sjkim	i = rc->rc_src_rowcol_len;
311250881Sjkim	lz = &rc->rc_src_rowcol[--i];
312250881Sjkim	table_size = lz->width;
313250881Sjkim	while (i > 0) {
314250881Sjkim		lz = &rc->rc_src_rowcol[--i];
315250881Sjkim		table_size *= lz->width;
316250881Sjkim	}
317250881Sjkim	table_size *= rc->rc_dst_unit_bits/8;
318250881Sjkim
319250881Sjkim	if (table_size > UINT32_MAX ||
320250881Sjkim	    _region_size(&rc->rc_table) < table_size)
321250881Sjkim		return (EFTYPE);
322250881Sjkim
323250881Sjkim	return (0);
324250881Sjkim}
325250881Sjkim
326250881Sjkimtypedef int (*initfunc_t)(struct _citrus_mapper_std *);
327250881Sjkimstatic const struct {
328250881Sjkim	initfunc_t			 t_init;
329250881Sjkim	const char			*t_name;
330250881Sjkim} types[] = {
331250881Sjkim	{ &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL },
332250881Sjkim};
333250881Sjkim#define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0])))
334250881Sjkim
335250881Sjkimstatic int
336250881Sjkim/*ARGSUSED*/
337250881Sjkim_citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused,
338250881Sjkim    struct _citrus_mapper * __restrict cm, const char * __restrict curdir,
339250881Sjkim    const void * __restrict var, size_t lenvar,
340250881Sjkim    struct _citrus_mapper_traits * __restrict mt, size_t lenmt)
341250881Sjkim{
342250881Sjkim	struct _citrus_mapper_std *ms;
343250881Sjkim	char path[PATH_MAX];
344250881Sjkim	const char *type;
345250881Sjkim	int id, ret;
346250881Sjkim
347250881Sjkim	/* set traits */
348250881Sjkim	if (lenmt < sizeof(*mt)) {
349250881Sjkim		ret = EINVAL;
350250881Sjkim		goto err0;
351250881Sjkim	}
352250881Sjkim	mt->mt_src_max = mt->mt_dst_max = 1;	/* 1:1 converter */
353250881Sjkim	mt->mt_state_size = 0;			/* stateless */
354250881Sjkim
355250881Sjkim	/* alloc mapper std structure */
356250881Sjkim	ms = malloc(sizeof(*ms));
357250881Sjkim	if (ms == NULL) {
358250881Sjkim		ret = errno;
359250881Sjkim		goto err0;
360250881Sjkim	}
361250881Sjkim
362250881Sjkim	/* open mapper file */
363250881Sjkim	snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar,
364250881Sjkim	    (const char *)var);
365250881Sjkim	ret = _map_file(&ms->ms_file, path);
366250881Sjkim	if (ret)
367250881Sjkim		goto err1;
368250881Sjkim
369250881Sjkim	ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC,
370250881Sjkim	    &_db_hash_std, NULL);
371250881Sjkim	if (ret)
372250881Sjkim		goto err2;
373250881Sjkim
374250881Sjkim	/* get mapper type */
375250881Sjkim	ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE,
376250881Sjkim	    &type, NULL);
377250881Sjkim	if (ret) {
378250881Sjkim		if (ret == ENOENT)
379250881Sjkim			ret = EFTYPE;
380250881Sjkim		goto err3;
381250881Sjkim	}
382250881Sjkim	for (id = 0; id < NUM_OF_TYPES; id++)
383250881Sjkim		if (_bcs_strcasecmp(type, types[id].t_name) == 0)
384250881Sjkim			break;
385250881Sjkim
386250881Sjkim	if (id == NUM_OF_TYPES)
387250881Sjkim		goto err3;
388250881Sjkim
389250881Sjkim	/* init the per-type structure */
390250881Sjkim	ret = (*types[id].t_init)(ms);
391250881Sjkim	if (ret)
392250881Sjkim		goto err3;
393250881Sjkim
394250881Sjkim	cm->cm_closure = ms;
395250881Sjkim
396250881Sjkim	return (0);
397250881Sjkim
398250881Sjkimerr3:
399250881Sjkim	_db_close(ms->ms_db);
400250881Sjkimerr2:
401250881Sjkim	_unmap_file(&ms->ms_file);
402250881Sjkimerr1:
403250881Sjkim	free(ms);
404250881Sjkimerr0:
405250881Sjkim	return (ret);
406250881Sjkim}
407250881Sjkim
408250881Sjkimstatic void
409250881Sjkim/*ARGSUSED*/
410250881Sjkim_citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm)
411250881Sjkim{
412250881Sjkim	struct _citrus_mapper_std *ms;
413250881Sjkim
414250881Sjkim	ms = cm->cm_closure;
415250881Sjkim	if (ms->ms_uninit)
416250881Sjkim		(*ms->ms_uninit)(ms);
417250881Sjkim	_db_close(ms->ms_db);
418250881Sjkim	_unmap_file(&ms->ms_file);
419250881Sjkim	free(ms);
420250881Sjkim}
421250881Sjkim
422250881Sjkimstatic void
423250881Sjkim/*ARGSUSED*/
424250881Sjkim_citrus_mapper_std_mapper_init_state(void)
425250881Sjkim{
426250881Sjkim
427250881Sjkim}
428250881Sjkim
429250881Sjkimstatic int
430250881Sjkim/*ARGSUSED*/
431250881Sjkim_citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm,
432250881Sjkim    _index_t * __restrict dst, _index_t src, void * __restrict ps)
433250881Sjkim{
434250881Sjkim	struct _citrus_mapper_std *ms;
435250881Sjkim
436250881Sjkim	ms = cm->cm_closure;
437250881Sjkim	return ((*ms->ms_convert)(ms, dst, src, ps));
438250881Sjkim}
439250881Sjkim