xref: /freebsd/lib/libc/locale/rune.c (revision 8a16b7a18f5d0b031f09832fd7752fba717e2a97)
158f0484fSRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni  *
47b247341SBaptiste Daroussin  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
57b247341SBaptiste Daroussin  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
658f0484fSRodney W. Grimes  * Copyright (c) 1993
758f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
858f0484fSRodney W. Grimes  *
958f0484fSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
1058f0484fSRodney W. Grimes  * Paul Borman at Krystal Technologies.
1158f0484fSRodney W. Grimes  *
1258f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
1358f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
1458f0484fSRodney W. Grimes  * are met:
1558f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1658f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1758f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1858f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1958f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
20fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
2158f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
2258f0484fSRodney W. Grimes  *    without specific prior written permission.
2358f0484fSRodney W. Grimes  *
2458f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2558f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2658f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2758f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2858f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2958f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3058f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3158f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3258f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3358f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3458f0484fSRodney W. Grimes  * SUCH DAMAGE.
3558f0484fSRodney W. Grimes  */
3658f0484fSRodney W. Grimes 
3758f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint)
3858f0484fSRodney W. Grimes static char sccsid[] = "@(#)rune.c	8.1 (Berkeley) 6/4/93";
3958f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */
40333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
41333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
4258f0484fSRodney W. Grimes 
43d201fe46SDaniel Eischen #include "namespace.h"
44fd8e4ebcSMike Barcroft #include <arpa/inet.h>
4576692b80SAndrey A. Chernov #include <errno.h>
46a0998ce6STim J. Robbins #include <runetype.h>
4758f0484fSRodney W. Grimes #include <stdio.h>
48350a3d3eSAndrey A. Chernov #include <string.h>
4958f0484fSRodney W. Grimes #include <stdlib.h>
50350a3d3eSAndrey A. Chernov #include <sys/types.h>
51350a3d3eSAndrey A. Chernov #include <sys/stat.h>
527b247341SBaptiste Daroussin #include <sys/mman.h>
537b247341SBaptiste Daroussin #include <fcntl.h>
547b247341SBaptiste Daroussin #include <unistd.h>
55d201fe46SDaniel Eischen #include "un-namespace.h"
5658f0484fSRodney W. Grimes 
5777bc2a1cSRuslan Bukin #include "endian.h"
58228f8c4fSRuslan Ermilov #include "runefile.h"
59228f8c4fSRuslan Ermilov 
60350a3d3eSAndrey A. Chernov _RuneLocale *
617b247341SBaptiste Daroussin _Read_RuneMagi(const char *fname)
62350a3d3eSAndrey A. Chernov {
633fb3a430SRuslan Ermilov 	char *fdata, *data;
64350a3d3eSAndrey A. Chernov 	void *lastp;
653fb3a430SRuslan Ermilov 	_FileRuneLocale *frl;
66350a3d3eSAndrey A. Chernov 	_RuneLocale *rl;
673fb3a430SRuslan Ermilov 	_FileRuneEntry *frr;
68350a3d3eSAndrey A. Chernov 	_RuneEntry *rr;
69350a3d3eSAndrey A. Chernov 	struct stat sb;
7076692b80SAndrey A. Chernov 	int x, saverr;
713fb3a430SRuslan Ermilov 	void *variable;
723fb3a430SRuslan Ermilov 	_FileRuneEntry *runetype_ext_ranges;
733fb3a430SRuslan Ermilov 	_FileRuneEntry *maplower_ext_ranges;
743fb3a430SRuslan Ermilov 	_FileRuneEntry *mapupper_ext_ranges;
753fb3a430SRuslan Ermilov 	int runetype_ext_len = 0;
767b247341SBaptiste Daroussin 	int fd;
77350a3d3eSAndrey A. Chernov 
787b247341SBaptiste Daroussin 	if ((fd = _open(fname, O_RDONLY)) < 0) {
797b247341SBaptiste Daroussin 		errno = EINVAL;
8076692b80SAndrey A. Chernov 		return (NULL);
817b247341SBaptiste Daroussin 	}
827b247341SBaptiste Daroussin 
837b247341SBaptiste Daroussin 	if (_fstat(fd, &sb) < 0) {
847b247341SBaptiste Daroussin 		(void) _close(fd);
857b247341SBaptiste Daroussin 		errno = EINVAL;
867b247341SBaptiste Daroussin 		return (NULL);
877b247341SBaptiste Daroussin 	}
88350a3d3eSAndrey A. Chernov 
893fb3a430SRuslan Ermilov 	if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
907b247341SBaptiste Daroussin 		(void) _close(fd);
917b247341SBaptiste Daroussin 		errno = EINVAL;
9276692b80SAndrey A. Chernov 		return (NULL);
9376692b80SAndrey A. Chernov 	}
94350a3d3eSAndrey A. Chernov 
95350a3d3eSAndrey A. Chernov 
967b247341SBaptiste Daroussin 	fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
977b247341SBaptiste Daroussin 	(void) _close(fd);
987b247341SBaptiste Daroussin 	if (fdata == NULL) {
997b247341SBaptiste Daroussin 		errno = EINVAL;
10076692b80SAndrey A. Chernov 		return (NULL);
10176692b80SAndrey A. Chernov 	}
102350a3d3eSAndrey A. Chernov 
1037b247341SBaptiste Daroussin 	frl = (_FileRuneLocale *)(void *)fdata;
1043fb3a430SRuslan Ermilov 	lastp = fdata + sb.st_size;
105350a3d3eSAndrey A. Chernov 
1063fb3a430SRuslan Ermilov 	variable = frl + 1;
107350a3d3eSAndrey A. Chernov 
1083fb3a430SRuslan Ermilov 	if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
1097b247341SBaptiste Daroussin 		goto invalid;
110350a3d3eSAndrey A. Chernov 	}
111350a3d3eSAndrey A. Chernov 
1123fb3a430SRuslan Ermilov 	runetype_ext_ranges = (_FileRuneEntry *)variable;
11377bc2a1cSRuslan Bukin 	variable = runetype_ext_ranges + BSWAP(frl->runetype_ext_nranges);
1143fb3a430SRuslan Ermilov 	if (variable > lastp) {
1157b247341SBaptiste Daroussin 		goto invalid;
116350a3d3eSAndrey A. Chernov 	}
117350a3d3eSAndrey A. Chernov 
1183fb3a430SRuslan Ermilov 	maplower_ext_ranges = (_FileRuneEntry *)variable;
11977bc2a1cSRuslan Bukin 	variable = maplower_ext_ranges + BSWAP(frl->maplower_ext_nranges);
1203fb3a430SRuslan Ermilov 	if (variable > lastp) {
1217b247341SBaptiste Daroussin 		goto invalid;
122350a3d3eSAndrey A. Chernov 	}
123350a3d3eSAndrey A. Chernov 
1243fb3a430SRuslan Ermilov 	mapupper_ext_ranges = (_FileRuneEntry *)variable;
12577bc2a1cSRuslan Bukin 	variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
1263fb3a430SRuslan Ermilov 	if (variable > lastp) {
1277b247341SBaptiste Daroussin 		goto invalid;
128350a3d3eSAndrey A. Chernov 	}
129350a3d3eSAndrey A. Chernov 
1303fb3a430SRuslan Ermilov 	frr = runetype_ext_ranges;
13177bc2a1cSRuslan Bukin 	for (x = 0; x < BSWAP(frl->runetype_ext_nranges); ++x) {
1323fb3a430SRuslan Ermilov 		uint32_t *types;
133350a3d3eSAndrey A. Chernov 
13477bc2a1cSRuslan Bukin 		if (BSWAP(frr[x].map) == 0) {
13577bc2a1cSRuslan Bukin 			int len = BSWAP(frr[x].max) - BSWAP(frr[x].min) + 1;
1363fb3a430SRuslan Ermilov 			types = variable;
1373fb3a430SRuslan Ermilov 			variable = types + len;
1383fb3a430SRuslan Ermilov 			runetype_ext_len += len;
1393fb3a430SRuslan Ermilov 			if (variable > lastp) {
1407b247341SBaptiste Daroussin 				goto invalid;
141350a3d3eSAndrey A. Chernov 			}
1423fb3a430SRuslan Ermilov 		}
143350a3d3eSAndrey A. Chernov 	}
144350a3d3eSAndrey A. Chernov 
14577bc2a1cSRuslan Bukin 	if ((char *)variable + BSWAP(frl->variable_len) > (char *)lastp) {
1467b247341SBaptiste Daroussin 		goto invalid;
147350a3d3eSAndrey A. Chernov 	}
148350a3d3eSAndrey A. Chernov 
149350a3d3eSAndrey A. Chernov 	/*
1503fb3a430SRuslan Ermilov 	 * Convert from disk format to host format.
1513fb3a430SRuslan Ermilov 	 */
1523fb3a430SRuslan Ermilov 	data = malloc(sizeof(_RuneLocale) +
15377bc2a1cSRuslan Bukin 	    (BSWAP(frl->runetype_ext_nranges) + BSWAP(frl->maplower_ext_nranges) +
15477bc2a1cSRuslan Bukin 	    BSWAP(frl->mapupper_ext_nranges)) * sizeof(_RuneEntry) +
1553fb3a430SRuslan Ermilov 	    runetype_ext_len * sizeof(*rr->__types) +
15677bc2a1cSRuslan Bukin 	    BSWAP(frl->variable_len));
1573fb3a430SRuslan Ermilov 	if (data == NULL) {
1583fb3a430SRuslan Ermilov 		saverr = errno;
1597b247341SBaptiste Daroussin 		munmap(fdata, sb.st_size);
1603fb3a430SRuslan Ermilov 		errno = saverr;
1613fb3a430SRuslan Ermilov 		return (NULL);
1623fb3a430SRuslan Ermilov 	}
1633fb3a430SRuslan Ermilov 
1643fb3a430SRuslan Ermilov 	rl = (_RuneLocale *)data;
1653fb3a430SRuslan Ermilov 	rl->__variable = rl + 1;
1663fb3a430SRuslan Ermilov 
1673fb3a430SRuslan Ermilov 	memcpy(rl->__magic, _RUNE_MAGIC_1, sizeof(rl->__magic));
1683fb3a430SRuslan Ermilov 	memcpy(rl->__encoding, frl->encoding, sizeof(rl->__encoding));
1693fb3a430SRuslan Ermilov 
17077bc2a1cSRuslan Bukin 	rl->__variable_len = BSWAP(frl->variable_len);
17177bc2a1cSRuslan Bukin 	rl->__runetype_ext.__nranges = BSWAP(frl->runetype_ext_nranges);
17277bc2a1cSRuslan Bukin 	rl->__maplower_ext.__nranges = BSWAP(frl->maplower_ext_nranges);
17377bc2a1cSRuslan Bukin 	rl->__mapupper_ext.__nranges = BSWAP(frl->mapupper_ext_nranges);
1743fb3a430SRuslan Ermilov 
1753fb3a430SRuslan Ermilov 	for (x = 0; x < _CACHED_RUNES; ++x) {
17677bc2a1cSRuslan Bukin 		rl->__runetype[x] = BSWAP(frl->runetype[x]);
17777bc2a1cSRuslan Bukin 		rl->__maplower[x] = BSWAP(frl->maplower[x]);
17877bc2a1cSRuslan Bukin 		rl->__mapupper[x] = BSWAP(frl->mapupper[x]);
1793fb3a430SRuslan Ermilov 	}
1803fb3a430SRuslan Ermilov 
1813fb3a430SRuslan Ermilov 	rl->__runetype_ext.__ranges = (_RuneEntry *)rl->__variable;
1823fb3a430SRuslan Ermilov 	rl->__variable = rl->__runetype_ext.__ranges +
1833fb3a430SRuslan Ermilov 	    rl->__runetype_ext.__nranges;
1843fb3a430SRuslan Ermilov 
1853fb3a430SRuslan Ermilov 	rl->__maplower_ext.__ranges = (_RuneEntry *)rl->__variable;
1863fb3a430SRuslan Ermilov 	rl->__variable = rl->__maplower_ext.__ranges +
1873fb3a430SRuslan Ermilov 	    rl->__maplower_ext.__nranges;
1883fb3a430SRuslan Ermilov 
1893fb3a430SRuslan Ermilov 	rl->__mapupper_ext.__ranges = (_RuneEntry *)rl->__variable;
1903fb3a430SRuslan Ermilov 	rl->__variable = rl->__mapupper_ext.__ranges +
1913fb3a430SRuslan Ermilov 	    rl->__mapupper_ext.__nranges;
1923fb3a430SRuslan Ermilov 
19377bc2a1cSRuslan Bukin 	variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
1943fb3a430SRuslan Ermilov 	frr = runetype_ext_ranges;
1953fb3a430SRuslan Ermilov 	rr = rl->__runetype_ext.__ranges;
1963fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__runetype_ext.__nranges; ++x) {
1973fb3a430SRuslan Ermilov 		uint32_t *types;
1983fb3a430SRuslan Ermilov 
19977bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
20077bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
20177bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2023fb3a430SRuslan Ermilov 		if (rr[x].__map == 0) {
2033fb3a430SRuslan Ermilov 			int len = rr[x].__max - rr[x].__min + 1;
2043fb3a430SRuslan Ermilov 			types = variable;
2053fb3a430SRuslan Ermilov 			variable = types + len;
2063fb3a430SRuslan Ermilov 			rr[x].__types = rl->__variable;
2073fb3a430SRuslan Ermilov 			rl->__variable = rr[x].__types + len;
2083fb3a430SRuslan Ermilov 			while (len-- > 0)
2093fb3a430SRuslan Ermilov 				rr[x].__types[len] = types[len];
2103fb3a430SRuslan Ermilov 		} else
2113fb3a430SRuslan Ermilov 			rr[x].__types = NULL;
2123fb3a430SRuslan Ermilov 	}
2133fb3a430SRuslan Ermilov 
2143fb3a430SRuslan Ermilov 	frr = maplower_ext_ranges;
2153fb3a430SRuslan Ermilov 	rr = rl->__maplower_ext.__ranges;
2163fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__maplower_ext.__nranges; ++x) {
21777bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
21877bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
21977bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2203fb3a430SRuslan Ermilov 	}
2213fb3a430SRuslan Ermilov 
2223fb3a430SRuslan Ermilov 	frr = mapupper_ext_ranges;
2233fb3a430SRuslan Ermilov 	rr = rl->__mapupper_ext.__ranges;
2243fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__mapupper_ext.__nranges; ++x) {
22577bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
22677bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
22777bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2283fb3a430SRuslan Ermilov 	}
2293fb3a430SRuslan Ermilov 
2303fb3a430SRuslan Ermilov 	memcpy(rl->__variable, variable, rl->__variable_len);
2317b247341SBaptiste Daroussin 	munmap(fdata, sb.st_size);
2323fb3a430SRuslan Ermilov 
2333fb3a430SRuslan Ermilov 	/*
234350a3d3eSAndrey A. Chernov 	 * Go out and zero pointers that should be zero.
235350a3d3eSAndrey A. Chernov 	 */
236ddc1ededSTim J. Robbins 	if (!rl->__variable_len)
2373fb3a430SRuslan Ermilov 		rl->__variable = NULL;
238350a3d3eSAndrey A. Chernov 
239ddc1ededSTim J. Robbins 	if (!rl->__runetype_ext.__nranges)
2403fb3a430SRuslan Ermilov 		rl->__runetype_ext.__ranges = NULL;
241350a3d3eSAndrey A. Chernov 
242ddc1ededSTim J. Robbins 	if (!rl->__maplower_ext.__nranges)
2433fb3a430SRuslan Ermilov 		rl->__maplower_ext.__ranges = NULL;
244350a3d3eSAndrey A. Chernov 
245ddc1ededSTim J. Robbins 	if (!rl->__mapupper_ext.__nranges)
2463fb3a430SRuslan Ermilov 		rl->__mapupper_ext.__ranges = NULL;
247350a3d3eSAndrey A. Chernov 
248350a3d3eSAndrey A. Chernov 	return (rl);
2497b247341SBaptiste Daroussin 
2507b247341SBaptiste Daroussin invalid:
2517b247341SBaptiste Daroussin 	munmap(fdata, sb.st_size);
2527b247341SBaptiste Daroussin 	errno = EINVAL;
2537b247341SBaptiste Daroussin 	return (NULL);
254350a3d3eSAndrey A. Chernov }
255