1#include <string.h>
2
3#include "include/pw.h"
4#include "src/types/string/string_internal.h"
5
6static bool substreq_n_n(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
7{
8 return 0 == memcmp(str_start_ptr, substr_start_ptr, substr_end_ptr - substr_start_ptr);
9}
10
11static bool substreq_1_2(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
12{
13 while (substr_start_ptr < substr_end_ptr) {
14 if (*str_start_ptr++ != *((uint16_t*) substr_start_ptr)) {
15 return false;
16 }
17 substr_start_ptr += 2;
18 }
19 return true;
20}
21
22static bool substreq_1_3(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
23{
24 while (substr_start_ptr < substr_end_ptr) {
25 char32_t sub_chr = *substr_start_ptr++;
26 sub_chr |= (*substr_start_ptr++) << 8;
27 sub_chr |= (*substr_start_ptr++) << 16;
28 if (*str_start_ptr++ != sub_chr) {
29 return false;
30 }
31 }
32 return true;
33}
34
35static bool substreq_1_4(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
36{
37 while (substr_start_ptr < substr_end_ptr) {
38 if (*str_start_ptr++ != *((char32_t*) substr_start_ptr)) {
39 return false;
40 }
41 substr_start_ptr += 4;
42 }
43 return true;
44}
45
46
47static bool substreq_2_1(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
48{
49 while (substr_start_ptr < substr_end_ptr) {
50 if (*((uint16_t*) str_start_ptr) != *substr_start_ptr++) {
51 return false;
52 }
53 str_start_ptr += 2;
54 }
55 return true;
56}
57
58static bool substreq_2_3(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
59{
60 while (substr_start_ptr < substr_end_ptr) {
61 char32_t sub_chr = *substr_start_ptr++;
62 sub_chr |= (*substr_start_ptr++) << 8;
63 sub_chr |= (*substr_start_ptr++) << 16;
64 if (*((uint16_t*) str_start_ptr) != sub_chr) {
65 return false;
66 }
67 str_start_ptr += 2;
68 }
69 return true;
70}
71
72static bool substreq_2_4(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
73{
74 while (substr_start_ptr < substr_end_ptr) {
75 if (*((uint16_t*) str_start_ptr) != *((char32_t*) substr_start_ptr)) {
76 return false;
77 }
78 str_start_ptr += 2;
79 substr_start_ptr += 4;
80 }
81 return true;
82}
83
84
85static bool substreq_3_1(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
86{
87 while (substr_start_ptr < substr_end_ptr) {
88 char32_t chr = *str_start_ptr++;
89 chr |= (*str_start_ptr++) << 8;
90 chr |= (*str_start_ptr++) << 16;
91 if (chr != *substr_start_ptr++) {
92 return false;
93 }
94 }
95 return true;
96}
97
98static bool substreq_3_2(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
99{
100 while (substr_start_ptr < substr_end_ptr) {
101 char32_t chr = *str_start_ptr++;
102 chr |= (*str_start_ptr++) << 8;
103 chr |= (*str_start_ptr++) << 16;
104 if (chr != *((uint16_t*) substr_start_ptr)) {
105 return false;
106 }
107 substr_start_ptr += 2;
108 }
109 return true;
110}
111
112static bool substreq_3_4(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
113{
114 while (substr_start_ptr < substr_end_ptr) {
115 char32_t chr = *str_start_ptr++;
116 chr |= (*str_start_ptr++) << 8;
117 chr |= (*str_start_ptr++) << 16;
118 if (chr != *((char32_t*) substr_start_ptr)) {
119 return false;
120 }
121 str_start_ptr += 4;
122 }
123 return true;
124}
125
126
127static bool substreq_4_1(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
128{
129 while (substr_start_ptr < substr_end_ptr) {
130 if (*((char32_t*) str_start_ptr) != *substr_start_ptr++) {
131 return false;
132 }
133 str_start_ptr += 4;
134 }
135 return true;
136}
137
138static bool substreq_4_2(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
139{
140 while (substr_start_ptr < substr_end_ptr) {
141 if (*((char32_t*) str_start_ptr) != *((uint16_t*) substr_start_ptr)) {
142 return false;
143 }
144 str_start_ptr += 4;
145 substr_start_ptr += 2;
146 }
147 return true;
148}
149
150static bool substreq_4_3(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
151{
152 while (substr_start_ptr < substr_end_ptr) {
153 char32_t sub_chr = *substr_start_ptr++;
154 sub_chr |= (*substr_start_ptr++) << 8;
155 sub_chr |= (*substr_start_ptr++) << 16;
156 if (*((char32_t*) str_start_ptr) != sub_chr) {
157 return false;
158 }
159 str_start_ptr += 4;
160 }
161 return true;
162}
163
164// Comparison with UTF-8 string.
165
166#define CMP_UTF8(CHAR_TYPE, CHAR_SIZE) \
167 static bool substreq_##CHAR_SIZE##_0(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr) \
168 { \
169 while(substr_start_ptr < substr_end_ptr) { \
170 char32_t c = _pw_decode_utf8_char(&substr_start_ptr); \
171 if (c != *((CHAR_TYPE*) str_start_ptr)) { \
172 return false; \
173 } \
174 str_start_ptr += CHAR_SIZE; \
175 } \
176 return true; \
177 }
178CMP_UTF8(uint8_t, 1)
179CMP_UTF8(uint16_t, 2)
180CMP_UTF8(char32_t, 4)
181
182static bool substreq_3_0(uint8_t* str_start_ptr, uint8_t* substr_start_ptr, uint8_t* substr_end_ptr)
183{
184 while(substr_start_ptr < substr_end_ptr) {
185 char32_t c1 = _pw_decode_utf8_char(&substr_start_ptr);
186 char32_t c2 = *str_start_ptr++;
187 c2 |= (*str_start_ptr++) << 8;
188 c2 |= (*str_start_ptr++) << 16;
189 if (c1 != c2) {
190 return false;
191 }
192 }
193 return true;
194}
195
196
197SubstrEq _pw_substreq_variants[5][5] = {
198 {
199 nullptr,
200 nullptr,
201 nullptr,
202 nullptr,
203 nullptr
204 },
205 {
206 substreq_1_0,
207 substreq_n_n,
208 substreq_1_2,
209 substreq_1_3,
210 substreq_1_4
211 },
212 {
213 substreq_2_0,
214 substreq_2_1,
215 substreq_n_n,
216 substreq_2_3,
217 substreq_2_4
218 },
219 {
220 substreq_3_0,
221 substreq_3_1,
222 substreq_3_2,
223 substreq_n_n,
224 substreq_3_4
225 },
226 {
227 substreq_4_0,
228 substreq_4_1,
229 substreq_4_2,
230 substreq_4_3,
231 substreq_n_n
232 }
233};
234
235
236/****************************************************************
237 * High-level functions
238 */
239
240[[nodiscard]] bool _pw_substring_eq(PwValuePtr a, unsigned start_pos, unsigned end_pos, PwValuePtr b)
241{
242 pw_assert_string(a);
243 unsigned a_length;
244 uint8_t* a_ptr = _pw_string_start_length(a, &a_length);
245
246 if (_pw_unlikely(end_pos > a_length)) {
247 end_pos = a_length;
248 }
249 if (_pw_unlikely(end_pos < start_pos)) {
250 return false;
251 }
252 unsigned substr_length = end_pos - start_pos;
253 unsigned b_length = pw_strlen(b);
254 if (_pw_unlikely(substr_length != b_length)) {
255 return false;
256 }
257 if (_pw_unlikely(substr_length == 0)) {
258 return true;
259 }
260 uint8_t* b_end_ptr;
261 uint8_t* b_start_ptr = _pw_string_start_end(b, &b_end_ptr);
262 SubstrEq fn_substreq = _pw_substreq_variants[a->char_size][b->char_size];
263 return fn_substreq(a_ptr + start_pos * a->char_size, b_start_ptr, b_end_ptr);
264}
265
266[[nodiscard]] bool _pw_startswith_c32(PwValuePtr str, char32_t prefix)
267{
268 pw_assert_string(str);
269 unsigned length = pw_strlen(str);
270 if (_pw_unlikely(length == 0)) {
271 return false;
272 }
273 return _pw_get_char(_pw_string_start(str), str->char_size) == prefix;
274}
275
276[[nodiscard]] bool _pw_startswith(PwValuePtr str, PwValuePtr prefix)
277{
278 return _pw_substring_eq(str, 0, pw_strlen(prefix), prefix);
279}
280
281[[nodiscard]] bool _pw_endswith_c32(PwValuePtr str, char32_t prefix)
282{
283 pw_assert_string(str);
284 unsigned length;
285 uint8_t* ptr = _pw_string_start_length(str, &length);
286 if (_pw_unlikely(length == 0)) {
287 return false;
288 }
289 uint8_t char_size = str->char_size;
290 return prefix == _pw_get_char(ptr + (length - 1) * char_size, char_size);
291}
292
293[[nodiscard]] bool _pw_endswith(PwValuePtr str, PwValuePtr suffix)
294{
295 unsigned str_len = pw_strlen(str);
296 unsigned suffix_len = pw_strlen(suffix);
297 if (_pw_unlikely(str_len < suffix_len)) {
298 return false;
299 }
300 return _pw_substring_eq(str, str_len - suffix_len, str_len, suffix);
301}