1122145Sdavidxu/*- 2128004Stjr * Copyright (c) 2004 Tim J. Robbins. All rights reserved. 3122145Sdavidxu * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 4122145Sdavidxu * All rights reserved. 5122145Sdavidxu * 6235785Stheraven * Copyright (c) 2011 The FreeBSD Foundation 7235785Stheraven * All rights reserved. 8235785Stheraven * Portions of this software were developed by David Chisnall 9235785Stheraven * under sponsorship from the FreeBSD Foundation. 10235785Stheraven * 11122145Sdavidxu * Redistribution and use in source and binary forms, with or without 12122145Sdavidxu * modification, are permitted provided that the following conditions 13122145Sdavidxu * are met: 14122145Sdavidxu * 1. Redistributions of source code must retain the above copyright 15122145Sdavidxu * notice, this list of conditions and the following disclaimer. 16122145Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright 17122145Sdavidxu * notice, this list of conditions and the following disclaimer in the 18122145Sdavidxu * documentation and/or other materials provided with the distribution. 19122145Sdavidxu * 20122145Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21122145Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22122145Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23122145Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24122145Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25122145Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26122145Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27122145Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28122145Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29122145Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30122145Sdavidxu * SUCH DAMAGE. 31122145Sdavidxu */ 32122145Sdavidxu 33128004Stjr#include <sys/param.h> 34122145Sdavidxu__FBSDID("$FreeBSD$"); 35122145Sdavidxu 36128155Stjr#include <errno.h> 37122145Sdavidxu#include <runetype.h> 38122145Sdavidxu#include <stdlib.h> 39128004Stjr#include <string.h> 40122145Sdavidxu#include <wchar.h> 41129153Stjr#include "mblocal.h" 42122145Sdavidxu 43142654Sphantomstatic size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict, 44142654Sphantom size_t, mbstate_t * __restrict); 45142654Sphantomstatic int _GB2312_mbsinit(const mbstate_t *); 46142654Sphantomstatic size_t _GB2312_wcrtomb(char * __restrict, wchar_t, 47142654Sphantom mbstate_t * __restrict); 48122145Sdavidxu 49128004Stjrtypedef struct { 50128004Stjr int count; 51128004Stjr u_char bytes[2]; 52128004Stjr} _GB2312State; 53128004Stjr 54122145Sdavidxuint 55235785Stheraven_GB2312_init(struct xlocale_ctype *l, _RuneLocale *rl) 56122145Sdavidxu{ 57122145Sdavidxu 58235785Stheraven l->runes = rl; 59235785Stheraven l->__mbrtowc = _GB2312_mbrtowc; 60235785Stheraven l->__wcrtomb = _GB2312_wcrtomb; 61235785Stheraven l->__mbsinit = _GB2312_mbsinit; 62235785Stheraven l->__mb_cur_max = 2; 63235785Stheraven l->__mb_sb_limit = 128; 64122145Sdavidxu return (0); 65122145Sdavidxu} 66122145Sdavidxu 67142654Sphantomstatic int 68128004Stjr_GB2312_mbsinit(const mbstate_t *ps) 69128004Stjr{ 70128004Stjr 71128081Stjr return (ps == NULL || ((const _GB2312State *)ps)->count == 0); 72128004Stjr} 73128004Stjr 74122282Stjrstatic __inline int 75122145Sdavidxu_GB2312_check(const char *str, size_t n) 76122145Sdavidxu{ 77122145Sdavidxu const u_char *s = (const u_char *)str; 78122145Sdavidxu 79122145Sdavidxu if (n == 0) 80122145Sdavidxu /* Incomplete multibyte sequence */ 81122145Sdavidxu return (-2); 82122145Sdavidxu if (s[0] >= 0xa1 && s[0] <= 0xfe) { 83122145Sdavidxu if (n < 2) 84122145Sdavidxu /* Incomplete multibyte sequence */ 85122145Sdavidxu return (-2); 86122145Sdavidxu if (s[1] < 0xa1 || s[1] > 0xfe) 87122145Sdavidxu /* Invalid multibyte sequence */ 88122145Sdavidxu return (-1); 89122145Sdavidxu return (2); 90122145Sdavidxu } else if (s[0] & 0x80) { 91122145Sdavidxu /* Invalid multibyte sequence */ 92122145Sdavidxu return (-1); 93122145Sdavidxu } 94122145Sdavidxu return (1); 95122145Sdavidxu} 96122145Sdavidxu 97142654Sphantomstatic size_t 98122145Sdavidxu_GB2312_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, 99128004Stjr mbstate_t * __restrict ps) 100122145Sdavidxu{ 101128004Stjr _GB2312State *gs; 102122145Sdavidxu wchar_t wc; 103128004Stjr int i, len, ocount; 104128004Stjr size_t ncopy; 105122145Sdavidxu 106128089Sdavidxu gs = (_GB2312State *)ps; 107128004Stjr 108128155Stjr if (gs->count < 0 || gs->count > sizeof(gs->bytes)) { 109128155Stjr errno = EINVAL; 110128155Stjr return ((size_t)-1); 111128155Stjr } 112128155Stjr 113128004Stjr if (s == NULL) { 114128004Stjr s = ""; 115128004Stjr n = 1; 116128004Stjr pwc = NULL; 117128004Stjr } 118128004Stjr 119128004Stjr ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(gs->bytes) - gs->count); 120128004Stjr memcpy(gs->bytes + gs->count, s, ncopy); 121128004Stjr ocount = gs->count; 122128004Stjr gs->count += ncopy; 123128004Stjr s = (char *)gs->bytes; 124128004Stjr n = gs->count; 125128004Stjr 126122145Sdavidxu if ((len = _GB2312_check(s, n)) < 0) 127122145Sdavidxu return ((size_t)len); 128122145Sdavidxu wc = 0; 129122145Sdavidxu i = len; 130122145Sdavidxu while (i-- > 0) 131122145Sdavidxu wc = (wc << 8) | (unsigned char)*s++; 132122145Sdavidxu if (pwc != NULL) 133122145Sdavidxu *pwc = wc; 134128004Stjr gs->count = 0; 135128004Stjr return (wc == L'\0' ? 0 : len - ocount); 136122145Sdavidxu} 137122145Sdavidxu 138142654Sphantomstatic size_t 139128155Stjr_GB2312_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) 140122145Sdavidxu{ 141128155Stjr _GB2312State *gs; 142122145Sdavidxu 143128155Stjr gs = (_GB2312State *)ps; 144128155Stjr 145128155Stjr if (gs->count != 0) { 146128155Stjr errno = EINVAL; 147128155Stjr return ((size_t)-1); 148128155Stjr } 149128155Stjr 150122145Sdavidxu if (s == NULL) 151122145Sdavidxu /* Reset to initial shift state (no-op) */ 152122145Sdavidxu return (1); 153122145Sdavidxu if (wc & 0x8000) { 154122145Sdavidxu *s++ = (wc >> 8) & 0xff; 155122145Sdavidxu *s = wc & 0xff; 156122145Sdavidxu return (2); 157122145Sdavidxu } 158122145Sdavidxu *s = wc & 0xff; 159122145Sdavidxu return (1); 160122145Sdavidxu} 161