CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
string_private_utf8.h
1#pragma once
2
3_meta_inline _Pure uint32 _strUTF8SeqLen(uint8 u)
4{
5 // single byte encoding aka ASCII
6 if (u < 0x80)
7 return 1;
8
9 if (u >= 0x80 && u <= 0xbf)
10 return 0; // continuation byte, not valid here!
11 else if (u == 0xc0 || u == 0xc1)
12 return 0; // overlong encoding of code point < 0x80
13 else if (u >= 0xc2 && u <= 0xdf)
14 return 2;
15 else if (u >= 0xe0 && u <= 0xef)
16 return 3;
17 else if (u >= 0xf0 && u <= 0xf4)
18 return 4;
19
20 return 0;
21}
22
23_meta_inline bool _strUTF8DecodeSeq(striter* _Nonnull it, uint32 len, uint8 ch,
24 int32* _Nullable codepoint)
25{
26 int32 ret = 0;
27 // the loop below runs len down to 1, so the overlong checks need the original
28 uint32 seqlen = len;
29
30 if (len == 2)
31 ret = ch & 0x1f;
32 else if (len == 3)
33 ret = ch & 0x0f;
34 else if (len == 4)
35 ret = ch & 0x07;
36 else
37 return false;
38
39 for (; len > 1; --len) {
40 if (!striChar(it, (uint8*)&ch))
41 return false;
42
43 if (ch < 0x80 || ch > 0xbf)
44 return false; // continuation byte must follow
45
46 ret = (ret << 6) | (ch & 0x3f);
47 }
48
49 if (ret > 0x10ffff || // outside unicode range
50 (ret >= 0xd800 && ret <= 0xdfff) || // UTF-16 surrogate pairs
51 (seqlen == 2 && ret < 0x80) || // overlong encodings
52 (seqlen == 3 && ret < 0x800) || (seqlen == 4 && ret < 0x10000))
53 return false;
54
55 if (codepoint)
56 *codepoint = ret;
57
58 return true;
59}
60
61_meta_inline uint32 _strUTF8Decode(striter* _Nonnull it, int32* _Nullable codepoint)
62{
63 uint8 first;
64 if (!striChar(it, (uint8*)&first))
65 return 0;
66
67 uint32 len = _strUTF8SeqLen(first);
68
69 if (len == 1) {
70 if (codepoint)
71 *codepoint = first;
72 return 1;
73 }
74
75 if (_strUTF8DecodeSeq(it, len, first, codepoint))
76 return len;
77 return 0;
78}
79
80// Returns 0 for anything that isn't a legal encoding
81_meta_inline uint32 _strUTF8Encode(uint8* _Nonnull buffer, int32 codepoint)
82{
83 if (codepoint < 0 || codepoint > 0x10ffff || (codepoint >= 0xd800 && codepoint <= 0xdfff))
84 return 0;
85
86 if (codepoint < 0x80) {
87 buffer[0] = (uint8)codepoint;
88 return 1;
89 } else if (codepoint < 0x800) {
90 buffer[0] = 0xc0 | ((codepoint & 0x7c0) >> 6);
91 buffer[1] = 0x80 | ((codepoint & 0x03f));
92 return 2;
93 } else if (codepoint < 0x10000) {
94 buffer[0] = 0xe0 | ((codepoint & 0xf000) >> 12);
95 buffer[1] = 0x80 | ((codepoint & 0x0fc0) >> 6);
96 buffer[2] = 0x80 | ((codepoint & 0x003f));
97 return 3;
98 }
99
100 buffer[0] = 0xf0 | ((codepoint & 0x1c0000) >> 18);
101 buffer[1] = 0x80 | ((codepoint & 0x03f000) >> 12);
102 buffer[2] = 0x80 | ((codepoint & 0x000fc0) >> 6);
103 buffer[3] = 0x80 | ((codepoint & 0x00003f));
104 return 4;
105}
bool striChar(striter *i, uint8 *out)
Definition striter.h:307