1 /* $NetBSD: citrus_big5.c,v 1.9 2005/10/29 18:02:04 tshiozak Exp $ */ 2 3 /*- 4 * Copyright (c)2002 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 /*- 30 * Copyright (c) 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * Paul Borman at Krystal Technologies. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 #if defined(LIBC_SCCS) && !defined(lint) 63 __RCSID("$NetBSD: citrus_big5.c,v 1.9 2005/10/29 18:02:04 tshiozak Exp $"); 64 #endif /* LIBC_SCCS and not lint */ 65 66 #include <assert.h> 67 #include <errno.h> 68 #include <string.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <stddef.h> 72 #include <locale.h> 73 #include <wchar.h> 74 #include <sys/types.h> 75 #include <limits.h> 76 77 #include "citrus_namespace.h" 78 #include "citrus_types.h" 79 #include "citrus_module.h" 80 #include "citrus_ctype.h" 81 #include "citrus_stdenc.h" 82 #include "citrus_big5.h" 83 84 /* ---------------------------------------------------------------------- 85 * private stuffs used by templates 86 */ 87 88 typedef struct { 89 char ch[2]; 90 int chlen; 91 } _BIG5State; 92 93 typedef struct { 94 int dummy; 95 } _BIG5EncodingInfo; 96 97 typedef struct { 98 _BIG5EncodingInfo ei; 99 struct { 100 /* for future multi-locale facility */ 101 _BIG5State s_mblen; 102 _BIG5State s_mbrlen; 103 _BIG5State s_mbrtowc; 104 _BIG5State s_mbtowc; 105 _BIG5State s_mbsrtowcs; 106 _BIG5State s_wcrtomb; 107 _BIG5State s_wcsrtombs; 108 _BIG5State s_wctomb; 109 } states; 110 } _BIG5CTypeInfo; 111 112 #define _CEI_TO_EI(_cei_) (&(_cei_)->ei) 113 #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ 114 115 #define _FUNCNAME(m) _citrus_BIG5_##m 116 #define _ENCODING_INFO _BIG5EncodingInfo 117 #define _CTYPE_INFO _BIG5CTypeInfo 118 #define _ENCODING_STATE _BIG5State 119 #define _ENCODING_MB_CUR_MAX(_ei_) 2 120 #define _ENCODING_IS_STATE_DEPENDENT 0 121 #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) 0 122 123 124 static __inline void 125 /*ARGSUSED*/ 126 _citrus_BIG5_init_state(_BIG5EncodingInfo * __restrict ei, 127 _BIG5State * __restrict s) 128 { 129 memset(s, 0, sizeof(*s)); 130 } 131 132 static __inline void 133 /*ARGSUSED*/ 134 _citrus_BIG5_pack_state(_BIG5EncodingInfo * __restrict ei, 135 void * __restrict pspriv, 136 const _BIG5State * __restrict s) 137 { 138 memcpy(pspriv, (const void *)s, sizeof(*s)); 139 } 140 141 static __inline void 142 /*ARGSUSED*/ 143 _citrus_BIG5_unpack_state(_BIG5EncodingInfo * __restrict ei, 144 _BIG5State * __restrict s, 145 const void * __restrict pspriv) 146 { 147 memcpy((void *)s, pspriv, sizeof(*s)); 148 } 149 150 static __inline int 151 _citrus_BIG5_check(u_int c) 152 { 153 c &= 0xff; 154 return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1); 155 } 156 157 static __inline int 158 _citrus_BIG5_check2(u_int c) 159 { 160 c &= 0xff; 161 if ((c >= 0x40 && c <= 0x7f) || (c >= 0xa1 && c <= 0xfe)) 162 return 1; 163 else 164 return 0; 165 } 166 167 static int 168 /*ARGSUSED*/ 169 _citrus_BIG5_encoding_module_init(_BIG5EncodingInfo * __restrict ei, 170 const void * __restrict var, size_t lenvar) 171 { 172 _DIAGASSERT(ei != NULL); 173 174 memset((void *)ei, 0, sizeof(*ei)); 175 176 return (0); 177 } 178 179 static void 180 /*ARGSUSED*/ 181 _citrus_BIG5_encoding_module_uninit(_BIG5EncodingInfo *ei) 182 { 183 } 184 185 static int 186 /*ARGSUSED*/ 187 _citrus_BIG5_mbrtowc_priv(_BIG5EncodingInfo * __restrict ei, 188 wchar_t * __restrict pwc, 189 const char ** __restrict s, size_t n, 190 _BIG5State * __restrict psenc, 191 size_t * __restrict nresult) 192 { 193 wchar_t wchar; 194 int c; 195 int chlenbak; 196 const char *s0; 197 198 _DIAGASSERT(nresult != 0); 199 _DIAGASSERT(ei != NULL); 200 _DIAGASSERT(psenc != NULL); 201 _DIAGASSERT(s != NULL && *s != NULL); 202 203 s0 = *s; 204 205 if (s0 == NULL) { 206 _citrus_BIG5_init_state(ei, psenc); 207 *nresult = 0; 208 return (0); 209 } 210 211 chlenbak = psenc->chlen; 212 213 /* make sure we have the first byte in the buffer */ 214 switch (psenc->chlen) { 215 case 0: 216 if (n < 1) 217 goto restart; 218 psenc->ch[0] = *s0++; 219 psenc->chlen = 1; 220 n--; 221 break; 222 case 1: 223 break; 224 default: 225 /* illegal state */ 226 goto ilseq; 227 } 228 229 c = _citrus_BIG5_check(psenc->ch[0] & 0xff); 230 if (c == 0) 231 goto ilseq; 232 while (psenc->chlen < c) { 233 if (n < 1) { 234 goto restart; 235 } 236 psenc->ch[psenc->chlen] = *s0++; 237 psenc->chlen++; 238 n--; 239 } 240 241 switch (c) { 242 case 1: 243 wchar = psenc->ch[0] & 0xff; 244 break; 245 case 2: 246 if (!_citrus_BIG5_check2(psenc->ch[1] & 0xff)) 247 goto ilseq; 248 wchar = ((psenc->ch[0] & 0xff) << 8) | (psenc->ch[1] & 0xff); 249 break; 250 default: 251 /* illegal state */ 252 goto ilseq; 253 } 254 255 *s = s0; 256 psenc->chlen = 0; 257 if (pwc) 258 *pwc = wchar; 259 if (!wchar) 260 *nresult = 0; 261 else 262 *nresult = c - chlenbak; 263 264 return (0); 265 266 ilseq: 267 psenc->chlen = 0; 268 *nresult = (size_t)-1; 269 return (EILSEQ); 270 271 restart: 272 *s = s0; 273 *nresult = (size_t)-2; 274 return (0); 275 } 276 277 static int 278 /*ARGSUSED*/ 279 _citrus_BIG5_wcrtomb_priv(_BIG5EncodingInfo * __restrict ei, 280 char * __restrict s, 281 size_t n, wchar_t wc, _BIG5State * __restrict psenc, 282 size_t * __restrict nresult) 283 { 284 int l, ret; 285 286 _DIAGASSERT(ei != NULL); 287 _DIAGASSERT(nresult != 0); 288 _DIAGASSERT(s != NULL); 289 290 /* check invalid sequence */ 291 if (wc & ~0xffff) { 292 ret = EILSEQ; 293 goto err; 294 } 295 296 if (wc & 0x8000) { 297 if (_citrus_BIG5_check((wc >> 8) & 0xff) != 2 || 298 !_citrus_BIG5_check2(wc & 0xff)) { 299 ret = EILSEQ; 300 goto err; 301 } 302 l = 2; 303 } else { 304 if (wc & ~0xff || !_citrus_BIG5_check(wc & 0xff)) { 305 ret = EILSEQ; 306 goto err; 307 } 308 l = 1; 309 } 310 311 if (n < l) { 312 /* bound check failure */ 313 ret = E2BIG; 314 goto err; 315 } 316 317 if (l == 2) { 318 s[0] = (wc >> 8) & 0xff; 319 s[1] = wc & 0xff; 320 } else 321 s[0] = wc & 0xff; 322 323 *nresult = l; 324 325 return 0; 326 327 err: 328 *nresult = (size_t)-1; 329 return ret; 330 } 331 332 static __inline int 333 /*ARGSUSED*/ 334 _citrus_BIG5_stdenc_wctocs(_BIG5EncodingInfo * __restrict ei, 335 _csid_t * __restrict csid, 336 _index_t * __restrict idx, wchar_t wc) 337 { 338 339 _DIAGASSERT(csid != NULL && idx != NULL); 340 341 if (wc<0x100) 342 *csid = 0; 343 else 344 *csid = 1; 345 *idx = (_index_t)wc; 346 347 return 0; 348 } 349 350 static __inline int 351 /*ARGSUSED*/ 352 _citrus_BIG5_stdenc_cstowc(_BIG5EncodingInfo * __restrict ei, 353 wchar_t * __restrict wc, 354 _csid_t csid, _index_t idx) 355 { 356 u_int8_t h, l; 357 358 _DIAGASSERT(wc != NULL); 359 360 switch (csid) { 361 case 0: 362 if (idx>=0x80U) 363 return EILSEQ; 364 *wc = (wchar_t)idx; 365 break; 366 case 1: 367 if (idx>=0x10000U) 368 return EILSEQ; 369 h = idx >> 8; 370 l = idx; 371 if (h<0xA1 || h>0xF9 || l<0x40 || l>0xFE) 372 return EILSEQ; 373 *wc = (wchar_t)idx; 374 break; 375 default: 376 return EILSEQ; 377 } 378 379 return 0; 380 } 381 382 static __inline int 383 /*ARGSUSED*/ 384 _citrus_BIG5_stdenc_get_state_desc_generic(_BIG5EncodingInfo * __restrict ei, 385 _BIG5State * __restrict psenc, 386 int * __restrict rstate) 387 { 388 389 if (psenc->chlen == 0) 390 *rstate = _STDENC_SDGEN_INITIAL; 391 else 392 *rstate = _STDENC_SDGEN_INCOMPLETE_CHAR; 393 394 return 0; 395 } 396 397 /* ---------------------------------------------------------------------- 398 * public interface for ctype 399 */ 400 401 _CITRUS_CTYPE_DECLS(BIG5); 402 _CITRUS_CTYPE_DEF_OPS(BIG5); 403 404 #include "citrus_ctype_template.h" 405 406 407 /* ---------------------------------------------------------------------- 408 * public interface for stdenc 409 */ 410 411 _CITRUS_STDENC_DECLS(BIG5); 412 _CITRUS_STDENC_DEF_OPS(BIG5); 413 414 #include "citrus_stdenc_template.h" 415