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