1/*
2 * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16#include <aws/common/byte_buf.h>
17#include <aws/common/private/byte_buf.h>
18
19#include <stdarg.h>
20
21#ifdef _MSC_VER
22/* disables warning non const declared initializers for Microsoft compilers */
23# pragma warning(disable : 4204)
24# pragma warning(disable : 4706)
25#endif
26
27int aws_byte_buf_init(struct aws_byte_buf *buf, struct aws_allocator *allocator, size_t capacity) {
28 AWS_PRECONDITION(buf);
29 AWS_PRECONDITION(allocator);
30
31 buf->buffer = (capacity == 0) ? NULL : aws_mem_acquire(allocator, capacity);
32 if (capacity != 0 && buf->buffer == NULL) {
33 return AWS_OP_ERR;
34 }
35
36 buf->len = 0;
37 buf->capacity = capacity;
38 buf->allocator = allocator;
39 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
40 return AWS_OP_SUCCESS;
41}
42
43int aws_byte_buf_init_copy(struct aws_byte_buf *dest, struct aws_allocator *allocator, const struct aws_byte_buf *src) {
44 AWS_PRECONDITION(allocator);
45 AWS_PRECONDITION(dest);
46 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(src));
47
48 if (!src->buffer) {
49 AWS_ZERO_STRUCT(*dest);
50 dest->allocator = allocator;
51 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
52 return AWS_OP_SUCCESS;
53 }
54
55 *dest = *src;
56 dest->allocator = allocator;
57 dest->buffer = (uint8_t *)aws_mem_acquire(allocator, src->capacity);
58 if (dest->buffer == NULL) {
59 AWS_ZERO_STRUCT(*dest);
60 return AWS_OP_ERR;
61 }
62 memcpy(dest->buffer, src->buffer, src->len);
63 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
64 return AWS_OP_SUCCESS;
65}
66
67bool aws_byte_buf_is_valid(const struct aws_byte_buf *const buf) {
68 return buf && ((buf->capacity == 0 && buf->len == 0 && buf->buffer == NULL) ||
69 (buf->capacity > 0 && buf->len <= buf->capacity && AWS_MEM_IS_WRITABLE(buf->buffer, buf->len)));
70}
71
72bool aws_byte_cursor_is_valid(const struct aws_byte_cursor *cursor) {
73 return cursor &&
74 ((cursor->len == 0) || (cursor->len > 0 && cursor->ptr && AWS_MEM_IS_READABLE(cursor->ptr, cursor->len)));
75}
76
77void aws_byte_buf_reset(struct aws_byte_buf *buf, bool zero_contents) {
78 if (zero_contents) {
79 aws_byte_buf_secure_zero(buf);
80 }
81 buf->len = 0;
82}
83
84void aws_byte_buf_clean_up(struct aws_byte_buf *buf) {
85 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
86 if (buf->allocator && buf->buffer) {
87 aws_mem_release(buf->allocator, (void *)buf->buffer);
88 }
89 buf->allocator = NULL;
90 buf->buffer = NULL;
91 buf->len = 0;
92 buf->capacity = 0;
93}
94
95void aws_byte_buf_secure_zero(struct aws_byte_buf *buf) {
96 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
97 if (buf->buffer) {
98 aws_secure_zero(buf->buffer, buf->capacity);
99 }
100 buf->len = 0;
101 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
102}
103
104void aws_byte_buf_clean_up_secure(struct aws_byte_buf *buf) {
105 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
106 aws_byte_buf_secure_zero(buf);
107 aws_byte_buf_clean_up(buf);
108 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
109}
110
111bool aws_byte_buf_eq(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
112 AWS_PRECONDITION(aws_byte_buf_is_valid(a));
113 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
114 bool rval = aws_array_eq(a->buffer, a->len, b->buffer, b->len);
115 AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
116 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
117 return rval;
118}
119
120bool aws_byte_buf_eq_ignore_case(const struct aws_byte_buf *const a, const struct aws_byte_buf *const b) {
121 AWS_PRECONDITION(aws_byte_buf_is_valid(a));
122 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
123 bool rval = aws_array_eq_ignore_case(a->buffer, a->len, b->buffer, b->len);
124 AWS_POSTCONDITION(aws_byte_buf_is_valid(a));
125 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
126 return rval;
127}
128
129bool aws_byte_buf_eq_c_str(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(buf->buffer, buf->len, c_str);
133 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
134 return rval;
135}
136
137bool aws_byte_buf_eq_c_str_ignore_case(const struct aws_byte_buf *const buf, const char *const c_str) {
138 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
139 AWS_PRECONDITION(c_str != NULL);
140 bool rval = aws_array_eq_c_str_ignore_case(buf->buffer, buf->len, c_str);
141 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
142 return rval;
143}
144
145int aws_byte_buf_init_copy_from_cursor(
146 struct aws_byte_buf *dest,
147 struct aws_allocator *allocator,
148 struct aws_byte_cursor src) {
149 AWS_PRECONDITION(allocator);
150 AWS_PRECONDITION(dest);
151 AWS_ERROR_PRECONDITION(aws_byte_cursor_is_valid(&src));
152
153 AWS_ZERO_STRUCT(*dest);
154
155 dest->buffer = (src.len > 0) ? (uint8_t *)aws_mem_acquire(allocator, src.len) : NULL;
156 if (src.len != 0 && dest->buffer == NULL) {
157 return AWS_OP_ERR;
158 }
159
160 dest->len = src.len;
161 dest->capacity = src.len;
162 dest->allocator = allocator;
163 if (src.len > 0) {
164 memcpy(dest->buffer, src.ptr, src.len);
165 }
166 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
167 return AWS_OP_SUCCESS;
168}
169
170bool aws_byte_cursor_next_split(
171 const struct aws_byte_cursor *AWS_RESTRICT input_str,
172 char split_on,
173 struct aws_byte_cursor *AWS_RESTRICT substr) {
174
175 bool first_run = false;
176 if (!substr->ptr) {
177 first_run = true;
178 substr->ptr = input_str->ptr;
179 substr->len = 0;
180 }
181
182 if (substr->ptr > input_str->ptr + input_str->len) {
183 /* This will hit if the last substring returned was an empty string after terminating split_on. */
184 AWS_ZERO_STRUCT(*substr);
185 return false;
186 }
187
188 /* Calculate first byte to search. */
189 substr->ptr += substr->len;
190 /* Remaining bytes is the number we started with minus the number of bytes already read. */
191 substr->len = input_str->len - (substr->ptr - input_str->ptr);
192
193 if (!first_run && substr->len == 0) {
194 /* This will hit if the string doesn't end with split_on but we're done. */
195 AWS_ZERO_STRUCT(*substr);
196 return false;
197 }
198
199 if (!first_run && *substr->ptr == split_on) {
200 /* If not first rodeo and the character after substr is split_on, skip. */
201 ++substr->ptr;
202 --substr->len;
203
204 if (substr->len == 0) {
205 /* If split character was last in the string, return empty substr. */
206 return true;
207 }
208 }
209
210 uint8_t *new_location = memchr(substr->ptr, split_on, substr->len);
211 if (new_location) {
212
213 /* Character found, update string length. */
214 substr->len = new_location - substr->ptr;
215 }
216
217 return true;
218}
219
220int aws_byte_cursor_split_on_char_n(
221 const struct aws_byte_cursor *AWS_RESTRICT input_str,
222 char split_on,
223 size_t n,
224 struct aws_array_list *AWS_RESTRICT output) {
225 AWS_ASSERT(input_str && input_str->ptr);
226 AWS_ASSERT(output);
227 AWS_ASSERT(output->item_size >= sizeof(struct aws_byte_cursor));
228
229 size_t max_splits = n > 0 ? n : SIZE_MAX;
230 size_t split_count = 0;
231
232 struct aws_byte_cursor substr;
233 AWS_ZERO_STRUCT(substr);
234
235 /* Until we run out of substrs or hit the max split count, keep iterating and pushing into the array list. */
236 while (split_count <= max_splits && aws_byte_cursor_next_split(input_str, split_on, &substr)) {
237
238 if (split_count == max_splits) {
239 /* If this is the last split, take the rest of the string. */
240 substr.len = input_str->len - (substr.ptr - input_str->ptr);
241 }
242
243 if (AWS_UNLIKELY(aws_array_list_push_back(output, (const void *)&substr))) {
244 return AWS_OP_ERR;
245 }
246 ++split_count;
247 }
248
249 return AWS_OP_SUCCESS;
250}
251
252int aws_byte_cursor_split_on_char(
253 const struct aws_byte_cursor *AWS_RESTRICT input_str,
254 char split_on,
255 struct aws_array_list *AWS_RESTRICT output) {
256
257 return aws_byte_cursor_split_on_char_n(input_str, split_on, 0, output);
258}
259
260int aws_byte_cursor_find_exact(
261 const struct aws_byte_cursor *AWS_RESTRICT input_str,
262 const struct aws_byte_cursor *AWS_RESTRICT to_find,
263 struct aws_byte_cursor *first_find) {
264 if (to_find->len > input_str->len) {
265 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
266 }
267
268 if (to_find->len < 1) {
269 return aws_raise_error(AWS_ERROR_SHORT_BUFFER);
270 }
271
272 struct aws_byte_cursor working_cur = *input_str;
273
274 while (working_cur.len) {
275 uint8_t *first_char_location = memchr(working_cur.ptr, (char)*to_find->ptr, working_cur.len);
276
277 if (!first_char_location) {
278 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
279 }
280
281 aws_byte_cursor_advance(&working_cur, first_char_location - working_cur.ptr);
282
283 if (working_cur.len < to_find->len) {
284 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
285 }
286
287 if (!memcmp(working_cur.ptr, to_find->ptr, to_find->len)) {
288 *first_find = working_cur;
289 return AWS_OP_SUCCESS;
290 }
291
292 aws_byte_cursor_advance(&working_cur, 1);
293 }
294
295 return aws_raise_error(AWS_ERROR_STRING_MATCH_NOT_FOUND);
296}
297
298int aws_byte_buf_cat(struct aws_byte_buf *dest, size_t number_of_args, ...) {
299 AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
300
301 va_list ap;
302 va_start(ap, number_of_args);
303
304 for (size_t i = 0; i < number_of_args; ++i) {
305 struct aws_byte_buf *buffer = va_arg(ap, struct aws_byte_buf *);
306 struct aws_byte_cursor cursor = aws_byte_cursor_from_buf(buffer);
307
308 if (aws_byte_buf_append(dest, &cursor)) {
309 va_end(ap);
310 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
311 return AWS_OP_ERR;
312 }
313 }
314
315 va_end(ap);
316 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
317 return AWS_OP_SUCCESS;
318}
319
320bool aws_byte_cursor_eq(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
321 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
322 AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
323 bool rv = aws_array_eq(a->ptr, a->len, b->ptr, b->len);
324 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
325 AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
326 return rv;
327}
328
329bool aws_byte_cursor_eq_ignore_case(const struct aws_byte_cursor *a, const struct aws_byte_cursor *b) {
330 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
331 AWS_PRECONDITION(aws_byte_cursor_is_valid(b));
332 bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->ptr, b->len);
333 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
334 AWS_POSTCONDITION(aws_byte_cursor_is_valid(b));
335 return rv;
336}
337
338/* Every possible uint8_t value, lowercased */
339static const uint8_t s_tolower_table[256] = {
340 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
341 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
342 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 'a',
343 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
344 'x', 'y', 'z', 91, 92, 93, 94, 95, 96, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
345 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 123, 124, 125, 126, 127, 128, 129, 130, 131,
346 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
347 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
348 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
349 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
350 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
351 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255};
352
353const uint8_t *aws_lookup_table_to_lower_get(void) {
354 return s_tolower_table;
355}
356
357bool aws_array_eq_ignore_case(
358 const void *const array_a,
359 const size_t len_a,
360 const void *const array_b,
361 const size_t len_b) {
362 AWS_PRECONDITION(
363 (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
364 AWS_PRECONDITION(
365 (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
366
367 if (len_a != len_b) {
368 return false;
369 }
370
371 const uint8_t *bytes_a = array_a;
372 const uint8_t *bytes_b = array_b;
373 for (size_t i = 0; i < len_a; ++i) {
374 if (s_tolower_table[bytes_a[i]] != s_tolower_table[bytes_b[i]]) {
375 return false;
376 }
377 }
378
379 return true;
380}
381
382bool aws_array_eq(const void *const array_a, const size_t len_a, const void *const array_b, const size_t len_b) {
383 AWS_PRECONDITION(
384 (len_a == 0) || AWS_MEM_IS_READABLE(array_a, len_a), "Input array [array_a] must be readable up to [len_a].");
385 AWS_PRECONDITION(
386 (len_b == 0) || AWS_MEM_IS_READABLE(array_b, len_b), "Input array [array_b] must be readable up to [len_b].");
387
388 if (len_a != len_b) {
389 return false;
390 }
391
392 if (len_a == 0) {
393 return true;
394 }
395
396 return !memcmp(array_a, array_b, len_a);
397}
398
399bool aws_array_eq_c_str_ignore_case(const void *const array, const size_t array_len, const char *const c_str) {
400 AWS_PRECONDITION(
401 array || (array_len == 0),
402 "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
403 AWS_PRECONDITION(c_str != NULL);
404
405 /* Simpler implementation could have been:
406 * return aws_array_eq_ignore_case(array, array_len, c_str, strlen(c_str));
407 * but that would have traversed c_str twice.
408 * This implementation traverses c_str just once. */
409
410 const uint8_t *array_bytes = array;
411 const uint8_t *str_bytes = (const uint8_t *)c_str;
412
413 for (size_t i = 0; i < array_len; ++i) {
414 uint8_t s = str_bytes[i];
415 if (s == '\0') {
416 return false;
417 }
418
419 if (s_tolower_table[array_bytes[i]] != s_tolower_table[s]) {
420 return false;
421 }
422 }
423
424 return str_bytes[array_len] == '\0';
425}
426
427bool aws_array_eq_c_str(const void *const array, const size_t array_len, const char *const c_str) {
428 AWS_PRECONDITION(
429 array || (array_len == 0),
430 "Either input pointer [array_a] mustn't be NULL or input [array_len] mustn't be zero.");
431 AWS_PRECONDITION(c_str != NULL);
432
433 /* Simpler implementation could have been:
434 * return aws_array_eq(array, array_len, c_str, strlen(c_str));
435 * but that would have traversed c_str twice.
436 * This implementation traverses c_str just once. */
437
438 const uint8_t *array_bytes = array;
439 const uint8_t *str_bytes = (const uint8_t *)c_str;
440
441 for (size_t i = 0; i < array_len; ++i) {
442 uint8_t s = str_bytes[i];
443 if (s == '\0') {
444 return false;
445 }
446
447 if (array_bytes[i] != s) {
448 return false;
449 }
450 }
451
452 return str_bytes[array_len] == '\0';
453}
454
455uint64_t aws_hash_array_ignore_case(const void *array, const size_t len) {
456 AWS_PRECONDITION(AWS_MEM_IS_READABLE(array, len));
457 /* FNV-1a: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function */
458 const uint64_t fnv_offset_basis = 0xcbf29ce484222325ULL;
459 const uint64_t fnv_prime = 0x100000001b3ULL;
460
461 const uint8_t *i = array;
462 const uint8_t *end = i + len;
463
464 uint64_t hash = fnv_offset_basis;
465 while (i != end) {
466 const uint8_t lower = s_tolower_table[*i++];
467 hash ^= lower;
468#ifdef CBMC
469# pragma CPROVER check push
470# pragma CPROVER check disable "unsigned-overflow"
471#endif
472 hash *= fnv_prime;
473#ifdef CBMC
474# pragma CPROVER check pop
475#endif
476 }
477 return hash;
478}
479
480uint64_t aws_hash_byte_cursor_ptr_ignore_case(const void *item) {
481 AWS_PRECONDITION(aws_byte_cursor_is_valid(item));
482 const struct aws_byte_cursor *const cursor = item;
483 uint64_t rval = aws_hash_array_ignore_case(cursor->ptr, cursor->len);
484 AWS_POSTCONDITION(aws_byte_cursor_is_valid(item));
485 return rval;
486}
487
488bool aws_byte_cursor_eq_byte_buf(const struct aws_byte_cursor *const a, const struct aws_byte_buf *const b) {
489 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
490 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
491 bool rv = aws_array_eq(a->ptr, a->len, b->buffer, b->len);
492 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
493 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
494 return rv;
495}
496
497bool aws_byte_cursor_eq_byte_buf_ignore_case(
498 const struct aws_byte_cursor *const a,
499 const struct aws_byte_buf *const b) {
500 AWS_PRECONDITION(aws_byte_cursor_is_valid(a));
501 AWS_PRECONDITION(aws_byte_buf_is_valid(b));
502 bool rv = aws_array_eq_ignore_case(a->ptr, a->len, b->buffer, b->len);
503 AWS_POSTCONDITION(aws_byte_cursor_is_valid(a));
504 AWS_POSTCONDITION(aws_byte_buf_is_valid(b));
505 return rv;
506}
507
508bool aws_byte_cursor_eq_c_str(const struct aws_byte_cursor *const cursor, const char *const c_str) {
509 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
510 AWS_PRECONDITION(c_str != NULL);
511 bool rv = aws_array_eq_c_str(cursor->ptr, cursor->len, c_str);
512 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
513 return rv;
514}
515
516bool aws_byte_cursor_eq_c_str_ignore_case(const struct aws_byte_cursor *const cursor, const char *const c_str) {
517 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
518 AWS_PRECONDITION(c_str != NULL);
519 bool rv = aws_array_eq_c_str_ignore_case(cursor->ptr, cursor->len, c_str);
520 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
521 return rv;
522}
523
524int aws_byte_buf_append(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
525 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
526 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
527
528 if (to->capacity - to->len < from->len) {
529 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
530 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
531 return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
532 }
533
534 if (from->len > 0) {
535 /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
536 AWS_ASSERT(from->ptr);
537 AWS_ASSERT(to->buffer);
538 memcpy(to->buffer + to->len, from->ptr, from->len);
539 to->len += from->len;
540 }
541
542 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
543 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
544 return AWS_OP_SUCCESS;
545}
546
547int aws_byte_buf_append_with_lookup(
548 struct aws_byte_buf *AWS_RESTRICT to,
549 const struct aws_byte_cursor *AWS_RESTRICT from,
550 const uint8_t *lookup_table) {
551 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
552 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
553 AWS_PRECONDITION(
554 AWS_MEM_IS_READABLE(lookup_table, 256), "Input array [lookup_table] must be at least 256 bytes long.");
555
556 if (to->capacity - to->len < from->len) {
557 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
558 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
559 return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
560 }
561
562 for (size_t i = 0; i < from->len; ++i) {
563 to->buffer[to->len + i] = lookup_table[from->ptr[i]];
564 }
565
566 if (aws_add_size_checked(to->len, from->len, &to->len)) {
567 return AWS_OP_ERR;
568 }
569
570 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
571 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
572 return AWS_OP_SUCCESS;
573}
574
575int aws_byte_buf_append_dynamic(struct aws_byte_buf *to, const struct aws_byte_cursor *from) {
576 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
577 AWS_PRECONDITION(aws_byte_cursor_is_valid(from));
578 AWS_ERROR_PRECONDITION(to->allocator);
579
580 if (to->capacity - to->len < from->len) {
581 /*
582 * NewCapacity = Max(OldCapacity * 2, OldCapacity + MissingCapacity)
583 */
584 size_t missing_capacity = from->len - (to->capacity - to->len);
585
586 size_t required_capacity = 0;
587 if (aws_add_size_checked(to->capacity, missing_capacity, &required_capacity)) {
588 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
589 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
590 return AWS_OP_ERR;
591 }
592
593 /*
594 * It's ok if this overflows, just clamp to max possible.
595 * In theory this lets us still grow a buffer that's larger than 1/2 size_t space
596 * at least enough to accommodate the append.
597 */
598 size_t growth_capacity = aws_add_size_saturating(to->capacity, to->capacity);
599
600 size_t new_capacity = required_capacity;
601 if (new_capacity < growth_capacity) {
602 new_capacity = growth_capacity;
603 }
604
605 /*
606 * Attempt to resize - we intentionally do not use reserve() in order to preserve
607 * the (unlikely) use case of from and to being the same buffer range.
608 */
609
610 /*
611 * Try the max, but if that fails and the required is smaller, try it in fallback
612 */
613 uint8_t *new_buffer = aws_mem_acquire(to->allocator, new_capacity);
614 if (new_buffer == NULL) {
615 if (new_capacity > required_capacity) {
616 new_capacity = required_capacity;
617 new_buffer = aws_mem_acquire(to->allocator, new_capacity);
618 if (new_buffer == NULL) {
619 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
620 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
621 return AWS_OP_ERR;
622 }
623 } else {
624 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
625 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
626 return AWS_OP_ERR;
627 }
628 }
629
630 /*
631 * Copy old buffer -> new buffer
632 */
633 if (to->len > 0) {
634 memcpy(new_buffer, to->buffer, to->len);
635 }
636 /*
637 * Copy what we actually wanted to append in the first place
638 */
639 if (from->len > 0) {
640 memcpy(new_buffer + to->len, from->ptr, from->len);
641 }
642 /*
643 * Get rid of the old buffer
644 */
645 aws_mem_release(to->allocator, to->buffer);
646
647 /*
648 * Switch to the new buffer
649 */
650 to->buffer = new_buffer;
651 to->capacity = new_capacity;
652 } else {
653 if (from->len > 0) {
654 /* This assert teaches clang-tidy that from->ptr and to->buffer cannot be null in a non-empty buffers */
655 AWS_ASSERT(from->ptr);
656 AWS_ASSERT(to->buffer);
657 memcpy(to->buffer + to->len, from->ptr, from->len);
658 }
659 }
660
661 to->len += from->len;
662
663 AWS_POSTCONDITION(aws_byte_buf_is_valid(to));
664 AWS_POSTCONDITION(aws_byte_cursor_is_valid(from));
665 return AWS_OP_SUCCESS;
666}
667
668int aws_byte_buf_reserve(struct aws_byte_buf *buffer, size_t requested_capacity) {
669 AWS_ERROR_PRECONDITION(buffer->allocator);
670 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
671
672 if (requested_capacity <= buffer->capacity) {
673 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
674 return AWS_OP_SUCCESS;
675 }
676
677 if (aws_mem_realloc(buffer->allocator, (void **)&buffer->buffer, buffer->capacity, requested_capacity)) {
678 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
679 return AWS_OP_ERR;
680 }
681
682 buffer->capacity = requested_capacity;
683
684 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
685 return AWS_OP_SUCCESS;
686}
687
688int aws_byte_buf_reserve_relative(struct aws_byte_buf *buffer, size_t additional_length) {
689 AWS_ERROR_PRECONDITION(buffer->allocator);
690 AWS_ERROR_PRECONDITION(aws_byte_buf_is_valid(buffer));
691
692 size_t requested_capacity = 0;
693 if (AWS_UNLIKELY(aws_add_size_checked(buffer->len, additional_length, &requested_capacity))) {
694 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
695 return AWS_OP_ERR;
696 }
697
698 return aws_byte_buf_reserve(buffer, requested_capacity);
699}
700
701struct aws_byte_cursor aws_byte_cursor_right_trim_pred(
702 const struct aws_byte_cursor *source,
703 aws_byte_predicate_fn *predicate) {
704 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
705 AWS_PRECONDITION(predicate != NULL);
706 struct aws_byte_cursor trimmed = *source;
707
708 while (trimmed.len > 0 && predicate(*(trimmed.ptr + trimmed.len - 1))) {
709 --trimmed.len;
710 }
711 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
712 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
713 return trimmed;
714}
715
716struct aws_byte_cursor aws_byte_cursor_left_trim_pred(
717 const struct aws_byte_cursor *source,
718 aws_byte_predicate_fn *predicate) {
719 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
720 AWS_PRECONDITION(predicate != NULL);
721 struct aws_byte_cursor trimmed = *source;
722
723 while (trimmed.len > 0 && predicate(*(trimmed.ptr))) {
724 --trimmed.len;
725 ++trimmed.ptr;
726 }
727 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
728 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&trimmed));
729 return trimmed;
730}
731
732struct aws_byte_cursor aws_byte_cursor_trim_pred(
733 const struct aws_byte_cursor *source,
734 aws_byte_predicate_fn *predicate) {
735 AWS_PRECONDITION(aws_byte_cursor_is_valid(source));
736 AWS_PRECONDITION(predicate != NULL);
737 struct aws_byte_cursor left_trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
738 struct aws_byte_cursor dest = aws_byte_cursor_right_trim_pred(&left_trimmed, predicate);
739 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
740 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&dest));
741 return dest;
742}
743
744bool aws_byte_cursor_satisfies_pred(const struct aws_byte_cursor *source, aws_byte_predicate_fn *predicate) {
745 struct aws_byte_cursor trimmed = aws_byte_cursor_left_trim_pred(source, predicate);
746 bool rval = (trimmed.len == 0);
747 AWS_POSTCONDITION(aws_byte_cursor_is_valid(source));
748 return rval;
749}
750
751int aws_byte_cursor_compare_lexical(const struct aws_byte_cursor *lhs, const struct aws_byte_cursor *rhs) {
752 AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
753 AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
754 /* make sure we don't pass NULL pointers to memcmp */
755 AWS_PRECONDITION(lhs->ptr != NULL);
756 AWS_PRECONDITION(rhs->ptr != NULL);
757 size_t comparison_length = lhs->len;
758 if (comparison_length > rhs->len) {
759 comparison_length = rhs->len;
760 }
761
762 int result = memcmp(lhs->ptr, rhs->ptr, comparison_length);
763
764 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
765 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
766 if (result != 0) {
767 return result;
768 }
769
770 if (lhs->len != rhs->len) {
771 return comparison_length == lhs->len ? -1 : 1;
772 }
773
774 return 0;
775}
776
777int aws_byte_cursor_compare_lookup(
778 const struct aws_byte_cursor *lhs,
779 const struct aws_byte_cursor *rhs,
780 const uint8_t *lookup_table) {
781 AWS_PRECONDITION(aws_byte_cursor_is_valid(lhs));
782 AWS_PRECONDITION(aws_byte_cursor_is_valid(rhs));
783 AWS_PRECONDITION(AWS_MEM_IS_READABLE(lookup_table, 256));
784 const uint8_t *lhs_curr = lhs->ptr;
785 const uint8_t *lhs_end = lhs_curr + lhs->len;
786
787 const uint8_t *rhs_curr = rhs->ptr;
788 const uint8_t *rhs_end = rhs_curr + rhs->len;
789
790 while (lhs_curr < lhs_end && rhs_curr < rhs_end) {
791 uint8_t lhc = lookup_table[*lhs_curr];
792 uint8_t rhc = lookup_table[*rhs_curr];
793
794 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
795 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
796 if (lhc < rhc) {
797 return -1;
798 }
799
800 if (lhc > rhc) {
801 return 1;
802 }
803
804 lhs_curr++;
805 rhs_curr++;
806 }
807
808 AWS_POSTCONDITION(aws_byte_cursor_is_valid(lhs));
809 AWS_POSTCONDITION(aws_byte_cursor_is_valid(rhs));
810 if (lhs_curr < lhs_end) {
811 return 1;
812 }
813
814 if (rhs_curr < rhs_end) {
815 return -1;
816 }
817
818 return 0;
819}
820
821/**
822 * For creating a byte buffer from a null-terminated string literal.
823 */
824struct aws_byte_buf aws_byte_buf_from_c_str(const char *c_str) {
825 struct aws_byte_buf buf;
826 buf.len = (!c_str) ? 0 : strlen(c_str);
827 buf.capacity = buf.len;
828 buf.buffer = (buf.capacity == 0) ? NULL : (uint8_t *)c_str;
829 buf.allocator = NULL;
830 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
831 return buf;
832}
833
834struct aws_byte_buf aws_byte_buf_from_array(const void *bytes, size_t len) {
835 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(bytes, len), "Input array [bytes] must be writable up to [len] bytes.");
836 struct aws_byte_buf buf;
837 buf.buffer = (len > 0) ? (uint8_t *)bytes : NULL;
838 buf.len = len;
839 buf.capacity = len;
840 buf.allocator = NULL;
841 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
842 return buf;
843}
844
845struct aws_byte_buf aws_byte_buf_from_empty_array(const void *bytes, size_t capacity) {
846 AWS_PRECONDITION(
847 AWS_MEM_IS_WRITABLE(bytes, capacity), "Input array [bytes] must be writable up to [capacity] bytes.");
848 struct aws_byte_buf buf;
849 buf.buffer = (capacity > 0) ? (uint8_t *)bytes : NULL;
850 buf.len = 0;
851 buf.capacity = capacity;
852 buf.allocator = NULL;
853 AWS_POSTCONDITION(aws_byte_buf_is_valid(&buf));
854 return buf;
855}
856
857struct aws_byte_cursor aws_byte_cursor_from_buf(const struct aws_byte_buf *const buf) {
858 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
859 struct aws_byte_cursor cur;
860 cur.ptr = buf->buffer;
861 cur.len = buf->len;
862 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
863 return cur;
864}
865
866struct aws_byte_cursor aws_byte_cursor_from_c_str(const char *c_str) {
867 struct aws_byte_cursor cur;
868 cur.ptr = (uint8_t *)c_str;
869 cur.len = (cur.ptr) ? strlen(c_str) : 0;
870 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
871 return cur;
872}
873
874struct aws_byte_cursor aws_byte_cursor_from_array(const void *const bytes, const size_t len) {
875 AWS_PRECONDITION(len == 0 || AWS_MEM_IS_READABLE(bytes, len), "Input array [bytes] must be readable up to [len].");
876 struct aws_byte_cursor cur;
877 cur.ptr = (uint8_t *)bytes;
878 cur.len = len;
879 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&cur));
880 return cur;
881}
882
883#ifdef CBMC
884# pragma CPROVER check push
885# pragma CPROVER check disable "unsigned-overflow"
886#endif
887/**
888 * If index >= bound, bound > (SIZE_MAX / 2), or index > (SIZE_MAX / 2), returns
889 * 0. Otherwise, returns UINTPTR_MAX. This function is designed to return the correct
890 * value even under CPU speculation conditions, and is intended to be used for
891 * SPECTRE mitigation purposes.
892 */
893size_t aws_nospec_mask(size_t index, size_t bound) {
894 /*
895 * SPECTRE mitigation - we compute a mask that will be zero if len < 0
896 * or len >= buf->len, and all-ones otherwise, and AND it into the index.
897 * It is critical that we avoid any branches in this logic.
898 */
899
900 /*
901 * Hide the index value from the optimizer. This helps ensure that all this
902 * logic doesn't get eliminated.
903 */
904#if defined(__GNUC__) || defined(__clang__)
905 __asm__ __volatile__("" : "+r"(index));
906#endif
907#if defined(_MSVC_LANG)
908 /*
909 * MSVC doesn't have a good way for us to blind the optimizer, and doesn't
910 * even have inline asm on x64. Some experimentation indicates that this
911 * hack seems to confuse it sufficiently for our needs.
912 */
913 *((volatile uint8_t *)&index) += 0;
914#endif
915
916 /*
917 * If len > (SIZE_MAX / 2), then we can end up with len - buf->len being
918 * positive simply because the sign bit got inverted away. So we also check
919 * that the sign bit isn't set from the start.
920 *
921 * We also check that bound <= (SIZE_MAX / 2) to catch cases where the
922 * buffer is _already_ out of bounds.
923 */
924 size_t negative_mask = index | bound;
925 size_t toobig_mask = bound - index - (uintptr_t)1;
926 size_t combined_mask = negative_mask | toobig_mask;
927
928 /*
929 * combined_mask needs to have its sign bit OFF for us to be in range.
930 * We'd like to expand this to a mask we can AND into our index, so flip
931 * that bit (and everything else), shift it over so it's the only bit in the
932 * ones position, and multiply across the entire register.
933 *
934 * First, extract the (inverse) top bit and move it to the lowest bit.
935 * Because there's no standard SIZE_BIT in C99, we'll divide by a mask with
936 * just the top bit set instead.
937 */
938
939 combined_mask = (~combined_mask) / (SIZE_MAX - (SIZE_MAX >> 1));
940
941 /*
942 * Now multiply it to replicate it across all bits.
943 *
944 * Note that GCC is smart enough to optimize the divide-and-multiply into
945 * an arithmetic right shift operation on x86.
946 */
947 combined_mask = combined_mask * UINTPTR_MAX;
948
949 return combined_mask;
950}
951#ifdef CBMC
952# pragma CPROVER check pop
953#endif
954
955/**
956 * Tests if the given aws_byte_cursor has at least len bytes remaining. If so,
957 * *buf is advanced by len bytes (incrementing ->ptr and decrementing ->len),
958 * and an aws_byte_cursor referring to the first len bytes of the original *buf
959 * is returned. Otherwise, an aws_byte_cursor with ->ptr = NULL, ->len = 0 is
960 * returned.
961 *
962 * Note that if len is above (SIZE_MAX / 2), this function will also treat it as
963 * a buffer overflow, and return NULL without changing *buf.
964 */
965struct aws_byte_cursor aws_byte_cursor_advance(struct aws_byte_cursor *const cursor, const size_t len) {
966 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
967 struct aws_byte_cursor rv;
968 if (cursor->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || len > cursor->len) {
969 rv.ptr = NULL;
970 rv.len = 0;
971 } else {
972 rv.ptr = cursor->ptr;
973 rv.len = len;
974
975 cursor->ptr += len;
976 cursor->len -= len;
977 }
978 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
979 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
980 return rv;
981}
982
983/**
984 * Behaves identically to aws_byte_cursor_advance, but avoids speculative
985 * execution potentially reading out-of-bounds pointers (by returning an
986 * empty ptr in such speculated paths).
987 *
988 * This should generally be done when using an untrusted or
989 * data-dependent value for 'len', to avoid speculating into a path where
990 * cursor->ptr points outside the true ptr length.
991 */
992
993struct aws_byte_cursor aws_byte_cursor_advance_nospec(struct aws_byte_cursor *const cursor, size_t len) {
994 AWS_PRECONDITION(aws_byte_cursor_is_valid(cursor));
995
996 struct aws_byte_cursor rv;
997
998 if (len <= cursor->len && len <= (SIZE_MAX >> 1) && cursor->len <= (SIZE_MAX >> 1)) {
999 /*
1000 * If we're speculating past a failed bounds check, null out the pointer. This ensures
1001 * that we don't try to read past the end of the buffer and leak information about other
1002 * memory through timing side-channels.
1003 */
1004 uintptr_t mask = aws_nospec_mask(len, cursor->len + 1);
1005
1006 /* Make sure we don't speculate-underflow len either */
1007 len = len & mask;
1008 cursor->ptr = (uint8_t *)((uintptr_t)cursor->ptr & mask);
1009 /* Make sure subsequent nospec accesses don't advance ptr past NULL */
1010 cursor->len = cursor->len & mask;
1011
1012 rv.ptr = cursor->ptr;
1013 /* Make sure anything acting upon the returned cursor _also_ doesn't advance past NULL */
1014 rv.len = len & mask;
1015
1016 cursor->ptr += len;
1017 cursor->len -= len;
1018 } else {
1019 rv.ptr = NULL;
1020 rv.len = 0;
1021 }
1022
1023 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cursor));
1024 AWS_POSTCONDITION(aws_byte_cursor_is_valid(&rv));
1025 return rv;
1026}
1027
1028/**
1029 * Reads specified length of data from byte cursor and copies it to the
1030 * destination array.
1031 *
1032 * On success, returns true and updates the cursor pointer/length accordingly.
1033 * If there is insufficient space in the cursor, returns false, leaving the
1034 * cursor unchanged.
1035 */
1036bool aws_byte_cursor_read(struct aws_byte_cursor *AWS_RESTRICT cur, void *AWS_RESTRICT dest, const size_t len) {
1037 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1038 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(dest, len));
1039 struct aws_byte_cursor slice = aws_byte_cursor_advance_nospec(cur, len);
1040
1041 if (slice.ptr) {
1042 memcpy(dest, slice.ptr, len);
1043 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1044 AWS_POSTCONDITION(AWS_MEM_IS_READABLE(dest, len));
1045 return true;
1046 }
1047 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1048 return false;
1049}
1050
1051/**
1052 * Reads as many bytes from cursor as size of buffer, and copies them to buffer.
1053 *
1054 * On success, returns true and updates the cursor pointer/length accordingly.
1055 * If there is insufficient space in the cursor, returns false, leaving the
1056 * cursor unchanged.
1057 */
1058bool aws_byte_cursor_read_and_fill_buffer(
1059 struct aws_byte_cursor *AWS_RESTRICT cur,
1060 struct aws_byte_buf *AWS_RESTRICT dest) {
1061 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1062 AWS_PRECONDITION(aws_byte_buf_is_valid(dest));
1063 if (aws_byte_cursor_read(cur, dest->buffer, dest->capacity)) {
1064 dest->len = dest->capacity;
1065 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1066 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1067 return true;
1068 }
1069 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1070 AWS_POSTCONDITION(aws_byte_buf_is_valid(dest));
1071 return false;
1072}
1073
1074/**
1075 * Reads a single byte from cursor, placing it in *var.
1076 *
1077 * On success, returns true and updates the cursor pointer/length accordingly.
1078 * If there is insufficient space in the cursor, returns false, leaving the
1079 * cursor unchanged.
1080 */
1081bool aws_byte_cursor_read_u8(struct aws_byte_cursor *AWS_RESTRICT cur, uint8_t *AWS_RESTRICT var) {
1082 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1083 bool rv = aws_byte_cursor_read(cur, var, 1);
1084 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1085 return rv;
1086}
1087
1088/**
1089 * Reads a 16-bit value in network byte order from cur, and places it in host
1090 * byte order into var.
1091 *
1092 * On success, returns true and updates the cursor pointer/length accordingly.
1093 * If there is insufficient space in the cursor, returns false, leaving the
1094 * cursor unchanged.
1095 */
1096bool aws_byte_cursor_read_be16(struct aws_byte_cursor *cur, uint16_t *var) {
1097 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1098 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1099 bool rv = aws_byte_cursor_read(cur, var, 2);
1100
1101 if (AWS_LIKELY(rv)) {
1102 *var = aws_ntoh16(*var);
1103 }
1104
1105 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1106 return rv;
1107}
1108
1109/**
1110 * Reads a 32-bit value in network byte order from cur, and places it in host
1111 * byte order into var.
1112 *
1113 * On success, returns true and updates the cursor pointer/length accordingly.
1114 * If there is insufficient space in the cursor, returns false, leaving the
1115 * cursor unchanged.
1116 */
1117bool aws_byte_cursor_read_be32(struct aws_byte_cursor *cur, uint32_t *var) {
1118 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1119 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1120 bool rv = aws_byte_cursor_read(cur, var, 4);
1121
1122 if (AWS_LIKELY(rv)) {
1123 *var = aws_ntoh32(*var);
1124 }
1125
1126 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1127 return rv;
1128}
1129
1130/**
1131 * Reads a 32-bit value in network byte order from cur, and places it in host
1132 * byte order into var.
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 */
1138bool aws_byte_cursor_read_float_be32(struct aws_byte_cursor *cur, float *var) {
1139 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1140 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1141 bool rv = aws_byte_cursor_read(cur, var, sizeof(float));
1142
1143 if (AWS_LIKELY(rv)) {
1144 *var = aws_ntohf32(*var);
1145 }
1146
1147 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1148 return rv;
1149}
1150
1151/**
1152 * Reads a 64-bit value in network byte order from cur, and places it in host
1153 * byte order into var.
1154 *
1155 * On success, returns true and updates the cursor pointer/length accordingly.
1156 * If there is insufficient space in the cursor, returns false, leaving the
1157 * cursor unchanged.
1158 */
1159bool aws_byte_cursor_read_float_be64(struct aws_byte_cursor *cur, double *var) {
1160 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1161 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1162 bool rv = aws_byte_cursor_read(cur, var, sizeof(double));
1163
1164 if (AWS_LIKELY(rv)) {
1165 *var = aws_ntohf64(*var);
1166 }
1167
1168 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1169 return rv;
1170}
1171
1172/**
1173 * Reads a 64-bit value in network byte order from cur, and places it in host
1174 * byte order into var.
1175 *
1176 * On success, returns true and updates the cursor pointer/length accordingly.
1177 * If there is insufficient space in the cursor, returns false, leaving the
1178 * cursor unchanged.
1179 */
1180bool aws_byte_cursor_read_be64(struct aws_byte_cursor *cur, uint64_t *var) {
1181 AWS_PRECONDITION(aws_byte_cursor_is_valid(cur));
1182 AWS_PRECONDITION(AWS_OBJECT_PTR_IS_WRITABLE(var));
1183 bool rv = aws_byte_cursor_read(cur, var, sizeof(*var));
1184
1185 if (AWS_LIKELY(rv)) {
1186 *var = aws_ntoh64(*var);
1187 }
1188
1189 AWS_POSTCONDITION(aws_byte_cursor_is_valid(cur));
1190 return rv;
1191}
1192
1193/**
1194 * Appends a sub-buffer to the specified buffer.
1195 *
1196 * If the buffer has at least `len' bytes remaining (buffer->capacity - buffer->len >= len),
1197 * then buffer->len is incremented by len, and an aws_byte_buf is assigned to *output corresponding
1198 * to the last len bytes of the input buffer. The aws_byte_buf at *output will have a null
1199 * allocator, a zero initial length, and a capacity of 'len'. The function then returns true.
1200 *
1201 * If there is insufficient space, then this function nulls all fields in *output and returns
1202 * false.
1203 */
1204bool aws_byte_buf_advance(
1205 struct aws_byte_buf *const AWS_RESTRICT buffer,
1206 struct aws_byte_buf *const AWS_RESTRICT output,
1207 const size_t len) {
1208 AWS_PRECONDITION(aws_byte_buf_is_valid(buffer));
1209 AWS_PRECONDITION(aws_byte_buf_is_valid(output));
1210 if (buffer->capacity - buffer->len >= len) {
1211 *output = aws_byte_buf_from_array(buffer->buffer + buffer->len, len);
1212 buffer->len += len;
1213 output->len = 0;
1214 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1215 AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1216 return true;
1217 } else {
1218 AWS_ZERO_STRUCT(*output);
1219 AWS_POSTCONDITION(aws_byte_buf_is_valid(buffer));
1220 AWS_POSTCONDITION(aws_byte_buf_is_valid(output));
1221 return false;
1222 }
1223}
1224
1225/**
1226 * Write specified number of bytes from array to byte buffer.
1227 *
1228 * On success, returns true and updates the buffer length accordingly.
1229 * If there is insufficient space in the buffer, returns false, leaving the
1230 * buffer unchanged.
1231 */
1232bool aws_byte_buf_write(struct aws_byte_buf *AWS_RESTRICT buf, const uint8_t *AWS_RESTRICT src, size_t len) {
1233 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1234 AWS_PRECONDITION(AWS_MEM_IS_WRITABLE(src, len), "Input array [src] must be readable up to [len] bytes.");
1235
1236 if (buf->len > (SIZE_MAX >> 1) || len > (SIZE_MAX >> 1) || buf->len + len > buf->capacity) {
1237 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1238 return false;
1239 }
1240
1241 memcpy(buf->buffer + buf->len, src, len);
1242 buf->len += len;
1243
1244 AWS_POSTCONDITION(aws_byte_buf_is_valid(buf));
1245 return true;
1246}
1247
1248/**
1249 * Copies all bytes from buffer to buffer.
1250 *
1251 * On success, returns true and updates the buffer /length accordingly.
1252 * If there is insufficient space in the buffer, returns false, leaving the
1253 * buffer unchanged.
1254 */
1255bool aws_byte_buf_write_from_whole_buffer(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_buf src) {
1256 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1257 AWS_PRECONDITION(aws_byte_buf_is_valid(&src));
1258 return aws_byte_buf_write(buf, src.buffer, src.len);
1259}
1260
1261/**
1262 * Copies all bytes from buffer to buffer.
1263 *
1264 * On success, returns true and updates the buffer /length accordingly.
1265 * If there is insufficient space in the buffer, returns false, leaving the
1266 * buffer unchanged.
1267 */
1268bool aws_byte_buf_write_from_whole_cursor(struct aws_byte_buf *AWS_RESTRICT buf, struct aws_byte_cursor src) {
1269 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1270 AWS_PRECONDITION(aws_byte_cursor_is_valid(&src));
1271 return aws_byte_buf_write(buf, src.ptr, src.len);
1272}
1273
1274/**
1275 * Copies one byte to buffer.
1276 *
1277 * On success, returns true and updates the cursor /length
1278 accordingly.
1279
1280 * If there is insufficient space in the cursor, returns false, leaving the
1281 cursor unchanged.
1282 */
1283bool aws_byte_buf_write_u8(struct aws_byte_buf *AWS_RESTRICT buf, uint8_t c) {
1284 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1285 return aws_byte_buf_write(buf, &c, 1);
1286}
1287
1288/**
1289 * Writes a 16-bit integer in network byte order (big endian) to buffer.
1290 *
1291 * On success, returns true and updates the cursor /length accordingly.
1292 * If there is insufficient space in the cursor, returns false, leaving the
1293 * cursor unchanged.
1294 */
1295bool aws_byte_buf_write_be16(struct aws_byte_buf *buf, uint16_t x) {
1296 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1297 x = aws_hton16(x);
1298 return aws_byte_buf_write(buf, (uint8_t *)&x, 2);
1299}
1300
1301/**
1302 * Writes a 32-bit integer in network byte order (big endian) to buffer.
1303 *
1304 * On success, returns true and updates the cursor /length accordingly.
1305 * If there is insufficient space in the cursor, returns false, leaving the
1306 * cursor unchanged.
1307 */
1308bool aws_byte_buf_write_be32(struct aws_byte_buf *buf, uint32_t x) {
1309 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1310 x = aws_hton32(x);
1311 return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1312}
1313
1314/**
1315 * Writes a 32-bit float in network byte order (big endian) to buffer.
1316 *
1317 * On success, returns true and updates the cursor /length accordingly.
1318 * If there is insufficient space in the cursor, returns false, leaving the
1319 * cursor unchanged.
1320 */
1321bool aws_byte_buf_write_float_be32(struct aws_byte_buf *buf, float x) {
1322 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1323 x = aws_htonf32(x);
1324 return aws_byte_buf_write(buf, (uint8_t *)&x, 4);
1325}
1326
1327/**
1328 * Writes a 64-bit integer in network byte order (big endian) to buffer.
1329 *
1330 * On success, returns true and updates the cursor /length accordingly.
1331 * If there is insufficient space in the cursor, returns false, leaving the
1332 * cursor unchanged.
1333 */
1334bool aws_byte_buf_write_be64(struct aws_byte_buf *buf, uint64_t x) {
1335 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1336 x = aws_hton64(x);
1337 return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1338}
1339
1340/**
1341 * Writes a 64-bit float in network byte order (big endian) to buffer.
1342 *
1343 * On success, returns true and updates the cursor /length accordingly.
1344 * If there is insufficient space in the cursor, returns false, leaving the
1345 * cursor unchanged.
1346 */
1347bool aws_byte_buf_write_float_be64(struct aws_byte_buf *buf, double x) {
1348 AWS_PRECONDITION(aws_byte_buf_is_valid(buf));
1349 x = aws_htonf64(x);
1350 return aws_byte_buf_write(buf, (uint8_t *)&x, 8);
1351}
1352
1353int aws_byte_buf_append_and_update(struct aws_byte_buf *to, struct aws_byte_cursor *from_and_update) {
1354 AWS_PRECONDITION(aws_byte_buf_is_valid(to));
1355 AWS_PRECONDITION(aws_byte_cursor_is_valid(from_and_update));
1356
1357 if (aws_byte_buf_append(to, from_and_update)) {
1358 return AWS_OP_ERR;
1359 }
1360
1361 from_and_update->ptr = to->buffer + (to->len - from_and_update->len);
1362 return AWS_OP_SUCCESS;
1363}
1364