Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2023 Project CHIP Authors
4 : * All rights reserved.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #include "utf8.h"
19 :
20 : namespace chip {
21 : namespace Utf8 {
22 :
23 : namespace {
24 : /**
25 : State machine for UTF8 valid bytes
26 :
27 : Table 3-7. Well-Formed UTF-8 Byte Sequences
28 :
29 : Code Points | First B | Second B | Third B | Fourth B
30 : ------------------+----------+------------+---------+---------
31 : U+0000..U+007F | 00..7F | | |
32 : U+0080..U+07FF | C2..DF | 80..BF | |
33 : U+0800..U+0FFF | E0 | A0..BF (A) | 80..BF |
34 : U+1000..U+CFFF | E1..EC | 80..BF | 80..BF |
35 : U+D000..U+D7FF | ED | 80..9F (B) | 80..BF |
36 : U+E000..U+FFFF | EE..EF | 80..BF | 80..BF |
37 : U+10000..U+3FFFF | F0 | 90..BF (C) | 80..BF | 80..BF
38 : U+40000..U+FFFFF | F1..F3 | 80..BF | 80..BF | 80..BF
39 : U+100000..U+10FFFF| F4 | 80..8F (D) | 80..BF | 80..BF
40 : */
41 :
42 : enum class ParserState
43 : {
44 : kFirstByte,
45 : kSecondByte_A,
46 : kSecondByte_B,
47 : kSecondByte_C,
48 : kSecondByte_D,
49 : kExtraOneByte, // 0x80 .. 0xBF once
50 : kExtraTwoBytes, // 0x80 .. 0xBF twice
51 : kExtraThreeBytes, // 0x80 .. 0xBF three times
52 : //
53 : kInvalid, // some error
54 : };
55 :
56 126218 : ParserState NextState(ParserState state, uint8_t value)
57 : {
58 126218 : switch (state)
59 : {
60 126097 : case ParserState::kFirstByte:
61 126097 : if (value <= 0x7F)
62 : {
63 125997 : return ParserState::kFirstByte;
64 : }
65 100 : else if ((value >= 0xC2) && (value <= 0xDF))
66 : {
67 16 : return ParserState::kExtraOneByte;
68 : }
69 84 : else if (value == 0xE0)
70 : {
71 6 : return ParserState::kSecondByte_A;
72 : }
73 78 : else if ((value >= 0xE1) && (value <= 0xEC))
74 : {
75 3 : return ParserState::kExtraTwoBytes;
76 : }
77 75 : else if (value == 0xED)
78 : {
79 6 : return ParserState::kSecondByte_B;
80 : }
81 69 : else if ((value >= 0xEE) && (value <= 0xEF))
82 : {
83 35 : return ParserState::kExtraTwoBytes;
84 : }
85 34 : else if (value == 0xF0)
86 : {
87 8 : return ParserState::kSecondByte_C;
88 : }
89 26 : else if ((value >= 0xF1) && (value <= 0xF3))
90 : {
91 3 : return ParserState::kExtraThreeBytes;
92 : }
93 23 : else if (value == 0xF4)
94 : {
95 6 : return ParserState::kSecondByte_D;
96 : }
97 : else
98 : {
99 17 : return ParserState::kInvalid;
100 : }
101 5 : case ParserState::kSecondByte_A:
102 5 : if (value >= 0xA0 && value <= 0xBF)
103 : {
104 1 : return ParserState::kExtraOneByte;
105 : }
106 : else
107 : {
108 4 : return ParserState::kInvalid;
109 : }
110 6 : case ParserState::kSecondByte_B:
111 6 : if (value >= 0x80 && value <= 0x9F)
112 : {
113 3 : return ParserState::kExtraOneByte;
114 : }
115 : else
116 : {
117 3 : return ParserState::kInvalid;
118 : }
119 7 : case ParserState::kSecondByte_C:
120 7 : if (value >= 0x90 && value <= 0xBF)
121 : {
122 3 : return ParserState::kExtraTwoBytes;
123 : }
124 : else
125 : {
126 4 : return ParserState::kInvalid;
127 : }
128 5 : case ParserState::kSecondByte_D:
129 5 : if (value >= 0x80 && value <= 0x8F)
130 : {
131 1 : return ParserState::kExtraTwoBytes;
132 : }
133 : else
134 : {
135 4 : return ParserState::kInvalid;
136 : }
137 55 : case ParserState::kExtraOneByte:
138 55 : if (value >= 0x80 && value <= 0xBF)
139 : {
140 55 : return ParserState::kFirstByte;
141 : }
142 : else
143 : {
144 0 : return ParserState::kInvalid;
145 : }
146 41 : case ParserState::kExtraTwoBytes:
147 41 : if (value >= 0x80 && value <= 0xBF)
148 : {
149 41 : return ParserState::kExtraOneByte;
150 : }
151 : else
152 : {
153 0 : return ParserState::kInvalid;
154 : }
155 2 : case ParserState::kExtraThreeBytes:
156 2 : if (value >= 0x80 && value <= 0xBF)
157 : {
158 2 : return ParserState::kExtraTwoBytes;
159 : }
160 : else
161 : {
162 0 : return ParserState::kInvalid;
163 : }
164 0 : default:
165 0 : return ParserState::kInvalid;
166 : }
167 : }
168 :
169 : } // namespace
170 :
171 2371 : bool IsValid(CharSpan span)
172 : {
173 2371 : ParserState state = ParserState::kFirstByte;
174 :
175 2371 : const char * data = span.data();
176 2371 : const size_t kLength = span.size();
177 :
178 : // Every byte should be valid
179 128557 : for (size_t i = 0; i < kLength; i++)
180 : {
181 126218 : state = NextState(state, static_cast<uint8_t>(data[i]));
182 :
183 126218 : if (state == ParserState::kInvalid)
184 : {
185 32 : return false;
186 : }
187 : }
188 :
189 : // finally no continuation should be expected
190 2339 : return state == ParserState::kFirstByte;
191 : }
192 :
193 : } // namespace Utf8
194 : } // namespace chip
|