14297a3b0SGarrett D'Amore /* 22d08521bSGarrett D'Amore * Copyright 2013 Garrett D'Amore <garrett@damore.org> 36b5e5868SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 44297a3b0SGarrett D'Amore * Copyright (c) 2002-2004 Tim J. Robbins 54297a3b0SGarrett D'Amore * All rights reserved. 64297a3b0SGarrett D'Amore * 74297a3b0SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 84297a3b0SGarrett D'Amore * modification, are permitted provided that the following conditions 94297a3b0SGarrett D'Amore * are met: 104297a3b0SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 114297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 124297a3b0SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 134297a3b0SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 144297a3b0SGarrett D'Amore * documentation and/or other materials provided with the distribution. 154297a3b0SGarrett D'Amore * 164297a3b0SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174297a3b0SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184297a3b0SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194297a3b0SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204297a3b0SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214297a3b0SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224297a3b0SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234297a3b0SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244297a3b0SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254297a3b0SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264297a3b0SGarrett D'Amore * SUCH DAMAGE. 274297a3b0SGarrett D'Amore */ 284297a3b0SGarrett D'Amore 294297a3b0SGarrett D'Amore /* 304297a3b0SGarrett D'Amore * PRC National Standard GB 18030-2000 encoding of Chinese text. 314297a3b0SGarrett D'Amore * 324297a3b0SGarrett D'Amore * See gb18030(5) for details. 334297a3b0SGarrett D'Amore */ 344297a3b0SGarrett D'Amore 354297a3b0SGarrett D'Amore #include "lint.h" 364297a3b0SGarrett D'Amore #include <sys/types.h> 374297a3b0SGarrett D'Amore #include <errno.h> 384297a3b0SGarrett D'Amore #include <stdlib.h> 394297a3b0SGarrett D'Amore #include <string.h> 404297a3b0SGarrett D'Amore #include <wchar.h> 414297a3b0SGarrett D'Amore #include "mblocal.h" 422d08521bSGarrett D'Amore #include "lctype.h" 434297a3b0SGarrett D'Amore 444297a3b0SGarrett D'Amore 454297a3b0SGarrett D'Amore static size_t _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD, 464297a3b0SGarrett D'Amore const char *_RESTRICT_KYWD, 47*d8e0a9a1SRobert Mustacchi size_t, mbstate_t *_RESTRICT_KYWD, boolean_t); 484297a3b0SGarrett D'Amore static int _GB18030_mbsinit(const mbstate_t *); 494297a3b0SGarrett D'Amore static size_t _GB18030_wcrtomb(char *_RESTRICT_KYWD, wchar_t, 504297a3b0SGarrett D'Amore mbstate_t *_RESTRICT_KYWD); 512d08521bSGarrett D'Amore static size_t _GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD, 522d08521bSGarrett D'Amore const char **_RESTRICT_KYWD, size_t, size_t, 532d08521bSGarrett D'Amore mbstate_t *_RESTRICT_KYWD); 542d08521bSGarrett D'Amore static size_t _GB18030_wcsnrtombs(char *_RESTRICT_KYWD, 552d08521bSGarrett D'Amore const wchar_t **_RESTRICT_KYWD, size_t, size_t, 562d08521bSGarrett D'Amore mbstate_t *_RESTRICT_KYWD); 572d08521bSGarrett D'Amore 582d08521bSGarrett D'Amore void 592d08521bSGarrett D'Amore _GB18030_init(struct lc_ctype *lct) 604297a3b0SGarrett D'Amore { 614297a3b0SGarrett D'Amore 622d08521bSGarrett D'Amore lct->lc_mbrtowc = _GB18030_mbrtowc; 632d08521bSGarrett D'Amore lct->lc_wcrtomb = _GB18030_wcrtomb; 642d08521bSGarrett D'Amore lct->lc_mbsinit = _GB18030_mbsinit; 652d08521bSGarrett D'Amore lct->lc_mbsnrtowcs = _GB18030_mbsnrtowcs; 662d08521bSGarrett D'Amore lct->lc_wcsnrtombs = _GB18030_wcsnrtombs; 672d08521bSGarrett D'Amore lct->lc_max_mblen = 4; 682d08521bSGarrett D'Amore lct->lc_is_ascii = 0; 694297a3b0SGarrett D'Amore } 704297a3b0SGarrett D'Amore 714297a3b0SGarrett D'Amore static int 724297a3b0SGarrett D'Amore _GB18030_mbsinit(const mbstate_t *ps) 734297a3b0SGarrett D'Amore { 744297a3b0SGarrett D'Amore 754297a3b0SGarrett D'Amore return (ps == NULL || ((const _GB18030State *)ps)->count == 0); 764297a3b0SGarrett D'Amore } 774297a3b0SGarrett D'Amore 784297a3b0SGarrett D'Amore static size_t 794297a3b0SGarrett D'Amore _GB18030_mbrtowc(wchar_t *_RESTRICT_KYWD pwc, const char *_RESTRICT_KYWD s, 80*d8e0a9a1SRobert Mustacchi size_t n, mbstate_t *_RESTRICT_KYWD ps, boolean_t zero) 814297a3b0SGarrett D'Amore { 824297a3b0SGarrett D'Amore _GB18030State *gs; 834297a3b0SGarrett D'Amore wchar_t wch; 844297a3b0SGarrett D'Amore int ch, len, ocount; 854297a3b0SGarrett D'Amore size_t ncopy; 864297a3b0SGarrett D'Amore 874297a3b0SGarrett D'Amore gs = (_GB18030State *)ps; 884297a3b0SGarrett D'Amore 894297a3b0SGarrett D'Amore if (gs->count < 0 || gs->count > sizeof (gs->bytes)) { 904297a3b0SGarrett D'Amore errno = EINVAL; 914297a3b0SGarrett D'Amore return ((size_t)-1); 924297a3b0SGarrett D'Amore } 934297a3b0SGarrett D'Amore 944297a3b0SGarrett D'Amore if (s == NULL) { 954297a3b0SGarrett D'Amore s = ""; 964297a3b0SGarrett D'Amore n = 1; 974297a3b0SGarrett D'Amore pwc = NULL; 984297a3b0SGarrett D'Amore } 994297a3b0SGarrett D'Amore 1004297a3b0SGarrett D'Amore ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof (gs->bytes) - gs->count); 1014297a3b0SGarrett D'Amore (void) memcpy(gs->bytes + gs->count, s, ncopy); 1024297a3b0SGarrett D'Amore ocount = gs->count; 1034297a3b0SGarrett D'Amore gs->count += ncopy; 1044297a3b0SGarrett D'Amore s = (char *)gs->bytes; 1054297a3b0SGarrett D'Amore n = gs->count; 1064297a3b0SGarrett D'Amore 1074297a3b0SGarrett D'Amore if (n == 0) 1084297a3b0SGarrett D'Amore /* Incomplete multibyte sequence */ 1094297a3b0SGarrett D'Amore return ((size_t)-2); 1104297a3b0SGarrett D'Amore 1114297a3b0SGarrett D'Amore /* 1124297a3b0SGarrett D'Amore * Single byte: [00-7f] 1134297a3b0SGarrett D'Amore * Two byte: [81-fe][40-7e,80-fe] 1144297a3b0SGarrett D'Amore * Four byte: [81-fe][30-39][81-fe][30-39] 1154297a3b0SGarrett D'Amore */ 1164297a3b0SGarrett D'Amore ch = (unsigned char)*s++; 1174297a3b0SGarrett D'Amore if (ch <= 0x7f) { 1184297a3b0SGarrett D'Amore len = 1; 1194297a3b0SGarrett D'Amore wch = ch; 1204297a3b0SGarrett D'Amore } else if (ch >= 0x81 && ch <= 0xfe) { 1214297a3b0SGarrett D'Amore wch = ch; 1224297a3b0SGarrett D'Amore if (n < 2) 1234297a3b0SGarrett D'Amore return ((size_t)-2); 1244297a3b0SGarrett D'Amore ch = (unsigned char)*s++; 1254297a3b0SGarrett D'Amore if ((ch >= 0x40 && ch <= 0x7e) || (ch >= 0x80 && ch <= 0xfe)) { 1264297a3b0SGarrett D'Amore wch = (wch << 8) | ch; 1274297a3b0SGarrett D'Amore len = 2; 1284297a3b0SGarrett D'Amore } else if (ch >= 0x30 && ch <= 0x39) { 1294297a3b0SGarrett D'Amore /* 1304297a3b0SGarrett D'Amore * Strip high bit off the wide character we will 1314297a3b0SGarrett D'Amore * eventually output so that it is positive when 1324297a3b0SGarrett D'Amore * cast to wint_t on 32-bit twos-complement machines. 1334297a3b0SGarrett D'Amore */ 1344297a3b0SGarrett D'Amore wch = ((wch & 0x7f) << 8) | ch; 1354297a3b0SGarrett D'Amore if (n < 3) 1364297a3b0SGarrett D'Amore return ((size_t)-2); 1374297a3b0SGarrett D'Amore ch = (unsigned char)*s++; 1384297a3b0SGarrett D'Amore if (ch < 0x81 || ch > 0xfe) 1394297a3b0SGarrett D'Amore goto ilseq; 1404297a3b0SGarrett D'Amore wch = (wch << 8) | ch; 1414297a3b0SGarrett D'Amore if (n < 4) 1424297a3b0SGarrett D'Amore return ((size_t)-2); 1434297a3b0SGarrett D'Amore ch = (unsigned char)*s++; 1444297a3b0SGarrett D'Amore if (ch < 0x30 || ch > 0x39) 1454297a3b0SGarrett D'Amore goto ilseq; 1464297a3b0SGarrett D'Amore wch = (wch << 8) | ch; 1474297a3b0SGarrett D'Amore len = 4; 1484297a3b0SGarrett D'Amore } else 1494297a3b0SGarrett D'Amore goto ilseq; 1504297a3b0SGarrett D'Amore } else 1514297a3b0SGarrett D'Amore goto ilseq; 1524297a3b0SGarrett D'Amore 1534297a3b0SGarrett D'Amore if (pwc != NULL) 1544297a3b0SGarrett D'Amore *pwc = wch; 1554297a3b0SGarrett D'Amore gs->count = 0; 156*d8e0a9a1SRobert Mustacchi if (zero || wch != L'\0') { 157*d8e0a9a1SRobert Mustacchi return (len - ocount); 158*d8e0a9a1SRobert Mustacchi } else { 159*d8e0a9a1SRobert Mustacchi return (0); 160*d8e0a9a1SRobert Mustacchi } 1614297a3b0SGarrett D'Amore ilseq: 1624297a3b0SGarrett D'Amore errno = EILSEQ; 1634297a3b0SGarrett D'Amore return ((size_t)-1); 1644297a3b0SGarrett D'Amore } 1654297a3b0SGarrett D'Amore 1664297a3b0SGarrett D'Amore static size_t 1674297a3b0SGarrett D'Amore _GB18030_wcrtomb(char *_RESTRICT_KYWD s, wchar_t wc, 1684297a3b0SGarrett D'Amore mbstate_t *_RESTRICT_KYWD ps) 1694297a3b0SGarrett D'Amore { 1704297a3b0SGarrett D'Amore _GB18030State *gs; 1714297a3b0SGarrett D'Amore size_t len; 1724297a3b0SGarrett D'Amore int c; 1734297a3b0SGarrett D'Amore 1744297a3b0SGarrett D'Amore gs = (_GB18030State *)ps; 1754297a3b0SGarrett D'Amore 1764297a3b0SGarrett D'Amore if (gs->count != 0) { 1774297a3b0SGarrett D'Amore errno = EINVAL; 1784297a3b0SGarrett D'Amore return ((size_t)-1); 1794297a3b0SGarrett D'Amore } 1804297a3b0SGarrett D'Amore 1814297a3b0SGarrett D'Amore if (s == NULL) 1824297a3b0SGarrett D'Amore /* Reset to initial shift state (no-op) */ 1834297a3b0SGarrett D'Amore return (1); 1844297a3b0SGarrett D'Amore if ((wc & ~0x7fffffff) != 0) 1854297a3b0SGarrett D'Amore goto ilseq; 1864297a3b0SGarrett D'Amore if (wc & 0x7f000000) { 1874297a3b0SGarrett D'Amore /* Replace high bit that mbrtowc() removed. */ 1884297a3b0SGarrett D'Amore wc |= 0x80000000; 1894297a3b0SGarrett D'Amore c = (wc >> 24) & 0xff; 1904297a3b0SGarrett D'Amore if (c < 0x81 || c > 0xfe) 1914297a3b0SGarrett D'Amore goto ilseq; 1924297a3b0SGarrett D'Amore *s++ = c; 1934297a3b0SGarrett D'Amore c = (wc >> 16) & 0xff; 1944297a3b0SGarrett D'Amore if (c < 0x30 || c > 0x39) 1954297a3b0SGarrett D'Amore goto ilseq; 1964297a3b0SGarrett D'Amore *s++ = c; 1974297a3b0SGarrett D'Amore c = (wc >> 8) & 0xff; 1984297a3b0SGarrett D'Amore if (c < 0x81 || c > 0xfe) 1994297a3b0SGarrett D'Amore goto ilseq; 2004297a3b0SGarrett D'Amore *s++ = c; 2014297a3b0SGarrett D'Amore c = wc & 0xff; 2024297a3b0SGarrett D'Amore if (c < 0x30 || c > 0x39) 2034297a3b0SGarrett D'Amore goto ilseq; 2044297a3b0SGarrett D'Amore *s++ = c; 2054297a3b0SGarrett D'Amore len = 4; 2064297a3b0SGarrett D'Amore } else if (wc & 0x00ff0000) 2074297a3b0SGarrett D'Amore goto ilseq; 2084297a3b0SGarrett D'Amore else if (wc & 0x0000ff00) { 2094297a3b0SGarrett D'Amore c = (wc >> 8) & 0xff; 2104297a3b0SGarrett D'Amore if (c < 0x81 || c > 0xfe) 2114297a3b0SGarrett D'Amore goto ilseq; 2124297a3b0SGarrett D'Amore *s++ = c; 2134297a3b0SGarrett D'Amore c = wc & 0xff; 2144297a3b0SGarrett D'Amore if (c < 0x40 || c == 0x7f || c == 0xff) 2154297a3b0SGarrett D'Amore goto ilseq; 2164297a3b0SGarrett D'Amore *s++ = c; 2174297a3b0SGarrett D'Amore len = 2; 2184297a3b0SGarrett D'Amore } else if (wc <= 0x7f) { 2194297a3b0SGarrett D'Amore *s++ = wc; 2204297a3b0SGarrett D'Amore len = 1; 2214297a3b0SGarrett D'Amore } else 2224297a3b0SGarrett D'Amore goto ilseq; 2234297a3b0SGarrett D'Amore 2244297a3b0SGarrett D'Amore return (len); 2254297a3b0SGarrett D'Amore ilseq: 2264297a3b0SGarrett D'Amore errno = EILSEQ; 2274297a3b0SGarrett D'Amore return ((size_t)-1); 2284297a3b0SGarrett D'Amore } 2292d08521bSGarrett D'Amore 2302d08521bSGarrett D'Amore static size_t 2312d08521bSGarrett D'Amore _GB18030_mbsnrtowcs(wchar_t *_RESTRICT_KYWD dst, 2322d08521bSGarrett D'Amore const char **_RESTRICT_KYWD src, size_t nms, size_t len, 2332d08521bSGarrett D'Amore mbstate_t *_RESTRICT_KYWD ps) 2342d08521bSGarrett D'Amore { 2352d08521bSGarrett D'Amore return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GB18030_mbrtowc)); 2362d08521bSGarrett D'Amore } 2372d08521bSGarrett D'Amore 2382d08521bSGarrett D'Amore static size_t 2392d08521bSGarrett D'Amore _GB18030_wcsnrtombs(char *_RESTRICT_KYWD dst, 2402d08521bSGarrett D'Amore const wchar_t **_RESTRICT_KYWD src, size_t nwc, size_t len, 2412d08521bSGarrett D'Amore mbstate_t *_RESTRICT_KYWD ps) 2422d08521bSGarrett D'Amore { 2432d08521bSGarrett D'Amore return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GB18030_wcrtomb)); 2442d08521bSGarrett D'Amore } 245