1 /* $FreeBSD$ */
2 /* $NetBSD: citrus_johab.c,v 1.4 2008/06/14 16:01:07 tnozaki Exp $ */
3 
4 /*-
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * Copyright (c)2006 Citrus Project,
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 #include <sys/types.h>
33 
34 #include <assert.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <stdbool.h>
38 #include <stddef.h>
39 #include <stdint.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <wchar.h>
44 
45 #include "citrus_namespace.h"
46 #include "citrus_types.h"
47 #include "citrus_bcs.h"
48 #include "citrus_module.h"
49 #include "citrus_stdenc.h"
50 #include "citrus_johab.h"
51 
52 /* ----------------------------------------------------------------------
53  * private stuffs used by templates
54  */
55 
56 typedef struct {
57 	int	 chlen;
58 	char	 ch[2];
59 } _JOHABState;
60 
61 typedef struct {
62 	int	 dummy;
63 } _JOHABEncodingInfo;
64 
65 #define _CEI_TO_EI(_cei_)		(&(_cei_)->ei)
66 #define _CEI_TO_STATE(_cei_, _func_)	(_cei_)->states.s_##_func_
67 
68 #define _FUNCNAME(m)			_citrus_JOHAB_##m
69 #define _ENCODING_INFO			_JOHABEncodingInfo
70 #define _ENCODING_STATE			_JOHABState
71 #define _ENCODING_MB_CUR_MAX(_ei_)		2
72 #define _ENCODING_IS_STATE_DEPENDENT		0
73 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)	0
74 
75 
76 static __inline void
77 /*ARGSUSED*/
78 _citrus_JOHAB_init_state(_JOHABEncodingInfo * __restrict ei __unused,
79     _JOHABState * __restrict psenc)
80 {
81 
82 	psenc->chlen = 0;
83 }
84 
85 #if 0
86 static __inline void
87 /*ARGSUSED*/
88 _citrus_JOHAB_pack_state(_JOHABEncodingInfo * __restrict ei __unused,
89     void * __restrict pspriv, const _JOHABState * __restrict psenc)
90 {
91 
92 	memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
93 }
94 
95 static __inline void
96 /*ARGSUSED*/
97 _citrus_JOHAB_unpack_state(_JOHABEncodingInfo * __restrict ei __unused,
98     _JOHABState * __restrict psenc, const void * __restrict pspriv)
99 {
100 
101 	memcpy((void *)psenc, pspriv, sizeof(*psenc));
102 }
103 #endif
104 
105 static void
106 /*ARGSUSED*/
107 _citrus_JOHAB_encoding_module_uninit(_JOHABEncodingInfo *ei __unused)
108 {
109 
110 	/* ei may be null */
111 }
112 
113 static int
114 /*ARGSUSED*/
115 _citrus_JOHAB_encoding_module_init(_JOHABEncodingInfo * __restrict ei __unused,
116     const void * __restrict var __unused, size_t lenvar __unused)
117 {
118 
119 	/* ei may be null */
120 	return (0);
121 }
122 
123 static __inline bool
124 ishangul(int l, int t)
125 {
126 
127 	return ((l >= 0x84 && l <= 0xD3) &&
128 	    ((t >= 0x41 && t <= 0x7E) || (t >= 0x81 && t <= 0xFE)));
129 }
130 
131 static __inline bool
132 isuda(int l, int t)
133 {
134 
135 	return ((l == 0xD8) &&
136 	    ((t >= 0x31 && t <= 0x7E) || (t >= 0x91 && t <= 0xFE)));
137 }
138 
139 static __inline bool
140 ishanja(int l, int t)
141 {
142 
143 	return (((l >= 0xD9 && l <= 0xDE) || (l >= 0xE0 && l <= 0xF9)) &&
144 	    ((t >= 0x31 && t <= 0x7E) || (t >= 0x91 && t <= 0xFE)));
145 }
146 
147 static int
148 /*ARGSUSED*/
149 _citrus_JOHAB_mbrtowc_priv(_JOHABEncodingInfo * __restrict ei,
150     wchar_t * __restrict pwc, char ** __restrict s, size_t n,
151     _JOHABState * __restrict psenc, size_t * __restrict nresult)
152 {
153 	char *s0;
154 	int l, t;
155 
156 	if (*s == NULL) {
157 		_citrus_JOHAB_init_state(ei, psenc);
158 		*nresult = _ENCODING_IS_STATE_DEPENDENT;
159 		return (0);
160 	}
161 	s0 = *s;
162 
163 	switch (psenc->chlen) {
164 	case 0:
165 		if (n-- < 1)
166 			goto restart;
167 		l = *s0++ & 0xFF;
168 		if (l <= 0x7F) {
169 			if (pwc != NULL)
170 				*pwc = (wchar_t)l;
171 			*nresult = (l == 0) ? 0 : 1;
172 			*s = s0;
173 			return (0);
174 		}
175 		psenc->ch[psenc->chlen++] = l;
176 		break;
177 	case 1:
178 		l = psenc->ch[0] & 0xFF;
179 		break;
180 	default:
181 		return (EINVAL);
182 	}
183 	if (n-- < 1) {
184 restart:
185 		*nresult = (size_t)-2;
186 		*s = s0;
187 		return (0);
188 	}
189 	t = *s0++ & 0xFF;
190 	if (!ishangul(l, t) && !isuda(l, t) && !ishanja(l, t)) {
191 		*nresult = (size_t)-1;
192 		return (EILSEQ);
193 	}
194 	if (pwc != NULL)
195 		*pwc = (wchar_t)(l << 8 | t);
196 	*nresult = s0 - *s;
197 	*s = s0;
198 	psenc->chlen = 0;
199 
200 	return (0);
201 }
202 
203 static int
204 /*ARGSUSED*/
205 _citrus_JOHAB_wcrtomb_priv(_JOHABEncodingInfo * __restrict ei __unused,
206     char * __restrict s, size_t n, wchar_t wc,
207     _JOHABState * __restrict psenc, size_t * __restrict nresult)
208 {
209 	int l, t;
210 
211 	if (psenc->chlen != 0)
212 		return (EINVAL);
213 
214 	/* XXX assume wchar_t as int */
215 	if ((uint32_t)wc <= 0x7F) {
216 		if (n < 1)
217 			goto e2big;
218 		*s = wc & 0xFF;
219 		*nresult = 1;
220 	} else if ((uint32_t)wc <= 0xFFFF) {
221 		if (n < 2) {
222 e2big:
223 			*nresult = (size_t)-1;
224 			return (E2BIG);
225 		}
226 		l = (wc >> 8) & 0xFF;
227 		t = wc & 0xFF;
228 		if (!ishangul(l, t) && !isuda(l, t) && !ishanja(l, t))
229 			goto ilseq;
230 		*s++ = l;
231 		*s = t;
232 		*nresult = 2;
233 	} else {
234 ilseq:
235 		*nresult = (size_t)-1;
236 		return (EILSEQ);
237 	}
238 	return (0);
239 
240 }
241 
242 static __inline int
243 /*ARGSUSED*/
244 _citrus_JOHAB_stdenc_wctocs(_JOHABEncodingInfo * __restrict ei __unused,
245     _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
246 {
247 	int m, l, linear, t;
248 
249 	/* XXX assume wchar_t as int */
250 	if ((uint32_t)wc <= 0x7F) {
251 		*idx = (_index_t)wc;
252 		*csid = 0;
253 	} else if ((uint32_t)wc <= 0xFFFF) {
254 		l = (wc >> 8) & 0xFF;
255 		t = wc & 0xFF;
256 		if (ishangul(l, t) || isuda(l, t)) {
257 			*idx = (_index_t)wc;
258 			*csid = 1;
259 		} else {
260 			if (l >= 0xD9 && l <= 0xDE) {
261 				linear = l - 0xD9;
262 				m = 0x21;
263 			} else if (l >= 0xE0 && l <= 0xF9) {
264 				linear = l - 0xE0;
265 				m = 0x4A;
266 			} else
267 				return (EILSEQ);
268 			linear *= 188;
269 			if (t >= 0x31 && t <= 0x7E)
270 				linear += t - 0x31;
271 			else if (t >= 0x91 && t <= 0xFE)
272 				linear += t - 0x43;
273 			else
274 				return (EILSEQ);
275 			l = (linear / 94) + m;
276 			t = (linear % 94) + 0x21;
277 			*idx = (_index_t)((l << 8) | t);
278 			*csid = 2;
279 		}
280 	} else
281 		return (EILSEQ);
282 	return (0);
283 }
284 
285 static __inline int
286 /*ARGSUSED*/
287 _citrus_JOHAB_stdenc_cstowc(_JOHABEncodingInfo * __restrict ei __unused,
288     wchar_t * __restrict wc, _csid_t csid, _index_t idx)
289 {
290 	int m, n, l, linear, t;
291 
292 	switch (csid) {
293 	case 0:
294 	case 1:
295 		*wc = (wchar_t)idx;
296 		break;
297 	case 2:
298 		if (idx >= 0x2121 && idx <= 0x2C71) {
299 			m = 0xD9;
300 			n = 0x21;
301 		} else if (idx >= 0x4A21 && idx <= 0x7D7E) {
302 			m = 0xE0;
303 			n = 0x4A;
304 		} else
305 			return (EILSEQ);
306 		l = ((idx >> 8) & 0xFF) - n;
307 		t = (idx & 0xFF) - 0x21;
308 		linear = (l * 94) + t;
309 		l = (linear / 188) + m;
310 		t = linear % 188;
311 		t += (t <= 0x4D) ? 0x31 : 0x43;
312 		break;
313 	default:
314 		return (EILSEQ);
315 	}
316 	return (0);
317 }
318 
319 static __inline int
320 /*ARGSUSED*/
321 _citrus_JOHAB_stdenc_get_state_desc_generic(_JOHABEncodingInfo * __restrict ei __unused,
322     _JOHABState * __restrict psenc, int * __restrict rstate)
323 {
324 
325 	*rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL :
326 	    _STDENC_SDGEN_INCOMPLETE_CHAR;
327 	return (0);
328 }
329 
330 /* ----------------------------------------------------------------------
331  * public interface for stdenc
332  */
333 
334 _CITRUS_STDENC_DECLS(JOHAB);
335 _CITRUS_STDENC_DEF_OPS(JOHAB);
336 
337 #include "citrus_stdenc_template.h"
338