Line data Source code
1 : /**
2 : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0.
4 : */
5 :
6 : #include <aws/common/byte_buf.h>
7 : #include <aws/common/private/byte_buf.h>
8 :
9 : #include <stdarg.h>
10 :
11 : #ifdef _MSC_VER
12 : /* disables warning non const declared initializers for Microsoft compilers */
13 : # pragma warning(disable : 4204)
14 : # pragma warning(disable : 4706)
15 : #endif
16 :
17 6347 : int aws_byte_buf_init(struct aws_byte_buf *buf, struct aws_allocator *allocator, size_t capacity) {
18 6347 : AWS_PRECONDITION(buf);
19 6347 : AWS_PRECONDITION(allocator);
20 6347 :
21 6347 : buf->buffer = (capacity == 0) ? NULL : aws_mem_acquire(allocator, capacity);
22 6347 : if (capacity != 0 && buf->buffer == NULL) {
23 0 : AWS_ZERO_STRUCT(*buf);
24 0 : return AWS_OP_ERR;
25 0 : }
26 6347 :
27 6347 : buf->len = 0;
28 6347 : buf->capacity = capacity;
29 6347 : buf->allocator = allocator;
30 6347 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
31 6347 : return AWS_OP_SUCCESS;
32 6347 : }
33 :
34 61646 : int aws_byte_buf_init_copy(struct aws_byte_buf *dest, struct aws_allocator *allocator, const struct aws_byte_buf *src) {
35 61646 : AWS_PRECONDITION(allocator);
36 61646 : AWS_PRECONDITION(dest);
37 61646 : AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(src));
38 61646 :
39 61646 : if (!src->buffer) {
40 0 : AWS_ZERO_STRUCT(*dest);
41 0 : dest->allocator = allocator;
42 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
43 0 : return AWS_OP_SUCCESS;
44 61646 : }
45 61646 :
46 61646 : *dest = *src;
47 61646 : dest->allocator = allocator;
48 61646 : dest->buffer = (uint8_t *)aws_mem_acquire(allocator, src->capacity);
49 61646 : if (dest->buffer == NULL) {
50 0 : AWS_ZERO_STRUCT(*dest);
51 0 : return AWS_OP_ERR;
52 0 : }
53 61646 : memcpy(dest->buffer, src->buffer, src->len);
54 61646 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
55 61646 : return AWS_OP_SUCCESS;
56 61646 : }
57 :
58 12074594 : bool aws_byte_buf_is_valid(const struct aws_byte_buf *const buf) {
59 12074594 : return buf != NULL &&
60 12074594 : ((buf->capacity == 0 && buf->len == 0 && buf->buffer == NULL) ||
61 12074594 : (buf->capacity > 0 && buf->len <= buf->capacity && AWS_MEM_IS_WRITABLE(buf->buffer, buf->capacity)));
62 12074594 : }
63 :
64 12464168 : bool aws_byte_cursor_is_valid(const struct aws_byte_cursor *cursor) {
65 12464168 : return cursor != NULL &&
66 12464168 : ((cursor->len == 0) || (cursor->len > 0 && cursor->ptr && AWS_MEM_IS_READABLE(cursor->ptr, cursor->len)));
67 12464168 : }
68 :
69 133441 : void aws_byte_buf_reset(struct aws_byte_buf *buf, bool zero_contents) {
70 133441 : if (zero_contents) {
71 73226 : aws_byte_buf_secure_zero(buf);
72 73226 : }
73 133441 : buf->len = 0;
74 133441 : }
75 :
76 235392 : void aws_byte_buf_clean_up(struct aws_byte_buf *buf) {
77 235392 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
78 235392 : if (buf->allocator && buf->buffer) {
79 235392 : aws_mem_release(buf->allocator, (void *)buf->buffer);
80 235392 : }
81 235392 : buf->allocator = NULL;
82 235392 : buf->buffer = NULL;
83 235392 : buf->len = 0;
84 235392 : buf->capacity = 0;
85 235392 : }
86 :
87 324190 : void aws_byte_buf_secure_zero(struct aws_byte_buf *buf) {
88 324190 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
89 324190 : if (buf->buffer) {
90 324190 : aws_secure_zero(buf->buffer, buf->capacity);
91 324190 : }
92 324190 : buf->len = 0;
93 324190 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
94 324190 : }
95 :
96 116980 : void aws_byte_buf_clean_up_secure(struct aws_byte_buf *buf) {
97 116980 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
98 116980 : aws_byte_buf_secure_zero(buf);
99 116980 : aws_byte_buf_clean_up(buf);
100 116980 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
101 116980 : }
102 :
103 45619 : bool aws_byte_buf_eq(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
104 45619 : AWS_PRECONDITION(aws_byte_buf_is_valid(a));
105 45619 : AWS_PRECONDITION(aws_byte_buf_is_valid(b));
106 45619 : bool rval = aws_array_eq(a->buffer, a->len, b->buffer, b->len);
107 45619 : AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
108 45619 : AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
109 45619 : return rval;
110 45619 : }
111 :
112 37851 : bool aws_byte_buf_eq_ignore_case(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
113 37851 : AWS_PRECONDITION(aws_byte_buf_is_valid(a));
114 37851 : AWS_PRECONDITION(aws_byte_buf_is_valid(b));
115 37851 : bool rval = aws_array_eq_ignore_case(a->buffer, a->len, b->buffer, b->len);
116 37851 : AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
117 37851 : AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
118 37851 : return rval;
119 37851 : }
120 :
121 30625 : bool aws_byte_buf_eq_c_str(const struct aws_byte_buf *const buf, const char *const c_str) {
122 30625 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
123 30625 : AWS_PRECONDITION(c_str != NULL);
124 30625 : bool rval = aws_array_eq_c_str(buf->buffer, buf->len, c_str);
125 30625 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
126 30625 : return rval;
127 30625 : }
128 :
129 26707 : bool aws_byte_buf_eq_c_str_ignore_case(const struct aws_byte_buf *const buf, const char *const c_str) {
130 26707 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
131 26707 : AWS_PRECONDITION(c_str != NULL);
132 26707 : bool rval = aws_array_eq_c_str_ignore_case(buf->buffer, buf->len, c_str);
133 26707 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
134 26707 : return rval;
135 26707 : }
136 :
137 : int aws_byte_buf_init_copy_from_cursor(
138 : struct aws_byte_buf *dest,
139 : struct aws_allocator *allocator,
140 134081 : struct aws_byte_cursor src) {
141 134081 : AWS_PRECONDITION(allocator);
142 134081 : AWS_PRECONDITION(dest);
143 134081 : AWS_ERROR_PRECONDITION(aws_byte_cursor_is_valid(&src));
144 134081 :
145 134081 : AWS_ZERO_STRUCT(*dest);
146 134081 :
147 134081 : dest->buffer = (src.len > 0) ? (uint8_t *)aws_mem_acquire(allocator, src.len) : NULL;
148 134081 : if (src.len != 0 && dest->buffer == NULL) {
149 0 : return AWS_OP_ERR;
150 0 : }
151 134081 :
152 134081 : dest->len = src.len;
153 134081 : dest->capacity = src.len;
154 134081 : dest->allocator = allocator;
155 134081 : if (src.len > 0) {
156 117408 : memcpy(dest->buffer, src.ptr, src.len);
157 117408 : }
158 134081 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
159 134081 : return AWS_OP_SUCCESS;
160 134081 : }
161 :
162 0 : int aws_byte_buf_init_cache_and_update_cursors(struct aws_byte_buf *dest, struct aws_allocator *allocator, ...) {
163 0 : AWS_PRECONDITION(allocator);
164 0 : AWS_PRECONDITION(dest);
165 0 :
166 0 : AWS_ZERO_STRUCT(*dest);
167 0 :
168 0 : size_t total_len = 0;
169 0 : va_list args;
170 0 : va_start(args, allocator);
171 0 :
172 0 : /* Loop until final NULL arg is encountered */
173 0 : struct aws_byte_cursor *cursor_i;
174 0 : while ((cursor_i = va_arg(args, struct aws_byte_cursor *)) != NULL) {
175 0 : AWS_ASSERT(aws_byte_cursor_is_valid(cursor_i));
176 0 : if (aws_add_size_checked(total_len, cursor_i->len, &total_len)) {
177 0 : return AWS_OP_ERR;
178 0 : }
179 0 : }
180 0 : va_end(args);
181 0 :
182 0 : if (aws_byte_buf_init(dest, allocator, total_len)) {
183 0 : return AWS_OP_ERR;
184 0 : }
185 0 :
186 0 : va_start(args, allocator);
187 0 : while ((cursor_i = va_arg(args, struct aws_byte_cursor *)) != NULL) {
188 0 : /* Impossible for this call to fail, we pre-allocated sufficient space */
189 0 : aws_byte_buf_append_and_update(dest, cursor_i);
190 0 : }
191 0 : va_end(args);
192 0 :
193 0 : return AWS_OP_SUCCESS;
194 0 : }
195 :
196 : bool aws_byte_cursor_next_split(
197 : const struct aws_byte_cursor *AWS_RESTRICT input_str,
198 : char split_on,
199 0 : struct aws_byte_cursor *AWS_RESTRICT substr) {
200 0 :
201 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(input_str));
202 0 :
203 0 : /* If substr is zeroed-out, then this is the first run. */
204 0 : const bool first_run = substr->ptr == NULL;
205 0 :
206 0 : /* It's legal for input_str to be zeroed out: {.ptr=NULL, .len=0}
207 0 : * Deal with this case separately */
208 0 : if (AWS_UNLIKELY(input_str->ptr == NULL)) {
209 0 : if (first_run) {
210 0 : /* Set substr->ptr to something non-NULL so that next split() call doesn't look like the first run */
211 0 : substr->ptr = (void *)"";
212 0 : substr->len = 0;
213 0 : return true;
214 0 : }
215 0 :
216 0 : /* done */
217 0 : AWS_ZERO_STRUCT(*substr);
218 0 : return false;
219 0 : }
220 0 :
221 0 : /* Rest of function deals with non-NULL input_str->ptr */
222 0 :
223 0 : if (first_run) {
224 0 : *substr = *input_str;
225 0 : } else {
226 0 : /* This is not the first run.
227 0 : * Advance substr past the previous split. */
228 0 : const uint8_t *input_end = input_str->ptr + input_str->len;
229 0 : substr->ptr += substr->len + 1;
230 0 :
231 0 : /* Note that it's ok if substr->ptr == input_end, this happens in the
232 0 : * final valid split of an input_str that ends with the split_on character:
233 0 : * Ex: "AB&" split on '&' produces "AB" and "" */
234 0 : if (substr->ptr > input_end || substr->ptr < input_str->ptr) { /* 2nd check is overflow check */
235 0 : /* done */
236 0 : AWS_ZERO_STRUCT(*substr);
237 0 : return false;
238 0 : }
239 0 :
240 0 : /* update len to be remainder of the string */
241 0 : substr->len = input_str->len - (substr->ptr - input_str->ptr);
242 0 : }
243 0 :
244 0 : /* substr is now remainder of string, search for next split */
245 0 : uint8_t *new_location = memchr(substr->ptr, split_on, substr->len);
246 0 : if (new_location) {
247 0 :
248 0 : /* Character found, update string length. */
249 0 : substr->len = new_location - substr->ptr;
250 0 : }
251 0 :
252 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(substr));
253 0 : return true;
254 0 : }
255 :
256 : int aws_byte_cursor_split_on_char_n(
257 : const struct aws_byte_cursor *AWS_RESTRICT input_str,
258 : char split_on,
259 : size_t n,
260 0 : struct aws_array_list *AWS_RESTRICT output) {
261 0 : AWS_ASSERT(aws_byte_cursor_is_valid(input_str));
262 0 : AWS_ASSERT(output);
263 0 : AWS_ASSERT(output->item_size >= sizeof(struct aws_byte_cursor));
264 0 :
265 0 : size_t max_splits = n > 0 ? n : SIZE_MAX;
266 0 : size_t split_count = 0;
267 0 :
268 0 : struct aws_byte_cursor substr;
269 0 : AWS_ZERO_STRUCT(substr);
270 0 :
271 0 : /* Until we run out of substrs or hit the max split count, keep iterating and pushing into the array list. */
272 0 : while (split_count <= max_splits && aws_byte_cursor_next_split(input_str, split_on, &substr)) {
273 0 :
274 0 : if (split_count == max_splits) {
275 0 : /* If this is the last split, take the rest of the string. */
276 0 : substr.len = input_str->len - (substr.ptr - input_str->ptr);
277 0 : }
278 0 :
279 0 : if (AWS_UNLIKELY(aws_array_list_push_back(output, (const void *)&substr))) {
280 0 : return AWS_OP_ERR;
281 0 : }
282 0 : ++split_count;
283 0 : }
284 0 :
285 0 : return AWS_OP_SUCCESS;
286 0 : }
287 :
288 : int aws_byte_cursor_split_on_char(
289 : const struct aws_byte_cursor *AWS_RESTRICT input_str,
290 : char split_on,
291 0 : struct aws_array_list *AWS_RESTRICT output) {
292 0 :
293 0 : return aws_byte_cursor_split_on_char_n(input_str, split_on, 0, output);
294 0 : }
295 :
296 : int aws_byte_cursor_find_exact(
297 : const struct aws_byte_cursor *AWS_RESTRICT input_str,
298 : const struct aws_byte_cursor *AWS_RESTRICT to_find,
299 0 : struct aws_byte_cursor *first_find) {
300 0 : if (to_find->len > input_str->len) {
301 0 : return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
302 0 : }
303 0 :
304 0 : if (to_find->len < 1) {
305 0 : return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
306 0 : }
307 0 :
308 0 : struct aws_byte_cursor working_cur = *input_str;
309 0 :
310 0 : while (working_cur.len) {
311 0 : uint8_t *first_char_location = memchr(working_cur.ptr, (char)*to_find->ptr, working_cur.len);
312 0 :
313 0 : if (!first_char_location) {
314 0 : return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
315 0 : }
316 0 :
317 0 : aws_byte_cursor_advance(&working_cur, first_char_location - working_cur.ptr);
318 0 :
319 0 : if (working_cur.len < to_find->len) {
320 0 : return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
321 0 : }
322 0 :
323 0 : if (!memcmp(working_cur.ptr, to_find->ptr, to_find->len)) {
324 0 : *first_find = working_cur;
325 0 : return AWS_OP_SUCCESS;
326 0 : }
327 0 :
328 0 : aws_byte_cursor_advance(&working_cur, 1);
329 0 : }
330 0 :
331 0 : return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
332 0 : }
333 :
334 0 : int aws_byte_buf_cat(struct aws_byte_buf *dest, size_t number_of_args, ...) {
335 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
336 0 :
337 0 : va_list ap;
338 0 : va_start(ap, number_of_args);
339 0 :
340 0 : for (size_t i = 0; i < number_of_args; ++i) {
341 0 : struct aws_byte_buf *buffer = va_arg(ap, struct aws_byte_buf *);
342 0 : struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(buffer);
343 0 :
344 0 : if (aws_byte_buf_append(dest, &cursor)) {
345 0 : va_end(ap);
346 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
347 0 : return AWS_OP_ERR;
348 0 : }
349 0 : }
350 0 :
351 0 : va_end(ap);
352 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
353 0 : return AWS_OP_SUCCESS;
354 0 : }
355 :
356 40595 : bool aws_byte_cursor_eq(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
357 40595 : AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
358 40595 : AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
359 40595 : bool rv = aws_array_eq(a->ptr, a->len, b->ptr, b->len);
360 40595 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
361 40595 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
362 40595 : return rv;
363 40595 : }
364 :
365 37106 : bool aws_byte_cursor_eq_ignore_case(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
366 37106 : AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
367 37106 : AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
368 37106 : bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->ptr, b->len);
369 37106 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
370 37106 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
371 37106 : return rv;
372 37106 : }
373 :
374 : /* Every possible uint8_t value, lowercased */
375 : static const uint8_t s_tolower_table[] = {
376 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
377 : 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
378 : 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'a',
379 : 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
380 : 'x', 'y', 'z', 91, 92, 93, 94, 95, 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
381 : 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123, 124, 125, 126, 127, 128, 129, 130, 131,
382 : 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
383 : 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
384 : 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
385 : 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
386 : 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
387 : 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
388 : AWS_STATIC_ASSERT(AWS_ARRAY_SIZE(s_tolower_table) == 256);
389 :
390 0 : const uint8_t *aws_lookup_table_to_lower_get(void) {
391 0 : return s_tolower_table;
392 0 : }
393 :
394 : bool aws_array_eq_ignore_case(
395 : const void *const array_a,
396 : const size_t len_a,
397 : const void *const array_b,
398 313983 : const size_t len_b) {
399 313983 : AWS_PRECONDITION(
400 313983 : (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
401 313983 : AWS_PRECONDITION(
402 313983 : (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
403 313983 :
404 313983 : if (len_a != len_b) {
405 164354 : return false;
406 164354 : }
407 149629 :
408 149629 : const uint8_t *bytes_a = array_a;
409 149629 : const uint8_t *bytes_b = array_b;
410 294168 : for (size_t i = 0; i < len_a; ++i) {
411 204473 : if (s_tolower_table[bytes_a[i]] != s_tolower_table[bytes_b[i]]) {
412 59934 : return false;
413 59934 : }
414 204473 : }
415 149629 :
416 149629 : return true;
417 149629 : }
418 :
419 397126 : bool aws_array_eq(const void *const array_a, const size_t len_a, const void *const array_b, const size_t len_b) {
420 397126 : AWS_PRECONDITION(
421 397126 : (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
422 397126 : AWS_PRECONDITION(
423 397126 : (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
424 397126 :
425 397126 : if (len_a != len_b) {
426 196331 : return false;
427 196331 : }
428 200795 :
429 200795 : if (len_a == 0) {
430 48038 : return true;
431 48038 : }
432 152757 :
433 152757 : return !memcmp(array_a, array_b, len_a);
434 152757 : }
435 :
436 125312 : bool aws_array_eq_c_str_ignore_case(const void *const array, const size_t array_len, const char *const c_str) {
437 125312 : AWS_PRECONDITION(
438 125312 : array || (array_len == 0),
439 125312 : "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
440 125312 : AWS_PRECONDITION(c_str != NULL);
441 125312 :
442 125312 : /* Simpler implementation could have been:
443 125312 : * return aws_array_eq_ignore_case(array, array_len, c_str, strlen(c_str));
444 125312 : * but that would have traversed c_str twice.
445 125312 : * This implementation traverses c_str just once. */
446 125312 :
447 125312 : const uint8_t *array_bytes = array;
448 125312 : const uint8_t *str_bytes = (const uint8_t *)c_str;
449 125312 :
450 233923 : for (size_t i = 0; i < array_len; ++i) {
451 185832 : uint8_t s = str_bytes[i];
452 185832 : if (s == '\0') {
453 27539 : return false;
454 27539 : }
455 158293 :
456 158293 : if (s_tolower_table[array_bytes[i]] != s_tolower_table[s]) {
457 49682 : return false;
458 49682 : }
459 158293 : }
460 125312 :
461 125312 : return str_bytes[array_len] == '\0';
462 125312 : }
463 :
464 172058 : bool aws_array_eq_c_str(const void *const array, const size_t array_len, const char *const c_str) {
465 172058 : AWS_PRECONDITION(
466 172058 : array || (array_len == 0),
467 172058 : "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
468 172058 : AWS_PRECONDITION(c_str != NULL);
469 172058 :
470 172058 : /* Simpler implementation could have been:
471 172058 : * return aws_array_eq(array, array_len, c_str, strlen(c_str));
472 172058 : * but that would have traversed c_str twice.
473 172058 : * This implementation traverses c_str just once. */
474 172058 :
475 172058 : const uint8_t *array_bytes = array;
476 172058 : const uint8_t *str_bytes = (const uint8_t *)c_str;
477 172058 :
478 342629 : for (size_t i = 0; i < array_len; ++i) {
479 261563 : uint8_t s = str_bytes[i];
480 261563 : if (s == '\0') {
481 32831 : return false;
482 32831 : }
483 228732 :
484 228732 : if (array_bytes[i] != s) {
485 58161 : return false;
486 58161 : }
487 228732 : }
488 172058 :
489 172058 : return str_bytes[array_len] == '\0';
490 172058 : }
491 :
492 141568 : uint64_t aws_hash_array_ignore_case(const void *array, const size_t len) {
493 141568 : AWS_PRECONDITION(AWS_MEM_IS_READABLE(array, len));
494 141568 : /* FNV-1a: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */
495 141568 : const uint64_t fnv_offset_basis = 0xcbf29ce484222325ULL;
496 141568 : const uint64_t fnv_prime = 0x100000001b3ULL;
497 141568 :
498 141568 : const uint8_t *i = array;
499 141568 : const uint8_t *end = i + len;
500 141568 :
501 141568 : uint64_t hash = fnv_offset_basis;
502 827386 : while (i != end) {
503 685818 : const uint8_t lower = s_tolower_table[*i++];
504 685818 : hash ^= lower;
505 : #ifdef CBMC
506 : # pragma CPROVER check push
507 : # pragma CPROVER check disable "unsigned-overflow"
508 : #endif
509 : hash *= fnv_prime;
510 : #ifdef CBMC
511 : # pragma CPROVER check pop
512 : #endif
513 : }
514 141568 : return hash;
515 141568 : }
516 :
517 141568 : uint64_t aws_hash_byte_cursor_ptr_ignore_case(const void *item) {
518 141568 : AWS_PRECONDITION(aws_byte_cursor_is_valid(item));
519 141568 : const struct aws_byte_cursor *const cursor = item;
520 141568 : uint64_t rval = aws_hash_array_ignore_case(cursor->ptr, cursor->len);
521 141568 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(item));
522 141568 : return rval;
523 141568 : }
524 :
525 32134 : bool aws_byte_cursor_eq_byte_buf(const struct aws_byte_cursor *const a, const struct aws_byte_buf *const b) {
526 32134 : AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
527 32134 : AWS_PRECONDITION(aws_byte_buf_is_valid(b));
528 32134 : bool rv = aws_array_eq(a->ptr, a->len, b->buffer, b->len);
529 32134 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
530 32134 : AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
531 32134 : return rv;
532 32134 : }
533 :
534 : bool aws_byte_cursor_eq_byte_buf_ignore_case(
535 : const struct aws_byte_cursor *const a,
536 30405 : const struct aws_byte_buf *const b) {
537 30405 : AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
538 30405 : AWS_PRECONDITION(aws_byte_buf_is_valid(b));
539 30405 : bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->buffer, b->len);
540 30405 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
541 30405 : AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
542 30405 : return rv;
543 30405 : }
544 :
545 27696 : bool aws_byte_cursor_eq_c_str(const struct aws_byte_cursor *const cursor, const char *const c_str) {
546 27696 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
547 27696 : AWS_PRECONDITION(c_str != NULL);
548 27696 : bool rv = aws_array_eq_c_str(cursor->ptr, cursor->len, c_str);
549 27696 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
550 27696 : return rv;
551 27696 : }
552 :
553 24652 : bool aws_byte_cursor_eq_c_str_ignore_case(const struct aws_byte_cursor *const cursor, const char *const c_str) {
554 24652 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
555 24652 : AWS_PRECONDITION(c_str != NULL);
556 24652 : bool rv = aws_array_eq_c_str_ignore_case(cursor->ptr, cursor->len, c_str);
557 24652 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
558 24652 : return rv;
559 24652 : }
560 :
561 201198 : int aws_byte_buf_append(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
562 201198 : AWS_PRECONDITION(aws_byte_buf_is_valid(to));
563 201198 : AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
564 201198 :
565 201198 : if (to->capacity - to->len < from->len) {
566 88330 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
567 88330 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
568 88330 : return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
569 112868 : }
570 112868 :
571 112868 : if (from->len > 0) {
572 48815 : /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
573 48815 : AWS_ASSERT(from->ptr);
574 48815 : AWS_ASSERT(to->buffer);
575 48815 : memcpy(to->buffer + to->len, from->ptr, from->len);
576 48815 : to->len += from->len;
577 48815 : }
578 112868 :
579 112868 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
580 112868 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
581 112868 : return AWS_OP_SUCCESS;
582 112868 : }
583 :
584 : int aws_byte_buf_append_with_lookup(
585 : struct aws_byte_buf *AWS_RESTRICT to,
586 : const struct aws_byte_cursor *AWS_RESTRICT from,
587 116557 : const uint8_t *lookup_table) {
588 116557 : AWS_PRECONDITION(aws_byte_buf_is_valid(to));
589 116557 : AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
590 116557 : AWS_PRECONDITION(
591 116557 : AWS_MEM_IS_READABLE(lookup_table, 256), "Input array [lookup_table] must be at least 256 bytes long.");
592 116557 :
593 116557 : if (to->capacity - to->len < from->len) {
594 69736 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
595 69736 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
596 69736 : return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
597 46821 : }
598 46821 :
599 220534 : for (size_t i = 0; i < from->len; ++i) {
600 173713 : to->buffer[to->len + i] = lookup_table[from->ptr[i]];
601 173713 : }
602 46821 :
603 46821 : if (aws_add_size_checked(to->len, from->len, &to->len)) {
604 0 : return AWS_OP_ERR;
605 0 : }
606 46821 :
607 46821 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
608 46821 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
609 46821 : return AWS_OP_SUCCESS;
610 46821 : }
611 :
612 : static int s_aws_byte_buf_append_dynamic(
613 : struct aws_byte_buf *to,
614 : const struct aws_byte_cursor *from,
615 130907 : bool clear_released_memory) {
616 130907 : AWS_PRECONDITION(aws_byte_buf_is_valid(to));
617 130907 : AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
618 130907 : AWS_ERROR_PRECONDITION(to->allocator);
619 130907 :
620 130907 : if (to->capacity - to->len < from->len) {
621 81166 : /*
622 81166 : * NewCapacity = Max(OldCapacity * 2, OldCapacity + MissingCapacity)
623 81166 : */
624 81166 : size_t missing_capacity = from->len - (to->capacity - to->len);
625 81166 :
626 81166 : size_t required_capacity = 0;
627 81166 : if (aws_add_size_checked(to->capacity, missing_capacity, &required_capacity)) {
628 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
629 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
630 0 : return AWS_OP_ERR;
631 81166 : }
632 81166 :
633 81166 : /*
634 81166 : * It's ok if this overflows, just clamp to max possible.
635 81166 : * In theory this lets us still grow a buffer that's larger than 1/2 size_t space
636 81166 : * at least enough to accommodate the append.
637 81166 : */
638 81166 : size_t growth_capacity = aws_add_size_saturating(to->capacity, to->capacity);
639 81166 :
640 81166 : size_t new_capacity = required_capacity;
641 81166 : if (new_capacity < growth_capacity) {
642 32821 : new_capacity = growth_capacity;
643 32821 : }
644 81166 :
645 81166 : /*
646 81166 : * Attempt to resize - we intentionally do not use reserve() in order to preserve
647 81166 : * the (unlikely) use case of from and to being the same buffer range.
648 81166 : */
649 81166 :
650 81166 : /*
651 81166 : * Try the max, but if that fails and the required is smaller, try it in fallback
652 81166 : */
653 81166 : uint8_t *new_buffer = aws_mem_acquire(to->allocator, new_capacity);
654 81166 : if (new_buffer == NULL) {
655 0 : if (new_capacity > required_capacity) {
656 0 : new_capacity = required_capacity;
657 0 : new_buffer = aws_mem_acquire(to->allocator, new_capacity);
658 0 : if (new_buffer == NULL) {
659 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
660 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
661 0 : return AWS_OP_ERR;
662 0 : }
663 0 : } else {
664 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
665 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
666 0 : return AWS_OP_ERR;
667 81166 : }
668 0 : }
669 81166 :
670 81166 : /*
671 81166 : * Copy old buffer -> new buffer
672 81166 : */
673 81166 : if (to->len > 0) {
674 40889 : memcpy(new_buffer, to->buffer, to->len);
675 40889 : }
676 81166 : /*
677 81166 : * Copy what we actually wanted to append in the first place
678 81166 : */
679 81166 : if (from->len > 0) {
680 81166 : memcpy(new_buffer + to->len, from->ptr, from->len);
681 81166 : }
682 81166 :
683 81166 : if (clear_released_memory) {
684 0 : aws_secure_zero(to->buffer, to->capacity);
685 0 : }
686 81166 :
687 81166 : /*
688 81166 : * Get rid of the old buffer
689 81166 : */
690 81166 : aws_mem_release(to->allocator, to->buffer);
691 81166 :
692 81166 : /*
693 81166 : * Switch to the new buffer
694 81166 : */
695 81166 : to->buffer = new_buffer;
696 81166 : to->capacity = new_capacity;
697 81166 : } else {
698 49741 : if (from->len > 0) {
699 35413 : /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
700 35413 : AWS_ASSERT(from->ptr);
701 35413 : AWS_ASSERT(to->buffer);
702 35413 : memcpy(to->buffer + to->len, from->ptr, from->len);
703 35413 : }
704 49741 : }
705 130907 :
706 130907 : to->len += from->len;
707 130907 :
708 130907 : AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
709 130907 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
710 130907 : return AWS_OP_SUCCESS;
711 130907 : }
712 :
713 130907 : int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
714 130907 : return s_aws_byte_buf_append_dynamic(to, from, false);
715 130907 : }
716 :
717 0 : int aws_byte_buf_append_dynamic_secure(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
718 0 : return s_aws_byte_buf_append_dynamic(to, from, true);
719 0 : }
720 :
721 0 : static int s_aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value, bool clear_released_memory) {
722 : #if defined(_MSC_VER)
723 : # pragma warning(push)
724 : # pragma warning(disable : 4221)
725 : #endif /* _MSC_VER */
726 :
727 0 : /* msvc isn't a fan of this pointer-to-local assignment */
728 0 : struct aws_byte_cursor eq_cursor = {.len = 1, .ptr = &value};
729 0 :
730 : #if defined(_MSC_VER)
731 : # pragma warning(pop)
732 : #endif /* _MSC_VER */
733 :
734 0 : return s_aws_byte_buf_append_dynamic(buffer, &eq_cursor, clear_released_memory);
735 0 : }
736 :
737 0 : int aws_byte_buf_append_byte_dynamic(struct aws_byte_buf *buffer, uint8_t value) {
738 0 : return s_aws_byte_buf_append_byte_dynamic(buffer, value, false);
739 0 : }
740 :
741 0 : int aws_byte_buf_append_byte_dynamic_secure(struct aws_byte_buf *buffer, uint8_t value) {
742 0 : return s_aws_byte_buf_append_byte_dynamic(buffer, value, true);
743 0 : }
744 :
745 132655 : int aws_byte_buf_reserve(struct aws_byte_buf *buffer, size_t requested_capacity) {
746 132655 : AWS_ERROR_PRECONDITION(buffer->allocator);
747 132655 : AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
748 132655 :
749 132655 : if (requested_capacity <= buffer->capacity) {
750 9219 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
751 9219 : return AWS_OP_SUCCESS;
752 123436 : }
753 123436 :
754 123436 : if (aws_mem_realloc(buffer->allocator, (void **)&buffer->buffer, buffer->capacity, requested_capacity)) {
755 0 : return AWS_OP_ERR;
756 0 : }
757 123436 :
758 123436 : buffer->capacity = requested_capacity;
759 123436 :
760 123436 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
761 123436 : return AWS_OP_SUCCESS;
762 123436 : }
763 :
764 119455 : int aws_byte_buf_reserve_relative(struct aws_byte_buf *buffer, size_t additional_length) {
765 119455 : AWS_ERROR_PRECONDITION(buffer->allocator);
766 119455 : AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
767 119455 :
768 119455 : size_t requested_capacity = 0;
769 119455 : if (AWS_UNLIKELY(aws_add_size_checked(buffer->len, additional_length, &requested_capacity))) {
770 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
771 0 : return AWS_OP_ERR;
772 119455 : }
773 119455 :
774 119455 : return aws_byte_buf_reserve(buffer, requested_capacity);
775 119455 : }
776 :
777 : struct aws_byte_cursor aws_byte_cursor_right_trim_pred(
778 : const struct aws_byte_cursor *source,
779 106155 : aws_byte_predicate_fn *predicate) {
780 106155 : AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
781 106155 : AWS_PRECONDITION(predicate != NULL);
782 106155 : struct aws_byte_cursor trimmed = *source;
783 106155 :
784 256647 : while (trimmed.len > 0 && predicate(*(trimmed.ptr + trimmed.len - 1))) {
785 150492 : --trimmed.len;
786 150492 : }
787 106155 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
788 106155 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
789 106155 : return trimmed;
790 106155 : }
791 :
792 : struct aws_byte_cursor aws_byte_cursor_left_trim_pred(
793 : const struct aws_byte_cursor *source,
794 161425 : aws_byte_predicate_fn *predicate) {
795 161425 : AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
796 161425 : AWS_PRECONDITION(predicate != NULL);
797 161425 : struct aws_byte_cursor trimmed = *source;
798 161425 :
799 442777 : while (trimmed.len > 0 && predicate(*(trimmed.ptr))) {
800 281352 : --trimmed.len;
801 281352 : ++trimmed.ptr;
802 281352 : }
803 161425 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
804 161425 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
805 161425 : return trimmed;
806 161425 : }
807 :
808 : struct aws_byte_cursor aws_byte_cursor_trim_pred(
809 : const struct aws_byte_cursor *source,
810 55875 : aws_byte_predicate_fn *predicate) {
811 55875 : AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
812 55875 : AWS_PRECONDITION(predicate != NULL);
813 55875 : struct aws_byte_cursor left_trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
814 55875 : struct aws_byte_cursor dest = aws_byte_cursor_right_trim_pred(&left_trimmed, predicate);
815 55875 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
816 55875 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&dest));
817 55875 : return dest;
818 55875 : }
819 :
820 52071 : bool aws_byte_cursor_satisfies_pred(const struct aws_byte_cursor *source, aws_byte_predicate_fn *predicate) {
821 52071 : struct aws_byte_cursor trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
822 52071 : bool rval = (trimmed.len == 0);
823 52071 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
824 52071 : return rval;
825 52071 : }
826 :
827 62530 : int aws_byte_cursor_compare_lexical(const struct aws_byte_cursor *lhs, const struct aws_byte_cursor *rhs) {
828 62530 : AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
829 62530 : AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
830 62530 : /* make sure we don't pass NULL pointers to memcmp */
831 62530 : AWS_PRECONDITION(lhs->ptr != NULL);
832 62530 : AWS_PRECONDITION(rhs->ptr != NULL);
833 62530 : size_t comparison_length = lhs->len;
834 62530 : if (comparison_length > rhs->len) {
835 6780 : comparison_length = rhs->len;
836 6780 : }
837 62530 :
838 62530 : int result = memcmp(lhs->ptr, rhs->ptr, comparison_length);
839 62530 :
840 62530 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
841 62530 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
842 62530 : if (result != 0) {
843 0 : return result;
844 0 : }
845 62530 :
846 62530 : if (lhs->len != rhs->len) {
847 8205 : return comparison_length == lhs->len ? -1 : 1;
848 8205 : }
849 54325 :
850 54325 : return 0;
851 54325 : }
852 :
853 : int aws_byte_cursor_compare_lookup(
854 : const struct aws_byte_cursor *lhs,
855 : const struct aws_byte_cursor *rhs,
856 53656 : const uint8_t *lookup_table) {
857 53656 : AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
858 53656 : AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
859 53656 : AWS_PRECONDITION(AWS_MEM_IS_READABLE(lookup_table, 256));
860 53656 : const uint8_t *lhs_curr = lhs->ptr;
861 53656 : const uint8_t *lhs_end = lhs_curr + lhs->len;
862 53656 :
863 53656 : const uint8_t *rhs_curr = rhs->ptr;
864 53656 : const uint8_t *rhs_end = rhs_curr + rhs->len;
865 53656 :
866 164931 : while (lhs_curr < lhs_end && rhs_curr < rhs_end) {
867 111275 : uint8_t lhc = lookup_table[*lhs_curr];
868 111275 : uint8_t rhc = lookup_table[*rhs_curr];
869 111275 :
870 111275 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
871 111275 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
872 111275 : if (lhc < rhc) {
873 0 : return -1;
874 0 : }
875 111275 :
876 111275 : if (lhc > rhc) {
877 0 : return 1;
878 0 : }
879 111275 :
880 111275 : lhs_curr++;
881 111275 : rhs_curr++;
882 111275 : }
883 53656 :
884 53656 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
885 53656 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
886 53656 : if (lhs_curr < lhs_end) {
887 11588 : return 1;
888 11588 : }
889 42068 :
890 42068 : if (rhs_curr < rhs_end) {
891 2264 : return -1;
892 2264 : }
893 39804 :
894 39804 : return 0;
895 39804 : }
896 :
897 : /**
898 : * For creating a byte buffer from a null-terminated string literal.
899 : */
900 138695 : struct aws_byte_buf aws_byte_buf_from_c_str(const char *c_str) {
901 138695 : struct aws_byte_buf buf;
902 138695 : buf.len = (!c_str) ? 0 : strlen(c_str);
903 138695 : buf.capacity = buf.len;
904 138695 : buf.buffer = (buf.capacity == 0) ? NULL : (uint8_t *)c_str;
905 138695 : buf.allocator = NULL;
906 138695 : AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
907 138695 : return buf;
908 138695 : }
909 :
910 50081 : struct aws_byte_buf aws_byte_buf_from_array(const void *bytes, size_t len) {
911 50081 : AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(bytes, len), "Input array [bytes] must be writable up to [len] bytes.");
912 50081 : struct aws_byte_buf buf;
913 50081 : buf.buffer = (len > 0) ? (uint8_t *)bytes : NULL;
914 50081 : buf.len = len;
915 50081 : buf.capacity = len;
916 50081 : buf.allocator = NULL;
917 50081 : AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
918 50081 : return buf;
919 50081 : }
920 :
921 40423 : struct aws_byte_buf aws_byte_buf_from_empty_array(const void *bytes, size_t capacity) {
922 40423 : AWS_PRECONDITION(
923 40423 : AWS_MEM_IS_WRITABLE(bytes, capacity), "Input array [bytes] must be writable up to [capacity] bytes.");
924 40423 : struct aws_byte_buf buf;
925 40423 : buf.buffer = (capacity > 0) ? (uint8_t *)bytes : NULL;
926 40423 : buf.len = 0;
927 40423 : buf.capacity = capacity;
928 40423 : buf.allocator = NULL;
929 40423 : AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
930 40423 : return buf;
931 40423 : }
932 :
933 130001 : struct aws_byte_cursor aws_byte_cursor_from_buf(const struct aws_byte_buf *const buf) {
934 130001 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
935 130001 : struct aws_byte_cursor cur;
936 130001 : cur.ptr = buf->buffer;
937 130001 : cur.len = buf->len;
938 130001 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
939 130001 : return cur;
940 130001 : }
941 :
942 139281 : struct aws_byte_cursor aws_byte_cursor_from_c_str(const char *c_str) {
943 139281 : struct aws_byte_cursor cur;
944 139281 : cur.ptr = (uint8_t *)c_str;
945 139281 : cur.len = (cur.ptr) ? strlen(c_str) : 0;
946 139281 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
947 139281 : return cur;
948 139281 : }
949 :
950 175485 : struct aws_byte_cursor aws_byte_cursor_from_array(const void *const bytes, const size_t len) {
951 175485 : AWS_PRECONDITION(len == 0 || AWS_MEM_IS_READABLE(bytes, len), "Input array [bytes] must be readable up to [len].");
952 175485 : struct aws_byte_cursor cur;
953 175485 : cur.ptr = (uint8_t *)bytes;
954 175485 : cur.len = len;
955 175485 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
956 175485 : return cur;
957 175485 : }
958 :
959 : #ifdef CBMC
960 : # pragma CPROVER check push
961 : # pragma CPROVER check disable "unsigned-overflow"
962 : #endif
963 : /**
964 : * If index >= bound, bound > (SIZE_MAX / 2), or index > (SIZE_MAX / 2), returns
965 : * 0. Otherwise, returns UINTPTR_MAX. This function is designed to return the correct
966 : * value even under CPU speculation conditions, and is intended to be used for
967 : * SPECTRE mitigation purposes.
968 : */
969 229729 : size_t aws_nospec_mask(size_t index, size_t bound) {
970 229729 : /*
971 229729 : * SPECTRE mitigation - we compute a mask that will be zero if len < 0
972 229729 : * or len >= buf->len, and all-ones otherwise, and AND it into the index.
973 229729 : * It is critical that we avoid any branches in this logic.
974 229729 : */
975 229729 :
976 229729 : /*
977 229729 : * Hide the index value from the optimizer. This helps ensure that all this
978 229729 : * logic doesn't get eliminated.
979 229729 : */
980 229729 : #if defined(__GNUC__) || defined(__clang__)
981 229729 : __asm__ __volatile__("" : "+r"(index));
982 229729 : #endif
983 : #if defined(_MSVC_LANG)
984 : /*
985 : * MSVC doesn't have a good way for us to blind the optimizer, and doesn't
986 : * even have inline asm on x64. Some experimentation indicates that this
987 : * hack seems to confuse it sufficiently for our needs.
988 : */
989 : *((volatile uint8_t *)&index) += 0;
990 : #endif
991 :
992 229729 : /*
993 229729 : * If len > (SIZE_MAX / 2), then we can end up with len - buf->len being
994 229729 : * positive simply because the sign bit got inverted away. So we also check
995 229729 : * that the sign bit isn't set from the start.
996 229729 : *
997 229729 : * We also check that bound <= (SIZE_MAX / 2) to catch cases where the
998 229729 : * buffer is _already_ out of bounds.
999 229729 : */
1000 229729 : size_t negative_mask = index | bound;
1001 229729 : size_t toobig_mask = bound - index - (uintptr_t)1;
1002 229729 : size_t combined_mask = negative_mask | toobig_mask;
1003 229729 :
1004 229729 : /*
1005 229729 : * combined_mask needs to have its sign bit OFF for us to be in range.
1006 229729 : * We'd like to expand this to a mask we can AND into our index, so flip
1007 229729 : * that bit (and everything else), shift it over so it's the only bit in the
1008 229729 : * ones position, and multiply across the entire register.
1009 229729 : *
1010 229729 : * First, extract the (inverse) top bit and move it to the lowest bit.
1011 229729 : * Because there's no standard SIZE_BIT in C99, we'll divide by a mask with
1012 229729 : * just the top bit set instead.
1013 229729 : */
1014 229729 :
1015 229729 : combined_mask = (~combined_mask) / (SIZE_MAX - (SIZE_MAX >> 1));
1016 229729 :
1017 229729 : /*
1018 229729 : * Now multiply it to replicate it across all bits.
1019 229729 : *
1020 229729 : * Note that GCC is smart enough to optimize the divide-and-multiply into
1021 229729 : * an arithmetic right shift operation on x86.
1022 229729 : */
1023 229729 : combined_mask = combined_mask * UINTPTR_MAX;
1024 229729 :
1025 229729 : return combined_mask;
1026 229729 : }
1027 : #ifdef CBMC
1028 : # pragma CPROVER check pop
1029 : #endif
1030 :
1031 : /**
1032 : * Tests if the given aws_byte_cursor has at least len bytes remaining. If so,
1033 : * *buf is advanced by len bytes (incrementing ->ptr and decrementing ->len),
1034 : * and an aws_byte_cursor referring to the first len bytes of the original *buf
1035 : * is returned. Otherwise, an aws_byte_cursor with ->ptr = NULL, ->len = 0 is
1036 : * returned.
1037 : *
1038 : * Note that if len is above (SIZE_MAX / 2), this function will also treat it as
1039 : * a buffer overflow, and return NULL without changing *buf.
1040 : */
1041 53505 : struct aws_byte_cursor aws_byte_cursor_advance(struct aws_byte_cursor *const cursor, const size_t len) {
1042 53505 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
1043 53505 : struct aws_byte_cursor rv;
1044 53505 : if (cursor->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || len > cursor->len) {
1045 45386 : rv.ptr = NULL;
1046 45386 : rv.len = 0;
1047 45386 : } else {
1048 8119 : rv.ptr = cursor->ptr;
1049 8119 : rv.len = len;
1050 8119 :
1051 8119 : cursor->ptr += len;
1052 8119 : cursor->len -= len;
1053 8119 : }
1054 53505 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
1055 53505 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
1056 53505 : return rv;
1057 53505 : }
1058 :
1059 : /**
1060 : * Behaves identically to aws_byte_cursor_advance, but avoids speculative
1061 : * execution potentially reading out-of-bounds pointers (by returning an
1062 : * empty ptr in such speculated paths).
1063 : *
1064 : * This should generally be done when using an untrusted or
1065 : * data-dependent value for 'len', to avoid speculating into a path where
1066 : * cursor->ptr points outside the true ptr length.
1067 : */
1068 :
1069 269501 : struct aws_byte_cursor aws_byte_cursor_advance_nospec(struct aws_byte_cursor *const cursor, size_t len) {
1070 269501 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
1071 269501 :
1072 269501 : struct aws_byte_cursor rv;
1073 269501 :
1074 269501 : if (len <= cursor->len && len <= (SIZE_MAX >> 1) && cursor->len <= (SIZE_MAX >> 1)) {
1075 185672 : /*
1076 185672 : * If we're speculating past a failed bounds check, null out the pointer. This ensures
1077 185672 : * that we don't try to read past the end of the buffer and leak information about other
1078 185672 : * memory through timing side-channels.
1079 185672 : */
1080 185672 : uintptr_t mask = aws_nospec_mask(len, cursor->len + 1);
1081 185672 :
1082 185672 : /* Make sure we don't speculate-underflow len either */
1083 185672 : len = len & mask;
1084 185672 : cursor->ptr = (uint8_t *)((uintptr_t)cursor->ptr & mask);
1085 185672 : /* Make sure subsequent nospec accesses don't advance ptr past NULL */
1086 185672 : cursor->len = cursor->len & mask;
1087 185672 :
1088 185672 : rv.ptr = cursor->ptr;
1089 185672 : /* Make sure anything acting upon the returned cursor _also_ doesn't advance past NULL */
1090 185672 : rv.len = len & mask;
1091 185672 :
1092 185672 : cursor->ptr += len;
1093 185672 : cursor->len -= len;
1094 222283 : } else {
1095 83829 : rv.ptr = NULL;
1096 83829 : rv.len = 0;
1097 83829 : }
1098 269501 :
1099 269501 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
1100 269501 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
1101 269501 : return rv;
1102 269501 : }
1103 :
1104 : /**
1105 : * Reads specified length of data from byte cursor and copies it to the
1106 : * destination array.
1107 : *
1108 : * On success, returns true and updates the cursor pointer/length accordingly.
1109 : * If there is insufficient space in the cursor, returns false, leaving the
1110 : * cursor unchanged.
1111 : */
1112 234122 : bool aws_byte_cursor_read(struct aws_byte_cursor *AWS_RESTRICT cur, void *AWS_RESTRICT dest, const size_t len) {
1113 234122 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1114 234122 : AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(dest, len));
1115 234122 : if (len == 0) {
1116 14950 : return true;
1117 14950 : }
1118 219172 :
1119 219172 : struct aws_byte_cursor slice = aws_byte_cursor_advance_nospec(cur, len);
1120 219172 :
1121 219172 : if (slice.ptr) {
1122 178813 : memcpy(dest, slice.ptr, len);
1123 178813 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1124 178813 : AWS_POSTCONDITION(AWS_MEM_IS_READABLE(dest, len));
1125 178813 : return true;
1126 40359 : }
1127 40359 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1128 40359 : return false;
1129 40359 : }
1130 :
1131 : /**
1132 : * Reads as many bytes from cursor as size of buffer, and copies them to buffer.
1133 : *
1134 : * On success, returns true and updates the cursor pointer/length accordingly.
1135 : * If there is insufficient space in the cursor, returns false, leaving the
1136 : * cursor unchanged.
1137 : */
1138 : bool aws_byte_cursor_read_and_fill_buffer(
1139 : struct aws_byte_cursor *AWS_RESTRICT cur,
1140 51715 : struct aws_byte_buf *AWS_RESTRICT dest) {
1141 51715 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1142 51715 : AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
1143 51715 : if (aws_byte_cursor_read(cur, dest->buffer, dest->capacity)) {
1144 32487 : dest->len = dest->capacity;
1145 32487 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1146 32487 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1147 32487 : return true;
1148 19228 : }
1149 19228 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1150 19228 : AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1151 19228 : return false;
1152 19228 : }
1153 :
1154 : /**
1155 : * Reads a single byte from cursor, placing it in *var.
1156 : *
1157 : * On success, returns true and updates the cursor pointer/length accordingly.
1158 : * If there is insufficient space in the cursor, returns false, leaving the
1159 : * cursor unchanged.
1160 : */
1161 46628 : bool aws_byte_cursor_read_u8(struct aws_byte_cursor *AWS_RESTRICT cur, uint8_t *AWS_RESTRICT var) {
1162 46628 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1163 46628 : AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(var, 1));
1164 46628 : bool rv = aws_byte_cursor_read(cur, var, 1);
1165 46628 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1166 46628 : return rv;
1167 46628 : }
1168 :
1169 : /**
1170 : * Reads a 16-bit value in network byte order from cur, and places it in host
1171 : * byte order into var.
1172 : *
1173 : * On success, returns true and updates the cursor pointer/length accordingly.
1174 : * If there is insufficient space in the cursor, returns false, leaving the
1175 : * cursor unchanged.
1176 : */
1177 37907 : bool aws_byte_cursor_read_be16(struct aws_byte_cursor *cur, uint16_t *var) {
1178 37907 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1179 37907 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1180 37907 : bool rv = aws_byte_cursor_read(cur, var, 2);
1181 37907 :
1182 37907 : if (AWS_LIKELY(rv)) {
1183 37907 : *var = aws_ntoh16(*var);
1184 37907 : }
1185 37907 :
1186 37907 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1187 37907 : return rv;
1188 37907 : }
1189 :
1190 : /**
1191 : * Reads an unsigned 24-bit value (3 bytes) in network byte order from cur,
1192 : * and places it in host byte order into 32-bit var.
1193 : * Ex: if cur's next 3 bytes are {0xAA, 0xBB, 0xCC}, then var becomes 0x00AABBCC.
1194 : *
1195 : * On success, returns true and updates the cursor pointer/length accordingly.
1196 : * If there is insufficient space in the cursor, returns false, leaving the
1197 : * cursor unchanged.
1198 : */
1199 0 : bool aws_byte_cursor_read_be24(struct aws_byte_cursor *cur, uint32_t *var) {
1200 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1201 0 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1202 0 :
1203 0 : uint8_t *var_bytes = (void *)var;
1204 0 :
1205 0 : /* read into "lower" 3 bytes */
1206 0 : bool rv = aws_byte_cursor_read(cur, &var_bytes[1], 3);
1207 0 :
1208 0 : if (AWS_LIKELY(rv)) {
1209 0 : /* zero out "highest" 4th byte*/
1210 0 : var_bytes[0] = 0;
1211 0 :
1212 0 : *var = aws_ntoh32(*var);
1213 0 : }
1214 0 :
1215 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1216 0 : return rv;
1217 0 : }
1218 :
1219 : /**
1220 : * Reads a 32-bit value in network byte order from cur, and places it in host
1221 : * byte order into var.
1222 : *
1223 : * On success, returns true and updates the cursor pointer/length accordingly.
1224 : * If there is insufficient space in the cursor, returns false, leaving the
1225 : * cursor unchanged.
1226 : */
1227 36198 : bool aws_byte_cursor_read_be32(struct aws_byte_cursor *cur, uint32_t *var) {
1228 36198 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1229 36198 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1230 36198 : bool rv = aws_byte_cursor_read(cur, var, 4);
1231 36198 :
1232 36198 : if (AWS_LIKELY(rv)) {
1233 36198 : *var = aws_ntoh32(*var);
1234 36198 : }
1235 36198 :
1236 36198 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1237 36198 : return rv;
1238 36198 : }
1239 :
1240 : /**
1241 : * Reads a 32-bit value in network byte order from cur, and places it in host
1242 : * byte order into var.
1243 : *
1244 : * On success, returns true and updates the cursor pointer/length accordingly.
1245 : * If there is insufficient space in the cursor, returns false, leaving the
1246 : * cursor unchanged.
1247 : */
1248 0 : bool aws_byte_cursor_read_float_be32(struct aws_byte_cursor *cur, float *var) {
1249 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1250 0 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1251 0 : bool rv = aws_byte_cursor_read(cur, var, sizeof(float));
1252 0 :
1253 0 : if (AWS_LIKELY(rv)) {
1254 0 : *var = aws_ntohf32(*var);
1255 0 : }
1256 0 :
1257 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1258 0 : return rv;
1259 0 : }
1260 :
1261 : /**
1262 : * Reads a 64-bit value in network byte order from cur, and places it in host
1263 : * byte order into var.
1264 : *
1265 : * On success, returns true and updates the cursor pointer/length accordingly.
1266 : * If there is insufficient space in the cursor, returns false, leaving the
1267 : * cursor unchanged.
1268 : */
1269 0 : bool aws_byte_cursor_read_float_be64(struct aws_byte_cursor *cur, double *var) {
1270 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1271 0 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1272 0 : bool rv = aws_byte_cursor_read(cur, var, sizeof(double));
1273 0 :
1274 0 : if (AWS_LIKELY(rv)) {
1275 0 : *var = aws_ntohf64(*var);
1276 0 : }
1277 0 :
1278 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1279 0 : return rv;
1280 0 : }
1281 :
1282 : /**
1283 : * Reads a 64-bit value in network byte order from cur, and places it in host
1284 : * byte order into var.
1285 : *
1286 : * On success, returns true and updates the cursor pointer/length accordingly.
1287 : * If there is insufficient space in the cursor, returns false, leaving the
1288 : * cursor unchanged.
1289 : */
1290 27959 : bool aws_byte_cursor_read_be64(struct aws_byte_cursor *cur, uint64_t *var) {
1291 27959 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1292 27959 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1293 27959 : bool rv = aws_byte_cursor_read(cur, var, sizeof(*var));
1294 27959 :
1295 27959 : if (AWS_LIKELY(rv)) {
1296 27959 : *var = aws_ntoh64(*var);
1297 27959 : }
1298 27959 :
1299 27959 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1300 27959 : return rv;
1301 27959 : }
1302 :
1303 : /* Lookup from '0' -> 0, 'f' -> 0xf, 'F' -> 0xF, etc
1304 : * invalid characters have value 255 */
1305 : /* clang-format off */
1306 : static const uint8_t s_hex_to_num_table[] = {
1307 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1308 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1309 : 255, 255,
1310 : /* 0 - 9 */
1311 : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
1312 : 255, 255, 255, 255, 255, 255, 255,
1313 : /* A - F */
1314 : 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
1315 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1316 : 255, 255, 255,
1317 : /* a - f */
1318 : 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
1319 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1320 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1321 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1322 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1323 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1324 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1325 : 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
1326 : };
1327 : AWS_STATIC_ASSERT(AWS_ARRAY_SIZE(s_hex_to_num_table) == 256);
1328 : /* clang-format on */
1329 :
1330 0 : const uint8_t *aws_lookup_table_hex_to_num_get(void) {
1331 0 : return s_hex_to_num_table;
1332 0 : }
1333 :
1334 0 : bool aws_byte_cursor_read_hex_u8(struct aws_byte_cursor *cur, uint8_t *var) {
1335 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1336 0 : AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1337 0 :
1338 0 : bool success = false;
1339 0 : if (AWS_LIKELY(cur->len >= 2)) {
1340 0 : const uint8_t hi = s_hex_to_num_table[cur->ptr[0]];
1341 0 : const uint8_t lo = s_hex_to_num_table[cur->ptr[1]];
1342 0 :
1343 0 : /* table maps invalid characters to 255 */
1344 0 : if (AWS_LIKELY(hi != 255 && lo != 255)) {
1345 0 : *var = (hi << 4) | lo;
1346 0 : cur->ptr += 2;
1347 0 : cur->len -= 2;
1348 0 : success = true;
1349 0 : }
1350 0 : }
1351 0 :
1352 0 : AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1353 0 : return success;
1354 0 : }
1355 :
1356 : /**
1357 : * Appends a sub-buffer to the specified buffer.
1358 : *
1359 : * If the buffer has at least `len' bytes remaining (buffer->capacity - buffer->len >= len),
1360 : * then buffer->len is incremented by len, and an aws_byte_buf is assigned to *output corresponding
1361 : * to the last len bytes of the input buffer. The aws_byte_buf at *output will have a null
1362 : * allocator, a zero initial length, and a capacity of 'len'. The function then returns true.
1363 : *
1364 : * If there is insufficient space, then this function nulls all fields in *output and returns
1365 : * false.
1366 : */
1367 : bool aws_byte_buf_advance(
1368 : struct aws_byte_buf *const AWS_RESTRICT buffer,
1369 : struct aws_byte_buf *const AWS_RESTRICT output,
1370 55440 : const size_t len) {
1371 55440 : AWS_PRECONDITION(aws_byte_buf_is_valid(buffer));
1372 55440 : AWS_PRECONDITION(aws_byte_buf_is_valid(output));
1373 55440 : if (buffer->capacity - buffer->len >= len) {
1374 7265 : *output = aws_byte_buf_from_array(buffer->buffer + buffer->len, len);
1375 7265 : buffer->len += len;
1376 7265 : output->len = 0;
1377 7265 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1378 7265 : AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1379 7265 : return true;
1380 48175 : } else {
1381 48175 : AWS_ZERO_STRUCT(*output);
1382 48175 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1383 48175 : AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1384 48175 : return false;
1385 48175 : }
1386 55440 : }
1387 :
1388 : /**
1389 : * Write specified number of bytes from array to byte buffer.
1390 : *
1391 : * On success, returns true and updates the buffer length accordingly.
1392 : * If there is insufficient space in the buffer, returns false, leaving the
1393 : * buffer unchanged.
1394 : */
1395 346779 : bool aws_byte_buf_write(struct aws_byte_buf *AWS_RESTRICT buf, const uint8_t *AWS_RESTRICT src, size_t len) {
1396 346779 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1397 346779 : AWS_PRECONDITION(AWS_MEM_IS_READABLE(src, len), "Input array [src] must be readable up to [len] bytes.");
1398 346779 :
1399 346779 : if (len == 0) {
1400 44302 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1401 44302 : return true;
1402 302477 : }
1403 302477 :
1404 302477 : if (buf->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || buf->len + len > buf->capacity) {
1405 112539 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1406 112539 : return false;
1407 189938 : }
1408 189938 :
1409 189938 : memcpy(buf->buffer + buf->len, src, len);
1410 189938 : buf->len += len;
1411 189938 :
1412 189938 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1413 189938 : return true;
1414 189938 : }
1415 :
1416 : /**
1417 : * Copies all bytes from buffer to buffer.
1418 : *
1419 : * On success, returns true and updates the buffer /length accordingly.
1420 : * If there is insufficient space in the buffer, returns false, leaving the
1421 : * buffer unchanged.
1422 : */
1423 48834 : bool aws_byte_buf_write_from_whole_buffer(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_buf src) {
1424 48834 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1425 48834 : AWS_PRECONDITION(aws_byte_buf_is_valid(&src));
1426 48834 : return aws_byte_buf_write(buf, src.buffer, src.len);
1427 48834 : }
1428 :
1429 : /**
1430 : * Copies all bytes from buffer to buffer.
1431 : *
1432 : * On success, returns true and updates the buffer /length accordingly.
1433 : * If there is insufficient space in the buffer, returns false, leaving the
1434 : * buffer unchanged.
1435 : */
1436 41020 : bool aws_byte_buf_write_from_whole_cursor(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_cursor src) {
1437 41020 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1438 41020 : AWS_PRECONDITION(aws_byte_cursor_is_valid(&src));
1439 41020 : return aws_byte_buf_write(buf, src.ptr, src.len);
1440 41020 : }
1441 :
1442 : struct aws_byte_cursor aws_byte_buf_write_to_capacity(
1443 : struct aws_byte_buf *buf,
1444 0 : struct aws_byte_cursor *advancing_cursor) {
1445 0 :
1446 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1447 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(advancing_cursor));
1448 0 :
1449 0 : size_t available = buf->capacity - buf->len;
1450 0 : size_t write_size = aws_min_size(available, advancing_cursor->len);
1451 0 : struct aws_byte_cursor write_cursor = aws_byte_cursor_advance(advancing_cursor, write_size);
1452 0 : aws_byte_buf_write_from_whole_cursor(buf, write_cursor);
1453 0 : return write_cursor;
1454 0 : }
1455 :
1456 : /**
1457 : * Copies one byte to buffer.
1458 : *
1459 : * On success, returns true and updates the cursor /length
1460 : accordingly.
1461 :
1462 : * If there is insufficient space in the cursor, returns false, leaving the
1463 : cursor unchanged.
1464 : */
1465 50887 : bool aws_byte_buf_write_u8(struct aws_byte_buf *AWS_RESTRICT buf, uint8_t c) {
1466 50887 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1467 50887 : return aws_byte_buf_write(buf, &c, 1);
1468 50887 : }
1469 :
1470 : /**
1471 : * Writes one byte repeatedly to buffer (like memset)
1472 : *
1473 : * If there is insufficient space in the buffer, returns false, leaving the
1474 : * buffer unchanged.
1475 : */
1476 0 : bool aws_byte_buf_write_u8_n(struct aws_byte_buf *buf, uint8_t c, size_t count) {
1477 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1478 0 :
1479 0 : if (buf->len > (SIZE_MAX >> 1) || count > (SIZE_MAX >> 1) || buf->len + count > buf->capacity) {
1480 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1481 0 : return false;
1482 0 : }
1483 0 :
1484 0 : memset(buf->buffer + buf->len, c, count);
1485 0 : buf->len += count;
1486 0 :
1487 0 : AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1488 0 : return true;
1489 0 : }
1490 :
1491 : /**
1492 : * Writes a 16-bit integer in network byte order (big endian) to buffer.
1493 : *
1494 : * On success, returns true and updates the cursor /length accordingly.
1495 : * If there is insufficient space in the cursor, returns false, leaving the
1496 : * cursor unchanged.
1497 : */
1498 58165 : bool aws_byte_buf_write_be16(struct aws_byte_buf *buf, uint16_t x) {
1499 58165 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1500 58165 : x = aws_hton16(x);
1501 58165 : return aws_byte_buf_write(buf, (uint8_t *)&x, 2);
1502 58165 : }
1503 :
1504 : /**
1505 : * Writes low 24-bits (3 bytes) of an unsigned integer in network byte order (big endian) to buffer.
1506 : * Ex: If x is 0x00AABBCC then {0xAA, 0xBB, 0xCC} is written to buffer.
1507 : *
1508 : * On success, returns true and updates the buffer /length accordingly.
1509 : * If there is insufficient space in the buffer, or x's value cannot fit in 3 bytes,
1510 : * returns false, leaving the buffer unchanged.
1511 : */
1512 0 : bool aws_byte_buf_write_be24(struct aws_byte_buf *buf, uint32_t x) {
1513 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1514 0 :
1515 0 : if (x > 0x00FFFFFF) {
1516 0 : return false;
1517 0 : }
1518 0 :
1519 0 : uint32_t be32 = aws_hton32(x);
1520 0 : uint8_t *be32_bytes = (uint8_t *)&be32;
1521 0 :
1522 0 : /* write "lower" 3 bytes */
1523 0 : return aws_byte_buf_write(buf, &be32_bytes[1], 3);
1524 0 : }
1525 :
1526 : /**
1527 : * Writes a 32-bit integer in network byte order (big endian) to buffer.
1528 : *
1529 : * On success, returns true and updates the cursor /length accordingly.
1530 : * If there is insufficient space in the cursor, returns false, leaving the
1531 : * cursor unchanged.
1532 : */
1533 53153 : bool aws_byte_buf_write_be32(struct aws_byte_buf *buf, uint32_t x) {
1534 53153 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1535 53153 : x = aws_hton32(x);
1536 53153 : return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1537 53153 : }
1538 :
1539 : /**
1540 : * Writes a 32-bit float in network byte order (big endian) to buffer.
1541 : *
1542 : * On success, returns true and updates the cursor /length accordingly.
1543 : * If there is insufficient space in the cursor, returns false, leaving the
1544 : * cursor unchanged.
1545 : */
1546 0 : bool aws_byte_buf_write_float_be32(struct aws_byte_buf *buf, float x) {
1547 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1548 0 : x = aws_htonf32(x);
1549 0 : return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1550 0 : }
1551 :
1552 : /**
1553 : * Writes a 64-bit integer in network byte order (big endian) to buffer.
1554 : *
1555 : * On success, returns true and updates the cursor /length accordingly.
1556 : * If there is insufficient space in the cursor, returns false, leaving the
1557 : * cursor unchanged.
1558 : */
1559 55318 : bool aws_byte_buf_write_be64(struct aws_byte_buf *buf, uint64_t x) {
1560 55318 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1561 55318 : x = aws_hton64(x);
1562 55318 : return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1563 55318 : }
1564 :
1565 : /**
1566 : * Writes a 64-bit float in network byte order (big endian) to buffer.
1567 : *
1568 : * On success, returns true and updates the cursor /length accordingly.
1569 : * If there is insufficient space in the cursor, returns false, leaving the
1570 : * cursor unchanged.
1571 : */
1572 0 : bool aws_byte_buf_write_float_be64(struct aws_byte_buf *buf, double x) {
1573 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1574 0 : x = aws_htonf64(x);
1575 0 : return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1576 0 : }
1577 :
1578 0 : int aws_byte_buf_append_and_update(struct aws_byte_buf *to, struct aws_byte_cursor *from_and_update) {
1579 0 : AWS_PRECONDITION(aws_byte_buf_is_valid(to));
1580 0 : AWS_PRECONDITION(aws_byte_cursor_is_valid(from_and_update));
1581 0 :
1582 0 : if (aws_byte_buf_append(to, from_and_update)) {
1583 0 : return AWS_OP_ERR;
1584 0 : }
1585 0 :
1586 0 : from_and_update->ptr = to->buffer + (to->len - from_and_update->len);
1587 0 : return AWS_OP_SUCCESS;
1588 0 : }
1589 :
1590 : static struct aws_byte_cursor s_null_terminator_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("\0");
1591 0 : int aws_byte_buf_append_null_terminator(struct aws_byte_buf *buf) {
1592 0 : return aws_byte_buf_append_dynamic(buf, &s_null_terminator_cursor);
1593 0 : }
1594 :
1595 0 : bool aws_isalnum(uint8_t ch) {
1596 0 : return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9');
1597 0 : }
1598 :
1599 0 : bool aws_isalpha(uint8_t ch) {
1600 0 : return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
1601 0 : }
1602 :
1603 0 : bool aws_isdigit(uint8_t ch) {
1604 0 : return (ch >= '0' && ch <= '9');
1605 0 : }
1606 :
1607 0 : bool aws_isxdigit(uint8_t ch) {
1608 0 : return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
1609 0 : }
1610 :
1611 0 : bool aws_isspace(uint8_t ch) {
1612 0 : switch (ch) {
1613 0 : case 0x20: /* ' ' - space */
1614 0 : case 0x09: /* '\t' - horizontal tab */
1615 0 : case 0x0A: /* '\n' - line feed */
1616 0 : case 0x0B: /* '\v' - vertical tab */
1617 0 : case 0x0C: /* '\f' - form feed */
1618 0 : case 0x0D: /* '\r' - carriage return */
1619 0 : return true;
1620 0 : default:
1621 0 : return false;
1622 0 : }
1623 0 : }
|