Repository: incubator-mynewt-core Updated Branches: refs/heads/develop a9d943b70 -> 6d5df7301
cborattr; support arrays of objects, values as objects, and unnamed attributes. Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/6d5df730 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/6d5df730 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/6d5df730 Branch: refs/heads/develop Commit: 6d5df73017c2832538df654492300fd94d7d9520 Parents: a9d943b Author: Marko Kiiskila <[email protected]> Authored: Tue Jan 3 16:48:01 2017 -0800 Committer: Marko Kiiskila <[email protected]> Committed: Tue Jan 3 16:48:01 2017 -0800 ---------------------------------------------------------------------- encoding/cborattr/include/cborattr/cborattr.h | 24 +++ encoding/cborattr/src/cborattr.c | 58 ++++-- encoding/cborattr/test/src/test_cborattr.c | 3 + encoding/cborattr/test/src/test_cborattr.h | 3 + .../test/src/testcases/cborattr_decode_object.c | 198 +++++++++++++++++++ .../testcases/cborattr_decode_object_array.c | 126 ++++++++++++ .../testcases/cborattr_decode_unnamed_array.c | 99 ++++++++++ 7 files changed, 493 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/include/cborattr/cborattr.h ---------------------------------------------------------------------- diff --git a/encoding/cborattr/include/cborattr/cborattr.h b/encoding/cborattr/include/cborattr/cborattr.h index ed92d35..a1cfe79 100644 --- a/encoding/cborattr/include/cborattr/cborattr.h +++ b/encoding/cborattr/include/cborattr/cborattr.h @@ -51,6 +51,7 @@ typedef enum CborAttrType { CborAttrDoubleType, CborAttrArrayType, CborAttrObjectType, + CborAttrStructObjectType, CborAttrNullType, } CborAttrType; @@ -107,6 +108,7 @@ struct cbor_attr_t { } bytestring; struct cbor_array_t array; size_t offset; + struct cbor_attr_t *obj; } addr; union { long long int integer; @@ -119,6 +121,28 @@ struct cbor_attr_t { 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 *); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/src/cborattr.c ---------------------------------------------------------------------- diff --git a/encoding/cborattr/src/cborattr.c b/encoding/cborattr/src/cborattr.c index 19b0584..6329753 100644 --- a/encoding/cborattr/src/cborattr.c +++ b/encoding/cborattr/src/cborattr.c @@ -65,6 +65,11 @@ valid_attr_type(CborType ct, CborAttrType at) return 1; } break; + case CborAttrObjectType: + if (ct == CborMapType) { + return 1; + } + break; case CborAttrNullType: if (ct == CborNullType) { return 1; @@ -84,7 +89,7 @@ cbor_target_address(const struct cbor_attr_t *cursor, { char *targetaddr = NULL; - if (parent == NULL || parent->element_type != CborAttrObjectType) { + if (parent == NULL || parent->element_type != CborAttrStructObjectType) { /* ordinary case - use the address in the cursor structure */ switch (cursor->type) { case CborAttrNullType: @@ -132,7 +137,7 @@ cbor_internal_read_object(CborValue *root_value, const struct cbor_array_t *parent, int offset) { - const struct cbor_attr_t *cursor; + const struct cbor_attr_t *cursor, *best_match; char attrbuf[CBOR_ATTR_MAX + 1]; void *lptr; CborValue cur_value; @@ -190,29 +195,36 @@ cbor_internal_read_object(CborValue *root_value, err |= cbor_value_copy_text_string(&cur_value, attrbuf, &len, NULL); } - } else { - err |= CborErrorIllegalType; - goto err_return; - } - /* 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); + /* 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 { - err |= CborErrorIllegalType; - goto err_return; + 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) && - (memcmp(cursor->attribute, attrbuf, len) == 0)) { - break; + if (valid_attr_type(type, cursor->type)) { + if (cursor->attribute == CBORATTR_ATTR_UNNAMED && + attrbuf[0] == '\0') { + best_match = cursor; + } else if (!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); @@ -253,6 +265,10 @@ cbor_internal_read_object(CborValue *root_value, 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; } @@ -308,12 +324,18 @@ cbor_read_array(struct CborValue *value, const struct cbor_array_t *arr) 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++; - err |= cbor_value_advance(&elem); + if (arr->element_type != CborAttrStructObjectType) { + err |= cbor_value_advance(&elem); + } if (!cbor_value_is_valid(&elem)) { break; } http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/test/src/test_cborattr.c ---------------------------------------------------------------------- diff --git a/encoding/cborattr/test/src/test_cborattr.c b/encoding/cborattr/test/src/test_cborattr.c index bdcce20..8125660 100644 --- a/encoding/cborattr/test/src/test_cborattr.c +++ b/encoding/cborattr/test/src/test_cborattr.c @@ -26,9 +26,12 @@ 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(); } #if MYNEWT_VAL(SELFTEST) http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/test/src/test_cborattr.h ---------------------------------------------------------------------- diff --git a/encoding/cborattr/test/src/test_cborattr.h b/encoding/cborattr/test/src/test_cborattr.h index 68823b4..1a5757b 100644 --- a/encoding/cborattr/test/src/test_cborattr.h +++ b/encoding/cborattr/test/src/test_cborattr.h @@ -41,9 +41,12 @@ const uint8_t *test_str1(int *len); 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); #ifdef __cplusplus http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/test/src/testcases/cborattr_decode_object.c ---------------------------------------------------------------------- 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 0000000..25a32d2 --- /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; + int64_t 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 + } + }; + int64_t a_val = 0; + int64_t 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); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/test/src/testcases/cborattr_decode_object_array.c ---------------------------------------------------------------------- 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 0000000..82cc34f --- /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")); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/6d5df730/encoding/cborattr/test/src/testcases/cborattr_decode_unnamed_array.c ---------------------------------------------------------------------- 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 0000000..c4446b8 --- /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; + int64_t 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); +}
