1219019Sgabor/* $FreeBSD: stable/11/lib/libc/iconv/citrus_esdb.c 316613 2017-04-07 16:08:04Z pfg $ */ 2219019Sgabor/* $NetBSD: citrus_esdb.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2003 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/types.h> 32219019Sgabor 33219019Sgabor#include <assert.h> 34219019Sgabor#include <errno.h> 35219019Sgabor#include <limits.h> 36219019Sgabor#include <paths.h> 37219019Sgabor#include <stdbool.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_memstream.h" 47219019Sgabor#include "citrus_mmap.h" 48219019Sgabor#include "citrus_lookup.h" 49219019Sgabor#include "citrus_db.h" 50219019Sgabor#include "citrus_db_hash.h" 51219019Sgabor#include "citrus_esdb.h" 52219019Sgabor#include "citrus_esdb_file.h" 53219019Sgabor 54219019Sgabor#define ESDB_DIR "esdb.dir" 55219019Sgabor#define ESDB_ALIAS "esdb.alias" 56219019Sgabor 57219019Sgabor/* 58219019Sgabor * _citrus_esdb_alias: 59219019Sgabor * resolve encoding scheme name aliases. 60219019Sgabor */ 61219019Sgaborconst char * 62219019Sgabor_citrus_esdb_alias(const char *esname, char *buf, size_t bufsize) 63219019Sgabor{ 64219019Sgabor 65219019Sgabor return (_lookup_alias(_PATH_ESDB "/" ESDB_ALIAS, esname, buf, bufsize, 66219019Sgabor _LOOKUP_CASE_IGNORE)); 67219019Sgabor} 68219019Sgabor 69219019Sgabor 70219019Sgabor/* 71219019Sgabor * conv_esdb: 72219019Sgabor * external representation -> local structure. 73219019Sgabor */ 74219019Sgaborstatic int 75219019Sgaborconv_esdb(struct _citrus_esdb *esdb, struct _region *fr) 76219019Sgabor{ 77219019Sgabor struct _citrus_db *db; 78219019Sgabor const char *str; 79219019Sgabor char buf[100]; 80219019Sgabor uint32_t csid, i, num_charsets, tmp, version; 81219019Sgabor int ret; 82219019Sgabor 83219019Sgabor /* open db */ 84219019Sgabor ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL); 85219019Sgabor if (ret) 86219019Sgabor goto err0; 87219019Sgabor 88219019Sgabor /* check version */ 89219019Sgabor ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL); 90219019Sgabor if (ret) 91219019Sgabor goto err1; 92219019Sgabor switch (version) { 93219019Sgabor case 0x00000001: 94219019Sgabor /* current version */ 95219019Sgabor /* initial version */ 96219019Sgabor break; 97219019Sgabor default: 98219019Sgabor ret = EFTYPE; 99219019Sgabor goto err1; 100219019Sgabor } 101219019Sgabor 102219019Sgabor /* get encoding/variable */ 103219019Sgabor ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL); 104219019Sgabor if (ret) 105219019Sgabor goto err1; 106219019Sgabor esdb->db_encname = strdup(str); 107219019Sgabor if (esdb->db_encname == NULL) { 108219019Sgabor ret = errno; 109219019Sgabor goto err1; 110219019Sgabor } 111219019Sgabor 112219019Sgabor esdb->db_len_variable = 0; 113219019Sgabor esdb->db_variable = NULL; 114219019Sgabor ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL); 115219019Sgabor if (ret == 0) { 116219019Sgabor esdb->db_len_variable = strlen(str) + 1; 117219019Sgabor esdb->db_variable = strdup(str); 118219019Sgabor if (esdb->db_variable == NULL) { 119219019Sgabor ret = errno; 120219019Sgabor goto err2; 121219019Sgabor } 122219019Sgabor } else if (ret != ENOENT) 123219019Sgabor goto err2; 124219019Sgabor 125219019Sgabor /* get number of charsets */ 126219019Sgabor ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS, 127219019Sgabor &num_charsets, NULL); 128219019Sgabor if (ret) 129219019Sgabor goto err3; 130219019Sgabor esdb->db_num_charsets = num_charsets; 131219019Sgabor 132219019Sgabor /* get invalid character */ 133219019Sgabor ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL); 134219019Sgabor if (ret == 0) { 135219019Sgabor esdb->db_use_invalid = 1; 136219019Sgabor esdb->db_invalid = tmp; 137219019Sgabor } else if (ret == ENOENT) 138219019Sgabor esdb->db_use_invalid = 0; 139219019Sgabor else 140219019Sgabor goto err3; 141219019Sgabor 142219019Sgabor /* get charsets */ 143219019Sgabor esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets)); 144219019Sgabor if (esdb->db_charsets == NULL) { 145219019Sgabor ret = errno; 146219019Sgabor goto err3; 147219019Sgabor } 148219019Sgabor for (i = 0; i < num_charsets; i++) { 149219019Sgabor snprintf(buf, sizeof(buf), 150219019Sgabor _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i); 151219019Sgabor ret = _db_lookup32_by_s(db, buf, &csid, NULL); 152219019Sgabor if (ret) 153219019Sgabor goto err4; 154219019Sgabor esdb->db_charsets[i].ec_csid = csid; 155219019Sgabor 156219019Sgabor snprintf(buf, sizeof(buf), 157219019Sgabor _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i); 158219019Sgabor ret = _db_lookupstr_by_s(db, buf, &str, NULL); 159219019Sgabor if (ret) 160219019Sgabor goto err4; 161219019Sgabor esdb->db_charsets[i].ec_csname = strdup(str); 162219019Sgabor if (esdb->db_charsets[i].ec_csname == NULL) { 163219019Sgabor ret = errno; 164219019Sgabor goto err4; 165219019Sgabor } 166219019Sgabor } 167219019Sgabor 168219019Sgabor _db_close(db); 169219019Sgabor return (0); 170219019Sgabor 171219019Sgaborerr4: 172219019Sgabor for (; i > 0; i--) 173219019Sgabor free(esdb->db_charsets[i - 1].ec_csname); 174219019Sgabor free(esdb->db_charsets); 175219019Sgaborerr3: 176219019Sgabor free(esdb->db_variable); 177219019Sgaborerr2: 178219019Sgabor free(esdb->db_encname); 179219019Sgaborerr1: 180219019Sgabor _db_close(db); 181219019Sgabor if (ret == ENOENT) 182219019Sgabor ret = EFTYPE; 183219019Sgaborerr0: 184219019Sgabor return (ret); 185219019Sgabor} 186219019Sgabor 187219019Sgabor/* 188219019Sgabor * _citrus_esdb_open: 189219019Sgabor * open an ESDB file. 190219019Sgabor */ 191219019Sgaborint 192219019Sgabor_citrus_esdb_open(struct _citrus_esdb *db, const char *esname) 193219019Sgabor{ 194219019Sgabor struct _region fr; 195219019Sgabor const char *realname, *encfile; 196219019Sgabor char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX]; 197219019Sgabor int ret; 198219019Sgabor 199219019Sgabor snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS); 200219019Sgabor realname = _lookup_alias(path, esname, buf1, sizeof(buf1), 201219019Sgabor _LOOKUP_CASE_IGNORE); 202219019Sgabor 203219019Sgabor snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR); 204219019Sgabor encfile = _lookup_simple(path, realname, buf2, sizeof(buf2), 205219019Sgabor _LOOKUP_CASE_IGNORE); 206219019Sgabor if (encfile == NULL) 207219019Sgabor return (ENOENT); 208219019Sgabor 209219019Sgabor /* open file */ 210219019Sgabor snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile); 211219019Sgabor ret = _map_file(&fr, path); 212219019Sgabor if (ret) 213219019Sgabor return (ret); 214219019Sgabor 215219019Sgabor ret = conv_esdb(db, &fr); 216219019Sgabor 217219019Sgabor _unmap_file(&fr); 218219019Sgabor 219219019Sgabor return (ret); 220219019Sgabor} 221219019Sgabor 222219019Sgabor/* 223219019Sgabor * _citrus_esdb_close: 224219019Sgabor * free an ESDB. 225219019Sgabor */ 226219019Sgaborvoid 227219019Sgabor_citrus_esdb_close(struct _citrus_esdb *db) 228219019Sgabor{ 229219019Sgabor 230219019Sgabor for (int i = 0; i < db->db_num_charsets; i++) 231219019Sgabor free(db->db_charsets[i].ec_csname); 232219019Sgabor db->db_num_charsets = 0; 233219019Sgabor free(db->db_charsets); db->db_charsets = NULL; 234219019Sgabor free(db->db_encname); db->db_encname = NULL; 235219019Sgabor db->db_len_variable = 0; 236219019Sgabor free(db->db_variable); db->db_variable = NULL; 237219019Sgabor} 238219019Sgabor 239219019Sgabor/* 240219019Sgabor * _citrus_esdb_free_list: 241219019Sgabor * free the list. 242219019Sgabor */ 243219019Sgaborvoid 244219019Sgabor_citrus_esdb_free_list(char **list, size_t num) 245219019Sgabor{ 246219019Sgabor 247219019Sgabor for (size_t i = 0; i < num; i++) 248219019Sgabor free(list[i]); 249219019Sgabor free(list); 250219019Sgabor} 251219019Sgabor 252219019Sgabor/* 253219019Sgabor * _citrus_esdb_get_list: 254219019Sgabor * get esdb entries. 255219019Sgabor */ 256219019Sgaborint 257219019Sgabor_citrus_esdb_get_list(char ***rlist, size_t *rnum, bool sorted) 258219019Sgabor{ 259219019Sgabor struct _citrus_lookup *cla, *cld; 260219019Sgabor struct _region key, data; 261219019Sgabor char **list, **q; 262219019Sgabor char buf[PATH_MAX]; 263219019Sgabor size_t num; 264219019Sgabor int ret; 265219019Sgabor 266219019Sgabor ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS, 267219019Sgabor _LOOKUP_CASE_IGNORE); 268219019Sgabor if (ret) 269219019Sgabor goto quit0; 270219019Sgabor 271219019Sgabor ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR, 272219019Sgabor _LOOKUP_CASE_IGNORE); 273219019Sgabor if (ret) 274219019Sgabor goto quit1; 275219019Sgabor 276219019Sgabor /* count number of entries */ 277219019Sgabor num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld); 278219019Sgabor 279219019Sgabor _lookup_seq_rewind(cla); 280219019Sgabor _lookup_seq_rewind(cld); 281219019Sgabor 282219019Sgabor /* allocate list pointer space */ 283219019Sgabor list = malloc(num * sizeof(char *)); 284219019Sgabor num = 0; 285219019Sgabor if (list == NULL) { 286219019Sgabor ret = errno; 287219019Sgabor goto quit3; 288219019Sgabor } 289219019Sgabor 290219019Sgabor /* get alias entries */ 291219019Sgabor while ((ret = _lookup_seq_next(cla, &key, &data)) == 0) { 292301215Spfg /* XXX: sorted? */ 293301215Spfg snprintf(buf, sizeof(buf), "%.*s/%.*s", 294301215Spfg (int)_region_size(&data), 295301215Spfg (const char *)_region_head(&data), 296301215Spfg (int)_region_size(&key), 297301215Spfg (const char *)_region_head(&key)); 298219019Sgabor _bcs_convert_to_upper(buf); 299219019Sgabor list[num] = strdup(buf); 300219019Sgabor if (list[num] == NULL) { 301219019Sgabor ret = errno; 302219019Sgabor goto quit3; 303219019Sgabor } 304219019Sgabor num++; 305219019Sgabor } 306219019Sgabor if (ret != ENOENT) 307219019Sgabor goto quit3; 308219019Sgabor /* get dir entries */ 309219019Sgabor while ((ret = _lookup_seq_next(cld, &key, &data)) == 0) { 310219019Sgabor if (!sorted) 311219019Sgabor snprintf(buf, sizeof(buf), "%.*s", 312219019Sgabor (int)_region_size(&key), 313219019Sgabor (const char *)_region_head(&key)); 314219019Sgabor else { 315219019Sgabor /* check duplicated entry */ 316219019Sgabor char *p; 317219019Sgabor char buf1[PATH_MAX]; 318219019Sgabor 319219019Sgabor snprintf(buf1, sizeof(buf1), "%.*s", 320219019Sgabor (int)_region_size(&data), 321219019Sgabor (const char *)_region_head(&data)); 322219019Sgabor if ((p = strchr(buf1, '/')) != NULL) 323290169Sbdrewery memmove(buf1, p + 1, strlen(p) - 1); 324219019Sgabor if ((p = strstr(buf1, ".esdb")) != NULL) 325219019Sgabor *p = '\0'; 326219019Sgabor snprintf(buf, sizeof(buf), "%s/%.*s", buf1, 327219019Sgabor (int)_region_size(&key), 328219019Sgabor (const char *)_region_head(&key)); 329219019Sgabor } 330219019Sgabor _bcs_convert_to_upper(buf); 331219019Sgabor ret = _lookup_seq_lookup(cla, buf, NULL); 332219019Sgabor if (ret) { 333219019Sgabor if (ret != ENOENT) 334219019Sgabor goto quit3; 335219019Sgabor /* not duplicated */ 336219019Sgabor list[num] = strdup(buf); 337219019Sgabor if (list[num] == NULL) { 338219019Sgabor ret = errno; 339219019Sgabor goto quit3; 340219019Sgabor } 341219019Sgabor num++; 342219019Sgabor } 343219019Sgabor } 344219019Sgabor if (ret != ENOENT) 345219019Sgabor goto quit3; 346219019Sgabor 347219019Sgabor ret = 0; 348219019Sgabor /* XXX: why reallocing the list space posteriorly? 349219019Sgabor shouldn't be done earlier? */ 350316613Spfg q = reallocarray(list, num, sizeof(char *)); 351219019Sgabor if (!q) { 352219019Sgabor ret = ENOMEM; 353219019Sgabor goto quit3; 354219019Sgabor } 355219019Sgabor list = q; 356219019Sgabor *rlist = list; 357219019Sgabor *rnum = num; 358219019Sgaborquit3: 359219019Sgabor if (ret) 360219019Sgabor _citrus_esdb_free_list(list, num); 361219019Sgabor _lookup_seq_close(cld); 362219019Sgaborquit1: 363219019Sgabor _lookup_seq_close(cla); 364219019Sgaborquit0: 365219019Sgabor return (ret); 366219019Sgabor} 367