5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is furnished to do
10 * so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 static unsigned char utf8_lengths[256] = {
26 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ascii characters */
27 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
28 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
29 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
30 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
31 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
32 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
33 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
34 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0xBF are within multibyte sequences */
35 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* they could be interpreted as 2-byte starts but */
36 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* the codepoint would be < 127 */
37 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */
38 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* C0 and C1 would also result in overlong encodings */
39 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* */
40 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
41 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
42 /* with F5 the codepoint is above 0x10FFFF,
43 * F8-FB would start 5-byte sequences
44 * FC-FD would start 6-byte sequences
49 static uchar_t utf8_range[5] = {
50 1, /* invalid - let's not allow the creation of 0-bytes :P */
51 1, /* ascii minimum */
52 0x80, /* 2-byte minimum */
53 0x800, /* 3-byte minimum */
54 0x10000, /* 4-byte minimum */
57 /** Analyze the next character and return various information if requested.
58 * @param _s An utf-8 string.
59 * @param _start Filled with the start byte-offset of the next valid character
60 * @param _len Filled with the length of the next valid character
61 * @param _ch Filled with the unicode value of the next character
62 * @param _maxlen Maximum number of bytes to read from _s
63 * @return Whether or not another valid character is in the string
65 bool u8_analyze(const char *_s, size_t *_start, size_t *_len, uchar_t *_ch, size_t _maxlen)
67 const unsigned char *s = (const unsigned char*)_s;
74 while (i < _maxlen && s[i] && (bits = utf8_lengths[s[i]]) == 0)
77 if (i >= _maxlen || !s[i]) {
78 if (_start) *_start = i;
83 if (bits == 1) { /* ascii */
84 if (_start) *_start = i;
86 if (_ch) *_ch = (uchar_t)s[i];
90 ch = (s[i] & (0xFF >> bits));
91 for (j = 1; j < bits; ++j)
93 if ( (s[i+j] & 0xC0) != 0x80 )
96 /* in gmqcc, invalid / overlong encodings are considered an error
102 ch = (ch << 6) | (s[i+j] & 0x3F);
104 if (ch < utf8_range[bits] || ch >= 0x10FFFF)
123 /* might come in handy */
124 size_t u8_strlen(const char *_s)
128 const unsigned char *s = (const unsigned char*)_s;
132 /* ascii char, skip u8_analyze */
140 /* invalid, skip u8_analyze */
147 if (!u8_analyze((const char*)s, &st, &ln, NULL, 0x10))
149 /* valid character, skip after it */
156 size_t u8_strnlen(const char *_s, size_t n)
160 const unsigned char *s = (const unsigned char*)_s;
164 /* ascii char, skip u8_analyze */
173 /* invalid, skip u8_analyze */
181 if (!u8_analyze((const char*)s, &st, &ln, NULL, n))
183 /* valid character, see if it's still inside the range specified by n: */
193 /* Required for character constants */
194 uchar_t u8_getchar(const char *_s, const char **_end)
199 if (!u8_analyze(_s, &st, &ln, &ch, 0x10))
202 *_end = _s + st + ln;
206 uchar_t u8_getnchar(const char *_s, const char **_end, size_t _maxlen)
211 if (!u8_analyze(_s, &st, &ln, &ch, _maxlen))
214 *_end = _s + st + ln;
218 /* required for \x{asdf}-like string escape sequences */
219 int u8_fromchar(uchar_t w, char *to, size_t maxlen)
227 /* We may want an -f flag for this behaviour...
240 /* for a little speedup */
249 to[1] = 0x80 | (w & 0x3F); w >>= 6;
261 to[2] = 0x80 | (w & 0x3F); w >>= 6;
262 to[1] = 0x80 | (w & 0x3F); w >>= 6;
276 to[3] = 0x80 | (w & 0x3F); w >>= 6;
277 to[2] = 0x80 | (w & 0x3F); w >>= 6;
278 to[1] = 0x80 | (w & 0x3F); w >>= 6;