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