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