You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ja...@apache.org on 2026/10/12 16:26:13 UTC
(mynewt-core) 04/24: encoding/cborattr: Import cborattr from mcumgr
This is an automated email from the ASF dual-hosted git repository.
sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
commit 5a318392aacad77bf43906946db403538adcaa62
Author: Szymon Janc <sz...@codecoup.pl>
AuthorDate: Wed Oct 7 10:50:35 2026 +0200
encoding/cborattr: Import cborattr from mcumgr
encoding/cborattr is now a regular package with cborattr code and unit
tests imported unmodified from apache/mynewt-mcumgr at commit 7bdd41ffb,
instead of being a link to @apache-mynewt-mcumgr/cborattr. Only package
names and dependencies in pkg.yml files are updated, Zephyr build file
(CMakeLists.txt) is not imported.
Assisted-by: Claude:claude-opus-5-5
---
encoding/cborattr/include/cborattr/cborattr.h | 227 +++++++
encoding/cborattr/pkg.yml | 13 +-
encoding/cborattr/src/cborattr.c | 753 +++++++++++++++++++++
encoding/cborattr/{pkg.yml => syscfg.yml} | 15 +-
encoding/cborattr/{ => test}/pkg.yml | 20 +-
encoding/cborattr/test/src/test_cborattr.c | 52 ++
encoding/cborattr/test/src/test_cborattr.h | 62 ++
encoding/cborattr/test/src/test_cborattr_utils.c | 50 ++
.../cborattr/test/src/testcases/cborattr_decode1.c | 83 +++
.../src/testcases/cborattr_decode_bool_array.c | 101 +++
.../test/src/testcases/cborattr_decode_int_array.c | 143 ++++
.../test/src/testcases/cborattr_decode_nesting.c | 99 +++
.../test/src/testcases/cborattr_decode_obj_array.c | 109 +++
.../test/src/testcases/cborattr_decode_object.c | 198 ++++++
.../src/testcases/cborattr_decode_object_array.c | 126 ++++
.../test/src/testcases/cborattr_decode_partial.c | 47 ++
.../test/src/testcases/cborattr_decode_simple.c | 123 ++++
.../src/testcases/cborattr_decode_string_array.c | 135 ++++
.../cborattr_decode_string_array_bounds.c | 102 +++
.../src/testcases/cborattr_decode_string_bounds.c | 119 ++++
.../src/testcases/cborattr_decode_substring_key.c | 111 +++
.../src/testcases/cborattr_decode_unnamed_array.c | 99 +++
.../test/src/testcases/cborattr_encode_omit.c | 140 ++++
.../test/src/testcases/cborattr_encode_simple.c | 143 ++++
24 files changed, 3058 insertions(+), 12 deletions(-)
diff --git a/encoding/cborattr/include/cborattr/cborattr.h b/encoding/cborattr/include/cborattr/cborattr.h
new file mode 100644
index 000000000..d025e6404
--- /dev/null
+++ b/encoding/cborattr/include/cborattr/cborattr.h
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 CBORATTR_H
+#define CBORATTR_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include "tinycbor/cbor.h"
+
+#ifdef MYNEWT
+#include <os/os_mbuf.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This library wraps the tinycbor decoder with a attribute based decoder
+ * suitable for decoding a binary version of json. Specifically, the
+ * contents of the cbor contains pairs of attributes. where the attribute
+ * is a key/value pair. keys are always text strings, but values can be
+ * many different things (enumerated below) */
+
+typedef enum CborAttrType {
+ CborAttrIntegerType = 1,
+ CborAttrUnsignedIntegerType,
+ CborAttrByteStringType,
+ CborAttrTextStringType,
+ CborAttrBooleanType,
+ CborAttrHalfFloatType,
+ CborAttrFloatType,
+ CborAttrDoubleType,
+ CborAttrArrayType,
+ CborAttrObjectType,
+ CborAttrStructObjectType,
+ CborAttrNullType,
+} CborAttrType;
+
+struct cbor_attr_t;
+
+struct cbor_enum_t {
+ char *name;
+ long long int value;
+};
+
+struct cbor_array_t {
+ CborAttrType element_type;
+ union {
+ struct {
+ const struct cbor_attr_t *subtype;
+ char *base;
+ size_t stride;
+ } objects;
+ struct {
+ char **ptrs;
+ char *store;
+ int storelen;
+ } strings;
+ struct {
+ long long int *store;
+ } integers;
+ struct {
+ long long unsigned int *store;
+ } uintegers;
+ struct {
+ double *store;
+ } reals;
+ struct{
+ uint16_t *store;
+ } halffloats;
+ struct {
+ bool *store;
+ } booleans;
+ } arr;
+ int *count;
+ int maxlen;
+};
+
+struct cbor_attr_t {
+ char *attribute;
+ CborAttrType type;
+ union {
+ long long int *integer;
+ long long unsigned int *uinteger;
+ uint16_t *halffloat;
+ double *real;
+ float *fval;
+ char *string;
+ bool *boolean;
+ struct byte_string {
+ uint8_t *data;
+ size_t *len;
+ } bytestring;
+ struct cbor_array_t array;
+ size_t offset;
+ struct cbor_attr_t *obj;
+ } addr;
+ union {
+ long long int integer;
+ double real;
+ bool boolean;
+ float fval;
+ uint16_t halffloat;
+ } dflt;
+ size_t len;
+ bool nodefault;
+};
+
+#ifndef __ZEPHYR__
+/** An array value to be encoded as CBOR. */
+struct cbor_out_arr_val_t {
+ struct cbor_out_val_t *elems;
+ size_t len;
+};
+
+/** A single value to be encoded as CBOR. */
+struct cbor_out_val_t {
+ /** The type of data. */
+ CborAttrType type;
+
+ /** The data value. */
+ union {
+ long long int integer;
+ long long unsigned int uinteger;
+ double real;
+ float fval;
+ uint16_t halffloat;
+ const char *string;
+ bool boolean;
+ struct {
+ const uint8_t *data;
+ size_t len;
+ } bytestring;
+ struct cbor_out_arr_val_t array;
+ struct cbor_out_attr_t *obj; /* Terminated with a type=0 entry. */
+ };
+};
+
+/** An object key-value pair to be encoded as CBOR. */
+struct cbor_out_attr_t {
+ const char *attribute; /** The attribute name (key). */
+ struct cbor_out_val_t val; /** The attribute value. */
+ bool omit; /** Attribute ignored if true. */
+};
+#endif
+
+/*
+ * Use the following macros to declare template initializers for
+ * CborAttrStructObjectType arrays. Writing the equivalents out by hand is
+ * error-prone.
+ *
+ * CBOR_STRUCT_OBJECT takes a structure name s, and a fieldname f in s.
+ *
+ * CBOR_STRUCT_ARRAY takes the name of a structure array, a pointer to a an
+ * initializer defining the subobject type, and the address of an integer to
+ * store the length in.
+ */
+#define CBORATTR_STRUCT_OBJECT(s, f) .addr.offset = offsetof(s, f)
+#define CBORATTR_STRUCT_ARRAY(a, e, n) \
+ .addr.array.element_type = CborAttrStructObjectType, \
+ .addr.array.arr.objects.subtype = e, \
+ .addr.array.arr.objects.base = (char*)a, \
+ .addr.array.arr.objects.stride = sizeof(a[0]), \
+ .addr.array.count = n, \
+ .addr.array.maxlen = (int)(sizeof(a)/sizeof(a[0]))
+
+#define CBORATTR_ATTR_UNNAMED (char *)(-1)
+
+int cbor_read_object(struct CborValue *, const struct cbor_attr_t *);
+int cbor_read_array(struct CborValue *, const struct cbor_array_t *);
+
+int cbor_read_flat_attrs(const uint8_t *data, int len,
+ const struct cbor_attr_t *attrs);
+#ifdef MYNEWT
+int cbor_read_mbuf_attrs(struct os_mbuf *m, uint16_t off, uint16_t len,
+ const struct cbor_attr_t *attrs);
+
+/**
+ * @brief Encodes a CBOR representation of the specified key-value map.
+ *
+ * @param enc The CBOR encoder to write to.
+ * @param attrs The key-value map to encode.
+ *
+ * @return 0 on success; SYS_E[...] error on failure.
+ */
+int cbor_write_object(struct CborEncoder *enc,
+ const struct cbor_out_attr_t *attrs);
+
+/**
+ * @brief Encodes a CBOR representation of the specified key-value map into an
+ * msys mbuf chain.
+ *
+ * @param attrs The key-value map to encode.
+ * @param out_om On success, points to the populate mbuf chain.
+ *
+ * @return 0 on success; SYS_E[...] error on failure.
+ */
+int cbor_write_object_msys(const struct cbor_out_attr_t *attrs,
+ struct os_mbuf **out_om);
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CBORATTR_H */
+
diff --git a/encoding/cborattr/pkg.yml b/encoding/cborattr/pkg.yml
index 99207ebfc..6f19678b5 100644
--- a/encoding/cborattr/pkg.yml
+++ b/encoding/cborattr/pkg.yml
@@ -6,7 +6,7 @@
# to you 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,
@@ -18,5 +18,12 @@
#
pkg.name: encoding/cborattr
-pkg.type: transient
-pkg.link: "@apache-mynewt-mcumgr/cborattr"
+pkg.description: CBOR encoding/decoding library
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - "@apache-mynewt-core/encoding/tinycbor"
+
+pkg.cflags.FLOAT_USER: -DFLOAT_SUPPORT
diff --git a/encoding/cborattr/src/cborattr.c b/encoding/cborattr/src/cborattr.c
new file mode 100644
index 000000000..797d96a6f
--- /dev/null
+++ b/encoding/cborattr/src/cborattr.c
@@ -0,0 +1,753 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "cborattr/cborattr.h"
+#include "tinycbor/cbor.h"
+#include "tinycbor/cbor_buf_reader.h"
+
+#ifdef __ZEPHYR__
+#include <zephyr/kernel.h>
+#ifdef CONFIG_MGMT_CBORATTR_MAX_SIZE
+#define CBORATTR_MAX_SIZE CONFIG_MGMT_CBORATTR_MAX_SIZE
+#else
+#define CBORATTR_MAX_SIZE 512
+#endif
+#endif
+
+#ifdef MYNEWT
+#include "syscfg/syscfg.h"
+#include "tinycbor/cbor_mbuf_reader.h"
+#include "tinycbor/cbor_mbuf_writer.h"
+#include "os/os_mbuf.h"
+#define CBORATTR_MAX_SIZE MYNEWT_VAL(CBORATTR_MAX_SIZE)
+#define CBORATTR_MAX_NESTING MYNEWT_VAL(CBORATTR_MAX_NESTING)
+#endif
+
+#ifndef CBORATTR_MAX_NESTING
+#define CBORATTR_MAX_NESTING 16
+#endif
+
+/* this maps a CborType to a matching CborAtter Type. The mapping is not
+ * one-to-one because of signedness of integers
+ * and therefore we need a function to do this trickery */
+static int
+valid_attr_type(CborType ct, CborAttrType at)
+{
+ switch (at) {
+ case CborAttrIntegerType:
+ case CborAttrUnsignedIntegerType:
+ if (ct == CborIntegerType) {
+ return 1;
+ }
+ break;
+ case CborAttrByteStringType:
+ if (ct == CborByteStringType) {
+ return 1;
+ }
+ break;
+ case CborAttrTextStringType:
+ if (ct == CborTextStringType) {
+ return 1;
+ }
+ break;
+ case CborAttrBooleanType:
+ if (ct == CborBooleanType) {
+ return 1;
+ }
+ break;
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ if (ct == CborHalfFloatType) {
+ return 1;
+ }
+ break;
+ case CborAttrFloatType:
+ if (ct == CborFloatType) {
+ return 1;
+ }
+ break;
+ case CborAttrDoubleType:
+ if (ct == CborDoubleType) {
+ return 1;
+ }
+ break;
+#endif
+ case CborAttrArrayType:
+ if (ct == CborArrayType) {
+ return 1;
+ }
+ break;
+ case CborAttrObjectType:
+ if (ct == CborMapType) {
+ return 1;
+ }
+ break;
+ case CborAttrNullType:
+ if (ct == CborNullType) {
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Advances past the value at *it. Unlike cbor_value_advance(), containers are
+ * walked iteratively with a fixed size stack, and values nested deeper than
+ * CBORATTR_MAX_NESTING are rejected with CborErrorNestingTooDeep.
+ */
+static CborError
+cborattr_advance(CborValue *it)
+{
+ CborValue stack[CBORATTR_MAX_NESTING];
+ CborValue *cur;
+ CborValue *parent;
+ CborError err;
+ int depth;
+
+ if (!cbor_value_is_container(it)) {
+ return cbor_value_advance(it);
+ }
+
+ err = cbor_value_enter_container(it, &stack[0]);
+ if (err) {
+ return err;
+ }
+ depth = 1;
+
+ while (depth > 0) {
+ cur = &stack[depth - 1];
+ if (cbor_value_at_end(cur)) {
+ parent = (depth == 1) ? it : &stack[depth - 2];
+ err = cbor_value_leave_container(parent, cur);
+ if (err) {
+ return err;
+ }
+ depth--;
+ } else if (cbor_value_is_container(cur)) {
+ if (depth >= CBORATTR_MAX_NESTING) {
+ return CborErrorNestingTooDeep;
+ }
+ err = cbor_value_enter_container(cur, &stack[depth]);
+ if (err) {
+ return err;
+ }
+ depth++;
+ } else {
+ err = cbor_value_advance(cur);
+ if (err) {
+ return err;
+ }
+ }
+ }
+
+ return CborNoError;
+}
+
+/* this function find the pointer to the memory location to
+ * write or read and attribute from the cbor_attr_r structure */
+static char *
+cbor_target_address(const struct cbor_attr_t *cursor,
+ const struct cbor_array_t *parent, int offset)
+{
+ char *targetaddr = NULL;
+
+ if (parent == NULL || parent->element_type != CborAttrStructObjectType) {
+ /* ordinary case - use the address in the cursor structure */
+ switch (cursor->type) {
+ case CborAttrNullType:
+ targetaddr = NULL;
+ break;
+ case CborAttrIntegerType:
+ targetaddr = (char *)&cursor->addr.integer[offset];
+ break;
+ case CborAttrUnsignedIntegerType:
+ targetaddr = (char *)&cursor->addr.uinteger[offset];
+ break;
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ targetaddr = (char *)&cursor->addr.halffloat[offset];
+ break;
+ case CborAttrFloatType:
+ targetaddr = (char *)&cursor->addr.fval[offset];
+ break;
+ case CborAttrDoubleType:
+ targetaddr = (char *)&cursor->addr.real[offset];
+ break;
+#endif
+ case CborAttrByteStringType:
+ targetaddr = (char *) cursor->addr.bytestring.data;
+ break;
+ case CborAttrTextStringType:
+ targetaddr = cursor->addr.string;
+ break;
+ case CborAttrBooleanType:
+ targetaddr = (char *)&cursor->addr.boolean[offset];
+ break;
+ default:
+ targetaddr = NULL;
+ break;
+ }
+ } else {
+ /* tricky case - hacking a member in an array of structures */
+ targetaddr =
+ parent->arr.objects.base + (offset * parent->arr.objects.stride) +
+ cursor->addr.offset;
+ }
+ return targetaddr;
+}
+
+static int
+cbor_internal_read_object(CborValue *root_value,
+ const struct cbor_attr_t *attrs,
+ const struct cbor_array_t *parent,
+ int offset)
+{
+ const struct cbor_attr_t *cursor, *best_match;
+ char attrbuf[CBORATTR_MAX_SIZE + 1];
+ void *lptr;
+ CborValue cur_value;
+ CborError err = 0;
+ size_t len = 0;
+ CborType type = CborInvalidType;
+
+ /* stuff fields with defaults in case they're omitted in the JSON input */
+ for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+ if (!cursor->nodefault) {
+ lptr = cbor_target_address(cursor, parent, offset);
+ if (lptr != NULL) {
+ switch (cursor->type) {
+ case CborAttrIntegerType:
+ memcpy(lptr, &cursor->dflt.integer, sizeof(long long int));
+ break;
+ case CborAttrUnsignedIntegerType:
+ memcpy(lptr, &cursor->dflt.integer,
+ sizeof(long long unsigned int));
+ break;
+ case CborAttrBooleanType:
+ memcpy(lptr, &cursor->dflt.boolean, sizeof(bool));
+ break;
+ case CborAttrTextStringType:
+ if (cursor->len > 0) {
+ *(char *)lptr = '\0';
+ }
+ break;
+ case CborAttrByteStringType:
+ if (cursor->addr.bytestring.len) {
+ *cursor->addr.bytestring.len = 0;
+ }
+ break;
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ memcpy(lptr, &cursor->dflt.halffloat, sizeof(uint16_t));
+ break;
+ case CborAttrFloatType:
+ memcpy(lptr, &cursor->dflt.fval, sizeof(float));
+ break;
+ case CborAttrDoubleType:
+ memcpy(lptr, &cursor->dflt.real, sizeof(double));
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (cbor_value_is_map(root_value)) {
+ err |= cbor_value_enter_container(root_value, &cur_value);
+ } else {
+ err |= CborErrorIllegalType;
+ return err;
+ }
+
+ /* contains key value pairs */
+ while (cbor_value_is_valid(&cur_value) && !err) {
+ /* get the attribute */
+ if (cbor_value_is_text_string(&cur_value)) {
+ err |= cbor_value_calculate_string_length(&cur_value, &len);
+ if (err) {
+ break;
+ }
+ if (len > CBORATTR_MAX_SIZE) {
+ err |= CborErrorDataTooLarge;
+ break;
+ }
+ err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len,
+ NULL);
+
+ /* at least get the type of the next value so we can match the
+ * attribute name and type for a perfect match */
+ err |= cborattr_advance(&cur_value);
+ if (cbor_value_is_valid(&cur_value)) {
+ type = cbor_value_get_type(&cur_value);
+ } else {
+ err |= CborErrorIllegalType;
+ break;
+ }
+ } else {
+ attrbuf[0] = '\0';
+ type = cbor_value_get_type(&cur_value);
+ }
+
+ /* find this attribute in our list */
+ best_match = NULL;
+ for (cursor = attrs; cursor->attribute != NULL; cursor++) {
+ if (valid_attr_type(type, cursor->type)) {
+ if (cursor->attribute == CBORATTR_ATTR_UNNAMED &&
+ attrbuf[0] == '\0') {
+ best_match = cursor;
+ } else if (strlen(cursor->attribute) == len &&
+ !memcmp(cursor->attribute, attrbuf, len)) {
+ break;
+ }
+ }
+ }
+ if (!cursor->attribute && best_match) {
+ cursor = best_match;
+ }
+ /* we found a match */
+ if (cursor->attribute != NULL) {
+ lptr = cbor_target_address(cursor, parent, offset);
+ switch (cursor->type) {
+ case CborAttrNullType:
+ /* nothing to do */
+ break;
+ case CborAttrBooleanType:
+ err |= cbor_value_get_boolean(&cur_value, lptr);
+ break;
+ case CborAttrIntegerType:
+ err |= cbor_value_get_int64(&cur_value, lptr);
+ break;
+ case CborAttrUnsignedIntegerType:
+ err |= cbor_value_get_uint64(&cur_value, lptr);
+ break;
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ err |= cbor_value_get_half_float(&cur_value, lptr);
+ break;
+ case CborAttrFloatType:
+ err |= cbor_value_get_float(&cur_value, lptr);
+ break;
+ case CborAttrDoubleType:
+ err |= cbor_value_get_double(&cur_value, lptr);
+ break;
+#endif
+ case CborAttrByteStringType: {
+ size_t len = cursor->len;
+ CborError copy_err;
+
+ copy_err = cbor_value_copy_byte_string(&cur_value, lptr,
+ &len, NULL);
+ err |= copy_err;
+ /* On error len is set to string length, not copied length */
+ *cursor->addr.bytestring.len = copy_err ? 0 : len;
+ break;
+ }
+ case CborAttrTextStringType: {
+ size_t len;
+ CborError copy_err;
+
+ if (cursor->len < 1) {
+ err |= CborErrorOutOfMemory;
+ break;
+ }
+ /* Reserve space for terminating NUL */
+ len = cursor->len - 1;
+ copy_err = cbor_value_copy_text_string(&cur_value, lptr,
+ &len, NULL);
+ err |= copy_err;
+ ((char *)lptr)[copy_err ? 0 : len] = '\0';
+ break;
+ }
+ case CborAttrArrayType:
+ err |= cbor_read_array(&cur_value, &cursor->addr.array);
+ continue;
+ case CborAttrObjectType:
+ err |= cbor_internal_read_object(&cur_value, cursor->addr.obj,
+ NULL, 0);
+ continue;
+ default:
+ err |= CborErrorIllegalType;
+ }
+ }
+ err |= cborattr_advance(&cur_value);
+ }
+ if (!err) {
+ /* that should be it for this container */
+ err |= cbor_value_leave_container(root_value, &cur_value);
+ }
+ return err;
+}
+
+int
+cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr)
+{
+ CborError err = 0;
+ CborError adv_err = CborNoError;
+ struct CborValue elem;
+ int off, arrcount;
+ size_t len;
+ void *lptr;
+ char *tp;
+
+ err = cbor_value_enter_container(value, &elem);
+ if (err) {
+ return err;
+ }
+ arrcount = 0;
+ tp = arr->arr.strings.store;
+ for (off = 0; off < arr->maxlen; off++) {
+ switch (arr->element_type) {
+ case CborAttrBooleanType:
+ lptr = &arr->arr.booleans.store[off];
+ err |= cbor_value_get_boolean(&elem, lptr);
+ break;
+ case CborAttrIntegerType:
+ lptr = &arr->arr.integers.store[off];
+ err |= cbor_value_get_int64(&elem, lptr);
+ break;
+ case CborAttrUnsignedIntegerType:
+ lptr = &arr->arr.uintegers.store[off];
+ err |= cbor_value_get_uint64(&elem, lptr);
+ break;
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ lptr = &arr->arr.halffloats.store[off];
+ err |= cbor_value_get_half_float(&elem, lptr);
+ break;
+ case CborAttrFloatType:
+ case CborAttrDoubleType:
+ lptr = &arr->arr.reals.store[off];
+ err |= cbor_value_get_double(&elem, lptr);
+ break;
+#endif
+ case CborAttrTextStringType:
+ len = arr->arr.strings.storelen - (tp - arr->arr.strings.store);
+ if (len < 1) {
+ err |= CborErrorOutOfMemory;
+ break;
+ }
+ /* Reserve space for terminating NUL */
+ len--;
+ err |= cbor_value_copy_text_string(&elem, tp, &len, NULL);
+ if (err) {
+ break;
+ }
+ tp[len] = '\0';
+ arr->arr.strings.ptrs[off] = tp;
+ tp += len + 1;
+ break;
+ case CborAttrStructObjectType:
+ err |= cbor_internal_read_object(&elem, arr->arr.objects.subtype,
+ arr, off);
+ break;
+ default:
+ err |= CborErrorIllegalType;
+ break;
+ }
+ if (err) {
+ break;
+ }
+ arrcount++;
+ if (arr->element_type != CborAttrStructObjectType) {
+ adv_err = cborattr_advance(&elem);
+ err |= adv_err;
+ if (adv_err) {
+ /* elem was not advanced, no further progress is possible */
+ break;
+ }
+ }
+ if (!cbor_value_is_valid(&elem)) {
+ break;
+ }
+ }
+ if (arr->count) {
+ *arr->count = arrcount;
+ }
+ while (!adv_err && !cbor_value_at_end(&elem)) {
+ err |= CborErrorDataTooLarge;
+ adv_err = cborattr_advance(&elem);
+ err |= adv_err;
+ }
+ if (adv_err) {
+ /* elem is not at the end of container so it cannot be left */
+ return err;
+ }
+ err |= cbor_value_leave_container(value, &elem);
+ return err;
+}
+
+int
+cbor_read_object(struct CborValue *value, const struct cbor_attr_t *attrs)
+{
+ int st;
+
+ st = cbor_internal_read_object(value, attrs, NULL, 0);
+ return st;
+}
+
+/*
+ * Read in cbor key/values from flat buffer pointed by data, and fill them
+ * into attrs.
+ *
+ * @param data Pointer to beginning of cbor encoded data
+ * @param len Number of bytes in the buffer
+ * @param attrs Array of cbor objects to look for.
+ *
+ * @return 0 on success; non-zero on failure.
+ */
+int
+cbor_read_flat_attrs(const uint8_t *data, int len,
+ const struct cbor_attr_t *attrs)
+{
+ struct cbor_buf_reader reader;
+ struct CborParser parser;
+ struct CborValue value;
+ CborError err;
+
+ cbor_buf_reader_init(&reader, data, len);
+ err = cbor_parser_init(&reader.r, 0, &parser, &value);
+ if (err != CborNoError) {
+ return -1;
+ }
+ return cbor_read_object(&value, attrs);
+}
+
+#ifdef MYNEWT
+static int cbor_write_val(struct CborEncoder *enc,
+ const struct cbor_out_val_t *val);
+
+/*
+ * Read in cbor key/values from os_mbuf pointed by m, and fill them
+ * into attrs.
+ *
+ * @param m Pointer to os_mbuf containing cbor encoded data
+ * @param off Offset into mbuf where cbor data begins
+ * @param len Number of bytes to decode
+ * @param attrs Array of cbor objects to look for.
+ *
+ * @return 0 on success; non-zero on failure.
+ */
+int
+cbor_read_mbuf_attrs(struct os_mbuf *m, uint16_t off, uint16_t len,
+ const struct cbor_attr_t *attrs)
+{
+ struct cbor_mbuf_reader cmr;
+ struct CborParser parser;
+ struct CborValue value;
+ CborError err;
+
+ cbor_mbuf_reader_init(&cmr, m, off);
+ err = cbor_parser_init(&cmr.r, 0, &parser, &value);
+ if (err != CborNoError) {
+ return -1;
+ }
+ return cbor_read_object(&value, attrs);
+}
+
+static int
+cbor_write_arr_val(struct CborEncoder *enc,
+ const struct cbor_out_arr_val_t *arr)
+{
+ struct CborEncoder arr_enc;
+ size_t i;
+ int rc;
+
+ rc = cbor_encoder_create_array(enc, &arr_enc, arr->len);
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+
+ for (i = 0; i < arr->len; i++) {
+ rc = cbor_write_val(&arr_enc, &arr->elems[i]);
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+ }
+
+ rc = cbor_encoder_close_container(enc, &arr_enc);
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+
+ return 0;
+}
+
+static int
+cbor_write_val(struct CborEncoder *enc, const struct cbor_out_val_t *val)
+{
+ int len;
+ int rc;
+
+ switch (val->type) {
+ case CborAttrNullType:
+ rc = cbor_encode_null(enc);
+ break;
+
+ case CborAttrBooleanType:
+ rc = cbor_encode_boolean(enc, val->boolean);
+ break;
+
+ case CborAttrIntegerType:
+ rc = cbor_encode_int(enc, val->integer);
+ break;
+
+ case CborAttrUnsignedIntegerType:
+ rc = cbor_encode_uint(enc, val->uinteger);
+ break;
+
+#if FLOAT_SUPPORT
+ case CborAttrHalfFloatType:
+ rc = cbor_encode_half_float(enc, &val->halffloat);
+ break;
+
+ case CborAttrFloatType:
+ rc = cbor_encode_float(enc, val->fval);
+ break;
+
+ case CborAttrDoubleType:
+ rc = cbor_encode_double(enc, val->real);
+ break;
+#endif
+
+ case CborAttrByteStringType:
+ if (val->bytestring.data == NULL &&
+ val->bytestring.len != 0) {
+
+ return SYS_EINVAL;
+ }
+
+ rc = cbor_encode_byte_string(enc, val->bytestring.data,
+ val->bytestring.len);
+ break;
+
+ case CborAttrTextStringType:
+ if (val->string == NULL) {
+ len = 0;
+ } else {
+ len = strlen(val->string);
+ }
+ rc = cbor_encode_text_string(enc, val->string, len);
+ break;
+
+ case CborAttrObjectType:
+ rc = cbor_write_object(enc, val->obj);
+ break;
+
+ case CborAttrArrayType:
+ rc = cbor_write_arr_val(enc, &val->array);
+ break;
+
+ default:
+ return SYS_ENOTSUP;
+ }
+
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+
+ return 0;
+}
+
+static int
+cbor_write_attr(struct CborEncoder *enc, const struct cbor_out_attr_t *attr)
+{
+ int len;
+ int rc;
+
+ if (attr->omit) {
+ return 0;
+ }
+
+ if (!attr->attribute) {
+ rc = SYS_EINVAL;
+ return rc;
+ }
+
+ len = strlen(attr->attribute);
+ rc = cbor_encode_text_string(enc, attr->attribute, len);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = cbor_write_val(enc, &attr->val);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+cbor_write_object(struct CborEncoder *enc, const struct cbor_out_attr_t *attrs)
+{
+ const struct cbor_out_attr_t *attr;
+ struct CborEncoder map;
+ int rc;
+
+ rc = cbor_encoder_create_map(enc, &map, CborIndefiniteLength);
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+
+ for (attr = attrs; attr->val.type != 0; attr++) {
+ rc = cbor_write_attr(&map, attr);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+
+ rc = cbor_encoder_close_container(enc, &map);
+ if (rc != 0) {
+ return SYS_ENOMEM;
+ }
+
+ return 0;
+}
+
+int
+cbor_write_object_msys(const struct cbor_out_attr_t *attrs,
+ struct os_mbuf **out_om)
+{
+ struct cbor_mbuf_writer writer;
+ struct CborEncoder encoder;
+ int rc;
+
+ *out_om = os_msys_get_pkthdr(0, 0);
+ if (*out_om == NULL) {
+ return SYS_ENOMEM;
+ }
+
+ cbor_mbuf_writer_init(&writer, *out_om);
+ cbor_encoder_init(&encoder, &writer.enc, 0);
+
+ rc = cbor_write_object(&encoder, attrs);
+ if (rc != 0) {
+ os_mbuf_free_chain(*out_om);
+ *out_om = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+#endif
diff --git a/encoding/cborattr/pkg.yml b/encoding/cborattr/syscfg.yml
similarity index 68%
copy from encoding/cborattr/pkg.yml
copy to encoding/cborattr/syscfg.yml
index 99207ebfc..793ff7549 100644
--- a/encoding/cborattr/pkg.yml
+++ b/encoding/cborattr/syscfg.yml
@@ -1,4 +1,3 @@
-#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -17,6 +16,14 @@
# under the License.
#
-pkg.name: encoding/cborattr
-pkg.type: transient
-pkg.link: "@apache-mynewt-mcumgr/cborattr"
+# Package: mgmt/imgmgr
+
+syscfg.defs:
+ CBORATTR_MAX_SIZE:
+ description: 'The maximum size of a CBOR attribute during decoding'
+ value: 512
+ CBORATTR_MAX_NESTING:
+ description: >
+ Maximum nesting depth of CBOR containers that can be skipped
+ while decoding. Values nested deeper are rejected.
+ value: 16
diff --git a/encoding/cborattr/pkg.yml b/encoding/cborattr/test/pkg.yml
similarity index 63%
copy from encoding/cborattr/pkg.yml
copy to encoding/cborattr/test/pkg.yml
index 99207ebfc..df0c50a8b 100644
--- a/encoding/cborattr/pkg.yml
+++ b/encoding/cborattr/test/pkg.yml
@@ -1,4 +1,3 @@
-#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
@@ -6,7 +5,7 @@
# to you 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,
@@ -16,7 +15,18 @@
# specific language governing permissions and limitations
# under the License.
#
+pkg.name: encoding/cborattr/test
+pkg.type: unittest
+pkg.description: "CBOR attr unit tests."
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - '@apache-mynewt-core/encoding/tinycbor'
+ - '@apache-mynewt-core/encoding/cborattr'
-pkg.name: encoding/cborattr
-pkg.type: transient
-pkg.link: "@apache-mynewt-mcumgr/cborattr"
+pkg.deps.SELFTEST:
+ - '@apache-mynewt-core/sys/console/stub'
+ - '@apache-mynewt-core/sys/log/full'
+ - '@apache-mynewt-core/test/testutil'
diff --git a/encoding/cborattr/test/src/test_cborattr.c b/encoding/cborattr/test/src/test_cborattr.c
new file mode 100644
index 000000000..e3406286e
--- /dev/null
+++ b/encoding/cborattr/test/src/test_cborattr.c
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+
+TEST_SUITE(test_cborattr_suite)
+{
+ test_cborattr_decode1();
+ test_cborattr_decode_partial();
+ test_cborattr_decode_simple();
+ test_cborattr_decode_object();
+ test_cborattr_decode_int_array();
+ test_cborattr_decode_bool_array();
+ test_cborattr_decode_string_array();
+ test_cborattr_decode_object_array();
+ test_cborattr_decode_unnamed_array();
+ test_cborattr_decode_substring_key();
+ test_cborattr_decode_nesting();
+ test_cborattr_decode_string_bounds();
+ test_cborattr_decode_string_array_bounds();
+}
+
+#if MYNEWT_VAL(SELFTEST)
+int
+main(int argc, char **argv)
+{
+ sysinit();
+
+ test_cborattr_suite();
+
+ return tu_any_failed;
+}
+#endif
diff --git a/encoding/cborattr/test/src/test_cborattr.h b/encoding/cborattr/test/src/test_cborattr.h
new file mode 100644
index 000000000..d423f25e0
--- /dev/null
+++ b/encoding/cborattr/test/src/test_cborattr.h
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 TEST_CBORATTR_H
+#define TEST_CBORATTR_H
+
+#include <assert.h>
+#include <string.h>
+#include "testutil/testutil.h"
+#include "test_cborattr.h"
+#include "tinycbor/cbor.h"
+#include "cborattr/cborattr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Returns test data.
+ */
+const uint8_t *test_str1(int *len);
+
+void cborattr_test_util_encode(const struct cbor_out_attr_t *attrs,
+ const uint8_t *expected, int len);
+/*
+ * Testcases
+ */
+TEST_CASE_DECL(test_cborattr_decode1);
+TEST_CASE_DECL(test_cborattr_decode_partial);
+TEST_CASE_DECL(test_cborattr_decode_simple);
+TEST_CASE_DECL(test_cborattr_decode_object);
+TEST_CASE_DECL(test_cborattr_decode_int_array);
+TEST_CASE_DECL(test_cborattr_decode_bool_array);
+TEST_CASE_DECL(test_cborattr_decode_string_array);
+TEST_CASE_DECL(test_cborattr_decode_object_array);
+TEST_CASE_DECL(test_cborattr_decode_unnamed_array);
+TEST_CASE_DECL(test_cborattr_decode_substring_key);
+TEST_CASE_DECL(test_cborattr_decode_nesting);
+TEST_CASE_DECL(test_cborattr_decode_string_bounds);
+TEST_CASE_DECL(test_cborattr_decode_string_array_bounds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TEST_CBORATTR_H */
+
diff --git a/encoding/cborattr/test/src/test_cborattr_utils.c b/encoding/cborattr/test/src/test_cborattr_utils.c
new file mode 100644
index 000000000..d520e069c
--- /dev/null
+++ b/encoding/cborattr/test/src/test_cborattr_utils.c
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+/*
+ * {"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"}
+ */
+static const uint8_t test_data1[] = {
+ 0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
+ 0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
+ 0x44, 0x61, 0x65, 0x61, 0x45
+};
+
+const uint8_t *
+test_str1(int *len)
+{
+ *len = sizeof(test_data1);
+ return (test_data1);
+}
+
+void
+cborattr_test_util_encode(const struct cbor_out_attr_t *attrs,
+ const uint8_t *expected, int len)
+{
+ struct os_mbuf *om;
+ int rc;
+
+ rc = cbor_write_object_msys(attrs, &om);
+ TEST_ASSERT_FATAL(rc == 0);
+
+ TEST_ASSERT(os_mbuf_cmpf(om, 0, expected, len) == 0);
+
+ os_mbuf_free_chain(om);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode1.c b/encoding/cborattr/test/src/testcases/cborattr_decode1.c
new file mode 100644
index 000000000..1b6cddf48
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode1.c
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode1)
+{
+ const uint8_t *data;
+ int len;
+ int rc;
+ char test_str_a[4] = { '\0' };
+ char test_str_b[4] = { '\0' };
+ char test_str_c[4] = { '\0' };
+ char test_str_d[4] = { '\0' };
+ char test_str_e[4] = { '\0' };
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_a,
+ .len = sizeof(test_str_a),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "b",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_b,
+ .len = sizeof(test_str_b),
+ .nodefault = true
+ },
+ [2] = {
+ .attribute = "c",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_c,
+ .len = sizeof(test_str_c),
+ .nodefault = true
+ },
+ [3] = {
+ .attribute = "d",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_d,
+ .len = sizeof(test_str_d),
+ .nodefault = true,
+ },
+ [4] = {
+ .attribute = "e",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_e,
+ .len = sizeof(test_str_e),
+ .nodefault = true,
+ },
+ [5] = {
+ .attribute = NULL
+ }
+ };
+
+ data = test_str1(&len);
+ rc = cbor_read_flat_attrs(data, len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(!strcmp(test_str_a, "A"));
+ TEST_ASSERT(!strcmp(test_str_b, "B"));
+ TEST_ASSERT(!strcmp(test_str_c, "C"));
+ TEST_ASSERT(!strcmp(test_str_d, "D"));
+ TEST_ASSERT(!strcmp(test_str_e, "E"));
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_bool_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_bool_array.c
new file mode 100644
index 000000000..71520c428
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_bool_array.c
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_bool_array(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: [true,true,false]
+ */
+ cbor_encode_text_stringz(&data, "a");
+
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+ cbor_encode_boolean(&array, true);
+ cbor_encode_boolean(&array, true);
+ cbor_encode_boolean(&array, false);
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * array of booleans
+ */
+TEST_CASE(test_cborattr_decode_bool_array)
+{
+ int rc;
+ bool arr_data[5];
+ int arr_cnt = 0;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrBooleanType,
+ .addr.array.arr.booleans.store = arr_data,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_bool_array();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 3);
+ TEST_ASSERT(arr_data[0] == true);
+ TEST_ASSERT(arr_data[1] == true);
+ TEST_ASSERT(arr_data[2] == false);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_int_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_int_array.c
new file mode 100644
index 000000000..fde602cc7
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_int_array.c
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_int_array(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: [1,2,33,15,-4]
+ */
+ cbor_encode_text_stringz(&data, "a");
+
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+ cbor_encode_int(&array, 1);
+ cbor_encode_int(&array, 2);
+ cbor_encode_int(&array, 33);
+ cbor_encode_int(&array, 15);
+ cbor_encode_int(&array, -4);
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_int_array)
+{
+ int rc;
+ long long int arr_data[5];
+ long long int b_int;
+ int arr_cnt = 0;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrIntegerType,
+ .addr.array.arr.integers.store = arr_data,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "b",
+ .type = CborAttrIntegerType,
+ .addr.integer = &b_int,
+ .dflt.integer = 1
+ },
+ [2] = {
+ .attribute = NULL
+ }
+ };
+ struct cbor_attr_t test_attrs_small[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrIntegerType,
+ .addr.array.arr.integers.store = arr_data,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = 1,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "b",
+ .type = CborAttrIntegerType,
+ .addr.integer = &b_int,
+ .dflt.integer = 1
+ },
+ [2] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_int_array();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 5);
+ TEST_ASSERT(arr_data[0] == 1);
+ TEST_ASSERT(arr_data[1] == 2);
+ TEST_ASSERT(arr_data[2] == 33);
+ TEST_ASSERT(arr_data[3] == 15);
+ TEST_ASSERT(arr_data[4] == -4);
+ TEST_ASSERT(b_int == 1);
+
+ memset(arr_data, 0, sizeof(arr_data));
+ b_int = 0;
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs_small);
+ TEST_ASSERT(rc == CborErrorDataTooLarge);
+ TEST_ASSERT(arr_cnt == 1);
+ TEST_ASSERT(arr_data[0] == 1);
+ TEST_ASSERT(arr_data[1] == 0);
+ TEST_ASSERT(b_int == 1);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_nesting.c b/encoding/cborattr/test/src/testcases/cborattr_decode_nesting.c
new file mode 100644
index 000000000..4d8524fe6
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_nesting.c
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+#define TEST_NESTING_DEEP 200
+
+static uint8_t test_nesting_buf[TEST_NESTING_DEEP + 32];
+
+/*
+ * Encodes {"a": 1, "x": <value>} or {"a": [1, <value>]} where value is an
+ * integer nested in specified number of single element arrays.
+ */
+static int
+test_nesting_encode(int depth, bool in_array)
+{
+ int len = 0;
+ int i;
+
+ test_nesting_buf[len++] = in_array ? 0xa1 : 0xa2;
+ test_nesting_buf[len++] = 0x61;
+ test_nesting_buf[len++] = 'a';
+ if (in_array) {
+ test_nesting_buf[len++] = 0x82;
+ test_nesting_buf[len++] = 0x01;
+ } else {
+ test_nesting_buf[len++] = 0x01;
+ test_nesting_buf[len++] = 0x61;
+ test_nesting_buf[len++] = 'x';
+ }
+ for (i = 0; i < depth; i++) {
+ test_nesting_buf[len++] = 0x81;
+ }
+ test_nesting_buf[len++] = 0x00;
+
+ return len;
+}
+
+TEST_CASE_SELF(test_cborattr_decode_nesting)
+{
+ long long int a;
+ long long int arr[1];
+ int arr_cnt;
+ int len;
+ int rc;
+
+ const struct cbor_attr_t attrs[] = {
+ {
+ .attribute = "a",
+ .type = CborAttrIntegerType,
+ .addr.integer = &a,
+ },
+ { 0 },
+ };
+ const struct cbor_attr_t arr_attrs[] = {
+ {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrIntegerType,
+ .addr.array.arr.integers.store = arr,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = 1,
+ },
+ { 0 },
+ };
+
+ /* Unknown attribute with nested value is skipped. */
+ len = test_nesting_encode(4, false);
+ a = 0;
+ rc = cbor_read_flat_attrs(test_nesting_buf, len, attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(a == 1);
+
+ /* Value nested deeper than allowed is rejected. */
+ len = test_nesting_encode(TEST_NESTING_DEEP, false);
+ rc = cbor_read_flat_attrs(test_nesting_buf, len, attrs);
+ TEST_ASSERT(rc != 0);
+
+ /* Excess array element nested deeper than allowed is rejected. */
+ len = test_nesting_encode(TEST_NESTING_DEEP, true);
+ rc = cbor_read_flat_attrs(test_nesting_buf, len, arr_attrs);
+ TEST_ASSERT(rc != 0);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_obj_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_obj_array.c
new file mode 100644
index 000000000..57c46cdf2
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_obj_array.c
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_obj_array(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+ CborEncoder obj;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: [{ n:"a", v:1}, {n:"b", v:2} ]
+ */
+ cbor_encode_text_stringz(&data, "a");
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+ cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&obj, "n");
+ cbor_encode_text_stringz(&obj, "a");
+ cbor_encode_text_stringz(&obj, "v");
+ cbor_encode_int(&obj, 1);
+ cbor_encoder_close_container(&array, &obj);
+
+ cbor_encoder_create_map(&array, &obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&obj, "n");
+ cbor_encode_text_stringz(&obj, "b");
+ cbor_encode_text_stringz(&obj, "v");
+ cbor_encode_int(&obj, 2);
+ cbor_encoder_close_container(&array, &obj);
+
+ cbor_encoder_close_container(&data, &array);
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_obj_array)
+{
+ int rc;
+ char arr_data[4];
+ int arr_cnt;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrNullType,
+ .addr.array.arr.objects.base = arr_data,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = 4,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_obj_array();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 2);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_object.c b/encoding/cborattr/test/src/testcases/cborattr_decode_object.c
new file mode 100644
index 000000000..81e6f9231
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_object.c
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_data(void)
+{
+ CborEncoder test_data;
+ CborEncoder sub_obj;
+
+ test_cbor_len = 0;
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+ cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+ /*
+ * p: { bm : 7 }
+ */
+ cbor_encode_text_stringz(&test_data, "p");
+
+ cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&test_data, "bm");
+ cbor_encode_int(&test_data, 7);
+ cbor_encoder_close_container(&test_data, &sub_obj);
+
+ cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+static void
+test_encode_data_complex(void)
+{
+ CborEncoder test_data;
+ CborEncoder sub_obj;
+ CborEncoder sub_sub_obj;
+
+ test_cbor_len = 0;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+ cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+
+ /*
+ * p: { bm : 7 }, c: { d : { i : 1 } }, a: 3
+ */
+ cbor_encode_text_stringz(&test_data, "p");
+
+ cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&test_data, "bm");
+ cbor_encode_int(&test_data, 7);
+ cbor_encoder_close_container(&test_data, &sub_obj);
+
+ cbor_encode_text_stringz(&test_data, "c");
+ cbor_encoder_create_map(&test_data, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&sub_obj, "d");
+
+ cbor_encoder_create_map(&sub_obj, &sub_sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&sub_sub_obj, "i");
+ cbor_encode_int(&sub_sub_obj, 1);
+ cbor_encoder_close_container(&sub_obj, &sub_sub_obj);
+ cbor_encoder_close_container(&test_data, &sub_obj);
+
+ cbor_encode_text_stringz(&test_data, "a");
+ cbor_encode_int(&test_data, 3);
+
+ cbor_encoder_close_container(&test_encoder, &test_data);
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_object)
+{
+ int rc;
+ long long int bm_val = 0;
+ struct cbor_attr_t test_sub_attr_bm[] = {
+ [0] = {
+ .attribute = "bm",
+ .type = CborAttrIntegerType,
+ .addr.integer = &bm_val,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "p",
+ .type = CborAttrObjectType,
+ .addr.obj = test_sub_attr_bm,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+ long long int a_val = 0;
+ long long int i_val = 0;
+ struct cbor_attr_t test_sub_sub_attr[] = {
+ [0] = {
+ .attribute = "i",
+ .type = CborAttrIntegerType,
+ .addr.integer = &i_val,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+ struct cbor_attr_t test_sub_attr_d[] = {
+ [0] = {
+ .attribute = "d",
+ .type = CborAttrObjectType,
+ .addr.obj = test_sub_sub_attr,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+ struct cbor_attr_t test_attr_complex[] = {
+ [0] = {
+ .attribute = "c",
+ .type = CborAttrObjectType,
+ .addr.obj = test_sub_attr_d,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "a",
+ .type = CborAttrIntegerType,
+ .addr.integer = &a_val,
+ .nodefault = true
+ },
+ [2] = {
+ .attribute = "p",
+ .type = CborAttrObjectType,
+ .addr.obj = test_sub_attr_bm,
+ .nodefault = true
+ },
+ [3] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_data();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(bm_val == 7);
+
+ test_encode_data_complex();
+
+ bm_val = 0;
+ i_val = 0;
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attr_complex);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(bm_val == 7);
+ TEST_ASSERT(i_val == 1);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_object_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_object_array.c
new file mode 100644
index 000000000..82cc34f17
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_object_array.c
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_object_array(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+ CborEncoder sub_obj;
+
+ test_cbor_len = 0;
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: [ { h:"str1"}, {h:"2str"}, {h:"str3"}]
+ */
+ cbor_encode_text_stringz(&data, "a");
+
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+
+ cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&sub_obj, "h");
+ cbor_encode_text_stringz(&sub_obj, "str1");
+ cbor_encoder_close_container(&array, &sub_obj);
+
+ cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&sub_obj, "h");
+ cbor_encode_text_stringz(&sub_obj, "2str");
+ cbor_encoder_close_container(&array, &sub_obj);
+
+ cbor_encoder_create_map(&array, &sub_obj, CborIndefiniteLength);
+ cbor_encode_text_stringz(&sub_obj, "h");
+ cbor_encode_text_stringz(&sub_obj, "str3");
+ cbor_encoder_close_container(&array, &sub_obj);
+
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * object array
+ */
+TEST_CASE(test_cborattr_decode_object_array)
+{
+ int rc;
+ struct h_obj {
+ char h_data[32];
+ } arr_objs[5];
+ int arr_cnt = 0;
+ struct cbor_attr_t sub_attr[] = {
+ [0] = {
+ .attribute = "h",
+ .type = CborAttrTextStringType,
+ CBORATTR_STRUCT_OBJECT(struct h_obj, h_data),
+ .len = sizeof(arr_objs[0].h_data)
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ CBORATTR_STRUCT_ARRAY(arr_objs, sub_attr, &arr_cnt),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_object_array();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 3);
+ TEST_ASSERT(!strcmp(arr_objs[0].h_data, "str1"));
+ TEST_ASSERT(!strcmp(arr_objs[1].h_data, "2str"));
+ TEST_ASSERT(!strcmp(arr_objs[2].h_data, "str3"));
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_partial.c b/encoding/cborattr/test/src/testcases/cborattr_decode_partial.c
new file mode 100644
index 000000000..df0b8d4f5
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_partial.c
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Simple decoding. Only have key for one of the key/value pairs.
+ */
+TEST_CASE(test_cborattr_decode_partial)
+{
+ const uint8_t *data;
+ int len;
+ int rc;
+ char test_str_b[4] = { '\0' };
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "b",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_b,
+ .len = sizeof(test_str_b),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ data = test_str1(&len);
+ rc = cbor_read_flat_attrs(data, len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(!strcmp(test_str_b, "B"));
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_simple.c b/encoding/cborattr/test/src/testcases/cborattr_decode_simple.c
new file mode 100644
index 000000000..aef3a8078
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_simple.c
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_data(void)
+{
+ CborEncoder test_data;
+ uint8_t data[4] = { 0, 1, 2 };
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &test_data, CborIndefiniteLength);
+ /*
+ * a:22
+ */
+ cbor_encode_text_stringz(&test_data, "a");
+ cbor_encode_uint(&test_data, 22);
+
+ /*
+ * b:-13
+ */
+ cbor_encode_text_stringz(&test_data, "b");
+ cbor_encode_int(&test_data, -13);
+
+ /*
+ * c:0x000102
+ */
+ cbor_encode_text_stringz(&test_data, "c");
+ cbor_encode_byte_string(&test_data, data, 3);
+ cbor_encoder_close_container(&test_encoder, &test_data);
+
+ /*
+ * XXX add other data types to encode here.
+ */
+
+}
+
+/*
+ * Simple decoding.
+ */
+TEST_CASE(test_cborattr_decode_simple)
+{
+ int rc;
+ long long unsigned int a_val = 0;
+ long long int b_val = 0;
+ uint8_t c_data[4];
+ size_t c_len;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrIntegerType,
+ .addr.uinteger = &a_val,
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "b",
+ .type = CborAttrIntegerType,
+ .addr.integer = &b_val,
+ .nodefault = true
+ },
+ [2] = {
+ .attribute = "c",
+ .type = CborAttrByteStringType,
+ .addr.bytestring.data = c_data,
+ .addr.bytestring.len = &c_len,
+ .len = sizeof(c_data)
+ },
+ [3] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_data();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(a_val == 22);
+ TEST_ASSERT(b_val == -13);
+ TEST_ASSERT(c_len == 3);
+ TEST_ASSERT(c_data[0] == 0 && c_data[1] == 1 && c_data[2] == 2);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_string_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_string_array.c
new file mode 100644
index 000000000..d68e8dfaf
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_string_array.c
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_string_array_one(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+
+ test_cbor_len = 0;
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: ["asdf"]
+ */
+ cbor_encode_text_stringz(&data, "a");
+
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+ cbor_encode_text_stringz(&array, "asdf");
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+static void
+test_encode_string_array_three(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+
+ test_cbor_len = 0;
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * a: ["asdf", "k", "blurb"]
+ */
+ cbor_encode_text_stringz(&data, "a");
+
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+ cbor_encode_text_stringz(&array, "asdf");
+ cbor_encode_text_stringz(&array, "k");
+ cbor_encode_text_stringz(&array, "blurb");
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * string array
+ */
+TEST_CASE(test_cborattr_decode_string_array)
+{
+ int rc;
+ char *str_ptrs[5];
+ char arr_data[256];
+ int arr_cnt = 0;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrTextStringType,
+ .addr.array.arr.strings.ptrs = str_ptrs,
+ .addr.array.arr.strings.store = arr_data,
+ .addr.array.arr.strings.storelen = sizeof(arr_data),
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_string_array_one();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 1);
+ TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+
+ test_encode_string_array_three();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 3);
+ TEST_ASSERT(!strcmp(str_ptrs[0], "asdf"));
+ TEST_ASSERT(!strcmp(str_ptrs[1], "k"));
+ TEST_ASSERT(!strcmp(str_ptrs[2], "blurb"));
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_string_array_bounds.c b/encoding/cborattr/test/src/testcases/cborattr_decode_string_array_bounds.c
new file mode 100644
index 000000000..b0a2ce432
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_string_array_bounds.c
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+static uint8_t test_arr_buf[64];
+static int test_arr_len;
+
+static int
+test_arr_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_arr_buf + test_arr_len, data, len);
+ test_arr_len += len;
+ assert(test_arr_len < sizeof(test_arr_buf));
+ return 0;
+}
+
+/* Encodes {"a": [strs...]} */
+static void
+test_arr_encode(const char **strs, int cnt)
+{
+ struct cbor_encoder_writer writer = { .write = test_arr_wr };
+ CborEncoder enc;
+ CborEncoder map;
+ CborEncoder arr;
+ int i;
+
+ test_arr_len = 0;
+ cbor_encoder_init(&enc, &writer, 0);
+ cbor_encoder_create_map(&enc, &map, CborIndefiniteLength);
+ cbor_encode_text_stringz(&map, "a");
+ cbor_encoder_create_array(&map, &arr, CborIndefiniteLength);
+ for (i = 0; i < cnt; i++) {
+ cbor_encode_text_stringz(&arr, strs[i]);
+ }
+ cbor_encoder_close_container(&map, &arr);
+ cbor_encoder_close_container(&enc, &map);
+}
+
+TEST_CASE_SELF(test_cborattr_decode_string_array_bounds)
+{
+ const char *fit[] = { "ab", "cd" };
+ const char *no_fit[] = { "abcdefgh", "zzzzzzzzzzzz", "zzzzzzzzzzzz" };
+ struct {
+ char store[8];
+ char guard[24];
+ } buf;
+ char *ptrs[3];
+ int cnt;
+ int rc;
+ int i;
+
+ const struct cbor_attr_t attrs[] = {
+ {
+ .attribute = "a",
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrTextStringType,
+ .addr.array.arr.strings.ptrs = ptrs,
+ .addr.array.arr.strings.store = buf.store,
+ .addr.array.arr.strings.storelen = sizeof(buf.store),
+ .addr.array.count = &cnt,
+ .addr.array.maxlen = 3,
+ },
+ { 0 },
+ };
+
+ /* Strings fitting in store are decoded. */
+ test_arr_encode(fit, 2);
+ rc = cbor_read_flat_attrs(test_arr_buf, test_arr_len, attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(cnt == 2);
+ TEST_ASSERT(strcmp(ptrs[0], "ab") == 0);
+ TEST_ASSERT(strcmp(ptrs[1], "cd") == 0);
+
+ /* String not fitting in store is rejected and nothing is written past
+ * the store.
+ */
+ memset(buf.guard, 0x5a, sizeof(buf.guard));
+ test_arr_encode(no_fit, 3);
+ rc = cbor_read_flat_attrs(test_arr_buf, test_arr_len, attrs);
+ TEST_ASSERT(rc != 0);
+ TEST_ASSERT(cnt == 0);
+ for (i = 0; i < sizeof(buf.guard); i++) {
+ TEST_ASSERT_FATAL(buf.guard[i] == 0x5a);
+ }
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_string_bounds.c b/encoding/cborattr/test/src/testcases/cborattr_decode_string_bounds.c
new file mode 100644
index 000000000..8e399e0b2
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_string_bounds.c
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+static uint8_t test_str_buf[64];
+static int test_str_len;
+
+static int
+test_str_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_str_buf + test_str_len, data, len);
+ test_str_len += len;
+ assert(test_str_len < sizeof(test_str_buf));
+ return 0;
+}
+
+/* Encodes {"s": <text>, "b": <bytes>, "i": 1}, omitting NULL members. */
+static void
+test_str_encode(const char *s, const uint8_t *b, size_t b_len)
+{
+ struct cbor_encoder_writer writer = { .write = test_str_wr };
+ CborEncoder enc;
+ CborEncoder map;
+
+ test_str_len = 0;
+ cbor_encoder_init(&enc, &writer, 0);
+ cbor_encoder_create_map(&enc, &map, CborIndefiniteLength);
+ if (s) {
+ cbor_encode_text_stringz(&map, "s");
+ cbor_encode_text_stringz(&map, s);
+ }
+ if (b) {
+ cbor_encode_text_stringz(&map, "b");
+ cbor_encode_byte_string(&map, b, b_len);
+ }
+ cbor_encode_text_stringz(&map, "i");
+ cbor_encode_uint(&map, 1);
+ cbor_encoder_close_container(&enc, &map);
+}
+
+TEST_CASE_SELF(test_cborattr_decode_string_bounds)
+{
+ const uint8_t bytes[8] = { 0 };
+ uint8_t b[4];
+ size_t b_len;
+ char s[4];
+ long long int i;
+ int rc;
+
+ const struct cbor_attr_t attrs[] = {
+ {
+ .attribute = "s",
+ .type = CborAttrTextStringType,
+ .addr.string = s,
+ .len = sizeof(s),
+ },
+ {
+ .attribute = "b",
+ .type = CborAttrByteStringType,
+ .addr.bytestring.data = b,
+ .addr.bytestring.len = &b_len,
+ .len = sizeof(b),
+ },
+ {
+ .attribute = "i",
+ .type = CborAttrIntegerType,
+ .addr.integer = &i,
+ },
+ { 0 },
+ };
+
+ /* String shorter than buffer is decoded and terminated. */
+ memset(s, 'x', sizeof(s));
+ test_str_encode("abc", bytes, 4);
+ rc = cbor_read_flat_attrs(test_str_buf, test_str_len, attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(strcmp(s, "abc") == 0);
+ TEST_ASSERT(b_len == 4);
+ TEST_ASSERT(i == 1);
+
+ /* String filling whole buffer is rejected, buffer is left terminated. */
+ memset(s, 'x', sizeof(s));
+ test_str_encode("abcd", NULL, 0);
+ rc = cbor_read_flat_attrs(test_str_buf, test_str_len, attrs);
+ TEST_ASSERT(rc != 0);
+ TEST_ASSERT(s[0] == '\0');
+
+ /* Too long byte string is rejected and reports zero length. */
+ test_str_encode(NULL, bytes, sizeof(bytes));
+ rc = cbor_read_flat_attrs(test_str_buf, test_str_len, attrs);
+ TEST_ASSERT(rc != 0);
+ TEST_ASSERT(b_len == 0);
+
+ /* Omitted string and byte string are set to empty. */
+ memset(s, 'x', sizeof(s));
+ b_len = 1234;
+ test_str_encode(NULL, NULL, 0);
+ rc = cbor_read_flat_attrs(test_str_buf, test_str_len, attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(s[0] == '\0');
+ TEST_ASSERT(b_len == 0);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_substring_key.c b/encoding/cborattr/test/src/testcases/cborattr_decode_substring_key.c
new file mode 100644
index 000000000..6eee7740c
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_substring_key.c
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_substring_key(void)
+{
+ CborEncoder data;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ /*
+ * { "a": "A", "aa": "AA", "aaa" : "AAA" }
+ */
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ cbor_encode_text_stringz(&data, "a");
+ cbor_encode_text_stringz(&data, "A");
+ cbor_encode_text_stringz(&data, "aa");
+ cbor_encode_text_stringz(&data, "AA");
+ cbor_encode_text_stringz(&data, "aaa");
+ cbor_encode_text_stringz(&data, "AAA");
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * substring key
+ */
+TEST_CASE(test_cborattr_decode_substring_key)
+{
+ int rc;
+ char test_str_1a[4] = { '\0' };
+ char test_str_2a[4] = { '\0' };
+ char test_str_3a[4] = { '\0' };
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = "aaa",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_3a,
+ .len = sizeof(test_str_3a),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = "aa",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_2a,
+ .len = sizeof(test_str_2a),
+ .nodefault = true
+ },
+ [2] = {
+ .attribute = "a",
+ .type = CborAttrTextStringType,
+ .addr.string = test_str_1a,
+ .len = sizeof(test_str_1a),
+ .nodefault = true
+ },
+ [3] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_substring_key();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(!strcmp(test_str_1a, "A"));
+ TEST_ASSERT(!strcmp(test_str_2a, "AA"));
+ TEST_ASSERT(!strcmp(test_str_3a, "AAA"));
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c b/encoding/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
new file mode 100644
index 000000000..0baf4ccb8
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+/*
+ * Where we collect cbor data.
+ */
+static uint8_t test_cbor_buf[1024];
+static int test_cbor_len;
+
+/*
+ * CBOR encoder data structures.
+ */
+static int test_cbor_wr(struct cbor_encoder_writer *, const char *, int);
+static CborEncoder test_encoder;
+static struct cbor_encoder_writer test_writer = {
+ .write = test_cbor_wr
+};
+
+static int
+test_cbor_wr(struct cbor_encoder_writer *cew, const char *data, int len)
+{
+ memcpy(test_cbor_buf + test_cbor_len, data, len);
+ test_cbor_len += len;
+
+ assert(test_cbor_len < sizeof(test_cbor_buf));
+ return 0;
+}
+
+static void
+test_encode_unnamed_array(void)
+{
+ CborEncoder data;
+ CborEncoder array;
+
+ cbor_encoder_init(&test_encoder, &test_writer, 0);
+
+ cbor_encoder_create_map(&test_encoder, &data, CborIndefiniteLength);
+
+ /*
+ * [1,2,33]
+ */
+ cbor_encoder_create_array(&data, &array, CborIndefiniteLength);
+ cbor_encode_int(&array, 1);
+ cbor_encode_int(&array, 2);
+ cbor_encode_int(&array, 33);
+ cbor_encoder_close_container(&data, &array);
+
+ cbor_encoder_close_container(&test_encoder, &data);
+}
+
+/*
+ * integer array
+ */
+TEST_CASE(test_cborattr_decode_unnamed_array)
+{
+ int rc;
+ long long int arr_data[5];
+ int arr_cnt = 0;
+ struct cbor_attr_t test_attrs[] = {
+ [0] = {
+ .attribute = CBORATTR_ATTR_UNNAMED,
+ .type = CborAttrArrayType,
+ .addr.array.element_type = CborAttrIntegerType,
+ .addr.array.arr.integers.store = arr_data,
+ .addr.array.count = &arr_cnt,
+ .addr.array.maxlen = sizeof(arr_data) / sizeof(arr_data[0]),
+ .nodefault = true
+ },
+ [1] = {
+ .attribute = NULL
+ }
+ };
+
+ test_encode_unnamed_array();
+
+ rc = cbor_read_flat_attrs(test_cbor_buf, test_cbor_len, test_attrs);
+ TEST_ASSERT(rc == 0);
+ TEST_ASSERT(arr_cnt == 3);
+ TEST_ASSERT(arr_data[0] == 1);
+ TEST_ASSERT(arr_data[1] == 2);
+ TEST_ASSERT(arr_data[2] == 33);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_encode_omit.c b/encoding/cborattr/test/src/testcases/cborattr_encode_omit.c
new file mode 100644
index 000000000..7d6b91fc8
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_encode_omit.c
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+TEST_CASE_SELF(test_cborattr_encode_omit)
+{
+ /* Omit everything except the "str" value. */
+ const struct cbor_out_attr_t attrs[11] = {
+ {
+ .attribute = "null",
+ .val = {
+ .type = CborAttrNullType,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "bool",
+ .val = {
+ .type = CborAttrBooleanType,
+ .boolean = true,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "int",
+ .val = {
+ .type = CborAttrIntegerType,
+ .integer = -99,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "uint",
+ .val = {
+ .type = CborAttrUnsignedIntegerType,
+ .integer = 8442,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "float",
+ .val = {
+ .type = CborAttrFloatType,
+ .fval = 8.0,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "double",
+ .val = {
+ .type = CborAttrDoubleType,
+ .real = 16.0,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "bytes",
+ .val = {
+ .type = CborAttrByteStringType,
+ .bytestring.data = (uint8_t[]) {1, 2, 3},
+ .bytestring.len = 3,
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "str",
+ .val = {
+ .type = CborAttrTextStringType,
+ .string = "mystr",
+ },
+ },
+ {
+ .attribute = "arr",
+ .val = {
+ .type = CborAttrArrayType,
+ .array = {
+ .elems = (struct cbor_out_val_t[]) {
+ [0] = {
+ .type = CborAttrUnsignedIntegerType,
+ .integer = 4355,
+ },
+ [1] = {
+ .type = CborAttrBooleanType,
+ .integer = false,
+ },
+ },
+ .len = 2,
+ },
+ },
+ .omit = true,
+ },
+ {
+ .attribute = "obj",
+ .val = {
+ .type = CborAttrObjectType,
+ .obj = (struct cbor_out_attr_t[]) {
+ {
+ .attribute = "inner_str",
+ .val = {
+ .type = CborAttrTextStringType,
+ .string = "mystr2",
+ },
+ },
+ {
+ .attribute = "inner_int",
+ .val = {
+ .type = CborAttrIntegerType,
+ .integer = 123,
+ },
+ },
+ { 0 }
+ },
+ },
+ .omit = true,
+ },
+ { 0 }
+ };
+ const uint8_t exp[] = {
+ 0xbf, 0x63, 0x73, 0x74, 0x72, 0x65, 0x6d, 0x79,
+ 0x73, 0x74, 0x72, 0xff,
+ };
+
+ cborattr_test_util_encode(attrs, exp, sizeof exp);
+}
diff --git a/encoding/cborattr/test/src/testcases/cborattr_encode_simple.c b/encoding/cborattr/test/src/testcases/cborattr_encode_simple.c
new file mode 100644
index 000000000..1ddcf3cac
--- /dev/null
+++ b/encoding/cborattr/test/src/testcases/cborattr_encode_simple.c
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "test_cborattr.h"
+
+TEST_CASE_SELF(test_cborattr_encode_simple)
+{
+ const struct cbor_out_attr_t attrs[] = {
+ {
+ .attribute = "null",
+ .val = {
+ .type = CborAttrNullType,
+ },
+ },
+ {
+ .attribute = "bool",
+ .val = {
+ .type = CborAttrBooleanType,
+ .boolean = true,
+ },
+ },
+ {
+ .attribute = "int",
+ .val = {
+ .type = CborAttrIntegerType,
+ .integer = -99,
+ },
+ },
+ {
+ .attribute = "uint",
+ .val = {
+ .type = CborAttrUnsignedIntegerType,
+ .integer = 8442,
+ },
+ },
+ {
+ .attribute = "float",
+ .val = {
+ .type = CborAttrFloatType,
+ .fval = 8.0,
+ },
+ },
+ {
+ .attribute = "double",
+ .val = {
+ .type = CborAttrDoubleType,
+ .real = 16.0,
+ },
+ },
+ {
+ .attribute = "bytes",
+ .val = {
+ .type = CborAttrByteStringType,
+ .bytestring.data = (uint8_t[]) {1, 2, 3},
+ .bytestring.len = 3,
+ },
+ },
+ {
+ .attribute = "str",
+ .val = {
+ .type = CborAttrTextStringType,
+ .string = "mystr",
+ },
+ },
+ {
+ .attribute = "arr",
+ .val = {
+ .type = CborAttrArrayType,
+ .array = {
+ .elems = (struct cbor_out_val_t[]) {
+ [0] = {
+ .type = CborAttrUnsignedIntegerType,
+ .integer = 4355,
+ },
+ [1] = {
+ .type = CborAttrBooleanType,
+ .integer = false,
+ },
+ },
+ .len = 2,
+ },
+ },
+ },
+ {
+ .attribute = "obj",
+ .val = {
+ .type = CborAttrObjectType,
+ .obj = (struct cbor_out_attr_t[]) {
+ {
+ .attribute = "inner_str",
+ .val = {
+ .type = CborAttrTextStringType,
+ .string = "mystr2",
+ },
+ },
+ {
+ .attribute = "inner_int",
+ .val = {
+ .type = CborAttrIntegerType,
+ .integer = 123,
+ },
+ },
+ { 0 }
+ },
+ },
+ },
+ { 0 }
+ };
+ const uint8_t exp[] = {
+ 0xbf, 0x64, 0x6e, 0x75, 0x6c, 0x6c, 0xf6, 0x64,
+ 0x62, 0x6f, 0x6f, 0x6c, 0xf5, 0x63, 0x69, 0x6e,
+ 0x74, 0x38, 0x62, 0x64, 0x75, 0x69, 0x6e, 0x74,
+ 0x19, 0x20, 0xfa, 0x65, 0x66, 0x6c, 0x6f, 0x61,
+ 0x74, 0xfa, 0x41, 0x00, 0x00, 0x00, 0x66, 0x64,
+ 0x6f, 0x75, 0x62, 0x6c, 0x65, 0xfb, 0x40, 0x30,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x62,
+ 0x79, 0x74, 0x65, 0x73, 0x43, 0x01, 0x02, 0x03,
+ 0x63, 0x73, 0x74, 0x72, 0x65, 0x6d, 0x79, 0x73,
+ 0x74, 0x72, 0x63, 0x61, 0x72, 0x72, 0x82, 0x19,
+ 0x11, 0x03, 0xf4, 0x63, 0x6f, 0x62, 0x6a, 0xbf,
+ 0x69, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x5f, 0x73,
+ 0x74, 0x72, 0x66, 0x6d, 0x79, 0x73, 0x74, 0x72,
+ 0x32, 0x69, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x5f,
+ 0x69, 0x6e, 0x74, 0x18, 0x7b, 0xff, 0xff,
+ };
+
+ cborattr_test_util_encode(attrs, exp, sizeof exp);
+}