Commit 147c63d7 authored by Brendan Moran's avatar Brendan Moran
Browse files

Add pull parser support

parent de681e02
......@@ -24,9 +24,9 @@ OUT?=../out/
Q?=@
TARGET=${OUT}bm_cbor.a
TARGET=${OUT}pull_cbor.a
SRCS=bm_cbor.c
SRCS=pull_cbor.c bm_cbor.c
OBJS=$(patsubst %.c,${OUT}%.o,${SRCS})
all: ${TARGET}
......
......@@ -16,17 +16,21 @@
// limitations under the License.
// ----------------------------------------------------------------------------
#include "bm_cbor.h"
#include <stdint.h>
#include <stddef.h>
#if BM_CBOR_ERR_INFO != 0
bm_cbor_err_info_t bm_cbor_err_info = {0};
#endif
int bm_cbor_get_as_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n)
{
if (*p >= end) {
RETURN_ERROR(CBOR_ERR_OVERRUN);
RETURN_ERROR(CBOR_ERR_OVERRUN, *p);
}
uint8_t iv = **p & ~CBOR_TYPE_MASK;
if (iv >= 28){
RETURN_ERROR(CBOR_ERR_INTEGER_ENCODING);
RETURN_ERROR(CBOR_ERR_INTEGER_ENCODING, *p);
}
(*p)++;
//TODO: do not increment p until size check is good
......@@ -37,7 +41,7 @@ int bm_cbor_get_as_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n
const uint8_t* uend = *p + (1 << (iv-24));
if (uend > end) {
--(*p);
RETURN_ERROR(CBOR_ERR_OVERRUN);
RETURN_ERROR(CBOR_ERR_OVERRUN, *p);
}
for (*n = 0; *p < uend; (*p)++) {
*n = *n << 8 | **p;
......@@ -49,7 +53,7 @@ int bm_cbor_get_as_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n
int bm_cbor_get_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n){
uint8_t type = **p & CBOR_TYPE_MASK;
if (type != CBOR_TYPE_UINT) {
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH);
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH, *p);
}
return bm_cbor_get_as_uint(p, end, n);
}
......@@ -57,7 +61,7 @@ int bm_cbor_get_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n){
int bm_cbor_get_int(const uint8_t** p, const uint8_t* end, bm_cbor_int_t* n) {
uint8_t type = **p & CBOR_TYPE_MASK;
if (type != CBOR_TYPE_NINT && type != CBOR_TYPE_UINT) {
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH);
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH, *p);
}
bm_cbor_uint_t uv;
int rc = bm_cbor_get_as_uint(p, end, &uv);
......@@ -66,7 +70,7 @@ int bm_cbor_get_int(const uint8_t** p, const uint8_t* end, bm_cbor_int_t* n) {
}
if (uv & (1UL << (BM_CBOR_INT_SIZE -1))) {
// Valid CBOR, but requires larger integers to decode
RETURN_ERROR(CBOR_ERR_INTEGER_DECODE_OVERFLOW);
RETURN_ERROR(CBOR_ERR_INTEGER_DECODE_OVERFLOW, *p);
}
if (type == CBOR_TYPE_NINT) {
*n = -1 - (bm_cbor_int_t)uv;
......@@ -111,47 +115,47 @@ int bm_cbor_extract_primitive(
{
val->primitive = (**p & (~CBOR_TYPE_MASK));
(*p)++;
RETURN_ERROR(CBOR_ERR_NONE);
RETURN_ERROR(CBOR_ERR_NONE, *p);
}
int cbor_check_type_extract_ref(
int bm_cbor_check_type_extract_ref(
const uint8_t **p,
const uint8_t *end,
cbor_value_t *o_val,
bm_cbor_value_t *o_val,
const uint8_t cbor_type
) {
if ((**p & CBOR_TYPE_MASK) != cbor_type) {
PD_PRINTF("Expected: %u Actual %u\n", (unsigned) cbor_type>>5, (unsigned)(**p & CBOR_TYPE_MASK)>>5);
// BM_CBOR_ERR_PRINT("Expected: %u Actual %u\n", (unsigned) cbor_type>>5, (unsigned)(**p & CBOR_TYPE_MASK)>>5);
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH);
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH, *p);
}
o_val->cbor_start = *p;
return cbor_extract_ref(p, end, o_val);
return bm_cbor_extract_ref(p, end, o_val);
}
int (*cbor_extractors[])(
int (*bm_cbor_extractors[])(
const uint8_t **p,
const uint8_t *end,
cbor_value_t *val) =
bm_cbor_value_t *val) =
{
cbor_extract_uint,
cbor_extract_int,
cbor_extract_ref,
cbor_extract_ref,
cbor_extract_ref,
cbor_extract_ref,
cbor_extract_ref,
cbor_extract_primitive
bm_cbor_extract_uint,
bm_cbor_extract_int,
bm_cbor_extract_ref,
bm_cbor_extract_ref,
bm_cbor_extract_ref,
bm_cbor_extract_ref,
bm_cbor_extract_ref,
bm_cbor_extract_primitive
};
int cbor_skip(const uint8_t **p, const uint8_t *end)
int bm_cbor_skip(const uint8_t **p, const uint8_t *end)
{
uint8_t ct = **p & CBOR_TYPE_MASK;
size_t handler_index = ct >> 5;
cbor_value_t val;
int rc = cbor_extractors[handler_index](p, end, &val);
bm_cbor_value_t val;
int rc = bm_cbor_extractors[handler_index](p, end, &val);
if ((*p) > end) {
SET_ERROR(rc, CBOR_ERR_OVERRUN);
SET_ERROR(rc, CBOR_ERR_OVERRUN,*p);
}
if (rc != CBOR_ERR_NONE) {
return rc;
......@@ -165,7 +169,7 @@ int cbor_skip(const uint8_t **p, const uint8_t *end)
if ((*p) + val.ref.uival <= end) {
(*p) += val.ref.uival;
} else {
SET_ERROR(rc, CBOR_ERR_OVERRUN);
SET_ERROR(rc, CBOR_ERR_OVERRUN, *p);
}
break;
case CBOR_TYPE_MAP:
......@@ -173,18 +177,19 @@ int cbor_skip(const uint8_t **p, const uint8_t *end)
// no break;
case CBOR_TYPE_LIST:
for (size_t count = val.ref.uival; count && rc == CBOR_ERR_NONE; count--) {
rc = cbor_skip(p, end);
rc = bm_cbor_skip(p, end);
}
break;
case CBOR_TYPE_SIMPLE:
if (val.primitive == (CBOR_NULL & ~CBOR_TYPE_MASK)) {
break;
} else {
// PD_PRINTF("primitive : %02x\n", val.primitive);
// BM_CBOR_ERR_PRINT("primitive : %02x\n", val.primitive);
}
default:
// PD_PRINTF("Skip Unimplemented for type %u\n", (unsigned) ct>>5);
SET_ERROR(rc, CBOR_ERR_UNIMPLEMENTED);
// BM_CBOR_ERR_PRINT("Skip Unimplemented for type %u\n", (unsigned) ct>>5);
SET_ERROR(rc, CBOR_ERR_UNIMPLEMENTED, *p);
}
return rc;
}
\ No newline at end of file
}
......@@ -15,7 +15,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------
#ifndef _BM_CBOR_H_
#define _BM_CBOR_H_
/**
* @file Basic Minimal CBOR (bm_cbor)
* @brief A minimalist CBOR parser.
......@@ -45,28 +46,56 @@ enum {
CBOR_ERR_INTEGER_DECODE_OVERFLOW,
CBOR_ERR_INTEGER_ENCODING,
CBOR_ERR_UNIMPLEMENTED,
CBOR_ERR_MAX,
};
#ifndef PRINT_ON_ERROR
#define PRINT_ON_ERROR 0
#define PRINT_ON_ERROR 1
#endif
#if PRINT_ON_ERROR == 0
#define BM_CBOR_ERR_PRINT(...)
#else
#include <stdio.h>
#define BM_CBOR_ERR_PRINT printf
#ifndef BM_CBOR_ERR_INFO
#define BM_CBOR_ERR_INFO 1
#endif
#ifndef BM_CBOR_ERR_INFO_DGB
#define BM_CBOR_ERR_INFO_DGB 1
#endif
#if BM_CBOR_ERR_INFO != 0
typedef struct bm_cbor_err_info_s {
const uint8_t *ptr;
int cbor_err;
#if BM_CBOR_ERR_INFO_DGB != 0
unsigned line;
const char* file;
#endif
} bm_cbor_err_info_t;
extern bm_cbor_err_info_t bm_cbor_err_info;
static inline bm_cbor_err_info_t* bm_cbor_get_err_info() { return & bm_cbor_err_info;}
#endif
#define SET_ERROR(RC, VAL)\
#define SET_ERROR(RC, VAL, PTR)\
do{\
(RC)=(VAL);\
if((VAL) && PRINT_ON_ERROR){BM_CBOR_ERR_PRINT("Error " #VAL " (%i) set on %s:%u\r\n",(VAL),__FILE__,__LINE__);\
if ((VAL) && BM_CBOR_ERR_INFO){\
bm_cbor_err_info.ptr = (PTR);\
bm_cbor_err_info.cbor_err = (VAL);\
if (BM_CBOR_ERR_INFO_DGB) {\
bm_cbor_err_info.line = (__LINE__);\
bm_cbor_err_info.file = (__FILE__);\
}\
}}while(0)
#define RETURN_ERROR(VAL)\
#define RETURN_ERROR(VAL, PTR)\
do{\
if((VAL) && PRINT_ON_ERROR){BM_CBOR_ERR_PRINT("Error " #VAL " (%i) set on %s:%u\r\n",(VAL),__FILE__,__LINE__);}\
if ((VAL) && BM_CBOR_ERR_INFO){\
bm_cbor_err_info.ptr = (PTR);\
bm_cbor_err_info.cbor_err = (VAL);\
if (BM_CBOR_ERR_INFO_DGB) {\
bm_cbor_err_info.line = (__LINE__);\
bm_cbor_err_info.file = (__FILE__);\
}\
}\
return (VAL);}while(0)
......@@ -85,6 +114,7 @@ typedef int32_t bm_cbor_int_t;
#endif
typedef struct bm_cbor_value_s {
const uint8_t *cbor_start;
union {
bm_cbor_uint_t u;
bm_cbor_int_t i;
......@@ -96,11 +126,15 @@ typedef struct bm_cbor_value_s {
};
} bm_cbor_value_t;
typedef struct bm_cbor_start_value_s {
bm_cbor_value_s v;
typedef struct bm_cbor_reference_s {
bm_cbor_value_t v;
const uint8_t *s;
} bm_cbor_start_value_t;
} bm_cbor_reference_t;
extern int (*bm_cbor_extractors[])(
const uint8_t **p,
const uint8_t *end,
bm_cbor_value_t *val);
int bm_cbor_get_as_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n);
int bm_cbor_get_uint(const uint8_t** p, const uint8_t* end, bm_cbor_uint_t* n);
......@@ -109,4 +143,12 @@ int bm_cbor_get_int(const uint8_t** p, const uint8_t* end, bm_cbor_int_t* n);
int bm_cbor_extract_uint(const uint8_t **p, const uint8_t *end, bm_cbor_value_t *val);
int bm_cbor_extract_int(const uint8_t **p, const uint8_t *end, bm_cbor_value_t *val);
int bm_cbor_extract_ref(const uint8_t **p, const uint8_t *end, bm_cbor_value_t *val);
int bm_cbor_extract_primitive(const uint8_t **p, const uint8_t *end, bm_cbor_value_t *val);
\ No newline at end of file
int bm_cbor_extract_primitive(const uint8_t **p, const uint8_t *end, bm_cbor_value_t *val);
int bm_cbor_check_type_extract_ref(
const uint8_t **p,
const uint8_t *end,
bm_cbor_value_t *o_val,
const uint8_t cbor_type
);
int bm_cbor_skip(const uint8_t **p, const uint8_t *end);
#endif // _BM_CBOR_H_
// ----------------------------------------------------------------------------
// Copyright 2020-2021 ARM Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------
#include "bm_cbor.h"
#include "pull_cbor.h"
#include <stdint.h>
#include <stddef.h>
#include <string.h>
// TODO: Further unit tests for units below this line
//===================================================
static int get_handler(
const uint8_t cbor_b1,
const uint8_t cbor_sub,
const cbor_keyed_parse_element_t** h,
const cbor_keyed_parse_elements_t* handlers,
const int32_t key
) {
size_t i;
// Step 1: find the first key that matches
int success = 0;
for (i = 0; i < handlers->count; i++)
{
if (handlers->elements[i].key == key) {
success = 1;
break;
}
}
if (!success ) {
PD_PRINTF("Couldn't find a handler for key %d\n", (int) key);
RETURN_ERROR(CBOR_ERR_KEY_MISMATCH, NULL);
}
// PD_PRINTF("Key Matched, Matching major %u, sub:%u\n", (unsigned) cbor_b1>>5, (unsigned)cbor_sub >> 5);
// Step 2: Loop through handlers until a matching handler is found or a key mismatch is found
// const cbor_keyed_parse_element_t* h;
for (; i < handlers->count && handlers->elements[i].key == key; i++) {
// do {
uint8_t cbor_type = (cbor_b1 & CBOR_TYPE_MASK) >> 5;
*h = &handlers->elements[i];
if ((*h)->bstr_wrap) {
if (cbor_type != CBOR_TYPE_BSTR >> 5) {
continue;
}
cbor_type = (cbor_sub & CBOR_TYPE_MASK) >> 5;
}
if ((*h)->type == cbor_type) {
return CBOR_ERR_NONE;
}
if (cbor_type == CBOR_TYPE_UINT >> 5 && (*h)->type == CBOR_TYPE_NINT >> 5)
{
return CBOR_ERR_NONE;
}
if ((*h)->null_opt && cbor_b1 == CBOR_NULL) {
return CBOR_ERR_NONE;
}
} // while (++i < handlers->count && (*h)->key == key);
PD_PRINTF("Type Mismatch\n");
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH, NULL);
}
/**
*
* Step 1: get the handler.
* Step 2: Unwrap if bstr-wrapped.
* Step 3: Invoke the appropriate handler.
*/
int pull_cbor_handle_keyed_element(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
int32_t key
) {
// TODO: Add pre-call-function?
// PD_PRINTF("parse offset: %zu, key: %" PRIi64 "\n", (size_t)((*p)-ctx->envelope.ptr), key);
bm_cbor_value_t val;
val.cbor_start = *p;
// Perform the extract in advance.
uint8_t cbor_b1 = **p;
int rc = bm_cbor_extractors[(cbor_b1 & CBOR_TYPE_MASK)>>5](p, end, &val);
if (rc != CBOR_ERR_NONE) {
return rc;
}
// PD_PRINTF("Extract done\r\n");
uint8_t cbor_sub = **p;
const cbor_keyed_parse_element_t *handler;
rc = get_handler(cbor_b1, cbor_sub, &handler, handlers, key);
if (rc != CBOR_ERR_NONE) {
bm_cbor_get_err_info()->ptr = *p;
return rc;
}
// PD_PRINTF("Selected handler %zu", handler_index);
PD_PRINTF("%s\n", handler->desc);
uint8_t cbor_type = cbor_b1 & CBOR_TYPE_MASK;
if (handler->bstr_wrap) {
// PD_PRINTF("parse offset: %zu. Unwrapping BSTR\n", (size_t)((*p)-ctx->envelope.ptr));
val.cbor_start = *p;
end = val.ref.ptr + val.ref.uival;
rc = bm_cbor_extractors[(cbor_sub & CBOR_TYPE_MASK)>>5](p, end, &val);
if (rc != CBOR_ERR_NONE) {
return rc;
}
cbor_type = cbor_sub & CBOR_TYPE_MASK;
// PD_PRINTF("Next type: %u\n", (unsigned)cbor_type >> 5);
}
// PD_PRINTF("[%s:%d] Invoking: %s\n", __FUNCTION__, __LINE__, handler->desc);
if (handler->ptr == NULL) {
// Nothing to do.
PD_PRINTF("Skipping...\n");
*p = val.cbor_start;
rc = bm_cbor_skip(p, end);
}
else if (handler->extract) {
memcpy((void *)handler->ptr, &val, sizeof(bm_cbor_value_t));
}
else if (handler->has_handler) {
pull_cbor_handler_t handler_fn = (pull_cbor_handler_t) handler->ptr;
// PD_PRINTF("Invoking explicit handler for CBOR Major %u\r\n", (unsigned)cbor_type >> 5);
rc = handler_fn(p, end, ctx, &val, key, cbor_type);
} else {
// PD_PRINTF("Invoking default handler for CBOR Major %u\r\n", (unsigned)cbor_type >> 5);
const cbor_keyed_parse_elements_t *children = (const cbor_keyed_parse_elements_t *) handler->ptr;
switch(cbor_type) {
case CBOR_TYPE_LIST:{
int (*handler_fn)(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
size_t n_elements
) = NULL;
if (handler->is_array) {
handler_fn = pull_cbor_handle_array;
}
else if (handler->is_kv) {
handler_fn = pull_cbor_handle_pairs;
}
else {
handler_fn = pull_cbor_handle_list;
}
rc = handler_fn(p, end, ctx, children, val.ref.uival);
break;
}
case CBOR_TYPE_MAP:
rc = pull_cbor_handle_pairs(p, end, ctx, children, val.ref.uival*2);
break;
case CBOR_TYPE_TAG:
rc = pull_cbor_handle_keyed_element(p, end, ctx, children, val.ref.uival);
break;
}
}
if (rc == CBOR_ERR_NONE) {
if (handler->bstr_wrap) {
*p = end;
}
else if ((cbor_b1 & CBOR_TYPE_MASK) == CBOR_TYPE_BSTR) {
*p = val.ref.ptr+val.ref.uival;
}
}
return rc;
}
int pull_cbor_handle_array(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
size_t n_elements
) {
int rc = CBOR_ERR_NONE;
for (; rc == CBOR_ERR_NONE && n_elements; n_elements--) {
// PD_PRINTF("[%s:%d] ",__FUNCTION__, __LINE__);
// PD_PRINTF("parse offset: %zu, key: %" PRIi64 "\n", (size_t)((*p)-ctx->envelope.ptr), 0LL);
rc = pull_cbor_handle_keyed_element(p, end, ctx, handlers, 0);
}
return rc;
}
int pull_cbor_handle_list(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
size_t n_elements
) {
int rc = CBOR_ERR_NONE;
for (size_t i = 0; rc == CBOR_ERR_NONE && i < n_elements; i++) {
// PD_PRINTF("[%s:%d] ",__FUNCTION__, __LINE__);
// PD_PRINTF("parse offset: %zu, key: %" PRIi64 "\n", (size_t)((*p)-ctx->envelope.ptr), (int64_t)i);
rc = pull_cbor_handle_keyed_element(p, end, ctx, handlers, i);
}
return rc;
}
int pull_cbor_handle_pairs(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
size_t n_pairs
) {
n_pairs = n_pairs/2;
// PD_PRINTF("Handling %zu pairs\n", n_pairs);
int rc = CBOR_ERR_NONE;
for (; rc == CBOR_ERR_NONE && n_pairs; n_pairs--) {
bm_cbor_int_t key;
// Get Key
rc = bm_cbor_get_int(p, end, &key);
if (rc != CBOR_ERR_NONE) {
break;
}
//TODO: range-check key64
// Find handler
// PD_PRINTF("[%s:%d] ",__FUNCTION__, __LINE__);
// PD_PRINTF("parse offset: %zu, key: %" PRIi64 "\n", (size_t)((*p)-ctx->envelope.ptr), (int64_t)key64);
rc = pull_cbor_handle_keyed_element(p, end, ctx, handlers, key);
}
return rc;
}
int pull_cbor_handle_tag(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers
) {
bm_cbor_value_t tag;
int rc = bm_cbor_check_type_extract_ref(
p, end, &tag, CBOR_TYPE_TAG
);
if (rc != CBOR_ERR_NONE) {
return rc;
}
// PD_PRINTF("[%s:%d] ",__FUNCTION__, __LINE__);
// PD_PRINTF("parse offset: %zu, key: %" PRIi64 "\n", (size_t)((*p)-ctx->envelope.ptr), (int64_t)tag.ref.uival);
// PD_PRINTF("Choosing betwen %zu tags\n", handlers->count);
return pull_cbor_handle_keyed_element(p, end, ctx, handlers, tag.ref.uival);
}
int pull_cbor_process_kv(
const uint8_t** p,
const uint8_t* end,
void *ctx,
const cbor_keyed_parse_elements_t *handlers,
const uint8_t type
) {
// Ensure that the wrapper is a map.
if ((**p & CBOR_TYPE_MASK) != type) {
RETURN_ERROR(CBOR_ERR_TYPE_MISMATCH, *p);
}
bm_cbor_value_t val;
int rc = bm_cbor_extract_ref(p, end, &val);
if (rc == CBOR_ERR_NONE) {
uint32_t n_keys = type == CBOR_TYPE_LIST ? val.ref.uival : val.ref.uival*2;
rc = pull_cbor_handle_pairs(p, end, ctx, handlers, n_keys);
}
return rc;
}
\ No newline at end of file
// ----------------------------------------------------------------------------
// Copyright 2020-2021 ARM Ltd.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------
#ifndef _PULL_CBOR_H_
#define _PULL_CBOR_H_
#include <stddef.h>
// #define FLEXARRAY_HELPER(STRUCT_TYPE, TYPE, NAME, TMPNAME, ...)\
// const TYPE TMPNAME [] = { \
// __VA_ARGS__\
// };\
// union {\
// const STRUCT_TYPE elements;\
// const uint8_t raw [sizeof(TMPNAME) + sizeof(STRUCT_TYPE)];\
// } NAME = {{.count = ARRAY_SIZE(TMPNAME), elements={ \
// __VA_ARGS__\
// }}}
// #define FLEXARRAY(STRUCT_TYPE, TYPE, NAME, ...) FLEXARRAY_HELPER(STRUCT_TYPE, TYPE, NAME, _flexarray_ ## NAME ## _tmp, __VA_ARGS__)
// #define CBOR_KPARSE_ELEMENT_LIST(NAME, ...) \
// FLEXARRAY(cbor_keyed_parse_elements_t, cbor_keyed_parse_element_t, NAME, __VA_ARGS__)
#ifdef PARSER_DEBUG
#define CBOR_KPARSE_ELEMENT_C_BWRAP_KV(KEY, TYPE, CHILDREN, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, .is_kv = 1, .bstr_wrap = 1, 0, 0, 0, .ptr = (CHILDREN), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_C_BWRAP(KEY, TYPE, CHILDREN, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, .bstr_wrap = 1, 0, 0, 0, .ptr = (CHILDREN), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_A_BWRAP(KEY, TYPE, CHILDREN, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, .bstr_wrap = 1, .is_array = 1, 0, 0, .ptr = (CHILDREN), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_C(KEY, TYPE, CHILDREN, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, 0, 0, 0, 0, .ptr = (CHILDREN), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_H(KEY, TYPE, HANDLER, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, .has_handler = 1, 0, 0, 0, 0, .ptr = (HANDLER), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_H_BWRAP(KEY, TYPE, HANDLER, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, .has_handler = 1, .bstr_wrap = 1, 0, 0, 0, .ptr = (HANDLER), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_EX(KEY, TYPE, VAL, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, 0, 0, .extract = 1, 0, .ptr = (VAL), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT_EX_BWRAP(KEY, TYPE, VAL, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, .bstr_wrap = 1, 0, .extract = 1, 0, .ptr = (VAL), .desc=(DESC)}
#define CBOR_KPARSE_ELEMENT(KEY, TYPE, HANDLER, DESC)\
{.key = (KEY), 0, .type = (TYPE) >> 5, 0, 0, 0, .ptr=(HANDLER), .desc=(