1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
/* See LICENSE file for copyright and license details. */
#ifndef LIBUTF8_H
#define LIBUTF8_H
#include <stddef.h>
#include <stdint.h>
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Winline"
#endif
/**
* The greatest Unicode codepoint
*
* @seealso libutf8_is_invalid
*/
#define LIBUTF8_ULTIMATE_CODEPOINT UINT32_C(0x10FFFF)
/**
* The Unicode replacement character as a UTF-32 codepoint
*
* @seealso LIBUTF8_REPLACEMENT_CHARACTER_UTF8
*/
#define LIBUTF8_REPLACEMENT_CHARACTER_CODEPOINT 0xFFFDu
/**
* The Unicode replacement character encoded as UTF-8
*
* @seealso LIBUTF8_REPLACEMENT_CHARACTER_CODEPOINT
*/
#define LIBUTF8_REPLACEMENT_CHARACTER_UTF8 "\xEF\xBF\xBD"
/**
* Replace a decoded invalid codepoint with
* `LIBUTF8_REPLACEMENT_CHARACTER_CODEPOINT`
*
* @seealso LIBUTF8_RETURN_INVALID
*/
#define LIBUTF8_REPLACE_INVALID 0x0001u
/**
* Return a decoded invalid codepoint unchanged
*
* @seealso LIBUTF8_REPLACE_INVALID
*/
#define LIBUTF8_RETURN_INVALID 0x0002u
/**
* Accept UTF-8 sequences that decode past
* `LIBUTF8_ULTIMATE_CODEPOINT` to a maximum of 31 bits
*/
#define LIBUTF8_ALLOW_31_BITS 0x0004u
/**
* Accept the two-byte overlong encoding of U+0000
*
* @seealso LIBUTF8_ALLOW_LONG_ENCODING
*/
#define LIBUTF8_ALLOW_2BYTE_NULL 0x0008u
/**
* Accept all overlong UTF-8 encodings
*
* This flag implies LIBUTF8_ALLOW_2BYTE_NULL
*
* @seealso LIBUTF8_ALLOW_2BYTE_NULL
*/
#define LIBUTF8_ALLOW_LONG_ENCODING 0x0010u
/**
* Test whether a codepoint is a non-character Unicode codepoint
*
* @param codepoint The codepoint to test
* @return 1 if `codepoint` is a non-character Unicode codepoint, 0 otherwise
*
* A non-character Unicode codepoint is codepoint
* reserved as invalid and without special meaning
*
* The result is unspecified if `codepoint` is
* greater than LIBUTF8_ULTIMATE_CODEPOINT
*
* @seealso libutf8_is_invalid
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline int
libutf8_is_noncharacter(uint_least32_t codepoint)
{
return (0xFDD0u <= codepoint && codepoint <= 0xFDEFu) || (codepoint & 0xFFFEu) == 0xFFFEu;
}
/**
* Test whether a codepoint is a UTF-16 surrogate
*
* @param codepoint The codepoint to test
* @return 1 if `codepoint` is a UTF-16 surrogate, 0 otherwise
*
* @seealso libutf8_is_invalid
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline int
libutf8_is_surrogate(uint_least32_t codepoint)
{
return 0xD800u <= codepoint && codepoint <= 0xDFFFu;
}
/**
* Test whether a codepoint is invalid Unicode
*
* @param codepoint The codepoint to test
* @return 1 if `codepoint` is outside the Unicode range,
* a surrogate, or a non-character; 0 otherwise
*
* @seealso libutf8_is_valid
* @seealso LIBUTF8_ULTIMATE_CODEPOINT
* @seealso libutf8_is_noncharacter
* @seealso libutf8_is_surrogate
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline int
libutf8_is_invalid(uint_least32_t codepoint)
{
return codepoint > LIBUTF8_ULTIMATE_CODEPOINT ||
libutf8_is_noncharacter(codepoint) ||
libutf8_is_surrogate(codepoint);
}
/**
* Test whether a codepoint is valid Unicode
*
* @param codepoint The codepoint to test
* @return 1 if `codepoint` is within the Unicode range
* and is neither a surrogate nor a non-character,
* 0 otherwise
*
* @seealso libutf8_is_invalid
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline int
libutf8_is_valid(uint_least32_t codepoint)
{
return !libutf8_is_invalid(codepoint);
}
/**
* Test whether a byte is a UTF-8 continuation byte
*
* @param c The byte to test
* @return 1 if `c` is a codepoint continuation byte,
* 0 otherwise
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline int
libutf8_is_continuation(char c)
{
return ((unsigned char)c & 0xC0u) == 0x80u;
}
/**
* Get the number of bytes required to encode a codepoint
*
* @param codepoint The codepoint to measure
* @return The number of bytes required to encode `codepoint`;
* 0 if `codepoint` does not fit in an unsigned 31-bit integer
*
* The maximum return value is 4 for valid Unicode
* codepoints and 6 for any value accept by `libutf8_encode`
*
* This function never sets `errno`, however an
* appropriate `errno`-value is `EDOM` when this
* function returns 0
*
* @seealso libutf8_encode
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__GNUC__)
__attribute__((const, warn_unused_result))
#endif
inline size_t
libutf8_encode_measure(uint_least32_t codepoint)
{
if (codepoint >> 7 == 0u) return 1u;
if (codepoint >> 11 == 0u) return 2u;
if (codepoint >> 16 == 0u) return 3u;
if (codepoint >> 21 == 0u) return 4u;
if (codepoint >> 26 == 0u) return 5u;
if (codepoint >> 31 == 0u) return 6u;
return 0u;
}
/**
* Encode a codepoint as UTF-8
*
* @param out_buffer Output buffer; must have room for the number
* of bytes required to encode `codepoint`
* @param codepoint The codepoint to encode
* @return The number of bytes written
*
* NB! The output is not NUL-terminated
*
* Besides Unicode codepoints, this function encodes 31-bit
* values greater than `LIBUTF8_ULTIMATE_CODEPOINT` using
* historical UTF-8 sequences up to 6 bytes. This lets
* applications embed application-specific data in a file.
*
* This function never sets `errno`, however an
* appropriate `errno`-value is `EDOM` when this
* function returns 0
*
* @seealso libutf8_encode_measure
* @seealso libutf8_is_valid
* @seealso libutf8_decode
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__clang__)
__attribute__((nonnull(1), warn_unused_result))
#elif defined(__GNUC__)
__attribute__((nonnull(1), access(write_only, 1), warn_unused_result))
#endif
size_t libutf8_encode(char *out_buffer, uint_least32_t codepoint);
/**
* Decode the first UTF-8 sequence in a string
*
* @param text The input string; must contain a complete candidate sequence
* @param codepoint_out Unless `NULL`, output for the decoded codepoint
* @param flags Bitwise OR of zero or more or the following flags:
* - LIBUTF8_REPLACE_INVALID:
* Replace invalid codepoints, up to `LIBUTF8_ULTIMATE_CODEPOINT`,
* with the REPLACEMENT CHARACTER.
* NB! This only affects invalid codepoints, not illegal byte sequences.
* - LIBUTF8_RETURN_INVALID:
* Treat invalid codepoints, up to `LIBUTF8_ULTIMATE_CODEPOINT`, as valid
* - LIBUTF8_ALLOW_31_BITS
* Treat 31-bit codepoints greater than
* `LIBUTF8_ULTIMATE_CODEPOINT` as valid.
* - LIBUTF8_ALLOW_2BYTE_NULL
* Accept the overlong 2-byte encoding of U+0000.
* - LIBUTF8_ALLOW_LONG_ENCODING
* Accept overlong encodings, up to 6 bytes.
* @return The number of decoded bytes, 0 if the input is invalid
*
* It is unspecified which flag dominates:
* LIBUTF8_REPLACE_INVALID or LIBUTF8_RETURN_INVALID
*
* This function never sets `errno`, however an
* appropriate `errno`-value is `EILSEQ` when this
* function returns 0
*
* @seealso libutf8_decode_mem
* @seealso libutf8_is_continuation
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__clang__)
__attribute__((nonnull(1), warn_unused_result))
#elif defined(__GNUC__)
__attribute__((nonnull(1), access(write_only, 2), warn_unused_result))
#endif
size_t libutf8_decode(const char *text, uint_least32_t *codepoint_out, unsigned flags);
/**
* Decode the first UTF-8 sequence in a string
*
* @param text The input string; must contain a complete candidate sequence
* @param text_len The number of bytes available in `text`
* @param codepoint_out Unless `NULL`, output for the decoded codepoint
* @param flags Bitwise OR of zero or more or the following flags:
* - LIBUTF8_REPLACE_INVALID:
* Replace invalid codepoints, up to `LIBUTF8_ULTIMATE_CODEPOINT`,
* with the REPLACEMENT CHARACTER.
* NB! This only affects invalid codepoints, not illegal byte sequences.
* - LIBUTF8_RETURN_INVALID:
* Treat invalid codepoints, up to `LIBUTF8_ULTIMATE_CODEPOINT`, as valid
* - LIBUTF8_ALLOW_31_BITS
* Treat 31-bit codepoints greater than
* `LIBUTF8_ULTIMATE_CODEPOINT` as valid.
* - LIBUTF8_ALLOW_2BYTE_NULL
* Accept the overlong 2-byte encoding of U+0000.
* - LIBUTF8_ALLOW_LONG_ENCODING
* Accept overlong encodings, up to 6 bytes.
* @return The number of decoded bytes, 0 if the input is invalid;
* or the required sequence length specified by a valid
* leading byte if `text_len` is less than this value
* (input is truncated)
*
* Note, that a return value greater than `text_len` does not
* necessarily (it is unspecified) indicate that all available
* bytes are invalid, only that the first byte is valid
*
* This function never sets `errno`, however an
* appropriate `errno`-value is `EILSEQ` when this
* function returns 0
*
* @seealso libutf8_decode
* @seealso libutf8_is_continuation
*
* This function is MT-Safe, AS-Safe, and AC-Safe
*/
#if defined(__clang__)
__attribute__((warn_unused_result))
#elif defined(__GNUC__)
__attribute__((access(read_only, 1, 2), access(write_only, 3), warn_unused_result))
#endif
size_t libutf8_decode_mem(const char *text, size_t text_len, uint_least32_t *codepoint_out, unsigned flags);
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
#endif
|