xref: /freebsd/lib/libiconv_modules/MSKanji/citrus_mskanji.c (revision ad30f8e79bd1007cc2476e491bd21b4f5e389e0a)
1*ad30f8e7SGabor Kovesdan /* $FreeBSD$ */
2*ad30f8e7SGabor Kovesdan /*	$NetBSD: citrus_mskanji.c,v 1.13 2008/06/14 16:01:08 tnozaki Exp $	*/
3*ad30f8e7SGabor Kovesdan 
4*ad30f8e7SGabor Kovesdan /*-
5*ad30f8e7SGabor Kovesdan  * Copyright (c)2002 Citrus Project,
6*ad30f8e7SGabor Kovesdan  * All rights reserved.
7*ad30f8e7SGabor Kovesdan  *
8*ad30f8e7SGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
9*ad30f8e7SGabor Kovesdan  * modification, are permitted provided that the following conditions
10*ad30f8e7SGabor Kovesdan  * are met:
11*ad30f8e7SGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
12*ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
13*ad30f8e7SGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
14*ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
15*ad30f8e7SGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
16*ad30f8e7SGabor Kovesdan  *
17*ad30f8e7SGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*ad30f8e7SGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*ad30f8e7SGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*ad30f8e7SGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*ad30f8e7SGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*ad30f8e7SGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*ad30f8e7SGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*ad30f8e7SGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*ad30f8e7SGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*ad30f8e7SGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*ad30f8e7SGabor Kovesdan  * SUCH DAMAGE.
28*ad30f8e7SGabor Kovesdan  */
29*ad30f8e7SGabor Kovesdan 
30*ad30f8e7SGabor Kovesdan /*
31*ad30f8e7SGabor Kovesdan  *    ja_JP.SJIS locale table for BSD4.4/rune
32*ad30f8e7SGabor Kovesdan  *    version 1.0
33*ad30f8e7SGabor Kovesdan  *    (C) Sin'ichiro MIYATANI / Phase One, Inc
34*ad30f8e7SGabor Kovesdan  *    May 12, 1995
35*ad30f8e7SGabor Kovesdan  *
36*ad30f8e7SGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
37*ad30f8e7SGabor Kovesdan  * modification, are permitted provided that the following conditions
38*ad30f8e7SGabor Kovesdan  * are met:
39*ad30f8e7SGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
40*ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
41*ad30f8e7SGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
42*ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
43*ad30f8e7SGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
44*ad30f8e7SGabor Kovesdan  * 3. All advertising materials mentioning features or use of this software
45*ad30f8e7SGabor Kovesdan  *    must display the following acknowledgement:
46*ad30f8e7SGabor Kovesdan  *      This product includes software developed by Phase One, Inc.
47*ad30f8e7SGabor Kovesdan  * 4. The name of Phase One, Inc. may be used to endorse or promote products
48*ad30f8e7SGabor Kovesdan  *    derived from this software without specific prior written permission.
49*ad30f8e7SGabor Kovesdan  *
50*ad30f8e7SGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51*ad30f8e7SGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52*ad30f8e7SGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53*ad30f8e7SGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54*ad30f8e7SGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55*ad30f8e7SGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56*ad30f8e7SGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57*ad30f8e7SGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58*ad30f8e7SGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59*ad30f8e7SGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60*ad30f8e7SGabor Kovesdan  * SUCH DAMAGE.
61*ad30f8e7SGabor Kovesdan  */
62*ad30f8e7SGabor Kovesdan 
63*ad30f8e7SGabor Kovesdan 
64*ad30f8e7SGabor Kovesdan #include <sys/cdefs.h>
65*ad30f8e7SGabor Kovesdan #include <sys/types.h>
66*ad30f8e7SGabor Kovesdan 
67*ad30f8e7SGabor Kovesdan #include <assert.h>
68*ad30f8e7SGabor Kovesdan #include <errno.h>
69*ad30f8e7SGabor Kovesdan #include <limits.h>
70*ad30f8e7SGabor Kovesdan #include <stdbool.h>
71*ad30f8e7SGabor Kovesdan #include <stddef.h>
72*ad30f8e7SGabor Kovesdan #include <stdio.h>
73*ad30f8e7SGabor Kovesdan #include <stdlib.h>
74*ad30f8e7SGabor Kovesdan #include <string.h>
75*ad30f8e7SGabor Kovesdan #include <wchar.h>
76*ad30f8e7SGabor Kovesdan 
77*ad30f8e7SGabor Kovesdan #include "citrus_namespace.h"
78*ad30f8e7SGabor Kovesdan #include "citrus_types.h"
79*ad30f8e7SGabor Kovesdan #include "citrus_bcs.h"
80*ad30f8e7SGabor Kovesdan #include "citrus_module.h"
81*ad30f8e7SGabor Kovesdan #include "citrus_stdenc.h"
82*ad30f8e7SGabor Kovesdan #include "citrus_mskanji.h"
83*ad30f8e7SGabor Kovesdan 
84*ad30f8e7SGabor Kovesdan 
85*ad30f8e7SGabor Kovesdan /* ----------------------------------------------------------------------
86*ad30f8e7SGabor Kovesdan  * private stuffs used by templates
87*ad30f8e7SGabor Kovesdan  */
88*ad30f8e7SGabor Kovesdan 
89*ad30f8e7SGabor Kovesdan typedef struct _MSKanjiState {
90*ad30f8e7SGabor Kovesdan 	int	 chlen;
91*ad30f8e7SGabor Kovesdan 	char	 ch[2];
92*ad30f8e7SGabor Kovesdan } _MSKanjiState;
93*ad30f8e7SGabor Kovesdan 
94*ad30f8e7SGabor Kovesdan typedef struct {
95*ad30f8e7SGabor Kovesdan 	int	 mode;
96*ad30f8e7SGabor Kovesdan #define MODE_JIS2004	1
97*ad30f8e7SGabor Kovesdan } _MSKanjiEncodingInfo;
98*ad30f8e7SGabor Kovesdan 
99*ad30f8e7SGabor Kovesdan #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
100*ad30f8e7SGabor Kovesdan #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
101*ad30f8e7SGabor Kovesdan 
102*ad30f8e7SGabor Kovesdan #define _FUNCNAME(m)			_citrus_MSKanji_##m
103*ad30f8e7SGabor Kovesdan #define _ENCODING_INFO			_MSKanjiEncodingInfo
104*ad30f8e7SGabor Kovesdan #define _ENCODING_STATE			_MSKanjiState
105*ad30f8e7SGabor Kovesdan #define _ENCODING_MB_CUR_MAX(_ei_)	2
106*ad30f8e7SGabor Kovesdan #define _ENCODING_IS_STATE_DEPENDENT	0
107*ad30f8e7SGabor Kovesdan #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	0
108*ad30f8e7SGabor Kovesdan 
109*ad30f8e7SGabor Kovesdan 
110*ad30f8e7SGabor Kovesdan static bool
111*ad30f8e7SGabor Kovesdan _mskanji1(int c)
112*ad30f8e7SGabor Kovesdan {
113*ad30f8e7SGabor Kovesdan 
114*ad30f8e7SGabor Kovesdan 	return ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc));
115*ad30f8e7SGabor Kovesdan }
116*ad30f8e7SGabor Kovesdan 
117*ad30f8e7SGabor Kovesdan static bool
118*ad30f8e7SGabor Kovesdan _mskanji2(int c)
119*ad30f8e7SGabor Kovesdan {
120*ad30f8e7SGabor Kovesdan 
121*ad30f8e7SGabor Kovesdan 	return ((c >= 0x40 && c <= 0x7e) || (c >= 0x80 && c <= 0xfc));
122*ad30f8e7SGabor Kovesdan }
123*ad30f8e7SGabor Kovesdan 
124*ad30f8e7SGabor Kovesdan static __inline void
125*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
126*ad30f8e7SGabor Kovesdan _citrus_MSKanji_init_state(_MSKanjiEncodingInfo * __restrict ei __unused,
127*ad30f8e7SGabor Kovesdan     _MSKanjiState * __restrict s)
128*ad30f8e7SGabor Kovesdan {
129*ad30f8e7SGabor Kovesdan 
130*ad30f8e7SGabor Kovesdan 	s->chlen = 0;
131*ad30f8e7SGabor Kovesdan }
132*ad30f8e7SGabor Kovesdan 
133*ad30f8e7SGabor Kovesdan static __inline void
134*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
135*ad30f8e7SGabor Kovesdan _citrus_MSKanji_pack_state(_MSKanjiEncodingInfo * __restrict ei __unused,
136*ad30f8e7SGabor Kovesdan     void * __restrict pspriv, const _MSKanjiState * __restrict s)
137*ad30f8e7SGabor Kovesdan {
138*ad30f8e7SGabor Kovesdan 
139*ad30f8e7SGabor Kovesdan 	memcpy(pspriv, (const void *)s, sizeof(*s));
140*ad30f8e7SGabor Kovesdan }
141*ad30f8e7SGabor Kovesdan 
142*ad30f8e7SGabor Kovesdan static __inline void
143*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
144*ad30f8e7SGabor Kovesdan _citrus_MSKanji_unpack_state(_MSKanjiEncodingInfo * __restrict ei __unused,
145*ad30f8e7SGabor Kovesdan     _MSKanjiState * __restrict s, const void * __restrict pspriv)
146*ad30f8e7SGabor Kovesdan {
147*ad30f8e7SGabor Kovesdan 
148*ad30f8e7SGabor Kovesdan 	memcpy((void *)s, pspriv, sizeof(*s));
149*ad30f8e7SGabor Kovesdan }
150*ad30f8e7SGabor Kovesdan 
151*ad30f8e7SGabor Kovesdan static int
152*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
153*ad30f8e7SGabor Kovesdan _citrus_MSKanji_mbrtowc_priv(_MSKanjiEncodingInfo * __restrict ei,
154*ad30f8e7SGabor Kovesdan     wchar_t * __restrict pwc, char ** __restrict s, size_t n,
155*ad30f8e7SGabor Kovesdan     _MSKanjiState * __restrict psenc, size_t * __restrict nresult)
156*ad30f8e7SGabor Kovesdan {
157*ad30f8e7SGabor Kovesdan 	char *s0;
158*ad30f8e7SGabor Kovesdan 	wchar_t wchar;
159*ad30f8e7SGabor Kovesdan 	int chlenbak, len;
160*ad30f8e7SGabor Kovesdan 
161*ad30f8e7SGabor Kovesdan 	s0 = *s;
162*ad30f8e7SGabor Kovesdan 
163*ad30f8e7SGabor Kovesdan 	if (s0 == NULL) {
164*ad30f8e7SGabor Kovesdan 		_citrus_MSKanji_init_state(ei, psenc);
165*ad30f8e7SGabor Kovesdan 		*nresult = 0; /* state independent */
166*ad30f8e7SGabor Kovesdan 		return (0);
167*ad30f8e7SGabor Kovesdan 	}
168*ad30f8e7SGabor Kovesdan 
169*ad30f8e7SGabor Kovesdan 	chlenbak = psenc->chlen;
170*ad30f8e7SGabor Kovesdan 
171*ad30f8e7SGabor Kovesdan 	/* make sure we have the first byte in the buffer */
172*ad30f8e7SGabor Kovesdan 	switch (psenc->chlen) {
173*ad30f8e7SGabor Kovesdan 	case 0:
174*ad30f8e7SGabor Kovesdan 		if (n < 1)
175*ad30f8e7SGabor Kovesdan 			goto restart;
176*ad30f8e7SGabor Kovesdan 		psenc->ch[0] = *s0++;
177*ad30f8e7SGabor Kovesdan 		psenc->chlen = 1;
178*ad30f8e7SGabor Kovesdan 		n--;
179*ad30f8e7SGabor Kovesdan 		break;
180*ad30f8e7SGabor Kovesdan 	case 1:
181*ad30f8e7SGabor Kovesdan 		break;
182*ad30f8e7SGabor Kovesdan 	default:
183*ad30f8e7SGabor Kovesdan 		/* illegal state */
184*ad30f8e7SGabor Kovesdan 		goto encoding_error;
185*ad30f8e7SGabor Kovesdan 	}
186*ad30f8e7SGabor Kovesdan 
187*ad30f8e7SGabor Kovesdan 	len = _mskanji1(psenc->ch[0] & 0xff) ? 2 : 1;
188*ad30f8e7SGabor Kovesdan 	while (psenc->chlen < len) {
189*ad30f8e7SGabor Kovesdan 		if (n < 1)
190*ad30f8e7SGabor Kovesdan 			goto restart;
191*ad30f8e7SGabor Kovesdan 		psenc->ch[psenc->chlen] = *s0++;
192*ad30f8e7SGabor Kovesdan 		psenc->chlen++;
193*ad30f8e7SGabor Kovesdan 		n--;
194*ad30f8e7SGabor Kovesdan 	}
195*ad30f8e7SGabor Kovesdan 
196*ad30f8e7SGabor Kovesdan 	*s = s0;
197*ad30f8e7SGabor Kovesdan 
198*ad30f8e7SGabor Kovesdan 	switch (len) {
199*ad30f8e7SGabor Kovesdan 	case 1:
200*ad30f8e7SGabor Kovesdan 		wchar = psenc->ch[0] & 0xff;
201*ad30f8e7SGabor Kovesdan 		break;
202*ad30f8e7SGabor Kovesdan 	case 2:
203*ad30f8e7SGabor Kovesdan 		if (!_mskanji2(psenc->ch[1] & 0xff))
204*ad30f8e7SGabor Kovesdan 			goto encoding_error;
205*ad30f8e7SGabor Kovesdan 		wchar = ((psenc->ch[0] & 0xff) << 8) | (psenc->ch[1] & 0xff);
206*ad30f8e7SGabor Kovesdan 		break;
207*ad30f8e7SGabor Kovesdan 	default:
208*ad30f8e7SGabor Kovesdan 		/* illegal state */
209*ad30f8e7SGabor Kovesdan 		goto encoding_error;
210*ad30f8e7SGabor Kovesdan 	}
211*ad30f8e7SGabor Kovesdan 
212*ad30f8e7SGabor Kovesdan 	psenc->chlen = 0;
213*ad30f8e7SGabor Kovesdan 
214*ad30f8e7SGabor Kovesdan 	if (pwc)
215*ad30f8e7SGabor Kovesdan 		*pwc = wchar;
216*ad30f8e7SGabor Kovesdan 	*nresult = wchar ? len - chlenbak : 0;
217*ad30f8e7SGabor Kovesdan 	return (0);
218*ad30f8e7SGabor Kovesdan 
219*ad30f8e7SGabor Kovesdan encoding_error:
220*ad30f8e7SGabor Kovesdan 	psenc->chlen = 0;
221*ad30f8e7SGabor Kovesdan 	*nresult = (size_t)-1;
222*ad30f8e7SGabor Kovesdan 	return (EILSEQ);
223*ad30f8e7SGabor Kovesdan 
224*ad30f8e7SGabor Kovesdan restart:
225*ad30f8e7SGabor Kovesdan 	*nresult = (size_t)-2;
226*ad30f8e7SGabor Kovesdan 	*s = s0;
227*ad30f8e7SGabor Kovesdan 	return (0);
228*ad30f8e7SGabor Kovesdan }
229*ad30f8e7SGabor Kovesdan 
230*ad30f8e7SGabor Kovesdan 
231*ad30f8e7SGabor Kovesdan static int
232*ad30f8e7SGabor Kovesdan _citrus_MSKanji_wcrtomb_priv(_MSKanjiEncodingInfo * __restrict ei __unused,
233*ad30f8e7SGabor Kovesdan     char * __restrict s, size_t n, wchar_t wc,
234*ad30f8e7SGabor Kovesdan     _MSKanjiState * __restrict psenc __unused, size_t * __restrict nresult)
235*ad30f8e7SGabor Kovesdan {
236*ad30f8e7SGabor Kovesdan 	int ret;
237*ad30f8e7SGabor Kovesdan 
238*ad30f8e7SGabor Kovesdan 	/* check invalid sequence */
239*ad30f8e7SGabor Kovesdan 	if (wc & ~0xffff) {
240*ad30f8e7SGabor Kovesdan 		ret = EILSEQ;
241*ad30f8e7SGabor Kovesdan 		goto err;
242*ad30f8e7SGabor Kovesdan 	}
243*ad30f8e7SGabor Kovesdan 
244*ad30f8e7SGabor Kovesdan 	if (wc & 0xff00) {
245*ad30f8e7SGabor Kovesdan 		if (n < 2) {
246*ad30f8e7SGabor Kovesdan 			ret = E2BIG;
247*ad30f8e7SGabor Kovesdan 			goto err;
248*ad30f8e7SGabor Kovesdan 		}
249*ad30f8e7SGabor Kovesdan 
250*ad30f8e7SGabor Kovesdan 		s[0] = (wc >> 8) & 0xff;
251*ad30f8e7SGabor Kovesdan 		s[1] = wc & 0xff;
252*ad30f8e7SGabor Kovesdan 		if (!_mskanji1(s[0] & 0xff) || !_mskanji2(s[1] & 0xff)) {
253*ad30f8e7SGabor Kovesdan 			ret = EILSEQ;
254*ad30f8e7SGabor Kovesdan 			goto err;
255*ad30f8e7SGabor Kovesdan 		}
256*ad30f8e7SGabor Kovesdan 
257*ad30f8e7SGabor Kovesdan 		*nresult = 2;
258*ad30f8e7SGabor Kovesdan 		return (0);
259*ad30f8e7SGabor Kovesdan 	} else {
260*ad30f8e7SGabor Kovesdan 		if (n < 1) {
261*ad30f8e7SGabor Kovesdan 			ret = E2BIG;
262*ad30f8e7SGabor Kovesdan 			goto err;
263*ad30f8e7SGabor Kovesdan 		}
264*ad30f8e7SGabor Kovesdan 
265*ad30f8e7SGabor Kovesdan 		s[0] = wc & 0xff;
266*ad30f8e7SGabor Kovesdan 		if (_mskanji1(s[0] & 0xff)) {
267*ad30f8e7SGabor Kovesdan 			ret = EILSEQ;
268*ad30f8e7SGabor Kovesdan 			goto err;
269*ad30f8e7SGabor Kovesdan 		}
270*ad30f8e7SGabor Kovesdan 
271*ad30f8e7SGabor Kovesdan 		*nresult = 1;
272*ad30f8e7SGabor Kovesdan 		return (0);
273*ad30f8e7SGabor Kovesdan 	}
274*ad30f8e7SGabor Kovesdan 
275*ad30f8e7SGabor Kovesdan err:
276*ad30f8e7SGabor Kovesdan 	*nresult = (size_t)-1;
277*ad30f8e7SGabor Kovesdan 	return (ret);
278*ad30f8e7SGabor Kovesdan }
279*ad30f8e7SGabor Kovesdan 
280*ad30f8e7SGabor Kovesdan 
281*ad30f8e7SGabor Kovesdan static __inline int
282*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
283*ad30f8e7SGabor Kovesdan _citrus_MSKanji_stdenc_wctocs(_MSKanjiEncodingInfo * __restrict ei,
284*ad30f8e7SGabor Kovesdan     _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
285*ad30f8e7SGabor Kovesdan {
286*ad30f8e7SGabor Kovesdan 	_index_t col, row;
287*ad30f8e7SGabor Kovesdan 	int offset;
288*ad30f8e7SGabor Kovesdan 
289*ad30f8e7SGabor Kovesdan 	if ((_wc_t)wc < 0x80) {
290*ad30f8e7SGabor Kovesdan 		/* ISO-646 */
291*ad30f8e7SGabor Kovesdan 		*csid = 0;
292*ad30f8e7SGabor Kovesdan 		*idx = (_index_t)wc;
293*ad30f8e7SGabor Kovesdan 	} else if ((_wc_t)wc < 0x100) {
294*ad30f8e7SGabor Kovesdan 		/* KANA */
295*ad30f8e7SGabor Kovesdan 		*csid = 1;
296*ad30f8e7SGabor Kovesdan 		*idx = (_index_t)wc & 0x7F;
297*ad30f8e7SGabor Kovesdan 	} else {
298*ad30f8e7SGabor Kovesdan 		/* Kanji (containing Gaiji zone) */
299*ad30f8e7SGabor Kovesdan 		/*
300*ad30f8e7SGabor Kovesdan 		 * 94^2 zone (contains a part of Gaiji (0xED40 - 0xEEFC)):
301*ad30f8e7SGabor Kovesdan 		 * 0x8140 - 0x817E -> 0x2121 - 0x215F
302*ad30f8e7SGabor Kovesdan 		 * 0x8180 - 0x819E -> 0x2160 - 0x217E
303*ad30f8e7SGabor Kovesdan 		 * 0x819F - 0x81FC -> 0x2221 - 0x227E
304*ad30f8e7SGabor Kovesdan 		 *
305*ad30f8e7SGabor Kovesdan 		 * 0x8240 - 0x827E -> 0x2321 - 0x235F
306*ad30f8e7SGabor Kovesdan 		 *  ...
307*ad30f8e7SGabor Kovesdan 		 * 0x9F9F - 0x9FFc -> 0x5E21 - 0x5E7E
308*ad30f8e7SGabor Kovesdan 		 *
309*ad30f8e7SGabor Kovesdan 		 * 0xE040 - 0xE07E -> 0x5F21 - 0x5F5F
310*ad30f8e7SGabor Kovesdan 		 *  ...
311*ad30f8e7SGabor Kovesdan 		 * 0xEF9F - 0xEFFC -> 0x7E21 - 0x7E7E
312*ad30f8e7SGabor Kovesdan 		 *
313*ad30f8e7SGabor Kovesdan 		 * extended Gaiji zone:
314*ad30f8e7SGabor Kovesdan 		 * 0xF040 - 0xFCFC
315*ad30f8e7SGabor Kovesdan 		 *
316*ad30f8e7SGabor Kovesdan 		 * JIS X0213-plane2:
317*ad30f8e7SGabor Kovesdan 		 * 0xF040 - 0xF09E -> 0x2121 - 0x217E
318*ad30f8e7SGabor Kovesdan 		 * 0xF140 - 0xF19E -> 0x2321 - 0x237E
319*ad30f8e7SGabor Kovesdan 		 * ...
320*ad30f8e7SGabor Kovesdan 		 * 0xF240 - 0xF29E -> 0x2521 - 0x257E
321*ad30f8e7SGabor Kovesdan 		 *
322*ad30f8e7SGabor Kovesdan 		 * 0xF09F - 0xF0FC -> 0x2821 - 0x287E
323*ad30f8e7SGabor Kovesdan 		 * 0xF29F - 0xF2FC -> 0x2C21 - 0x2C7E
324*ad30f8e7SGabor Kovesdan 		 * ...
325*ad30f8e7SGabor Kovesdan 		 * 0xF44F - 0xF49E -> 0x2F21 - 0x2F7E
326*ad30f8e7SGabor Kovesdan 		 *
327*ad30f8e7SGabor Kovesdan 		 * 0xF49F - 0xF4FC -> 0x6E21 - 0x6E7E
328*ad30f8e7SGabor Kovesdan 		 * ...
329*ad30f8e7SGabor Kovesdan 		 * 0xFC9F - 0xFCFC -> 0x7E21 - 0x7E7E
330*ad30f8e7SGabor Kovesdan 		 */
331*ad30f8e7SGabor Kovesdan 		row = ((_wc_t)wc >> 8) & 0xFF;
332*ad30f8e7SGabor Kovesdan 		col = (_wc_t)wc & 0xFF;
333*ad30f8e7SGabor Kovesdan 		if (!_mskanji1(row) || !_mskanji2(col))
334*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
335*ad30f8e7SGabor Kovesdan 		if ((ei->mode & MODE_JIS2004) == 0 || row < 0xF0) {
336*ad30f8e7SGabor Kovesdan 			*csid = 2;
337*ad30f8e7SGabor Kovesdan 			offset = 0x81;
338*ad30f8e7SGabor Kovesdan 		} else {
339*ad30f8e7SGabor Kovesdan 			*csid = 3;
340*ad30f8e7SGabor Kovesdan 			if ((_wc_t)wc <= 0xF49E) {
341*ad30f8e7SGabor Kovesdan 				offset = (_wc_t)wc >= 0xF29F ||
342*ad30f8e7SGabor Kovesdan 				    ((_wc_t)wc >= 0xF09F &&
343*ad30f8e7SGabor Kovesdan 				    (_wc_t)wc <= 0xF0FC) ? 0xED : 0xF0;
344*ad30f8e7SGabor Kovesdan 			} else
345*ad30f8e7SGabor Kovesdan 				offset = 0xCE;
346*ad30f8e7SGabor Kovesdan 		}
347*ad30f8e7SGabor Kovesdan 		row -= offset;
348*ad30f8e7SGabor Kovesdan 		if (row >= 0x5F)
349*ad30f8e7SGabor Kovesdan 			row -= 0x40;
350*ad30f8e7SGabor Kovesdan 		row = row * 2 + 0x21;
351*ad30f8e7SGabor Kovesdan 		col -= 0x1F;
352*ad30f8e7SGabor Kovesdan 		if (col >= 0x61)
353*ad30f8e7SGabor Kovesdan 			col -= 1;
354*ad30f8e7SGabor Kovesdan 		if (col > 0x7E) {
355*ad30f8e7SGabor Kovesdan 			row += 1;
356*ad30f8e7SGabor Kovesdan 			col -= 0x5E;
357*ad30f8e7SGabor Kovesdan 		}
358*ad30f8e7SGabor Kovesdan 		*idx = ((_index_t)row << 8) | col;
359*ad30f8e7SGabor Kovesdan 	}
360*ad30f8e7SGabor Kovesdan 
361*ad30f8e7SGabor Kovesdan 	return (0);
362*ad30f8e7SGabor Kovesdan }
363*ad30f8e7SGabor Kovesdan 
364*ad30f8e7SGabor Kovesdan static __inline int
365*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
366*ad30f8e7SGabor Kovesdan _citrus_MSKanji_stdenc_cstowc(_MSKanjiEncodingInfo * __restrict ei,
367*ad30f8e7SGabor Kovesdan     wchar_t * __restrict wc, _csid_t csid, _index_t idx)
368*ad30f8e7SGabor Kovesdan {
369*ad30f8e7SGabor Kovesdan 	uint32_t col, row;
370*ad30f8e7SGabor Kovesdan 	int offset;
371*ad30f8e7SGabor Kovesdan 
372*ad30f8e7SGabor Kovesdan 	switch (csid) {
373*ad30f8e7SGabor Kovesdan 	case 0:
374*ad30f8e7SGabor Kovesdan 		/* ISO-646 */
375*ad30f8e7SGabor Kovesdan 		if (idx >= 0x80)
376*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
377*ad30f8e7SGabor Kovesdan 		*wc = (wchar_t)idx;
378*ad30f8e7SGabor Kovesdan 		break;
379*ad30f8e7SGabor Kovesdan 	case 1:
380*ad30f8e7SGabor Kovesdan 		/* kana */
381*ad30f8e7SGabor Kovesdan 		if (idx >= 0x80)
382*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
383*ad30f8e7SGabor Kovesdan 		*wc = (wchar_t)idx + 0x80;
384*ad30f8e7SGabor Kovesdan 		break;
385*ad30f8e7SGabor Kovesdan 	case 3:
386*ad30f8e7SGabor Kovesdan 		if ((ei->mode & MODE_JIS2004) == 0)
387*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
388*ad30f8e7SGabor Kovesdan 	/*FALLTHROUGH*/
389*ad30f8e7SGabor Kovesdan 	case 2:
390*ad30f8e7SGabor Kovesdan 		/* kanji */
391*ad30f8e7SGabor Kovesdan 		row = (idx >> 8);
392*ad30f8e7SGabor Kovesdan 		if (row < 0x21)
393*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
394*ad30f8e7SGabor Kovesdan 		if (csid == 3) {
395*ad30f8e7SGabor Kovesdan 			if (row <= 0x2F)
396*ad30f8e7SGabor Kovesdan 				offset = (row == 0x22 || row >= 0x26) ?
397*ad30f8e7SGabor Kovesdan 				    0xED : 0xF0;
398*ad30f8e7SGabor Kovesdan 			else if (row >= 0x4D && row <= 0x7E)
399*ad30f8e7SGabor Kovesdan 				offset = 0xCE;
400*ad30f8e7SGabor Kovesdan 			else
401*ad30f8e7SGabor Kovesdan 				return (EILSEQ);
402*ad30f8e7SGabor Kovesdan 		} else {
403*ad30f8e7SGabor Kovesdan 			if (row > 0x97)
404*ad30f8e7SGabor Kovesdan 				return (EILSEQ);
405*ad30f8e7SGabor Kovesdan 			offset = (row < 0x5F) ? 0x81 : 0xC1;
406*ad30f8e7SGabor Kovesdan 		}
407*ad30f8e7SGabor Kovesdan 		col = idx & 0xFF;
408*ad30f8e7SGabor Kovesdan 		if (col < 0x21 || col > 0x7E)
409*ad30f8e7SGabor Kovesdan 			return (EILSEQ);
410*ad30f8e7SGabor Kovesdan 		row -= 0x21; col -= 0x21;
411*ad30f8e7SGabor Kovesdan 		if ((row & 1) == 0) {
412*ad30f8e7SGabor Kovesdan 			col += 0x40;
413*ad30f8e7SGabor Kovesdan 			if (col >= 0x7F)
414*ad30f8e7SGabor Kovesdan 				col += 1;
415*ad30f8e7SGabor Kovesdan 		} else
416*ad30f8e7SGabor Kovesdan 			col += 0x9F;
417*ad30f8e7SGabor Kovesdan 		row = row / 2 + offset;
418*ad30f8e7SGabor Kovesdan 		*wc = ((wchar_t)row << 8) | col;
419*ad30f8e7SGabor Kovesdan 		break;
420*ad30f8e7SGabor Kovesdan 	default:
421*ad30f8e7SGabor Kovesdan 		return (EILSEQ);
422*ad30f8e7SGabor Kovesdan 	}
423*ad30f8e7SGabor Kovesdan 
424*ad30f8e7SGabor Kovesdan 	return (0);
425*ad30f8e7SGabor Kovesdan }
426*ad30f8e7SGabor Kovesdan 
427*ad30f8e7SGabor Kovesdan static __inline int
428*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
429*ad30f8e7SGabor Kovesdan _citrus_MSKanji_stdenc_get_state_desc_generic(_MSKanjiEncodingInfo * __restrict ei __unused,
430*ad30f8e7SGabor Kovesdan     _MSKanjiState * __restrict psenc, int * __restrict rstate)
431*ad30f8e7SGabor Kovesdan {
432*ad30f8e7SGabor Kovesdan 
433*ad30f8e7SGabor Kovesdan 	*rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL :
434*ad30f8e7SGabor Kovesdan 	    _STDENC_SDGEN_INCOMPLETE_CHAR;
435*ad30f8e7SGabor Kovesdan 	return (0);
436*ad30f8e7SGabor Kovesdan }
437*ad30f8e7SGabor Kovesdan 
438*ad30f8e7SGabor Kovesdan static int
439*ad30f8e7SGabor Kovesdan /*ARGSUSED*/
440*ad30f8e7SGabor Kovesdan _citrus_MSKanji_encoding_module_init(_MSKanjiEncodingInfo *  __restrict ei,
441*ad30f8e7SGabor Kovesdan     const void * __restrict var, size_t lenvar)
442*ad30f8e7SGabor Kovesdan {
443*ad30f8e7SGabor Kovesdan 	const char *p;
444*ad30f8e7SGabor Kovesdan 
445*ad30f8e7SGabor Kovesdan 	p = var;
446*ad30f8e7SGabor Kovesdan 	memset((void *)ei, 0, sizeof(*ei));
447*ad30f8e7SGabor Kovesdan 	while (lenvar > 0) {
448*ad30f8e7SGabor Kovesdan 		switch (_bcs_toupper(*p)) {
449*ad30f8e7SGabor Kovesdan 		case 'J':
450*ad30f8e7SGabor Kovesdan 			MATCH(JIS2004, ei->mode |= MODE_JIS2004);
451*ad30f8e7SGabor Kovesdan 			break;
452*ad30f8e7SGabor Kovesdan 		}
453*ad30f8e7SGabor Kovesdan 		++p;
454*ad30f8e7SGabor Kovesdan 		--lenvar;
455*ad30f8e7SGabor Kovesdan 	}
456*ad30f8e7SGabor Kovesdan 
457*ad30f8e7SGabor Kovesdan 	return (0);
458*ad30f8e7SGabor Kovesdan }
459*ad30f8e7SGabor Kovesdan 
460*ad30f8e7SGabor Kovesdan static void
461*ad30f8e7SGabor Kovesdan _citrus_MSKanji_encoding_module_uninit(_MSKanjiEncodingInfo *ei __unused)
462*ad30f8e7SGabor Kovesdan {
463*ad30f8e7SGabor Kovesdan 
464*ad30f8e7SGabor Kovesdan }
465*ad30f8e7SGabor Kovesdan 
466*ad30f8e7SGabor Kovesdan /* ----------------------------------------------------------------------
467*ad30f8e7SGabor Kovesdan  * public interface for stdenc
468*ad30f8e7SGabor Kovesdan  */
469*ad30f8e7SGabor Kovesdan 
470*ad30f8e7SGabor Kovesdan _CITRUS_STDENC_DECLS(MSKanji);
471*ad30f8e7SGabor Kovesdan _CITRUS_STDENC_DEF_OPS(MSKanji);
472*ad30f8e7SGabor Kovesdan 
473*ad30f8e7SGabor Kovesdan #include "citrus_stdenc_template.h"
474