Branch data Line data Source code
1 : : #include "unicode.h"
2 : :
3 : 401481 : size_t utf8_val(int* codepoint, const char* inp) {
4 : 401481 : unsigned char c = *inp++;
5 : : int val;
6 [ + + ]: 401481 : if (c < 0x80) {
7 : : // plain ascii
8 : 401134 : *codepoint = c;
9 : 401134 : return 1u;
10 : : }
11 : : // RPG Hacker: Byte sequences starting with 0xC0 or 0xC1 are invalid.
12 : : // So are byte sequences starting with anything >= 0xF5.
13 : : // And anything below 0xC0 indicates a follow-up byte and should never be at the start of a sequence.
14 [ + - + - ]: 347 : else if (c > 0xC1 && c < 0xF5) {
15 : : // 1, 2 or 3 continuation bytes
16 [ + + + + ]: 347 : int cont_byte_count = (c >= 0xF0) ? 3 : (c >= 0xE0) ? 2 : 1;
17 : : // bit hack to extract the significant bits from the start byte
18 : 347 : val = (c & ((1 << (6 - cont_byte_count)) - 1));
19 [ + + ]: 1010 : for (int i = 0; i < cont_byte_count; i++) {
20 : 665 : unsigned char next = *inp++;
21 [ + + ]: 665 : if ((next & 0xC0) != 0x80) {
22 : 2 : *codepoint = -1;
23 : 2 : return 0u;
24 : : }
25 : 663 : val = (val << 6) | (next & 0x3F);
26 : : }
27 : 345 : if (// too many cont.bytes
28 [ + - + - ]: 345 : (*inp & 0xC0) == 0x80 ||
29 : :
30 : : // invalid codepoints
31 [ + + ]: 345 : val > 0x10FFFF ||
32 : :
33 : : // check overlong encodings
34 [ + - + + ]: 345 : (cont_byte_count == 3 && val < 0x1000) ||
35 [ + - + + ]: 345 : (cont_byte_count == 2 && val < 0x800) ||
36 [ + - + + ]: 345 : (cont_byte_count == 1 && val < 0x80) ||
37 : :
38 : : // UTF16 surrogates
39 [ - + ]: 215 : (val >= 0xD800 && val <= 0xDFFF)
40 : : ) {
41 : 0 : *codepoint = -1;
42 : 0 : return 0u;
43 : : };
44 : 345 : *codepoint = val;
45 : 345 : return 1u + cont_byte_count;
46 : : }
47 : :
48 : : // if none of the above, this couldn't possibly be a valid encoding
49 : 0 : *codepoint = -1;
50 : 0 : return 0u;
51 : : }
52 : :
53 : 29329 : bool codepoint_to_utf8(string* out, unsigned int codepoint) {
54 : 29329 : *out = "";
55 [ + + ]: 29329 : if (codepoint < 0x80) {
56 : 28752 : *out += (unsigned char)codepoint;
57 : : }
58 [ - + ]: 577 : else if (codepoint < 0x800) {
59 : 0 : *out += (unsigned char)(0xc0 | (codepoint >> 6));
60 : 0 : *out += (unsigned char)(0x80 | (codepoint & 0x3f));
61 : : }
62 [ + + ]: 577 : else if (codepoint < 0x10000) {
63 : 345 : *out += (unsigned char)(0xe0 | (codepoint >> 12));
64 : 345 : *out += (unsigned char)(0x80 | ((codepoint >> 6) & 0x3f));
65 : 345 : *out += (unsigned char)(0x80 | (codepoint & 0x3f));
66 : : }
67 [ + - ]: 232 : else if (codepoint < 0x110000) {
68 : 232 : *out += (unsigned char)(0xf0 | (codepoint >> 18));
69 : 232 : *out += (unsigned char)(0x80 | ((codepoint >> 12) & 0x3f));
70 : 232 : *out += (unsigned char)(0x80 | ((codepoint >> 6) & 0x3f));
71 : 232 : *out += (unsigned char)(0x80 | (codepoint & 0x3f));
72 : : }
73 : 0 : else return false;
74 : :
75 : 29329 : return true;
76 : : }
77 : :
78 : 728 : bool is_valid_utf8(const char* inp) {
79 [ + + ]: 212950 : while (*inp != '\0') {
80 : : int codepoint;
81 : 212224 : inp += utf8_val(&codepoint, inp);
82 : :
83 [ + + ]: 212224 : if (codepoint == -1) return false;
84 : : }
85 : :
86 : 363 : return true;
87 : : }
88 : :
89 : 29329 : size_t utf16_val(int* codepoint, const wchar_t* inp)
90 : : {
91 : 29329 : wchar_t first_word = *inp;
92 : :
93 [ + + - + ]: 29329 : if (first_word <= 0xD800 || first_word >= 0xDFFF)
94 : : {
95 : : // Single word
96 : 29097 : *codepoint = first_word;
97 : 29097 : return 1u;
98 : : }
99 [ + - + - ]: 232 : else if (first_word >= 0xD800 && first_word <= 0xDBFF)
100 : : {
101 : : // Start of a surrogate pair
102 : 232 : wchar_t second_word = *(inp + 1);
103 : :
104 [ + - + - ]: 232 : if (second_word >= 0xDC00 && second_word <= 0xDFFF)
105 : : {
106 : 232 : *codepoint = 0x10000
107 : 232 : + ((int)(first_word - 0xD800) << 10u)
108 : 232 : + ((int)(second_word - 0xDC00));
109 : 232 : return 2u;
110 : : }
111 : : }
112 : :
113 : : // Everything not covered above is considered invalid.
114 : 0 : *codepoint = -1;
115 : 0 : return 0u;
116 : : }
117 : :
118 : 186477 : bool codepoint_to_utf16(std::wstring* out, unsigned int codepoint)
119 : : {
120 [ + + + - ]: 186477 : if (codepoint >= 0x10000 && codepoint <= 0x10FFFF)
121 : : {
122 : 15 : wchar_t high = (wchar_t)(((codepoint - 0x10000) >> 10) + 0xD800);
123 : 15 : wchar_t low = (wchar_t)(((codepoint - 0x10000) & 0b1111111111) + 0xDC00);
124 : :
125 : 15 : *out = std::wstring() + high + low;
126 : 15 : return true;
127 : : }
128 [ - + - - ]: 186462 : else if (codepoint <= 0xD800 || codepoint >= 0xDFFF)
129 : : {
130 : 186462 : *out = std::wstring() + (wchar_t)codepoint;
131 : 186462 : return true;
132 : : }
133 : :
134 : : // Everything not covered above should be considered invalid.
135 : 0 : return false;
136 : : }
137 : :
138 : :
139 : 1150 : bool utf16_to_utf8(string* result, const wchar_t* u16_str)
140 : : {
141 : 1150 : *result = "";
142 : :
143 : : int codepoint;
144 : : do
145 : : {
146 : 29329 : u16_str += utf16_val(&codepoint, u16_str);
147 : :
148 : 29329 : string next;
149 [ + - + - : 29329 : if (codepoint == -1 || !codepoint_to_utf8(&next, codepoint)) return false;
- + - + ]
150 : :
151 : 29329 : *result += next;
152 [ + - + + ]: 58658 : } while (codepoint != 0);
153 : :
154 : 1150 : return true;
155 : : }
156 : :
157 : 4207 : bool utf8_to_utf16(std::wstring* result, const char* u8_str)
158 : : {
159 : 4207 : *result = L"";
160 : :
161 : : int codepoint;
162 : : do
163 : : {
164 : 186477 : u8_str += utf8_val(&codepoint, u8_str);
165 : :
166 : 186477 : std::wstring next;
167 [ + - + - : 186477 : if (codepoint == -1 || !codepoint_to_utf16(&next, codepoint)) return false;
- + - + ]
168 : :
169 : 186477 : *result += next;
170 [ + - + + ]: 372954 : } while (codepoint != 0);
171 : :
172 : 4207 : return true;
173 : : }
|