gb2312.c revision 142654
1696Spaul/*- 214260Spst * Copyright (c) 2004 Tim J. Robbins. All rights reserved. 3696Spaul * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 4696Spaul * All rights reserved. 5696Spaul * 6696Spaul * Redistribution and use in source and binary forms, with or without 7696Spaul * modification, are permitted provided that the following conditions 8696Spaul * are met: 9696Spaul * 1. Redistributions of source code must retain the above copyright 10696Spaul * notice, this list of conditions and the following disclaimer. 11696Spaul * 2. Redistributions in binary form must reproduce the above copyright 12696Spaul * notice, this list of conditions and the following disclaimer in the 13696Spaul * documentation and/or other materials provided with the distribution. 14696Spaul * 15696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16696Spaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 171153Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18696Spaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19696Spaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20696Spaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21696Spaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22696Spaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23696Spaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24696Spaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25696Spaul * SUCH DAMAGE. 26696Spaul */ 27696Spaul 28696Spaul#include <sys/param.h> 29696Spaul__FBSDID("$FreeBSD: head/lib/libc/locale/gb2312.c 142654 2005-02-27 15:11:09Z phantom $"); 3018597Speter 31696Spaul#include <errno.h> 32696Spaul#include <runetype.h> 33696Spaul#include <stdlib.h> 34696Spaul#include <string.h> 35696Spaul#include <wchar.h> 36696Spaul#include "mblocal.h" 37696Spaul 38696Spaulstatic size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict, 39696Spaul size_t, mbstate_t * __restrict); 401741Srichstatic int _GB2312_mbsinit(const mbstate_t *); 411741Srichstatic size_t _GB2312_wcrtomb(char * __restrict, wchar_t, 4217142Sjkh mbstate_t * __restrict); 4317142Sjkh 44696Spaultypedef struct { 45696Spaul int count; 46696Spaul u_char bytes[2]; 47696Spaul} _GB2312State; 48696Spaul 491741Srichint 501741Srich_GB2312_init(_RuneLocale *rl) 51696Spaul{ 521741Srich 53696Spaul _CurrentRuneLocale = rl; 5418597Speter __mbrtowc = _GB2312_mbrtowc; 55696Spaul __wcrtomb = _GB2312_wcrtomb; 5618597Speter __mbsinit = _GB2312_mbsinit; 5718597Speter __mb_cur_max = 2; 5818597Speter return (0); 5918597Speter} 6018597Speter 61696Spaulstatic int 62696Spaul_GB2312_mbsinit(const mbstate_t *ps) 63696Spaul{ 645205Snate 655205Snate return (ps == NULL || ((const _GB2312State *)ps)->count == 0); 66696Spaul} 67696Spaul 68696Spaulstatic __inline int 699290Sasami_GB2312_check(const char *str, size_t n) 70696Spaul{ 71696Spaul const u_char *s = (const u_char *)str; 72696Spaul 73696Spaul if (n == 0) 74696Spaul /* Incomplete multibyte sequence */ 75696Spaul return (-2); 76696Spaul if (s[0] >= 0xa1 && s[0] <= 0xfe) { 77696Spaul if (n < 2) 78696Spaul /* Incomplete multibyte sequence */ 79696Spaul return (-2); 80696Spaul if (s[1] < 0xa1 || s[1] > 0xfe) 81696Spaul /* Invalid multibyte sequence */ 82696Spaul return (-1); 8318597Speter return (2); 84696Spaul } else if (s[0] & 0x80) { 85696Spaul /* Invalid multibyte sequence */ 861153Sjkh return (-1); 879290Sasami } 889290Sasami return (1); 899290Sasami} 90696Spaul 91696Spaulstatic size_t 92696Spaul_GB2312_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, 93696Spaul mbstate_t * __restrict ps) 94696Spaul{ 95696Spaul _GB2312State *gs; 96696Spaul wchar_t wc; 97696Spaul int i, len, ocount; 98696Spaul size_t ncopy; 999290Sasami 100696Spaul gs = (_GB2312State *)ps; 1019290Sasami 1029290Sasami if (gs->count < 0 || gs->count > sizeof(gs->bytes)) { 103696Spaul errno = EINVAL; 1049290Sasami return ((size_t)-1); 1059290Sasami } 1069290Sasami 107696Spaul if (s == NULL) { 108696Spaul s = ""; 109696Spaul n = 1; 1109290Sasami pwc = NULL; 1119290Sasami } 112696Spaul 113696Spaul ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(gs->bytes) - gs->count); 11418597Speter memcpy(gs->bytes + gs->count, s, ncopy); 1155205Snate ocount = gs->count; 116696Spaul gs->count += ncopy; 117696Spaul s = (char *)gs->bytes; 118696Spaul n = gs->count; 119696Spaul 12018597Speter if ((len = _GB2312_check(s, n)) < 0) 12118597Speter return ((size_t)len); 1229290Sasami wc = 0; 1239290Sasami i = len; 1249290Sasami while (i-- > 0) 1259290Sasami wc = (wc << 8) | (unsigned char)*s++; 126696Spaul if (pwc != NULL) 12718597Speter *pwc = wc; 1281741Srich gs->count = 0; 129696Spaul return (wc == L'\0' ? 0 : len - ocount); 13018597Speter} 13118597Speter 13218597Speterstatic size_t 13318597Speter_GB2312_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) 13418597Speter{ 13518597Speter _GB2312State *gs; 13618597Speter 13718597Speter gs = (_GB2312State *)ps; 13818597Speter 13918597Speter if (gs->count != 0) { 14018597Speter errno = EINVAL; 14118597Speter return ((size_t)-1); 14218597Speter } 14318597Speter 144696Spaul if (s == NULL) 1451153Sjkh /* Reset to initial shift state (no-op) */ 146696Spaul return (1); 1479290Sasami if (wc & 0x8000) { 148696Spaul *s++ = (wc >> 8) & 0xff; 149696Spaul *s = wc & 0xff; 150696Spaul return (2); 151696Spaul } 152696Spaul *s = wc & 0xff; 1531153Sjkh return (1); 154696Spaul} 1551153Sjkh