1 /* $FreeBSD: head/lib/libiconv_modules/HZ/citrus_hz.c 281550 2015-04-15 09:09:20Z tijl $ */
2 /* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */
5 * Copyright (c)2004, 2006 Citrus Project,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
31 #include <sys/cdefs.h>
32 #include <sys/queue.h>
33 #include <sys/types.h>
44 #include "citrus_namespace.h"
45 #include "citrus_types.h"
46 #include "citrus_bcs.h"
47 #include "citrus_module.h"
48 #include "citrus_stdenc.h"
50 #include "citrus_hz.h"
51 #include "citrus_prop.h"
56 * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx
57 * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx
58 * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
61 #define ESCAPE_CHAR '~'
64 CTRL
= 0, ASCII
= 1, GB2312
= 2, CS94
= 3, CS96
= 4
73 static const range_t ranges
[] = {
74 #define RANGE(start, end) { start, end, (end - start) + 1 }
75 /* CTRL */ RANGE(0x00, 0x1F),
76 /* ASCII */ RANGE(0x20, 0x7F),
77 /* GB2312 */ RANGE(0x21, 0x7E),
78 /* CS94 */ RANGE(0x21, 0x7E),
79 /* CS96 */ RANGE(0x20, 0x7F),
83 typedef struct escape_t escape_t
;
91 typedef TAILQ_HEAD(escape_list
, escape_t
) escape_list
;
93 TAILQ_ENTRY(escape_t
) entry
;
100 #define GL(escape) ((escape)->left)
101 #define GR(escape) ((escape)->right)
102 #define SET(escape) ((escape)->set)
103 #define ESC(escape) ((escape)->ch)
104 #define INIT(escape) (TAILQ_FIRST(SET(escape)))
106 static __inline escape_t
*
107 find_escape(escape_list
*set
, int ch
)
111 TAILQ_FOREACH(escape
, set
, entry
) {
112 if (ESC(escape
) == ch
)
126 #define E0SET(ei) (&(ei)->e0)
127 #define E1SET(ei) (&(ei)->e1)
128 #define INIT0(ei) (TAILQ_FIRST(E0SET(ei)))
129 #define INIT1(ei) (TAILQ_FIRST(E1SET(ei)))
137 #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
138 #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
140 #define _FUNCNAME(m) _citrus_HZ_##m
141 #define _ENCODING_INFO _HZEncodingInfo
142 #define _ENCODING_STATE _HZState
143 #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX
144 #define _ENCODING_IS_STATE_DEPENDENT 1
145 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL)
148 _citrus_HZ_init_state(_HZEncodingInfo
* __restrict ei
,
149 _HZState
* __restrict psenc
)
153 psenc
->inuse
= INIT0(ei
);
159 _citrus_HZ_pack_state(_HZEncodingInfo
* __restrict ei __unused
,
160 void *__restrict pspriv
, const _HZState
* __restrict psenc
)
163 memcpy(pspriv
, (const void *)psenc
, sizeof(*psenc
));
168 _citrus_HZ_unpack_state(_HZEncodingInfo
* __restrict ei __unused
,
169 _HZState
* __restrict psenc
, const void * __restrict pspriv
)
172 memcpy((void *)psenc
, pspriv
, sizeof(*psenc
));
177 _citrus_HZ_mbrtowc_priv(_HZEncodingInfo
* __restrict ei
,
178 wchar_t * __restrict pwc
, char ** __restrict s
, size_t n
,
179 _HZState
* __restrict psenc
, size_t * __restrict nresult
)
181 escape_t
*candidate
, *init
;
183 const range_t
*range
;
186 int bit
, ch
, head
, len
, tail
;
189 _citrus_HZ_init_state(ei
, psenc
);
194 if (psenc
->chlen
< 0 || psenc
->inuse
== NULL
)
198 bit
= head
= tail
= 0;
200 for (len
= 0; len
<= MB_LEN_MAX
;) {
201 if (psenc
->chlen
== tail
) {
204 *nresult
= (size_t)-2;
207 psenc
->ch
[psenc
->chlen
++] = *s0
++;
210 ch
= (unsigned char)psenc
->ch
[tail
++];
212 if ((ch
& ~0x80) <= 0x1F) {
213 if (psenc
->inuse
!= INIT0(ei
))
219 graphic
= GR(psenc
->inuse
);
223 graphic
= GL(psenc
->inuse
);
224 if (ch
== ESCAPE_CHAR
)
230 } else if (tail
== 2 && psenc
->ch
[0] == ESCAPE_CHAR
) {
231 if (tail
< psenc
->chlen
)
233 if (ch
== ESCAPE_CHAR
) {
235 } else if (ch
== '\n') {
236 if (psenc
->inuse
!= INIT0(ei
))
238 tail
= psenc
->chlen
= 0;
243 if (psenc
->inuse
== init
) {
245 } else if (INIT(psenc
->inuse
) == init
) {
250 if (candidate
== NULL
) {
251 candidate
= find_escape(
252 SET(psenc
->inuse
), ch
);
253 if (candidate
== NULL
) {
260 psenc
->inuse
= candidate
;
261 tail
= psenc
->chlen
= 0;
264 } else if (ch
& 0x80) {
265 if (graphic
!= GR(psenc
->inuse
))
269 if (graphic
!= GL(psenc
->inuse
))
272 range
= &ranges
[(size_t)graphic
->charset
];
273 if (range
->start
> ch
|| range
->end
< ch
)
277 if (graphic
->length
== (tail
- head
)) {
278 if (graphic
->charset
> GB2312
)
279 bit
|= ESC(psenc
->inuse
) << 24;
284 *nresult
= (size_t)-1;
287 if (tail
< psenc
->chlen
)
293 *nresult
= (wc
== 0) ? 0 : len
;
299 _citrus_HZ_wcrtomb_priv(_HZEncodingInfo
* __restrict ei
,
300 char * __restrict s
, size_t n
, wchar_t wc
,
301 _HZState
* __restrict psenc
, size_t * __restrict nresult
)
303 escape_t
*candidate
, *init
;
305 const range_t
*range
;
309 if (psenc
->chlen
!= 0 || psenc
->inuse
== NULL
)
317 if ((uint32_t)wc
<= 0x1F) {
318 candidate
= INIT0(ei
);
319 graphic
= (bit
== 0) ? candidate
->left
: candidate
->right
;
322 range
= &ranges
[(size_t)CTRL
];
324 } else if ((uint32_t)wc
<= 0x7F) {
328 candidate
= graphic
->escape
;
329 range
= &ranges
[(size_t)graphic
->charset
];
330 len
= graphic
->length
;
331 } else if ((uint32_t)wc
<= 0x7F7F) {
332 graphic
= ei
->gb2312
;
335 candidate
= graphic
->escape
;
336 range
= &ranges
[(size_t)graphic
->charset
];
337 len
= graphic
->length
;
339 ch
= (wc
>> 24) & 0xFF;
340 candidate
= find_escape(E0SET(ei
), ch
);
341 if (candidate
== NULL
) {
342 candidate
= find_escape(E1SET(ei
), ch
);
343 if (candidate
== NULL
)
347 graphic
= (bit
== 0) ? candidate
->left
: candidate
->right
;
350 range
= &ranges
[(size_t)graphic
->charset
];
351 len
= graphic
->length
;
353 if (psenc
->inuse
!= candidate
) {
355 if (SET(psenc
->inuse
) == SET(candidate
)) {
356 if (INIT(psenc
->inuse
) != init
||
357 psenc
->inuse
== init
|| candidate
== init
)
359 } else if (candidate
== (init
= INIT(candidate
))) {
366 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
367 psenc
->ch
[psenc
->chlen
++] = ESC(init
);
372 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
373 psenc
->ch
[psenc
->chlen
++] = ESC(candidate
);
374 psenc
->inuse
= candidate
;
379 ch
= (wc
>> (len
* 8)) & 0xFF;
380 if (range
->start
> ch
|| range
->end
< ch
)
382 psenc
->ch
[psenc
->chlen
++] = ch
| bit
;
384 memcpy(s
, psenc
->ch
, psenc
->chlen
);
385 *nresult
= psenc
->chlen
;
391 *nresult
= (size_t)-1;
396 _citrus_HZ_put_state_reset(_HZEncodingInfo
* __restrict ei
,
397 char * __restrict s
, size_t n
, _HZState
* __restrict psenc
,
398 size_t * __restrict nresult
)
402 if (psenc
->chlen
!= 0 || psenc
->inuse
== NULL
)
404 candidate
= INIT0(ei
);
405 if (psenc
->inuse
!= candidate
) {
409 psenc
->ch
[psenc
->chlen
++] = ESCAPE_CHAR
;
410 psenc
->ch
[psenc
->chlen
++] = ESC(candidate
);
414 if (psenc
->chlen
> 0)
415 memcpy(s
, psenc
->ch
, psenc
->chlen
);
416 *nresult
= psenc
->chlen
;
417 _citrus_HZ_init_state(ei
, psenc
);
423 _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo
* __restrict ei
,
424 _HZState
* __restrict psenc
, int * __restrict rstate
)
427 if (psenc
->chlen
< 0 || psenc
->inuse
== NULL
)
429 *rstate
= (psenc
->chlen
== 0)
430 ? ((psenc
->inuse
== INIT0(ei
))
431 ? _STDENC_SDGEN_INITIAL
432 : _STDENC_SDGEN_STABLE
)
433 : ((psenc
->ch
[0] == ESCAPE_CHAR
)
434 ? _STDENC_SDGEN_INCOMPLETE_SHIFT
435 : _STDENC_SDGEN_INCOMPLETE_CHAR
);
442 _citrus_HZ_stdenc_wctocs(_HZEncodingInfo
* __restrict ei __unused
,
443 _csid_t
* __restrict csid
, _index_t
* __restrict idx
, wchar_t wc
)
452 if ((uint32_t)wc
<= 0x7F) {
453 *csid
= (_csid_t
)bit
;
455 } else if ((uint32_t)wc
<= 0x7F7F) {
456 *csid
= (_csid_t
)(bit
| 0x8000);
459 *csid
= (_index_t
)(wc
& ~0x00FFFF7F);
460 *idx
= (_csid_t
)(wc
& 0x00FFFF7F);
468 _citrus_HZ_stdenc_cstowc(_HZEncodingInfo
* __restrict ei __unused
,
469 wchar_t * __restrict wc
, _csid_t csid
, _index_t idx
)
476 *wc
|= (wchar_t)0x80;
482 *wc
|= (wchar_t)csid
;
489 _citrus_HZ_encoding_module_uninit(_HZEncodingInfo
*ei
)
493 while ((escape
= TAILQ_FIRST(E0SET(ei
))) != NULL
) {
494 TAILQ_REMOVE(E0SET(ei
), escape
, entry
);
499 while ((escape
= TAILQ_FIRST(E1SET(ei
))) != NULL
) {
500 TAILQ_REMOVE(E1SET(ei
), escape
, entry
);
508 _citrus_HZ_parse_char(void *context
, const char *name __unused
, const char *s
)
513 p
= (void **)context
;
514 escape
= (escape_t
*)p
[0];
515 if (escape
->ch
!= '\0')
518 if (escape
->ch
== ESCAPE_CHAR
|| *s
!= '\0')
525 _citrus_HZ_parse_graphic(void *context
, const char *name
, const char *s
)
532 p
= (void **)context
;
533 escape
= (escape_t
*)p
[0];
534 ei
= (_HZEncodingInfo
*)p
[1];
535 graphic
= calloc(1, sizeof(*graphic
));
538 if (strcmp("GL", name
) == 0) {
539 if (GL(escape
) != NULL
)
541 GL(escape
) = graphic
;
542 } else if (strcmp("GR", name
) == 0) {
543 if (GR(escape
) != NULL
)
545 GR(escape
) = graphic
;
551 graphic
->escape
= escape
;
552 if (_bcs_strncasecmp("ASCII", s
, 5) == 0) {
555 graphic
->charset
= ASCII
;
559 } else if (_bcs_strncasecmp("GB2312", s
, 6) == 0) {
562 graphic
->charset
= GB2312
;
564 ei
->gb2312
= graphic
;
566 } else if (strncmp("94*", s
, 3) == 0)
567 graphic
->charset
= CS94
;
568 else if (strncmp("96*", s
, 3) == 0)
569 graphic
->charset
= CS96
;
574 case '1': case '2': case '3':
575 graphic
->length
= (size_t)(*s
- '0');
585 static const _citrus_prop_hint_t escape_hints
[] = {
586 _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char
),
587 _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic
),
588 _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic
),
589 _CITRUS_PROP_HINT_END
593 _citrus_HZ_parse_escape(void *context
, const char *name
, const char *s
)
599 ei
= (_HZEncodingInfo
*)context
;
600 escape
= calloc(1, sizeof(*escape
));
603 if (strcmp("0", name
) == 0) {
604 escape
->set
= E0SET(ei
);
605 TAILQ_INSERT_TAIL(E0SET(ei
), escape
, entry
);
606 } else if (strcmp("1", name
) == 0) {
607 escape
->set
= E1SET(ei
);
608 TAILQ_INSERT_TAIL(E1SET(ei
), escape
, entry
);
613 p
[0] = (void *)escape
;
615 return (_citrus_prop_parse_variable(
616 escape_hints
, (void *)&p
[0], s
, strlen(s
)));
619 static const _citrus_prop_hint_t root_hints
[] = {
620 _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape
),
621 _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape
),
622 _CITRUS_PROP_HINT_END
626 _citrus_HZ_encoding_module_init(_HZEncodingInfo
* __restrict ei
,
627 const void * __restrict var
, size_t lenvar
)
631 memset(ei
, 0, sizeof(*ei
));
632 TAILQ_INIT(E0SET(ei
));
633 TAILQ_INIT(E1SET(ei
));
634 errnum
= _citrus_prop_parse_variable(
635 root_hints
, (void *)ei
, var
, lenvar
);
637 _citrus_HZ_encoding_module_uninit(ei
);
641 /* ----------------------------------------------------------------------
642 * public interface for stdenc
645 _CITRUS_STDENC_DECLS(HZ
);
646 _CITRUS_STDENC_DEF_OPS(HZ
);
648 #include "citrus_stdenc_template.h"