1219019Sgabor/* $FreeBSD: releng/10.3/lib/libiconv_modules/EUC/citrus_euc.c 282275 2015-04-30 16:08:47Z tijl $ */ 2219019Sgabor/* $NetBSD: citrus_euc.c,v 1.14 2009/01/11 02:46:24 christos Exp $ */ 3219019Sgabor 4219019Sgabor/*- 5219019Sgabor * Copyright (c)2002 Citrus Project, 6219019Sgabor * All rights reserved. 7219019Sgabor * 8219019Sgabor * Redistribution and use in source and binary forms, with or without 9219019Sgabor * modification, are permitted provided that the following conditions 10219019Sgabor * are met: 11219019Sgabor * 1. Redistributions of source code must retain the above copyright 12219019Sgabor * notice, this list of conditions and the following disclaimer. 13219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 14219019Sgabor * notice, this list of conditions and the following disclaimer in the 15219019Sgabor * documentation and/or other materials provided with the distribution. 16219019Sgabor * 17219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219019Sgabor * SUCH DAMAGE. 28219019Sgabor */ 29219019Sgabor 30219019Sgabor/*- 31219019Sgabor * Copyright (c) 1993 32219019Sgabor * The Regents of the University of California. All rights reserved. 33219019Sgabor * 34219019Sgabor * This code is derived from software contributed to Berkeley by 35219019Sgabor * Paul Borman at Krystal Technologies. 36219019Sgabor * 37219019Sgabor * Redistribution and use in source and binary forms, with or without 38219019Sgabor * modification, are permitted provided that the following conditions 39219019Sgabor * are met: 40219019Sgabor * 1. Redistributions of source code must retain the above copyright 41219019Sgabor * notice, this list of conditions and the following disclaimer. 42219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 43219019Sgabor * notice, this list of conditions and the following disclaimer in the 44219019Sgabor * documentation and/or other materials provided with the distribution. 45219019Sgabor * 3. Neither the name of the University nor the names of its contributors 46219019Sgabor * may be used to endorse or promote products derived from this software 47219019Sgabor * without specific prior written permission. 48219019Sgabor * 49219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59219019Sgabor * SUCH DAMAGE. 60219019Sgabor */ 61219019Sgabor 62219019Sgabor#include <sys/cdefs.h> 63219019Sgabor#include <sys/types.h> 64219019Sgabor 65219019Sgabor#include <assert.h> 66219019Sgabor#include <errno.h> 67219019Sgabor#include <limits.h> 68219019Sgabor#include <stddef.h> 69219019Sgabor#include <stdio.h> 70219019Sgabor#include <stdlib.h> 71219019Sgabor#include <string.h> 72219019Sgabor#include <wchar.h> 73219019Sgabor 74219019Sgabor#include "citrus_namespace.h" 75219019Sgabor#include "citrus_bcs.h" 76219019Sgabor#include "citrus_types.h" 77219019Sgabor#include "citrus_module.h" 78219019Sgabor#include "citrus_stdenc.h" 79219019Sgabor#include "citrus_euc.h" 80219019Sgabor 81219019Sgabor 82219019Sgabor/* ---------------------------------------------------------------------- 83219019Sgabor * private stuffs used by templates 84219019Sgabor */ 85219019Sgabor 86219019Sgabortypedef struct { 87219019Sgabor int chlen; 88219019Sgabor char ch[3]; 89219019Sgabor} _EUCState; 90219019Sgabor 91219019Sgabortypedef struct { 92219019Sgabor wchar_t bits[4]; 93219019Sgabor wchar_t mask; 94219019Sgabor unsigned count[4]; 95219019Sgabor unsigned mb_cur_max; 96219019Sgabor} _EUCEncodingInfo; 97219019Sgabor 98219019Sgabor#define _SS2 0x008e 99219019Sgabor#define _SS3 0x008f 100219019Sgabor 101219019Sgabor#define _CEI_TO_EI(_cei_) (&(_cei_)->ei) 102219019Sgabor#define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ 103219019Sgabor 104219019Sgabor#define _FUNCNAME(m) _citrus_EUC_##m 105219019Sgabor#define _ENCODING_INFO _EUCEncodingInfo 106219019Sgabor#define _ENCODING_STATE _EUCState 107219019Sgabor#define _ENCODING_MB_CUR_MAX(_ei_) (_ei_)->mb_cur_max 108219019Sgabor#define _ENCODING_IS_STATE_DEPENDENT 0 109219019Sgabor#define _STATE_NEEDS_EXPLICIT_INIT(_ps_) 0 110219019Sgabor 111219019Sgabor 112219019Sgaborstatic __inline int 113219019Sgabor_citrus_EUC_cs(unsigned int c) 114219019Sgabor{ 115219019Sgabor 116219019Sgabor c &= 0xff; 117219019Sgabor 118219019Sgabor return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0); 119219019Sgabor} 120219019Sgabor 121219019Sgaborstatic __inline int 122219019Sgabor_citrus_EUC_parse_variable(_EUCEncodingInfo *ei, const void *var, 123219019Sgabor size_t lenvar __unused) 124219019Sgabor{ 125219019Sgabor char *e; 126219019Sgabor const char *v; 127219019Sgabor int x; 128219019Sgabor 129219019Sgabor /* parse variable string */ 130219019Sgabor if (!var) 131219019Sgabor return (EFTYPE); 132219019Sgabor 133219019Sgabor v = (const char *)var; 134219019Sgabor 135219019Sgabor while (*v == ' ' || *v == '\t') 136219019Sgabor ++v; 137219019Sgabor 138219019Sgabor ei->mb_cur_max = 1; 139219019Sgabor for (x = 0; x < 4; ++x) { 140219019Sgabor ei->count[x] = (int)_bcs_strtol(v, (char **)&e, 0); 141219019Sgabor if (v == e || !(v = e) || ei->count[x] < 1 || ei->count[x] > 4) { 142219019Sgabor return (EFTYPE); 143219019Sgabor } 144219019Sgabor if (ei->mb_cur_max < ei->count[x]) 145219019Sgabor ei->mb_cur_max = ei->count[x]; 146219019Sgabor while (*v == ' ' || *v == '\t') 147219019Sgabor ++v; 148219019Sgabor ei->bits[x] = (int)_bcs_strtol(v, (char **)&e, 0); 149219019Sgabor if (v == e || !(v = e)) { 150219019Sgabor return (EFTYPE); 151219019Sgabor } 152219019Sgabor while (*v == ' ' || *v == '\t') 153219019Sgabor ++v; 154219019Sgabor } 155219019Sgabor ei->mask = (int)_bcs_strtol(v, (char **)&e, 0); 156219019Sgabor if (v == e || !(v = e)) { 157219019Sgabor return (EFTYPE); 158219019Sgabor } 159219019Sgabor 160219019Sgabor return (0); 161219019Sgabor} 162219019Sgabor 163219019Sgabor 164219019Sgaborstatic __inline void 165219019Sgabor/*ARGSUSED*/ 166219019Sgabor_citrus_EUC_init_state(_EUCEncodingInfo *ei __unused, _EUCState *s) 167219019Sgabor{ 168219019Sgabor 169219019Sgabor memset(s, 0, sizeof(*s)); 170219019Sgabor} 171219019Sgabor 172260264Sdim#if 0 173219019Sgaborstatic __inline void 174219019Sgabor/*ARGSUSED*/ 175219019Sgabor_citrus_EUC_pack_state(_EUCEncodingInfo *ei __unused, void *pspriv, 176219019Sgabor const _EUCState *s) 177219019Sgabor{ 178219019Sgabor 179219019Sgabor memcpy(pspriv, (const void *)s, sizeof(*s)); 180219019Sgabor} 181219019Sgabor 182219019Sgaborstatic __inline void 183219019Sgabor/*ARGSUSED*/ 184219019Sgabor_citrus_EUC_unpack_state(_EUCEncodingInfo *ei __unused, _EUCState *s, 185219019Sgabor const void *pspriv) 186219019Sgabor{ 187219019Sgabor 188219019Sgabor memcpy((void *)s, pspriv, sizeof(*s)); 189219019Sgabor} 190260264Sdim#endif 191219019Sgabor 192219019Sgaborstatic int 193282275Stijl_citrus_EUC_mbrtowc_priv(_EUCEncodingInfo *ei, wchar_t *pwc, char **s, 194219019Sgabor size_t n, _EUCState *psenc, size_t *nresult) 195219019Sgabor{ 196219019Sgabor wchar_t wchar; 197219019Sgabor int c, chlenbak, cs, len; 198282275Stijl char *s0, *s1 = NULL; 199219019Sgabor 200219019Sgabor s0 = *s; 201219019Sgabor 202219019Sgabor if (s0 == NULL) { 203219019Sgabor _citrus_EUC_init_state(ei, psenc); 204219019Sgabor *nresult = 0; /* state independent */ 205219019Sgabor return (0); 206219019Sgabor } 207219019Sgabor 208219019Sgabor chlenbak = psenc->chlen; 209219019Sgabor 210219019Sgabor /* make sure we have the first byte in the buffer */ 211219019Sgabor switch (psenc->chlen) { 212219019Sgabor case 0: 213219019Sgabor if (n < 1) 214219019Sgabor goto restart; 215219019Sgabor psenc->ch[0] = *s0++; 216219019Sgabor psenc->chlen = 1; 217219019Sgabor n--; 218219019Sgabor break; 219219019Sgabor case 1: 220219019Sgabor case 2: 221219019Sgabor break; 222219019Sgabor default: 223219019Sgabor /* illgeal state */ 224219019Sgabor goto encoding_error; 225219019Sgabor } 226219019Sgabor 227219019Sgabor c = ei->count[cs = _citrus_EUC_cs(psenc->ch[0] & 0xff)]; 228219019Sgabor if (c == 0) 229219019Sgabor goto encoding_error; 230219019Sgabor while (psenc->chlen < c) { 231219019Sgabor if (n < 1) 232219019Sgabor goto restart; 233219019Sgabor psenc->ch[psenc->chlen] = *s0++; 234219019Sgabor psenc->chlen++; 235219019Sgabor n--; 236219019Sgabor } 237219019Sgabor *s = s0; 238219019Sgabor 239219019Sgabor switch (cs) { 240219019Sgabor case 3: 241219019Sgabor case 2: 242219019Sgabor /* skip SS2/SS3 */ 243219019Sgabor len = c - 1; 244219019Sgabor s1 = &psenc->ch[1]; 245219019Sgabor break; 246219019Sgabor case 1: 247219019Sgabor case 0: 248219019Sgabor len = c; 249219019Sgabor s1 = &psenc->ch[0]; 250219019Sgabor break; 251219019Sgabor default: 252219019Sgabor goto encoding_error; 253219019Sgabor } 254219019Sgabor wchar = 0; 255219019Sgabor while (len-- > 0) 256219019Sgabor wchar = (wchar << 8) | (*s1++ & 0xff); 257219019Sgabor wchar = (wchar & ~ei->mask) | ei->bits[cs]; 258219019Sgabor 259219019Sgabor psenc->chlen = 0; 260219019Sgabor if (pwc) 261219019Sgabor *pwc = wchar; 262219019Sgabor *nresult = wchar ? (size_t)(c - chlenbak) : 0; 263219019Sgabor return (0); 264219019Sgabor 265219019Sgaborencoding_error: 266219019Sgabor psenc->chlen = 0; 267219019Sgabor *nresult = (size_t)-1; 268219019Sgabor return (EILSEQ); 269219019Sgabor 270219019Sgaborrestart: 271219019Sgabor *nresult = (size_t)-2; 272219019Sgabor *s = s0; 273219019Sgabor return (0); 274219019Sgabor} 275219019Sgabor 276219019Sgaborstatic int 277219019Sgabor_citrus_EUC_wcrtomb_priv(_EUCEncodingInfo *ei, char *s, size_t n, wchar_t wc, 278219019Sgabor _EUCState *psenc __unused, size_t *nresult) 279219019Sgabor{ 280219019Sgabor wchar_t m, nm; 281219019Sgabor unsigned int cs; 282219019Sgabor int ret; 283219019Sgabor short i; 284219019Sgabor 285219019Sgabor m = wc & ei->mask; 286219019Sgabor nm = wc & ~m; 287219019Sgabor 288219019Sgabor for (cs = 0; cs < sizeof(ei->count) / sizeof(ei->count[0]); cs++) 289219019Sgabor if (m == ei->bits[cs]) 290219019Sgabor break; 291219019Sgabor /* fallback case - not sure if it is necessary */ 292219019Sgabor if (cs == sizeof(ei->count) / sizeof(ei->count[0])) 293219019Sgabor cs = 1; 294219019Sgabor 295219019Sgabor i = ei->count[cs]; 296219019Sgabor if (n < (unsigned)i) { 297219019Sgabor ret = E2BIG; 298219019Sgabor goto err; 299219019Sgabor } 300219019Sgabor m = (cs) ? 0x80 : 0x00; 301219019Sgabor switch (cs) { 302219019Sgabor case 2: 303219019Sgabor *s++ = _SS2; 304219019Sgabor i--; 305219019Sgabor break; 306219019Sgabor case 3: 307219019Sgabor *s++ = _SS3; 308219019Sgabor i--; 309219019Sgabor break; 310219019Sgabor } 311219019Sgabor 312219019Sgabor while (i-- > 0) 313219019Sgabor *s++ = ((nm >> (i << 3)) & 0xff) | m; 314219019Sgabor 315219019Sgabor *nresult = (size_t)ei->count[cs]; 316219019Sgabor return (0); 317219019Sgabor 318219019Sgaborerr: 319219019Sgabor *nresult = (size_t)-1; 320219019Sgabor return (ret); 321219019Sgabor} 322219019Sgabor 323219019Sgaborstatic __inline int 324219019Sgabor/*ARGSUSED*/ 325219019Sgabor_citrus_EUC_stdenc_wctocs(_EUCEncodingInfo * __restrict ei, 326219019Sgabor _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc) 327219019Sgabor{ 328219019Sgabor wchar_t m, nm; 329219019Sgabor 330219019Sgabor m = wc & ei->mask; 331219019Sgabor nm = wc & ~m; 332219019Sgabor 333219019Sgabor *csid = (_citrus_csid_t)m; 334219019Sgabor *idx = (_citrus_index_t)nm; 335219019Sgabor 336219019Sgabor return (0); 337219019Sgabor} 338219019Sgabor 339219019Sgaborstatic __inline int 340219019Sgabor/*ARGSUSED*/ 341219019Sgabor_citrus_EUC_stdenc_cstowc(_EUCEncodingInfo * __restrict ei, 342219019Sgabor wchar_t * __restrict wc, _csid_t csid, _index_t idx) 343219019Sgabor{ 344219019Sgabor 345219019Sgabor if ((csid & ~ei->mask) != 0 || (idx & ei->mask) != 0) 346219019Sgabor return (EINVAL); 347219019Sgabor 348219019Sgabor *wc = (wchar_t)csid | (wchar_t)idx; 349219019Sgabor 350219019Sgabor return (0); 351219019Sgabor} 352219019Sgabor 353219019Sgaborstatic __inline int 354219019Sgabor/*ARGSUSED*/ 355219019Sgabor_citrus_EUC_stdenc_get_state_desc_generic(_EUCEncodingInfo * __restrict ei __unused, 356219019Sgabor _EUCState * __restrict psenc, int * __restrict rstate) 357219019Sgabor{ 358219019Sgabor 359219019Sgabor *rstate = (psenc->chlen == 0) ? _STDENC_SDGEN_INITIAL : 360219019Sgabor _STDENC_SDGEN_INCOMPLETE_CHAR; 361219019Sgabor return (0); 362219019Sgabor} 363219019Sgabor 364219019Sgaborstatic int 365219019Sgabor/*ARGSUSED*/ 366219019Sgabor_citrus_EUC_encoding_module_init(_EUCEncodingInfo * __restrict ei, 367219019Sgabor const void * __restrict var, size_t lenvar) 368219019Sgabor{ 369219019Sgabor 370219019Sgabor return (_citrus_EUC_parse_variable(ei, var, lenvar)); 371219019Sgabor} 372219019Sgabor 373219019Sgaborstatic void 374219019Sgabor/*ARGSUSED*/ 375219019Sgabor_citrus_EUC_encoding_module_uninit(_EUCEncodingInfo * __restrict ei __unused) 376219019Sgabor{ 377219019Sgabor 378219019Sgabor} 379219019Sgabor 380219019Sgabor/* ---------------------------------------------------------------------- 381219019Sgabor * public interface for stdenc 382219019Sgabor */ 383219019Sgabor 384219019Sgabor_CITRUS_STDENC_DECLS(EUC); 385219019Sgabor_CITRUS_STDENC_DEF_OPS(EUC); 386219019Sgabor 387219019Sgabor#include "citrus_stdenc_template.h" 388