1/* $FreeBSD: releng/11.0/lib/libiconv_modules/mapper_zone/citrus_mapper_zone.c 219019 2011-02-25 00:04:39Z gabor $ */
2/*	$NetBSD: citrus_mapper_zone.c,v 1.4 2003/07/12 15:39:21 tshiozak Exp $	*/
3
4/*-
5 * Copyright (c)2003 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#include <sys/cdefs.h>
31#include <sys/queue.h>
32
33#include <assert.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include "citrus_namespace.h"
40#include "citrus_types.h"
41#include "citrus_bcs.h"
42#include "citrus_module.h"
43#include "citrus_region.h"
44#include "citrus_memstream.h"
45#include "citrus_mmap.h"
46#include "citrus_hash.h"
47#include "citrus_mapper.h"
48#include "citrus_mapper_zone.h"
49
50/* ---------------------------------------------------------------------- */
51
52_CITRUS_MAPPER_DECLS(mapper_zone);
53_CITRUS_MAPPER_DEF_OPS(mapper_zone);
54
55
56/* ---------------------------------------------------------------------- */
57
58struct _zone {
59	uint32_t	 z_begin;
60	uint32_t	 z_end;
61};
62
63struct _citrus_mapper_zone {
64	struct _zone	 mz_col;
65	struct _zone	 mz_row;
66	int32_t		 mz_col_offset;
67	int32_t		 mz_row_offset;
68	int		 mz_col_bits;
69};
70
71struct _parse_state {
72	enum { S_BEGIN, S_OFFSET }	ps_state;
73	union {
74		uint32_t	u_imm;
75		int32_t		s_imm;
76		struct _zone	zone;
77	} u;
78#define ps_u_imm	u.u_imm
79#define ps_s_imm	u.s_imm
80#define ps_zone		u.zone
81	int ps_top;
82};
83
84int
85_citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops)
86{
87
88	memcpy(ops, &_citrus_mapper_zone_mapper_ops,
89	       sizeof(_citrus_mapper_zone_mapper_ops));
90
91	return (0);
92}
93
94#define BUFSIZE 20
95#define T_ERR	0x100
96#define T_IMM	0x101
97
98static int
99get_imm(struct _memstream *ms, struct _parse_state *ps)
100{
101	int c, i, sign = 0;
102	char buf[BUFSIZE + 1];
103	char *p;
104
105	for (i = 0; i < BUFSIZE; i++) {
106retry:
107		c = _memstream_peek(ms);
108		if (i == 0) {
109			if (sign == 0 && (c == '+' || c == '-')) {
110				sign = c;
111				_memstream_getc(ms);
112				goto retry;
113			} else if (!_bcs_isdigit(c))
114				break;
115		} else if (!_bcs_isxdigit(c))
116			if (!(i == 1 && c == 'x'))
117				break;
118		buf[i] = _memstream_getc(ms);
119	}
120	buf[i] = '\0';
121	ps->ps_u_imm = strtoul(buf, &p, 0);
122	if ((p - buf) != i)
123		return (T_ERR);
124	if (sign == '-')
125		ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm;
126	return (T_IMM);
127}
128
129static int
130get_tok(struct _memstream *ms, struct _parse_state *ps)
131{
132	int c;
133
134loop:
135	c = _memstream_peek(ms);
136	if (c == 0x00)
137		return (EOF);
138	if (_bcs_isspace(c)) {
139		_memstream_getc(ms);
140		goto loop;
141	}
142
143	switch (ps->ps_state) {
144	case S_BEGIN:
145		switch (c) {
146		case ':':
147		case '-':
148		case '/':
149			_memstream_getc(ms);
150			return (c);
151		case '0':
152		case '1':
153		case '2':
154		case '3':
155		case '4':
156		case '5':
157		case '6':
158		case '7':
159		case '8':
160		case '9':
161			return (get_imm(ms, ps));
162		}
163		break;
164	case S_OFFSET:
165		switch (c) {
166		case '/':
167			_memstream_getc(ms);
168			return (c);
169		case '+':
170		case '-':
171		case '0':
172		case '1':
173		case '2':
174		case '3':
175		case '4':
176		case '5':
177		case '6':
178		case '7':
179		case '8':
180		case '9':
181			return (get_imm(ms, ps));
182		}
183		break;
184	}
185	return (T_ERR);
186}
187
188static int
189parse_zone(struct _memstream *ms, struct _parse_state *ps, struct _zone *z)
190{
191
192	if (get_tok(ms, ps) != T_IMM)
193		return (-1);
194	z->z_begin = ps->ps_u_imm;
195	if (get_tok(ms, ps) != '-')
196		return (-1);
197	if (get_tok(ms, ps) != T_IMM)
198		return (-1);
199	z->z_end = ps->ps_u_imm;
200
201	if (z->z_begin > z->z_end)
202		return (-1);
203
204	return (0);
205}
206
207static int
208check_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval)
209{
210	uint32_t remain;
211
212	if (maxval != 0 && z->z_end >= maxval)
213		return (-1);
214
215	if (ofs > 0) {
216		if (maxval == 0)
217			/* this should 0x100000000 - z->z_end */
218			remain = (z->z_end == 0) ? 0xFFFFFFFF :
219			    0xFFFFFFFF - z->z_end + 1;
220		else
221			remain = maxval - z->z_end;
222		if ((uint32_t)ofs > remain)
223			return (-1);
224	} else if (ofs < 0) {
225		if (z->z_begin < (uint32_t)-ofs)
226			return (-1);
227	}
228
229	return (0);
230}
231
232static int
233parse_var(struct _citrus_mapper_zone *mz, struct _memstream *ms)
234{
235	struct _parse_state ps;
236	uint32_t colmax, rowmax;
237	int isrc, ret;
238
239	ps.ps_state = S_BEGIN;
240
241	if (parse_zone(ms, &ps, &mz->mz_col))
242		return (-1);
243
244	ret = get_tok(ms, &ps);
245	if (ret == '/') {
246		/* rowzone / colzone / bits */
247		isrc = 1;
248		mz->mz_row = mz->mz_col;
249
250		if (parse_zone(ms, &ps, &mz->mz_col))
251			return (-1);
252		if (get_tok(ms, &ps) != '/')
253			return (-1);
254		if (get_tok(ms, &ps) != T_IMM)
255			return (-1);
256		mz->mz_col_bits = ps.ps_u_imm;
257		if (mz->mz_col_bits < 0 || mz->mz_col_bits > 32)
258			return (-1);
259		ret = get_tok(ms, &ps);
260	} else {
261		/* colzone */
262		isrc = 0;
263		mz->mz_col_bits = 32;
264		mz->mz_row.z_begin = mz->mz_row.z_end = 0;
265	}
266	if (ret == ':') {
267		/* offset */
268		ps.ps_state = S_OFFSET;
269		if (get_tok(ms, &ps) != T_IMM)
270			return (-1);
271		mz->mz_col_offset = ps.ps_s_imm;
272		if (isrc) {
273			/* row/col */
274			mz->mz_row_offset = mz->mz_col_offset;
275			if (get_tok(ms, &ps) != '/')
276				return (-1);
277			if (get_tok(ms, &ps) != T_IMM)
278				return (-1);
279			mz->mz_col_offset = ps.ps_s_imm;
280		} else
281			mz->mz_row_offset = 0;
282		ret = get_tok(ms, &ps);
283	}
284	if (ret != EOF)
285		return (-1);
286
287	/* sanity check */
288	colmax = (mz->mz_col_bits == 32) ? 0 : 1 << mz->mz_col_bits;
289	rowmax = (mz->mz_col_bits == 0) ? 0 : 1 << (32-mz->mz_col_bits);
290	if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax))
291		return (-1);
292	if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax))
293		return (-1);
294
295	return (0);
296}
297
298static int
299/*ARGSUSED*/
300_citrus_mapper_zone_mapper_init(struct _citrus_mapper_area *__restrict ma __unused,
301    struct _citrus_mapper * __restrict cm, const char * __restrict dir __unused,
302    const void * __restrict var, size_t lenvar,
303    struct _citrus_mapper_traits * __restrict mt, size_t lenmt)
304{
305	struct _citrus_mapper_zone *mz;
306	struct _memstream ms;
307	struct _region r;
308
309	if (lenmt < sizeof(*mt))
310		return (EINVAL);
311
312	mz = malloc(sizeof(*mz));
313	if (mz == NULL)
314		return (errno);
315
316	mz->mz_col.z_begin = mz->mz_col.z_end = 0;
317	mz->mz_row.z_begin = mz->mz_row.z_end = 0;
318	mz->mz_col_bits = 0;
319	mz->mz_row_offset = 0;
320	mz->mz_col_offset = 0;
321
322	_region_init(&r, __DECONST(void *, var), lenvar);
323	_memstream_bind(&ms, &r);
324	if (parse_var(mz, &ms)) {
325		free(mz);
326		return (EINVAL);
327	}
328	cm->cm_closure = mz;
329	mt->mt_src_max = mt->mt_dst_max = 1;	/* 1:1 converter */
330	mt->mt_state_size = 0;			/* stateless */
331
332	return (0);
333}
334
335static void
336/*ARGSUSED*/
337_citrus_mapper_zone_mapper_uninit(struct _citrus_mapper *cm __unused)
338{
339
340}
341
342static int
343/*ARGSUSED*/
344_citrus_mapper_zone_mapper_convert(struct _citrus_mapper * __restrict cm,
345    _citrus_index_t * __restrict dst, _citrus_index_t src,
346    void * __restrict ps __unused)
347{
348	struct _citrus_mapper_zone *mz = cm->cm_closure;
349	uint32_t col, row;
350
351	if (mz->mz_col_bits == 32) {
352		col = src;
353		row = 0;
354		if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end)
355			return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
356		if (mz->mz_col_offset > 0)
357			col += (uint32_t)mz->mz_col_offset;
358		else
359			col -= (uint32_t)-mz->mz_col_offset;
360		*dst = col;
361	} else {
362		col = src & (((uint32_t)1 << mz->mz_col_bits) - 1);
363		row = src >> mz->mz_col_bits;
364		if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end ||
365		    col < mz->mz_col.z_begin || col > mz->mz_col.z_end)
366			return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
367		if (mz->mz_col_offset > 0)
368			col += (uint32_t)mz->mz_col_offset;
369		else
370			col -= (uint32_t)-mz->mz_col_offset;
371		if (mz->mz_row_offset > 0)
372			row += (uint32_t)mz->mz_row_offset;
373		else
374			row -= (uint32_t)-mz->mz_row_offset;
375		*dst = col | (row << mz->mz_col_bits);
376	}
377	return (_CITRUS_MAPPER_CONVERT_SUCCESS);
378}
379
380static void
381/*ARGSUSED*/
382_citrus_mapper_zone_mapper_init_state(void)
383{
384
385}
386