646 lines
18 KiB
C
646 lines
18 KiB
C
/*
|
|
* 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.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)
|
|
#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;
|
|
}
|
|
|
|
/* 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;
|
|
#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)) {
|
|
if (cbor_value_calculate_string_length(&cur_value, &len) == 0) {
|
|
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 |= cbor_value_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;
|
|
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;
|
|
}
|
|
}
|
|
err = cbor_value_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;
|
|
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);
|
|
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);
|
|
}
|
|
|
|
#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
|