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:
Øyvind Rønningstad 2022-02-28 13:47:57 +01:00 committed by David Brown
parent 35f61d305d
commit a7d34caaa7
23 changed files with 2970 additions and 1932 deletions

3
.gitmodules vendored
View File

@ -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

View File

@ -11,7 +11,6 @@ samples/*
scripts/*
sim/*
testplan/*
ext/cddl_gen/*
ext/fiat/*
ext/mbedtls/*
ext/mbedtls-asn1/*

View File

@ -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;

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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"

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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