1 /* 2 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 3 * Copyright (c) 2004 Tim J. Robbins. All rights reserved. 4 * Copyright (c) 2003 David Xu <davidxu@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "lint.h" 30 #include <sys/types.h> 31 #include <errno.h> 32 #include "runetype.h" 33 #include <stdlib.h> 34 #include <string.h> 35 #include <wchar.h> 36 #include "mblocal.h" 37 38 static size_t _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD, 39 const char *_RESTRICT_KYWD, 40 size_t, mbstate_t *_RESTRICT_KYWD); 41 static int _GB2312_mbsinit(const mbstate_t *); 42 static size_t _GB2312_wcrtomb(char *_RESTRICT_KYWD, wchar_t, 43 mbstate_t *_RESTRICT_KYWD); 44 45 typedef struct { 46 int count; 47 uchar_t bytes[2]; 48 } _GB2312State; 49 50 int 51 _GB2312_init(_RuneLocale *rl) 52 { 53 54 _CurrentRuneLocale = rl; 55 __mbrtowc = _GB2312_mbrtowc; 56 __wcrtomb = _GB2312_wcrtomb; 57 __mbsinit = _GB2312_mbsinit; 58 __ctype[520] = 2; 59 charset_is_ascii = 0; 60 return (0); 61 } 62 63 static int 64 _GB2312_mbsinit(const mbstate_t *ps) 65 { 66 67 return (ps == NULL || ((const _GB2312State *)ps)->count == 0); 68 } 69 70 static int 71 _GB2312_check(const char *str, size_t n) 72 { 73 const uchar_t *s = (const uchar_t *)str; 74 75 if (n == 0) 76 /* Incomplete multibyte sequence */ 77 return (-2); 78 if (s[0] >= 0xa1 && s[0] <= 0xfe) { 79 if (n < 2) 80 /* Incomplete multibyte sequence */ 81 return (-2); 82 if (s[1] < 0xa1 || s[1] > 0xfe) 83 /* Invalid multibyte sequence */ 84 return (-1); 85 return (2); 86 } else if (s[0] & 0x80) { 87 /* Invalid multibyte sequence */ 88 return (-1); 89 } 90 return (1); 91 } 92 93 static size_t 94 _GB2312_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, 95 size_t n, mbstate_t *_RESTRICT_KYWD ps) 96 { 97 _GB2312State *gs; 98 wchar_t wc; 99 int i, len, ocount; 100 size_t ncopy; 101 102 gs = (_GB2312State *)ps; 103 104 if (gs->count < 0 || gs->count > sizeof (gs->bytes)) { 105 errno = EINVAL; 106 return ((size_t)-1); 107 } 108 109 if (s == NULL) { 110 s = ""; 111 n = 1; 112 pwc = NULL; 113 } 114 115 ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof (gs->bytes) - gs->count); 116 (void) memcpy(gs->bytes + gs->count, s, ncopy); 117 ocount = gs->count; 118 gs->count += ncopy; 119 s = (char *)gs->bytes; 120 n = gs->count; 121 122 if ((len = _GB2312_check(s, n)) < 0) 123 return ((size_t)len); 124 wc = 0; 125 i = len; 126 while (i-- > 0) 127 wc = (wc << 8) | (unsigned char)*s++; 128 if (pwc != NULL) 129 *pwc = wc; 130 gs->count = 0; 131 return (wc == L'\0' ? 0 : len - ocount); 132 } 133 134 static size_t 135 _GB2312_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, 136 mbstate_t *_RESTRICT_KYWD ps) 137 { 138 _GB2312State *gs; 139 140 gs = (_GB2312State *)ps; 141 142 if (gs->count != 0) { 143 errno = EINVAL; 144 return ((size_t)-1); 145 } 146 147 if (s == NULL) 148 /* Reset to initial shift state (no-op) */ 149 return (1); 150 if (wc & 0x8000) { 151 *s++ = (wc >> 8) & 0xff; 152 *s = wc & 0xff; 153 return (2); 154 } 155 *s = wc & 0xff; 156 return (1); 157 }