ddb66f30fa582572b4b995af3720509a10045e70
[dragonfly.git] / lib / libc / citrus / modules / citrus_johab.c
1 /* $NetBSD: citrus_johab.c,v 1.3 2007/10/23 15:28:25 tnozaki Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_johab.c,v 1.1 2008/04/10 10:21:01 hasso Exp $ */
3
4 /*-
5  * Copyright (c)2006 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/types.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stddef.h>
38 #include <locale.h>
39 #include <wchar.h>
40 #include <limits.h>
41
42 #include "citrus_namespace.h"
43 #include "citrus_types.h"
44 #include "citrus_bcs.h"
45 #include "citrus_module.h"
46 #include "citrus_ctype.h"
47 #include "citrus_stdenc.h"
48 #include "citrus_johab.h"
49
50 /* ----------------------------------------------------------------------
51  * private stuffs used by templates
52  */
53
54 typedef struct {
55         int chlen;
56         char ch[2];
57 } _JOHABState;
58
59 typedef struct {
60         int dummy;
61 } _JOHABEncodingInfo;
62
63 typedef struct {
64         _JOHABEncodingInfo      ei;
65         struct {
66                 /* for future multi-locale facility */
67                 _JOHABState     s_mblen;
68                 _JOHABState     s_mbrlen;
69                 _JOHABState     s_mbrtowc;
70                 _JOHABState     s_mbtowc;
71                 _JOHABState     s_mbsrtowcs;
72                 _JOHABState     s_wcrtomb;
73                 _JOHABState     s_wcsrtombs;
74                 _JOHABState     s_wctomb;
75         } states;
76 } _JOHABCTypeInfo;
77
78 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
79 #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
80
81 #define _FUNCNAME(m)                    _citrus_JOHAB_##m
82 #define _ENCODING_INFO                  _JOHABEncodingInfo
83 #define _CTYPE_INFO                     _JOHABCTypeInfo
84 #define _ENCODING_STATE                 _JOHABState
85 #define _ENCODING_MB_CUR_MAX(_ei_)              2
86 #define _ENCODING_IS_STATE_DEPENDENT            0
87 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
88
89
90 static __inline void
91 /*ARGSUSED*/
92 _citrus_JOHAB_init_state(_JOHABEncodingInfo * __restrict ei,
93         _JOHABState * __restrict psenc)
94 {
95         /* ei may be null */
96         _DIAGASSERT(psenc != NULL);
97
98         psenc->chlen = 0;
99 }
100
101 static __inline void
102 /*ARGSUSED*/
103 _citrus_JOHAB_pack_state(_JOHABEncodingInfo * __restrict ei,
104         void * __restrict pspriv,
105         const _JOHABState * __restrict psenc)
106 {
107         /* ei may be null */
108         _DIAGASSERT(pspriv != NULL);
109         _DIAGASSERT(psenc != NULL);
110
111         memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
112 }
113
114 static __inline void
115 /*ARGSUSED*/
116 _citrus_JOHAB_unpack_state(_JOHABEncodingInfo * __restrict ei,
117         _JOHABState * __restrict psenc,
118         const void * __restrict pspriv)
119 {
120         /* ei may be null */
121         _DIAGASSERT(psenc != NULL);
122         _DIAGASSERT(pspriv != NULL);
123
124         memcpy((void *)psenc, pspriv, sizeof(*psenc));
125 }
126
127 static void
128 /*ARGSUSED*/
129 _citrus_JOHAB_encoding_module_uninit(_JOHABEncodingInfo *ei)
130 {
131         /* ei may be null */
132 }
133
134 static int
135 /*ARGSUSED*/
136 _citrus_JOHAB_encoding_module_init(_JOHABEncodingInfo * __restrict ei,
137         const void * __restrict var, size_t lenvar)
138 {
139         /* ei may be null */
140         return 0;
141 }
142
143 static __inline int
144 ishangul(int l, int t)
145 {
146
147         return (l >= 0x84 && l <= 0xD3) &&
148               ((t >= 0x41 && t <= 0x7E) || (t >= 0x81 && t <= 0xFE));
149 }
150
151 static __inline int
152 isuda(int l, int t)
153 {
154         return (l == 0xD8) &&
155                ((t >= 0x31 && t <= 0x7E) || (t >= 0x91 && t <= 0xFE));
156 }
157
158 static __inline int
159 ishanja(int l, int t)
160 {
161         return ((l >= 0xD9 && l <= 0xDE) || (l >= 0xE0 && l <= 0xF9)) &&
162                ((t >= 0x31 && t <= 0x7E) || (t >= 0x91 && t <= 0xFE));
163 }
164
165 static int
166 /*ARGSUSED*/
167 _citrus_JOHAB_mbrtowc_priv(_JOHABEncodingInfo * __restrict ei,
168         wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
169         _JOHABState * __restrict psenc, size_t * __restrict nresult)
170 {
171         const char *s0;
172         int l, t;
173
174         /* ei may be unused */
175         _DIAGASSERT(s != NULL);
176         _DIAGASSERT(psenc != NULL);
177         _DIAGASSERT(nresult != 0);
178
179         if (*s == NULL) {
180                 _citrus_JOHAB_init_state(ei, psenc);
181                 *nresult = _ENCODING_IS_STATE_DEPENDENT;
182                 return 0;
183         } 
184         s0 = *s;
185
186         switch (psenc->chlen) {
187         case 0:
188                 if (n-- < 1)
189                         goto restart;
190                 l = *s0++ & 0xFF;
191                 if (l <= 0x7F) {
192                         if (pwc != NULL)
193                                 *pwc = (wchar_t)l;
194                         *nresult = (l == 0) ? 0 : 1;
195                         *s = s0;
196                         return 0;
197                 }
198                 psenc->ch[psenc->chlen++] = l;
199                 break;
200         case 1:
201                 l = psenc->ch[0] & 0xFF;
202                 break;
203         default:
204                 return EINVAL;
205         }
206         if (n-- < 1) {
207 restart:
208                 *nresult = (size_t)-2;
209                 *s = s0;
210                 return 0;
211         }
212         t = *s0++ & 0xFF;
213         if (!ishangul(l, t) && !isuda(l, t) && !ishanja(l, t)) {
214                 *nresult = (size_t)-1;
215                 return EILSEQ;
216         }
217         if (pwc != NULL)
218                 *pwc = (wchar_t)(l << 8 | t);
219         *nresult = s0 - *s;
220         *s = s0;
221         psenc->chlen = 0;
222
223         return 0;
224 }
225
226 static int
227 /*ARGSUSED*/
228 _citrus_JOHAB_wcrtomb_priv(_JOHABEncodingInfo * __restrict ei,
229         char * __restrict s, size_t n, wchar_t wc,
230         _JOHABState * __restrict psenc, size_t * __restrict nresult)
231 {
232         int l, t;
233
234         /* ei may be unused */
235         _DIAGASSERT(s != NULL);
236         _DIAGASSERT(psenc != NULL);
237         _DIAGASSERT(nresult != NULL);
238
239         if (psenc->chlen != 0)
240                 return EINVAL;
241
242         /* XXX assume wchar_t as int */
243         if ((uint32_t)wc <= 0x7F) {
244                 if (n < 1)
245                         goto e2big;
246                 *s = wc & 0xFF;
247                 *nresult = 1;
248         } else if ((uint32_t)wc <= 0xFFFF) {
249                 if (n < 2) {
250 e2big:
251                         *nresult = (size_t)-1;
252                         return E2BIG;
253                 }
254                 l = (wc >> 8) & 0xFF;
255                 t = wc & 0xFF;
256                 if (!ishangul(l, t) && !isuda(l, t) && !ishanja(l, t))
257                         goto ilseq;
258                 *s++ = l;
259                 *s = t;
260                 *nresult = 2;
261         } else {
262 ilseq:
263                 *nresult = (size_t)-1;
264                 return EILSEQ;
265         }
266         return 0;
267
268 }
269
270 static __inline int
271 /*ARGSUSED*/
272 _citrus_JOHAB_stdenc_wctocs(_JOHABEncodingInfo * __restrict ei,
273         _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
274 {
275         int m, l, t, linear;
276
277         /* ei may be unused */
278         _DIAGASSERT(csid != NULL);
279         _DIAGASSERT(idx != NULL);
280
281         /* XXX assume wchar_t as int */
282         if ((uint32_t)wc <= 0x7F) {
283                 *idx = (_index_t)wc;
284                 *csid = 0;
285         } else if ((uint32_t)wc <= 0xFFFF) {
286                 l = (wc >> 8) & 0xFF;
287                 t = wc & 0xFF;
288                 if (ishangul(l, t) || isuda(l, t)) {
289                         *idx = (_index_t)wc;
290                         *csid = 1;
291                 } else {
292                         if (l >= 0xD9 && l <= 0xDE) {
293                                 linear = l - 0xD9;
294                                 m = 0x21;
295                         } else if (l >= 0xE0 && l <= 0xF9) {
296                                 linear = l - 0xE0;
297                                 m = 0x4A;
298                         } else {
299                                 return EILSEQ;
300                         }
301                         linear *= 188;
302                         if (t >= 0x31 && t <= 0x7E) {
303                                 linear += t - 0x31;
304                         } else if (t >= 0x91 && t <= 0xFE) {
305                                 linear += t - 0x43;
306                         } else {
307                                 return EILSEQ;
308                         }
309                         l = (linear / 94) + m;
310                         t = (linear % 94) + 0x21;
311                         *idx = (_index_t)((l << 8) | t);
312                         *csid = 2;
313                 }
314         } else {
315                 return EILSEQ;
316         }
317         return 0;
318 }
319
320 static __inline int
321 /*ARGSUSED*/
322 _citrus_JOHAB_stdenc_cstowc(_JOHABEncodingInfo * __restrict ei,
323         wchar_t * __restrict wc, _csid_t csid, _index_t idx)
324 {
325         int m, n, l, t, linear;
326
327         /* ei may be unused */
328         _DIAGASSERT(wc != NULL);
329
330         switch (csid) {
331         case 0:
332         case 1:
333                 *wc = (wchar_t)idx;
334                 break;
335         case 2:
336                 if (idx >= 0x2121 && idx <= 0x2C71) {
337                         m = 0xD9;
338                         n = 0x21;
339                 } else if (idx >= 0x4A21 && idx <= 0x7D7E) {
340                         m = 0xE0;
341                         n = 0x4A;
342                 } else {
343                         return EILSEQ;
344                 }
345                 l = ((idx >> 8) & 0xFF) - n;
346                 t = (idx & 0xFF) - 0x21;
347                 linear = (l * 94) + t;
348                 l = (linear / 188) + m;
349                 t = linear % 188;
350                 t += (t <= 0x4D) ? 0x31 : 0x43;
351                 break;
352         default:
353                 return EILSEQ;
354         }
355         return 0;
356 }
357
358 static __inline int
359 /*ARGSUSED*/
360 _citrus_JOHAB_stdenc_get_state_desc_generic(_JOHABEncodingInfo * __restrict ei,
361         _JOHABState * __restrict psenc, int * __restrict rstate)
362 {
363         /* ei may be unused */
364         _DIAGASSERT(psenc != NULL);
365         _DIAGASSERT(rstate != NULL);
366
367         *rstate = (psenc->chlen == 0)
368             ? _STDENC_SDGEN_INITIAL
369             : _STDENC_SDGEN_INCOMPLETE_CHAR;
370         return 0;
371 }
372
373 /* ----------------------------------------------------------------------
374  * public interface for ctype
375  */
376
377 _CITRUS_CTYPE_DECLS(JOHAB);
378 _CITRUS_CTYPE_DEF_OPS(JOHAB);
379
380 #include "citrus_ctype_template.h"
381
382
383 /* ----------------------------------------------------------------------
384  * public interface for stdenc
385  */
386
387 _CITRUS_STDENC_DECLS(JOHAB);
388 _CITRUS_STDENC_DEF_OPS(JOHAB);
389
390 #include "citrus_stdenc_template.h"