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