xref: /freebsd/lib/libc/locale/rune.c (revision fbbd9655)
158f0484fSRodney W. Grimes /*-
27b247341SBaptiste Daroussin  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
37b247341SBaptiste Daroussin  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
458f0484fSRodney W. Grimes  * Copyright (c) 1993
558f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
658f0484fSRodney W. Grimes  *
758f0484fSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
858f0484fSRodney W. Grimes  * Paul Borman at Krystal Technologies.
958f0484fSRodney W. Grimes  *
1058f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
1158f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
1258f0484fSRodney W. Grimes  * are met:
1358f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
1458f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1558f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1658f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1758f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
1958f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
2058f0484fSRodney W. Grimes  *    without specific prior written permission.
2158f0484fSRodney W. Grimes  *
2258f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2358f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2458f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2558f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2658f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2758f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2858f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2958f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3058f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3158f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258f0484fSRodney W. Grimes  * SUCH DAMAGE.
3358f0484fSRodney W. Grimes  */
3458f0484fSRodney W. Grimes 
3558f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint)
3658f0484fSRodney W. Grimes static char sccsid[] = "@(#)rune.c	8.1 (Berkeley) 6/4/93";
3758f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */
38333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
39333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
4058f0484fSRodney W. Grimes 
41d201fe46SDaniel Eischen #include "namespace.h"
42fd8e4ebcSMike Barcroft #include <arpa/inet.h>
4376692b80SAndrey A. Chernov #include <errno.h>
44a0998ce6STim J. Robbins #include <runetype.h>
4558f0484fSRodney W. Grimes #include <stdio.h>
46350a3d3eSAndrey A. Chernov #include <string.h>
4758f0484fSRodney W. Grimes #include <stdlib.h>
48350a3d3eSAndrey A. Chernov #include <sys/types.h>
49350a3d3eSAndrey A. Chernov #include <sys/stat.h>
507b247341SBaptiste Daroussin #include <sys/mman.h>
517b247341SBaptiste Daroussin #include <fcntl.h>
527b247341SBaptiste Daroussin #include <unistd.h>
53d201fe46SDaniel Eischen #include "un-namespace.h"
5458f0484fSRodney W. Grimes 
5577bc2a1cSRuslan Bukin #include "endian.h"
56228f8c4fSRuslan Ermilov #include "runefile.h"
57228f8c4fSRuslan Ermilov 
58350a3d3eSAndrey A. Chernov _RuneLocale *
597b247341SBaptiste Daroussin _Read_RuneMagi(const char *fname)
60350a3d3eSAndrey A. Chernov {
613fb3a430SRuslan Ermilov 	char *fdata, *data;
62350a3d3eSAndrey A. Chernov 	void *lastp;
633fb3a430SRuslan Ermilov 	_FileRuneLocale *frl;
64350a3d3eSAndrey A. Chernov 	_RuneLocale *rl;
653fb3a430SRuslan Ermilov 	_FileRuneEntry *frr;
66350a3d3eSAndrey A. Chernov 	_RuneEntry *rr;
67350a3d3eSAndrey A. Chernov 	struct stat sb;
6876692b80SAndrey A. Chernov 	int x, saverr;
693fb3a430SRuslan Ermilov 	void *variable;
703fb3a430SRuslan Ermilov 	_FileRuneEntry *runetype_ext_ranges;
713fb3a430SRuslan Ermilov 	_FileRuneEntry *maplower_ext_ranges;
723fb3a430SRuslan Ermilov 	_FileRuneEntry *mapupper_ext_ranges;
733fb3a430SRuslan Ermilov 	int runetype_ext_len = 0;
747b247341SBaptiste Daroussin 	int fd;
75350a3d3eSAndrey A. Chernov 
767b247341SBaptiste Daroussin 	if ((fd = _open(fname, O_RDONLY)) < 0) {
777b247341SBaptiste Daroussin 		errno = EINVAL;
7876692b80SAndrey A. Chernov 		return (NULL);
797b247341SBaptiste Daroussin 	}
807b247341SBaptiste Daroussin 
817b247341SBaptiste Daroussin 	if (_fstat(fd, &sb) < 0) {
827b247341SBaptiste Daroussin 		(void) _close(fd);
837b247341SBaptiste Daroussin 		errno = EINVAL;
847b247341SBaptiste Daroussin 		return (NULL);
857b247341SBaptiste Daroussin 	}
86350a3d3eSAndrey A. Chernov 
873fb3a430SRuslan Ermilov 	if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
887b247341SBaptiste Daroussin 		(void) _close(fd);
897b247341SBaptiste Daroussin 		errno = EINVAL;
9076692b80SAndrey A. Chernov 		return (NULL);
9176692b80SAndrey A. Chernov 	}
92350a3d3eSAndrey A. Chernov 
93350a3d3eSAndrey A. Chernov 
947b247341SBaptiste Daroussin 	fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
957b247341SBaptiste Daroussin 	(void) _close(fd);
967b247341SBaptiste Daroussin 	if (fdata == NULL) {
977b247341SBaptiste Daroussin 		errno = EINVAL;
9876692b80SAndrey A. Chernov 		return (NULL);
9976692b80SAndrey A. Chernov 	}
100350a3d3eSAndrey A. Chernov 
1017b247341SBaptiste Daroussin 	frl = (_FileRuneLocale *)(void *)fdata;
1023fb3a430SRuslan Ermilov 	lastp = fdata + sb.st_size;
103350a3d3eSAndrey A. Chernov 
1043fb3a430SRuslan Ermilov 	variable = frl + 1;
105350a3d3eSAndrey A. Chernov 
1063fb3a430SRuslan Ermilov 	if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
1077b247341SBaptiste Daroussin 		goto invalid;
108350a3d3eSAndrey A. Chernov 	}
109350a3d3eSAndrey A. Chernov 
1103fb3a430SRuslan Ermilov 	runetype_ext_ranges = (_FileRuneEntry *)variable;
11177bc2a1cSRuslan Bukin 	variable = runetype_ext_ranges + BSWAP(frl->runetype_ext_nranges);
1123fb3a430SRuslan Ermilov 	if (variable > lastp) {
1137b247341SBaptiste Daroussin 		goto invalid;
114350a3d3eSAndrey A. Chernov 	}
115350a3d3eSAndrey A. Chernov 
1163fb3a430SRuslan Ermilov 	maplower_ext_ranges = (_FileRuneEntry *)variable;
11777bc2a1cSRuslan Bukin 	variable = maplower_ext_ranges + BSWAP(frl->maplower_ext_nranges);
1183fb3a430SRuslan Ermilov 	if (variable > lastp) {
1197b247341SBaptiste Daroussin 		goto invalid;
120350a3d3eSAndrey A. Chernov 	}
121350a3d3eSAndrey A. Chernov 
1223fb3a430SRuslan Ermilov 	mapupper_ext_ranges = (_FileRuneEntry *)variable;
12377bc2a1cSRuslan Bukin 	variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
1243fb3a430SRuslan Ermilov 	if (variable > lastp) {
1257b247341SBaptiste Daroussin 		goto invalid;
126350a3d3eSAndrey A. Chernov 	}
127350a3d3eSAndrey A. Chernov 
1283fb3a430SRuslan Ermilov 	frr = runetype_ext_ranges;
12977bc2a1cSRuslan Bukin 	for (x = 0; x < BSWAP(frl->runetype_ext_nranges); ++x) {
1303fb3a430SRuslan Ermilov 		uint32_t *types;
131350a3d3eSAndrey A. Chernov 
13277bc2a1cSRuslan Bukin 		if (BSWAP(frr[x].map) == 0) {
13377bc2a1cSRuslan Bukin 			int len = BSWAP(frr[x].max) - BSWAP(frr[x].min) + 1;
1343fb3a430SRuslan Ermilov 			types = variable;
1353fb3a430SRuslan Ermilov 			variable = types + len;
1363fb3a430SRuslan Ermilov 			runetype_ext_len += len;
1373fb3a430SRuslan Ermilov 			if (variable > lastp) {
1387b247341SBaptiste Daroussin 				goto invalid;
139350a3d3eSAndrey A. Chernov 			}
1403fb3a430SRuslan Ermilov 		}
141350a3d3eSAndrey A. Chernov 	}
142350a3d3eSAndrey A. Chernov 
14377bc2a1cSRuslan Bukin 	if ((char *)variable + BSWAP(frl->variable_len) > (char *)lastp) {
1447b247341SBaptiste Daroussin 		goto invalid;
145350a3d3eSAndrey A. Chernov 	}
146350a3d3eSAndrey A. Chernov 
147350a3d3eSAndrey A. Chernov 	/*
1483fb3a430SRuslan Ermilov 	 * Convert from disk format to host format.
1493fb3a430SRuslan Ermilov 	 */
1503fb3a430SRuslan Ermilov 	data = malloc(sizeof(_RuneLocale) +
15177bc2a1cSRuslan Bukin 	    (BSWAP(frl->runetype_ext_nranges) + BSWAP(frl->maplower_ext_nranges) +
15277bc2a1cSRuslan Bukin 	    BSWAP(frl->mapupper_ext_nranges)) * sizeof(_RuneEntry) +
1533fb3a430SRuslan Ermilov 	    runetype_ext_len * sizeof(*rr->__types) +
15477bc2a1cSRuslan Bukin 	    BSWAP(frl->variable_len));
1553fb3a430SRuslan Ermilov 	if (data == NULL) {
1563fb3a430SRuslan Ermilov 		saverr = errno;
1577b247341SBaptiste Daroussin 		munmap(fdata, sb.st_size);
1583fb3a430SRuslan Ermilov 		errno = saverr;
1593fb3a430SRuslan Ermilov 		return (NULL);
1603fb3a430SRuslan Ermilov 	}
1613fb3a430SRuslan Ermilov 
1623fb3a430SRuslan Ermilov 	rl = (_RuneLocale *)data;
1633fb3a430SRuslan Ermilov 	rl->__variable = rl + 1;
1643fb3a430SRuslan Ermilov 
1653fb3a430SRuslan Ermilov 	memcpy(rl->__magic, _RUNE_MAGIC_1, sizeof(rl->__magic));
1663fb3a430SRuslan Ermilov 	memcpy(rl->__encoding, frl->encoding, sizeof(rl->__encoding));
1673fb3a430SRuslan Ermilov 
16877bc2a1cSRuslan Bukin 	rl->__variable_len = BSWAP(frl->variable_len);
16977bc2a1cSRuslan Bukin 	rl->__runetype_ext.__nranges = BSWAP(frl->runetype_ext_nranges);
17077bc2a1cSRuslan Bukin 	rl->__maplower_ext.__nranges = BSWAP(frl->maplower_ext_nranges);
17177bc2a1cSRuslan Bukin 	rl->__mapupper_ext.__nranges = BSWAP(frl->mapupper_ext_nranges);
1723fb3a430SRuslan Ermilov 
1733fb3a430SRuslan Ermilov 	for (x = 0; x < _CACHED_RUNES; ++x) {
17477bc2a1cSRuslan Bukin 		rl->__runetype[x] = BSWAP(frl->runetype[x]);
17577bc2a1cSRuslan Bukin 		rl->__maplower[x] = BSWAP(frl->maplower[x]);
17677bc2a1cSRuslan Bukin 		rl->__mapupper[x] = BSWAP(frl->mapupper[x]);
1773fb3a430SRuslan Ermilov 	}
1783fb3a430SRuslan Ermilov 
1793fb3a430SRuslan Ermilov 	rl->__runetype_ext.__ranges = (_RuneEntry *)rl->__variable;
1803fb3a430SRuslan Ermilov 	rl->__variable = rl->__runetype_ext.__ranges +
1813fb3a430SRuslan Ermilov 	    rl->__runetype_ext.__nranges;
1823fb3a430SRuslan Ermilov 
1833fb3a430SRuslan Ermilov 	rl->__maplower_ext.__ranges = (_RuneEntry *)rl->__variable;
1843fb3a430SRuslan Ermilov 	rl->__variable = rl->__maplower_ext.__ranges +
1853fb3a430SRuslan Ermilov 	    rl->__maplower_ext.__nranges;
1863fb3a430SRuslan Ermilov 
1873fb3a430SRuslan Ermilov 	rl->__mapupper_ext.__ranges = (_RuneEntry *)rl->__variable;
1883fb3a430SRuslan Ermilov 	rl->__variable = rl->__mapupper_ext.__ranges +
1893fb3a430SRuslan Ermilov 	    rl->__mapupper_ext.__nranges;
1903fb3a430SRuslan Ermilov 
19177bc2a1cSRuslan Bukin 	variable = mapupper_ext_ranges + BSWAP(frl->mapupper_ext_nranges);
1923fb3a430SRuslan Ermilov 	frr = runetype_ext_ranges;
1933fb3a430SRuslan Ermilov 	rr = rl->__runetype_ext.__ranges;
1943fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__runetype_ext.__nranges; ++x) {
1953fb3a430SRuslan Ermilov 		uint32_t *types;
1963fb3a430SRuslan Ermilov 
19777bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
19877bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
19977bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2003fb3a430SRuslan Ermilov 		if (rr[x].__map == 0) {
2013fb3a430SRuslan Ermilov 			int len = rr[x].__max - rr[x].__min + 1;
2023fb3a430SRuslan Ermilov 			types = variable;
2033fb3a430SRuslan Ermilov 			variable = types + len;
2043fb3a430SRuslan Ermilov 			rr[x].__types = rl->__variable;
2053fb3a430SRuslan Ermilov 			rl->__variable = rr[x].__types + len;
2063fb3a430SRuslan Ermilov 			while (len-- > 0)
2073fb3a430SRuslan Ermilov 				rr[x].__types[len] = types[len];
2083fb3a430SRuslan Ermilov 		} else
2093fb3a430SRuslan Ermilov 			rr[x].__types = NULL;
2103fb3a430SRuslan Ermilov 	}
2113fb3a430SRuslan Ermilov 
2123fb3a430SRuslan Ermilov 	frr = maplower_ext_ranges;
2133fb3a430SRuslan Ermilov 	rr = rl->__maplower_ext.__ranges;
2143fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__maplower_ext.__nranges; ++x) {
21577bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
21677bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
21777bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2183fb3a430SRuslan Ermilov 	}
2193fb3a430SRuslan Ermilov 
2203fb3a430SRuslan Ermilov 	frr = mapupper_ext_ranges;
2213fb3a430SRuslan Ermilov 	rr = rl->__mapupper_ext.__ranges;
2223fb3a430SRuslan Ermilov 	for (x = 0; x < rl->__mapupper_ext.__nranges; ++x) {
22377bc2a1cSRuslan Bukin 		rr[x].__min = BSWAP(frr[x].min);
22477bc2a1cSRuslan Bukin 		rr[x].__max = BSWAP(frr[x].max);
22577bc2a1cSRuslan Bukin 		rr[x].__map = BSWAP(frr[x].map);
2263fb3a430SRuslan Ermilov 	}
2273fb3a430SRuslan Ermilov 
2283fb3a430SRuslan Ermilov 	memcpy(rl->__variable, variable, rl->__variable_len);
2297b247341SBaptiste Daroussin 	munmap(fdata, sb.st_size);
2303fb3a430SRuslan Ermilov 
2313fb3a430SRuslan Ermilov 	/*
232350a3d3eSAndrey A. Chernov 	 * Go out and zero pointers that should be zero.
233350a3d3eSAndrey A. Chernov 	 */
234ddc1ededSTim J. Robbins 	if (!rl->__variable_len)
2353fb3a430SRuslan Ermilov 		rl->__variable = NULL;
236350a3d3eSAndrey A. Chernov 
237ddc1ededSTim J. Robbins 	if (!rl->__runetype_ext.__nranges)
2383fb3a430SRuslan Ermilov 		rl->__runetype_ext.__ranges = NULL;
239350a3d3eSAndrey A. Chernov 
240ddc1ededSTim J. Robbins 	if (!rl->__maplower_ext.__nranges)
2413fb3a430SRuslan Ermilov 		rl->__maplower_ext.__ranges = NULL;
242350a3d3eSAndrey A. Chernov 
243ddc1ededSTim J. Robbins 	if (!rl->__mapupper_ext.__nranges)
2443fb3a430SRuslan Ermilov 		rl->__mapupper_ext.__ranges = NULL;
245350a3d3eSAndrey A. Chernov 
246350a3d3eSAndrey A. Chernov 	return (rl);
2477b247341SBaptiste Daroussin 
2487b247341SBaptiste Daroussin invalid:
2497b247341SBaptiste Daroussin 	munmap(fdata, sb.st_size);
2507b247341SBaptiste Daroussin 	errno = EINVAL;
2517b247341SBaptiste Daroussin 	return (NULL);
252350a3d3eSAndrey A. Chernov }
253