boot_serial: Upgrade from cddl-gen 0.1.0 to zcbor 0.4.0
cddl-gen has been renamed to zcbor. Update regenerate_serial_recovery_cbor.sh and regenerate/recopy all files. Remove the submodule in ext/ since it is no longer necessary when the zcbor package is installed (only needed for regeneration, not for building). Signed-off-by: Øyvind Rønningstad <oyvind.ronningstad@nordicsemi.no>
This commit is contained in:
parent
35f61d305d
commit
a7d34caaa7
|
@ -19,9 +19,6 @@
|
|||
[submodule "boot/cypress/libs/cy-mbedtls-acceleration"]
|
||||
path = boot/cypress/libs/cy-mbedtls-acceleration
|
||||
url = https://github.com/cypresssemiconductorco/cy-mbedtls-acceleration.git
|
||||
[submodule "ext/cddl-gen"]
|
||||
path = ext/cddl-gen
|
||||
url = https://github.com/NordicSemiconductor/cddl-gen.git
|
||||
[submodule "boot/espressif/hal/esp-idf"]
|
||||
path = boot/espressif/hal/esp-idf
|
||||
url = https://github.com/espressif/esp-idf.git
|
||||
|
|
|
@ -11,7 +11,6 @@ samples/*
|
|||
scripts/*
|
||||
sim/*
|
||||
testplan/*
|
||||
ext/cddl_gen/*
|
||||
ext/fiat/*
|
||||
ext/mbedtls/*
|
||||
ext/mbedtls-asn1/*
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "sysflash/sysflash.h"
|
||||
|
||||
#include "bootutil/bootutil_log.h"
|
||||
#include "cbor_encode.h"
|
||||
#include "zcbor_encode.h"
|
||||
|
||||
#ifdef __ZEPHYR__
|
||||
#include <sys/reboot.h>
|
||||
|
@ -99,17 +99,12 @@ static char bs_obuf[BOOT_SERIAL_OUT_MAX];
|
|||
|
||||
static void boot_serial_output(void);
|
||||
|
||||
static cbor_state_backups_t dummy_backups;
|
||||
static cbor_state_t cbor_state = {
|
||||
.backups = &dummy_backups
|
||||
};
|
||||
static zcbor_state_t cbor_state[2];
|
||||
|
||||
void reset_cbor_state(void)
|
||||
{
|
||||
cbor_state.payload_mut = (uint8_t *)bs_obuf;
|
||||
cbor_state.payload_end = (const uint8_t *)bs_obuf
|
||||
+ sizeof(bs_obuf);
|
||||
cbor_state.elem_count = 0;
|
||||
zcbor_new_encode_state(cbor_state, 2, (uint8_t *)bs_obuf,
|
||||
(size_t)bs_obuf + sizeof(bs_obuf), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +121,7 @@ void reset_cbor_state(void)
|
|||
*/
|
||||
extern int bs_peruser_system_specific(const struct nmgr_hdr *hdr,
|
||||
const char *buffer,
|
||||
int len, cbor_state_t *cs);
|
||||
int len, zcbor_state_t *cs);
|
||||
|
||||
/*
|
||||
* Convert version into string without use of snprintf().
|
||||
|
@ -157,6 +152,9 @@ u32toa(char *tgt, uint32_t val)
|
|||
return dst - tgt;
|
||||
}
|
||||
|
||||
#define zcbor_tstr_put_lit_cast(state, string) \
|
||||
zcbor_tstr_encode_ptr(state, (uint8_t *)string, sizeof(string) - 1)
|
||||
|
||||
/*
|
||||
* dst has to be able to fit "255.255.65535.4294967295" (25 characters).
|
||||
*/
|
||||
|
@ -186,9 +184,9 @@ bs_list(char *buf, int len)
|
|||
const struct flash_area *fap;
|
||||
uint8_t image_index;
|
||||
|
||||
map_start_encode(&cbor_state, 1);
|
||||
tstrx_put(&cbor_state, "images");
|
||||
list_start_encode(&cbor_state, 5);
|
||||
zcbor_map_start_encode(cbor_state, 1);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "images");
|
||||
zcbor_list_start_encode(cbor_state, 5);
|
||||
image_index = 0;
|
||||
IMAGES_ITER(image_index) {
|
||||
for (slot = 0; slot < 2; slot++) {
|
||||
|
@ -235,24 +233,24 @@ bs_list(char *buf, int len)
|
|||
continue;
|
||||
}
|
||||
|
||||
map_start_encode(&cbor_state, 20);
|
||||
zcbor_map_start_encode(cbor_state, 20);
|
||||
|
||||
#if (BOOT_IMAGE_NUMBER > 1)
|
||||
tstrx_put(&cbor_state, "image");
|
||||
uintx32_put(&cbor_state, image_index);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "image");
|
||||
zcbor_uint32_put(cbor_state, image_index);
|
||||
#endif
|
||||
|
||||
tstrx_put(&cbor_state, "slot");
|
||||
uintx32_put(&cbor_state, slot);
|
||||
tstrx_put(&cbor_state, "version");
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "slot");
|
||||
zcbor_uint32_put(cbor_state, slot);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "version");
|
||||
|
||||
bs_list_img_ver((char *)tmpbuf, sizeof(tmpbuf), &hdr.ih_ver);
|
||||
tstrx_put_term(&cbor_state, (char *)tmpbuf);
|
||||
map_end_encode(&cbor_state, 20);
|
||||
zcbor_tstr_encode_ptr(cbor_state, tmpbuf, strlen((char *)tmpbuf));
|
||||
zcbor_map_end_encode(cbor_state, 20);
|
||||
}
|
||||
}
|
||||
list_end_encode(&cbor_state, 5);
|
||||
map_end_encode(&cbor_state, 1);
|
||||
zcbor_list_end_encode(cbor_state, 5);
|
||||
zcbor_map_end_encode(cbor_state, 1);
|
||||
boot_serial_output();
|
||||
}
|
||||
|
||||
|
@ -289,15 +287,15 @@ bs_upload(char *buf, int len)
|
|||
*/
|
||||
|
||||
struct Upload upload;
|
||||
uint32_t decoded_len;
|
||||
bool result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
|
||||
size_t decoded_len;
|
||||
uint_fast8_t result = cbor_decode_Upload((const uint8_t *)buf, len, &upload, &decoded_len);
|
||||
|
||||
if (!result || (len != decoded_len)) {
|
||||
if ((result != ZCBOR_SUCCESS) || (len != decoded_len)) {
|
||||
goto out_invalid_data;
|
||||
}
|
||||
|
||||
for (int i = 0; i < upload._Upload_members_count; i++) {
|
||||
struct Member_ *member = &upload._Upload_members[i];
|
||||
struct Member_ *member = &upload._Upload_members[i]._Upload_members;
|
||||
switch(member->_Member_choice) {
|
||||
case _Member_image:
|
||||
img_num = member->_Member_image;
|
||||
|
@ -458,14 +456,14 @@ bs_upload(char *buf, int len)
|
|||
|
||||
out:
|
||||
BOOT_LOG_INF("RX: 0x%x", rc);
|
||||
map_start_encode(&cbor_state, 10);
|
||||
tstrx_put(&cbor_state, "rc");
|
||||
uintx32_put(&cbor_state, rc);
|
||||
zcbor_map_start_encode(cbor_state, 10);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "rc");
|
||||
zcbor_uint32_put(cbor_state, rc);
|
||||
if (rc == 0) {
|
||||
tstrx_put(&cbor_state, "off");
|
||||
uintx32_put(&cbor_state, curr_off);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "off");
|
||||
zcbor_uint32_put(cbor_state, curr_off);
|
||||
}
|
||||
map_end_encode(&cbor_state, 10);
|
||||
zcbor_map_end_encode(cbor_state, 10);
|
||||
|
||||
boot_serial_output();
|
||||
flash_area_close(fap);
|
||||
|
@ -484,10 +482,10 @@ out:
|
|||
static void
|
||||
bs_rc_rsp(int rc_code)
|
||||
{
|
||||
map_start_encode(&cbor_state, 10);
|
||||
tstrx_put(&cbor_state, "rc");
|
||||
uintx32_put(&cbor_state, rc_code);
|
||||
map_end_encode(&cbor_state, 10);
|
||||
zcbor_map_start_encode(cbor_state, 10);
|
||||
zcbor_tstr_put_lit_cast(cbor_state, "rc");
|
||||
zcbor_uint32_put(cbor_state, rc_code);
|
||||
zcbor_map_end_encode(cbor_state, 10);
|
||||
boot_serial_output();
|
||||
}
|
||||
|
||||
|
@ -605,7 +603,7 @@ boot_serial_input(char *buf, int len)
|
|||
break;
|
||||
}
|
||||
} else if (MCUBOOT_PERUSER_MGMT_GROUP_ENABLED == 1) {
|
||||
if (bs_peruser_system_specific(hdr, buf, len, &cbor_state) == 0) {
|
||||
if (bs_peruser_system_specific(hdr, buf, len, cbor_state) == 0) {
|
||||
boot_serial_output();
|
||||
}
|
||||
} else {
|
||||
|
@ -628,7 +626,7 @@ boot_serial_output(void)
|
|||
char encoded_buf[BASE64_ENCODE_SIZE(sizeof(buf))];
|
||||
|
||||
data = bs_obuf;
|
||||
len = (uint32_t)cbor_state.payload_mut - (uint32_t)bs_obuf;
|
||||
len = (uint32_t)cbor_state->payload_mut - (uint32_t)bs_obuf;
|
||||
|
||||
bs_hdr->nh_op++;
|
||||
bs_hdr->nh_flags = 0;
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "cbor_common.h"
|
||||
|
||||
_Static_assert((sizeof(size_t) == sizeof(void *)),
|
||||
"This code needs size_t to be the same length as pointers.");
|
||||
|
||||
bool new_backup(cbor_state_t *state, uint32_t new_elem_count)
|
||||
{
|
||||
if ((state->backups->current_backup + 1)
|
||||
>= state->backups->num_backups) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
uint32_t i = ++(state->backups->current_backup);
|
||||
memcpy(&state->backups->backup_list[i], state,
|
||||
sizeof(cbor_state_t));
|
||||
|
||||
state->elem_count = new_elem_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool restore_backup(cbor_state_t *state, uint32_t flags,
|
||||
uint32_t max_elem_count)
|
||||
{
|
||||
const uint8_t *payload = state->payload;
|
||||
const uint32_t elem_count = state->elem_count;
|
||||
|
||||
if (state->backups->current_backup == 0) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (flags & FLAG_RESTORE) {
|
||||
uint32_t i = state->backups->current_backup;
|
||||
|
||||
memcpy(state, &state->backups->backup_list[i],
|
||||
sizeof(cbor_state_t));
|
||||
}
|
||||
|
||||
if (flags & FLAG_DISCARD) {
|
||||
state->backups->current_backup--;
|
||||
}
|
||||
|
||||
if (elem_count > max_elem_count) {
|
||||
cbor_print("elem_count: %d (expected max %d)\r\n",
|
||||
elem_count, max_elem_count);
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (flags & FLAG_TRANSFER_PAYLOAD) {
|
||||
state->payload = payload;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool union_start_code(cbor_state_t *state)
|
||||
{
|
||||
if (!new_backup(state, state->elem_count)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool union_elem_code(cbor_state_t *state)
|
||||
{
|
||||
if (!restore_backup(state, FLAG_RESTORE, state->elem_count)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool union_end_code(cbor_state_t *state)
|
||||
{
|
||||
if (!restore_backup(state, FLAG_DISCARD, state->elem_count)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool entry_function(const uint8_t *payload, uint32_t payload_len,
|
||||
const void *struct_ptr, uint32_t *payload_len_out,
|
||||
cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups)
|
||||
{
|
||||
cbor_state_t state = {
|
||||
.payload = payload,
|
||||
.payload_end = payload + payload_len,
|
||||
.elem_count = elem_count,
|
||||
};
|
||||
|
||||
cbor_state_t state_backups[num_backups + 1];
|
||||
|
||||
cbor_state_backups_t backups = {
|
||||
.backup_list = state_backups,
|
||||
.current_backup = 0,
|
||||
.num_backups = num_backups + 1,
|
||||
};
|
||||
|
||||
state.backups = &backups;
|
||||
|
||||
bool result = func(&state, struct_ptr);
|
||||
|
||||
if (result && (payload_len_out != NULL)) {
|
||||
*payload_len_out = MIN(payload_len,
|
||||
(size_t)state.payload - (size_t)payload);
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef CBOR_COMMON_H__
|
||||
#define CBOR_COMMON_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/** Convenience type that allows pointing to strings directly inside the payload
|
||||
* without the need to copy out.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const uint8_t *value;
|
||||
uint32_t len;
|
||||
} cbor_string_type_t;
|
||||
|
||||
#ifdef CDDL_CBOR_VERBOSE
|
||||
#include <sys/printk.h>
|
||||
#define cbor_trace() (printk("bytes left: %d, byte: 0x%x, elem_count: 0x%zx, %s:%d\n",\
|
||||
(uint32_t)state->payload_end - (uint32_t)state->payload, *state->payload, state->elem_count,\
|
||||
__FILE__, __LINE__))
|
||||
#define cbor_assert(expr, ...) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
printk("ASSERTION \n \"" #expr \
|
||||
"\"\nfailed at %s:%d with message:\n ", \
|
||||
__FILE__, __LINE__); \
|
||||
printk(__VA_ARGS__);\
|
||||
return false; \
|
||||
} \
|
||||
} while(0)
|
||||
#define cbor_print(...) printk(__VA_ARGS__)
|
||||
#else
|
||||
#define cbor_trace() ((void)state)
|
||||
#define cbor_assert(...)
|
||||
#define cbor_print(...)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
|
||||
struct cbor_state_backups_s;
|
||||
|
||||
typedef struct cbor_state_backups_s cbor_state_backups_t;
|
||||
|
||||
typedef struct{
|
||||
union {
|
||||
uint8_t *payload_mut;
|
||||
uint8_t const *payload; /**< The current place in the payload. Will be
|
||||
updated when an element is correctly
|
||||
processed. */
|
||||
};
|
||||
uint8_t const *payload_bak; /**< Temporary backup of payload. */
|
||||
uint32_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. */
|
||||
cbor_state_backups_t *backups;
|
||||
} cbor_state_t;
|
||||
|
||||
struct cbor_state_backups_s{
|
||||
cbor_state_t *backup_list;
|
||||
uint32_t current_backup;
|
||||
uint32_t num_backups;
|
||||
};
|
||||
|
||||
/** Function pointer type used with multi_decode.
|
||||
*
|
||||
* This type is compatible with all decoding functions here and in the generated
|
||||
* code, except for multi_decode.
|
||||
*/
|
||||
typedef bool(cbor_encoder_t)(cbor_state_t *, const void *);
|
||||
typedef bool(cbor_decoder_t)(cbor_state_t *, void *);
|
||||
|
||||
/** Enumeration representing the major types available in CBOR.
|
||||
*
|
||||
* The major type is represented in the 3 first bits of the header byte.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
CBOR_MAJOR_TYPE_PINT = 0, ///! Positive Integer
|
||||
CBOR_MAJOR_TYPE_NINT = 1, ///! Negative Integer
|
||||
CBOR_MAJOR_TYPE_BSTR = 2, ///! Byte String
|
||||
CBOR_MAJOR_TYPE_TSTR = 3, ///! Text String
|
||||
CBOR_MAJOR_TYPE_LIST = 4, ///! List
|
||||
CBOR_MAJOR_TYPE_MAP = 5, ///! Map
|
||||
CBOR_MAJOR_TYPE_TAG = 6, ///! Semantic Tag
|
||||
CBOR_MAJOR_TYPE_PRIM = 7, ///! Primitive Type
|
||||
} cbor_major_type_t;
|
||||
|
||||
/** Shorthand macro to check if a result is within min/max constraints.
|
||||
*/
|
||||
#define PTR_VALUE_IN_RANGE(type, res, min, max) \
|
||||
(((min == NULL) || (*(type *)res >= *(type *)min)) \
|
||||
&& ((max == NULL) || (*(type *)res <= *(type *)max)))
|
||||
|
||||
#define FAIL() \
|
||||
do {\
|
||||
cbor_trace(); \
|
||||
return false; \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define VALUE_IN_HEADER 23 /**! For values below this, the value is encoded
|
||||
directly in the header. */
|
||||
|
||||
#define BOOL_TO_PRIM 20 ///! In CBOR, false/true have the values 20/21
|
||||
|
||||
#define FLAG_RESTORE 1UL
|
||||
#define FLAG_DISCARD 2UL
|
||||
#define FLAG_TRANSFER_PAYLOAD 4UL
|
||||
|
||||
bool new_backup(cbor_state_t *state, uint32_t new_elem_count);
|
||||
|
||||
bool restore_backup(cbor_state_t *state, uint32_t flags,
|
||||
uint32_t max_elem_count);
|
||||
|
||||
bool union_start_code(cbor_state_t *state);
|
||||
|
||||
bool union_elem_code(cbor_state_t *state);
|
||||
|
||||
bool union_end_code(cbor_state_t *state);
|
||||
|
||||
bool entry_function(const uint8_t *payload, uint32_t payload_len,
|
||||
const void *struct_ptr, uint32_t *payload_len_out,
|
||||
cbor_encoder_t func, uint32_t elem_count, uint32_t num_backups);
|
||||
|
||||
#endif /* CBOR_COMMON_H__ */
|
|
@ -1,629 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cbor_decode.h"
|
||||
#include "cbor_common.h"
|
||||
|
||||
|
||||
/** Return value length from additional value.
|
||||
*/
|
||||
static uint32_t additional_len(uint8_t additional)
|
||||
{
|
||||
if (24 <= additional && additional <= 27) {
|
||||
/* 24 => 1
|
||||
* 25 => 2
|
||||
* 26 => 4
|
||||
* 27 => 8
|
||||
*/
|
||||
return 1 << (additional - 24);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Extract the major type, i.e. the first 3 bits of the header byte. */
|
||||
#define MAJOR_TYPE(header_byte) (((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) \
|
||||
do {\
|
||||
if (expr) { \
|
||||
(state->payload)--; \
|
||||
FAIL(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define FAIL_IF(expr) \
|
||||
do {\
|
||||
if (expr) { \
|
||||
FAIL(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define FAIL_RESTORE() \
|
||||
state->payload = state->payload_bak; \
|
||||
state->elem_count++; \
|
||||
FAIL()
|
||||
|
||||
/** Get a single value.
|
||||
*
|
||||
* @details @p ppayload must point to the header byte. This function will
|
||||
* retrieve the value (either from within the additional info, or from
|
||||
* the subsequent bytes) and return it in the result. The result can
|
||||
* have arbitrary length.
|
||||
*
|
||||
* The function will also validate
|
||||
* - Min/max constraints on the value.
|
||||
* - That @p payload doesn't overrun past @p payload_end.
|
||||
* - That @p elem_count has not been exhausted.
|
||||
*
|
||||
* @p ppayload and @p elem_count are updated if the function
|
||||
* 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).
|
||||
*/
|
||||
static bool value_extract(cbor_state_t *state,
|
||||
void *const result, uint32_t result_len)
|
||||
{
|
||||
cbor_trace();
|
||||
cbor_assert(result_len != 0, "0-length result not supported.\n");
|
||||
cbor_assert(result != NULL, NULL);
|
||||
|
||||
FAIL_IF((state->elem_count == 0) \
|
||||
|| (state->payload >= state->payload_end));
|
||||
|
||||
uint8_t *u8_result = (uint8_t *)result;
|
||||
uint8_t additional = ADDITIONAL(*state->payload);
|
||||
|
||||
state->payload_bak = state->payload;
|
||||
(state->payload)++;
|
||||
|
||||
memset(result, 0, result_len);
|
||||
if (additional <= VALUE_IN_HEADER) {
|
||||
#ifdef CONFIG_BIG_ENDIAN
|
||||
u8_result[result_len - 1] = additional;
|
||||
#else
|
||||
u8_result[0] = additional;
|
||||
#endif /* CONFIG_BIG_ENDIAN */
|
||||
} else {
|
||||
uint32_t len = additional_len(additional);
|
||||
|
||||
FAIL_AND_DECR_IF(len > result_len);
|
||||
FAIL_AND_DECR_IF((state->payload + len)
|
||||
> state->payload_end);
|
||||
|
||||
#ifdef CONFIG_BIG_ENDIAN
|
||||
memcpy(&u8_result[result_len - len], state->payload, len);
|
||||
#else
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
u8_result[i] = (state->payload)[len - i - 1];
|
||||
}
|
||||
#endif /* CONFIG_BIG_ENDIAN */
|
||||
|
||||
(state->payload) += len;
|
||||
}
|
||||
|
||||
(state->elem_count)--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool int32_decode(cbor_state_t *state, int32_t *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
uint32_t uint_result;
|
||||
int32_t int_result;
|
||||
|
||||
if (!value_extract(state, &uint_result, 4)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
cbor_print("uintval: %u\r\n", uint_result);
|
||||
if (uint_result >= (1 << (8*sizeof(uint_result)-1))) {
|
||||
/* Value is too large to fit in a signed integer. */
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
if (major_type == CBOR_MAJOR_TYPE_NINT) {
|
||||
/* Convert from CBOR's representation. */
|
||||
int_result = -1 - uint_result;
|
||||
} else {
|
||||
int_result = uint_result;
|
||||
}
|
||||
|
||||
cbor_print("val: %d\r\n", int_result);
|
||||
*result = int_result;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool intx32_decode(cbor_state_t *state, int32_t *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != CBOR_MAJOR_TYPE_PINT
|
||||
&& major_type != CBOR_MAJOR_TYPE_NINT) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!int32_decode(state, result)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intx32_expect(cbor_state_t *state, int32_t result)
|
||||
{
|
||||
int32_t value;
|
||||
|
||||
if (!intx32_decode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (value != result) {
|
||||
cbor_print("%d != %d\r\n", value, result);
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool uint32_decode(cbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
if (!value_extract(state, result, 4)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uintx32_decode(cbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != CBOR_MAJOR_TYPE_PINT) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
FAIL();
|
||||
}
|
||||
if (!uint32_decode(state, result)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uintx32_expect(cbor_state_t *state, uint32_t result)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (!uintx32_decode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
cbor_print("%u != %u\r\n", value, result);
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uintx32_expect_union(cbor_state_t *state, uint32_t result)
|
||||
{
|
||||
union_elem_code(state);
|
||||
return uintx32_expect(state, result);
|
||||
}
|
||||
|
||||
|
||||
static bool strx_start_decode(cbor_state_t *state,
|
||||
cbor_string_type_t *result, cbor_major_type_t exp_major_type)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != exp_major_type) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!uint32_decode(state, &result->len)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (result->len > (state->payload_end - state->payload)) {
|
||||
cbor_print("error: 0x%x > 0x%x\r\n",
|
||||
(uint32_t)result->len,
|
||||
(uint32_t)(state->payload_end - state->payload));
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
result->value = state->payload;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result)
|
||||
{
|
||||
if(!strx_start_decode(state, result, CBOR_MAJOR_TYPE_BSTR)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!new_backup(state, 0xFFFFFFFF)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
/* Overflow is checked in strx_start_decode() */
|
||||
state->payload_end = result->value + result->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bstrx_cbor_end_decode(cbor_state_t *state)
|
||||
{
|
||||
if (state->payload != state->payload_end) {
|
||||
FAIL();
|
||||
}
|
||||
if (!restore_backup(state,
|
||||
FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD,
|
||||
0xFFFFFFFF)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool strx_decode(cbor_state_t *state, cbor_string_type_t *result,
|
||||
cbor_major_type_t exp_major_type)
|
||||
{
|
||||
if (!strx_start_decode(state, result, exp_major_type)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
/* Overflow is checked in strx_start_decode() */
|
||||
(state->payload) += result->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool strx_expect(cbor_state_t *state, cbor_string_type_t *result,
|
||||
cbor_major_type_t exp_major_type)
|
||||
{
|
||||
cbor_string_type_t tmp_result;
|
||||
|
||||
if (!strx_decode(state, &tmp_result, exp_major_type)) {
|
||||
FAIL();
|
||||
}
|
||||
if ((tmp_result.len != result->len)
|
||||
|| memcmp(result->value, tmp_result.value, tmp_result.len)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result)
|
||||
{
|
||||
return strx_decode(state, result, CBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result)
|
||||
{
|
||||
return strx_expect(state, result, CBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result)
|
||||
{
|
||||
return strx_decode(state, result, CBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result)
|
||||
{
|
||||
return strx_expect(state, result, CBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
static bool list_map_start_decode(cbor_state_t *state,
|
||||
cbor_major_type_t exp_major_type)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
uint32_t new_elem_count;
|
||||
|
||||
if (major_type != exp_major_type) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!uint32_decode(state, &new_elem_count)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!new_backup(state, new_elem_count)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool list_start_decode(cbor_state_t *state)
|
||||
{
|
||||
return list_map_start_decode(state, CBOR_MAJOR_TYPE_LIST);
|
||||
}
|
||||
|
||||
|
||||
bool map_start_decode(cbor_state_t *state)
|
||||
{
|
||||
bool ret = list_map_start_decode(state, CBOR_MAJOR_TYPE_MAP);
|
||||
|
||||
if (ret) {
|
||||
state->elem_count *= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool list_map_end_decode(cbor_state_t *state)
|
||||
{
|
||||
if (!restore_backup(state,
|
||||
FLAG_RESTORE | FLAG_DISCARD | FLAG_TRANSFER_PAYLOAD,
|
||||
0)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool list_end_decode(cbor_state_t *state)
|
||||
{
|
||||
return list_map_end_decode(state);
|
||||
}
|
||||
|
||||
|
||||
bool map_end_decode(cbor_state_t *state)
|
||||
{
|
||||
return list_map_end_decode(state);
|
||||
}
|
||||
|
||||
|
||||
static bool primx_decode(cbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != CBOR_MAJOR_TYPE_PRIM) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
FAIL();
|
||||
}
|
||||
if (!uint32_decode(state, result)) {
|
||||
FAIL();
|
||||
}
|
||||
if (*result > 0xFF) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool primx_expect(cbor_state_t *state, uint32_t result)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (!primx_decode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool nilx_expect(cbor_state_t *state, void *result)
|
||||
{
|
||||
if (!primx_expect(state, 22)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool boolx_decode(cbor_state_t *state, bool *result)
|
||||
{
|
||||
uint32_t tmp_result;
|
||||
|
||||
if (!primx_decode(state, &tmp_result)) {
|
||||
FAIL();
|
||||
}
|
||||
(*result) = tmp_result - BOOL_TO_PRIM;
|
||||
|
||||
cbor_print("boolval: %u\r\n", *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool boolx_expect(cbor_state_t *state, bool result)
|
||||
{
|
||||
bool value;
|
||||
|
||||
if (!boolx_decode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool double_decode(cbor_state_t *state, double *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != CBOR_MAJOR_TYPE_PRIM) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
FAIL();
|
||||
}
|
||||
if (!value_extract(state, result,
|
||||
sizeof(*result))) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool double_expect(cbor_state_t *state, double *result)
|
||||
{
|
||||
double value;
|
||||
|
||||
if (!double_decode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
if (value != *result) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool any_decode(cbor_state_t *state, void *result)
|
||||
{
|
||||
cbor_assert(result == NULL,
|
||||
"'any' type cannot be returned, only skipped.\n");
|
||||
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
uint32_t value;
|
||||
uint32_t num_decode;
|
||||
void *null_result = NULL;
|
||||
uint32_t temp_elem_count;
|
||||
uint8_t const *payload_bak;
|
||||
|
||||
if (!value_extract(state, &value, sizeof(value))) {
|
||||
/* Can happen because of elem_count (or payload_end) */
|
||||
FAIL();
|
||||
}
|
||||
|
||||
switch (major_type) {
|
||||
case CBOR_MAJOR_TYPE_BSTR:
|
||||
case CBOR_MAJOR_TYPE_TSTR:
|
||||
(state->payload) += value;
|
||||
break;
|
||||
case CBOR_MAJOR_TYPE_MAP:
|
||||
value *= 2; /* Because all members have a key. */
|
||||
/* Fallthrough */
|
||||
case CBOR_MAJOR_TYPE_LIST:
|
||||
temp_elem_count = state->elem_count;
|
||||
payload_bak = state->payload;
|
||||
state->elem_count = value;
|
||||
if (!multi_decode(value, value, &num_decode,
|
||||
(void *)any_decode, state,
|
||||
&null_result, 0)) {
|
||||
state->elem_count = temp_elem_count;
|
||||
state->payload = payload_bak;
|
||||
FAIL();
|
||||
}
|
||||
state->elem_count = temp_elem_count;
|
||||
break;
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool tag_decode(cbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
FAIL_IF(state->payload >= state->payload_end);
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
|
||||
if (major_type != CBOR_MAJOR_TYPE_TAG) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
FAIL();
|
||||
}
|
||||
if (!uint32_decode(state, result)) {
|
||||
FAIL();
|
||||
}
|
||||
state->elem_count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool tag_expect(cbor_state_t *state, uint32_t result)
|
||||
{
|
||||
uint32_t tag_val;
|
||||
|
||||
if (!tag_decode(state, &tag_val)) {
|
||||
FAIL();
|
||||
}
|
||||
if (tag_val != result) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool multi_decode(uint32_t min_decode,
|
||||
uint32_t max_decode,
|
||||
uint32_t *num_decode,
|
||||
cbor_decoder_t decoder,
|
||||
cbor_state_t *state,
|
||||
void *result,
|
||||
uint32_t result_len)
|
||||
{
|
||||
for (uint32_t i = 0; i < max_decode; i++) {
|
||||
uint8_t const *payload_bak = state->payload;
|
||||
uint32_t elem_count_bak = state->elem_count;
|
||||
|
||||
if (!decoder(state,
|
||||
(uint8_t *)result + i*result_len)) {
|
||||
*num_decode = i;
|
||||
state->payload = payload_bak;
|
||||
state->elem_count = elem_count_bak;
|
||||
if (i < min_decode) {
|
||||
FAIL();
|
||||
} else {
|
||||
cbor_print("Found %zu elements.\n", i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cbor_print("Found %zu elements.\n", max_decode);
|
||||
*num_decode = max_decode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool present_decode(uint32_t *present,
|
||||
cbor_decoder_t decoder,
|
||||
cbor_state_t *state,
|
||||
void *result)
|
||||
{
|
||||
uint32_t num_decode;
|
||||
bool retval = multi_decode(0, 1, &num_decode, decoder, state, result, 0);
|
||||
if (retval) {
|
||||
*present = num_decode;
|
||||
}
|
||||
return retval;
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef CBOR_DECODE_H__
|
||||
#define CBOR_DECODE_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "cbor_common.h"
|
||||
|
||||
/** The cbor_decode library provides functions for decoding CBOR data elements.
|
||||
*
|
||||
* This library is primarily meant to be called from code generated by
|
||||
* $CDDL_GEN_BASE/cddl_gen/cddl_gen.py script, or its equivalent cddl_gen
|
||||
* command line executable.
|
||||
*
|
||||
* Some details to notice about this library:
|
||||
* - Integers are all 32 bits (uint32_t). This means that CBOR's 64 bit values
|
||||
* are not supported, even when the code is running on a 64 bit architecture.
|
||||
* This applies to integer types, as well as lengths for other types.
|
||||
* - Strings are kept in the container type cbor_string_type_t, which is a
|
||||
* pointer and a length.
|
||||
* - When a function returns false, it only means that decoding that particular
|
||||
* value failed. If a value is allowed to take multiple different values,
|
||||
* another decoding function can be called if the first fails.
|
||||
* - There is some type casting going on under the hood to make the code
|
||||
* generator friendly. See especially the processor_t type which is compatible
|
||||
* with all functions except multi_decode, but the compiler doesn't "know"
|
||||
* this because they are defined with different pointer types. It also means
|
||||
* any usage of multi_decode must be made with care for function types.
|
||||
*
|
||||
*
|
||||
* CBOR's format is described well on Wikipedia
|
||||
* - https://en.wikipedia.org/wiki/CBOR
|
||||
* but here's a synopsis:
|
||||
*
|
||||
* Encoded CBOR data elements look like this.
|
||||
*
|
||||
* | Header | Value | Payload |
|
||||
* | 1 byte | 0, 1, 2, 4, or 8 bytes | 0 - 2^64-1 bytes/elements |
|
||||
* | 3 bits | 5 bits |
|
||||
* | Major | Additional|
|
||||
* | Type | info |
|
||||
*
|
||||
* The available major types can be seen in @ref cbor_major_type_t.
|
||||
*
|
||||
* For all types, Values 0-23 are encoded directly in the "Additional info",
|
||||
* meaning that the "Value" field is 0 bytes long. If "Additional info" is 24,
|
||||
* 25, 26, or 27, the "Value" field is 1, 2, 4, or 8 bytes long, respectively.
|
||||
*
|
||||
* Major types PINT, NINT, TAG, and PRIM elements have no payload, only Value.
|
||||
* PINT: Interpret the Value as a positive integer.
|
||||
* NINT: Interpret the Value as a positive integer, then multiply by -1 and
|
||||
* subtract 1.
|
||||
* TAG: The Value says something about the next non-tag element.
|
||||
* See https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
|
||||
* PRIM: Different Values mean different things:
|
||||
* 20: "false"
|
||||
* 21: "true"
|
||||
* 22: "null"
|
||||
* 23: "undefined"
|
||||
* >=0x10000: Interpret as IEEE 754 float with given precision
|
||||
*
|
||||
* For BSTR, TSTR, LIST, and MAP, the Value describes the length of the payload.
|
||||
* For BSTR and TSTR, the length is in bytes, for LIST, the length is in number
|
||||
* of elements, and for MAP, the length is in number of key/value element pairs.
|
||||
*
|
||||
* For LIST and MAP, sub elements are regular CBOR elements with their own
|
||||
* Header, Value and Payload. LISTs and MAPs can be recursively encoded.
|
||||
*
|
||||
* The additional info means slightly different things for different major
|
||||
* types.
|
||||
*/
|
||||
|
||||
/** Decode a PINT/NINT into a int32_t.
|
||||
*
|
||||
* @param[inout] state The current state of the decoding.
|
||||
* @param[out] result Where to place the decoded value.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
bool intx32_decode(cbor_state_t *state, int32_t *result);
|
||||
|
||||
/** Expect a PINT/NINT with a certain value. Uses intx32_decode internally.
|
||||
*
|
||||
* @param[inout] state The current state of the decoding.
|
||||
* @param[in] result The expected value
|
||||
*
|
||||
* @retval true If the result was decoded correctly and has the expected value.
|
||||
* @retval false If intx32_decode failed or the result doesn't have the
|
||||
* expected value.
|
||||
*/
|
||||
bool intx32_expect(cbor_state_t *state, int32_t result);
|
||||
|
||||
/** Decode a PINT. */
|
||||
bool uintx32_decode(cbor_state_t *state, uint32_t *result);
|
||||
bool uintx32_expect(cbor_state_t *state, uint32_t result);
|
||||
bool uintx32_expect_union(cbor_state_t *state, uint32_t result);
|
||||
|
||||
/** Decode and consume a BSTR header.
|
||||
*
|
||||
* The rest of the string can be decoded as CBOR.
|
||||
* A state backup is created to keep track of the element count.
|
||||
*
|
||||
* @retval true Header decoded correctly
|
||||
* @retval false Header decoded incorrectly, or backup failed.
|
||||
*/
|
||||
bool bstrx_cbor_start_decode(cbor_state_t *state, cbor_string_type_t *result);
|
||||
|
||||
/** Finalize decoding a CBOR-encoded bstr.
|
||||
*
|
||||
* Restore element count from backup.
|
||||
*/
|
||||
bool bstrx_cbor_end_decode(cbor_state_t *state);
|
||||
|
||||
/** Decode and consume a BSTR */
|
||||
bool bstrx_decode(cbor_state_t *state, cbor_string_type_t *result);
|
||||
bool bstrx_expect(cbor_state_t *state, cbor_string_type_t *result);
|
||||
|
||||
/** Decode and consume a TSTR */
|
||||
bool tstrx_decode(cbor_state_t *state, cbor_string_type_t *result);
|
||||
bool tstrx_expect(cbor_state_t *state, cbor_string_type_t *result);
|
||||
|
||||
/** Decode and consume a LIST header.
|
||||
*
|
||||
* The contents of the list can be decoded via subsequent function calls.
|
||||
* A state backup is created to keep track of the element count.
|
||||
*
|
||||
* @retval true Header decoded correctly
|
||||
* @retval false Header decoded incorrectly, or backup failed.
|
||||
*/
|
||||
bool list_start_decode(cbor_state_t *state);
|
||||
|
||||
/** Decode and consume a MAP header. */
|
||||
bool map_start_decode(cbor_state_t *state);
|
||||
|
||||
/** Finalize decoding a LIST
|
||||
*
|
||||
* Check that the list had the correct number of elements, and restore previous
|
||||
* element count from backup.
|
||||
*
|
||||
* @retval true Everything ok.
|
||||
* @retval false Element count not correct.
|
||||
*/
|
||||
bool list_end_decode(cbor_state_t *state);
|
||||
|
||||
/** Finalize decoding a MAP */
|
||||
bool map_end_decode(cbor_state_t *state);
|
||||
|
||||
/** Decode a "nil" primitive value. */
|
||||
bool nilx_expect(cbor_state_t *state, void *result);
|
||||
|
||||
/** Decode a boolean primitive value. */
|
||||
bool boolx_decode(cbor_state_t *state, bool *result);
|
||||
bool boolx_expect(cbor_state_t *state, bool result);
|
||||
|
||||
/** Decode a float */
|
||||
bool float_decode(cbor_state_t *state, double *result);
|
||||
bool float_expect(cbor_state_t *state, double *result);
|
||||
|
||||
/** Skip a single element, regardless of type and value. */
|
||||
bool any_decode(cbor_state_t *state, void *result);
|
||||
|
||||
/** Decode a tag. */
|
||||
bool tag_decode(cbor_state_t *state, uint32_t *result);
|
||||
bool tag_expect(cbor_state_t *state, uint32_t result);
|
||||
|
||||
/** Decode 0 or more elements with the same type and constraints.
|
||||
*
|
||||
* @details This must not necessarily decode all elements in a list. E.g. if
|
||||
* the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs
|
||||
* with length 8, that could be done with:
|
||||
*
|
||||
* @code{c}
|
||||
* uint32_t int_min = 0;
|
||||
* uint32_t int_max = 100;
|
||||
* uint32_t bstr_size = 8;
|
||||
* uint32_t ints[3];
|
||||
* cbor_string_type_t bstrs[2];
|
||||
* bool res;
|
||||
*
|
||||
* res = list_start_encode(state, 3, 5);
|
||||
* // check res
|
||||
* res = multi_encode(3, 3, &num_encode, uintx32_encode, state,
|
||||
* ints, &int_min, &int_max, 4);
|
||||
* // check res
|
||||
* res = multi_encode(0, 2, &num_encode, strx_encode, state,
|
||||
* bstrs, &bstr_size, &bstr_size,
|
||||
* sizeof(cbor_string_type_t));
|
||||
* // check res
|
||||
* res = list_end_encode(state, 3, 5);
|
||||
* // check res
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] min_decode The minimum acceptable number of elements.
|
||||
* @param[in] max_decode The maximum acceptable number of elements.
|
||||
* @param[out] num_decode The actual number of elements.
|
||||
* @param[in] decoder The decoder function to call under the hood. This
|
||||
* function will be called with the provided arguments
|
||||
* repeatedly until the function fails (returns false)
|
||||
* or until it has been called @p max_decode times.
|
||||
* result is moved @p result_len bytes for each call
|
||||
* to @p decoder, i.e. @p result refers to an array
|
||||
* of result variables.
|
||||
* @param[out] result Where to place the decoded values. Must be an array
|
||||
* of length at least @p max_decode.
|
||||
* @param[in] result_len The length of the result variables. Must be the
|
||||
* length matching the elements of @p result.
|
||||
*
|
||||
* @retval true If at least @p min_decode variables were correctly decoded.
|
||||
* @retval false If @p decoder failed before having decoded @p min_decode
|
||||
* values.
|
||||
*/
|
||||
bool multi_decode(uint32_t min_decode, uint32_t max_decode, uint32_t *num_decode,
|
||||
cbor_decoder_t decoder, cbor_state_t *state, void *result,
|
||||
uint32_t result_len);
|
||||
|
||||
bool present_decode(uint32_t *present,
|
||||
cbor_decoder_t decoder,
|
||||
cbor_state_t *state,
|
||||
void *result);
|
||||
|
||||
#endif /* CBOR_DECODE_H__ */
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cbor_encode.h"
|
||||
#include "cbor_common.h"
|
||||
|
||||
_Static_assert((sizeof(size_t) == sizeof(void *)),
|
||||
"This code needs size_t to be the same length as pointers.");
|
||||
|
||||
uint8_t get_additional(uint32_t len, uint8_t value0)
|
||||
{
|
||||
switch(len) {
|
||||
case 0: return value0;
|
||||
case 1: return 24;
|
||||
case 2: return 25;
|
||||
case 3: return 25;
|
||||
case 4: return 26;
|
||||
case 5: return 26;
|
||||
case 6: return 26;
|
||||
case 7: return 26;
|
||||
case 8: return 27;
|
||||
}
|
||||
|
||||
cbor_assert(false, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool encode_header_byte(cbor_state_t *state,
|
||||
cbor_major_type_t major_type, uint8_t additional)
|
||||
{
|
||||
if ((state->payload + 1) > state->payload_end) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
cbor_assert(additional < 32, NULL);
|
||||
|
||||
*(state->payload_mut++) = (major_type << 5) | (additional & 0x1F);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Encode a single value.
|
||||
*/
|
||||
static bool value_encode_len(cbor_state_t *state, cbor_major_type_t major_type,
|
||||
const void *const input, uint32_t result_len)
|
||||
{
|
||||
uint8_t *u8_result = (uint8_t *)input;
|
||||
|
||||
if ((state->payload + 1 + result_len) > state->payload_end) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (!encode_header_byte(state, major_type,
|
||||
get_additional(result_len, u8_result[0]))) {
|
||||
FAIL();
|
||||
}
|
||||
state->payload_mut--;
|
||||
cbor_trace();
|
||||
state->payload_mut++;
|
||||
|
||||
#ifdef CONFIG_BIG_ENDIAN
|
||||
memcpy(state->payload_mut, u8_result, result_len);
|
||||
state->payload_mut += result_len;
|
||||
#else
|
||||
for (; result_len > 0; result_len--) {
|
||||
*(state->payload_mut++) = u8_result[result_len - 1];
|
||||
}
|
||||
#endif
|
||||
|
||||
state->elem_count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t get_result_len(const void *const input, uint32_t max_result_len)
|
||||
{
|
||||
uint8_t *u8_result = (uint8_t *)input;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < max_result_len; i++) {
|
||||
#ifdef CONFIG_BIG_ENDIAN
|
||||
size_t idx = i;
|
||||
#else
|
||||
size_t idx = max_result_len - 1 - i;
|
||||
#endif
|
||||
if (u8_result[idx] != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
max_result_len -= i;
|
||||
|
||||
/* According to specification result length can be encoded on 1, 2, 4
|
||||
* or 8 bytes.
|
||||
*/
|
||||
cbor_assert(max_result_len <= 8, "Up to 8 bytes can be used to encode length.\n");
|
||||
size_t encode_byte_cnt = 1;
|
||||
|
||||
for (size_t i = 0; i <= 3; i++) {
|
||||
if (max_result_len <= encode_byte_cnt) {
|
||||
max_result_len = encode_byte_cnt;
|
||||
break;
|
||||
}
|
||||
|
||||
encode_byte_cnt *= 2;
|
||||
}
|
||||
|
||||
if ((max_result_len == 1) && (u8_result[0] <= VALUE_IN_HEADER)) {
|
||||
max_result_len = 0;
|
||||
}
|
||||
|
||||
return max_result_len;
|
||||
}
|
||||
|
||||
|
||||
static bool value_encode(cbor_state_t *state, cbor_major_type_t major_type,
|
||||
const void *const input, uint32_t max_result_len)
|
||||
{
|
||||
cbor_assert(max_result_len != 0, "0-length result not supported.\n");
|
||||
return value_encode_len(state, major_type, input,
|
||||
get_result_len(input, max_result_len));
|
||||
}
|
||||
|
||||
|
||||
bool intx32_put(cbor_state_t *state, int32_t input)
|
||||
{
|
||||
cbor_major_type_t major_type;
|
||||
|
||||
if (input < 0) {
|
||||
major_type = CBOR_MAJOR_TYPE_NINT;
|
||||
/* Convert from CBOR's representation. */
|
||||
input = -1 - input;
|
||||
} else {
|
||||
major_type = CBOR_MAJOR_TYPE_PINT;
|
||||
input = input;
|
||||
}
|
||||
|
||||
if (!value_encode(state, major_type, &input, 4)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool intx32_encode(cbor_state_t *state, const int32_t *input)
|
||||
{
|
||||
return intx32_put(state, *input);
|
||||
}
|
||||
|
||||
|
||||
static bool uint32_encode(cbor_state_t *state, const uint32_t *input,
|
||||
cbor_major_type_t major_type)
|
||||
{
|
||||
if (!value_encode(state, major_type, input, 4)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uintx32_encode(cbor_state_t *state, const uint32_t *input)
|
||||
{
|
||||
if (!uint32_encode(state, input, CBOR_MAJOR_TYPE_PINT)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uintx32_put(cbor_state_t *state, uint32_t input)
|
||||
{
|
||||
if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PINT)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool strx_start_encode(cbor_state_t *state,
|
||||
const cbor_string_type_t *input, cbor_major_type_t major_type)
|
||||
{
|
||||
if (input->value && ((get_result_len(&input->len, sizeof(input->len))
|
||||
+ 1 + input->len + (size_t)state->payload)
|
||||
> (size_t)state->payload_end)) {
|
||||
FAIL();
|
||||
}
|
||||
if (!uint32_encode(state, &input->len, major_type)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool primx_encode(cbor_state_t *state, uint32_t input)
|
||||
{
|
||||
if (!uint32_encode(state, &input, CBOR_MAJOR_TYPE_PRIM)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t remaining_str_len(cbor_state_t *state)
|
||||
{
|
||||
uint32_t max_len = (size_t)state->payload_end - (size_t)state->payload;
|
||||
uint32_t result_len = get_result_len(&max_len, sizeof(uint32_t));
|
||||
return max_len - result_len - 1;
|
||||
}
|
||||
|
||||
|
||||
bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result)
|
||||
{
|
||||
if (!new_backup(state, 0)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
uint32_t max_len = remaining_str_len(state);
|
||||
|
||||
/* Encode a dummy header */
|
||||
if (!uint32_encode(state, &max_len,
|
||||
CBOR_MAJOR_TYPE_BSTR)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool bstrx_cbor_end_encode(cbor_state_t *state)
|
||||
{
|
||||
const uint8_t *payload = state->payload;
|
||||
|
||||
if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
|
||||
FAIL();
|
||||
}
|
||||
cbor_string_type_t value;
|
||||
|
||||
value.value = state->payload_end - remaining_str_len(state);
|
||||
value.len = (size_t)payload - (size_t)value.value;
|
||||
|
||||
/* Reencode header of list now that we know the number of elements. */
|
||||
if (!bstrx_encode(state, &value)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool strx_encode(cbor_state_t *state,
|
||||
const cbor_string_type_t *input, cbor_major_type_t major_type)
|
||||
{
|
||||
if (!strx_start_encode(state, input, major_type)) {
|
||||
FAIL();
|
||||
}
|
||||
if (input->len > (state->payload_end - state->payload)) {
|
||||
FAIL();
|
||||
}
|
||||
if (state->payload_mut != input->value) {
|
||||
memmove(state->payload_mut, input->value, input->len);
|
||||
}
|
||||
state->payload += input->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
|
||||
{
|
||||
return strx_encode(state, input, CBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *input)
|
||||
{
|
||||
return strx_encode(state, input, CBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
static bool list_map_start_encode(cbor_state_t *state, uint32_t max_num,
|
||||
cbor_major_type_t major_type)
|
||||
{
|
||||
#ifdef CDDL_CBOR_CANONICAL
|
||||
if (!new_backup(state, 0)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
/* Encode dummy header with max number of elements. */
|
||||
if (!uint32_encode(state, &max_num, major_type)) {
|
||||
FAIL();
|
||||
}
|
||||
state->elem_count--; /* Because of dummy header. */
|
||||
#else
|
||||
if (!encode_header_byte(state, major_type, 31)) {
|
||||
FAIL();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool list_start_encode(cbor_state_t *state, uint32_t max_num)
|
||||
{
|
||||
return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
|
||||
}
|
||||
|
||||
|
||||
bool map_start_encode(cbor_state_t *state, uint32_t max_num)
|
||||
{
|
||||
return list_map_start_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
|
||||
}
|
||||
|
||||
|
||||
bool list_map_end_encode(cbor_state_t *state, uint32_t max_num,
|
||||
cbor_major_type_t major_type)
|
||||
{
|
||||
#ifdef CDDL_CBOR_CANONICAL
|
||||
uint32_t list_count = ((major_type == CBOR_MAJOR_TYPE_LIST) ?
|
||||
state->elem_count
|
||||
: (state->elem_count / 2));
|
||||
|
||||
const uint8_t *payload = state->payload;
|
||||
uint32_t max_header_len = get_result_len(&max_num, 4);
|
||||
uint32_t header_len = get_result_len(&list_count, 4);
|
||||
|
||||
if (!restore_backup(state, FLAG_RESTORE | FLAG_DISCARD, 0xFFFFFFFF)) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
cbor_print("list_count: %d\r\n", list_count);
|
||||
|
||||
/* Reencode header of list now that we know the number of elements. */
|
||||
if (!(uint32_encode(state, &list_count, major_type))) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
if (max_header_len != header_len) {
|
||||
const uint8_t *start = state->payload + max_header_len - header_len;
|
||||
uint32_t body_size = payload - start;
|
||||
memmove(state->payload_mut,
|
||||
state->payload + max_header_len - header_len,
|
||||
body_size);
|
||||
/* Reset payload pointer to end of list */
|
||||
state->payload += body_size;
|
||||
} else {
|
||||
/* Reset payload pointer to end of list */
|
||||
state->payload = payload;
|
||||
}
|
||||
#else
|
||||
if (!encode_header_byte(state, CBOR_MAJOR_TYPE_PRIM, 31)) {
|
||||
FAIL();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool list_end_encode(cbor_state_t *state, uint32_t max_num)
|
||||
{
|
||||
return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_LIST);
|
||||
}
|
||||
|
||||
|
||||
bool map_end_encode(cbor_state_t *state, uint32_t max_num)
|
||||
{
|
||||
return list_map_end_encode(state, max_num, CBOR_MAJOR_TYPE_MAP);
|
||||
}
|
||||
|
||||
|
||||
bool nilx_put(cbor_state_t *state, const void *input)
|
||||
{
|
||||
(void)input;
|
||||
return primx_encode(state, 22);
|
||||
}
|
||||
|
||||
|
||||
bool boolx_encode(cbor_state_t *state, const bool *input)
|
||||
{
|
||||
if (!primx_encode(state, *input + BOOL_TO_PRIM)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool boolx_put(cbor_state_t *state, bool input)
|
||||
{
|
||||
if (!primx_encode(state, input + BOOL_TO_PRIM)) {
|
||||
FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool double_encode(cbor_state_t *state, double *input)
|
||||
{
|
||||
if (!value_encode(state, CBOR_MAJOR_TYPE_PRIM, input,
|
||||
sizeof(*input))) {
|
||||
FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool double_put(cbor_state_t *state, double input)
|
||||
{
|
||||
return double_encode(state, &input);
|
||||
}
|
||||
|
||||
|
||||
bool any_encode(cbor_state_t *state, void *input)
|
||||
{
|
||||
return nilx_put(state, input);
|
||||
}
|
||||
|
||||
|
||||
bool tag_encode(cbor_state_t *state, uint32_t tag)
|
||||
{
|
||||
if (!value_encode(state, CBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
|
||||
FAIL();
|
||||
}
|
||||
state->elem_count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool multi_encode(uint32_t min_encode,
|
||||
uint32_t max_encode,
|
||||
const uint32_t *num_encode,
|
||||
cbor_encoder_t encoder,
|
||||
cbor_state_t *state,
|
||||
const void *input,
|
||||
uint32_t result_len)
|
||||
{
|
||||
if (!PTR_VALUE_IN_RANGE(uint32_t, num_encode, NULL, &max_encode)) {
|
||||
FAIL();
|
||||
}
|
||||
for (uint32_t i = 0; i < *num_encode; i++) {
|
||||
if (!encoder(state, (const uint8_t *)input + i*result_len)) {
|
||||
FAIL();
|
||||
}
|
||||
}
|
||||
cbor_print("Found %zu elements.\n", *num_encode);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool present_encode(const uint32_t *present,
|
||||
cbor_encoder_t encoder,
|
||||
cbor_state_t *state,
|
||||
const void *input)
|
||||
{
|
||||
uint32_t num_encode = *present;
|
||||
bool retval = multi_encode(0, 1, &num_encode, encoder, state, input, 0);
|
||||
return retval;
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* This file has been copied from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef CBOR_ENCODE_H__
|
||||
#define CBOR_ENCODE_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "cbor_common.h"
|
||||
|
||||
|
||||
/** Encode a PINT/NINT into a int32_t.
|
||||
*
|
||||
* @param[inout] state The current state of the decoding.
|
||||
* @param[out] result Where to place the encoded value.
|
||||
*
|
||||
* @retval true Everything is ok.
|
||||
* @retval false If the payload is exhausted.
|
||||
*/
|
||||
bool intx32_encode(cbor_state_t *state, const int32_t *input);
|
||||
bool intx32_put(cbor_state_t *state, int32_t result);
|
||||
|
||||
/** Encode a PINT into a uint32_t. */
|
||||
bool uintx32_encode(cbor_state_t *state, const uint32_t *result);
|
||||
bool uintx32_put(cbor_state_t *state, uint32_t result);
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @retval true Header encoded correctly
|
||||
* @retval false Header encoded incorrectly, or backup failed.
|
||||
*/
|
||||
bool bstrx_cbor_start_encode(cbor_state_t *state, const cbor_string_type_t *result);
|
||||
|
||||
/** Finalize encoding a CBOR-encoded BSTR.
|
||||
*
|
||||
* Restore element count from backup.
|
||||
*/
|
||||
bool bstrx_cbor_end_encode(cbor_state_t *state);
|
||||
|
||||
/** Encode a BSTR, */
|
||||
bool bstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
|
||||
|
||||
/** Encode a TSTR. */
|
||||
bool tstrx_encode(cbor_state_t *state, const cbor_string_type_t *result);
|
||||
|
||||
#define tstrx_put(state, string) \
|
||||
tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = (sizeof(string) - 1)})
|
||||
|
||||
#define tstrx_put_term(state, string) \
|
||||
tstrx_encode(state, &(cbor_string_type_t){.value = (const uint8_t *)string, .len = strlen((const char *)string)})
|
||||
|
||||
/** Encode a LIST header.
|
||||
*
|
||||
* The contents of the list can be decoded via subsequent function calls.
|
||||
* A state backup is created to keep track of the element count.
|
||||
*/
|
||||
bool list_start_encode(cbor_state_t *state, uint32_t max_num);
|
||||
|
||||
/** Encode a MAP header. */
|
||||
bool map_start_encode(cbor_state_t *state, uint32_t max_num);
|
||||
|
||||
/** Encode end of a LIST. Do some checks and deallocate backup. */
|
||||
bool list_end_encode(cbor_state_t *state, uint32_t max_num);
|
||||
|
||||
/** Encode end of a MAP. Do some checks and deallocate backup. */
|
||||
bool map_end_encode(cbor_state_t *state, uint32_t max_num);
|
||||
|
||||
/** Encode a "nil" primitive value. result should be NULL. */
|
||||
bool nilx_put(cbor_state_t *state, const void *result);
|
||||
|
||||
/** Encode a boolean primitive value. */
|
||||
bool boolx_encode(cbor_state_t *state, const bool *result);
|
||||
bool boolx_put(cbor_state_t *state, bool result);
|
||||
|
||||
/** Encode a float */
|
||||
bool float_encode(cbor_state_t *state, double *result);
|
||||
bool float_put(cbor_state_t *state, double result);
|
||||
|
||||
/** Dummy encode "any": Encode a "nil". input should be NULL. */
|
||||
bool any_encode(cbor_state_t *state, void *input);
|
||||
|
||||
/** Encode a tag. */
|
||||
bool tag_encode(cbor_state_t *state, uint32_t tag);
|
||||
|
||||
/** Encode 0 or more elements with the same type and constraints.
|
||||
*
|
||||
* @details This must not necessarily encode all elements in a list. E.g. if
|
||||
* the list contains 3 INTS between 0 and 100 followed by 0 to 2 BSTRs
|
||||
* with length 8, that could be done with:
|
||||
*
|
||||
* @code{c}
|
||||
* uint32_t int_min = 0;
|
||||
* uint32_t int_max = 100;
|
||||
* uint32_t bstr_size = 8;
|
||||
* uint32_t ints[3];
|
||||
* cbor_string_type_t bstrs[2] = <initialize here>;
|
||||
* bool res;
|
||||
*
|
||||
* res = list_start_encode(state, 5);
|
||||
* // check res
|
||||
* res = multi_encode(3, 3, &num_encode, uintx32_encode, state,
|
||||
* ints, 4);
|
||||
* // check res
|
||||
* res = multi_encode(0, 2, &num_encode, strx_encode, state,
|
||||
* bstrs, sizeof(cbor_string_type_t));
|
||||
* // check res
|
||||
* res = list_end_encode(state, 5);
|
||||
* // check res
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] min_encode The minimum acceptable number of elements.
|
||||
* @param[in] max_encode The maximum acceptable number of elements.
|
||||
* @param[in] num_encode The actual number of elements.
|
||||
* @param[in] encoder The encoder function to call under the hood. This
|
||||
* function will be called with the provided arguments
|
||||
* repeatedly until the function fails (returns false)
|
||||
* or until it has been called @p max_encode times.
|
||||
* result is moved @p result_len bytes for each call
|
||||
* to @p encoder, i.e. @p result refers to an array
|
||||
* of result variables.
|
||||
* @param[in] input Source of the encoded values. Must be an array
|
||||
* of length at least @p max_encode.
|
||||
* @param[in] result_len The length of the result variables. Must be the
|
||||
* length of the elements in result.
|
||||
*
|
||||
* @retval true If at least @p min_encode variables were correctly encoded.
|
||||
* @retval false If @p encoder failed before having encoded @p min_encode
|
||||
* values.
|
||||
*/
|
||||
bool multi_encode(uint32_t min_encode, uint32_t max_encode, const uint32_t *num_encode,
|
||||
cbor_encoder_t encoder, cbor_state_t *state, const void *input,
|
||||
uint32_t result_len);
|
||||
|
||||
bool present_encode(const uint32_t *present,
|
||||
cbor_encoder_t encoder,
|
||||
cbor_state_t *state,
|
||||
const void *input);
|
||||
|
||||
#endif /* CBOR_ENCODE_H__ */
|
|
@ -1,36 +1,30 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ "$1" == "--help" ] || [ "$1" == "" ]; then
|
||||
echo "Regenerate serial_recovery_cbor.c|h if the cddl-gen submodule is updated."
|
||||
echo "Regenerate serial_recovery_cbor.c|h if the zcbor submodule is updated."
|
||||
echo "Usage: $0 <copyright>"
|
||||
echo " e.g. $0 \"2021 Nordic Semiconductor ASA\""
|
||||
echo " e.g. $0 \"2022 Nordic Semiconductor ASA\""
|
||||
exit -1
|
||||
fi
|
||||
|
||||
add_copy_notice() {
|
||||
echo "$(printf '/*
|
||||
* This file has been %s from the cddl-gen submodule.
|
||||
* This file has been %s from the zcbor library.
|
||||
* Commit %s
|
||||
*/
|
||||
|
||||
' "$2" "$(git -C ../../../ext/cddl-gen rev-parse HEAD)"; cat $1;)" > $1
|
||||
' "$2" "$(zcbor --version)"; cat $1;)" > $1
|
||||
}
|
||||
|
||||
echo "Copying cbor_decode.c|h"
|
||||
echo "Copying zcbor_decode.c|h"
|
||||
copy_with_copy_notice() {
|
||||
cp $1 $2
|
||||
add_copy_notice $2 "copied"
|
||||
}
|
||||
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_decode.c cbor_decode.c
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_encode.c cbor_encode.c
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/src/cbor_common.c cbor_common.c
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_decode.h cbor_decode.h
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_encode.h cbor_encode.h
|
||||
copy_with_copy_notice ../../../ext/cddl-gen/include/cbor_common.h cbor_common.h
|
||||
|
||||
echo "Generating serial_recovery_cbor.c|h"
|
||||
python3 ../../../ext/cddl-gen/cddl_gen/cddl_gen.py -c serial_recovery.cddl code -d -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header
|
||||
zcbor -c serial_recovery.cddl code -d -t Upload --oc serial_recovery_cbor.c --oh serial_recovery_cbor.h --time-header --copy-sources
|
||||
|
||||
add_copyright() {
|
||||
echo "$(printf '/*
|
||||
|
@ -44,6 +38,10 @@ echo "$(printf '/*
|
|||
|
||||
add_copyright serial_recovery_cbor.c "$1"
|
||||
add_copyright serial_recovery_cbor.h "$1"
|
||||
add_copy_notice serial_recovery_cbor.c "generated"
|
||||
add_copy_notice serial_recovery_cbor.h "generated"
|
||||
add_copy_notice types_serial_recovery_cbor.h "generated"
|
||||
add_copyright serial_recovery_cbor_types.h "$1"
|
||||
add_copy_notice zcbor_decode.c "copied"
|
||||
add_copy_notice zcbor_encode.c "copied"
|
||||
add_copy_notice zcbor_common.c "copied"
|
||||
add_copy_notice zcbor_decode.h "copied"
|
||||
add_copy_notice zcbor_encode.h "copied"
|
||||
add_copy_notice zcbor_common.h "copied"
|
||||
|
|
|
@ -1,25 +1,21 @@
|
|||
/*
|
||||
* This file has been generated from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
|
||||
* at: 2021-08-02 17:09:42
|
||||
* Generated with a default_max_qty of 3
|
||||
* Generated using zcbor version 0.4.0
|
||||
* https://github.com/NordicSemiconductor/zcbor
|
||||
* at: 2022-03-31 12:37:11
|
||||
* Generated with a --default-max-qty of 3
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cbor_decode.h"
|
||||
#include "zcbor_decode.h"
|
||||
#include "serial_recovery_cbor.h"
|
||||
|
||||
#if DEFAULT_MAX_QTY != 3
|
||||
|
@ -28,67 +24,76 @@
|
|||
|
||||
|
||||
static bool decode_Member(
|
||||
cbor_state_t *state, struct Member_ *result)
|
||||
zcbor_state_t *state, struct Member_ *result)
|
||||
{
|
||||
cbor_print("%s\n", __func__);
|
||||
cbor_string_type_t tmp_str;
|
||||
zcbor_print("%s\r\n", __func__);
|
||||
struct zcbor_string tmp_str;
|
||||
bool int_res;
|
||||
|
||||
bool tmp_result = (((union_start_code(state) && (int_res = (((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"image",
|
||||
tmp_str.len = sizeof("image") - 1, &tmp_str)))))
|
||||
&& (intx32_decode(state, (&(*result)._Member_image)))) && (((*result)._Member_choice = _Member_image) || 1))
|
||||
|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"data",
|
||||
tmp_str.len = sizeof("data") - 1, &tmp_str)))))
|
||||
&& (bstrx_decode(state, (&(*result)._Member_data)))) && (((*result)._Member_choice = _Member_data) || 1)))
|
||||
|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"len",
|
||||
tmp_str.len = sizeof("len") - 1, &tmp_str)))))
|
||||
&& (intx32_decode(state, (&(*result)._Member_len)))) && (((*result)._Member_choice = _Member_len) || 1)))
|
||||
|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"off",
|
||||
tmp_str.len = sizeof("off") - 1, &tmp_str)))))
|
||||
&& (intx32_decode(state, (&(*result)._Member_off)))) && (((*result)._Member_choice = _Member_off) || 1)))
|
||||
|| (union_elem_code(state) && ((((tstrx_expect(state, ((tmp_str.value = (const uint8_t *)"sha",
|
||||
tmp_str.len = sizeof("sha") - 1, &tmp_str)))))
|
||||
&& (bstrx_decode(state, (&(*result)._Member_sha)))) && (((*result)._Member_choice = _Member_sha) || 1)))), union_end_code(state), int_res))));
|
||||
bool tmp_result = (((zcbor_union_start_code(state) && (int_res = (((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"image", tmp_str.len = sizeof("image") - 1, &tmp_str)))))
|
||||
&& (zcbor_int32_decode(state, (&(*result)._Member_image)))) && (((*result)._Member_choice = _Member_image) || 1))
|
||||
|| (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"data", tmp_str.len = sizeof("data") - 1, &tmp_str)))))
|
||||
&& (zcbor_bstr_decode(state, (&(*result)._Member_data)))) && (((*result)._Member_choice = _Member_data) || 1)))
|
||||
|| (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"len", tmp_str.len = sizeof("len") - 1, &tmp_str)))))
|
||||
&& (zcbor_int32_decode(state, (&(*result)._Member_len)))) && (((*result)._Member_choice = _Member_len) || 1)))
|
||||
|| (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"off", tmp_str.len = sizeof("off") - 1, &tmp_str)))))
|
||||
&& (zcbor_int32_decode(state, (&(*result)._Member_off)))) && (((*result)._Member_choice = _Member_off) || 1)))
|
||||
|| (zcbor_union_elem_code(state) && ((((zcbor_tstr_expect(state, ((tmp_str.value = (uint8_t *)"sha", tmp_str.len = sizeof("sha") - 1, &tmp_str)))))
|
||||
&& (zcbor_bstr_decode(state, (&(*result)._Member_sha)))) && (((*result)._Member_choice = _Member_sha) || 1)))), zcbor_union_end_code(state), int_res))));
|
||||
|
||||
if (!tmp_result)
|
||||
cbor_trace();
|
||||
zcbor_trace();
|
||||
|
||||
return tmp_result;
|
||||
}
|
||||
|
||||
static bool decode_repeated_Upload_members(
|
||||
zcbor_state_t *state, struct Upload_members *result)
|
||||
{
|
||||
zcbor_print("%s\r\n", __func__);
|
||||
|
||||
bool tmp_result = (((decode_Member(state, (&(*result)._Upload_members)))));
|
||||
|
||||
if (!tmp_result)
|
||||
zcbor_trace();
|
||||
|
||||
return tmp_result;
|
||||
}
|
||||
|
||||
static bool decode_Upload(
|
||||
cbor_state_t *state, struct Upload *result)
|
||||
zcbor_state_t *state, struct Upload *result)
|
||||
{
|
||||
cbor_print("%s\n", __func__);
|
||||
bool int_res;
|
||||
zcbor_print("%s\r\n", __func__);
|
||||
|
||||
bool tmp_result = (((map_start_decode(state) && (int_res = (multi_decode(1, 5, &(*result)._Upload_members_count, (void *)decode_Member, state, (&(*result)._Upload_members), sizeof(struct Member_))), ((map_end_decode(state)) && int_res)))));
|
||||
bool tmp_result = (((zcbor_map_start_decode(state) && ((zcbor_multi_decode(1, 5, &(*result)._Upload_members_count, (zcbor_decoder_t *)decode_repeated_Upload_members, state, (&(*result)._Upload_members), sizeof(struct Upload_members))) || (zcbor_list_map_end_force_decode(state), false)) && zcbor_map_end_decode(state))));
|
||||
|
||||
if (!tmp_result)
|
||||
cbor_trace();
|
||||
zcbor_trace();
|
||||
|
||||
return tmp_result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
__attribute__((unused)) static bool type_test_decode_Upload(
|
||||
struct Upload *result)
|
||||
{
|
||||
/* This function should not be called, it is present only to test that
|
||||
* the types of the function and struct match, since this information
|
||||
* is lost with the casts in the entry function.
|
||||
*/
|
||||
return decode_Upload(NULL, result);
|
||||
}
|
||||
|
||||
|
||||
bool cbor_decode_Upload(
|
||||
const uint8_t *payload, uint32_t payload_len,
|
||||
int cbor_decode_Upload(
|
||||
const uint8_t *payload, size_t payload_len,
|
||||
struct Upload *result,
|
||||
uint32_t *payload_len_out)
|
||||
size_t *payload_len_out)
|
||||
{
|
||||
return entry_function(payload, payload_len, (const void *)result,
|
||||
payload_len_out, (void *)decode_Upload,
|
||||
1, 2);
|
||||
zcbor_state_t states[4];
|
||||
|
||||
zcbor_new_state(states, sizeof(states) / sizeof(zcbor_state_t), payload, payload_len, 1);
|
||||
|
||||
bool ret = decode_Upload(states, result);
|
||||
|
||||
if (ret && (payload_len_out != NULL)) {
|
||||
*payload_len_out = MIN(payload_len,
|
||||
(size_t)states[0].payload - (size_t)payload);
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
int ret = zcbor_pop_error(states);
|
||||
return (ret == ZCBOR_SUCCESS) ? ZCBOR_ERR_UNKNOWN : ret;
|
||||
}
|
||||
return ZCBOR_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
/*
|
||||
* This file has been generated from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
|
||||
* at: 2021-08-02 17:09:42
|
||||
* Generated with a default_max_qty of 3
|
||||
* Generated using zcbor version 0.4.0
|
||||
* https://github.com/NordicSemiconductor/zcbor
|
||||
* at: 2022-03-31 12:37:11
|
||||
* Generated with a --default-max-qty of 3
|
||||
*/
|
||||
|
||||
#ifndef SERIAL_RECOVERY_CBOR_H__
|
||||
|
@ -22,18 +18,18 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cbor_decode.h"
|
||||
#include "types_serial_recovery_cbor.h"
|
||||
#include "zcbor_decode.h"
|
||||
#include "serial_recovery_cbor_types.h"
|
||||
|
||||
#if DEFAULT_MAX_QTY != 3
|
||||
#error "The type file was generated with a different default_max_qty than this file"
|
||||
#endif
|
||||
|
||||
|
||||
bool cbor_decode_Upload(
|
||||
const uint8_t *payload, uint32_t payload_len,
|
||||
int cbor_decode_Upload(
|
||||
const uint8_t *payload, size_t payload_len,
|
||||
struct Upload *result,
|
||||
uint32_t *payload_len_out);
|
||||
size_t *payload_len_out);
|
||||
|
||||
|
||||
#endif /* SERIAL_RECOVERY_CBOR_H__ */
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generated using zcbor version 0.4.0
|
||||
* https://github.com/NordicSemiconductor/zcbor
|
||||
* at: 2022-03-31 12:37:11
|
||||
* Generated with a --default-max-qty of 3
|
||||
*/
|
||||
|
||||
#ifndef SERIAL_RECOVERY_CBOR_TYPES_H__
|
||||
#define SERIAL_RECOVERY_CBOR_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "zcbor_decode.h"
|
||||
|
||||
/** Which value for --default-max-qty this file was created with.
|
||||
*
|
||||
* The define is used in the other generated file to do a build-time
|
||||
* compatibility check.
|
||||
*
|
||||
* See `zcbor --help` for more information about --default-max-qty
|
||||
*/
|
||||
#define DEFAULT_MAX_QTY 3
|
||||
|
||||
struct Member_ {
|
||||
union {
|
||||
struct {
|
||||
int32_t _Member_image;
|
||||
};
|
||||
struct {
|
||||
struct zcbor_string _Member_data;
|
||||
};
|
||||
struct {
|
||||
int32_t _Member_len;
|
||||
};
|
||||
struct {
|
||||
int32_t _Member_off;
|
||||
};
|
||||
struct {
|
||||
struct zcbor_string _Member_sha;
|
||||
};
|
||||
};
|
||||
enum {
|
||||
_Member_image,
|
||||
_Member_data,
|
||||
_Member_len,
|
||||
_Member_off,
|
||||
_Member_sha,
|
||||
} _Member_choice;
|
||||
};
|
||||
|
||||
struct Upload_members {
|
||||
struct Member_ _Upload_members;
|
||||
};
|
||||
|
||||
struct Upload {
|
||||
struct Upload_members _Upload_members[5];
|
||||
uint_fast32_t _Upload_members_count;
|
||||
};
|
||||
|
||||
|
||||
#endif /* SERIAL_RECOVERY_CBOR_TYPES_H__ */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* This file has been generated from the cddl-gen submodule.
|
||||
* Commit 9f77837f9950da1633d22abf6181a830521a6688
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generated with cddl_gen.py (https://github.com/NordicSemiconductor/cddl-gen)
|
||||
* at: 2021-08-02 17:09:42
|
||||
* Generated with a default_max_qty of 3
|
||||
*/
|
||||
|
||||
#ifndef TYPES_SERIAL_RECOVERY_CBOR_H__
|
||||
#define TYPES_SERIAL_RECOVERY_CBOR_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "cbor_decode.h"
|
||||
|
||||
#define DEFAULT_MAX_QTY 3
|
||||
|
||||
struct Member_ {
|
||||
union {
|
||||
struct {
|
||||
int32_t _Member_image;
|
||||
};
|
||||
struct {
|
||||
cbor_string_type_t _Member_data;
|
||||
};
|
||||
struct {
|
||||
int32_t _Member_len;
|
||||
};
|
||||
struct {
|
||||
int32_t _Member_off;
|
||||
};
|
||||
struct {
|
||||
cbor_string_type_t _Member_sha;
|
||||
};
|
||||
};
|
||||
enum {
|
||||
_Member_image,
|
||||
_Member_data,
|
||||
_Member_len,
|
||||
_Member_off,
|
||||
_Member_sha,
|
||||
} _Member_choice;
|
||||
};
|
||||
|
||||
struct Upload {
|
||||
struct Member_ _Upload_members[5];
|
||||
uint32_t _Upload_members_count;
|
||||
};
|
||||
|
||||
|
||||
#endif /* TYPES_SERIAL_RECOVERY_CBOR_H__ */
|
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "zcbor_common.h"
|
||||
|
||||
_Static_assert((sizeof(size_t) == sizeof(void *)),
|
||||
"This code needs size_t to be the same length as pointers.");
|
||||
|
||||
_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)
|
||||
{
|
||||
ZCBOR_CHECK_ERROR();
|
||||
|
||||
if ((state->constant_state->current_backup)
|
||||
>= state->constant_state->num_backups) {
|
||||
ZCBOR_ERR(ZCBOR_ERR_NO_BACKUP_MEM);
|
||||
}
|
||||
|
||||
state->payload_moved = false;
|
||||
|
||||
(state->constant_state->current_backup)++;
|
||||
|
||||
/* 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;
|
||||
|
||||
memcpy(&state->constant_state->backup_list[i], state,
|
||||
sizeof(zcbor_state_t));
|
||||
|
||||
state->elem_count = new_elem_count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags,
|
||||
uint_fast32_t max_elem_count)
|
||||
{
|
||||
const uint8_t *payload = state->payload;
|
||||
const uint_fast32_t elem_count = state->elem_count;
|
||||
|
||||
ZCBOR_CHECK_ERROR();
|
||||
|
||||
if (state->constant_state->current_backup == 0) {
|
||||
zcbor_print("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;
|
||||
|
||||
if (!(flags & ZCBOR_FLAG_TRANSFER_PAYLOAD)) {
|
||||
if (state->constant_state->backup_list[i].payload_moved) {
|
||||
zcbor_print("Payload pointer out of date.\r\n");
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
}
|
||||
memcpy(state, &state->constant_state->backup_list[i],
|
||||
sizeof(zcbor_state_t));
|
||||
}
|
||||
|
||||
if (flags & ZCBOR_FLAG_CONSUME) {
|
||||
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);
|
||||
ZCBOR_ERR(ZCBOR_ERR_HIGH_ELEM_COUNT);
|
||||
}
|
||||
|
||||
if (flags & ZCBOR_FLAG_TRANSFER_PAYLOAD) {
|
||||
state->payload = payload;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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++) {
|
||||
state->constant_state->backup_list[i].payload_end = new_payload_end;
|
||||
state->constant_state->backup_list[i].payload_moved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_union_start_code(zcbor_state_t *state)
|
||||
{
|
||||
if (!zcbor_new_backup(state, state->elem_count)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_union_elem_code(zcbor_state_t *state)
|
||||
{
|
||||
if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE, state->elem_count)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zcbor_union_end_code(zcbor_state_t *state)
|
||||
{
|
||||
if (!zcbor_process_backup(state, ZCBOR_FLAG_CONSUME, state->elem_count)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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)
|
||||
{
|
||||
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].constant_state = NULL;
|
||||
|
||||
if(n_states < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Use the last state as a struct zcbor_state_constant object. */
|
||||
state_array[0].constant_state = (struct zcbor_state_constant *)&state_array[n_states - 1];
|
||||
state_array[0].constant_state->backup_list = NULL;
|
||||
state_array[0].constant_state->num_backups = n_states - 2;
|
||||
state_array[0].constant_state->current_backup = 0;
|
||||
state_array[0].constant_state->error = ZCBOR_SUCCESS;
|
||||
#ifdef ZCBOR_STOP_ON_ERROR
|
||||
state_array[0].constant_state->stop_on_error = false;
|
||||
#endif
|
||||
if (n_states > 2) {
|
||||
state_array[0].constant_state->backup_list = &state_array[1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void zcbor_update_state(zcbor_state_t *state,
|
||||
const uint8_t *payload, size_t payload_len)
|
||||
{
|
||||
state->payload = payload;
|
||||
state->payload_end = payload + payload_len;
|
||||
|
||||
update_backups(state, state->payload_end);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments,
|
||||
uint_fast32_t num_fragments)
|
||||
{
|
||||
size_t total_len = 0;
|
||||
|
||||
if (fragments == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint_fast32_t i = 0; i < num_fragments; i++) {
|
||||
if (fragments[i].offset != total_len) {
|
||||
return false;
|
||||
}
|
||||
if (fragments[i].fragment.value == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (fragments[i].total_len != fragments[0].total_len) {
|
||||
return false;
|
||||
}
|
||||
total_len += fragments[i].fragment.len;
|
||||
if (total_len > fragments[0].total_len) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_fragments && total_len != fragments[0].total_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_fragments && (fragments[0].total_len == ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH)) {
|
||||
for (uint_fast32_t i = 0; i < num_fragments; i++) {
|
||||
fragments[i].total_len = total_len;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zcbor_splice_string_fragments(struct zcbor_string_fragment *fragments,
|
||||
uint_fast32_t num_fragments, uint8_t *result, size_t *result_len)
|
||||
{
|
||||
size_t total_len = 0;
|
||||
|
||||
if (!fragments) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint_fast32_t i = 0; i < num_fragments; i++) {
|
||||
if ((total_len > *result_len)
|
||||
|| (fragments[i].fragment.len > (*result_len - total_len))) {
|
||||
return false;
|
||||
}
|
||||
memcpy(&result[total_len],
|
||||
fragments[i].fragment.value, fragments[i].fragment.len);
|
||||
total_len += fragments[i].fragment.len;
|
||||
}
|
||||
|
||||
*result_len = total_len;
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZCBOR_COMMON_H__
|
||||
#define ZCBOR_COMMON_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/** Convenience type that allows pointing to strings directly inside the payload
|
||||
* without the need to copy out.
|
||||
*/
|
||||
struct zcbor_string {
|
||||
const uint8_t *value;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
||||
/** Type representing a string fragment.
|
||||
*
|
||||
* Don't modify any member variables, or subsequent calls may fail.
|
||||
**/
|
||||
struct zcbor_string_fragment {
|
||||
struct zcbor_string fragment; ///! Location and length of the fragment.
|
||||
size_t offset; ///! The offset in the full string at which this fragment belongs.
|
||||
size_t total_len; ///! The total length of the string this fragment is a part of.
|
||||
};
|
||||
|
||||
|
||||
/** 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 <sys/printk.h>
|
||||
#define zcbor_trace() (printk("bytes left: %zu, byte: 0x%x, elem_count: 0x%" PRIxFAST32 ", %s:%d\n",\
|
||||
(size_t)state->payload_end - (size_t)state->payload, *state->payload, \
|
||||
state->elem_count, __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)
|
||||
#else
|
||||
#define zcbor_assert(expr, ...)
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
|
||||
struct zcbor_state_constant;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t *payload_mut;
|
||||
uint8_t const *payload; /**< The current place in the payload. Will be
|
||||
updated when an element is correctly
|
||||
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. */
|
||||
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. */
|
||||
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;
|
||||
int error;
|
||||
#ifdef ZCBOR_STOP_ON_ERROR
|
||||
bool stop_on_error;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Function pointer type used with zcbor_multi_decode.
|
||||
*
|
||||
* This type is compatible with all decoding functions here and in the generated
|
||||
* code, except for zcbor_multi_decode.
|
||||
*/
|
||||
typedef bool(zcbor_encoder_t)(zcbor_state_t *, const void *);
|
||||
typedef bool(zcbor_decoder_t)(zcbor_state_t *, void *);
|
||||
|
||||
/** Enumeration representing the major types available in CBOR.
|
||||
*
|
||||
* The major type is represented in the 3 first bits of the header byte.
|
||||
*/
|
||||
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_t;
|
||||
|
||||
|
||||
/** Convenience macro for failing out of a decoding/encoding function.
|
||||
*/
|
||||
#define ZCBOR_FAIL() \
|
||||
do {\
|
||||
zcbor_trace(); \
|
||||
return false; \
|
||||
} while(0)
|
||||
|
||||
#define ZCBOR_ERR(err) \
|
||||
do { \
|
||||
zcbor_error(state, err); \
|
||||
ZCBOR_FAIL(); \
|
||||
} while(0)
|
||||
|
||||
#define ZCBOR_ERR_IF(expr, err) \
|
||||
do {\
|
||||
if (expr) { \
|
||||
ZCBOR_ERR(err); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ZCBOR_CHECK_PAYLOAD() \
|
||||
ZCBOR_ERR_IF(state->payload >= state->payload_end, ZCBOR_ERR_NO_PAYLOAD)
|
||||
|
||||
#ifdef ZCBOR_STOP_ON_ERROR
|
||||
#define ZCBOR_CHECK_ERROR() \
|
||||
do { \
|
||||
if (!zcbor_check_error(state)) { \
|
||||
ZCBOR_FAIL(); \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define ZCBOR_CHECK_ERROR()
|
||||
#endif
|
||||
|
||||
#define ZCBOR_VALUE_IN_HEADER 23 ///! Values below this are encoded directly in the header.
|
||||
#define ZCBOR_VALUE_IS_1_BYTE 24 ///! The next 1 byte contains the value.
|
||||
#define ZCBOR_VALUE_IS_2_BYTES 25 ///! The next 2 bytes contain the value.
|
||||
#define ZCBOR_VALUE_IS_4_BYTES 26 ///! The next 4 bytes contain the value.
|
||||
#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_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_SUCCESS 0
|
||||
#define ZCBOR_ERR_NO_BACKUP_MEM 1
|
||||
#define ZCBOR_ERR_NO_BACKUP_ACTIVE 2
|
||||
#define ZCBOR_ERR_LOW_ELEM_COUNT 3
|
||||
#define ZCBOR_ERR_HIGH_ELEM_COUNT 4
|
||||
#define ZCBOR_ERR_INT_SIZE 5
|
||||
#define ZCBOR_ERR_FLOAT_SIZE 6
|
||||
#define ZCBOR_ERR_ADDITIONAL_INVAL 7 ///! > 27
|
||||
#define ZCBOR_ERR_NO_PAYLOAD 8
|
||||
#define ZCBOR_ERR_PAYLOAD_NOT_CONSUMED 9
|
||||
#define ZCBOR_ERR_WRONG_TYPE 10
|
||||
#define ZCBOR_ERR_WRONG_VALUE 11
|
||||
#define ZCBOR_ERR_WRONG_RANGE 12
|
||||
#define ZCBOR_ERR_ITERATIONS 13
|
||||
#define ZCBOR_ERR_ASSERTION 14
|
||||
#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
|
||||
|
||||
/** 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
|
||||
};
|
||||
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Convenience function for starting encoding/decoding of a union.
|
||||
*
|
||||
* That is, for attempting to encode, or especially decode, multiple options.
|
||||
* Makes a new backup.
|
||||
*/
|
||||
bool zcbor_union_start_code(zcbor_state_t *state);
|
||||
|
||||
/** Convenience function before encoding/decoding one element of a union.
|
||||
*
|
||||
* Call this before attempting each option.
|
||||
* Restores the backup, without consuming it.
|
||||
*/
|
||||
bool zcbor_union_elem_code(zcbor_state_t *state);
|
||||
|
||||
/** Convenience function before encoding/decoding one element of a union.
|
||||
*
|
||||
* Consumes the backup without restoring it.
|
||||
*/
|
||||
bool zcbor_union_end_code(zcbor_state_t *state);
|
||||
|
||||
/** Initialize a state with backups.
|
||||
* One of the states in the array is used as a struct zcbor_state_constant object.
|
||||
* This means that you get a state with (n_states - 2) backups.
|
||||
* The constant state is mandatory so n_states must be at least 2.
|
||||
* 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.
|
||||
*
|
||||
* @retval false if n_states < 2
|
||||
* @retval true otherwise
|
||||
*/
|
||||
bool 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);
|
||||
|
||||
#ifdef ZCBOR_STOP_ON_ERROR
|
||||
/** Check stored error and fail if present, but only if stop_on_error is true. */
|
||||
static inline bool zcbor_check_error(const zcbor_state_t *state)
|
||||
{
|
||||
return !(state->constant_state->stop_on_error && state->constant_state->error);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Return the current error state, replacing it with SUCCESS. */
|
||||
static inline int zcbor_pop_error(zcbor_state_t *state)
|
||||
{
|
||||
int err = state->constant_state->error;
|
||||
|
||||
state->constant_state->error = ZCBOR_SUCCESS;
|
||||
return err;
|
||||
}
|
||||
|
||||
/** Write the provided error to the error state. */
|
||||
static inline void zcbor_error(zcbor_state_t *state, int err)
|
||||
{
|
||||
#ifdef ZCBOR_STOP_ON_ERROR
|
||||
if (zcbor_check_error(state))
|
||||
#endif
|
||||
{
|
||||
state->constant_state->error = err;
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether the current payload is exhausted. */
|
||||
static inline bool zcbor_payload_at_end(const zcbor_state_t *state)
|
||||
{
|
||||
return (state->payload == state->payload_end);
|
||||
}
|
||||
|
||||
/** Update the current payload pointer (and payload_end).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param[inout] state The current state, will be updated with
|
||||
* the new payload pointer.
|
||||
* @param[in] payload The new payload chunk.
|
||||
* @param[in] payload_len The length of the new payload chunk.
|
||||
*/
|
||||
void zcbor_update_state(zcbor_state_t *state,
|
||||
const uint8_t *payload, size_t payload_len);
|
||||
|
||||
/** Check that the provided fragments are complete and in the right order.
|
||||
*
|
||||
* If the total length is not known, the total_len can have the value
|
||||
* @ref ZCBOR_STRING_FRAGMENT_UNKNOWN_LENGTH. If so, all fragments will be
|
||||
* updated with the actual total length.
|
||||
*
|
||||
* @param[in] fragments An array of string fragments. Cannot be NULL.
|
||||
* @param[in] num_fragments The number of fragments in @p fragments.
|
||||
*
|
||||
* @retval true If the fragments are in the right order, and there are no
|
||||
* fragments missing.
|
||||
* @retval false If not all fragments have the same total_len, or gaps are
|
||||
* found, or if any fragment value is NULL.
|
||||
*/
|
||||
bool zcbor_validate_string_fragments(struct zcbor_string_fragment *fragments,
|
||||
uint_fast32_t num_fragments);
|
||||
|
||||
/** Assemble the fragments into a single string.
|
||||
*
|
||||
* The fragments are copied in the order they appear, without regard for
|
||||
* offset or total_len. To ensure that the fragments are correct, first
|
||||
* validate with @ref zcbor_validate_string_fragments.
|
||||
*
|
||||
* @param[in] fragments An array of string fragments. Cannot be NULL.
|
||||
* @param[in] num_fragments The number of fragments in @p fragments.
|
||||
* @param[out] result The buffer to place the assembled string into.
|
||||
* @param[inout] result_len In: The length of the @p result.
|
||||
* Out: The length of the assembled string.
|
||||
*
|
||||
* @retval true On success.
|
||||
* @retval false If the assembled string would be larger than the buffer.
|
||||
* 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);
|
||||
|
||||
#endif /* ZCBOR_COMMON_H__ */
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZCBOR_DEBUG_H__
|
||||
#define ZCBOR_DEBUG_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "zcbor_common.h"
|
||||
|
||||
__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");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* ZCBOR_DEBUG_H__ */
|
|
@ -0,0 +1,919 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "zcbor_decode.h"
|
||||
#include "zcbor_common.h"
|
||||
|
||||
|
||||
/** Return value length from additional value.
|
||||
*/
|
||||
static uint_fast32_t additional_len(uint8_t additional)
|
||||
{
|
||||
if (ZCBOR_VALUE_IS_1_BYTE <= additional && additional <= ZCBOR_VALUE_IS_8_BYTES) {
|
||||
/* 24 => 1
|
||||
* 25 => 2
|
||||
* 26 => 4
|
||||
* 27 => 8
|
||||
*/
|
||||
return 1U << (additional - ZCBOR_VALUE_IS_1_BYTE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Extract the major type, i.e. the first 3 bits of the header byte. */
|
||||
#define MAJOR_TYPE(header_byte) (((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)
|
||||
{
|
||||
ZCBOR_CHECK_ERROR();
|
||||
ZCBOR_CHECK_PAYLOAD();
|
||||
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);
|
||||
|
||||
if (major_type != exp_major_type) {
|
||||
ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define INITIAL_CHECKS() \
|
||||
do {\
|
||||
if (!initial_checks(state)) { \
|
||||
ZCBOR_FAIL(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define INITIAL_CHECKS_WITH_TYPE(exp_major_type) \
|
||||
do {\
|
||||
if (!type_check(state, exp_major_type)) { \
|
||||
ZCBOR_FAIL(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ERR_RESTORE(err) \
|
||||
do { \
|
||||
state->payload = state->payload_bak; \
|
||||
state->elem_count++; \
|
||||
ZCBOR_ERR(err); \
|
||||
} while(0)
|
||||
|
||||
#define FAIL_RESTORE() \
|
||||
do { \
|
||||
state->payload = state->payload_bak; \
|
||||
state->elem_count++; \
|
||||
ZCBOR_FAIL(); \
|
||||
} while(0)
|
||||
|
||||
/** Get a single value.
|
||||
*
|
||||
* @details @p ppayload must point to the header byte. This function will
|
||||
* retrieve the value (either from within the additional info, or from
|
||||
* the subsequent bytes) and return it in the result. The result can
|
||||
* have arbitrary length.
|
||||
*
|
||||
* The function will also validate
|
||||
* - Min/max constraints on the value.
|
||||
* - That @p payload doesn't overrun past @p payload_end.
|
||||
* - That @p elem_count has not been exhausted.
|
||||
*
|
||||
* @p ppayload and @p elem_count are updated if the function
|
||||
* 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).
|
||||
*/
|
||||
static bool value_extract(zcbor_state_t *state,
|
||||
void *const result, uint_fast32_t result_len)
|
||||
{
|
||||
zcbor_trace();
|
||||
zcbor_assert(result_len != 0, "0-length result not supported.\r\n");
|
||||
zcbor_assert(result != NULL, NULL);
|
||||
|
||||
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);
|
||||
|
||||
state->payload_bak = state->payload;
|
||||
(state->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 */
|
||||
|
||||
(state->payload) += len;
|
||||
}
|
||||
|
||||
(state->elem_count)--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int32_decode(zcbor_state_t *state, int32_t *result)
|
||||
{
|
||||
int64_t result64;
|
||||
|
||||
if (zcbor_int64_decode(state, &result64)) {
|
||||
if (result64 > INT32_MAX) {
|
||||
ERR_RESTORE(ZCBOR_ERR_INT_SIZE);
|
||||
}
|
||||
*result = (int32_t)result64;
|
||||
return true;
|
||||
} else {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int64_decode(zcbor_state_t *state, int64_t *result)
|
||||
{
|
||||
INITIAL_CHECKS();
|
||||
uint8_t major_type = MAJOR_TYPE(*state->payload);
|
||||
uint64_t uint_result;
|
||||
int64_t int_result;
|
||||
|
||||
if (major_type != ZCBOR_MAJOR_TYPE_PINT
|
||||
&& major_type != ZCBOR_MAJOR_TYPE_NINT) {
|
||||
/* Value to be read doesn't have the right type. */
|
||||
ZCBOR_ERR(ZCBOR_ERR_WRONG_TYPE);
|
||||
}
|
||||
|
||||
if (!value_extract(state, &uint_result, sizeof(uint_result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
zcbor_print("uintval: %" PRIu64 "\r\n", uint_result);
|
||||
|
||||
int_result = (int64_t)uint_result;
|
||||
|
||||
if (int_result < 0) {
|
||||
/* Value is too large to fit in a signed integer. */
|
||||
ERR_RESTORE(ZCBOR_ERR_INT_SIZE);
|
||||
}
|
||||
|
||||
if (major_type == ZCBOR_MAJOR_TYPE_NINT) {
|
||||
/* Convert from CBOR's representation. */
|
||||
*result = -1 - int_result;
|
||||
} else {
|
||||
*result = int_result;
|
||||
}
|
||||
|
||||
zcbor_print("val: %" PRIi64 "\r\n", *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint32_decode(zcbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT);
|
||||
|
||||
if (!value_extract(state, result, sizeof(*result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint32_expect_union(zcbor_state_t *state, uint32_t result)
|
||||
{
|
||||
zcbor_union_elem_code(state);
|
||||
return zcbor_uint32_expect(state, result);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint64_expect_union(zcbor_state_t *state, uint64_t result)
|
||||
{
|
||||
zcbor_union_elem_code(state);
|
||||
return zcbor_uint64_expect(state, result);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int32_expect(zcbor_state_t *state, int32_t result)
|
||||
{
|
||||
return zcbor_int64_expect(state, result);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int64_expect(zcbor_state_t *state, int64_t result)
|
||||
{
|
||||
int64_t value;
|
||||
|
||||
if (!zcbor_int64_decode(state, &value)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
if (value != result) {
|
||||
zcbor_print("%" PRIi64 " != %" PRIi64 "\r\n", value, result);
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint64_decode(zcbor_state_t *state, uint64_t *result)
|
||||
{
|
||||
INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PINT);
|
||||
|
||||
if (!value_extract(state, result, sizeof(*result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint32_expect(zcbor_state_t *state, uint32_t result)
|
||||
{
|
||||
return zcbor_uint64_expect(state, result);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint64_expect(zcbor_state_t *state, uint64_t result)
|
||||
{
|
||||
uint64_t value;
|
||||
|
||||
if (!zcbor_uint64_decode(state, &value)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
zcbor_print("%" PRIu64 " != %" PRIu64 "\r\n", value, result);
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool str_start_decode(zcbor_state_t *state,
|
||||
struct zcbor_string *result, zcbor_major_type_t exp_major_type)
|
||||
{
|
||||
INITIAL_CHECKS_WITH_TYPE(exp_major_type);
|
||||
|
||||
if (!value_extract(state, &result->len, sizeof(result->len))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
result->value = state->payload;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool str_overflow_check(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
if (result->len > (state->payload_end - state->payload)) {
|
||||
zcbor_print("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)
|
||||
{
|
||||
if (result == NULL) {
|
||||
struct zcbor_string dummy;
|
||||
result = &dummy;
|
||||
}
|
||||
|
||||
if(!str_start_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
if (!str_overflow_check(state, result)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
state->payload_end = result->value + result->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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_MAX_ELEM_COUNT)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void partition_fragment(const zcbor_state_t *state,
|
||||
struct zcbor_string_fragment *result)
|
||||
{
|
||||
result->fragment.len = MIN(result->fragment.len,
|
||||
(size_t)state->payload_end - (size_t)state->payload);
|
||||
}
|
||||
|
||||
|
||||
static bool start_decode_fragment(zcbor_state_t *state,
|
||||
struct zcbor_string_fragment *result,
|
||||
zcbor_major_type_t exp_major_type)
|
||||
{
|
||||
if(!str_start_decode(state, &result->fragment, exp_major_type)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
result->offset = 0;
|
||||
result->total_len = result->fragment.len;
|
||||
partition_fragment(state, result);
|
||||
state->payload_end = state->payload + result->fragment.len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state,
|
||||
struct zcbor_string_fragment *result)
|
||||
{
|
||||
if (!start_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void zcbor_next_fragment(zcbor_state_t *state,
|
||||
struct zcbor_string_fragment *prev_fragment,
|
||||
struct zcbor_string_fragment *result)
|
||||
{
|
||||
memcpy(result, prev_fragment, sizeof(*result));
|
||||
result->fragment.value = state->payload_mut;
|
||||
result->offset += prev_fragment->fragment.len;
|
||||
result->fragment.len = result->total_len - result->offset;
|
||||
|
||||
partition_fragment(state, result);
|
||||
zcbor_print("New fragment length %zu\r\n", result->fragment.len);
|
||||
|
||||
state->payload += result->fragment.len;
|
||||
}
|
||||
|
||||
|
||||
void zcbor_bstr_next_fragment(zcbor_state_t *state,
|
||||
struct zcbor_string_fragment *prev_fragment,
|
||||
struct zcbor_string_fragment *result)
|
||||
{
|
||||
memcpy(result, prev_fragment, sizeof(*result));
|
||||
result->fragment.value = state->payload_mut;
|
||||
result->offset += prev_fragment->fragment.len;
|
||||
result->fragment.len = result->total_len - result->offset;
|
||||
|
||||
partition_fragment(state, result);
|
||||
zcbor_print("fragment length %zu\r\n", result->fragment.len);
|
||||
state->payload_end = state->payload + result->fragment.len;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment)
|
||||
{
|
||||
return (fragment->total_len == (fragment->offset + fragment->fragment.len));
|
||||
}
|
||||
|
||||
|
||||
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)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
state->payload += result->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool str_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result,
|
||||
zcbor_major_type_t exp_major_type)
|
||||
{
|
||||
if (!start_decode_fragment(state, result, exp_major_type)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
(state->payload) += result->fragment.len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool str_expect(zcbor_state_t *state, struct zcbor_string *result,
|
||||
zcbor_major_type_t exp_major_type)
|
||||
{
|
||||
struct zcbor_string tmp_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)) {
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
return str_decode(state, result, ZCBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result)
|
||||
{
|
||||
return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
return str_expect(state, result, ZCBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
return str_decode(state, result, ZCBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result)
|
||||
{
|
||||
return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
return str_expect(state, result, ZCBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
static bool list_map_start_decode(zcbor_state_t *state,
|
||||
zcbor_major_type_t exp_major_type)
|
||||
{
|
||||
uint_fast32_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) {
|
||||
/* 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->elem_count--;
|
||||
} else {
|
||||
if (!value_extract(state, &new_elem_count, sizeof(new_elem_count))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
}
|
||||
|
||||
if (!zcbor_new_backup(state, new_elem_count)) {
|
||||
FAIL_RESTORE();
|
||||
}
|
||||
|
||||
state->indefinite_length_array = indefinite_length_array;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_list_start_decode(zcbor_state_t *state)
|
||||
{
|
||||
return list_map_start_decode(state, ZCBOR_MAJOR_TYPE_LIST);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_map_start_decode(zcbor_state_t *state)
|
||||
{
|
||||
bool ret = list_map_start_decode(state, ZCBOR_MAJOR_TYPE_MAP);
|
||||
|
||||
if (ret && !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);
|
||||
}
|
||||
state->elem_count *= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static bool array_end_expect(zcbor_state_t *state)
|
||||
{
|
||||
INITIAL_CHECKS();
|
||||
ZCBOR_ERR_IF(*state->payload != 0xFF, ZCBOR_ERR_WRONG_TYPE);
|
||||
|
||||
state->payload++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool list_map_end_decode(zcbor_state_t *state)
|
||||
{
|
||||
uint_fast32_t max_elem_count = 0;
|
||||
|
||||
if (state->indefinite_length_array) {
|
||||
if (!array_end_expect(state)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
max_elem_count = ZCBOR_MAX_ELEM_COUNT;
|
||||
state->indefinite_length_array = false;
|
||||
}
|
||||
if (!zcbor_process_backup(state,
|
||||
ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME | ZCBOR_FLAG_TRANSFER_PAYLOAD,
|
||||
max_elem_count)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_list_end_decode(zcbor_state_t *state)
|
||||
{
|
||||
return list_map_end_decode(state);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_map_end_decode(zcbor_state_t *state)
|
||||
{
|
||||
return list_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_MAX_ELEM_COUNT)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool primx_expect(zcbor_state_t *state, uint8_t result)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_PRIM);
|
||||
|
||||
if (!value_extract(state, &value, sizeof(value))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
if (value != result) {
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_nil_expect(zcbor_state_t *state, void *unused)
|
||||
{
|
||||
if (!primx_expect(state, 22)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_undefined_expect(zcbor_state_t *state, void *unused)
|
||||
{
|
||||
if (!primx_expect(state, 23)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bool_decode(zcbor_state_t *state, bool *result)
|
||||
{
|
||||
if (zcbor_bool_expect(state, false)) {
|
||||
*result = false;
|
||||
} else if (zcbor_bool_expect(state, true)) {
|
||||
*result = true;
|
||||
} else {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
zcbor_print("boolval: %u\r\n", *result);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bool_expect(zcbor_state_t *state, bool result)
|
||||
{
|
||||
if (!primx_expect(state, (uint8_t)(!!result) + ZCBOR_BOOL_TO_PRIM)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (!value_extract(state, result, sizeof(*result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float32_expect(zcbor_state_t *state, float result)
|
||||
{
|
||||
float value;
|
||||
|
||||
if (!zcbor_float32_decode(state, &value)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (!value_extract(state, result, sizeof(*result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float64_expect(zcbor_state_t *state, double result)
|
||||
{
|
||||
double value;
|
||||
|
||||
if (!zcbor_float64_decode(state, &value)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (value != result) {
|
||||
ERR_RESTORE(ZCBOR_ERR_WRONG_VALUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float_decode(zcbor_state_t *state, double *result)
|
||||
{
|
||||
float float_result;
|
||||
|
||||
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 result)
|
||||
{
|
||||
if (zcbor_float32_expect(state, (float)result)) {
|
||||
/* Do nothing */
|
||||
} else if (!zcbor_float64_expect(state, result)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_any_skip(zcbor_state_t *state, void *result)
|
||||
{
|
||||
zcbor_assert(result == NULL,
|
||||
"'any' type cannot be returned, only skipped.\r\n");
|
||||
|
||||
INITIAL_CHECKS();
|
||||
uint8_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;
|
||||
|
||||
payload_bak = state->payload;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!value_extract(state, &value, sizeof(value))) {
|
||||
/* Can happen because of elem_count (or payload_end) */
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
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;
|
||||
break;
|
||||
case ZCBOR_MAJOR_TYPE_MAP:
|
||||
value *= 2; /* Because all members have a key. */
|
||||
/* 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;
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
state->elem_count = temp_elem_count;
|
||||
break;
|
||||
default:
|
||||
/* Do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tag_decode(zcbor_state_t *state, uint32_t *result)
|
||||
{
|
||||
INITIAL_CHECKS_WITH_TYPE(ZCBOR_MAJOR_TYPE_TAG);
|
||||
|
||||
if (!value_extract(state, result, sizeof(*result))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
state->elem_count++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tag_expect(zcbor_state_t *state, uint32_t result)
|
||||
{
|
||||
uint32_t tag_val;
|
||||
|
||||
if (!zcbor_tag_decode(state, &tag_val)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (tag_val != result) {
|
||||
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,
|
||||
zcbor_decoder_t decoder,
|
||||
zcbor_state_t *state,
|
||||
void *result,
|
||||
uint_fast32_t result_len)
|
||||
{
|
||||
ZCBOR_CHECK_ERROR();
|
||||
for (uint_fast32_t i = 0; i < max_decode; i++) {
|
||||
uint8_t const *payload_bak = state->payload;
|
||||
uint_fast32_t elem_count_bak = state->elem_count;
|
||||
|
||||
if (!decoder(state,
|
||||
(uint8_t *)result + i*result_len)) {
|
||||
*num_decode = i;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
zcbor_print("Found %" PRIuFAST32 " elements.\r\n", max_decode);
|
||||
*num_decode = max_decode;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_present_decode(uint_fast32_t *present,
|
||||
zcbor_decoder_t decoder,
|
||||
zcbor_state_t *state,
|
||||
void *result)
|
||||
{
|
||||
uint_fast32_t num_decode;
|
||||
bool retval = zcbor_multi_decode(0, 1, &num_decode, decoder, state, result, 0);
|
||||
|
||||
zcbor_assert(retval, "zcbor_multi_decode should not fail with these parameters.\r\n");
|
||||
|
||||
*present = num_decode;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool 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)
|
||||
{
|
||||
return zcbor_new_state(state_array, n_states, payload, payload_len, elem_count);
|
||||
}
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZCBOR_DECODE_H__
|
||||
#define ZCBOR_DECODE_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "zcbor_common.h"
|
||||
|
||||
/** The zcbor_decode library provides functions for decoding CBOR data elements.
|
||||
*
|
||||
* See The README for an introduction to CBOR, including the meaning of pint,
|
||||
* nint, bstr etc.
|
||||
*/
|
||||
|
||||
|
||||
/** The following applies to all single-value decode functions that don't have docs.
|
||||
*
|
||||
* @param[inout] state The current state of the decoding.
|
||||
* @param[out] result Where to place the decoded value.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
/** 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);
|
||||
|
||||
/** Consume and expect a pint with a certain value, within a union.
|
||||
*
|
||||
* Calls @ref zcbor_union_elem_code then @ref zcbor_uint32_expect.
|
||||
*/
|
||||
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, uint8_t *ptr, size_t len)
|
||||
{
|
||||
return zcbor_bstr_expect(state, &(struct zcbor_string){.value = ptr, .len = len});
|
||||
}
|
||||
static inline bool zcbor_tstr_expect_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len)
|
||||
{
|
||||
return zcbor_tstr_expect(state, &(struct zcbor_string){.value = ptr, .len = len});
|
||||
}
|
||||
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Decode and consume a bstr header.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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_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);
|
||||
|
||||
/** Decode and consume a list/map header.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @retval true Header decoded correctly
|
||||
* @retval false Header decoded incorrectly, or backup failed.
|
||||
*/
|
||||
bool zcbor_list_start_decode(zcbor_state_t *state);
|
||||
bool zcbor_map_start_decode(zcbor_state_t *state);
|
||||
|
||||
/** Finalize decoding a list/map
|
||||
*
|
||||
* Check that the list/map had the correct number of elements, and restore the
|
||||
* previous element count from the backup.
|
||||
*
|
||||
* Use @ref zcbor_list_map_end_force_decode to forcibly consume the backup if
|
||||
* something has gone wrong.
|
||||
*
|
||||
* @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_list_map_end_force_decode(zcbor_state_t *state);
|
||||
|
||||
/** Decode 0 or more elements with the same type and constraints.
|
||||
*
|
||||
* The decoded values will appear consecutively in the @p result array.
|
||||
*
|
||||
* The following is an example of decoding a list containing 3 INTS followed by
|
||||
* 0 to 2 bstrs:
|
||||
*
|
||||
* @code{c}
|
||||
* uint32_t ints[3];
|
||||
* struct zcbor_string bstrs[2];
|
||||
* uint32_t num_decode;
|
||||
* bool res;
|
||||
*
|
||||
* res = zcbor_list_start_decode(state);
|
||||
* res = res && zcbor_multi_decode(3, 3, &num_decode, zcbor_uint32_decode,
|
||||
* state, ints, sizeof(ints[0]));
|
||||
* res = res && zcbor_multi_decode(0, 2, &num_decode, zcbor_bstr_decode,
|
||||
* state, bstrs, sizeof(bstrs[0]));
|
||||
* res = res && zcbor_list_end_decode(state);
|
||||
* // check res
|
||||
* @endcode
|
||||
*
|
||||
* The @ref zcbor_decoder_t type is designed to be compatible with all single-
|
||||
* value decoder functions in this library, e.g. @ref zcbor_uint32_decode,
|
||||
* @ref zcbor_tstr_expect, @ref zcbor_nil_expect, etc. For _expect() functions,
|
||||
* @p result will be used as a value instead of an array/pointer, so
|
||||
* @p result_len will determine how much the value changes for each call.
|
||||
* To decode the same value multiple times, use a @p result_len of 0.
|
||||
* This function can also be used with custom decoder functions, such as those
|
||||
* generated by the zcbor.py script, which for example decodes larger chunks of
|
||||
* the data at once.
|
||||
*
|
||||
* @param[in] min_decode The minimum acceptable number of elements.
|
||||
* @param[in] max_decode The maximum acceptable number of elements.
|
||||
* @param[out] num_decode The actual number of elements decoded.
|
||||
* @param[in] decoder The decoder function to call under the hood. This
|
||||
* function will be called with the provided arguments
|
||||
* repeatedly until the function fails (returns false)
|
||||
* or until it has been called @p max_decode times.
|
||||
* 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.
|
||||
* @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
|
||||
* length of the individual elements of @p result.
|
||||
*
|
||||
* @retval true If at least @p min_decode variables were correctly decoded.
|
||||
* @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,
|
||||
zcbor_decoder_t decoder, zcbor_state_t *state, void *result,
|
||||
uint_fast32_t result_len);
|
||||
|
||||
/** Attempt to decode a value that might not be present in the data.
|
||||
*
|
||||
* Works like @ref zcbor_multi_decode, with @p present as num_decode.
|
||||
* Will return true, even if the data is not present.
|
||||
*
|
||||
* @param[out] present Whether or not the data was present and successfully decoded.
|
||||
* @param[in] decoder The decoder to attempt.
|
||||
* @param[out] result The result, if present.
|
||||
*
|
||||
* @return Should always return true.
|
||||
*/
|
||||
bool zcbor_present_decode(uint_fast32_t *present,
|
||||
zcbor_decoder_t decoder,
|
||||
zcbor_state_t *state,
|
||||
void *result);
|
||||
|
||||
/** See @ref zcbor_new_state() */
|
||||
bool 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.
|
||||
*
|
||||
* This gives you a state variable named @p name. The variable functions like
|
||||
* a pointer.
|
||||
*
|
||||
* The return value from @ref zcbor_new_encode_state can be safely ignored
|
||||
* because the only error condition is n_states < 2, and this macro adds 2 to
|
||||
* num_backups to get n_states, so it can never be < 2.
|
||||
*
|
||||
* @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_STATE_D(name, num_backups, payload, payload_size, elem_count) \
|
||||
zcbor_state_t name[((num_backups) + 2)]; \
|
||||
do { \
|
||||
(void)zcbor_new_decode_state(name, ARRAY_SIZE(name), payload, payload_size, elem_count); \
|
||||
} while(0)
|
||||
|
||||
#endif /* ZCBOR_DECODE_H__ */
|
|
@ -0,0 +1,587 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "zcbor_encode.h"
|
||||
#include "zcbor_common.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)
|
||||
{
|
||||
switch(val) {
|
||||
case 1: return 0;
|
||||
case 2: return 1;
|
||||
case 3: return 2;
|
||||
case 4: return 2;
|
||||
case 5: return 3;
|
||||
case 6: return 3;
|
||||
case 7: return 3;
|
||||
case 8: return 3;
|
||||
}
|
||||
|
||||
zcbor_print("Should not come here.\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t get_additional(uint_fast32_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(additional < 32, NULL);
|
||||
|
||||
*(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)
|
||||
{
|
||||
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) {
|
||||
ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD);
|
||||
}
|
||||
|
||||
if (!encode_header_byte(state, major_type,
|
||||
get_additional(encoded_len, u8_result[0]))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
state->payload_mut--;
|
||||
zcbor_trace();
|
||||
state->payload_mut++;
|
||||
|
||||
#ifdef CONFIG_BIG_ENDIAN
|
||||
memcpy(state->payload_mut, u8_result, encoded_len);
|
||||
state->payload_mut += encoded_len;
|
||||
#else
|
||||
for (; encoded_len > 0; encoded_len--) {
|
||||
*(state->payload_mut++) = u8_result[encoded_len - 1];
|
||||
}
|
||||
#endif /* CONFIG_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];
|
||||
#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)
|
||||
{
|
||||
zcbor_assert(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);
|
||||
|
||||
return value_encode_len(state, major_type, result, result_len);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int32_put(zcbor_state_t *state, int32_t input)
|
||||
{
|
||||
return zcbor_int64_put(state, input);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int64_put(zcbor_state_t *state, int64_t input)
|
||||
{
|
||||
zcbor_major_type_t major_type;
|
||||
|
||||
if (input < 0) {
|
||||
major_type = ZCBOR_MAJOR_TYPE_NINT;
|
||||
/* Convert from CBOR's representation. */
|
||||
input = -1 - input;
|
||||
} else {
|
||||
major_type = ZCBOR_MAJOR_TYPE_PINT;
|
||||
input = input;
|
||||
}
|
||||
|
||||
if (!value_encode(state, major_type, &input, 8)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int32_encode(zcbor_state_t *state, const int32_t *input)
|
||||
{
|
||||
return zcbor_int32_put(state, *input);
|
||||
}
|
||||
|
||||
|
||||
static bool uint32_encode(zcbor_state_t *state, const uint32_t *input,
|
||||
zcbor_major_type_t major_type)
|
||||
{
|
||||
if (!value_encode(state, major_type, input, 4)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_int64_encode(zcbor_state_t *state, const int64_t *input)
|
||||
{
|
||||
return zcbor_int64_put(state, *input);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_uint32_put(zcbor_state_t *state, uint32_t input)
|
||||
{
|
||||
return zcbor_uint64_put(state, 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;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
> (size_t)state->payload_end)) {
|
||||
ZCBOR_ERR(ZCBOR_ERR_NO_PAYLOAD);
|
||||
}
|
||||
if (!value_encode(state, major_type, &input->len, sizeof(input->len))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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));
|
||||
|
||||
return max_len - result_len - 1;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_start_encode(zcbor_state_t *state)
|
||||
{
|
||||
if (!zcbor_new_backup(state, 0)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
uint64_t max_len = remaining_str_len(state);
|
||||
|
||||
/* Encode a dummy header */
|
||||
if (!uint64_encode(state, &max_len,
|
||||
ZCBOR_MAJOR_TYPE_BSTR)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result)
|
||||
{
|
||||
const uint8_t *payload = state->payload;
|
||||
struct zcbor_string dummy_value;
|
||||
|
||||
if (result == NULL) {
|
||||
/* Use a dummy value for the sake of the length calculation below.
|
||||
* Will not be returned.
|
||||
*/
|
||||
result = &dummy_value;
|
||||
}
|
||||
|
||||
if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
result->value = state->payload_end - remaining_str_len(state);
|
||||
result->len = (size_t)payload - (size_t)result->value;
|
||||
|
||||
/* Reencode header of list now that we know the number of elements. */
|
||||
if (!zcbor_bstr_encode(state, result)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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_ERR(ZCBOR_ERR_NO_PAYLOAD);
|
||||
}
|
||||
if (!str_start_encode(state, input, major_type)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
if (state->payload_mut != input->value) {
|
||||
/* Use memmove since string might be encoded into the same space
|
||||
* because of bstrx_cbor_start_encode/bstrx_cbor_end_encode. */
|
||||
memmove(state->payload_mut, input->value, input->len);
|
||||
}
|
||||
state->payload += input->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_bstr_encode(zcbor_state_t *state, const struct zcbor_string *input)
|
||||
{
|
||||
return str_encode(state, input, ZCBOR_MAJOR_TYPE_BSTR);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tstr_encode(zcbor_state_t *state, const struct zcbor_string *input)
|
||||
{
|
||||
return str_encode(state, input, ZCBOR_MAJOR_TYPE_TSTR);
|
||||
}
|
||||
|
||||
|
||||
static bool list_map_start_encode(zcbor_state_t *state, uint_fast32_t max_num,
|
||||
zcbor_major_type_t major_type)
|
||||
{
|
||||
#ifdef ZCBOR_CANONICAL
|
||||
if (!zcbor_new_backup(state, 0)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
/* Encode dummy header with max number of elements. */
|
||||
if (!value_encode(state, major_type, &max_num, sizeof(max_num))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
state->elem_count--; /* Because of dummy header. */
|
||||
#else
|
||||
if (!encode_header_byte(state, major_type, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_list_start_encode(zcbor_state_t *state, uint_fast32_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)
|
||||
{
|
||||
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,
|
||||
zcbor_major_type_t major_type)
|
||||
{
|
||||
#ifdef ZCBOR_CANONICAL
|
||||
uint_fast32_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);
|
||||
|
||||
if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME, 0xFFFFFFFF)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
zcbor_print("list_count: %" PRIuFAST32 "\r\n", list_count);
|
||||
|
||||
/* Reencode header of list now that we know the number of elements. */
|
||||
if (!(value_encode(state, major_type, &list_count, sizeof(list_count)))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
if (max_header_len != header_len) {
|
||||
const uint8_t *start = state->payload + max_header_len - header_len;
|
||||
size_t body_size = (size_t)payload - (size_t)start;
|
||||
memmove(state->payload_mut,
|
||||
state->payload + max_header_len - header_len,
|
||||
body_size);
|
||||
/* Reset payload pointer to end of list */
|
||||
state->payload += body_size;
|
||||
} else {
|
||||
/* Reset payload pointer to end of list */
|
||||
state->payload = payload;
|
||||
}
|
||||
#else
|
||||
if (!encode_header_byte(state, ZCBOR_MAJOR_TYPE_PRIM, ZCBOR_VALUE_IS_INDEFINITE_LENGTH)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_list_end_encode(zcbor_state_t *state, uint_fast32_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)
|
||||
{
|
||||
return list_map_end_encode(state, max_num, ZCBOR_MAJOR_TYPE_MAP);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_list_map_end_force_encode(zcbor_state_t *state)
|
||||
{
|
||||
#ifdef ZCBOR_CANONICAL
|
||||
if (!zcbor_process_backup(state, ZCBOR_FLAG_RESTORE | ZCBOR_FLAG_CONSUME,
|
||||
ZCBOR_MAX_ELEM_COUNT)) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_nil_put(zcbor_state_t *state, const void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
return primitive_put(state, 22);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_undefined_put(zcbor_state_t *state, const void *unused)
|
||||
{
|
||||
(void)unused;
|
||||
return primitive_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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float64_encode(zcbor_state_t *state, const double *input)
|
||||
{
|
||||
if (!value_encode(state, ZCBOR_MAJOR_TYPE_PRIM, input,
|
||||
sizeof(*input))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float64_put(zcbor_state_t *state, double input)
|
||||
{
|
||||
return zcbor_float64_encode(state, &input);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float32_encode(zcbor_state_t *state, const float *input)
|
||||
{
|
||||
if (!value_encode(state, ZCBOR_MAJOR_TYPE_PRIM, input,
|
||||
sizeof(*input))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_float32_put(zcbor_state_t *state, float input)
|
||||
{
|
||||
return zcbor_float32_encode(state, &input);
|
||||
}
|
||||
|
||||
|
||||
bool zcbor_tag_encode(zcbor_state_t *state, uint32_t tag)
|
||||
{
|
||||
if (!value_encode(state, ZCBOR_MAJOR_TYPE_TAG, &tag, sizeof(tag))) {
|
||||
ZCBOR_FAIL();
|
||||
}
|
||||
state->elem_count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
if ((*num_encode >= min_encode) && (*num_encode <= max_encode)) {
|
||||
return zcbor_multi_encode(*num_encode, encoder, state, input, result_len);
|
||||
} else {
|
||||
ZCBOR_ERR(ZCBOR_ERR_ITERATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ZCBOR_CHECK_ERROR();
|
||||
for (uint_fast32_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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
bool 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)
|
||||
{
|
||||
return zcbor_new_state(state_array, n_states, payload, payload_len, elem_count);
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
/*
|
||||
* This file has been copied from the zcbor library.
|
||||
* Commit zcbor 0.4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZCBOR_ENCODE_H__
|
||||
#define ZCBOR_ENCODE_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "zcbor_common.h"
|
||||
|
||||
/** The zcbor_encode library provides functions for encoding CBOR data elements.
|
||||
*
|
||||
* See The README for an introduction to CBOR, including the meaning of pint,
|
||||
* nint, bstr etc.
|
||||
*/
|
||||
|
||||
|
||||
/** 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 result);
|
||||
bool zcbor_uint64_put(zcbor_state_t *state, uint64_t input);
|
||||
|
||||
/** Encode a pint/nint from a pointer.
|
||||
*
|
||||
* Can be used for bulk encoding with @ref zcbor_multi_encode.
|
||||
*/
|
||||
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 *result);
|
||||
bool zcbor_uint64_encode(zcbor_state_t *state, const uint64_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, uint8_t *ptr, size_t len)
|
||||
{
|
||||
return zcbor_bstr_encode(state, &(struct zcbor_string){.value = ptr, .len = len});
|
||||
}
|
||||
static inline bool zcbor_tstr_encode_ptr(zcbor_state_t *state, uint8_t *ptr, size_t len)
|
||||
{
|
||||
return zcbor_tstr_encode(state, &(struct zcbor_string){.value = ptr, .len = len});
|
||||
}
|
||||
|
||||
/** 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)
|
||||
|
||||
/** Encode null-terminated string as a bstr/tstr.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
#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);
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* @param[inout] state The current state of the encoding.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* Restore element count from backup.
|
||||
*/
|
||||
bool zcbor_bstr_end_encode(zcbor_state_t *state, struct zcbor_string *result);
|
||||
|
||||
/** Encode a list/map header.
|
||||
*
|
||||
* The contents of the list/map can be encoded via subsequent function calls.
|
||||
* If ZCBOR_CANONICAL is defined, a state backup is created to keep track of the
|
||||
* element count.
|
||||
* When all members have been encoded, call @ref zcbor_list_end_encode /
|
||||
* @ref zcbor_map_end_encode to close the list/map.
|
||||
*
|
||||
* @param[inout] state The current state of the encoding.
|
||||
* @param[in] max_num The maximum number of members in the list/map.
|
||||
* This serves as a size hint for the header. Must be
|
||||
* equal to the max_num provided to the corresponding
|
||||
* @ref zcbor_list_end_encode / @ref zcbor_map_end_encode
|
||||
* 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);
|
||||
|
||||
/** Encode the end of a list/map. Do some checks and deallocate backup.
|
||||
*
|
||||
* - Default: Adds a list terminator (0xFF) to mark the
|
||||
* end of the list/map.
|
||||
* - If ZCBOR_CANONICAL is defined: Instead encodes the number of members in
|
||||
* the list/map header. If the header ends up a different size than expected,
|
||||
* the list/map contents are moved using memmove().
|
||||
*
|
||||
* Use @ref zcbor_list_map_end_force_encode to forcibly consume the backup if
|
||||
* something has gone wrong.
|
||||
*
|
||||
* @param[inout] state The current state of the encoding.
|
||||
* @param[in] max_num The maximum number of members in the list/map. Must be
|
||||
* equal to the max_num provided to the corresponding
|
||||
* @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_map_end_force_encode(zcbor_state_t *state);
|
||||
|
||||
/** Encode 0 or more elements with the same type and constraints.
|
||||
*
|
||||
* The encoded values are taken from the @p input array.
|
||||
*
|
||||
* The following is an example of encoding a list containing 3 INTS followed by
|
||||
* 0 to 2 bstrs:
|
||||
*
|
||||
* @code{c}
|
||||
* uint32_t ints[3] = <initialize>;
|
||||
* struct zcbor_string bstrs[2] = <initialize>;
|
||||
* bool res;
|
||||
*
|
||||
* res = zcbor_list_start_encode(state, 5);
|
||||
* res = res && zcbor_multi_encode(3, zcbor_uint32_encode, state,
|
||||
* ints, sizeof(uint32_t));
|
||||
* res = res && zcbor_multi_encode(2, zcbor_bstr_encode, state,
|
||||
* bstrs, sizeof(struct zcbor_string));
|
||||
* res = res && zcbor_list_end_encode(state, 5);
|
||||
* // check res
|
||||
* @endcode
|
||||
*
|
||||
* The @ref zcbor_encoder_t type is designed to be compatible with all single-
|
||||
* value encoder functions in this library, e.g. @ref zcbor_uint32_encode,
|
||||
* @ref zcbor_tstr_put, @ref zcbor_nil_put, etc. For _put() functions,
|
||||
* @p input will be used as a value instead of an array/pointer, so
|
||||
* @p input_len will determine how much the value changes for each call.
|
||||
* To encode the same value multiple times, use a @p input_len of 0.
|
||||
* This function can also be used with custom decoder functions, such as those
|
||||
* generated by the zcbor.py script, which for example encodes larger chunks of
|
||||
* the data at once.
|
||||
*
|
||||
* @param[in] num_encode The actual number of elements.
|
||||
* @param[in] encoder The encoder function to call under the hood. This
|
||||
* function will be called with the provided arguments
|
||||
* repeatedly until the function fails (returns false)
|
||||
* or until it has been called @p max_encode times.
|
||||
* The input pointer is moved @p input_len bytes for
|
||||
* each call to @p encoder, i.e. @p input refers to an
|
||||
* array of input variables.
|
||||
* @param[in] input Source of the encoded values. Must be an array of
|
||||
* at least @p max_encode elements.
|
||||
* @param[in] input_len The length of the input variables. Must be the
|
||||
* length of the individual elements in input.
|
||||
*
|
||||
* @retval true If at least @p min_encode variables were correctly encoded.
|
||||
* @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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** 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() */
|
||||
bool 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);
|
||||
|
||||
/** Convenience macro for declaring and initializing a state with backups.
|
||||
*
|
||||
* This gives you a state variable named @p name. The variable functions like
|
||||
* a pointer.
|
||||
*
|
||||
* The return value from @ref zcbor_new_encode_state can be safely ignored
|
||||
* because the only error condition is n_states < 2, and this macro adds 2 to
|
||||
* num_backups to get n_states, so it can never be < 2.
|
||||
*
|
||||
* @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_STATE_E(name, num_backups, payload, payload_size, elem_count) \
|
||||
zcbor_state_t name[((num_backups) + 2)]; \
|
||||
do { \
|
||||
(void)zcbor_new_encode_state(name, ARRAY_SIZE(name), payload, payload_size, elem_count); \
|
||||
} while(0)
|
||||
|
||||
#endif /* ZCBOR_ENCODE_H__ */
|
|
@ -252,9 +252,9 @@ if(CONFIG_MCUBOOT_SERIAL)
|
|||
zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/serial_recovery_cbor.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_decode.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_encode.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/cbor_common.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_decode.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_encode.c)
|
||||
zephyr_sources(${BOOT_DIR}/boot_serial/src/zcbor_common.c)
|
||||
|
||||
zephyr_include_directories(${BOOT_DIR}/bootutil/include)
|
||||
zephyr_include_directories(${BOOT_DIR}/boot_serial/include)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 9f77837f9950da1633d22abf6181a830521a6688
|
Loading…
Reference in New Issue