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