diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 5213866ad..988817fc1 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -437,7 +437,7 @@ bs_set(char *buf, int len) #endif zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_set_state_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm), @@ -655,7 +655,7 @@ bs_upload(char *buf, int len) #endif zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); struct zcbor_map_decode_key_val image_upload_decode[] = { ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num_tmp), @@ -908,7 +908,7 @@ bs_echo(char *buf, int len) uint32_t rc = MGMT_ERR_EINVAL; zcbor_state_t zsd[4]; - zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1); + zcbor_new_state(zsd, sizeof(zsd) / sizeof(zcbor_state_t), (uint8_t *)buf, len, 1, NULL, 0); if (!zcbor_map_start_decode(zsd)) { goto out; @@ -932,7 +932,7 @@ bs_echo(char *buf, int len) } zcbor_map_start_encode(cbor_state, 10); - zcbor_tstr_put_term(cbor_state, "r"); + zcbor_tstr_put_lit(cbor_state, "r"); if (zcbor_tstr_encode(cbor_state, &value) && zcbor_map_end_encode(cbor_state, 10)) { boot_serial_output(); return; diff --git a/boot/zcbor/add_zcbor_copy_version.sh b/boot/zcbor/add_zcbor_copy_version.sh index dc49887c0..a88ebf901 100755 --- a/boot/zcbor/add_zcbor_copy_version.sh +++ b/boot/zcbor/add_zcbor_copy_version.sh @@ -20,3 +20,5 @@ add_copy_notice src/zcbor_common.c "copied" add_copy_notice include/zcbor_decode.h "copied" add_copy_notice include/zcbor_encode.h "copied" add_copy_notice include/zcbor_common.h "copied" +add_copy_notice include/zcbor_print.h "copied" +add_copy_notice include/zcbor_tags.h "copied" diff --git a/boot/zcbor/include/zcbor_common.h b/boot/zcbor/include/zcbor_common.h index f44ded6ad..0583ab893 100644 --- a/boot/zcbor/include/zcbor_common.h +++ b/boot/zcbor/include/zcbor_common.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -15,11 +15,30 @@ #include #include #include +#include +#include "zcbor_tags.h" #ifdef __cplusplus extern "C" { #endif +#define ZCBOR_STRINGIFY_PRE(x) #x +#define ZCBOR_STRINGIFY(s) ZCBOR_STRINGIFY_PRE(s) + +#define ZCBOR_VERSION_MAJOR 0 +#define ZCBOR_VERSION_MINOR 8 +#define ZCBOR_VERSION_BUGFIX 1 + +/** The version string with dots and not prefix. */ +#define ZCBOR_VERSION_STR ZCBOR_STRINGIFY(ZCBOR_VERSION_MAJOR) \ + "." ZCBOR_STRINGIFY(ZCBOR_VERSION_MINOR) \ + "." ZCBOR_STRINGIFY(ZCBOR_VERSION_BUGFIX) + +/** Monotonically increasing integer representing the version. */ +#define ZCBOR_VERSION ((ZCBOR_VERSION_MAJOR << 24) \ + + (ZCBOR_VERSION_MINOR << 16) \ + + (ZCBOR_VERSION_BUGFIX << 8)) + /** Convenience type that allows pointing to strings directly inside the payload * without the need to copy out. */ @@ -43,54 +62,25 @@ struct zcbor_string_fragment { /** Size to use in struct zcbor_string_fragment when the real size is unknown. */ #define ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH SIZE_MAX -#ifdef ZCBOR_VERBOSE -#include -#define zcbor_trace() (printk("bytes left: %zu, byte: 0x%x, elem_count: 0x%" PRIxFAST32 ", err: %d, %s:%d\n",\ - (size_t)state->payload_end - (size_t)state->payload, *state->payload, state->elem_count, \ - state->constant_state ? state->constant_state->error : 0, __FILE__, __LINE__)) - -#define zcbor_print_assert(expr, ...) \ -do { \ - printk("ASSERTION \n \"" #expr \ - "\"\nfailed at %s:%d with message:\n ", \ - __FILE__, __LINE__); \ - printk(__VA_ARGS__);\ -} while(0) -#define zcbor_print(...) printk(__VA_ARGS__) -#else -#define zcbor_trace() ((void)state) -#define zcbor_print_assert(...) -#define zcbor_print(...) -#endif - -#ifdef ZCBOR_ASSERTS -#define zcbor_assert(expr, ...) \ -do { \ - if (!(expr)) { \ - zcbor_print_assert(expr, __VA_ARGS__); \ - ZCBOR_FAIL(); \ - } \ -} while(0) -#define zcbor_assert_state(expr, ...) \ -do { \ - if (!(expr)) { \ - zcbor_print_assert(expr, __VA_ARGS__); \ - ZCBOR_ERR(ZCBOR_ERR_ASSERTION); \ - } \ -} while(0) -#else -#define zcbor_assert(expr, ...) -#define zcbor_assert_state(expr, ...) -#endif - #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif +#ifndef MAX +#define MAX(a, b) (((a) < (b)) ? (b) : (a)) +#endif + #ifndef ZCBOR_ARRAY_SIZE #define ZCBOR_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif +/* Endian-dependent offset of smaller integer in a bigger one. */ +#ifdef ZCBOR_BIG_ENDIAN +#define ZCBOR_ECPY_OFFS(dst_len, src_len) ((dst_len) - (src_len)) +#else +#define ZCBOR_ECPY_OFFS(dst_len, src_len) (0) +#endif /* ZCBOR_BIG_ENDIAN */ + #if SIZE_MAX <= UINT64_MAX /** The ZCBOR_SUPPORTS_SIZE_T will be defined if processing of size_t type variables directly * with zcbor_size_ functions is supported. @@ -102,6 +92,7 @@ do { \ struct zcbor_state_constant; +/** The zcbor_state_t structure is used for both encoding and decoding. */ typedef struct { union { uint8_t *payload_mut; @@ -110,31 +101,59 @@ union { processed. */ }; uint8_t const *payload_bak; /**< Temporary backup of payload. */ - uint_fast32_t elem_count; /**< The current element is part of a LIST or a MAP, - and this keeps count of how many elements are - expected. This will be checked before processing - and decremented if the element is correctly - processed. */ + size_t elem_count; /**< The current element is part of a LIST or a MAP, + and this keeps count of how many elements are + expected. This will be checked before processing + and decremented if the element is correctly + processed. */ uint8_t const *payload_end; /**< The end of the payload. This will be checked against payload before processing each element. */ - bool indefinite_length_array; /**< Is set to true if the decoder is currently - decoding the contents of an indefinite- - length array. */ bool payload_moved; /**< Is set to true while the state is stored as a backup if @ref zcbor_update_state is called, since that function updates the payload_end of all backed-up states. */ + +/* This is the "decode state", the part of zcbor_state_t that is only used by zcbor_decode.c. */ +struct { + bool indefinite_length_array; /**< Is set to true if the decoder is currently + decoding the contents of an indefinite- + length array. */ + bool counting_map_elems; /**< Is set to true while the number of elements of the + current map are being counted. */ +#ifdef ZCBOR_MAP_SMART_SEARCH + uint8_t *map_search_elem_state; /**< Optional flags to use when searching unordered + maps. If this is not NULL and map_elem_count + is non-zero, this consists of one flag per element + in the current map. The n-th bit can be set to 0 + to indicate that the n-th element in the + map should not be searched. These are manipulated + via zcbor_elem_processed() or + zcbor_unordered_map_search(), and should not be + manipulated directly. */ +#else + size_t map_elems_processed; /**< The number of elements of an unordered map + that have been processed. */ +#endif + size_t map_elem_count; /**< Number of elements in the current unordered map. + This also serves as the number of bits (not bytes) + in the map_search_elem_state array (when applicable). */ +} decode_state; struct zcbor_state_constant *constant_state; /**< The part of the state that is not backed up and duplicated. */ } zcbor_state_t; struct zcbor_state_constant { zcbor_state_t *backup_list; - uint_fast32_t current_backup; - uint_fast32_t num_backups; + size_t current_backup; + size_t num_backups; int error; #ifdef ZCBOR_STOP_ON_ERROR bool stop_on_error; +#endif + bool manually_process_elem; /**< Whether an (unordered map) element should be automatically + marked as processed when found via @ref zcbor_search_map_key. */ +#ifdef ZCBOR_MAP_SMART_SEARCH + uint8_t *map_search_elem_state_end; /**< The end of the @ref map_search_elem_state buffer. */ #endif }; @@ -152,27 +171,42 @@ typedef bool(zcbor_decoder_t)(zcbor_state_t *, void *); */ typedef enum { - ZCBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer - ZCBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer - ZCBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String - ZCBOR_MAJOR_TYPE_TSTR = 3, ///! Text String - ZCBOR_MAJOR_TYPE_LIST = 4, ///! List - ZCBOR_MAJOR_TYPE_MAP = 5, ///! Map - ZCBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag - ZCBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type + ZCBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer + ZCBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer + ZCBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String + ZCBOR_MAJOR_TYPE_TSTR = 3, ///! Text String + ZCBOR_MAJOR_TYPE_LIST = 4, ///! List + ZCBOR_MAJOR_TYPE_MAP = 5, ///! Map + ZCBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag + ZCBOR_MAJOR_TYPE_SIMPLE = 7, ///! Simple values and floats } zcbor_major_type_t; +/** Extract the major type, i.e. the first 3 bits of the header byte. */ +#define ZCBOR_MAJOR_TYPE(header_byte) ((zcbor_major_type_t)(((header_byte) >> 5) & 0x7)) + +/** Extract the additional info, i.e. the last 5 bits of the header byte. */ +#define ZCBOR_ADDITIONAL(header_byte) ((header_byte) & 0x1F) /** Convenience macro for failing out of a decoding/encoding function. */ #define ZCBOR_FAIL() \ do {\ - zcbor_trace(); \ + zcbor_log("ZCBOR_FAIL "); \ + zcbor_trace_file(state); \ return false; \ } while(0) +#define ZCBOR_FAIL_IF(expr) \ +do {\ + if (expr) { \ + zcbor_log("ZCBOR_FAIL_IF(" #expr ") "); \ + ZCBOR_FAIL(); \ + } \ +} while(0) + #define ZCBOR_ERR(err) \ do { \ + zcbor_log("ZCBOR_ERR(%d) ", err); \ zcbor_error(state, err); \ ZCBOR_FAIL(); \ } while(0) @@ -180,6 +214,7 @@ do { \ #define ZCBOR_ERR_IF(expr, err) \ do {\ if (expr) { \ + zcbor_log("ZCBOR_ERR_IF(" #expr ", %d) ", err); \ ZCBOR_ERR(err); \ } \ } while(0) @@ -205,11 +240,12 @@ do { \ #define ZCBOR_VALUE_IS_8_BYTES 27 ///! The next 8 bytes contain the value. #define ZCBOR_VALUE_IS_INDEFINITE_LENGTH 31 ///! The list or map has indefinite length, and will instead be terminated by a 0xFF token. -#define ZCBOR_BOOL_TO_PRIM ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 +#define ZCBOR_BOOL_TO_SIMPLE ((uint8_t)20) ///! In CBOR, false/true have the values 20/21 #define ZCBOR_FLAG_RESTORE 1UL ///! Restore from the backup. Overwrite the current state with the state from the backup. #define ZCBOR_FLAG_CONSUME 2UL ///! Consume the backup. Remove the backup from the stack of backups. -#define ZCBOR_FLAG_TRANSFER_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. +#define ZCBOR_FLAG_KEEP_PAYLOAD 4UL ///! Keep the pre-restore payload after restoring. +#define ZCBOR_FLAG_KEEP_DECODE_STATE 8UL ///! Keep the pre-restore decode state (everything only used for decoding) #define ZCBOR_SUCCESS 0 #define ZCBOR_ERR_NO_BACKUP_MEM 1 @@ -226,47 +262,30 @@ do { \ #define ZCBOR_ERR_WRONG_RANGE 12 #define ZCBOR_ERR_ITERATIONS 13 #define ZCBOR_ERR_ASSERTION 14 +#define ZCBOR_ERR_PAYLOAD_OUTDATED 15 ///! Because of a call to @ref zcbor_update_state +#define ZCBOR_ERR_ELEM_NOT_FOUND 16 +#define ZCBOR_ERR_MAP_MISALIGNED 17 +#define ZCBOR_ERR_ELEMS_NOT_PROCESSED 18 +#define ZCBOR_ERR_NOT_AT_END 19 +#define ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE 20 +#define ZCBOR_ERR_INVALID_VALUE_ENCODING 21 ///! When ZCBOR_CANONICAL is defined, and the incoming data is not encoded with minimal length. #define ZCBOR_ERR_UNKNOWN 31 /** The largest possible elem_count. */ -#ifdef UINT_FAST32_MAX -#define ZCBOR_MAX_ELEM_COUNT UINT_FAST32_MAX -#else -#define ZCBOR_MAX_ELEM_COUNT ((uint_fast32_t)(-1L)) -#endif +#define ZCBOR_MAX_ELEM_COUNT SIZE_MAX /** Initial value for elem_count for when it just needs to be large. */ -#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 16) - - -/** Values defined by RFC8949 via www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */ -enum zcbor_rfc8949_tag { - ZCBOR_TAG_TIME_TSTR = 0, ///! text string Standard date/time string - ZCBOR_TAG_TIME_NUM = 1, ///! integer or float Epoch-based date/time - ZCBOR_TAG_UBIGNUM_BSTR = 2, ///! byte string Unsigned bignum - ZCBOR_TAG_BIGNUM_BSTR = 3, ///! byte string Negative bignum - ZCBOR_TAG_DECFRAC_ARR = 4, ///! array Decimal fraction - ZCBOR_TAG_BIGFLOAT_ARR = 5, ///! array Bigfloat - ZCBOR_TAG_2BASE64URL = 21, ///! (any) Expected conversion to base64url encoding - ZCBOR_TAG_2BASE64 = 22, ///! (any) Expected conversion to base64 encoding - ZCBOR_TAG_2BASE16 = 23, ///! (any) Expected conversion to base16 encoding - ZCBOR_TAG_BSTR = 24, ///! byte string Encoded CBOR data item - ZCBOR_TAG_URI_TSTR = 32, ///! text string URI - ZCBOR_TAG_BASE64URL_TSTR = 33, ///! text string base64url - ZCBOR_TAG_BASE64_TSTR = 34, ///! text string base64 - ZCBOR_TAG_MIME_TSTR = 36, ///! text string MIME message - ZCBOR_TAG_CBOR = 55799, ///! (any) Self-described CBOR -}; +#define ZCBOR_LARGE_ELEM_COUNT (ZCBOR_MAX_ELEM_COUNT - 15) /** Take a backup of the current state. Overwrite the current elem_count. */ -bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count); +bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count); /** Consult the most recent backup. In doing so, check whether elem_count is * less than or equal to max_elem_count. * Also, take action based on the flags (See ZCBOR_FLAG_*). */ -bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, uint_fast32_t max_elem_count); +bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, size_t max_elem_count); /** Convenience function for starting encoding/decoding of a union. * @@ -294,17 +313,30 @@ bool zcbor_union_end_code(zcbor_state_t *state); * If there is no struct zcbor_state_constant (n_states == 1), error codes are * not available. * This means that you get a state with (n_states - 2) backups. - * payload, payload_len, and elem_count are used to initialize the first state. - * in the array, which is the state that can be passed to cbor functions. + * payload, payload_len, elem_count, and elem_state are used to initialize the first state. + * The elem_state is only needed for unordered maps, when ZCBOR_MAP_SMART_SEARCH is enabled. + * It is ignored otherwise. */ -void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); +void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *elem_state, size_t elem_state_bytes); + +/** Do boilerplate entry function procedure. + * Initialize states, call function, and check the result. + */ +int zcbor_entry_function(const uint8_t *payload, size_t payload_len, + void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func, + size_t n_states, size_t elem_count); #ifdef ZCBOR_STOP_ON_ERROR -/** Check stored error and fail if present, but only if stop_on_error is true. */ +/** Check stored error and fail if present, but only if stop_on_error is true. + * + * @retval true No error found + * @retval false An error was found + */ static inline bool zcbor_check_error(const zcbor_state_t *state) { - struct zcbor_state_constant *cs = state->constant_state; + struct zcbor_state_constant *cs = state->constant_state; return !(cs && cs->stop_on_error && cs->error); } #endif @@ -355,9 +387,9 @@ static inline bool zcbor_payload_at_end(const zcbor_state_t *state) * For use when the payload is divided into multiple chunks. * * This function also updates all backups to the new payload_end. - * This sets a flag so that if a backup is processed with the flag - * @ref ZCBOR_FLAG_RESTORE, but without the flag - * @ref ZCBOR_FLAG_TRANSFER_PAYLOAD since this would cause an invalid state. + * This sets a flag so that @ref zcbor_process_backup fails if a backup is + * processed with the flag @ref ZCBOR_FLAG_RESTORE, but without the flag + * @ref ZCBOR_FLAG_KEEP_PAYLOAD since this would cause an invalid state. * * @param[inout] state The current state, will be updated with * the new payload pointer. @@ -382,7 +414,7 @@ void zcbor_update_state(zcbor_state_t *state, * found, or if any fragment value is NULL. */ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments); + size_t num_fragments); /** Assemble the fragments into a single string. * @@ -401,7 +433,79 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, * The buffer might still be written to. */ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments, uint8_t *result, size_t *result_len); + size_t num_fragments, uint8_t *result, size_t *result_len); + +/** Compare two struct zcbor_string instances. + * + * @param[in] str1 A string + * @param[in] str2 A string to compare to @p str1 + * + * @retval true if the strings are identical + * @retval false if length or contents don't match, or one one or both strings is NULL. + */ +bool zcbor_compare_strings(const struct zcbor_string *str1, + const struct zcbor_string *str2); + +/** Calculate the length of a CBOR string, list, or map header. + * + * This can be used to find the start of the CBOR object when you have a + * pointer to the start of the contents. The function assumes that the header + * will be the shortest it can be. + * + * @param[in] num_elems The number of elements in the string, list, or map. + * + * @return The length of the header in bytes (1-9). + */ +size_t zcbor_header_len(uint64_t value); + +/** Like @ref zcbor_header_len but for integer of any size <= 8. */ +size_t zcbor_header_len_ptr(const void *const value, size_t value_len); + +/** Convert a float16 value to float32. + * + * @param[in] input The float16 value stored in a uint16_t. + * + * @return The resulting float32 value. + */ +float zcbor_float16_to_32(uint16_t input); + +/** Convert a float32 value to float16. + * + * @param[in] input The float32 value. + * + * @return The resulting float16 value as a uint16_t. + */ +uint16_t zcbor_float32_to_16(float input); + +#ifdef ZCBOR_MAP_SMART_SEARCH +static inline size_t zcbor_round_up(size_t x, size_t align) +{ + return (((x) + (align) - 1) / (align) * (align)); +} + +#define ZCBOR_BITS_PER_BYTE 8 +/** Calculate the number of bytes needed to hold @p num_flags 1 bit flags + */ +static inline size_t zcbor_flags_to_bytes(size_t num_flags) +{ + return zcbor_round_up(num_flags, ZCBOR_BITS_PER_BYTE) / ZCBOR_BITS_PER_BYTE; +} + +/** Calculate the number of zcbor_state_t instances needed to hold @p num_flags 1 bit flags + */ +static inline size_t zcbor_flags_to_states(size_t num_flags) +{ + return zcbor_round_up(num_flags, sizeof(zcbor_state_t) * ZCBOR_BITS_PER_BYTE) + / (sizeof(zcbor_state_t) * ZCBOR_BITS_PER_BYTE); +} + +#define ZCBOR_FLAG_STATES(n_flags) zcbor_flags_to_states(n_flags) + +#else +#define ZCBOR_FLAG_STATES(n_flags) 0 +#endif + +size_t strnlen(const char *, size_t); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_debug.h b/boot/zcbor/include/zcbor_debug.h deleted file mode 100644 index 5f9b4778f..000000000 --- a/boot/zcbor/include/zcbor_debug.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef ZCBOR_DEBUG_H__ -#define ZCBOR_DEBUG_H__ - -#include -#include -#include -#include "zcbor_common.h" - -#ifdef __cplusplus -extern "C" { -#endif - -__attribute__((used)) -static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str1[j]); - } - printk("\r\n"); - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str2[j]); - } - printk("\r\n"); - for (uint32_t j = 0; j < size; j++) { - printk ("%x ", str1[j] != str2[j]); - } - printk("\r\n"); - printk("\r\n"); -} - -__attribute__((used)) -static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - for (uint32_t i = 0; i <= size / 16; i++) { - printk("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); - } - printk("\r\n"); -} - -__attribute__((used)) -static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) -{ - bool printed = false; - for (uint32_t i = 0; i <= size / 16; i++) { - if (memcmp(&str1[i*16], &str2[i*16], MIN(16, (size - i*16)) != 0)) { - printk("line %d (char %d)\r\n", i, i*16); - zcbor_print_compare_lines(&str1[i*16], &str2[i*16], - MIN(16, (size - i*16))); - printed = true; - } - } - if (printed) { - printk("\r\n"); - } -} - -#ifdef __cplusplus -} -#endif - -#endif /* ZCBOR_DEBUG_H__ */ diff --git a/boot/zcbor/include/zcbor_decode.h b/boot/zcbor/include/zcbor_decode.h index 53ce94db4..e5a58d82c 100644 --- a/boot/zcbor/include/zcbor_decode.h +++ b/boot/zcbor/include/zcbor_decode.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -28,213 +28,222 @@ extern "C" { */ -/** The following applies to all single-value decode functions that don't have docs. +/** See @ref zcbor_new_state() */ +void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *elem_state, size_t elem_state_bytes); + +/** Convenience macro for declaring and initializing a decoding state with backups. * - * @param[inout] state The current state of the decoding. - * @param[out] result Where to place the decoded value. + * This gives you a state variable named @p name. The variable functions like + * a pointer. + * + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). + * @param[in] n_flags For use if ZCBOR_MAP_SMART_SEARCH is enabled, ignored otherwise. + * The total number of unordered map search flags needed. + * I.e. the largest number of elements expected in an unordered map, + * including elements in nested unordered maps. + */ +#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count, n_flags) \ +zcbor_state_t name[((num_backups) + 2 + ZCBOR_FLAG_STATES(n_flags))]; \ +do { \ + zcbor_new_decode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count, \ + (uint8_t *)&name[(num_backups) + 1], ZCBOR_FLAG_STATES(n_flags) * sizeof(zcbor_state_t)); \ +} while(0) + + +/** The following applies to all _decode() functions listed directly below. + * + * @param[inout] state The current state of the decoding. + * @param[out] result Where to place the decoded value. + * @param[in] result_size (if present) Size in bytes of the memory at @p result * * @retval true If the value was decoded correctly. * @retval false If the value has the wrong type, the payload overflowed, the * element count was exhausted, or the value was larger than can * fit in the result variable. + * Use zcbor_peek_error() to see the error code. */ - -/** Decode and consume a pint/nint. */ -bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result); -bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result); -bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result); -bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result); -bool zcbor_size_decode(zcbor_state_t *state, size_t *result); -bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size); - -/** The following applies to all _expect() functions that don't have docs. - * - * @param[inout] state The current state of the decoding. - * @param[in] result The expected value. +bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result); /* pint/nint */ +bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result); /* pint/nint */ +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result); /* pint */ +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result); /* pint */ +bool zcbor_size_decode(zcbor_state_t *state, size_t *result); /* pint */ +bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size); /* pint/nint */ +bool zcbor_uint_decode(zcbor_state_t *state, void *result, size_t result_size); /* pint */ +bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result); /* bstr */ +bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result); /* tstr */ +bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result); /* CBOR tag */ +bool zcbor_simple_decode(zcbor_state_t *state, uint8_t *result); /* CBOR simple value */ +bool zcbor_bool_decode(zcbor_state_t *state, bool *result); /* boolean CBOR simple value */ +bool zcbor_float16_decode(zcbor_state_t *state, float *result); /* IEEE754 float16 */ +bool zcbor_float16_bytes_decode(zcbor_state_t *state, uint16_t *result); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_decode(zcbor_state_t *state, float *result); /* IEEE754 float16 or float32 */ +bool zcbor_float32_decode(zcbor_state_t *state, float *result); /* IEEE754 float32 */ +bool zcbor_float32_64_decode(zcbor_state_t *state, double *result); /* IEEE754 float32 or float64 */ +bool zcbor_float64_decode(zcbor_state_t *state, double *result); /* IEEE754 float64 */ +bool zcbor_float_decode(zcbor_state_t *state, double *result); /* IEEE754 float16, float32, or float64 */ + +/** The following applies to all _expect() and _pexpect() functions listed directly below. + * + * @param[inout] state The current state of the decoding. + * @param[in] expected The expected value. * * @retval true If the result was decoded correctly and has the expected value. * @retval false If the decoding failed or the result doesn't have the * expected value. + * Use zcbor_peek_error() to see the error code. */ -/** Consume and expect a pint/nint with a certain value. */ -bool zcbor_int32_expect(zcbor_state_t *state, int32_t result); -bool zcbor_int64_expect(zcbor_state_t *state, int64_t result); -bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result); -bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result); -bool zcbor_size_expect(zcbor_state_t *state, size_t result); +bool zcbor_int32_expect(zcbor_state_t *state, int32_t expected); /* pint/nint */ +bool zcbor_int64_expect(zcbor_state_t *state, int64_t expected); /* pint/nint */ +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t expected); /* pint */ +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t expected); /* pint */ +bool zcbor_size_expect(zcbor_state_t *state, size_t expected); /* pint */ +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *expected); /* bstr */ +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *expected); /* tstr */ +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t expected); /* CBOR tag */ +bool zcbor_simple_expect(zcbor_state_t *state, uint8_t expected); /* CBOR simple value */ +bool zcbor_bool_expect(zcbor_state_t *state, bool expected); /* boolean CBOR simple value */ +bool zcbor_nil_expect(zcbor_state_t *state, void *unused); /* 'nil' CBOR simple value */ +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused); /* 'undefined' CBOR simple value */ +bool zcbor_float16_expect(zcbor_state_t *state, float expected); /* IEEE754 float16 */ +bool zcbor_float16_bytes_expect(zcbor_state_t *state, uint16_t expected); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_expect(zcbor_state_t *state, float expected); /* IEEE754 float16 or float32 */ +bool zcbor_float32_expect(zcbor_state_t *state, float expected); /* IEEE754 float32 */ +bool zcbor_float32_64_expect(zcbor_state_t *state, double expected); /* IEEE754 float32 or float64 */ +bool zcbor_float64_expect(zcbor_state_t *state, double expected); /* IEEE754 float64 */ +bool zcbor_float_expect(zcbor_state_t *state, double expected); /* IEEE754 float16, float32, or float64 */ + +/** Like the _expect() functions but the value is passed through a pointer. + * (for use as a zcbor_decoder_t function) */ +bool zcbor_int32_pexpect(zcbor_state_t *state, int32_t *expected); /* pint/nint */ +bool zcbor_int64_pexpect(zcbor_state_t *state, int64_t *expected); /* pint/nint */ +bool zcbor_uint32_pexpect(zcbor_state_t *state, uint32_t *expected); /* pint */ +bool zcbor_uint64_pexpect(zcbor_state_t *state, uint64_t *expected); /* pint */ +bool zcbor_size_pexpect(zcbor_state_t *state, size_t *expected); /* pint */ +bool zcbor_tag_pexpect(zcbor_state_t *state, uint32_t *expected); /* CBOR tag */ +bool zcbor_simple_pexpect(zcbor_state_t *state, uint8_t *expected); /* CBOR simple value */ +bool zcbor_bool_pexpect(zcbor_state_t *state, bool *expected); /* boolean CBOR simple value */ +bool zcbor_float16_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float16 */ +bool zcbor_float16_bytes_pexpect(zcbor_state_t *state, uint16_t *expected); /* IEEE754 float16 raw bytes */ +bool zcbor_float16_32_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float16 or float32 */ +bool zcbor_float32_pexpect(zcbor_state_t *state, float *expected); /* IEEE754 float32 */ +bool zcbor_float32_64_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float32 or float64 */ +bool zcbor_float64_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float64 */ +bool zcbor_float_pexpect(zcbor_state_t *state, double *expected); /* IEEE754 float16, float32, or float64 */ /** Consume and expect a pint/nint with a certain value, within a union. * * Calls @ref zcbor_union_elem_code then @ref zcbor_[u]int[32|64]_expect. */ -bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result); -bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result); -bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result); -bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result); - -/** Decode and consume a bstr/tstr */ -bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result); -bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result); - -/** Consume and expect a bstr/tstr with the value of the provided string literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. A pointer to the string. - * @param[in] len The length of the string pointed to by @p string. - */ -static inline bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) -{ - struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_bstr_expect(state, &zs); -} -static inline bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) -{ - struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_tstr_expect(state, &zs); -} - - -/** Consume and expect a bstr/tstr with the value of the provided string literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. A string literal, e.g. "Foo", so - * that sizeof(string) - 1 is the length of the string. - */ -#define zcbor_bstr_expect_lit(state, string) \ - zcbor_bstr_expect_ptr(state, string, sizeof(string) - 1) -#define zcbor_tstr_expect_lit(state, string) \ - zcbor_tstr_expect_ptr(state, string, sizeof(string) - 1) - -/** Consume and expect a bstr/tstr with the value of the provided null-terminated string. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. Must be a null-terminated string, - * so that strlen can be used. - */ -#define zcbor_bstr_expect_term(state, string) \ - zcbor_bstr_expect_ptr(state, string, strlen(string)) -#define zcbor_tstr_expect_term(state, string) \ - zcbor_tstr_expect_ptr(state, string, strlen(string)) - -/** Consume and expect a bstr/tstr with the value of the provided char array literal. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to expect. An array literal, e.g. {'F', 'o', 'o'}, - * so that sizeof(string) is the length of the string. - */ -#define zcbor_bstr_expect_arr(state, string) \ - zcbor_bstr_expect_ptr(state, string, (sizeof(string))) -#define zcbor_tstr_expect_arr(state, string) \ - zcbor_tstr_expect_ptr(state, string, (sizeof(string))) - -/** Decode and consume a tag. */ -bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result); -bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result); - -/** Decode and consume a boolean primitive value. */ -bool zcbor_bool_decode(zcbor_state_t *state, bool *result); -bool zcbor_bool_expect(zcbor_state_t *state, bool result); - -/** Decode and consume a float */ -bool zcbor_float32_decode(zcbor_state_t *state, float *result); -bool zcbor_float32_expect(zcbor_state_t *state, float result); -bool zcbor_float64_decode(zcbor_state_t *state, double *result); -bool zcbor_float64_expect(zcbor_state_t *state, double result); -bool zcbor_float_decode(zcbor_state_t *state, double *result); -bool zcbor_float_expect(zcbor_state_t *state, double result); - -/** Consume and expect a "nil"/"undefined" primitive value. - * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_decoder_t. - */ -bool zcbor_nil_expect(zcbor_state_t *state, void *unused); -bool zcbor_undefined_expect(zcbor_state_t *state, void *unused); - -/** Skip a single element, regardless of type and value. - * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_decoder_t. - */ -bool zcbor_any_skip(zcbor_state_t *state, void *unused); +bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t expected); +bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t expected); +bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t expected); +bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t expected); -/** Decode and consume a bstr header. +/** Decode and consume a list/map header. * - * The rest of the string can be decoded as CBOR. + * The contents of the list can be decoded via subsequent function calls. * A state backup is created to keep track of the element count. - * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * Call @ref zcbor_list_end_decode / @ref zcbor_map_end_decode when done + * decoding the contents of the list/map * * @retval true Header decoded correctly * @retval false Header decoded incorrectly, or backup failed. */ -bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); - -/** Finalize decoding a CBOR-encoded bstr. - * - * Restore element count from backup. - */ -bool zcbor_bstr_end_decode(zcbor_state_t *state); - -/** Start decoding a bstr/tstr, even if the payload contains only part of it. - * - * This must be followed by a call to @ref zcbor_update_state, which can be - * followed by a call to @ref zcbor_next_fragment. Do not call this function - * again on subsequent fragments of the same string. - * - * This consumes the remaining payload as long as it belongs to the string. +bool zcbor_list_start_decode(zcbor_state_t *state); +bool zcbor_map_start_decode(zcbor_state_t *state); +bool zcbor_unordered_map_start_decode(zcbor_state_t *state); + +/** Search for a key in a map. + * + * The CBOR spec allows elements (key-value pairs) in maps to appear in any order. + * This function should be used when the order of elements is unknown. + * + * This must only be used while inside a map that has been entered via + * @ref zcbor_unordered_map_start_decode. Use @ref zcbor_unordered_map_end_decode + * when leaving the map. + * + * This function searches for keys. When this function returns successfully, + * the @p state is pointing to the value corresponding to the found key. + * Therefore, to be able to call this function again, the value must first be + * decoded or skipped. + * + * When searching unordered maps, the found elements must be kept track of. + * By default, this function automatically keeps track, which means it keeps a + * running count of the number of found elements, which is checked when exiting + * the map. You can do this manually instead, see @ref zcbor_elem_processed and + * @ref manually_process_elem. If ZCBOR_MAP_SMART_SEARCH is defined, a flag is + * kept for each element, instead of a rolling count. + * + * @note Unless ZCBOR_MAP_SMART_SEARCH is defined, + * elements are not individually marked as processed, so they may + * be returned again in a subsequent call to this function, if it is + * matched by the @p key_decoder of that call. Because of this, you should + * only use this function when you know the @p key_decoder matches no more + * than one of the keys. Typically this means all keys are known strings + * or integers, i.e. the @p key_decoder is typically a _pexpect() function. + * + * When searching for strings, there are convenience functions available, + * see the zcbor_search_key_* functions. + * + * @param[in] key_decoder A decoding function that will be tried against all + * keys in the map until it returns true, at which point + * @ref zcbor_unordered_map_search will return true. + * For example, a zcbor_*_pexpect() function. + * @param[inout] state The current state of decoding. Must be currently decoding + * the contents of a map, and pointing to one (any) of the + * keys, not one of the values. If successful, the @p state + * will be pointing to the value corresponding to the + * matched key. If unsuccessful, the @p state will be + * unchanged. + * @param[inout] key_result This will be passed as the second argument to the + * @p key_decoder. + * + * @retval true If the key was found, i.e. @p key_decoder returned true. + * @retval false If the key was not found after searching all map elements. + * Or the map was pointing to a value (not a key). + * Or an unexpected error happened while skipping elements or + * jumping from the end of the map to the start. */ -bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); -bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *state, void *key_result); -/** Extract the next fragment of a string. +/** Find a specific bstr/tstr key as part of a map with unknown element order. * - * Use this function to extract all but the first fragment. + * Uses @ref zcbor_unordered_map_search under the hood. Please refer to those docs + * for the conditions under which this can be called. + * Refer to the docs for zcbor_(t|b)str_expect_* (e.g. @ref zcbor_bstr_expect_ptr) + * for parameter docs. */ -void zcbor_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); +bool zcbor_search_key_bstr_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_search_key_tstr_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_search_key_bstr_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_search_key_tstr_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_search_key_bstr_lit(state, str) zcbor_search_key_bstr_ptr(state, str, sizeof(str) - 1) +#define zcbor_search_key_tstr_lit(state, str) zcbor_search_key_tstr_ptr(state, str, sizeof(str) - 1) +#define zcbor_search_key_bstr_arr(state, str) zcbor_search_key_bstr_ptr(state, str, (sizeof(str))) +#define zcbor_search_key_tstr_arr(state, str) zcbor_search_key_tstr_ptr(state, str, (sizeof(str))) -/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. +/** (Optional) Call this function to mark an (unordered map) element as processed. * - * The rest of the string can be decoded as CBOR. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when - * the current payload has been exhausted. - * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. - */ -bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *result); - -/** Start decoding the next fragment of a string. + * @note This should not be called unless the @ref manually_process_elem flag is set. + * By default, i.e. when @ref manually_process_elem is not set, this function is + * called internally by @ref zcbor_unordered_map_search whenever a key is found. * - * Use this function to extract all but the first fragment of a CBOR-encoded - * bstr. - */ -void zcbor_bstr_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); - -/** Can be used on any fragment to tell if it is the final fragment of the string. */ -bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); - -/** Decode and consume a list/map header. + * By default, this function increments the internal count @ref map_elems_processed. * - * The contents of the list can be decoded via subsequent function calls. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_list_end_decode / @ref zcbor_map_end_decode when done - * decoding the contents of the list/map + * If ZCBOR_MAP_SMART_SEARCH is defined, this function instead clears a flag for the + * element (key-value pair) that is currently being processed, or that has just been + * processed, meaning the element won't be found again via @ref zcbor_unordered_map_search. * - * @retval true Header decoded correctly - * @retval false Header decoded incorrectly, or backup failed. + * @ref zcbor_unordered_map_end_decode will fail if @ref map_elems_processed does not + * match the number of elements in the map, or if any of the map element's flag is set. */ -bool zcbor_list_start_decode(zcbor_state_t *state); -bool zcbor_map_start_decode(zcbor_state_t *state); +bool zcbor_elem_processed(zcbor_state_t *state); /** Finalize decoding a list/map * @@ -244,13 +253,33 @@ bool zcbor_map_start_decode(zcbor_state_t *state); * Use @ref zcbor_list_map_end_force_decode to forcibly consume the backup if * something has gone wrong. * + * In all successful cases, the state is returned pointing to the byte/element + * after the list/map in the payload. + * * @retval true Everything ok. * @retval false Element count not correct. */ bool zcbor_list_end_decode(zcbor_state_t *state); bool zcbor_map_end_decode(zcbor_state_t *state); +bool zcbor_unordered_map_end_decode(zcbor_state_t *state); bool zcbor_list_map_end_force_decode(zcbor_state_t *state); +/** Find whether the state is at the end of a list or map. + */ +bool zcbor_array_at_end(zcbor_state_t *state); + +/** Skip a single element, regardless of type and value. + * + * This means if the element is a map or list, this function will recursively + * skip all its contents. + * This function will also skip any tags preceeding the element. + * + * @param[inout] state The current state of the decoding. + * @param[in] unused Unused parameter to maintain signature parity with + * @ref zcbor_decoder_t. + */ +bool zcbor_any_skip(zcbor_state_t *state, void *unused); + /** Decode 0 or more elements with the same type and constraints. * * The decoded values will appear consecutively in the @p result array. @@ -293,6 +322,8 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state); * The result pointer is moved @p result_len bytes for * each call to @p decoder, i.e. @p result refers to * an array of result variables. + * Should not be an _expect() function, use + * _pexpect() instead. * @param[out] result Where to place the decoded values. Must be an array * of at least @p max_decode elements. * @param[in] result_len The length of each result variable. Must be the @@ -302,9 +333,9 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state); * @retval false If @p decoder failed before having decoded @p min_decode * values. */ -bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint_fast32_t *num_decode, +bool zcbor_multi_decode(size_t min_decode, size_t max_decode, size_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - uint_fast32_t result_len); + size_t result_len); /** Attempt to decode a value that might not be present in the data. * @@ -317,31 +348,102 @@ bool zcbor_multi_decode(uint_fast32_t min_decode, uint_fast32_t max_decode, uint * * @return Should always return true. */ -bool zcbor_present_decode(uint_fast32_t *present, +bool zcbor_present_decode(bool *present, zcbor_decoder_t decoder, zcbor_state_t *state, void *result); -/** See @ref zcbor_new_state() */ -void zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); -/** Convenience macro for declaring and initializing a state with backups. +/** Supplementary string (bstr/tstr) decoding functions: */ + +/** Consume and expect a bstr/tstr with the value of the provided char/uint8_t array. * - * This gives you a state variable named @p name. The variable functions like - * a pointer. + * @param[inout] state The current state of the decoding. + * @param[in] str The value to expect. A pointer to the string/array. + * _term() uses strnlen(), so @p str must be null-terminated. + * _lit() uses sizeof()-1, so @p str must be a (null-terminated) string literal. + * _arr() uses sizeof(), so @p str must be a uint8_t array (not null-terminated). + * @param[in] len (if present) The length of the string pointed to by @p str + * @param[in] maxlen (if present) The maximum length of the string pointed to by @p str. + * This value is passed to strnlen. + */ +bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len); +bool zcbor_bstr_expect_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_tstr_expect_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_bstr_expect_lit(state, str) zcbor_bstr_expect_ptr(state, str, sizeof(str) - 1) +#define zcbor_tstr_expect_lit(state, str) zcbor_tstr_expect_ptr(state, str, sizeof(str) - 1) +#define zcbor_bstr_expect_arr(state, str) zcbor_bstr_expect_ptr(state, str, sizeof(str)) +#define zcbor_tstr_expect_arr(state, str) zcbor_tstr_expect_ptr(state, str, sizeof(str)) + +/** Decode and consume a bstr header. * - * @param[in] name The name of the new state variable. - * @param[in] num_backups The number of backup slots to keep in the state. - * @param[in] payload The payload to work on. - * @param[in] payload_size The size (in bytes) of @p payload. - * @param[in] elem_count The starting elem_count (typically 1). + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * + * @param[inout] state The current state of the decoding. + * @param[out] result The resulting string, for reference. The string should be decoded via + * functions from this API since state is pointing to the start of the string, + * not the end. + * + * @retval true Header decoded correctly + * @retval false Header decoded incorrectly, or backup failed, or payload is not large enough + * to contain the contents of the string. Use @ref zcbor_bstr_start_decode_fragment + * for decoding fragmented payloads. */ -#define ZCBOR_STATE_D(name, num_backups, payload, payload_size, elem_count) \ -zcbor_state_t name[((num_backups) + 2)]; \ -do { \ - zcbor_new_decode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ -} while(0) +bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); + +/** Finalize decoding a CBOR-encoded bstr. + * + * Restore element count from backup. + */ +bool zcbor_bstr_end_decode(zcbor_state_t *state); + + +/** Supplementary string (bstr/tstr) decoding functions for fragmented payloads: */ + +/** Start decoding a bstr/tstr, even if the payload contains only part of it. + * + * This must be followed by a call to @ref zcbor_update_state, which can be + * followed by a call to @ref zcbor_next_fragment. Do not call this function + * again on subsequent fragments of the same string. + * + * This consumes the remaining payload as long as it belongs to the string. + */ +bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); + +/** Extract the next fragment of a string. + * + * Use this function to extract all but the first fragment. + */ +void zcbor_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. + * + * The rest of the string can be decoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when + * the current payload has been exhausted. + * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + */ +bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *result); + +/** Start decoding the next fragment of a string. + * + * Use this function to extract all but the first fragment of a CBOR-encoded + * bstr. + */ +void zcbor_bstr_next_fragment(zcbor_state_t *state, + struct zcbor_string_fragment *prev_fragment, + struct zcbor_string_fragment *result); + +/** Can be used on any fragment to tell if it is the final fragment of the string. */ +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_encode.h b/boot/zcbor/include/zcbor_encode.h index 40bcccfe1..5139d3ca3 100644 --- a/boot/zcbor/include/zcbor_encode.h +++ b/boot/zcbor/include/zcbor_encode.h @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -21,6 +21,7 @@ extern "C" { #endif + /** The zcbor_encode library provides functions for encoding CBOR data elements. * * See The README for an introduction to CBOR, including the meaning of pint, @@ -28,130 +29,72 @@ extern "C" { */ -/** The following param and retval docs apply to all single value encoding functions - * - * @param[inout] state The current state of the encoding. - * @param[in] input The value to encode. - * - * @retval true Everything is ok. - * @retval false If the payload is exhausted. Or an unexpected error happened. - */ - -/** Encode a pint/nint. */ -bool zcbor_int32_put(zcbor_state_t *state, int32_t input); -bool zcbor_int64_put(zcbor_state_t *state, int64_t input); -bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input); -bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); -bool zcbor_size_put(zcbor_state_t *state, size_t input); - -/** Encode a pint/nint from a pointer. - * - * Can be used for bulk encoding with @ref zcbor_multi_encode. - */ -bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_size); -bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); -bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); -bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input); -bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); -bool zcbor_size_encode(zcbor_state_t *state, const size_t *input); - -/** Encode a bstr. */ -bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); -/** Encode a tstr. */ -bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); - -/** Encode a pointer to a string as a bstr/tstr. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. A pointer to the string - * @param[in] len The length of the string pointed to by @p string. - */ -static inline bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *ptr, size_t len) -{ - const struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_bstr_encode(state, &zs); -} -static inline bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *ptr, size_t len) -{ - const struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; - - return zcbor_tstr_encode(state, &zs); -} - -/** Encode a string literal as a bstr/tstr. - * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. A string literal, e.g. "Foo", so - * that sizeof(string) - 1 is the length of the string. - */ -#define zcbor_bstr_put_lit(state, string) \ - zcbor_bstr_encode_ptr(state, string, sizeof(string) - 1) -#define zcbor_tstr_put_lit(state, string) \ - zcbor_tstr_encode_ptr(state, string, sizeof(string) - 1) +/** See @ref zcbor_new_state() */ +void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states, + uint8_t *payload, size_t payload_len, size_t elem_count); -/** Encode null-terminated string as a bstr/tstr. +/** Convenience macro for declaring and initializing an encoding state with backups. * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. Must be a null-terminated string, - * so that strlen can be used. - */ -#define zcbor_bstr_put_term(state, string) \ - zcbor_bstr_encode_ptr(state, string, strlen(string)) -#define zcbor_tstr_put_term(state, string) \ - zcbor_tstr_encode_ptr(state, string, strlen(string)) - -/** Encode a char array literal as a bstr/tstr. + * This gives you a state variable named @p name. The variable functions like + * a pointer. * - * @param[inout] state The current state of the encoding. - * @param[in] string The value to encode. An array literal, e.g. {'F', 'o', 'o'}, - * so that sizeof(string) is the length of the string. + * @param[in] name The name of the new state variable. + * @param[in] num_backups The number of backup slots to keep in the state. + * @param[in] payload The payload to work on. + * @param[in] payload_size The size (in bytes) of @p payload. + * @param[in] elem_count The starting elem_count (typically 1). */ -#define zcbor_bstr_put_arr(state, string) \ - zcbor_bstr_encode_ptr(state, string, sizeof(string)) -#define zcbor_tstr_put_arr(state, string) \ - zcbor_tstr_encode_ptr(state, string, sizeof(string)) - -/** Encode a tag. Must be called before encoding the value being tagged. */ -bool zcbor_tag_encode(zcbor_state_t *state, uint32_t input); - -/** Encode a boolean primitive value. */ -bool zcbor_bool_put(zcbor_state_t *state, bool input); -bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); - -/** Encode a float */ -bool zcbor_float32_put(zcbor_state_t *state, float input); -bool zcbor_float32_encode(zcbor_state_t *state, const float *input); -bool zcbor_float64_put(zcbor_state_t *state, double input); -bool zcbor_float64_encode(zcbor_state_t *state, const double *input); +#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \ +zcbor_state_t name[((num_backups) + 2)]; \ +do { \ + zcbor_new_encode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ +} while(0) -/** Encode a "nil"/"undefined" primitive value. @p unused should be NULL. - * - * @param[inout] state The current state of the encoding. - * @param[in] unused Unused parameter to maintain signature parity with - * @ref zcbor_encoder_t. - */ -bool zcbor_nil_put(zcbor_state_t *state, const void *unused); -bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); -/** Encode a bstr header. - * - * The rest of the string can be encoded as CBOR. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr. +/** The following applies to all _put and _encode functions listed directly below. * - * @param[inout] state The current state of the encoding. + * The difference between _put and _encode is only in the argument type, + * but when a @ref zcbor_encoder_t is needed, such as for @ref zcbor_multi_encode, + * the _encode variant must be used. * - * @retval true Header encoded correctly - * @retval false Header encoded incorrectly, or backup failed. - */ -bool zcbor_bstr_start_encode(zcbor_state_t *state); - -/** Finalize encoding a CBOR-encoded bstr. + * @param[inout] state The current state of the encoding. + * @param[in] input The value to encode. * - * Restore element count from backup. - */ -bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); + * @retval true Everything is ok. + * @retval false If the payload is exhausted. Or an unexpected error happened. + * Use zcbor_peek_error() to see the error code. + */ +bool zcbor_int32_put(zcbor_state_t *state, int32_t input); /* pint/nint */ +bool zcbor_int64_put(zcbor_state_t *state, int64_t input); /* pint/nint */ +bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input); /* pint */ +bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input); /* pint */ +bool zcbor_size_put(zcbor_state_t *state, size_t input); /* pint */ +bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag); /* CBOR tag */ +bool zcbor_simple_put(zcbor_state_t *state, uint8_t input); /* CBOR simple value */ +bool zcbor_bool_put(zcbor_state_t *state, bool input); /* boolean CBOR simple value */ +bool zcbor_nil_put(zcbor_state_t *state, const void *unused); /* 'nil' CBOR simple value */ +bool zcbor_undefined_put(zcbor_state_t *state, const void *unused); /* 'undefined' CBOR simple value */ +bool zcbor_float16_put(zcbor_state_t *state, float input); /* IEEE754 float16 */ +bool zcbor_float16_bytes_put(zcbor_state_t *state, uint16_t input); /* IEEE754 float16 raw bytes */ +bool zcbor_float32_put(zcbor_state_t *state, float input); /* IEEE754 float32 */ +bool zcbor_float64_put(zcbor_state_t *state, double input); /* IEEE754 float64 */ + +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input); /* pint/nint */ +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input); /* pint/nint */ +bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input); /* pint */ +bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input); /* pint */ +bool zcbor_size_encode(zcbor_state_t *state, const size_t *input); /* pint */ +bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_size); +bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size); +bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* bstr */ +bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input); /* tstr */ +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t *tag); /* CBOR tag. Note that zcbor_tag_encode()'s argument was changed to be a pointer. See also zcbor_tag_put(). */ +bool zcbor_simple_encode(zcbor_state_t *state, uint8_t *input); /* CBOR simple value */ +bool zcbor_bool_encode(zcbor_state_t *state, const bool *input); /* boolean CBOR simple value */ +bool zcbor_float16_encode(zcbor_state_t *state, const float *input); /* IEEE754 float16 */ +bool zcbor_float16_bytes_encode(zcbor_state_t *state, const uint16_t *input); /* IEEE754 float16 raw bytes */ +bool zcbor_float32_encode(zcbor_state_t *state, const float *input); /* IEEE754 float32 */ +bool zcbor_float64_encode(zcbor_state_t *state, const double *input); /* IEEE754 float64 */ /** Encode a list/map header. * @@ -169,8 +112,8 @@ bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); * call. * Only used when ZCBOR_CANONICAL is defined. */ -bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num); -bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num); +bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num); /** Encode the end of a list/map. Do some checks and deallocate backup. * @@ -189,8 +132,8 @@ bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num); * @ref zcbor_list_start_encode call. * Only used when ZCBOR_CANONICAL is defined. */ -bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num); -bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num); +bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num); +bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num); bool zcbor_list_map_end_force_encode(zcbor_state_t *state); /** Encode 0 or more elements with the same type and constraints. @@ -241,49 +184,59 @@ bool zcbor_list_map_end_force_encode(zcbor_state_t *state); * @retval false If @p encoder failed before having encoded @p min_encode * values. */ -bool zcbor_multi_encode(uint_fast32_t num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len); +bool zcbor_multi_encode(size_t num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len); /** Works like @ref zcbor_multi_encode * * But first checks that @p num_encode is between @p min_encode and @p max_encode. */ -bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, uint_fast32_t max_encode, const uint_fast32_t *num_encode, - zcbor_encoder_t encoder, zcbor_state_t *state, const void *input, - uint_fast32_t input_len); +bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode, + const size_t *num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t input_len); -/** Runs @p encoder on @p state and @p input if @p present is true. - * - * Calls @ref zcbor_multi_encode under the hood. - */ -bool zcbor_present_encode(const uint_fast32_t *present, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input); -/** See @ref zcbor_new_state() */ -void zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - uint8_t *payload, size_t payload_len, uint_fast32_t elem_count); +/* Supplementary string (bstr/tstr) encoding functions: */ -/** Convenience macro for declaring and initializing a state with backups. +/** Encode a char/uint8_t pointer as a bstr/tstr. * - * This gives you a state variable named @p name. The variable functions like - * a pointer. + * @param[inout] state The current state of the encoding. + * @param[in] str The value to encode. A pointer to the string/array. + * _term() uses strnlen(), so @p str must be null-terminated. + * _lit() uses sizeof()-1, so @p str must be a (null-terminated) string literal. + * _arr() uses sizeof(), so @p str must be a uint8_t array (not null-terminated). + * @param[in] len (if present) The length of the string pointed to by @p str + * @param[in] maxlen (if present) The maximum length of the string pointed to by @p str. + * This value is passed to strnlen. + */ +bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len); +bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len); +bool zcbor_bstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen); +bool zcbor_tstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen); +#define zcbor_bstr_put_lit(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str) - 1) +#define zcbor_tstr_put_lit(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str) - 1) +#define zcbor_bstr_put_arr(state, str) zcbor_bstr_encode_ptr(state, str, sizeof(str)) +#define zcbor_tstr_put_arr(state, str) zcbor_tstr_encode_ptr(state, str, sizeof(str)) + +/** Encode a bstr header. * - * @param[in] name The name of the new state variable. - * @param[in] num_backups The number of backup slots to keep in the state. - * @param[in] payload The payload to work on. - * @param[in] payload_size The size (in bytes) of @p payload. - * @param[in] elem_count The starting elem_count (typically 1). + * The rest of the string can be encoded as CBOR. + * A state backup is created to keep track of the element count. + * Call @ref zcbor_bstr_end_encode when done encoding the contents of the bstr. + * + * @param[inout] state The current state of the encoding. + * + * @retval true Header encoded correctly + * @retval false Header encoded incorrectly, or backup failed. */ -#define ZCBOR_STATE_E(name, num_backups, payload, payload_size, elem_count) \ -zcbor_state_t name[((num_backups) + 2)]; \ -do { \ - zcbor_new_encode_state(name, ZCBOR_ARRAY_SIZE(name), payload, payload_size, elem_count); \ -} while(0) +bool zcbor_bstr_start_encode(zcbor_state_t *state); + +/** Finalize encoding a CBOR-encoded bstr. + * + * This writes the final size of the bstr to the header. + * Restore element count from backup. + */ +bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result); #ifdef __cplusplus } diff --git a/boot/zcbor/include/zcbor_print.h b/boot/zcbor/include/zcbor_print.h new file mode 100644 index 000000000..6ab6d453d --- /dev/null +++ b/boot/zcbor/include/zcbor_print.h @@ -0,0 +1,170 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.1 + */ + +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_PRINT_H__ +#define ZCBOR_PRINT_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ZCBOR_PRINT_FUNC +#include +#define zcbor_do_print(...) printf(__VA_ARGS__) +#else +#define zcbor_do_print(...) ZCBOR_PRINT_FUNC(__VA_ARGS__) +#endif + +#ifdef ZCBOR_VERBOSE +#define zcbor_trace_raw(state) (zcbor_do_print("rem: %zu, cur: 0x%x, ec: 0x%zx, err: %d",\ + (size_t)state->payload_end - (size_t)state->payload, *state->payload, state->elem_count, \ + state->constant_state ? state->constant_state->error : 0)) +#define zcbor_trace(state, appendix) do { \ + zcbor_trace_raw(state); \ + zcbor_do_print(", %s\n", appendix); \ +} while(0) +#define zcbor_trace_file(state) do { \ + zcbor_trace_raw(state); \ + zcbor_do_print(", %s:%d\n", __FILE__, __LINE__); \ +} while(0) + +#define zcbor_log_assert(expr, ...) \ +do { \ + zcbor_do_print("ASSERTION \n \"" #expr \ + "\"\nfailed at %s:%d with message:\n ", \ + __FILE__, __LINE__); \ + zcbor_do_print(__VA_ARGS__);\ +} while(0) +#define zcbor_log(...) zcbor_do_print(__VA_ARGS__) +#else +#define zcbor_trace(state, appendix) +#define zcbor_trace_file(state) ((void)state) +#define zcbor_log_assert(...) +#define zcbor_log(...) +#endif + +#ifdef ZCBOR_ASSERTS +#define zcbor_assert(expr, ...) \ +do { \ + if (!(expr)) { \ + zcbor_log_assert(expr, __VA_ARGS__); \ + ZCBOR_FAIL(); \ + } \ +} while(0) +#define zcbor_assert_state(expr, ...) \ +do { \ + if (!(expr)) { \ + zcbor_log_assert(expr, __VA_ARGS__); \ + ZCBOR_ERR(ZCBOR_ERR_ASSERTION); \ + } \ +} while(0) +#else +#define zcbor_assert(expr, ...) +#define zcbor_assert_state(expr, ...) +#endif + +__attribute__((used)) +static void zcbor_print_compare_lines(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str1[j]); + } + zcbor_do_print("\r\n"); + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str2[j]); + } + zcbor_do_print("\r\n"); + for (uint32_t j = 0; j < size; j++) { + zcbor_do_print("%x ", str1[j] != str2[j]); + } + zcbor_do_print("\r\n"); + zcbor_do_print("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + const size_t col_width = 16; + + for (size_t i = 0; i <= size / col_width; i++) { + zcbor_do_print("line %zu (char %zu)\r\n", i, i*col_width); + zcbor_print_compare_lines(&str1[i*col_width], &str2[i*col_width], + MIN(col_width, (size - i*col_width))); + } + zcbor_do_print("\r\n"); +} + +__attribute__((used)) +static void zcbor_print_compare_strings_diff(const uint8_t *str1, const uint8_t *str2, uint32_t size) +{ + const size_t col_width = 16; + bool printed = false; + + for (size_t i = 0; i <= size / col_width; i++) { + if (memcmp(&str1[i*col_width], &str2[i*col_width], MIN(col_width, (size - i*col_width))) != 0) { + zcbor_do_print("line %zu (char %zu)\r\n", i, i*col_width); + zcbor_print_compare_lines(&str1[i*col_width], &str2[i*col_width], + MIN(col_width, (size - i*col_width))); + printed = true; + } + } + if (printed) { + zcbor_do_print("\r\n"); + } +} + +__attribute__((used)) +static const char *zcbor_error_str(int error) +{ + #define ZCBOR_ERR_CASE(err) case err: \ + return #err; /* The literal is static per C99 6.4.5 paragraph 5. */\ + + switch(error) { + ZCBOR_ERR_CASE(ZCBOR_SUCCESS) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_BACKUP_MEM) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_BACKUP_ACTIVE) + ZCBOR_ERR_CASE(ZCBOR_ERR_LOW_ELEM_COUNT) + ZCBOR_ERR_CASE(ZCBOR_ERR_HIGH_ELEM_COUNT) + ZCBOR_ERR_CASE(ZCBOR_ERR_INT_SIZE) + ZCBOR_ERR_CASE(ZCBOR_ERR_FLOAT_SIZE) + ZCBOR_ERR_CASE(ZCBOR_ERR_ADDITIONAL_INVAL) + ZCBOR_ERR_CASE(ZCBOR_ERR_NO_PAYLOAD) + ZCBOR_ERR_CASE(ZCBOR_ERR_PAYLOAD_NOT_CONSUMED) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_TYPE) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_VALUE) + ZCBOR_ERR_CASE(ZCBOR_ERR_WRONG_RANGE) + ZCBOR_ERR_CASE(ZCBOR_ERR_ITERATIONS) + ZCBOR_ERR_CASE(ZCBOR_ERR_ASSERTION) + ZCBOR_ERR_CASE(ZCBOR_ERR_PAYLOAD_OUTDATED) + ZCBOR_ERR_CASE(ZCBOR_ERR_ELEM_NOT_FOUND) + ZCBOR_ERR_CASE(ZCBOR_ERR_MAP_MISALIGNED) + ZCBOR_ERR_CASE(ZCBOR_ERR_ELEMS_NOT_PROCESSED) + ZCBOR_ERR_CASE(ZCBOR_ERR_NOT_AT_END) + ZCBOR_ERR_CASE(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE) + ZCBOR_ERR_CASE(ZCBOR_ERR_INVALID_VALUE_ENCODING) + } + #undef ZCBOR_ERR_CASE + + return "ZCBOR_ERR_UNKNOWN"; +} + +__attribute__((used)) +static void zcbor_print_error(int error) +{ + zcbor_do_print("%s\r\n", zcbor_error_str(error)); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZCBOR_PRINT_H__ */ diff --git a/boot/zcbor/include/zcbor_tags.h b/boot/zcbor/include/zcbor_tags.h new file mode 100644 index 000000000..d17e8b348 --- /dev/null +++ b/boot/zcbor/include/zcbor_tags.h @@ -0,0 +1,99 @@ +/* + * This file has been copied from the zcbor library. + * Commit zcbor 0.8.1 + */ + +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZCBOR_TAGS_H__ +#define ZCBOR_TAGS_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Values defined by RFCs via www.iana.org/assignments/cbor-tags/cbor-tags.xhtml */ +enum zcbor_tag { + ZCBOR_TAG_TIME_TSTR = 0, ///! text string [RFC8949] Standard date/time string + ZCBOR_TAG_TIME_NUM = 1, ///! integer or float [RFC8949] Epoch-based date/time + ZCBOR_TAG_UBIGNUM_BSTR = 2, ///! byte string [RFC8949] Unsigned bignum + ZCBOR_TAG_BIGNUM_BSTR = 3, ///! byte string [RFC8949] Negative bignum + ZCBOR_TAG_DECFRAC_ARR = 4, ///! array [RFC8949] Decimal fraction + ZCBOR_TAG_BIGFLOAT_ARR = 5, ///! array [RFC8949] Bigfloat + ZCBOR_TAG_COSE_ENCRYPT0 = 16, ///! COSE_Encrypt0 [RFC9052] COSE Single Recipient Encrypted Data Object + ZCBOR_TAG_COSE_MAC0 = 17, ///! COSE_Mac0 [RFC9052] COSE MAC w/o Recipients Object + ZCBOR_TAG_COSE_SIGN1 = 18, ///! COSE_Sign1 [RFC9052] COSE Single Signer Data Object + ZCBOR_TAG_2BASE64URL = 21, ///! (any) [RFC8949] Expected conversion to base64url encoding + ZCBOR_TAG_2BASE64 = 22, ///! (any) [RFC8949] Expected conversion to base64 encoding + ZCBOR_TAG_2BASE16 = 23, ///! (any) [RFC8949] Expected conversion to base16 encoding + ZCBOR_TAG_BSTR = 24, ///! byte string [RFC8949] Encoded CBOR data item + ZCBOR_TAG_URI_TSTR = 32, ///! text string [RFC8949] URI + ZCBOR_TAG_BASE64URL_TSTR = 33, ///! text string [RFC8949] base64url + ZCBOR_TAG_BASE64_TSTR = 34, ///! text string [RFC8949] base64 + ZCBOR_TAG_REGEX = 35, ///! text string [RFC7049] Regular expression (UTF-8) + ZCBOR_TAG_MIME_TSTR = 36, ///! text string [RFC8949] MIME message + ZCBOR_TAG_LANG_TSTR = 38, ///! array [RFC9290] Text string with language tag + ZCBOR_TAG_MULTI_DIM_ARR_R = 40, ///! array of arrays [RFC8746] Multi-dimensional array, row-major order + ZCBOR_TAG_HOMOG_ARR = 41, ///! array [RFC8746] Homogeneous array + ZCBOR_TAG_YANG_BITS = 42, ///! text string [RFC9254] YANG bits datatype; see Section 6.7. + ZCBOR_TAG_YANG_ENUM = 43, ///! text string [RFC9254] YANG enumeration datatype; see Section 6.6. + ZCBOR_TAG_YANG_IDENTITYREF = 44, ///! uint/tstr [RFC9254] YANG identityref datatype; see Section 6.10. + ZCBOR_TAG_YANK_INSTANCE_ID = 45, ///! uint/tstr/array [RFC9254] YANG instance-identifier datatype; see Section 6.13. + ZCBOR_TAG_SID = 46, ///! uint [RFC9254] YANG Schema Item iDentifier (sid); see Section 3.2. + ZCBOR_TAG_IPV4 = 52, ///! bstr or array [RFC9164] IPv4 + ZCBOR_TAG_IPV6 = 54, ///! bstr or array [RFC9164] IPv6 + ZCBOR_TAG_CWT = 61, ///! CWT [RFC8392] CBOR Web Token + ZCBOR_TAG_TYPED_ARR_U8 = 64, ///! byte string [RFC8746] uint8 Typed Array + ZCBOR_TAG_TYPED_ARR_U16_BE = 65, ///! byte string [RFC8746] uint16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U32_BE = 66, ///! byte string [RFC8746] uint32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U64_BE = 67, ///! byte string [RFC8746] uint64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U8_CA = 68, ///! byte string [RFC8746] uint8 Typed Array, clamped arithmetic + ZCBOR_TAG_TYPED_ARR_U16_LE = 69, ///! byte string [RFC8746] uint16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U32_LE = 70, ///! byte string [RFC8746] uint32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_U64_LE = 71, ///! byte string [RFC8746] uint64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S8 = 72, ///! byte string [RFC8746] sint8 Typed Array + ZCBOR_TAG_TYPED_ARR_S16_BE = 73, ///! byte string [RFC8746] sint16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S32_BE = 74, ///! byte string [RFC8746] sint32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S64_BE = 75, ///! byte string [RFC8746] sint64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S16_LE = 77, ///! byte string [RFC8746] sint16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S32_LE = 78, ///! byte string [RFC8746] sint32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_S64_LE = 79, ///! byte string [RFC8746] sint64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F16_BE = 80, ///! byte string [RFC8746] IEEE 754 binary16, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F32_BE = 81, ///! byte string [RFC8746] IEEE 754 binary32, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F64_BE = 82, ///! byte string [RFC8746] IEEE 754 binary64, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F128_BE = 83, ///! byte string [RFC8746] IEEE 754 binary128, big endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F16_LE = 84, ///! byte string [RFC8746] IEEE 754 binary16, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F32_LE = 85, ///! byte string [RFC8746] IEEE 754 binary32, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F64_LE = 86, ///! byte string [RFC8746] IEEE 754 binary64, little endian, Typed Array + ZCBOR_TAG_TYPED_ARR_F128_LE = 87, ///! byte string [RFC8746] IEEE 754 binary128, little endian, Typed Array + ZCBOR_TAG_COSE_ENCRYPT = 96, ///! COSE_Encrypt [RFC9052] COSE Encrypted Data Object + ZCBOR_TAG_COSE_MAC = 97, ///! COSE_Mac [RFC9052] COSE MACed Data Object + ZCBOR_TAG_COSE_SIGN = 98, ///! COSE_Sign [RFC9052] COSE Signed Data Object + ZCBOR_TAG_EPOCH_DAYS = 100, ///! integer [RFC8943] Number of days since the epoch date 1970-01-01 + ZCBOR_TAG_REL_OID_BER_SDNV = 110, ///! bstr/array/map [RFC9090] relative object identifier (BER encoding); SDNV [RFC6256] sequence + ZCBOR_TAG_OID_BER = 111, ///! bstr/array/map [RFC9090] object identifier (BER encoding) + ZCBOR_TAG_PEN_REL_OID_BER = 112, ///! bstr/array/map [RFC9090] object identifier (BER encoding), relative to 1.3.6.1.4.1 + ZCBOR_TAG_DOTS_SIG_CHAN_OBJ = 271, ///! DOTS sig chan obj [RFC9132] DDoS Open Threat Signaling (DOTS) signal channel object + ZCBOR_TAG_FULL_DATE_STR = 1004, ///! tstr (UTF-8) [RFC8943] Full-date string + ZCBOR_TAG_MULTI_DIM_ARR_C = 1040, ///! array of arrays [RFC8746] Multi-dimensional array, column-major order + ZCBOR_TAG_CBOR = 55799, ///! (any) [RFC8949] Self-described CBOR + ZCBOR_TAG_CBOR_SEQ_FILE = 55800, ///! tagged bstr [RFC9277] indicates that the file contains CBOR Sequences + ZCBOR_TAG_CBOR_FILE_LABEL = 55801, ///! tagged bstr [RFC9277] indicates that the file starts with a CBOR-Labeled Non-CBOR Data label. + ZCBOR_TAG_COAP_CT = 1668546817, ///! bstr or (any) [RFC9277] Start of range: the representation of content-format ct < 65025 is indicated by tag number TN(ct) = 0x63740101 + (ct / 255) * 256 + ct % 255 + ZCBOR_TAG_COAP_CT_END = 1668612095, ///! bstr or (any) [RFC9277] End of range: the representation of content-format ct < 65025 is indicated by tag number TN(ct) = 0x63740101 + (ct / 255) * 256 + ct % 255 +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* ZCBOR_TAGS_H__ */ diff --git a/boot/zcbor/src/zcbor_common.c b/boot/zcbor/src/zcbor_common.c index e7a5e3aee..af93e7ff4 100644 --- a/boot/zcbor/src/zcbor_common.c +++ b/boot/zcbor/src/zcbor_common.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -14,6 +14,7 @@ #include #include #include "zcbor_common.h" +#include "zcbor_print.h" _Static_assert((sizeof(size_t) == sizeof(void *)), "This code needs size_t to be the same length as pointers."); @@ -21,7 +22,7 @@ _Static_assert((sizeof(size_t) == sizeof(void *)), _Static_assert((sizeof(zcbor_state_t) >= sizeof(struct zcbor_state_constant)), "This code needs zcbor_state_t to be at least as large as zcbor_backups_t."); -bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) +bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count) { ZCBOR_CHECK_ERROR(); @@ -36,39 +37,41 @@ bool zcbor_new_backup(zcbor_state_t *state, uint_fast32_t new_elem_count) /* use the backup at current_backup - 1, since otherwise, the 0th * backup would be unused. */ - uint_fast32_t i = (state->constant_state->current_backup) - 1; + size_t i = (state->constant_state->current_backup) - 1; memcpy(&state->constant_state->backup_list[i], state, sizeof(zcbor_state_t)); state->elem_count = new_elem_count; + zcbor_log("New backup (level %zu)\n", i); + return true; } bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, - uint_fast32_t max_elem_count) + size_t max_elem_count) { - const uint8_t *payload = state->payload; - const uint_fast32_t elem_count = state->elem_count; - ZCBOR_CHECK_ERROR(); + zcbor_state_t local_copy = *state; if (state->constant_state->current_backup == 0) { - zcbor_print("No backups available.\r\n"); + zcbor_log("No backups available.\r\n"); ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_ACTIVE); } - if (flags & ZCBOR_FLAG_RESTORE) { - /* use the backup at current_backup - 1, since otherwise, the - * 0th backup would be unused. */ - uint_fast32_t i = state->constant_state->current_backup - 1; + /* use the backup at current_backup - 1, since otherwise, the + * 0th backup would be unused. */ + size_t i = state->constant_state->current_backup - 1; + + zcbor_log("Process backup (level %zu, flags 0x%x)\n", i, flags); - if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) { + if (flags & ZCBOR_FLAG_RESTORE) { + if (!(flags & ZCBOR_FLAG_KEEP_PAYLOAD)) { if (state->constant_state->backup_list[i].payload_moved) { - zcbor_print("Payload pointer out of date.\r\n"); - ZCBOR_FAIL(); + zcbor_log("Payload pointer out of date.\r\n"); + ZCBOR_ERR(ZCBOR_ERR_PAYLOAD_OUTDATED); } } memcpy(state, &state->constant_state->backup_list[i], @@ -79,14 +82,19 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, state->constant_state->current_backup--; } - if (elem_count > max_elem_count) { - zcbor_print("elem_count: %" PRIuFAST32 " (expected max %" PRIuFAST32 ")\r\n", - elem_count, max_elem_count); + if (local_copy.elem_count > max_elem_count) { + zcbor_log("elem_count: %zu (expected max %zu)\r\n", + local_copy.elem_count, max_elem_count); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } - if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) { - state->payload = payload; + if (flags & ZCBOR_FLAG_KEEP_PAYLOAD) { + state->payload = local_copy.payload; + } + + if (flags & ZCBOR_FLAG_KEEP_DECODE_STATE) { + /* Copy decode state */ + state->decode_state = local_copy.decode_state; } return true; @@ -95,7 +103,7 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end) { if (state->constant_state) { - for (int i = 0; i < state->constant_state->current_backup; i++) { + for (unsigned int i = 0; i < state->constant_state->current_backup; i++) { state->constant_state->backup_list[i].payload_end = new_payload_end; state->constant_state->backup_list[i].payload_moved = true; } @@ -128,17 +136,26 @@ bool zcbor_union_end_code(zcbor_state_t *state) return true; } -void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *flags, size_t flags_bytes) { state_array[0].payload = payload; state_array[0].payload_end = payload + payload_len; state_array[0].elem_count = elem_count; - state_array[0].indefinite_length_array = false; state_array[0].payload_moved = false; + state_array[0].decode_state.indefinite_length_array = false; +#ifdef ZCBOR_MAP_SMART_SEARCH + state_array[0].decode_state.map_search_elem_state = flags; + state_array[0].decode_state.map_elem_count = 0; +#else + state_array[0].decode_state.map_elems_processed = 0; + (void)flags; + (void)flags_bytes; +#endif state_array[0].constant_state = NULL; - if(n_states < 2) { + if (n_states < 2) { return; } @@ -150,6 +167,10 @@ void zcbor_new_state(zcbor_state_t *state_array, uint_fast32_t n_states, state_array[0].constant_state->error = ZCBOR_SUCCESS; #ifdef ZCBOR_STOP_ON_ERROR state_array[0].constant_state->stop_on_error = false; +#endif + state_array[0].constant_state->manually_process_elem = false; +#ifdef ZCBOR_MAP_SMART_SEARCH + state_array[0].constant_state->map_search_elem_state_end = flags + flags_bytes; #endif if (n_states > 2) { state_array[0].constant_state->backup_list = &state_array[1]; @@ -167,7 +188,7 @@ void zcbor_update_state(zcbor_state_t *state, bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments) + size_t num_fragments) { size_t total_len = 0; @@ -175,7 +196,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { if (fragments[i].offset != total_len) { return false; } @@ -196,7 +217,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) { - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { fragments[i].total_len = total_len; } } @@ -205,7 +226,7 @@ bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments, } bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, - uint_fast32_t num_fragments, uint8_t *result, size_t *result_len) + size_t num_fragments, uint8_t *result, size_t *result_len) { size_t total_len = 0; @@ -213,7 +234,7 @@ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, return false; } - for (uint_fast32_t i = 0; i < num_fragments; i++) { + for (size_t i = 0; i < num_fragments; i++) { if ((total_len > *result_len) || (fragments[i].fragment.len > (*result_len - total_len))) { return false; @@ -226,3 +247,189 @@ bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments, *result_len = total_len; return true; } + + +bool zcbor_compare_strings(const struct zcbor_string *str1, + const struct zcbor_string *str2) +{ + return (str1 != NULL) && (str2 != NULL) + && (str1->value != NULL) && (str2->value != NULL) && (str1->len == str2->len) + && (memcmp(str1->value, str2->value, str1->len) == 0); +} + + +size_t zcbor_header_len(uint64_t value) +{ + if (value <= ZCBOR_VALUE_IN_HEADER) { + return 1; + } else if (value <= 0xFF) { + return 2; + } else if (value <= 0xFFFF) { + return 3; + } else if (value <= 0xFFFFFFFF) { + return 5; + } else { + return 9; + } +} + + +size_t zcbor_header_len_ptr(const void *const value, size_t value_len) +{ + uint64_t val64 = 0; + + if (value_len > sizeof(val64)) { + return 0; + } + + memcpy(((uint8_t*)&val64) + ZCBOR_ECPY_OFFS(sizeof(val64), value_len), value, value_len); + return zcbor_header_len(val64); +} + + +int zcbor_entry_function(const uint8_t *payload, size_t payload_len, + void *result, size_t *payload_len_out, zcbor_state_t *state, zcbor_decoder_t func, + size_t n_states, size_t elem_count) +{ + zcbor_new_state(state, n_states, payload, payload_len, elem_count, NULL, 0); + + bool ret = func(state, result); + + if (!ret) { + int err = zcbor_pop_error(state); + + err = (err == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : err; + return err; + } + + if (payload_len_out != NULL) { + *payload_len_out = MIN(payload_len, + (size_t)state[0].payload - (size_t)payload); + } + return ZCBOR_SUCCESS; +} + + +/* Float16: */ +#define F16_SIGN_OFFS 15 /* Bit offset of the sign bit. */ +#define F16_EXPO_OFFS 10 /* Bit offset of the exponent. */ +#define F16_EXPO_MSK 0x1F /* Bitmask for the exponent (right shifted by F16_EXPO_OFFS). */ +#define F16_MANTISSA_MSK 0x3FF /* Bitmask for the mantissa. */ +#define F16_MAX 65520 /* Lowest float32 value that rounds up to float16 infinity. + * (65519.996 rounds to 65504) */ +#define F16_MIN_EXPO 24 /* Negative exponent of the non-zero float16 value closest to 0 (2^-24) */ +#define F16_MIN (1.0f / (1 << F16_MIN_EXPO)) /* The non-zero float16 value closest to 0 (2^-24) */ +#define F16_MIN_NORM (1.0f / (1 << 14)) /* The normalized float16 value closest to 0 (2^-14) */ +#define F16_BIAS 15 /* The exponent bias of normalized float16 values. */ + +/* Float32: */ +#define F32_SIGN_OFFS 31 /* Bit offset of the sign bit. */ +#define F32_EXPO_OFFS 23 /* Bit offset of the exponent. */ +#define F32_EXPO_MSK 0xFF /* Bitmask for the exponent (right shifted by F32_EXPO_OFFS). */ +#define F32_MANTISSA_MSK 0x7FFFFF /* Bitmask for the mantissa. */ +#define F32_BIAS 127 /* The exponent bias of normalized float32 values. */ + +/* Rounding: */ +#define SUBNORM_ROUND_MSK (F32_MANTISSA_MSK | (1 << F32_EXPO_OFFS)) /* mantissa + lsb of expo for + * tiebreak. */ +#define SUBNORM_ROUND_BIT_MSK (1 << (F32_EXPO_OFFS - 1)) /* msb of mantissa (0x400000) */ +#define NORM_ROUND_MSK (F32_MANTISSA_MSK >> (F16_EXPO_OFFS - 1)) /* excess mantissa when going from + * float32 to float16 + 1 extra bit + * for tiebreak. */ +#define NORM_ROUND_BIT_MSK (1 << (F32_EXPO_OFFS - F16_EXPO_OFFS - 1)) /* bit 12 (0x1000) */ + + +float zcbor_float16_to_32(uint16_t input) +{ + uint32_t sign = input >> F16_SIGN_OFFS; + uint32_t expo = (input >> F16_EXPO_OFFS) & F16_EXPO_MSK; + uint32_t mantissa = input & F16_MANTISSA_MSK; + + if ((expo == 0) && (mantissa != 0)) { + /* Subnormal float16 - convert to normalized float32 */ + return ((float)mantissa * F16_MIN) * (sign ? -1 : 1); + } else { + /* Normalized / zero / Infinity / NaN */ + uint32_t new_expo = (expo == 0 /* zero */) ? 0 + : (expo == F16_EXPO_MSK /* inf/NaN */) ? F32_EXPO_MSK + : (expo + (F32_BIAS - F16_BIAS)); + uint32_t value32 = (sign << F32_SIGN_OFFS) | (new_expo << F32_EXPO_OFFS) + | (mantissa << (F32_EXPO_OFFS - F16_EXPO_OFFS)); + return *(float *)&value32; + } +} + + +uint16_t zcbor_float32_to_16(float input) +{ + uint32_t value32 = *(uint32_t *)&input; + + uint32_t sign = value32 >> F32_SIGN_OFFS; + uint32_t expo = (value32 >> F32_EXPO_OFFS) & F32_EXPO_MSK; + uint32_t mantissa = value32 & F32_MANTISSA_MSK; + + uint16_t value16 = (uint16_t)(sign << F16_SIGN_OFFS); + + float abs_input; + *(uint32_t *)&abs_input = value32 & ~(1 << F32_SIGN_OFFS); + + if (abs_input <= (F16_MIN / 2)) { + /* 0 or too small for float16. Round down to 0. value16 is already correct. */ + } else if (abs_input < F16_MIN) { + /* Round up to 2^(-24) (F16_MIN), has other rounding rules than larger values. */ + value16 |= 0x0001; + } else if (abs_input < F16_MIN_NORM) { + /* Subnormal float16 (normal float32) */ + uint32_t adjusted_mantissa = + /* Adjust for the purposes of checking rounding. */ + /* The lsb of expo is needed for the cases where expo is 103 (minimum). */ + ((value32 << (expo - (F32_BIAS - F16_MIN_EXPO))) & SUBNORM_ROUND_MSK); + uint16_t rounding_bit = + /* "Round to nearest, ties to even". */ + /* 0x400000 means ties go down towards even. (0xC00000 means ties go up.) */ + (adjusted_mantissa & SUBNORM_ROUND_BIT_MSK) + && (adjusted_mantissa != SUBNORM_ROUND_BIT_MSK); + value16 |= ((uint16_t)(abs_input * (1 << 24)) + rounding_bit); /* expo is 0 */ + } else if (abs_input < F16_MAX) { + /* Normal float16 (normal float32) */ + uint16_t rounding_bit = + /* Bit 13 of the mantissa represents which way to round, except for the */ + /* special case where bits 0-12 and 14 are 0. */ + /* This is because of "Round to nearest, ties to even". */ + /* 0x1000 means ties go down towards even. (0x3000 means ties go up.) */ + ((mantissa & NORM_ROUND_BIT_MSK) + && ((mantissa & NORM_ROUND_MSK) != NORM_ROUND_BIT_MSK)); + value16 |= (uint16_t)((expo - (F32_BIAS - F16_BIAS)) << F16_EXPO_OFFS); + value16 |= (uint16_t)(mantissa >> (F32_EXPO_OFFS - F16_EXPO_OFFS)); + value16 += rounding_bit; /* Might propagate to exponent. */ + } else if (expo != F32_EXPO_MSK || !mantissa) { + /* Infinite, or finite normal float32 too large for float16. Round up to inf. */ + value16 |= (F16_EXPO_MSK << F16_EXPO_OFFS); + } else { + /* NaN */ + /* Preserve msbit of mantissa. */ + uint16_t new_mantissa = (uint16_t)(mantissa >> (F32_EXPO_OFFS - F16_EXPO_OFFS)); + value16 |= (F16_EXPO_MSK << F16_EXPO_OFFS) | (new_mantissa ? new_mantissa : 1); + } + + return value16; +} + + +/** Weak strnlen() implementation in case it is not available. + * + * This function is in the public domain, according to: + * https://github.com/arm-embedded/gcc-arm-none-eabi.debian/blob/master/src/libiberty/strnlen.c + */ +__attribute__((__weak__)) +size_t strnlen (const char *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen; ++i) { + if (s[i] == '\0') { + break; + } + } + return i; +} diff --git a/boot/zcbor/src/zcbor_decode.c b/boot/zcbor/src/zcbor_decode.c index c99fc8385..841c34171 100644 --- a/boot/zcbor/src/zcbor_decode.c +++ b/boot/zcbor/src/zcbor_decode.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -13,15 +13,19 @@ #include #include #include -#include -#include +#include +#include "zcbor_decode.h" +#include "zcbor_common.h" +#include "zcbor_print.h" /** Return value length from additional value. */ -static uint_fast32_t additional_len(uint8_t additional) +static size_t additional_len(uint8_t additional) { - if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { + if (additional <= ZCBOR_VALUE_IN_HEADER) { + return 0; + } else if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) { /* 24 => 1 * 25 => 2 * 26 => 4 @@ -29,23 +33,9 @@ static uint_fast32_t additional_len(uint8_t additional) */ return 1U << (additional - ZCBOR_VALUE_IS_1_BYTE); } - return 0; + return 0xF; } -/** Extract the major type, i.e. the first 3 bits of the header byte. */ -#define MAJOR_TYPE(header_byte) ((zcbor_major_type_t)(((header_byte) >> 5) & 0x7)) - -/** Extract the additional info, i.e. the last 5 bits of the header byte. */ -#define ADDITIONAL(header_byte) ((header_byte) & 0x1F) - - -#define FAIL_AND_DECR_IF(expr, err) \ -do {\ - if (expr) { \ - (state->payload)--; \ - ZCBOR_ERR(err); \ - } \ -} while(0) static bool initial_checks(zcbor_state_t *state) { @@ -54,12 +44,13 @@ static bool initial_checks(zcbor_state_t *state) return true; } + static bool type_check(zcbor_state_t *state, zcbor_major_type_t exp_major_type) { if (!initial_checks(state)) { ZCBOR_FAIL(); } - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); if (major_type != exp_major_type) { ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); @@ -67,6 +58,7 @@ static bool type_check(zcbor_state_t *state, zcbor_major_type_t exp_major_type) return true; } + #define INITIAL_CHECKS() \ do {\ if (!initial_checks(state)) { \ @@ -81,11 +73,17 @@ do {\ } \ } while(0) +static void err_restore(zcbor_state_t *state, int err) +{ + state->payload = state->payload_bak; + state->elem_count++; + zcbor_error(state, err); +} + #define ERR_RESTORE(err) \ do { \ - state->payload = state->payload_bak; \ - state->elem_count++; \ - ZCBOR_ERR(err); \ + err_restore(state, err); \ + ZCBOR_FAIL(); \ } while(0) #define FAIL_RESTORE() \ @@ -95,6 +93,21 @@ do { \ ZCBOR_FAIL(); \ } while(0) +#define PRINT_FUNC() zcbor_log("%s ", __func__); + + +static void endian_copy(uint8_t *dst, const uint8_t *src, size_t src_len) +{ +#ifdef ZCBOR_BIG_ENDIAN + memcpy(dst, src, src_len); +#else + for (size_t i = 0; i < src_len; i++) { + dst[i] = src[src_len - 1 - i]; + } +#endif /* ZCBOR_BIG_ENDIAN */ +} + + /** Get a single value. * * @details @p ppayload must point to the header byte. This function will @@ -111,61 +124,55 @@ do { \ * succeeds. If not, they are left unchanged. * * CBOR values are always big-endian, so this function converts from - * big to little-endian if necessary (@ref CONFIG_BIG_ENDIAN). + * big to little-endian if necessary (@ref ZCBOR_BIG_ENDIAN). */ static bool value_extract(zcbor_state_t *state, - void *const result, uint_fast32_t result_len) + void *const result, size_t result_len) { - zcbor_trace(); + zcbor_trace(state, "value_extract"); zcbor_assert_state(result_len != 0, "0-length result not supported.\r\n"); - zcbor_assert_state(result != NULL, NULL); + zcbor_assert_state(result_len <= 8, "result sizes above 8 bytes not supported.\r\n"); + zcbor_assert_state(result != NULL, "result cannot be NULL.\r\n"); INITIAL_CHECKS(); ZCBOR_ERR_IF((state->elem_count == 0), ZCBOR_ERR_LOW_ELEM_COUNT); - uint8_t *u8_result = (uint8_t *)result; - uint8_t additional = ADDITIONAL(*state->payload); + uint8_t additional = ZCBOR_ADDITIONAL(*state->payload); + size_t len = additional_len(additional); + uint8_t *result_offs = (uint8_t *)result + ZCBOR_ECPY_OFFS(result_len, MAX(1, len)); - state->payload_bak = state->payload; - (state->payload)++; + ZCBOR_ERR_IF(additional > ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_ADDITIONAL_INVAL); + ZCBOR_ERR_IF(len > result_len, ZCBOR_ERR_INT_SIZE); + ZCBOR_ERR_IF((state->payload + len + 1) > state->payload_end, + ZCBOR_ERR_NO_PAYLOAD); memset(result, 0, result_len); - if (additional <= ZCBOR_VALUE_IN_HEADER) { -#ifdef CONFIG_BIG_ENDIAN - u8_result[result_len - 1] = additional; -#else - u8_result[0] = additional; -#endif /* CONFIG_BIG_ENDIAN */ - } else { - uint_fast32_t len = additional_len(additional); - FAIL_AND_DECR_IF(len > result_len, ZCBOR_ERR_INT_SIZE); - FAIL_AND_DECR_IF(len == 0, ZCBOR_ERR_ADDITIONAL_INVAL); // additional_len() did not recognize the additional value. - FAIL_AND_DECR_IF((state->payload + len) > state->payload_end, - ZCBOR_ERR_NO_PAYLOAD); - -#ifdef CONFIG_BIG_ENDIAN - memcpy(&u8_result[result_len - len], state->payload, len); -#else - for (uint_fast32_t i = 0; i < len; i++) { - u8_result[i] = (state->payload)[len - i - 1]; - } -#endif /* CONFIG_BIG_ENDIAN */ + if (len == 0) { + *result_offs = additional; + } else { + endian_copy(result_offs, state->payload + 1, len); - (state->payload) += len; +#ifdef ZCBOR_CANONICAL + ZCBOR_ERR_IF((zcbor_header_len_ptr(result, result_len) != (len + 1)), + ZCBOR_ERR_INVALID_VALUE_ENCODING); +#endif } + state->payload_bak = state->payload; + (state->payload) += len + 1; (state->elem_count)--; return true; } -bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) +bool zcbor_int_decode(zcbor_state_t *state, void *result, size_t result_size) { + PRINT_FUNC(); INITIAL_CHECKS(); - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); - uint8_t *result_uint8 = (uint8_t *)result_int; - int8_t *result_int8 = (int8_t *)result_int; + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); + uint8_t *result_uint8 = (uint8_t *)result; + int8_t *result_int8 = (int8_t *)result; if (major_type != ZCBOR_MAJOR_TYPE_PINT && major_type != ZCBOR_MAJOR_TYPE_NINT) { @@ -173,14 +180,14 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE); } - if (!value_extract(state, result_int, int_size)) { + if (!value_extract(state, result, result_size)) { ZCBOR_FAIL(); } -#ifdef CONFIG_BIG_ENDIAN +#ifdef ZCBOR_BIG_ENDIAN if (result_int8[0] < 0) { #else - if (result_int8[int_size - 1] < 0) { + if (result_int8[result_size - 1] < 0) { #endif /* Value is too large to fit in a signed integer. */ ERR_RESTORE(ZCBOR_ERR_INT_SIZE); @@ -188,7 +195,7 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) if (major_type == ZCBOR_MAJOR_TYPE_NINT) { /* Convert from CBOR's representation by flipping all bits. */ - for (int i = 0; i < int_size; i++) { + for (unsigned int i = 0; i < result_size; i++) { result_uint8[i] = (uint8_t)~result_uint8[i]; } } @@ -199,29 +206,41 @@ bool zcbor_int_decode(zcbor_state_t *state, void *result_int, size_t int_size) bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result) { + PRINT_FUNC(); return zcbor_int_decode(state, result, sizeof(*result)); } bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result) { + PRINT_FUNC(); return zcbor_int_decode(state, result, sizeof(*result)); } -bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) +bool zcbor_uint_decode(zcbor_state_t *state, void *result, size_t result_size) { + PRINT_FUNC(); INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); - if (!value_extract(state, result, sizeof(*result))) { + if (!value_extract(state, result, result_size)) { + zcbor_log("uint with size %zu failed.\r\n", result_size); ZCBOR_FAIL(); } return true; } +bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result) +{ + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); +} + + bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -231,6 +250,7 @@ bool zcbor_int32_expect_union(zcbor_state_t *state, int32_t result) bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -240,6 +260,7 @@ bool zcbor_int64_expect_union(zcbor_state_t *state, int64_t result) bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -249,6 +270,7 @@ bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result) bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) { + PRINT_FUNC(); if (!zcbor_union_elem_code(state)) { ZCBOR_FAIL(); } @@ -256,72 +278,109 @@ bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result) } -bool zcbor_int32_expect(zcbor_state_t *state, int32_t result) +bool zcbor_int32_expect(zcbor_state_t *state, int32_t expected) { - return zcbor_int64_expect(state, result); + PRINT_FUNC(); + return zcbor_int64_expect(state, expected); +} + + +bool zcbor_int32_pexpect(zcbor_state_t *state, int32_t *expected) +{ + PRINT_FUNC(); + return zcbor_int32_expect(state, *expected); } -bool zcbor_int64_expect(zcbor_state_t *state, int64_t result) +bool zcbor_int64_expect(zcbor_state_t *state, int64_t expected) { - int64_t value; + PRINT_FUNC(); + int64_t actual; - if (!zcbor_int64_decode(state, &value)) { + if (!zcbor_int64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { - zcbor_print("%" PRIi64 " != %" PRIi64 "\r\n", value, result); + if (actual != expected) { + zcbor_log("%" PRIi64 " != %" PRIi64 "\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) +bool zcbor_int64_pexpect(zcbor_state_t *state, int64_t *expected) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT); + PRINT_FUNC(); + return zcbor_int64_expect(state, *expected); +} - if (!value_extract(state, result, sizeof(*result))) { - ZCBOR_FAIL(); - } - return true; + +bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result) +{ + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_decode(zcbor_state_t *state, size_t *result) { - return value_extract(state, result, sizeof(size_t)); + PRINT_FUNC(); + return zcbor_uint_decode(state, result, sizeof(*result)); } #endif -bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result) +bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t expected) { - return zcbor_uint64_expect(state, result); + PRINT_FUNC(); + return zcbor_uint64_expect(state, expected); +} + + +bool zcbor_uint32_pexpect(zcbor_state_t *state, uint32_t *expected) +{ + PRINT_FUNC(); + return zcbor_uint32_expect(state, *expected); } -bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result) +bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t expected) { - uint64_t value; + PRINT_FUNC(); + uint64_t actual; - if (!zcbor_uint64_decode(state, &value)) { + if (!zcbor_uint64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { - zcbor_print("%" PRIu64 " != %" PRIu64 "\r\n", value, result); + if (actual != expected) { + zcbor_log("%" PRIu64 " != %" PRIu64 "\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } +bool zcbor_uint64_pexpect(zcbor_state_t *state, uint64_t *expected) +{ + PRINT_FUNC(); + return zcbor_uint64_expect(state, *expected); +} + + #ifdef ZCBOR_SUPPORTS_SIZE_T -bool zcbor_size_expect(zcbor_state_t *state, size_t result) +bool zcbor_size_expect(zcbor_state_t *state, size_t expected) { - return zcbor_uint64_expect(state, result); + PRINT_FUNC(); + return zcbor_uint64_expect(state, expected); +} + + +bool zcbor_size_pexpect(zcbor_state_t *state, size_t *expected) +{ + PRINT_FUNC(); + return zcbor_size_expect(state, *expected); } #endif @@ -339,31 +398,37 @@ static bool str_start_decode(zcbor_state_t *state, return true; } - -static bool str_overflow_check(zcbor_state_t *state, struct zcbor_string *result) +static bool str_start_decode_with_overflow_check(zcbor_state_t *state, + struct zcbor_string *result, zcbor_major_type_t exp_major_type) { - if (result->len > (state->payload_end - state->payload)) { - zcbor_print("error: 0x%zu > 0x%zu\r\n", - result->len, - (state->payload_end - state->payload)); + bool res = str_start_decode(state, result, exp_major_type); + + if (!res) { + ZCBOR_FAIL(); + } + + /* Casting to size_t is safe since str_start_decode() checks that + * payload_end is bigger that payload. */ + if (result->len > (size_t)(state->payload_end - state->payload)) { + zcbor_log("error: 0x%zu > 0x%zu\r\n", + result->len, + (state->payload_end - state->payload)); ERR_RESTORE(ZCBOR_ERR_NO_PAYLOAD); } + return true; } bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); struct zcbor_string dummy; if (result == NULL) { result = &dummy; } - if(!str_start_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { - ZCBOR_FAIL(); - } - - if (!str_overflow_check(state, result)) { + if(!str_start_decode_with_overflow_check(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { ZCBOR_FAIL(); } @@ -381,7 +446,7 @@ bool zcbor_bstr_end_decode(zcbor_state_t *state) ZCBOR_ERR_IF(state->payload != state->payload_end, ZCBOR_ERR_PAYLOAD_NOT_CONSUMED); if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -402,6 +467,7 @@ static bool start_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result, zcbor_major_type_t exp_major_type) { + PRINT_FUNC(); if(!str_start_decode(state, &result->fragment, exp_major_type)) { ZCBOR_FAIL(); } @@ -417,6 +483,7 @@ static bool start_decode_fragment(zcbor_state_t *state, bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); if (!start_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { ZCBOR_FAIL(); } @@ -437,7 +504,7 @@ void zcbor_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_print("New fragment length %zu\r\n", result->fragment.len); + zcbor_log("New fragment length %zu\r\n", result->fragment.len); state->payload += result->fragment.len; } @@ -453,7 +520,7 @@ void zcbor_bstr_next_fragment(zcbor_state_t *state, result->fragment.len = result->total_len - result->offset; partition_fragment(state, result); - zcbor_print("fragment length %zu\r\n", result->fragment.len); + zcbor_log("fragment length %zu\r\n", result->fragment.len); state->payload_end = state->payload + result->fragment.len; } @@ -467,11 +534,7 @@ bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment) static bool str_decode(zcbor_state_t *state, struct zcbor_string *result, zcbor_major_type_t exp_major_type) { - if (!str_start_decode(state, result, exp_major_type)) { - ZCBOR_FAIL(); - } - - if (!str_overflow_check(state, result)) { + if (!str_start_decode_with_overflow_check(state, result, exp_major_type)) { ZCBOR_FAIL(); } @@ -500,8 +563,7 @@ static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, if (!str_decode(state, &tmp_result, exp_major_type)) { ZCBOR_FAIL(); } - if ((tmp_result.len != result->len) - || memcmp(result->value, tmp_result.value, tmp_result.len)) { + if (!zcbor_compare_strings(&tmp_result, result)) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; @@ -510,56 +572,97 @@ static bool str_expect(zcbor_state_t *state, struct zcbor_string *result, bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); return str_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR); } bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR); } -bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result) +bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *expected) { - return str_expect(state, result, ZCBOR_MAJOR_TYPE_BSTR); + PRINT_FUNC(); + return str_expect(state, expected, ZCBOR_MAJOR_TYPE_BSTR); } bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result) { + PRINT_FUNC(); return str_decode(state, result, ZCBOR_MAJOR_TYPE_TSTR); } bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) { + PRINT_FUNC(); return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_TSTR); } -bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result) +bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *expected) +{ + PRINT_FUNC(); + return str_expect(state, expected, ZCBOR_MAJOR_TYPE_TSTR); +} + + +bool zcbor_bstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + PRINT_FUNC(); + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_bstr_expect(state, &zs); +} + + +bool zcbor_tstr_expect_ptr(zcbor_state_t *state, char const *ptr, size_t len) { - return str_expect(state, result, ZCBOR_MAJOR_TYPE_TSTR); + PRINT_FUNC(); + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_tstr_expect(state, &zs); +} + + +bool zcbor_bstr_expect_term(zcbor_state_t *state, char const *string, size_t maxlen) +{ + PRINT_FUNC(); + return zcbor_bstr_expect_ptr(state, string, strnlen(string, maxlen)); +} + + +bool zcbor_tstr_expect_term(zcbor_state_t *state, char const *string, size_t maxlen) +{ + PRINT_FUNC(); + return zcbor_tstr_expect_ptr(state, string, strnlen(string, maxlen)); } static bool list_map_start_decode(zcbor_state_t *state, zcbor_major_type_t exp_major_type) { - uint_fast32_t new_elem_count; + size_t new_elem_count; bool indefinite_length_array = false; INITIAL_CHECKS_WITH_TYPE(exp_major_type); - if (ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { +#ifndef ZCBOR_CANONICAL + if (ZCBOR_ADDITIONAL(*state->payload) == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { /* Indefinite length array. */ new_elem_count = ZCBOR_LARGE_ELEM_COUNT; ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); indefinite_length_array = true; - state->payload++; + state->payload_bak = state->payload++; state->elem_count--; - } else { + } else +#endif + { if (!value_extract(state, &new_elem_count, sizeof(new_elem_count))) { ZCBOR_FAIL(); } @@ -569,7 +672,7 @@ static bool list_map_start_decode(zcbor_state_t *state, FAIL_RESTORE(); } - state->indefinite_length_array = indefinite_length_array; + state->decode_state.indefinite_length_array = indefinite_length_array; return true; } @@ -577,15 +680,17 @@ static bool list_map_start_decode(zcbor_state_t *state, bool zcbor_list_start_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_start_decode(state, ZCBOR_MAJOR_TYPE_LIST); } bool zcbor_map_start_decode(zcbor_state_t *state) { + PRINT_FUNC(); bool ret = list_map_start_decode(state, ZCBOR_MAJOR_TYPE_MAP); - if (ret && !state->indefinite_length_array) { + if (ret && !state->decode_state.indefinite_length_array) { if (state->elem_count >= (ZCBOR_MAX_ELEM_COUNT / 2)) { /* The new elem_count is too large. */ ERR_RESTORE(ZCBOR_ERR_INT_SIZE); @@ -596,6 +701,272 @@ bool zcbor_map_start_decode(zcbor_state_t *state) } +bool zcbor_array_at_end(zcbor_state_t *state) +{ +#ifdef ZCBOR_CANONICAL + const bool indefinite_length_array = false; +#else + const bool indefinite_length_array = state->decode_state.indefinite_length_array; +#endif + return ((!indefinite_length_array && (state->elem_count == 0)) + || (indefinite_length_array + && (state->payload < state->payload_end) + && (*state->payload == 0xFF))); +} + + +static size_t update_map_elem_count(zcbor_state_t *state, size_t elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH +static bool allocate_map_flags(zcbor_state_t *state, size_t elem_count); +#endif + + +bool zcbor_unordered_map_start_decode(zcbor_state_t *state) +{ + PRINT_FUNC(); + ZCBOR_FAIL_IF(!zcbor_map_start_decode(state)); + +#ifdef ZCBOR_MAP_SMART_SEARCH + state->decode_state.map_search_elem_state + += zcbor_flags_to_bytes(state->decode_state.map_elem_count); +#else + state->decode_state.map_elems_processed = 0; +#endif + state->decode_state.map_elem_count = 0; + state->decode_state.counting_map_elems = state->decode_state.indefinite_length_array; + + if (!state->decode_state.counting_map_elems) { + size_t old_flags = update_map_elem_count(state, state->elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH + ZCBOR_FAIL_IF(!allocate_map_flags(state, old_flags)); +#endif + (void)old_flags; + } + + return true; +} + + +/** Return the max (starting) elem_count of the current container. + * + * Should only be used for unordered maps (started with @ref zcbor_unordered_map_start_decode) + */ +static size_t zcbor_current_max_elem_count(zcbor_state_t *state) +{ + return (state->decode_state.indefinite_length_array ? \ + ZCBOR_LARGE_ELEM_COUNT : state->decode_state.map_elem_count * 2); +} + + +static bool map_restart(zcbor_state_t *state) +{ + if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_KEEP_DECODE_STATE, + ZCBOR_MAX_ELEM_COUNT)) { + ZCBOR_FAIL(); + } + + state->elem_count = zcbor_current_max_elem_count(state); + return true; +} + + +__attribute__((used)) +static size_t get_current_index(zcbor_state_t *state, uint32_t index_offset) +{ + /* Subtract mode because for GET, you want the index you are pointing to, while for SET, + * you want the one you just processed. This only comes into play when elem_count is even. */ + return ((zcbor_current_max_elem_count(state) - state->elem_count - index_offset) / 2); +} + + +#ifdef ZCBOR_MAP_SMART_SEARCH +#define FLAG_MODE_GET_CURRENT 0 +#define FLAG_MODE_CLEAR_CURRENT 1 +#define FLAG_MODE_CLEAR_UNUSED 2 + +static bool manipulate_flags(zcbor_state_t *state, uint32_t mode) +{ + const size_t last_index = (state->decode_state.map_elem_count - 1); + size_t index = (mode == FLAG_MODE_CLEAR_UNUSED) ? last_index : get_current_index(state, mode); + + ZCBOR_ERR_IF((index >= state->decode_state.map_elem_count), + ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE); + uint8_t *flag_byte = &state->decode_state.map_search_elem_state[index >> 3]; + uint8_t flag_mask = (uint8_t)(1 << (index & 7)); + + switch(mode) { + case FLAG_MODE_GET_CURRENT: + return (!!(*flag_byte & flag_mask)); + case FLAG_MODE_CLEAR_CURRENT: + *flag_byte &= ~flag_mask; + return true; + case FLAG_MODE_CLEAR_UNUSED: + *flag_byte &= (uint8_t)((flag_mask << 1) - 1); + return true; + } + return false; +} + + +static bool should_try_key(zcbor_state_t *state) +{ + return manipulate_flags(state, FLAG_MODE_GET_CURRENT); +} + + +bool zcbor_elem_processed(zcbor_state_t *state) +{ + return manipulate_flags(state, FLAG_MODE_CLEAR_CURRENT); +} + + +static bool allocate_map_flags(zcbor_state_t *state, size_t old_flags) +{ + size_t new_bytes = zcbor_flags_to_bytes(state->decode_state.map_elem_count); + size_t old_bytes = zcbor_flags_to_bytes(old_flags); + size_t extra_bytes = new_bytes - old_bytes; + const uint8_t *flags_end = state->constant_state->map_search_elem_state_end; + + if (extra_bytes) { + if ((state->decode_state.map_search_elem_state + new_bytes) > flags_end) { + state->decode_state.map_elem_count + = 8 * (size_t)(flags_end - state->decode_state.map_search_elem_state); + ZCBOR_ERR(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE); + } + + memset(&state->decode_state.map_search_elem_state[new_bytes - extra_bytes], 0xFF, extra_bytes); + } + return true; +} +#else + +static bool should_try_key(zcbor_state_t *state) +{ + return (state->decode_state.map_elems_processed < state->decode_state.map_elem_count); +} + + +bool zcbor_elem_processed(zcbor_state_t *state) +{ + if (should_try_key(state)) { + state->decode_state.map_elems_processed++; + } + return true; +} +#endif + + +static size_t update_map_elem_count(zcbor_state_t *state, size_t elem_count) +{ + size_t old_map_elem_count = state->decode_state.map_elem_count; + + state->decode_state.map_elem_count = MAX(old_map_elem_count, elem_count / 2); + return old_map_elem_count; +} + + +static bool handle_map_end(zcbor_state_t *state) +{ + state->decode_state.counting_map_elems = false; + return map_restart(state); +} + + +static bool try_key(zcbor_state_t *state, void *key_result, zcbor_decoder_t key_decoder) +{ + uint8_t const *payload_bak2 = state->payload; + size_t elem_count_bak = state->elem_count; + + if (!key_decoder(state, (uint8_t *)key_result)) { + state->payload = payload_bak2; + state->elem_count = elem_count_bak; + return false; + } + + zcbor_log("Found element at index %zu.\n", get_current_index(state, 1)); + return true; +} + + +bool zcbor_unordered_map_search(zcbor_decoder_t key_decoder, zcbor_state_t *state, void *key_result) +{ + PRINT_FUNC(); + /* elem_count cannot be odd since the map consists of key-value-pairs. + * This might mean that this function was called while pointing at a value (instead + * of a key). */ + ZCBOR_ERR_IF(state->elem_count & 1, ZCBOR_ERR_MAP_MISALIGNED); + + uint8_t const *payload_bak = state->payload; + size_t elem_count = state->elem_count; + + /* Loop once through all the elements of the map. */ + do { + if (zcbor_array_at_end(state)) { + if (!handle_map_end(state)) { + goto error; + } + continue; /* This continue is needed so the loop stops both if elem_count is + * at the very start or the very end of the map. */ + } + + if (state->decode_state.counting_map_elems) { + size_t m_elem_count = ZCBOR_LARGE_ELEM_COUNT - state->elem_count + 2; + size_t old_flags = update_map_elem_count(state, m_elem_count); +#ifdef ZCBOR_MAP_SMART_SEARCH + ZCBOR_FAIL_IF(!allocate_map_flags(state, old_flags)); +#endif + (void)old_flags; + } + + if (should_try_key(state) && try_key(state, key_result, key_decoder)) { + if (!state->constant_state->manually_process_elem) { + ZCBOR_FAIL_IF(!zcbor_elem_processed(state)); + } + return true; + } + + /* Skip over both the key and the value. */ + if (!zcbor_any_skip(state, NULL) || !zcbor_any_skip(state, NULL)) { + goto error; + } + } while (state->elem_count != elem_count); + + zcbor_error(state, ZCBOR_ERR_ELEM_NOT_FOUND); +error: + state->payload = payload_bak; + state->elem_count = elem_count; + ZCBOR_FAIL(); +} + + +bool zcbor_search_key_bstr_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_unordered_map_search((zcbor_decoder_t *)zcbor_bstr_expect, state, &zs); +} + + +bool zcbor_search_key_tstr_ptr(zcbor_state_t *state, char const *ptr, size_t len) +{ + struct zcbor_string zs = { .value = (const uint8_t *)ptr, .len = len }; + + return zcbor_unordered_map_search((zcbor_decoder_t *)zcbor_tstr_expect, state, &zs); +} + + +bool zcbor_search_key_bstr_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_search_key_bstr_ptr(state, str, strnlen(str, maxlen)); +} + + +bool zcbor_search_key_tstr_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_search_key_tstr_ptr(state, str, strnlen(str, maxlen)); +} + + static bool array_end_expect(zcbor_state_t *state) { INITIAL_CHECKS(); @@ -608,17 +979,19 @@ static bool array_end_expect(zcbor_state_t *state) static bool list_map_end_decode(zcbor_state_t *state) { - uint_fast32_t max_elem_count = 0; + size_t max_elem_count = 0; - if (state->indefinite_length_array) { +#ifndef ZCBOR_CANONICAL + if (state->decode_state.indefinite_length_array) { if (!array_end_expect(state)) { ZCBOR_FAIL(); } max_elem_count = ZCBOR_MAX_ELEM_COUNT; - state->indefinite_length_array = false; + state->decode_state.indefinite_length_array = false; } +#endif if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, max_elem_count)) { ZCBOR_FAIL(); } @@ -629,20 +1002,51 @@ static bool list_map_end_decode(zcbor_state_t *state) bool zcbor_list_end_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_end_decode(state); } bool zcbor_map_end_decode(zcbor_state_t *state) { + PRINT_FUNC(); return list_map_end_decode(state); } +bool zcbor_unordered_map_end_decode(zcbor_state_t *state) +{ + /* Checking zcbor_array_at_end() ensures that check is valid. + * In case the map is at the end, but state->decode_state.counting_map_elems isn't updated.*/ + ZCBOR_ERR_IF(!zcbor_array_at_end(state) && state->decode_state.counting_map_elems, + ZCBOR_ERR_ELEMS_NOT_PROCESSED); + + if (state->decode_state.map_elem_count > 0) { +#ifdef ZCBOR_MAP_SMART_SEARCH + manipulate_flags(state, FLAG_MODE_CLEAR_UNUSED); + + for (size_t i = 0; i < zcbor_flags_to_bytes(state->decode_state.map_elem_count); i++) { + if (state->decode_state.map_search_elem_state[i] != 0) { + zcbor_log("unprocessed element(s) in map: [%zu] = 0x%02x\n", + i, state->decode_state.map_search_elem_state[i]); + ZCBOR_ERR(ZCBOR_ERR_ELEMS_NOT_PROCESSED); + } + } +#else + ZCBOR_ERR_IF(should_try_key(state), ZCBOR_ERR_ELEMS_NOT_PROCESSED); +#endif + } + while (!zcbor_array_at_end(state)) { + zcbor_any_skip(state, NULL); + } + return zcbor_map_end_decode(state); +} + + bool zcbor_list_map_end_force_decode(zcbor_state_t *state) { if (!zcbor_process_backup(state, - ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD, + ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_KEEP_PAYLOAD, ZCBOR_MAX_ELEM_COUNT)) { ZCBOR_FAIL(); } @@ -651,69 +1055,180 @@ bool zcbor_list_map_end_force_decode(zcbor_state_t *state) } -static bool primx_expect(zcbor_state_t *state, uint8_t result) +bool zcbor_simple_decode(zcbor_state_t *state, uint8_t *result) { - uint32_t value; + PRINT_FUNC(); + PRINT_FUNC(); + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_SIMPLE); + + /* Simple values must be 0-23 (additional is 0-23) or 24-255 (additional is 24). + * Other additional values are not considered simple values. */ + ZCBOR_ERR_IF(ZCBOR_ADDITIONAL(*state->payload) > 24, ZCBOR_ERR_WRONG_TYPE); + + if (!value_extract(state, result, sizeof(*result))) { + ZCBOR_FAIL(); + } + return true; +} - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - if (!value_extract(state, &value, sizeof(value))) { +bool zcbor_simple_expect(zcbor_state_t *state, uint8_t expected) +{ + PRINT_FUNC(); + uint8_t actual; + + if (!zcbor_simple_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { + zcbor_log("simple value %u != %u\r\n", actual, expected); ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } + return true; } +bool zcbor_simple_pexpect(zcbor_state_t *state, uint8_t *expected) +{ + PRINT_FUNC(); + return zcbor_simple_expect(state, *expected); +} + + bool zcbor_nil_expect(zcbor_state_t *state, void *unused) { - if (!primx_expect(state, 22)) { + PRINT_FUNC(); + (void)unused; + return zcbor_simple_expect(state, 22); +} + + +bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) +{ + PRINT_FUNC(); + (void)unused; + return zcbor_simple_expect(state, 23); +} + + +bool zcbor_bool_decode(zcbor_state_t *state, bool *result) +{ + PRINT_FUNC(); + uint8_t value; + + if (!zcbor_simple_decode(state, &value)) { ZCBOR_FAIL(); } + value -= ZCBOR_BOOL_TO_SIMPLE; + if (value > 1) { + ERR_RESTORE(ZCBOR_ERR_WRONG_TYPE); + } + *result = value; + + zcbor_log("boolval: %u\r\n", *result); return true; } -bool zcbor_undefined_expect(zcbor_state_t *state, void *unused) +bool zcbor_bool_expect(zcbor_state_t *state, bool expected) { - if (!primx_expect(state, 23)) { + PRINT_FUNC(); + return zcbor_simple_expect(state, (uint8_t)(!!expected) + ZCBOR_BOOL_TO_SIMPLE); +} + + +bool zcbor_bool_pexpect(zcbor_state_t *state, bool *expected) +{ + PRINT_FUNC(); + return zcbor_bool_expect(state, *expected); +} + + +static bool float_check(zcbor_state_t *state, uint8_t additional_val) +{ + INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_SIMPLE); + ZCBOR_ERR_IF(ZCBOR_ADDITIONAL(*state->payload) != additional_val, ZCBOR_ERR_FLOAT_SIZE); + return true; +} + + +bool zcbor_float16_bytes_decode(zcbor_state_t *state, uint16_t *result) +{ + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_2_BYTES)); + + if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); } + return true; } -bool zcbor_bool_decode(zcbor_state_t *state, bool *result) +bool zcbor_float16_bytes_expect(zcbor_state_t *state, uint16_t expected) { - if (zcbor_bool_expect(state, false)) { - *result = false; - } else if (zcbor_bool_expect(state, true)) { - *result = true; - } else { + PRINT_FUNC(); + uint16_t actual; + + if (!zcbor_float16_bytes_decode(state, &actual)) { ZCBOR_FAIL(); } + if (actual != expected) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } + return true; +} + - zcbor_print("boolval: %u\r\n", *result); +bool zcbor_float16_bytes_pexpect(zcbor_state_t *state, uint16_t *expected) +{ + PRINT_FUNC(); + return zcbor_float16_bytes_expect(state, *expected); +} + + +bool zcbor_float16_decode(zcbor_state_t *state, float *result) +{ + PRINT_FUNC(); + uint16_t value16; + + if (!zcbor_float16_bytes_decode(state, &value16)) { + ZCBOR_FAIL(); + } + + *result = zcbor_float16_to_32(value16); return true; } -bool zcbor_bool_expect(zcbor_state_t *state, bool result) +bool zcbor_float16_expect(zcbor_state_t *state, float expected) { - if (!primx_expect(state, (uint8_t)(!!result) + ZCBOR_BOOL_TO_PRIM)) { + PRINT_FUNC(); + float actual; + + if (!zcbor_float16_decode(state, &actual)) { ZCBOR_FAIL(); } + if (actual != expected) { + ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); + } return true; } +bool zcbor_float16_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float16_expect(state, *expected); +} + + bool zcbor_float32_decode(zcbor_state_t *state, float *result) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_4_BYTES, ZCBOR_ERR_FLOAT_SIZE); + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_4_BYTES)); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -723,24 +1238,65 @@ bool zcbor_float32_decode(zcbor_state_t *state, float *result) } -bool zcbor_float32_expect(zcbor_state_t *state, float result) +bool zcbor_float32_expect(zcbor_state_t *state, float expected) { - float value; + PRINT_FUNC(); + float actual; - if (!zcbor_float32_decode(state, &value)) { + if (!zcbor_float32_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } +bool zcbor_float32_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float32_expect(state, *expected); +} + + +bool zcbor_float16_32_decode(zcbor_state_t *state, float *result) +{ + PRINT_FUNC(); + if (zcbor_float16_decode(state, result)) { + /* Do nothing */ + } else if (!zcbor_float32_decode(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_32_expect(zcbor_state_t *state, float expected) +{ + PRINT_FUNC(); + if (zcbor_float16_expect(state, expected)) { + /* Do nothing */ + } else if (!zcbor_float32_expect(state, expected)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_32_pexpect(zcbor_state_t *state, float *expected) +{ + PRINT_FUNC(); + return zcbor_float16_32_expect(state, *expected); +} + + bool zcbor_float64_decode(zcbor_state_t *state, double *result) { - INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM); - ZCBOR_ERR_IF(ADDITIONAL(*state->payload) != ZCBOR_VALUE_IS_8_BYTES, ZCBOR_ERR_FLOAT_SIZE); + PRINT_FUNC(); + ZCBOR_FAIL_IF(!float_check(state, ZCBOR_VALUE_IS_8_BYTES)); if (!value_extract(state, result, sizeof(*result))) { ZCBOR_FAIL(); @@ -750,22 +1306,31 @@ bool zcbor_float64_decode(zcbor_state_t *state, double *result) } -bool zcbor_float64_expect(zcbor_state_t *state, double result) +bool zcbor_float64_expect(zcbor_state_t *state, double expected) { - double value; + PRINT_FUNC(); + double actual; - if (!zcbor_float64_decode(state, &value)) { + if (!zcbor_float64_decode(state, &actual)) { ZCBOR_FAIL(); } - if (value != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_float_decode(zcbor_state_t *state, double *result) +bool zcbor_float64_pexpect(zcbor_state_t *state, double *expected) { + PRINT_FUNC(); + return zcbor_float64_expect(state, *expected); +} + + +bool zcbor_float32_64_decode(zcbor_state_t *state, double *result) +{ + PRINT_FUNC(); float float_result; if (zcbor_float32_decode(state, &float_result)) { @@ -778,11 +1343,12 @@ bool zcbor_float_decode(zcbor_state_t *state, double *result) } -bool zcbor_float_expect(zcbor_state_t *state, double result) +bool zcbor_float32_64_expect(zcbor_state_t *state, double expected) { - if (zcbor_float32_expect(state, (float)result)) { + PRINT_FUNC(); + if (zcbor_float64_expect(state, expected)) { /* Do nothing */ - } else if (!zcbor_float64_expect(state, result)) { + } else if (!zcbor_float32_expect(state, (float)expected)) { ZCBOR_FAIL(); } @@ -790,54 +1356,86 @@ bool zcbor_float_expect(zcbor_state_t *state, double result) } +bool zcbor_float32_64_pexpect(zcbor_state_t *state, double *expected) +{ + PRINT_FUNC(); + return zcbor_float32_64_expect(state, *expected); +} + + +bool zcbor_float_decode(zcbor_state_t *state, double *result) +{ + PRINT_FUNC(); + float float_result; + + if (zcbor_float16_decode(state, &float_result)) { + *result = (double)float_result; + } else if (zcbor_float32_decode(state, &float_result)) { + *result = (double)float_result; + } else if (!zcbor_float64_decode(state, result)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float_expect(zcbor_state_t *state, double expected) +{ + PRINT_FUNC(); + if (zcbor_float16_expect(state, (float)expected)) { + /* Do nothing */ + } else if (zcbor_float32_expect(state, (float)expected)) { + /* Do nothing */ + } else if (!zcbor_float64_expect(state, expected)) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float_pexpect(zcbor_state_t *state, double *expected) +{ + PRINT_FUNC(); + return zcbor_float_expect(state, *expected); +} + + bool zcbor_any_skip(zcbor_state_t *state, void *result) { + PRINT_FUNC(); zcbor_assert_state(result == NULL, "'any' type cannot be returned, only skipped.\r\n"); + (void)result; INITIAL_CHECKS(); - zcbor_major_type_t major_type = MAJOR_TYPE(*state->payload); - uint8_t additional = ADDITIONAL(*state->payload); - uint_fast32_t value; - uint_fast32_t num_decode; - uint_fast32_t temp_elem_count; - uint_fast32_t elem_count_bak = state->elem_count; - uint8_t const *payload_bak = state->payload; - uint64_t tag_dummy; + zcbor_major_type_t major_type = ZCBOR_MAJOR_TYPE(*state->payload); + uint8_t additional = ZCBOR_ADDITIONAL(*state->payload); + uint64_t value = 0; /* In case of indefinite_length_array. */ + zcbor_state_t state_copy; - payload_bak = state->payload; + memcpy(&state_copy, state, sizeof(zcbor_state_t)); - if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, - (zcbor_decoder_t *)zcbor_tag_decode, state, - (void *)&tag_dummy, 0)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; - ZCBOR_FAIL(); - } - - if ((major_type == ZCBOR_MAJOR_TYPE_MAP) || (major_type == ZCBOR_MAJOR_TYPE_LIST)) { - if (additional == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) { - ZCBOR_ERR_IF(state->elem_count == 0, ZCBOR_ERR_LOW_ELEM_COUNT); - state->payload++; - state->elem_count--; - temp_elem_count = state->elem_count; - payload_bak = state->payload; - state->elem_count = ZCBOR_LARGE_ELEM_COUNT; - if (!zcbor_multi_decode(0, ZCBOR_LARGE_ELEM_COUNT, &num_decode, - (zcbor_decoder_t *)zcbor_any_skip, state, - NULL, 0) - || (state->payload >= state->payload_end) - || !(*(state->payload++) == 0xFF)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; - ZCBOR_FAIL(); - } - state->elem_count = temp_elem_count; - return true; + while (major_type == ZCBOR_MAJOR_TYPE_TAG) { + uint32_t tag_dummy; + + if (!zcbor_tag_decode(&state_copy, &tag_dummy)) { + ZCBOR_FAIL(); } + ZCBOR_ERR_IF(state_copy.payload >= state_copy.payload_end, ZCBOR_ERR_NO_PAYLOAD); + major_type = ZCBOR_MAJOR_TYPE(*state_copy.payload); + additional = ZCBOR_ADDITIONAL(*state_copy.payload); } - if (!value_extract(state, &value, sizeof(value))) { +#ifdef ZCBOR_CANONICAL + const bool indefinite_length_array = false; +#else + const bool indefinite_length_array = ((additional == ZCBOR_VALUE_IS_INDEFINITE_LENGTH) + && ((major_type == ZCBOR_MAJOR_TYPE_LIST) || (major_type == ZCBOR_MAJOR_TYPE_MAP))); +#endif + + if (!indefinite_length_array && !value_extract(&state_copy, &value, sizeof(value))) { /* Can happen because of elem_count (or payload_end) */ ZCBOR_FAIL(); } @@ -845,38 +1443,49 @@ bool zcbor_any_skip(zcbor_state_t *state, void *result) switch (major_type) { case ZCBOR_MAJOR_TYPE_BSTR: case ZCBOR_MAJOR_TYPE_TSTR: - /* 'value' is the length of the BSTR or TSTR */ - if (value > (state->payload_end - state->payload)) { - ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); - } - (state->payload) += value; + /* 'value' is the length of the BSTR or TSTR. + * The subtraction is safe because value_extract() above + * checks that payload_end is greater than payload. */ + ZCBOR_ERR_IF( + value > (uint64_t)(state_copy.payload_end - state_copy.payload), + ZCBOR_ERR_NO_PAYLOAD); + (state_copy.payload) += value; break; case ZCBOR_MAJOR_TYPE_MAP: - value *= 2; /* Because all members have a key. */ - /* Fallthrough */ + ZCBOR_ERR_IF(value > (SIZE_MAX / 2), ZCBOR_ERR_INT_SIZE); + value *= 2; + /* fallthrough */ case ZCBOR_MAJOR_TYPE_LIST: - temp_elem_count = state->elem_count; - state->elem_count = value; - if (!zcbor_multi_decode(value, value, &num_decode, - (zcbor_decoder_t *)zcbor_any_skip, state, - NULL, 0)) { - state->elem_count = elem_count_bak; - state->payload = payload_bak; + if (indefinite_length_array) { + state_copy.payload++; + value = ZCBOR_LARGE_ELEM_COUNT; + } + state_copy.elem_count = (size_t)value; + state_copy.decode_state.indefinite_length_array = indefinite_length_array; + while (!zcbor_array_at_end(&state_copy)) { + if (!zcbor_any_skip(&state_copy, NULL)) { + ZCBOR_FAIL(); + } + } + if (indefinite_length_array && !array_end_expect(&state_copy)) { ZCBOR_FAIL(); } - state->elem_count = temp_elem_count; break; default: /* Do nothing */ break; } + state->payload = state_copy.payload; + state->elem_count--; + return true; } bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) { + PRINT_FUNC(); INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_TAG); if (!value_extract(state, result, sizeof(*result))) { @@ -887,32 +1496,41 @@ bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result) } -bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result) +bool zcbor_tag_expect(zcbor_state_t *state, uint32_t expected) { - uint32_t tag_val; + PRINT_FUNC(); + uint32_t actual; - if (!zcbor_tag_decode(state, &tag_val)) { + if (!zcbor_tag_decode(state, &actual)) { ZCBOR_FAIL(); } - if (tag_val != result) { + if (actual != expected) { ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE); } return true; } -bool zcbor_multi_decode(uint_fast32_t min_decode, - uint_fast32_t max_decode, - uint_fast32_t *num_decode, +bool zcbor_tag_pexpect(zcbor_state_t *state, uint32_t *expected) +{ + PRINT_FUNC(); + return zcbor_tag_expect(state, *expected); +} + + +bool zcbor_multi_decode(size_t min_decode, + size_t max_decode, + size_t *num_decode, zcbor_decoder_t decoder, zcbor_state_t *state, void *result, - uint_fast32_t result_len) + size_t result_len) { + PRINT_FUNC(); ZCBOR_CHECK_ERROR(); - for (uint_fast32_t i = 0; i < max_decode; i++) { + for (size_t i = 0; i < max_decode; i++) { uint8_t const *payload_bak = state->payload; - uint_fast32_t elem_count_bak = state->elem_count; + size_t elem_count_bak = state->elem_count; if (!decoder(state, (uint8_t *)result + i*result_len)) { @@ -920,33 +1538,35 @@ bool zcbor_multi_decode(uint_fast32_t min_decode, state->payload = payload_bak; state->elem_count = elem_count_bak; ZCBOR_ERR_IF(i < min_decode, ZCBOR_ERR_ITERATIONS); - zcbor_print("Found %" PRIuFAST32 " elements.\r\n", i); + zcbor_log("Found %zu elements.\r\n", i); return true; } } - zcbor_print("Found %" PRIuFAST32 " elements.\r\n", max_decode); + zcbor_log("Found %zu elements.\r\n", max_decode); *num_decode = max_decode; return true; } -bool zcbor_present_decode(uint_fast32_t *present, +bool zcbor_present_decode(bool *present, zcbor_decoder_t decoder, zcbor_state_t *state, void *result) { - uint_fast32_t num_decode; + PRINT_FUNC(); + size_t num_decode = 0; bool retval = zcbor_multi_decode(0, 1, &num_decode, decoder, state, result, 0); zcbor_assert_state(retval, "zcbor_multi_decode should not fail with these parameters.\r\n"); - *present = num_decode; + *present = !!num_decode; return retval; } -void zcbor_new_decode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - const uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_decode_state(zcbor_state_t *state_array, size_t n_states, + const uint8_t *payload, size_t payload_len, size_t elem_count, + uint8_t *flags, size_t flags_bytes) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, flags, flags_bytes); } diff --git a/boot/zcbor/src/zcbor_encode.c b/boot/zcbor/src/zcbor_encode.c index 1929cebd5..53d19c01f 100644 --- a/boot/zcbor/src/zcbor_encode.c +++ b/boot/zcbor/src/zcbor_encode.c @@ -1,6 +1,6 @@ /* * This file has been copied from the zcbor library. - * Commit zcbor 0.7.0 + * Commit zcbor 0.8.1 */ /* @@ -15,12 +15,13 @@ #include #include "zcbor_encode.h" #include "zcbor_common.h" +#include "zcbor_print.h" _Static_assert((sizeof(size_t) == sizeof(void *)), "This code needs size_t to be the same length as pointers."); -static uint8_t log2ceil(uint_fast32_t val) +static uint8_t log2ceil(size_t val) { switch(val) { case 1: return 0; @@ -33,114 +34,74 @@ static uint8_t log2ceil(uint_fast32_t val) case 8: return 3; } - zcbor_print("Should not come here.\r\n"); + zcbor_log("Should not come here.\r\n"); return 0; } -static uint8_t get_additional(uint_fast32_t len, uint8_t value0) + +static uint8_t get_additional(size_t len, uint8_t value0) { return len == 0 ? value0 : (uint8_t)(24 + log2ceil(len)); } + static bool encode_header_byte(zcbor_state_t *state, zcbor_major_type_t major_type, uint8_t additional) { ZCBOR_CHECK_ERROR(); ZCBOR_CHECK_PAYLOAD(); - zcbor_assert_state(additional < 32, NULL); + zcbor_assert_state(additional < 32, "Unsupported additional value: %d\r\n", additional); *(state->payload_mut++) = (uint8_t)((major_type << 5) | (additional & 0x1F)); return true; } -static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len); - - /** Encode a single value. */ static bool value_encode_len(zcbor_state_t *state, zcbor_major_type_t major_type, - const void *const result, uint_fast32_t result_len) + const void *const result, size_t result_len) { uint8_t *u8_result = (uint8_t *)result; - uint_fast32_t encoded_len = get_encoded_len(result, result_len); - if ((state->payload + 1 + encoded_len) > state->payload_end) { + if ((state->payload + 1 + result_len) > state->payload_end) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!encode_header_byte(state, major_type, - get_additional(encoded_len, u8_result[0]))) { + get_additional(result_len, u8_result[0]))) { ZCBOR_FAIL(); } state->payload_mut--; - zcbor_trace(); + zcbor_trace(state, "value_encode_len"); state->payload_mut++; -#ifdef CONFIG_BIG_ENDIAN - memcpy(state->payload_mut, u8_result, encoded_len); - state->payload_mut += encoded_len; +#ifdef ZCBOR_BIG_ENDIAN + memcpy(state->payload_mut, u8_result, result_len); + state->payload_mut += result_len; #else - for (; encoded_len > 0; encoded_len--) { - *(state->payload_mut++) = u8_result[encoded_len - 1]; + for (; result_len > 0; result_len--) { + *(state->payload_mut++) = u8_result[result_len - 1]; } -#endif /* CONFIG_BIG_ENDIAN */ +#endif /* ZCBOR_BIG_ENDIAN */ state->elem_count++; return true; } -static uint_fast32_t get_result_len(const void *const input, uint_fast32_t max_result_len) -{ - uint8_t *u8_result = (uint8_t *)input; - uint_fast32_t len = max_result_len; - - for (; len > 0; len--) { -#ifdef CONFIG_BIG_ENDIAN - if (u8_result[max_result_len - len] != 0) { -#else - if (u8_result[len - 1] != 0) { -#endif /* CONFIG_BIG_ENDIAN */ - break; - } - } - - /* Round up to nearest power of 2. */ - return len <= 2 ? len : (uint8_t)(1 << log2ceil(len)); -} - - -static const void *get_result(const void *const input, uint_fast32_t max_result_len, - uint_fast32_t result_len) -{ -#ifdef CONFIG_BIG_ENDIAN - return &((uint8_t *)input)[max_result_len - (result_len ? result_len : 1)]; -#else - return input; -#endif -} - - -static uint_fast32_t get_encoded_len(const void *const result, uint_fast32_t result_len) -{ - const uint8_t *u8_result = (const uint8_t *)result; - - if ((result_len == 1) && (u8_result[0] <= ZCBOR_VALUE_IN_HEADER)) { - return 0; - } - return result_len; -} - - static bool value_encode(zcbor_state_t *state, zcbor_major_type_t major_type, - const void *const input, uint_fast32_t max_result_len) + const void *const input, size_t max_result_len) { zcbor_assert_state(max_result_len != 0, "0-length result not supported.\r\n"); - uint_fast32_t result_len = get_result_len(input, max_result_len); - const void *const result = get_result(input, max_result_len, result_len); + size_t result_len = zcbor_header_len_ptr(input, max_result_len) - 1; + const void *result = input; + +#ifdef ZCBOR_BIG_ENDIAN + result = (uint8_t *)input + max_result_len - (result_len ? result_len : 1); +#endif return value_encode_len(state, major_type, result, result_len); } @@ -158,7 +119,7 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si ZCBOR_ERR(ZCBOR_ERR_INT_SIZE); } -#ifdef CONFIG_BIG_ENDIAN +#ifdef ZCBOR_BIG_ENDIAN if (input_int8[0] < 0) { #else if (input_int8[int_size - 1] < 0) { @@ -166,7 +127,7 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si major_type = ZCBOR_MAJOR_TYPE_NINT; /* Convert to CBOR's representation by flipping all bits. */ - for (int i = 0; i < int_size; i++) { + for (unsigned int i = 0; i < int_size; i++) { input_buf[i] = (uint8_t)~input_uint8[i]; } input = input_buf; @@ -182,53 +143,37 @@ bool zcbor_int_encode(zcbor_state_t *state, const void *input_int, size_t int_si } -bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) +bool zcbor_uint_encode(zcbor_state_t *state, const void *input_uint, size_t uint_size) { - return zcbor_int_encode(state, input, sizeof(*input)); + if (!value_encode(state, ZCBOR_MAJOR_TYPE_PINT, input_uint, uint_size)) { + zcbor_log("uint with size %zu failed.\r\n", uint_size); + ZCBOR_FAIL(); + } + return true; } -bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) +bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input) { return zcbor_int_encode(state, input, sizeof(*input)); } -static bool uint32_encode(zcbor_state_t *state, const uint32_t *input, - zcbor_major_type_t major_type) +bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input) { - if (!value_encode(state, major_type, input, 4)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_int_encode(state, input, sizeof(*input)); } bool zcbor_uint32_encode(zcbor_state_t *state, const uint32_t *input) { - if (!uint32_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; -} - - -static bool uint64_encode(zcbor_state_t *state, const uint64_t *input, - zcbor_major_type_t major_type) -{ - if (!value_encode(state, major_type, input, 8)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, input, sizeof(*input)); } bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_t *input) { - if (!uint64_encode(state, input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, input, sizeof(*input)); } @@ -246,37 +191,34 @@ bool zcbor_int64_put(zcbor_state_t *state, int64_t input) bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input) { - return zcbor_uint64_put(state, input); + return zcbor_uint_encode(state, &input, sizeof(input)); } bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input) { - if (!uint64_encode(state, &input, ZCBOR_MAJOR_TYPE_PINT)) { - ZCBOR_FAIL(); - } - return true; + return zcbor_uint_encode(state, &input, sizeof(input)); } #ifdef ZCBOR_SUPPORTS_SIZE_T bool zcbor_size_put(zcbor_state_t *state, size_t input) { - return zcbor_uint64_put(state, input); + return zcbor_uint_encode(state, &input, sizeof(input)); } bool zcbor_size_encode(zcbor_state_t *state, const size_t *input) { - return zcbor_size_put(state, *input); + return zcbor_uint_encode(state, input, sizeof(*input)); } #endif static bool str_start_encode(zcbor_state_t *state, const struct zcbor_string *input, zcbor_major_type_t major_type) { - if (input->value && ((get_result_len(&input->len, sizeof(input->len)) - + 1 + input->len + (size_t)state->payload) + if (input->value && ((zcbor_header_len_ptr(&input->len, sizeof(input->len)) + + input->len + (size_t)state->payload) > (size_t)state->payload_end)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } @@ -288,19 +230,10 @@ static bool str_start_encode(zcbor_state_t *state, } -static bool primitive_put(zcbor_state_t *state, uint32_t input) -{ - if (!uint32_encode(state, &input, ZCBOR_MAJOR_TYPE_PRIM)) { - ZCBOR_FAIL(); - } - return true; -} - - static size_t remaining_str_len(zcbor_state_t *state) { size_t max_len = (size_t)state->payload_end - (size_t)state->payload; - size_t result_len = get_result_len(&max_len, sizeof(max_len)); + size_t result_len = zcbor_header_len_ptr(&max_len, sizeof(max_len)) - 1; return max_len - result_len - 1; } @@ -315,8 +248,7 @@ bool zcbor_bstr_start_encode(zcbor_state_t *state) uint64_t max_len = remaining_str_len(state); /* Encode a dummy header */ - if (!uint64_encode(state, &max_len, - ZCBOR_MAJOR_TYPE_BSTR)) { + if (!value_encode(state, ZCBOR_MAJOR_TYPE_BSTR, &max_len, sizeof(max_len))) { ZCBOR_FAIL(); } return true; @@ -353,7 +285,8 @@ bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result) static bool str_encode(zcbor_state_t *state, const struct zcbor_string *input, zcbor_major_type_t major_type) { - if (input->len > (state->payload_end - state->payload)) { + ZCBOR_CHECK_PAYLOAD(); /* To make the size_t cast below safe. */ + if (input->len > (size_t)(state->payload_end - state->payload)) { ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD); } if (!str_start_encode(state, input, major_type)) { @@ -381,7 +314,35 @@ bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input) } -static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, +bool zcbor_bstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len) +{ + const struct zcbor_string zs = { .value = (const uint8_t *)str, .len = len }; + + return zcbor_bstr_encode(state, &zs); +} + + +bool zcbor_tstr_encode_ptr(zcbor_state_t *state, const char *str, size_t len) +{ + const struct zcbor_string zs = { .value = (const uint8_t *)str, .len = len }; + + return zcbor_tstr_encode(state, &zs); +} + + +bool zcbor_bstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_bstr_encode_ptr(state, str, strnlen(str, maxlen)); +} + + +bool zcbor_tstr_put_term(zcbor_state_t *state, char const *str, size_t maxlen) +{ + return zcbor_tstr_encode_ptr(state, str, strnlen(str, maxlen)); +} + + +static bool list_map_start_encode(zcbor_state_t *state, size_t max_num, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL @@ -395,6 +356,8 @@ static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, } state->elem_count--; /* Because of dummy header. */ #else + (void)max_num; + if (!encode_header_byte(state, major_type, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { ZCBOR_FAIL(); } @@ -403,54 +366,43 @@ static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num, } -bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_list_start_encode(zcbor_state_t *state, size_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_map_start_encode(zcbor_state_t *state, size_t max_num) { return list_map_start_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } -#ifdef ZCBOR_CANONICAL -static uint_fast32_t get_encoded_len2(const void *const input, uint_fast32_t max_result_len) -{ - uint_fast32_t result_len = get_result_len(input, max_result_len); - const void *const result = get_result(input, max_result_len, result_len); - - return get_encoded_len(result, result_len); -} -#endif - - -static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, +static bool list_map_end_encode(zcbor_state_t *state, size_t max_num, zcbor_major_type_t major_type) { #ifdef ZCBOR_CANONICAL - uint_fast32_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? + size_t list_count = ((major_type == ZCBOR_MAJOR_TYPE_LIST) ? state->elem_count : (state->elem_count / 2)); const uint8_t *payload = state->payload; - uint_fast32_t max_header_len = get_encoded_len2(&max_num, 4); - uint_fast32_t header_len = get_encoded_len2(&list_count, 4); + size_t max_header_len = zcbor_header_len_ptr(&max_num, 4) - 1; + size_t header_len = zcbor_header_len_ptr(&list_count, 4) - 1; if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) { ZCBOR_FAIL(); } - zcbor_print("list_count: %" PRIuFAST32 "\r\n", list_count); + zcbor_log("list_count: %zu\r\n", list_count); /** If max_num is smaller than the actual number of encoded elements, * the value_encode() below will corrupt the data if the encoded * header is larger than the previously encoded header. */ if (header_len > max_header_len) { - zcbor_print("max_num too small.\r\n"); + zcbor_log("max_num too small.\r\n"); ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT); } @@ -471,7 +423,9 @@ static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, state->payload = payload; } #else - if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_PRIM, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { + (void)max_num; + (void)major_type; + if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_SIMPLE, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) { ZCBOR_FAIL(); } #endif @@ -479,13 +433,13 @@ static bool list_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num, } -bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_list_end_encode(zcbor_state_t *state, size_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_LIST); } -bool zcbor_map_end_encode(zcbor_state_t *state, uint_fast32_t max_num) +bool zcbor_map_end_encode(zcbor_state_t *state, size_t max_num) { return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP); } @@ -499,45 +453,56 @@ bool zcbor_list_map_end_force_encode(zcbor_state_t *state) ZCBOR_FAIL(); } #endif + (void)state; return true; } +bool zcbor_simple_encode(zcbor_state_t *state, uint8_t *input) +{ + if (!value_encode(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { + zcbor_log("Error encoding %u (0x%p)\r\n", *input, input); + ZCBOR_FAIL(); + } + return true; +} + + +bool zcbor_simple_put(zcbor_state_t *state, uint8_t input) +{ + return value_encode(state, ZCBOR_MAJOR_TYPE_SIMPLE, &input, sizeof(input)); +} + + bool zcbor_nil_put(zcbor_state_t *state, const void *unused) { (void)unused; - return primitive_put(state, 22); + return zcbor_simple_put(state, 22); } bool zcbor_undefined_put(zcbor_state_t *state, const void *unused) { (void)unused; - return primitive_put(state, 23); + return zcbor_simple_put(state, 23); } bool zcbor_bool_encode(zcbor_state_t *state, const bool *input) { - if (!primitive_put(state, (uint32_t)(*input + ZCBOR_BOOL_TO_PRIM))) { - ZCBOR_FAIL(); - } - return true; + return zcbor_bool_put(state, *input); } bool zcbor_bool_put(zcbor_state_t *state, bool input) { - if (!primitive_put(state, (uint32_t)(input + ZCBOR_BOOL_TO_PRIM))) { - ZCBOR_FAIL(); - } - return true; + return zcbor_simple_put(state, (!!input + ZCBOR_BOOL_TO_SIMPLE)); } bool zcbor_float64_encode(zcbor_state_t *state, const double *input) { - if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -554,7 +519,7 @@ bool zcbor_float64_put(zcbor_state_t *state, double input) bool zcbor_float32_encode(zcbor_state_t *state, const float *input) { - if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_PRIM, input, + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, sizeof(*input))) { ZCBOR_FAIL(); } @@ -569,7 +534,36 @@ bool zcbor_float32_put(zcbor_state_t *state, float input) } -bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) +bool zcbor_float16_encode(zcbor_state_t *state, const float *input) +{ + return zcbor_float16_put(state, *input); +} + + +bool zcbor_float16_put(zcbor_state_t *state, float input) +{ + return zcbor_float16_bytes_put(state, zcbor_float32_to_16(input)); +} + + +bool zcbor_float16_bytes_encode(zcbor_state_t *state, const uint16_t *input) +{ + if (!value_encode_len(state, ZCBOR_MAJOR_TYPE_SIMPLE, input, + sizeof(*input))) { + ZCBOR_FAIL(); + } + + return true; +} + + +bool zcbor_float16_bytes_put(zcbor_state_t *state, uint16_t input) +{ + return zcbor_float16_bytes_encode(state, &input); +} + + +bool zcbor_tag_put(zcbor_state_t *state, uint32_t tag) { if (!value_encode(state, ZCBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) { ZCBOR_FAIL(); @@ -580,13 +574,15 @@ bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag) } -bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, - uint_fast32_t max_encode, - const uint_fast32_t *num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len) +bool zcbor_tag_encode(zcbor_state_t *state, uint32_t *tag) +{ + return zcbor_tag_put(state, *tag); +} + + +bool zcbor_multi_encode_minmax(size_t min_encode, size_t max_encode, + const size_t *num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len) { if ((*num_encode >= min_encode) && (*num_encode <= max_encode)) { @@ -596,34 +592,23 @@ bool zcbor_multi_encode_minmax(uint_fast32_t min_encode, } } -bool zcbor_multi_encode(uint_fast32_t num_encode, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input, - uint_fast32_t result_len) + +bool zcbor_multi_encode(const size_t num_encode, zcbor_encoder_t encoder, + zcbor_state_t *state, const void *input, size_t result_len) { ZCBOR_CHECK_ERROR(); - for (uint_fast32_t i = 0; i < num_encode; i++) { + for (size_t i = 0; i < num_encode; i++) { if (!encoder(state, (const uint8_t *)input + i*result_len)) { ZCBOR_FAIL(); } } - zcbor_print("Encoded %" PRIuFAST32 " elements.\n", num_encode); + zcbor_log("Encoded %zu elements.\n", num_encode); return true; } -bool zcbor_present_encode(const uint_fast32_t *present, - zcbor_encoder_t encoder, - zcbor_state_t *state, - const void *input) -{ - return zcbor_multi_encode(!!*present, encoder, state, input, 0); -} - - -void zcbor_new_encode_state(zcbor_state_t *state_array, uint_fast32_t n_states, - uint8_t *payload, size_t payload_len, uint_fast32_t elem_count) +void zcbor_new_encode_state(zcbor_state_t *state_array, size_t n_states, + uint8_t *payload, size_t payload_len, size_t elem_count) { - zcbor_new_state(state_array, n_states, payload, payload_len, elem_count); + zcbor_new_state(state_array, n_states, payload, payload_len, elem_count, NULL, 0); }