230 lines
5.7 KiB
C
230 lines
5.7 KiB
C
/*
|
|
* 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;
|
|
}
|