Add cboorattr library for zephyr
The library is needed for support mcuboot serial recovery interface.
This library wraps the tinycbor decoder with a attribute based decoder
suitable for decoding a binary version of json.
Origin: apache Mynewt
License: Apache-2.0
URL: https://github.com/apache/mynewt-core/tree/master/encoding/cborattr
commit: bf4b3f6f4cf293fc5a71d7787d5b81555434b6f8
Maintained-by: External
f. cbor_read_mbuf_attrs was removed as it was Mynewt specific.
Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
diff --git a/boot/zephyr/cborattr/CMakeLists.txt b/boot/zephyr/cborattr/CMakeLists.txt
new file mode 100644
index 0000000..77665a7
--- /dev/null
+++ b/boot/zephyr/cborattr/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(src)
+zephyr_include_directories(include)
diff --git a/boot/zephyr/cborattr/include/cborattr/cborattr.h b/boot/zephyr/cborattr/include/cborattr/cborattr.h
new file mode 100644
index 0000000..f38bcf3
--- /dev/null
+++ b/boot/zephyr/cborattr/include/cborattr/cborattr.h
@@ -0,0 +1,153 @@
+/*
+ * 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 __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,
+ 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 {
+ 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;
+ 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;
+ } dflt;
+ size_t len;
+ bool nodefault;
+};
+
+/*
+ * 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 __cplusplus
+}
+#endif
+
+#endif /* CBORATTR_H */
+
diff --git a/boot/zephyr/cborattr/src/CMakeLists.txt b/boot/zephyr/cborattr/src/CMakeLists.txt
new file mode 100644
index 0000000..cdea89f
--- /dev/null
+++ b/boot/zephyr/cborattr/src/CMakeLists.txt
@@ -0,0 +1 @@
+zephyr_sources(cborattr.c)
diff --git a/boot/zephyr/cborattr/src/cborattr.c b/boot/zephyr/cborattr/src/cborattr.c
new file mode 100644
index 0000000..a3e5698
--- /dev/null
+++ b/boot/zephyr/cborattr/src/cborattr.c
@@ -0,0 +1,393 @@
+/*
+ * 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>
+#include <zephyr.h>
+
+/* Import zephyr's configuration */
+#define CONFIG_CBORATTR_MAX_SIZE CONFIG_BOOT_MAX_LINE_INPUT_LEN
+
+/* 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;
+ }
+#if FLOAT_SUPPORT
+ 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;
+}
+
+/* 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 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[CONFIG_CBORATTR_MAX_SIZE + 1];
+ void *lptr;
+ CborValue cur_value;
+ CborError err = 0;
+ size_t len;
+ 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;
+#if FLOAT_SUPPORT
+ 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)) {
+ /* get the attribute */
+ if (cbor_value_is_text_string(&cur_value)) {
+ if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
+ if (len > CONFIG_CBORATTR_MAX_SIZE) {
+ err |= CborErrorDataTooLarge;
+ goto err_return;
+ }
+ 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 |= cbor_value_advance(&cur_value);
+ if (cbor_value_is_valid(&cur_value)) {
+ type = cbor_value_get_type(&cur_value);
+ } else {
+ err |= CborErrorIllegalType;
+ goto err_return;
+ }
+ } 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 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;
+ err |= cbor_value_copy_byte_string(&cur_value, lptr,
+ &len, NULL);
+ *cursor->addr.bytestring.len = len;
+ break;
+ }
+ case CborAttrTextStringType: {
+ size_t len = cursor->len;
+ err |= cbor_value_copy_text_string(&cur_value, lptr,
+ &len, NULL);
+ 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;
+ }
+ }
+ cbor_value_advance(&cur_value);
+ }
+err_return:
+ /* 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;
+ 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 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);
+ err |= cbor_value_copy_text_string(&elem, tp, &len, NULL);
+ 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;
+ }
+ arrcount++;
+ if (arr->element_type != CborAttrStructObjectType) {
+ err |= cbor_value_advance(&elem);
+ }
+ if (!cbor_value_is_valid(&elem)) {
+ break;
+ }
+ }
+ if (arr->count) {
+ *arr->count = arrcount;
+ }
+ while (!cbor_value_at_end(&elem)) {
+ err |= CborErrorDataTooLarge;
+ cbor_value_advance(&elem);
+ }
+ 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);
+}