1/* $FreeBSD$ */
2/*	$NetBSD: citrus_euc.c,v 1.14 2009/01/11 02:46:24 christos Exp $	*/
3
4/*-
5 * Copyright (c)2002 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 * SPDX-License-Identifier: BSD-3-Clause
32 *
33 * Copyright (c) 1993
34 *	The Regents of the University of California.  All rights reserved.
35 *
36 * This code is derived from software contributed to Berkeley by
37 * Paul Borman at Krystal Technologies.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 *    may be used to endorse or promote products derived from this software
49 *    without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64#include <sys/cdefs.h>
65#include <sys/types.h>
66
67#include <assert.h>
68#include <errno.h>
69#include <limits.h>
70#include <stddef.h>
71#include <stdio.h>
72#include <stdlib.h>
73#include <string.h>
74#include <wchar.h>
75
76#include "citrus_namespace.h"
77#include "citrus_bcs.h"
78#include "citrus_types.h"
79#include "citrus_module.h"
80#include "citrus_stdenc.h"
81#include "citrus_euc.h"
82
83
84/* ----------------------------------------------------------------------
85 * private stuffs used by templates
86 */
87
88typedef struct {
89	int	 chlen;
90	char	 ch[3];
91} _EUCState;
92
93typedef struct {
94	wchar_t		 bits[4];
95	wchar_t		 mask;
96	unsigned	 count[4];
97	unsigned	 mb_cur_max;
98} _EUCEncodingInfo;
99
100#define	_SS2	0x008e
101#define	_SS3	0x008f
102
103#define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
104#define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
105
106#define _FUNCNAME(m)			_citrus_EUC_##m
107#define _ENCODING_INFO			_EUCEncodingInfo
108#define _ENCODING_STATE			_EUCState
109#define _ENCODING_MB_CUR_MAX(_ei_)	(_ei_)->mb_cur_max
110#define _ENCODING_IS_STATE_DEPENDENT	0
111#define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	0
112
113
114static __inline int
115_citrus_EUC_cs(unsigned int c)
116{
117
118	c &= 0xff;
119
120	return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0);
121}
122
123static __inline int
124_citrus_EUC_parse_variable(_EUCEncodingInfo *ei, const void *var,
125    size_t lenvar __unused)
126{
127	char *e;
128	const char *v;
129	int x;
130
131	/* parse variable string */
132	if (!var)
133		return (EFTYPE);
134
135	v = (const char *)var;
136
137	while (*v == ' ' || *v == '\t')
138		++v;
139
140	ei->mb_cur_max = 1;
141	for (x = 0; x < 4; ++x) {
142		ei->count[x] = (int)_bcs_strtol(v, (char **)&e, 0);
143		if (v == e || !(v = e) || ei->count[x] < 1 || ei->count[x] > 4) {
144			return (EFTYPE);
145		}
146		if (ei->mb_cur_max < ei->count[x])
147			ei->mb_cur_max = ei->count[x];
148		while (*v == ' ' || *v == '\t')
149			++v;
150		ei->bits[x] = (int)_bcs_strtol(v, (char **)&e, 0);
151		if (v == e || !(v = e)) {
152			return (EFTYPE);
153		}
154		while (*v == ' ' || *v == '\t')
155			++v;
156	}
157	ei->mask = (int)_bcs_strtol(v, (char **)&e, 0);
158	if (v == e || !(v = e)) {
159		return (EFTYPE);
160	}
161
162	return (0);
163}
164
165
166static __inline void
167/*ARGSUSED*/
168_citrus_EUC_init_state(_EUCEncodingInfo *ei __unused, _EUCState *s)
169{
170
171	memset(s, 0, sizeof(*s));
172}
173
174#if 0
175static __inline void
176/*ARGSUSED*/
177_citrus_EUC_pack_state(_EUCEncodingInfo *ei __unused, void *pspriv,
178    const _EUCState *s)
179{
180
181	memcpy(pspriv, (const void *)s, sizeof(*s));
182}
183
184static __inline void
185/*ARGSUSED*/
186_citrus_EUC_unpack_state(_EUCEncodingInfo *ei __unused, _EUCState *s,
187    const void *pspriv)
188{
189
190	memcpy((void *)s, pspriv, sizeof(*s));
191}
192#endif
193
194static int
195_citrus_EUC_mbrtowc_priv(_EUCEncodingInfo *ei, wchar_t *pwc, char **s,
196    size_t n, _EUCState *psenc, size_t *nresult)
197{
198	wchar_t wchar;
199	int c, chlenbak, cs, len;
200	char *s0, *s1 = NULL;
201
202	s0 = *s;
203
204	if (s0 == NULL) {
205		_citrus_EUC_init_state(ei, psenc);
206		*nresult = 0; /* state independent */
207		return (0);
208	}
209
210	chlenbak = psenc->chlen;
211
212	/* make sure we have the first byte in the buffer */
213	switch (psenc->chlen) {
214	case 0:
215		if (n < 1)
216			goto restart;
217		psenc->ch[0] = *s0++;
218		psenc->chlen = 1;
219		n--;
220		break;
221	case 1:
222	case 2:
223		break;
224	default:
225		/* illgeal state */
226		goto encoding_error;
227	}
228
229	c = ei->count[cs = _citrus_EUC_cs(psenc->ch[0] & 0xff)];
230	if (c == 0)
231		goto encoding_error;
232	while (psenc->chlen < c) {
233		if (n < 1)
234			goto restart;
235		psenc->ch[psenc->chlen] = *s0++;
236		psenc->chlen++;
237		n--;
238	}
239	*s = s0;
240
241	switch (cs) {
242	case 3:
243	case 2:
244		/* skip SS2/SS3 */
245		len = c - 1;
246		s1 = &psenc->ch[1];
247		break;
248	case 1:
249	case 0:
250		len = c;
251		s1 = &psenc->ch[0];
252		break;
253	default:
254		goto encoding_error;
255	}
256	wchar = 0;
257	while (len-- > 0)
258		wchar = (wchar << 8) | (*s1++ & 0xff);
259	wchar = (wchar & ~ei->mask) | ei->bits[cs];
260
261	psenc->chlen = 0;
262	if (pwc)
263		*pwc = wchar;
264	*nresult = wchar ? (size_t)(c - chlenbak) : 0;
265	return (0);
266
267encoding_error:
268	psenc->chlen = 0;
269	*nresult = (size_t)-1;
270	return (EILSEQ);
271
272restart:
273	*nresult = (size_t)-2;
274	*s = s0;
275	return (0);
276}
277
278static int
279_citrus_EUC_wcrtomb_priv(_EUCEncodingInfo *ei, char *s, size_t n, wchar_t wc,
280    _EUCState *psenc __unused, size_t *nresult)
281{
282	wchar_t m, nm;
283	unsigned int cs;
284	int ret;
285	short i;
286
287	m = wc & ei->mask;
288	nm = wc & ~m;
289
290	for (cs = 0; cs < sizeof(ei->count) / sizeof(ei->count[0]); cs++)
291		if (m == ei->bits[cs])
292			break;
293	/* fallback case - not sure if it is necessary */
294	if (cs == sizeof(ei->count) / sizeof(ei->count[0]))
295		cs = 1;
296
297	i = ei->count[cs];
298	if (n < (unsigned)i) {
299		ret = E2BIG;
300		goto err;
301	}
302	m = (cs) ? 0x80 : 0x00;
303	switch (cs) {
304	case 2:
305		*s++ = _SS2;
306		i--;
307		break;
308	case 3:
309		*s++ = _SS3;
310		i--;
311		break;
312	}
313
314	while (i-- > 0)
315		*s++ = ((nm >> (i << 3)) & 0xff) | m;
316
317	*nresult = (size_t)ei->count[cs];
318	return (0);
319
320err:
321	*nresult = (size_t)-1;
322	return (ret);
323}
324
325static __inline int
326/*ARGSUSED*/
327_citrus_EUC_stdenc_wctocs(_EUCEncodingInfo * __restrict ei,
328    _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
329{
330	wchar_t m, nm;
331
332	m = wc & ei->mask;
333	nm = wc & ~m;
334
335	*csid = (_citrus_csid_t)m;
336	*idx  = (_citrus_index_t)nm;
337
338	return (0);
339}
340
341static __inline int
342/*ARGSUSED*/
343_citrus_EUC_stdenc_cstowc(_EUCEncodingInfo * __restrict ei,
344    wchar_t * __restrict wc, _csid_t csid, _index_t idx)
345{
346
347	if ((csid & ~ei->mask) != 0 || (idx & ei->mask) != 0)
348		return (EINVAL);
349
350	*wc = (wchar_t)csid | (wchar_t)idx;
351
352	return (0);
353}
354
355static __inline int
356/*ARGSUSED*/
357_citrus_EUC_stdenc_get_state_desc_generic(_EUCEncodingInfo * __restrict ei __unused,
358    _EUCState * __restrict psenc, int * __restrict rstate)
359{
360
361	*rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL :
362	    _STDENC_SDGEN_INCOMPLETE_CHAR;
363	return (0);
364}
365
366static int
367/*ARGSUSED*/
368_citrus_EUC_encoding_module_init(_EUCEncodingInfo * __restrict ei,
369    const void * __restrict var, size_t lenvar)
370{
371
372	return (_citrus_EUC_parse_variable(ei, var, lenvar));
373}
374
375static void
376/*ARGSUSED*/
377_citrus_EUC_encoding_module_uninit(_EUCEncodingInfo * __restrict ei __unused)
378{
379
380}
381
382/* ----------------------------------------------------------------------
383 * public interface for stdenc
384 */
385
386_CITRUS_STDENC_DECLS(EUC);
387_CITRUS_STDENC_DEF_OPS(EUC);
388
389#include "citrus_stdenc_template.h"
390