3d7af8282bc5798f74f2e76731c5aee3889ba9d5
[dragonfly.git] / lib / libc / citrus / modules / citrus_gbk2k.c
1 /* $NetBSD: src/lib/libc/citrus/modules/citrus_gbk2k.c,v 1.4 2003/06/26 12:09:57 tshiozak Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/modules/citrus_gbk2k.c,v 1.1 2005/03/11 23:33:53 joerg Exp $ */
3
4 /*-
5  * Copyright (c)2003 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 <limits.h>
34 #include <locale.h>
35 #include <stddef.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <wchar.h>
40
41 #include "citrus_namespace.h"
42 #include "citrus_types.h"
43 #include "citrus_bcs.h"
44 #include "citrus_module.h"
45 #include "citrus_ctype.h"
46 #include "citrus_stdenc.h"
47 #include "citrus_gbk2k.h"
48
49
50 /* ----------------------------------------------------------------------
51  * private stuffs used by templates
52  */
53
54 typedef struct _GBK2KState {
55         char ch[4];
56         int chlen;
57 } _GBK2KState;
58
59 typedef struct {
60         int ei_mode;
61 } _GBK2KEncodingInfo;
62 #define _MODE_2BYTE     0x0001
63
64 typedef struct {
65         _GBK2KEncodingInfo      ei;
66         struct {
67                 /* for future multi-locale facility */
68                 _GBK2KState     s_mblen;
69                 _GBK2KState     s_mbrlen;
70                 _GBK2KState     s_mbrtowc;
71                 _GBK2KState     s_mbtowc;
72                 _GBK2KState     s_mbsrtowcs;
73                 _GBK2KState     s_wcrtomb;
74                 _GBK2KState     s_wcsrtombs;
75                 _GBK2KState     s_wctomb;
76         } states;
77 } _GBK2KCTypeInfo;
78
79 #define _CEI_TO_EI(_cei_)               (&(_cei_)->ei)
80 #define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
81
82 #define _FUNCNAME(m)                    _citrus_GBK2K_##m
83 #define _ENCODING_INFO                  _GBK2KEncodingInfo
84 #define _CTYPE_INFO                     _GBK2KCTypeInfo
85 #define _ENCODING_STATE                 _GBK2KState
86 #define _ENCODING_MB_CUR_MAX(_ei_)      4
87 #define _ENCODING_IS_STATE_DEPENDENT    0
88 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_)        0
89
90 static __inline void
91 /*ARGSUSED*/
92 _citrus_GBK2K_init_state(_GBK2KEncodingInfo * __restrict ei,
93                          _GBK2KState * __restrict s)
94 {
95         memset(s, 0, sizeof(*s));
96 }
97
98 static __inline void
99 /*ARGSUSED*/
100 _citrus_GBK2K_pack_state(_GBK2KEncodingInfo * __restrict ei,
101                          void * __restrict pspriv,
102                          const _GBK2KState * __restrict s)
103 {
104         memcpy(pspriv, (const void *)s, sizeof(*s));
105 }
106
107 static __inline void
108 /*ARGSUSED*/
109 _citrus_GBK2K_unpack_state(_GBK2KEncodingInfo * __restrict ei,
110                            _GBK2KState * __restrict s,
111                            const void * __restrict pspriv)
112 {
113         memcpy((void *)s, pspriv, sizeof(*s));
114 }
115
116 static  __inline int
117 _mb_singlebyte(int c)
118 {
119         c &= 0xff;
120         return (c <= 0x7f);
121 }
122
123 static __inline int
124 _mb_leadbyte(int c)
125 {
126         c &= 0xff;
127         return (0x81 <= c && c <= 0xfe);
128 }
129
130 static __inline int
131 _mb_trailbyte(int c)
132 {
133         c &= 0xff;
134         return ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfe));
135 }
136
137 static __inline int
138 _mb_surrogate(int c)
139 {
140         c &= 0xff;
141         return (0x30 <= c && c <= 0x39);
142 }
143
144 static __inline int
145 _mb_count(wchar_t v)
146 {
147         u_int32_t c;
148
149         c = (u_int32_t)v; /* XXX */
150         if (!(c & 0xffffff00))
151                 return (1);
152         if (!(c & 0xffff0000))
153                 return (2);
154         return (4);
155 }
156
157 #define _PSENC          (psenc->ch[psenc->chlen - 1])
158 #define _PUSH_PSENC(c)  (psenc->ch[psenc->chlen++] = (c))
159
160 static int
161 _citrus_GBK2K_mbrtowc_priv(_GBK2KEncodingInfo * __restrict ei,
162                            wchar_t * __restrict pwc,
163                            const char ** __restrict s, size_t n,
164                            _GBK2KState * __restrict psenc,
165                            size_t * __restrict nresult)
166 {
167         int chlenbak, len;
168         const char *s0, *s1;
169         wchar_t wc;
170
171         _DIAGASSERT(ei != NULL);
172         /* pwc may be NULL */
173         _DIAGASSERT(s != NULL);
174         _DIAGASSERT(psenc != NULL);
175
176         s0 = *s;
177
178         if (s0 == NULL) {
179                 /* _citrus_GBK2K_init_state(ei, psenc); */
180                 psenc->chlen = 0;
181                 *nresult = 0;
182                 return (0);
183         }
184
185         chlenbak = psenc->chlen;
186
187         switch (psenc->chlen) {
188         case 3:
189                 if (!_mb_leadbyte (_PSENC))
190                         goto invalid;
191         /* FALLTHROUGH */
192         case 2:
193                 if (!_mb_surrogate(_PSENC) || _mb_trailbyte(_PSENC))
194                         goto invalid;
195         /* FALLTHROUGH */
196         case 1:
197                 if (!_mb_leadbyte (_PSENC))
198                         goto invalid;
199         /* FALLTHOROUGH */
200         case 0:
201                 break;
202         default:
203                 goto invalid;
204         }
205
206         for (;;) {
207                 if (n-- < 1)
208                         goto restart;
209
210                 _PUSH_PSENC(*s0++);
211
212                 switch (psenc->chlen) {
213                 case 1:
214                         if (_mb_singlebyte(_PSENC))
215                                 goto convert;
216                         if (_mb_leadbyte  (_PSENC))
217                                 continue;
218                         goto ilseq;
219                 case 2:
220                         if (_mb_trailbyte (_PSENC))
221                                 goto convert;
222                         if ((ei->ei_mode & _MODE_2BYTE) == 0 &&
223                             _mb_surrogate (_PSENC))
224                                 continue;
225                         goto ilseq;
226                 case 3:
227                         if (_mb_leadbyte  (_PSENC))
228                                 continue;
229                         goto ilseq;
230                 case 4:
231                         if (_mb_surrogate (_PSENC))
232                                 goto convert;
233                         goto ilseq;
234                 }
235         }
236
237 convert:
238         len = psenc->chlen;
239         s1  = &psenc->ch[0];
240         wc  = 0;
241         while (len-- > 0)
242                 wc = (wc << 8) | (*s1++ & 0xff);
243
244         if (pwc != NULL)
245                 *pwc = wc;
246         *s = s0;
247         *nresult = (wc == 0) ? 0 : psenc->chlen - chlenbak; 
248         /* _citrus_GBK2K_init_state(ei, psenc); */
249         psenc->chlen = 0;
250
251         return (0);
252
253 restart:
254         *s = s0;
255         *nresult = (size_t)-2;
256
257         return (0);
258
259 invalid:
260         return (EINVAL);
261
262 ilseq:
263         *nresult = (size_t)-1;
264         return (EILSEQ);
265 }
266
267 static int
268 _citrus_GBK2K_wcrtomb_priv(_GBK2KEncodingInfo * __restrict ei,
269                            char * __restrict s, size_t n, wchar_t wc,
270                            _GBK2KState * __restrict psenc,
271                            size_t * __restrict nresult)
272 {
273         int len, ret;
274
275         _DIAGASSERT(ei != NULL);
276         _DIAGASSERT(s != NULL);
277         _DIAGASSERT(psenc != NULL);
278
279         if (psenc->chlen != 0) {
280                 ret = EINVAL;
281                 goto err;
282         }
283
284         len = _mb_count(wc);
285         if (n < len) {
286                 ret = E2BIG;
287                 goto err;
288         }
289
290         switch (len) {
291         case 1:
292                 if (!_mb_singlebyte(_PUSH_PSENC(wc     ))) {
293                         ret = EILSEQ;
294                         goto err;
295                 }
296                 break;
297         case 2:
298                 if (!_mb_leadbyte  (_PUSH_PSENC(wc >> 8)) ||
299                     !_mb_trailbyte (_PUSH_PSENC(wc     ))) {
300                         ret = EILSEQ;
301                         goto err;
302                 }
303                 break;
304         case 4:
305                 if ((ei->ei_mode & _MODE_2BYTE) != 0 ||
306                     !_mb_leadbyte  (_PUSH_PSENC(wc >> 24)) ||
307                     !_mb_surrogate (_PUSH_PSENC(wc >> 16)) ||
308                     !_mb_leadbyte  (_PUSH_PSENC(wc >>  8)) ||
309                     !_mb_surrogate (_PUSH_PSENC(wc      ))) {
310                         ret = EILSEQ;
311                         goto err;
312                 }
313                 break;
314         }
315
316         _DIAGASSERT(len == psenc->chlen);
317
318         memcpy(s, psenc->ch, psenc->chlen);
319         *nresult = psenc->chlen;
320         /* _citrus_GBK2K_init_state(ei, psenc); */
321         psenc->chlen = 0;
322
323         return (0);
324
325 err:
326         *nresult = (size_t)-1;
327         return ret;
328 }
329
330 static __inline int
331 /*ARGSUSED*/
332 _citrus_GBK2K_stdenc_wctocs(_GBK2KEncodingInfo * __restrict ei,
333                             _csid_t * __restrict csid,
334                             _index_t * __restrict idx, wchar_t wc)
335 {
336         u_int8_t ch, cl;
337
338         _DIAGASSERT(csid != NULL && idx != NULL);
339
340         if ((u_int32_t)wc<0x80) {
341                 /* ISO646 */
342                 *csid = 0;
343                 *idx = (_index_t)wc;
344         } else if ((u_int32_t)wc>=0x10000) {
345                 /* GBKUCS : XXX */
346                 *csid = 3;
347                 *idx = (_index_t)wc;
348         } else {
349                 ch = (u_int8_t)(wc >> 8);
350                 cl = (u_int8_t)wc;
351                 if (ch>=0xA1 && cl>=0xA1) {
352                         /* EUC G1 */
353                         *csid = 1;
354                         *idx = (_index_t)wc & 0x7F7FU;
355                 } else {
356                         /* extended area (0x8140-) */
357                         *csid = 2;
358                         *idx = (_index_t)wc;
359                 }
360         }
361                 
362         return 0;
363 }
364
365 static __inline int
366 /*ARGSUSED*/
367 _citrus_GBK2K_stdenc_cstowc(_GBK2KEncodingInfo * __restrict ei,
368                             wchar_t * __restrict wc,
369                             _csid_t csid, _index_t idx)
370 {
371
372         _DIAGASSERT(wc != NULL);
373
374         switch (csid) {
375         case 0:
376                 /* ISO646 */
377                 *wc = (wchar_t)idx;
378                 break;
379         case 1:
380                 /* EUC G1 */
381                 *wc = (wchar_t)idx | 0x8080U;
382                 break;
383         case 2:
384                 /* extended area */
385                 *wc = (wchar_t)idx;
386                 break;
387         case 3:
388                 /* GBKUCS : XXX */
389                 if ((ei->ei_mode & _MODE_2BYTE) != 0)
390                         return EINVAL;
391                 *wc = (wchar_t)idx;
392                 break;
393         default:
394                 return EILSEQ;
395         }
396
397         return 0;
398 }
399
400 static int
401 /*ARGSUSED*/
402 _citrus_GBK2K_encoding_module_init(_GBK2KEncodingInfo * __restrict ei,
403                                    const void * __restrict var, size_t lenvar)
404 {
405         const char *p;
406
407         _DIAGASSERT(ei != NULL);
408
409         p = var;
410 #define MATCH(x, act)                                           \
411 do {                                                            \
412         if (lenvar >= (sizeof(#x)-1) &&                         \
413             _bcs_strncasecmp(p, #x, sizeof(#x)-1) == 0) {       \
414                 act;                                            \
415                 lenvar -= sizeof(#x)-1;                         \
416                 p += sizeof(#x)-1;                              \
417         }                                                       \
418 } while (/*CONSTCOND*/0)
419         while (lenvar>0) {
420                 switch (_bcs_tolower(*p)) {
421                 case '2':
422                         MATCH("2byte", ei->ei_mode |= _MODE_2BYTE);
423                         break;
424                 }
425                 p++;
426                 lenvar--;
427         }
428
429         memset((void *)ei, 0, sizeof(*ei));
430         return (0);
431 }
432
433 static void
434 /*ARGSUSED*/
435 _citrus_GBK2K_encoding_module_uninit(_GBK2KEncodingInfo *ei)
436 {
437 }
438
439
440 /* ----------------------------------------------------------------------
441  * public interface for ctype
442  */
443
444 _CITRUS_CTYPE_DECLS(GBK2K);
445 _CITRUS_CTYPE_DEF_OPS(GBK2K);
446
447 #include "citrus_ctype_template.h"
448
449 /* ----------------------------------------------------------------------
450  * public interface for stdenc
451  */
452
453 _CITRUS_STDENC_DECLS(GBK2K);
454 _CITRUS_STDENC_DEF_OPS(GBK2K);
455
456 #include "citrus_stdenc_template.h"