Deleted Added
full compact
utf8.c (128081) utf8.c (128155)
1/*-
2 * Copyright (c) 2002-2004 Tim J. Robbins
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
1/*-
2 * Copyright (c) 2002-2004 Tim J. Robbins
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
28__FBSDID("$FreeBSD: head/lib/libc/locale/utf8.c 128081 2004-04-10 00:27:52Z tjr $");
28__FBSDID("$FreeBSD: head/lib/libc/locale/utf8.c 128155 2004-04-12 13:09:18Z tjr $");
29
30#include <errno.h>
31#include <runetype.h>
32#include <stdlib.h>
33#include <string.h>
34#include <wchar.h>
35
36extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
37 size_t, mbstate_t * __restrict);
38extern int (*__mbsinit)(const mbstate_t *);
39extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
40
41size_t _UTF8_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t,
42 mbstate_t * __restrict);
43int _UTF8_mbsinit(const mbstate_t *);
44size_t _UTF8_wcrtomb(char * __restrict, wchar_t, mbstate_t * __restrict);
45
46typedef struct {
47 int count;
48 u_char bytes[6];
49} _UTF8State;
50
51int
52_UTF8_init(_RuneLocale *rl)
53{
54
55 __mbrtowc = _UTF8_mbrtowc;
56 __wcrtomb = _UTF8_wcrtomb;
57 __mbsinit = _UTF8_mbsinit;
58 _CurrentRuneLocale = rl;
59 __mb_cur_max = 6;
60
61 return (0);
62}
63
64int
65_UTF8_mbsinit(const mbstate_t *ps)
66{
67
68 return (ps == NULL || ((const _UTF8State *)ps)->count == 0);
69}
70
71size_t
72_UTF8_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
73 mbstate_t * __restrict ps)
74{
75 _UTF8State *us;
76 int ch, i, len, mask, ocount;
77 wchar_t lbound, wch;
78 size_t ncopy;
79
80 us = (_UTF8State *)ps;
81
29
30#include <errno.h>
31#include <runetype.h>
32#include <stdlib.h>
33#include <string.h>
34#include <wchar.h>
35
36extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
37 size_t, mbstate_t * __restrict);
38extern int (*__mbsinit)(const mbstate_t *);
39extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
40
41size_t _UTF8_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t,
42 mbstate_t * __restrict);
43int _UTF8_mbsinit(const mbstate_t *);
44size_t _UTF8_wcrtomb(char * __restrict, wchar_t, mbstate_t * __restrict);
45
46typedef struct {
47 int count;
48 u_char bytes[6];
49} _UTF8State;
50
51int
52_UTF8_init(_RuneLocale *rl)
53{
54
55 __mbrtowc = _UTF8_mbrtowc;
56 __wcrtomb = _UTF8_wcrtomb;
57 __mbsinit = _UTF8_mbsinit;
58 _CurrentRuneLocale = rl;
59 __mb_cur_max = 6;
60
61 return (0);
62}
63
64int
65_UTF8_mbsinit(const mbstate_t *ps)
66{
67
68 return (ps == NULL || ((const _UTF8State *)ps)->count == 0);
69}
70
71size_t
72_UTF8_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
73 mbstate_t * __restrict ps)
74{
75 _UTF8State *us;
76 int ch, i, len, mask, ocount;
77 wchar_t lbound, wch;
78 size_t ncopy;
79
80 us = (_UTF8State *)ps;
81
82 if (us->count < 0 || us->count > sizeof(us->bytes)) {
83 errno = EINVAL;
84 return ((size_t)-1);
85 }
86
82 if (s == NULL) {
83 s = "";
84 n = 1;
85 pwc = NULL;
86 }
87
88 ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(us->bytes) - us->count);
89 memcpy(us->bytes + us->count, s, ncopy);
90 ocount = us->count;
91 us->count += ncopy;
92 s = (char *)us->bytes;
93 n = us->count;
94
95 if (n == 0)
96 /* Incomplete multibyte sequence */
97 return ((size_t)-2);
98
99 /*
100 * Determine the number of octets that make up this character from
101 * the first octet, and a mask that extracts the interesting bits of
102 * the first octet.
103 *
104 * We also specify a lower bound for the character code to detect
105 * redundant, non-"shortest form" encodings. For example, the
106 * sequence C0 80 is _not_ a legal representation of the null
107 * character. This enforces a 1-to-1 mapping between character
108 * codes and their multibyte representations.
109 */
110 ch = (unsigned char)*s;
111 if ((ch & 0x80) == 0) {
112 mask = 0x7f;
113 len = 1;
114 lbound = 0;
115 } else if ((ch & 0xe0) == 0xc0) {
116 mask = 0x1f;
117 len = 2;
118 lbound = 0x80;
119 } else if ((ch & 0xf0) == 0xe0) {
120 mask = 0x0f;
121 len = 3;
122 lbound = 0x800;
123 } else if ((ch & 0xf8) == 0xf0) {
124 mask = 0x07;
125 len = 4;
126 lbound = 0x10000;
127 } else if ((ch & 0xfc) == 0xf8) {
128 mask = 0x03;
129 len = 5;
130 lbound = 0x200000;
131 } else if ((ch & 0xfc) == 0xfc) {
132 mask = 0x01;
133 len = 6;
134 lbound = 0x4000000;
135 } else {
136 /*
137 * Malformed input; input is not UTF-8.
138 */
139 errno = EILSEQ;
140 return ((size_t)-1);
141 }
142
143 if (n < (size_t)len)
144 /* Incomplete multibyte sequence */
145 return ((size_t)-2);
146
147 /*
148 * Decode the octet sequence representing the character in chunks
149 * of 6 bits, most significant first.
150 */
151 wch = (unsigned char)*s++ & mask;
152 i = len;
153 while (--i != 0) {
154 if ((*s & 0xc0) != 0x80) {
155 /*
156 * Malformed input; bad characters in the middle
157 * of a character.
158 */
159 errno = EILSEQ;
160 return ((size_t)-1);
161 }
162 wch <<= 6;
163 wch |= *s++ & 0x3f;
164 }
165 if (wch < lbound) {
166 /*
167 * Malformed input; redundant encoding.
168 */
169 errno = EILSEQ;
170 return ((size_t)-1);
171 }
172 if (pwc != NULL)
173 *pwc = wch;
174 us->count = 0;
175 return (wch == L'\0' ? 0 : len - ocount);
176}
177
178size_t
87 if (s == NULL) {
88 s = "";
89 n = 1;
90 pwc = NULL;
91 }
92
93 ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(us->bytes) - us->count);
94 memcpy(us->bytes + us->count, s, ncopy);
95 ocount = us->count;
96 us->count += ncopy;
97 s = (char *)us->bytes;
98 n = us->count;
99
100 if (n == 0)
101 /* Incomplete multibyte sequence */
102 return ((size_t)-2);
103
104 /*
105 * Determine the number of octets that make up this character from
106 * the first octet, and a mask that extracts the interesting bits of
107 * the first octet.
108 *
109 * We also specify a lower bound for the character code to detect
110 * redundant, non-"shortest form" encodings. For example, the
111 * sequence C0 80 is _not_ a legal representation of the null
112 * character. This enforces a 1-to-1 mapping between character
113 * codes and their multibyte representations.
114 */
115 ch = (unsigned char)*s;
116 if ((ch & 0x80) == 0) {
117 mask = 0x7f;
118 len = 1;
119 lbound = 0;
120 } else if ((ch & 0xe0) == 0xc0) {
121 mask = 0x1f;
122 len = 2;
123 lbound = 0x80;
124 } else if ((ch & 0xf0) == 0xe0) {
125 mask = 0x0f;
126 len = 3;
127 lbound = 0x800;
128 } else if ((ch & 0xf8) == 0xf0) {
129 mask = 0x07;
130 len = 4;
131 lbound = 0x10000;
132 } else if ((ch & 0xfc) == 0xf8) {
133 mask = 0x03;
134 len = 5;
135 lbound = 0x200000;
136 } else if ((ch & 0xfc) == 0xfc) {
137 mask = 0x01;
138 len = 6;
139 lbound = 0x4000000;
140 } else {
141 /*
142 * Malformed input; input is not UTF-8.
143 */
144 errno = EILSEQ;
145 return ((size_t)-1);
146 }
147
148 if (n < (size_t)len)
149 /* Incomplete multibyte sequence */
150 return ((size_t)-2);
151
152 /*
153 * Decode the octet sequence representing the character in chunks
154 * of 6 bits, most significant first.
155 */
156 wch = (unsigned char)*s++ & mask;
157 i = len;
158 while (--i != 0) {
159 if ((*s & 0xc0) != 0x80) {
160 /*
161 * Malformed input; bad characters in the middle
162 * of a character.
163 */
164 errno = EILSEQ;
165 return ((size_t)-1);
166 }
167 wch <<= 6;
168 wch |= *s++ & 0x3f;
169 }
170 if (wch < lbound) {
171 /*
172 * Malformed input; redundant encoding.
173 */
174 errno = EILSEQ;
175 return ((size_t)-1);
176 }
177 if (pwc != NULL)
178 *pwc = wch;
179 us->count = 0;
180 return (wch == L'\0' ? 0 : len - ocount);
181}
182
183size_t
179_UTF8_wcrtomb(char * __restrict s, wchar_t wc,
180 mbstate_t * __restrict ps __unused)
184_UTF8_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
181{
185{
186 _UTF8State *us;
182 unsigned char lead;
183 int i, len;
184
187 unsigned char lead;
188 int i, len;
189
190 us = (_UTF8State *)ps;
191
192 if (us->count < 0 || us->count > sizeof(us->bytes)) {
193 errno = EINVAL;
194 return ((size_t)-1);
195 }
196
185 if (s == NULL)
186 /* Reset to initial shift state (no-op) */
187 return (1);
188
189 /*
190 * Determine the number of octets needed to represent this character.
191 * We always output the shortest sequence possible. Also specify the
192 * first few bits of the first octet, which contains the information
193 * about the sequence length.
194 */
195 if ((wc & ~0x7f) == 0) {
196 lead = 0;
197 len = 1;
198 } else if ((wc & ~0x7ff) == 0) {
199 lead = 0xc0;
200 len = 2;
201 } else if ((wc & ~0xffff) == 0) {
202 lead = 0xe0;
203 len = 3;
204 } else if ((wc & ~0x1fffff) == 0) {
205 lead = 0xf0;
206 len = 4;
207 } else if ((wc & ~0x3ffffff) == 0) {
208 lead = 0xf8;
209 len = 5;
210 } else if ((wc & ~0x7fffffff) == 0) {
211 lead = 0xfc;
212 len = 6;
213 } else {
214 errno = EILSEQ;
215 return ((size_t)-1);
216 }
217
218 /*
219 * Output the octets representing the character in chunks
220 * of 6 bits, least significant last. The first octet is
221 * a special case because it contains the sequence length
222 * information.
223 */
224 for (i = len - 1; i > 0; i--) {
225 s[i] = (wc & 0x3f) | 0x80;
226 wc >>= 6;
227 }
228 *s = (wc & 0xff) | lead;
229
230 return (len);
231}
197 if (s == NULL)
198 /* Reset to initial shift state (no-op) */
199 return (1);
200
201 /*
202 * Determine the number of octets needed to represent this character.
203 * We always output the shortest sequence possible. Also specify the
204 * first few bits of the first octet, which contains the information
205 * about the sequence length.
206 */
207 if ((wc & ~0x7f) == 0) {
208 lead = 0;
209 len = 1;
210 } else if ((wc & ~0x7ff) == 0) {
211 lead = 0xc0;
212 len = 2;
213 } else if ((wc & ~0xffff) == 0) {
214 lead = 0xe0;
215 len = 3;
216 } else if ((wc & ~0x1fffff) == 0) {
217 lead = 0xf0;
218 len = 4;
219 } else if ((wc & ~0x3ffffff) == 0) {
220 lead = 0xf8;
221 len = 5;
222 } else if ((wc & ~0x7fffffff) == 0) {
223 lead = 0xfc;
224 len = 6;
225 } else {
226 errno = EILSEQ;
227 return ((size_t)-1);
228 }
229
230 /*
231 * Output the octets representing the character in chunks
232 * of 6 bits, least significant last. The first octet is
233 * a special case because it contains the sequence length
234 * information.
235 */
236 for (i = len - 1; i > 0; i--) {
237 s[i] = (wc & 0x3f) | 0x80;
238 wc >>= 6;
239 }
240 *s = (wc & 0xff) | lead;
241
242 return (len);
243}