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