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