1219019Sgabor/* $FreeBSD: stable/10/lib/libiconv_modules/mapper_std/citrus_mapper_std.c 336324 2018-07-16 00:28:33Z pfg $ */
2336324Spfg/*	$NetBSD: citrus_mapper_std.c,v 1.11 2018/06/11 18:03:38 kamil Exp $ */
3219019Sgabor
4219019Sgabor/*-
5219019Sgabor * Copyright (c)2003, 2006 Citrus Project,
6219019Sgabor * All rights reserved.
7219019Sgabor *
8219019Sgabor * Redistribution and use in source and binary forms, with or without
9219019Sgabor * modification, are permitted provided that the following conditions
10219019Sgabor * are met:
11219019Sgabor * 1. Redistributions of source code must retain the above copyright
12219019Sgabor *    notice, this list of conditions and the following disclaimer.
13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
14219019Sgabor *    notice, this list of conditions and the following disclaimer in the
15219019Sgabor *    documentation and/or other materials provided with the distribution.
16219019Sgabor *
17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20219019Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27219019Sgabor * SUCH DAMAGE.
28219019Sgabor */
29219019Sgabor
30219019Sgabor#include <sys/cdefs.h>
31219019Sgabor#include <sys/endian.h>
32219019Sgabor#include <sys/queue.h>
33219019Sgabor
34219019Sgabor#include <assert.h>
35219019Sgabor#include <errno.h>
36219019Sgabor#include <limits.h>
37219019Sgabor#include <stdint.h>
38219019Sgabor#include <stdio.h>
39219019Sgabor#include <stdlib.h>
40219019Sgabor#include <string.h>
41219019Sgabor
42219019Sgabor#include "citrus_namespace.h"
43219019Sgabor#include "citrus_types.h"
44219019Sgabor#include "citrus_bcs.h"
45219019Sgabor#include "citrus_region.h"
46219019Sgabor#include "citrus_mmap.h"
47219019Sgabor#include "citrus_module.h"
48219019Sgabor#include "citrus_hash.h"
49219019Sgabor#include "citrus_mapper.h"
50219019Sgabor#include "citrus_db.h"
51219019Sgabor#include "citrus_db_hash.h"
52219019Sgabor
53219019Sgabor#include "citrus_mapper_std.h"
54219019Sgabor#include "citrus_mapper_std_file.h"
55219019Sgabor
56219019Sgabor/* ---------------------------------------------------------------------- */
57219019Sgabor
58219019Sgabor_CITRUS_MAPPER_DECLS(mapper_std);
59219019Sgabor_CITRUS_MAPPER_DEF_OPS(mapper_std);
60219019Sgabor
61219019Sgabor
62219019Sgabor/* ---------------------------------------------------------------------- */
63219019Sgabor
64219019Sgaborint
65219019Sgabor_citrus_mapper_std_mapper_getops(struct _citrus_mapper_ops *ops)
66219019Sgabor{
67219019Sgabor
68219019Sgabor	memcpy(ops, &_citrus_mapper_std_mapper_ops,
69219019Sgabor	    sizeof(_citrus_mapper_std_mapper_ops));
70219019Sgabor
71219019Sgabor	return (0);
72219019Sgabor}
73219019Sgabor
74219019Sgabor/* ---------------------------------------------------------------------- */
75219019Sgabor
76219019Sgaborstatic int
77219019Sgabor/*ARGSUSED*/
78219019Sgaborrowcol_convert(struct _citrus_mapper_std * __restrict ms,
79219019Sgabor    _index_t * __restrict dst, _index_t src, void * __restrict ps __unused)
80219019Sgabor{
81219019Sgabor	struct _citrus_mapper_std_linear_zone *lz;
82219019Sgabor	struct _citrus_mapper_std_rowcol *rc;
83219019Sgabor	_index_t idx = 0, n;
84219019Sgabor	size_t i;
85219019Sgabor	uint32_t conv;
86219019Sgabor
87219019Sgabor	/* ps may be unused */
88219019Sgabor	rc = &ms->ms_rowcol;
89219019Sgabor
90219019Sgabor	for (i = rc->rc_src_rowcol_len * rc->rc_src_rowcol_bits,
91219019Sgabor	    lz = &rc->rc_src_rowcol[0]; i > 0; ++lz) {
92219019Sgabor		i -= rc->rc_src_rowcol_bits;
93219019Sgabor		n = (src >> i) & rc->rc_src_rowcol_mask;
94219019Sgabor		if (n < lz->begin || n > lz->end) {
95219019Sgabor			switch (rc->rc_oob_mode) {
96219019Sgabor			case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
97219019Sgabor				*dst = rc->rc_dst_invalid;
98219019Sgabor				return (_MAPPER_CONVERT_NONIDENTICAL);
99219019Sgabor			case _CITRUS_MAPPER_STD_OOB_ILSEQ:
100219019Sgabor				return (_MAPPER_CONVERT_ILSEQ);
101219019Sgabor			default:
102219019Sgabor				return (_MAPPER_CONVERT_FATAL);
103219019Sgabor			}
104219019Sgabor		}
105219019Sgabor		idx = idx * lz->width + n - lz->begin;
106219019Sgabor	}
107219019Sgabor	switch (rc->rc_dst_unit_bits) {
108219019Sgabor	case 8:
109219019Sgabor		conv = _region_peek8(&rc->rc_table, idx);
110219019Sgabor		break;
111219019Sgabor	case 16:
112219019Sgabor		conv = be16toh(_region_peek16(&rc->rc_table, idx*2));
113219019Sgabor		break;
114219019Sgabor	case 32:
115219019Sgabor		conv = be32toh(_region_peek32(&rc->rc_table, idx*4));
116219019Sgabor		break;
117219019Sgabor	default:
118219019Sgabor		return (_MAPPER_CONVERT_FATAL);
119219019Sgabor	}
120219019Sgabor
121219019Sgabor	if (conv == rc->rc_dst_invalid) {
122219019Sgabor		*dst = rc->rc_dst_invalid;
123219019Sgabor		return (_MAPPER_CONVERT_NONIDENTICAL);
124219019Sgabor	}
125219019Sgabor	if (conv == rc->rc_dst_ilseq)
126219019Sgabor		return (_MAPPER_CONVERT_ILSEQ);
127219019Sgabor
128219019Sgabor	*dst = conv;
129219019Sgabor
130219019Sgabor	return (_MAPPER_CONVERT_SUCCESS);
131219019Sgabor}
132219019Sgabor
133219019Sgaborstatic __inline int
134219019Sgaborset_linear_zone(struct _citrus_mapper_std_linear_zone *lz,
135219019Sgabor    uint32_t begin, uint32_t end)
136219019Sgabor{
137219019Sgabor
138219019Sgabor	if (begin > end)
139219019Sgabor		return (EFTYPE);
140219019Sgabor
141219019Sgabor	lz->begin = begin;
142219019Sgabor	lz->end = end;
143219019Sgabor	lz->width= end - begin + 1;
144219019Sgabor
145219019Sgabor	return (0);
146219019Sgabor}
147219019Sgabor
148219019Sgaborstatic __inline int
149219019Sgaborrowcol_parse_variable_compat(struct _citrus_mapper_std_rowcol *rc,
150219019Sgabor    struct _region *r)
151219019Sgabor{
152219019Sgabor	const struct _citrus_mapper_std_rowcol_info_compat_x *rcx;
153219019Sgabor	struct _citrus_mapper_std_linear_zone *lz;
154219019Sgabor	uint32_t m, n;
155219019Sgabor	int ret;
156219019Sgabor
157219019Sgabor	rcx = _region_head(r);
158219019Sgabor
159219019Sgabor	rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
160219019Sgabor	rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
161219019Sgabor	m = be32toh(rcx->rcx_src_col_bits);
162336324Spfg	n = 1U << (m - 1);
163219019Sgabor	n |= n - 1;
164219019Sgabor	rc->rc_src_rowcol_bits = m;
165219019Sgabor	rc->rc_src_rowcol_mask = n;
166219019Sgabor
167219019Sgabor	rc->rc_src_rowcol = malloc(2 *
168219019Sgabor	    sizeof(*rc->rc_src_rowcol));
169219019Sgabor	if (rc->rc_src_rowcol == NULL)
170219019Sgabor		return (ENOMEM);
171219019Sgabor	lz = rc->rc_src_rowcol;
172219019Sgabor	rc->rc_src_rowcol_len = 1;
173219019Sgabor	m = be32toh(rcx->rcx_src_row_begin);
174219019Sgabor	n = be32toh(rcx->rcx_src_row_end);
175219019Sgabor	if (m + n > 0) {
176219019Sgabor		ret = set_linear_zone(lz, m, n);
177264497Stijl		if (ret != 0) {
178264497Stijl			free(rc->rc_src_rowcol);
179264497Stijl			rc->rc_src_rowcol = NULL;
180219019Sgabor			return (ret);
181264497Stijl		}
182219019Sgabor		++rc->rc_src_rowcol_len, ++lz;
183219019Sgabor	}
184219019Sgabor	m = be32toh(rcx->rcx_src_col_begin);
185219019Sgabor	n = be32toh(rcx->rcx_src_col_end);
186219019Sgabor
187219019Sgabor	return (set_linear_zone(lz, m, n));
188219019Sgabor}
189219019Sgabor
190219019Sgaborstatic __inline int
191219019Sgaborrowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc,
192219019Sgabor    struct _region *r)
193219019Sgabor{
194219019Sgabor	const struct _citrus_mapper_std_rowcol_info_x *rcx;
195219019Sgabor	struct _citrus_mapper_std_linear_zone *lz;
196219019Sgabor	size_t i;
197219019Sgabor	uint32_t m, n;
198219019Sgabor	int ret;
199219019Sgabor
200219019Sgabor	rcx = _region_head(r);
201219019Sgabor
202219019Sgabor	rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
203219019Sgabor	rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
204219019Sgabor
205219019Sgabor	m = be32toh(rcx->rcx_src_rowcol_bits);
206219019Sgabor	n = 1 << (m - 1);
207219019Sgabor	n |= n - 1;
208219019Sgabor	rc->rc_src_rowcol_bits = m;
209219019Sgabor	rc->rc_src_rowcol_mask = n;
210219019Sgabor
211219019Sgabor	rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len);
212219019Sgabor	if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX)
213219019Sgabor		return (EFTYPE);
214219019Sgabor	rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len *
215219019Sgabor	    sizeof(*rc->rc_src_rowcol));
216219019Sgabor	if (rc->rc_src_rowcol == NULL)
217219019Sgabor		return (ENOMEM);
218219019Sgabor	for (i = 0, lz = rc->rc_src_rowcol;
219219019Sgabor	    i < rc->rc_src_rowcol_len; ++i, ++lz) {
220219019Sgabor		m = be32toh(rcx->rcx_src_rowcol[i].begin),
221219019Sgabor		n = be32toh(rcx->rcx_src_rowcol[i].end);
222219019Sgabor		ret = set_linear_zone(lz, m, n);
223219019Sgabor		if (ret != 0) {
224219019Sgabor			free(rc->rc_src_rowcol);
225219019Sgabor			rc->rc_src_rowcol = NULL;
226219019Sgabor			return (ret);
227219019Sgabor		}
228219019Sgabor	}
229219019Sgabor	return (0);
230219019Sgabor}
231219019Sgabor
232219019Sgaborstatic void
233219019Sgaborrowcol_uninit(struct _citrus_mapper_std *ms)
234219019Sgabor{
235219019Sgabor	struct _citrus_mapper_std_rowcol *rc;
236219019Sgabor
237219019Sgabor	rc = &ms->ms_rowcol;
238219019Sgabor	free(rc->rc_src_rowcol);
239219019Sgabor}
240219019Sgabor
241219019Sgaborstatic int
242219019Sgaborrowcol_init(struct _citrus_mapper_std *ms)
243219019Sgabor{
244219019Sgabor	struct _citrus_mapper_std_linear_zone *lz;
245219019Sgabor	struct _citrus_mapper_std_rowcol *rc;
246219019Sgabor	const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix;
247219019Sgabor	struct _region r;
248219019Sgabor	uint64_t table_size;
249219019Sgabor	size_t i;
250219019Sgabor	int ret;
251219019Sgabor
252219019Sgabor	ms->ms_convert = &rowcol_convert;
253219019Sgabor	ms->ms_uninit = &rowcol_uninit;
254219019Sgabor	rc = &ms->ms_rowcol;
255219019Sgabor
256219019Sgabor	/* get table region */
257219019Sgabor	ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE,
258219019Sgabor	    &rc->rc_table, NULL);
259219019Sgabor	if (ret) {
260219019Sgabor		if (ret == ENOENT)
261219019Sgabor			ret = EFTYPE;
262219019Sgabor		return (ret);
263219019Sgabor	}
264219019Sgabor
265219019Sgabor	/* get table information */
266219019Sgabor	ret = _db_lookup_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL);
267219019Sgabor	if (ret) {
268219019Sgabor		if (ret == ENOENT)
269219019Sgabor			ret = EFTYPE;
270219019Sgabor		return (ret);
271219019Sgabor	}
272219019Sgabor	switch (_region_size(&r)) {
273219019Sgabor	case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE:
274219019Sgabor		ret = rowcol_parse_variable_compat(rc, &r);
275219019Sgabor		break;
276219019Sgabor	case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE:
277219019Sgabor		ret = rowcol_parse_variable(rc, &r);
278219019Sgabor		break;
279219019Sgabor	default:
280219019Sgabor		return (EFTYPE);
281219019Sgabor	}
282219019Sgabor	if (ret != 0)
283219019Sgabor		return (ret);
284219019Sgabor	/* sanity check */
285219019Sgabor	switch (rc->rc_src_rowcol_bits) {
286219019Sgabor	case 8: case 16: case 32:
287219019Sgabor		if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits)
288219019Sgabor			break;
289219019Sgabor	/*FALLTHROUGH*/
290219019Sgabor	default:
291219019Sgabor		return (EFTYPE);
292219019Sgabor	}
293219019Sgabor
294219019Sgabor	/* ilseq extension */
295219019Sgabor	rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
296219019Sgabor	rc->rc_dst_ilseq = rc->rc_dst_invalid;
297219019Sgabor	ret = _db_lookup_by_s(ms->ms_db,
298219019Sgabor	    _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL);
299219019Sgabor	if (ret && ret != ENOENT)
300219019Sgabor		return (ret);
301219019Sgabor	if (_region_size(&r) < sizeof(*eix))
302219019Sgabor		return (EFTYPE);
303219019Sgabor	if (ret == 0) {
304219019Sgabor		eix = _region_head(&r);
305219019Sgabor		rc->rc_oob_mode = be32toh(eix->eix_oob_mode);
306219019Sgabor		rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq);
307219019Sgabor	}
308219019Sgabor
309219019Sgabor	/* calcurate expected table size */
310219019Sgabor	i = rc->rc_src_rowcol_len;
311219019Sgabor	lz = &rc->rc_src_rowcol[--i];
312219019Sgabor	table_size = lz->width;
313219019Sgabor	while (i > 0) {
314219019Sgabor		lz = &rc->rc_src_rowcol[--i];
315219019Sgabor		table_size *= lz->width;
316219019Sgabor	}
317219019Sgabor	table_size *= rc->rc_dst_unit_bits/8;
318219019Sgabor
319219019Sgabor	if (table_size > UINT32_MAX ||
320219019Sgabor	    _region_size(&rc->rc_table) < table_size)
321219019Sgabor		return (EFTYPE);
322219019Sgabor
323219019Sgabor	return (0);
324219019Sgabor}
325219019Sgabor
326219019Sgabortypedef int (*initfunc_t)(struct _citrus_mapper_std *);
327219019Sgaborstatic const struct {
328219019Sgabor	initfunc_t			 t_init;
329219019Sgabor	const char			*t_name;
330219019Sgabor} types[] = {
331219019Sgabor	{ &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL },
332219019Sgabor};
333219019Sgabor#define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0])))
334219019Sgabor
335219019Sgaborstatic int
336219019Sgabor/*ARGSUSED*/
337219019Sgabor_citrus_mapper_std_mapper_init(struct _citrus_mapper_area *__restrict ma __unused,
338219019Sgabor    struct _citrus_mapper * __restrict cm, const char * __restrict curdir,
339219019Sgabor    const void * __restrict var, size_t lenvar,
340219019Sgabor    struct _citrus_mapper_traits * __restrict mt, size_t lenmt)
341219019Sgabor{
342219019Sgabor	struct _citrus_mapper_std *ms;
343219019Sgabor	char path[PATH_MAX];
344219019Sgabor	const char *type;
345219019Sgabor	int id, ret;
346219019Sgabor
347219019Sgabor	/* set traits */
348219019Sgabor	if (lenmt < sizeof(*mt)) {
349219019Sgabor		ret = EINVAL;
350219019Sgabor		goto err0;
351219019Sgabor	}
352219019Sgabor	mt->mt_src_max = mt->mt_dst_max = 1;	/* 1:1 converter */
353219019Sgabor	mt->mt_state_size = 0;			/* stateless */
354219019Sgabor
355219019Sgabor	/* alloc mapper std structure */
356219019Sgabor	ms = malloc(sizeof(*ms));
357219019Sgabor	if (ms == NULL) {
358219019Sgabor		ret = errno;
359219019Sgabor		goto err0;
360219019Sgabor	}
361219019Sgabor
362219019Sgabor	/* open mapper file */
363219019Sgabor	snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar,
364219019Sgabor	    (const char *)var);
365219019Sgabor	ret = _map_file(&ms->ms_file, path);
366219019Sgabor	if (ret)
367219019Sgabor		goto err1;
368219019Sgabor
369219019Sgabor	ret = _db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC,
370219019Sgabor	    &_db_hash_std, NULL);
371219019Sgabor	if (ret)
372219019Sgabor		goto err2;
373219019Sgabor
374219019Sgabor	/* get mapper type */
375219019Sgabor	ret = _db_lookupstr_by_s(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE,
376219019Sgabor	    &type, NULL);
377219019Sgabor	if (ret) {
378219019Sgabor		if (ret == ENOENT)
379219019Sgabor			ret = EFTYPE;
380219019Sgabor		goto err3;
381219019Sgabor	}
382219019Sgabor	for (id = 0; id < NUM_OF_TYPES; id++)
383219019Sgabor		if (_bcs_strcasecmp(type, types[id].t_name) == 0)
384219019Sgabor			break;
385219019Sgabor
386219019Sgabor	if (id == NUM_OF_TYPES)
387219019Sgabor		goto err3;
388219019Sgabor
389219019Sgabor	/* init the per-type structure */
390219019Sgabor	ret = (*types[id].t_init)(ms);
391219019Sgabor	if (ret)
392219019Sgabor		goto err3;
393219019Sgabor
394219019Sgabor	cm->cm_closure = ms;
395219019Sgabor
396219019Sgabor	return (0);
397219019Sgabor
398219019Sgaborerr3:
399219019Sgabor	_db_close(ms->ms_db);
400219019Sgaborerr2:
401219019Sgabor	_unmap_file(&ms->ms_file);
402219019Sgaborerr1:
403219019Sgabor	free(ms);
404219019Sgaborerr0:
405219019Sgabor	return (ret);
406219019Sgabor}
407219019Sgabor
408219019Sgaborstatic void
409219019Sgabor/*ARGSUSED*/
410219019Sgabor_citrus_mapper_std_mapper_uninit(struct _citrus_mapper *cm)
411219019Sgabor{
412219019Sgabor	struct _citrus_mapper_std *ms;
413219019Sgabor
414219019Sgabor	ms = cm->cm_closure;
415219019Sgabor	if (ms->ms_uninit)
416219019Sgabor		(*ms->ms_uninit)(ms);
417219019Sgabor	_db_close(ms->ms_db);
418219019Sgabor	_unmap_file(&ms->ms_file);
419219019Sgabor	free(ms);
420219019Sgabor}
421219019Sgabor
422219019Sgaborstatic void
423219019Sgabor/*ARGSUSED*/
424219019Sgabor_citrus_mapper_std_mapper_init_state(void)
425219019Sgabor{
426219019Sgabor
427219019Sgabor}
428219019Sgabor
429219019Sgaborstatic int
430219019Sgabor/*ARGSUSED*/
431219019Sgabor_citrus_mapper_std_mapper_convert(struct _citrus_mapper * __restrict cm,
432219019Sgabor    _index_t * __restrict dst, _index_t src, void * __restrict ps)
433219019Sgabor{
434219019Sgabor	struct _citrus_mapper_std *ms;
435219019Sgabor
436219019Sgabor	ms = cm->cm_closure;
437219019Sgabor	return ((*ms->ms_convert)(ms, dst, src, ps));
438219019Sgabor}
439