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; 60252547Speter const char *src; 61252547Speter char *dst; 62251314Sed size_t srcleft, dstleft, invlen; 63251314Sed int err; 64251314Sed 65251314Sed FIX_LOCALE(locale); 66251314Sed if (ps == NULL) 67251314Sed ps = &locale->cXXrtomb; 68251314Sed cs = (_ConversionState *)ps; 69251314Sed handle = &cs->iconv; 70251314Sed 71251314Sed /* Reinitialize mbstate_t. */ 72251314Sed if (s == NULL || !cs->initialized) { 73251314Sed if (_citrus_iconv_open(&handle, UTF_XX_INTERNAL, 74251314Sed nl_langinfo_l(CODESET, locale)) != 0) { 75251314Sed cs->initialized = false; 76251314Sed errno = EINVAL; 77251314Sed return (-1); 78251314Sed } 79251314Sed handle->cv_shared->ci_discard_ilseq = true; 80251314Sed handle->cv_shared->ci_hooks = NULL; 81251314Sed cs->srcbuf_len = 0; 82251314Sed cs->initialized = true; 83251314Sed if (s == NULL) 84251314Sed return (1); 85251314Sed } 86251314Sed 87251314Sed assert(cs->srcbuf_len < sizeof(cs->srcbuf.widechar) / sizeof(charXX_t)); 88251314Sed cs->srcbuf.widechar[cs->srcbuf_len++] = c; 89251314Sed 90251314Sed /* Perform conversion. */ 91251314Sed src = cs->srcbuf.bytes; 92251314Sed srcleft = cs->srcbuf_len * sizeof(charXX_t); 93251314Sed dst = s; 94251314Sed dstleft = MB_CUR_MAX_L(locale); 95251314Sed err = _citrus_iconv_convert(handle, &src, &srcleft, &dst, &dstleft, 96251314Sed 0, &invlen); 97251314Sed 98251314Sed /* Character is part of a surrogate pair. We need more input. */ 99251314Sed if (err == EINVAL) 100251314Sed return (0); 101251314Sed cs->srcbuf_len = 0; 102251314Sed 103251314Sed /* Illegal sequence. */ 104251314Sed if (dst == s) { 105251314Sed errno = EILSEQ; 106251314Sed return ((size_t)-1); 107251314Sed } 108251314Sed return (dst - s); 109251314Sed} 110251314Sed 111251314Sedsize_t 112251314SedcXXrtomb(char * __restrict s, charXX_t c, mbstate_t * __restrict ps) 113251314Sed{ 114251314Sed 115251314Sed return (cXXrtomb_l(s, c, ps, __get_locale())); 116251314Sed} 117