1251314Sed/*- 2251314Sed * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org> 3251314Sed * All rights reserved. 4251314Sed * 5251314Sed * Redistribution and use in source and binary forms, with or without 6251314Sed * modification, are permitted provided that the following conditions 7251314Sed * are met: 8251314Sed * 1. Redistributions of source code must retain the above copyright 9251314Sed * notice, this list of conditions and the following disclaimer. 10251314Sed * 2. Redistributions in binary form must reproduce the above copyright 11251314Sed * notice, this list of conditions and the following disclaimer in the 12251314Sed * documentation and/or other materials provided with the distribution. 13251314Sed * 14251314Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15251314Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16251314Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17251314Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18251314Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251314Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20251314Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251314Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22251314Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23251314Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24251314Sed * SUCH DAMAGE. 25251314Sed */ 26251314Sed 27251314Sed#include <sys/cdefs.h> 28251314Sed__FBSDID("$FreeBSD$"); 29251314Sed 30251314Sed#include <sys/queue.h> 31251314Sed 32251314Sed#include <assert.h> 33251314Sed#include <errno.h> 34251314Sed#include <langinfo.h> 35251314Sed#include <uchar.h> 36251314Sed 37251314Sed#include "../iconv/citrus_hash.h" 38251314Sed#include "../iconv/citrus_module.h" 39251314Sed#include "../iconv/citrus_iconv.h" 40251314Sed#include "xlocale_private.h" 41251314Sed 42251314Sedtypedef struct { 43251314Sed bool initialized; 44251314Sed struct _citrus_iconv iconv; 45251314Sed union { 46251314Sed charXX_t widechar[SRCBUF_LEN]; 47251314Sed char bytes[sizeof(charXX_t) * SRCBUF_LEN]; 48251314Sed } srcbuf; 49251314Sed size_t srcbuf_len; 50251314Sed} _ConversionState; 51251314Sed_Static_assert(sizeof(_ConversionState) <= sizeof(mbstate_t), 52251314Sed "Size of _ConversionState must not exceed mbstate_t's size."); 53251314Sed 54251314Sedsize_t 55251314SedcXXrtomb_l(char * __restrict s, charXX_t c, mbstate_t * __restrict ps, 56251314Sed locale_t locale) 57251314Sed{ 58251314Sed _ConversionState *cs; 59251314Sed struct _citrus_iconv *handle; 60282275Stijl char *src, *dst; 61251314Sed size_t srcleft, dstleft, invlen; 62251314Sed int err; 63251314Sed 64251314Sed FIX_LOCALE(locale); 65251314Sed if (ps == NULL) 66251314Sed ps = &locale->cXXrtomb; 67251314Sed cs = (_ConversionState *)ps; 68251314Sed handle = &cs->iconv; 69251314Sed 70251314Sed /* Reinitialize mbstate_t. */ 71251314Sed if (s == NULL || !cs->initialized) { 72251314Sed if (_citrus_iconv_open(&handle, UTF_XX_INTERNAL, 73251314Sed nl_langinfo_l(CODESET, locale)) != 0) { 74251314Sed cs->initialized = false; 75251314Sed errno = EINVAL; 76251314Sed return (-1); 77251314Sed } 78251314Sed handle->cv_shared->ci_discard_ilseq = true; 79251314Sed handle->cv_shared->ci_hooks = NULL; 80251314Sed cs->srcbuf_len = 0; 81251314Sed cs->initialized = true; 82251314Sed if (s == NULL) 83251314Sed return (1); 84251314Sed } 85251314Sed 86251314Sed assert(cs->srcbuf_len < sizeof(cs->srcbuf.widechar) / sizeof(charXX_t)); 87251314Sed cs->srcbuf.widechar[cs->srcbuf_len++] = c; 88251314Sed 89251314Sed /* Perform conversion. */ 90251314Sed src = cs->srcbuf.bytes; 91251314Sed srcleft = cs->srcbuf_len * sizeof(charXX_t); 92251314Sed dst = s; 93251314Sed dstleft = MB_CUR_MAX_L(locale); 94251314Sed err = _citrus_iconv_convert(handle, &src, &srcleft, &dst, &dstleft, 95251314Sed 0, &invlen); 96251314Sed 97251314Sed /* Character is part of a surrogate pair. We need more input. */ 98251314Sed if (err == EINVAL) 99251314Sed return (0); 100251314Sed cs->srcbuf_len = 0; 101251314Sed 102251314Sed /* Illegal sequence. */ 103251314Sed if (dst == s) { 104251314Sed errno = EILSEQ; 105251314Sed return ((size_t)-1); 106251314Sed } 107251314Sed return (dst - s); 108251314Sed} 109251314Sed 110251314Sedsize_t 111251314SedcXXrtomb(char * __restrict s, charXX_t c, mbstate_t * __restrict ps) 112251314Sed{ 113251314Sed 114251314Sed return (cXXrtomb_l(s, c, ps, __get_locale())); 115251314Sed} 116