xref: /dragonfly/lib/libc/locale/rune.c (revision 1847e88f)
1 /*	$NetBSD: src/lib/libc/locale/rune.c,v 1.26 2004/05/09 11:26:33 kleink Exp $	*/
2 /*	$DragonFly: src/lib/libc/locale/rune.c,v 1.6 2005/11/20 09:18:37 swildner Exp $	*/
3 
4 /*-
5  * Copyright (c)1999 Citrus Project,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*-
31  * Copyright (c) 1993
32  *	The Regents of the University of California.  All rights reserved.
33  *
34  * This code is derived from software contributed to Berkeley by
35  * Paul Borman at Krystal Technologies.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  */
61 
62 #include <sys/types.h>
63 #include <sys/stat.h>
64 #include <assert.h>
65 #include <errno.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <wchar.h>
70 
71 #include <arpa/inet.h>
72 
73 #include "../citrus/citrus_module.h"
74 #include "../citrus/citrus_ctype.h"
75 #include "rune.h"
76 #include "rune_local.h"
77 
78 static int	readrange(_RuneLocale *, _RuneRange *, _FileRuneRange *,
79 			  void *, FILE *);
80 static void	_freeentry(_RuneRange *);
81 static void	_wctype_init(_RuneLocale *rl);
82 
83 static int
84 readrange(_RuneLocale *rl, _RuneRange *rr, _FileRuneRange *frr, void *lastp,
85 	  FILE *fp)
86 {
87 	uint32_t i;
88 	_RuneEntry *re;
89 	_FileRuneEntry fre;
90 
91 	_DIAGASSERT(rl != NULL);
92 	_DIAGASSERT(rr != NULL);
93 	_DIAGASSERT(frr != NULL);
94 	_DIAGASSERT(lastp != NULL);
95 	_DIAGASSERT(fp != NULL);
96 
97 	re = (_RuneEntry *)rl->rl_variable;
98 
99 	rr->rr_nranges = ntohl(frr->frr_nranges);
100 	if (rr->rr_nranges == 0) {
101 		rr->rr_rune_ranges = NULL;
102 		return(0);
103 	}
104 
105 	rr->rr_rune_ranges = re;
106 	for (i = 0; i < rr->rr_nranges; i++) {
107 		if (fread(&fre, sizeof(fre), 1, fp) != 1)
108 			return(-1);
109 
110 		re->re_min = ntohl((uint32_t)fre.fre_min);
111 		re->re_max = ntohl((uint32_t)fre.fre_max);
112 		re->re_map = ntohl((uint32_t)fre.fre_map);
113 		re++;
114 
115 		if ((void *)re > lastp)
116 			return(-1);
117 	}
118 	rl->rl_variable = re;
119 	return(0);
120 }
121 
122 static int
123 readentry(_RuneRange *rr, FILE *fp)
124 {
125 	_RuneEntry *re;
126 	size_t l, i, j;
127 	int error;
128 
129 	_DIAGASSERT(rr != NULL);
130 	_DIAGASSERT(fp != NULL);
131 
132 	re = rr->rr_rune_ranges;
133 	for (i = 0; i < rr->rr_nranges; i++) {
134 		if (re[i].re_map != 0) {
135 			re[i].re_rune_types = NULL;
136 			continue;
137 		}
138 
139 		l = re[i].re_max - re[i].re_min + 1;
140 		re[i].re_rune_types = malloc(l * sizeof(_RuneType));
141 		if (!re[i].re_rune_types) {
142 			error = ENOMEM;
143 			goto fail;
144 		}
145 		memset(re[i].re_rune_types, 0, l * sizeof(_RuneType));
146 
147 		if (fread(re[i].re_rune_types, sizeof(_RuneType), l, fp) != l)
148 			goto fail2;
149 
150 		for (j = 0; j < l; j++)
151 			re[i].re_rune_types[j] = ntohl(re[i].re_rune_types[j]);
152 	}
153 	return(0);
154 
155 fail:
156 	for (j = 0; j < i; j++) {
157 		free(re[j].re_rune_types);
158 		re[j].re_rune_types = NULL;
159 	}
160 	return(error);
161 
162 fail2:
163 	for (j = 0; j <= i; j++) {
164 		free(re[j].re_rune_types);
165 		re[j].re_rune_types = NULL;
166 	}
167 	return(errno);
168 }
169 
170 /* XXX: temporary implementation */
171 static void
172 find_codeset(_RuneLocale *rl)
173 {
174 	char *top, *codeset, *tail, *ep;
175 
176 	/* end of rl_variable region */
177 	ep = (char *)rl->rl_variable;
178 	ep += rl->rl_variable_len;
179 	rl->rl_codeset = NULL;
180 	if (!(top = strstr(rl->rl_variable, _RUNE_CODESET)))
181 		return;
182 	tail = strpbrk(top, " \t");
183 	codeset = top + sizeof(_RUNE_CODESET) - 1;
184 	if (tail) {
185 		*top = *tail;
186 		*tail = '\0';
187 		rl->rl_codeset = strdup(codeset);
188 		strlcpy(top + 1, tail + 1, (unsigned)(ep - (top + 1)));
189 	} else {
190 		*top = '\0';
191 		rl->rl_codeset = strdup(codeset);
192 	}
193 }
194 
195 static void
196 _freeentry(_RuneRange *rr)
197 {
198 	_RuneEntry *re;
199 	uint32_t i;
200 
201 	_DIAGASSERT(rr != NULL);
202 
203 	re = rr->rr_rune_ranges;
204 	for (i = 0; i < rr->rr_nranges; i++) {
205 		if (re[i].re_rune_types)
206 			free(re[i].re_rune_types);
207 		re[i].re_rune_types = NULL;
208 	}
209 }
210 
211 void
212 _wctype_init(_RuneLocale *rl)
213 {
214 	memcpy(&rl->rl_wctype, &_DefaultRuneLocale.rl_wctype,
215 	       sizeof(rl->rl_wctype));
216 }
217 
218 
219 _RuneLocale *
220 _Read_RuneMagi(FILE *fp)
221 {
222 	/* file */
223 	_FileRuneLocale frl;
224 	/* host data */
225 	char *hostdata;
226 	size_t hostdatalen;
227 	void *lastp;
228 	_RuneLocale *rl;
229 	struct stat sb;
230 	int x;
231 
232 	_DIAGASSERT(fp != NULL);
233 
234 	if (fstat(fileno(fp), &sb) < 0)
235 		return(NULL);
236 
237 	if (sb.st_size < sizeof(_FileRuneLocale))
238 		return(NULL);
239 	/* XXX more validation? */
240 
241 	/* Someone might have read the magic number once already */
242 	rewind(fp);
243 
244 	if (fread(&frl, sizeof(frl), 1, fp) != 1)
245 		return(NULL);
246 	if (memcmp(frl.frl_magic, _RUNE_MAGIC_1, sizeof(frl.frl_magic)))
247 		return(NULL);
248 
249 	hostdatalen = sizeof(*rl) + ntohl((u_int32_t)frl.frl_variable_len) +
250 	    ntohl(frl.frl_runetype_ext.frr_nranges) * sizeof(_RuneEntry) +
251 	    ntohl(frl.frl_maplower_ext.frr_nranges) * sizeof(_RuneEntry) +
252 	    ntohl(frl.frl_mapupper_ext.frr_nranges) * sizeof(_RuneEntry);
253 
254 	if ((hostdata = malloc(hostdatalen)) == NULL)
255 		return(NULL);
256 	memset(hostdata, 0, hostdatalen);
257 	lastp = hostdata + hostdatalen;
258 
259 	rl = (_RuneLocale *)(void *)hostdata;
260 	rl->rl_variable = rl + 1;
261 
262 	memcpy(rl->rl_magic, frl.frl_magic, sizeof(rl->rl_magic));
263 	memcpy(rl->rl_encoding, frl.frl_encoding, sizeof(rl->rl_encoding));
264 
265 	rl->rl_invalid_rune = ntohl((u_int32_t)frl.frl_invalid_rune);
266 	rl->rl_variable_len = ntohl((u_int32_t)frl.frl_variable_len);
267 
268 	for (x = 0; x < _CACHED_RUNES; ++x) {
269 		rl->rl_runetype[x] = ntohl(frl.frl_runetype[x]);
270 
271 		/* XXX assumes rune_t = u_int32_t */
272 		rl->rl_maplower[x] = ntohl((uint32_t)frl.frl_maplower[x]);
273 		rl->rl_mapupper[x] = ntohl((uint32_t)frl.frl_mapupper[x]);
274 	}
275 
276 	if (readrange(rl, &rl->rl_runetype_ext, &frl.frl_runetype_ext,
277 		      lastp, fp)) {
278 		free(hostdata);
279 		return(NULL);
280 	}
281 	if (readrange(rl, &rl->rl_maplower_ext, &frl.frl_maplower_ext,
282 		      lastp, fp)) {
283 		free(hostdata);
284 		return(NULL);
285 	}
286 	if (readrange(rl, &rl->rl_mapupper_ext, &frl.frl_mapupper_ext,
287 		      lastp, fp)) {
288 		free(hostdata);
289 		return(NULL);
290 	}
291 
292 	if (readentry(&rl->rl_runetype_ext, fp) != 0) {
293 		free(hostdata);
294 		return(NULL);
295 	}
296 
297 	if ((uint8_t *)rl->rl_variable + rl->rl_variable_len >
298 	    (uint8_t *)lastp) {
299 		_freeentry(&rl->rl_runetype_ext);
300 		free(hostdata);
301 		return(NULL);
302 	}
303 	if (rl->rl_variable_len == 0)
304 		rl->rl_variable = NULL;
305 	else if (fread(rl->rl_variable, rl->rl_variable_len, 1, fp) != 1) {
306 		_freeentry(&rl->rl_runetype_ext);
307 		free(hostdata);
308 		return(NULL);
309 	}
310 	find_codeset(rl);
311 	_wctype_init(rl);
312 
313 	/* error if we have junk at the tail */
314 	if (ftell(fp) != sb.st_size) {
315 		_freeentry(&rl->rl_runetype_ext);
316 		free(hostdata);
317 		return(NULL);
318 	}
319 
320 	return(rl);
321 }
322 
323 void
324 _NukeRune(_RuneLocale *rl)
325 {
326 	_DIAGASSERT(rl != NULL);
327 
328 	if (rl != &_DefaultRuneLocale) {
329 		_freeentry(&rl->rl_runetype_ext);
330 		if (rl->rl_codeset != NULL)
331 			free(rl->rl_codeset);
332 		if (rl->rl_citrus_ctype)
333 			_citrus_ctype_close(rl->rl_citrus_ctype);
334 		free(rl);
335 	}
336 }
337