| /* |
| // Copyright (c) 2016 Intel Corporation |
| // |
| // Licensed 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 <stddef.h> |
| |
| #include "os/mynewt.h" |
| |
| #include <tinycbor/cbor_mbuf_writer.h> |
| #include <tinycbor/cbor_mbuf_reader.h> |
| |
| #include "oic/port/mynewt/config.h" |
| #include "oic/oc_rep.h" |
| #include "oic/port/mynewt/config.h" |
| #include "port/oc_assert.h" |
| #include "api/oc_priv.h" |
| |
| #ifdef OC_CLIENT |
| static struct os_mempool oc_rep_objects; |
| static uint8_t oc_rep_objects_area[OS_MEMPOOL_BYTES(EST_NUM_REP_OBJECTS, |
| sizeof(oc_rep_t))]; |
| #endif |
| |
| static struct os_mbuf *g_outm; |
| CborEncoder g_encoder, root_map, links_array; |
| CborError g_err; |
| struct cbor_mbuf_writer g_buf_writer; |
| |
| void |
| oc_rep_new(struct os_mbuf *m) |
| { |
| g_err = CborNoError; |
| g_outm = m; |
| cbor_mbuf_writer_init(&g_buf_writer, m); |
| cbor_encoder_init(&g_encoder, &g_buf_writer.enc, 0); |
| } |
| |
| int |
| oc_rep_finalize(void) |
| { |
| int size = OS_MBUF_PKTLEN(g_outm); |
| oc_rep_reset(); |
| if (g_err != CborNoError) { |
| return -1; |
| } |
| return size; |
| } |
| |
| void |
| oc_rep_reset(void) |
| { |
| memset(&g_encoder, 0, sizeof(g_encoder)); |
| } |
| |
| #ifdef OC_CLIENT |
| static oc_rep_t * |
| _alloc_rep(void) |
| { |
| oc_rep_t *rep = os_memblock_get(&oc_rep_objects); |
| |
| memset(rep, 0, sizeof(*rep)); |
| #ifdef DEBUG |
| oc_assert(rep != NULL); |
| #endif |
| return rep; |
| } |
| |
| static void |
| _free_rep(oc_rep_t *rep_value) |
| { |
| os_memblock_put(&oc_rep_objects, rep_value); |
| } |
| |
| void |
| oc_free_rep(oc_rep_t *rep) |
| { |
| if (rep == NULL) { |
| return; |
| } |
| oc_free_rep(rep->next); |
| switch (rep->type) { |
| case BYTE_STRING_ARRAY: |
| case STRING_ARRAY: |
| oc_free_string_array(&rep->value_array); |
| break; |
| case BOOL_ARRAY: |
| oc_free_bool_array(&rep->value_array); |
| break; |
| case DOUBLE_ARRAY: |
| oc_free_double_array(&rep->value_array); |
| break; |
| case INT_ARRAY: |
| oc_free_int_array(&rep->value_array); |
| break; |
| case BYTE_STRING: |
| case STRING: |
| oc_free_string(&rep->value_string); |
| break; |
| case OBJECT: |
| oc_free_rep(rep->value_object); |
| break; |
| case OBJECT_ARRAY: |
| oc_free_rep(rep->value_object_array); |
| break; |
| default: |
| break; |
| } |
| oc_free_string(&rep->name); |
| _free_rep(rep); |
| } |
| |
| /* |
| An Object is a collection of key-value pairs. |
| A value_object value points to the first key-value pair, |
| and subsequent items are accessed via the next pointer. |
| |
| An Object Array is a collection of objects, where each object |
| is a collection of key-value pairs. |
| A value_object_array value points to the first object in the |
| array. This object is then traversed via its value_object pointer. |
| Subsequent objects in the object array are then accessed through |
| the next pointer of the first object. |
| */ |
| |
| /* Parse single property */ |
| static void |
| oc_parse_rep_value(CborValue *value, oc_rep_t **rep, CborError *err) |
| { |
| size_t k, len; |
| CborValue map, array; |
| *rep = _alloc_rep(); |
| oc_rep_t *cur = *rep, **prev = 0; |
| cur->next = 0; |
| cur->value_object_array = 0; |
| /* key */ |
| *err |= cbor_value_calculate_string_length(value, &len); |
| len++; |
| oc_alloc_string(&cur->name, len); |
| *err |= cbor_value_copy_text_string(value, oc_string(cur->name), &len, NULL); |
| *err |= cbor_value_advance(value); |
| /* value */ |
| switch (value->type) { |
| case CborIntegerType: |
| *err |= cbor_value_get_int64(value, &cur->value_int); |
| cur->type = INT; |
| break; |
| case CborBooleanType: |
| *err |= cbor_value_get_boolean(value, &cur->value_boolean); |
| cur->type = BOOL; |
| break; |
| case CborDoubleType: |
| *err |= cbor_value_get_double(value, &cur->value_double); |
| cur->type = DOUBLE; |
| break; |
| case CborByteStringType: |
| *err |= cbor_value_calculate_string_length(value, &len); |
| len++; |
| oc_alloc_string(&cur->value_string, len); |
| *err |= cbor_value_copy_byte_string(value, |
| (uint8_t *)oc_string(cur->value_string), |
| &len, NULL); |
| cur->type = BYTE_STRING; |
| break; |
| case CborTextStringType: |
| *err |= cbor_value_calculate_string_length(value, &len); |
| len++; |
| oc_alloc_string(&cur->value_string, len); |
| *err |= cbor_value_copy_text_string(value, oc_string(cur->value_string), |
| &len, NULL); |
| cur->type = STRING; |
| break; |
| case CborMapType: /* when value is a map/object */ { |
| oc_rep_t **obj = &cur->value_object; // object points to list of properties |
| *err |= cbor_value_enter_container(value, &map); |
| while (!cbor_value_at_end(&map)) { |
| oc_parse_rep_value(&map, obj, err); |
| (*obj)->next = 0; |
| obj = &(*obj)->next; |
| *err |= cbor_value_advance(&map); |
| } |
| cur->type = OBJECT; |
| } break; |
| case CborArrayType: |
| *err |= cbor_value_enter_container(value, &array); |
| len = 0; |
| cbor_value_get_array_length(value, &len); |
| if (len == 0) { |
| CborValue t = array; |
| while (!cbor_value_at_end(&t)) { |
| len++; |
| cbor_value_advance(&t); |
| } |
| } |
| k = 0; |
| while (!cbor_value_at_end(&array)) { |
| switch (array.type) { |
| case CborIntegerType: |
| if (k == 0) { |
| oc_new_int_array(&cur->value_array, len); |
| cur->type = INT | ARRAY; |
| } |
| *err |= |
| cbor_value_get_int64(&array, oc_int_array(cur->value_array) + k); |
| break; |
| case CborDoubleType: |
| if (k == 0) { |
| oc_new_double_array(&cur->value_array, len); |
| cur->type = DOUBLE | ARRAY; |
| } |
| *err |= |
| cbor_value_get_double(&array, oc_double_array(cur->value_array) + k); |
| break; |
| case CborBooleanType: |
| if (k == 0) { |
| oc_new_bool_array(&cur->value_array, len); |
| cur->type = BOOL | ARRAY; |
| } |
| *err |= |
| cbor_value_get_boolean(&array, oc_bool_array(cur->value_array) + k); |
| break; |
| case CborByteStringType: |
| if (k == 0) { |
| oc_new_string_array(&cur->value_array, len); |
| cur->type = BYTE_STRING | ARRAY; |
| } |
| *err |= cbor_value_calculate_string_length(&array, &len); |
| len++; |
| *err |= cbor_value_copy_byte_string( |
| &array, (uint8_t *)oc_string_array_get_item(cur->value_array, k), |
| &len, NULL); |
| break; |
| case CborTextStringType: |
| if (k == 0) { |
| oc_new_string_array(&cur->value_array, len); |
| cur->type = STRING | ARRAY; |
| } |
| *err |= cbor_value_calculate_string_length(&array, &len); |
| len++; |
| *err |= cbor_value_copy_text_string( |
| &array, (char *)oc_string_array_get_item(cur->value_array, k), &len, |
| NULL); |
| break; |
| case CborMapType: |
| if (k == 0) { |
| cur->type = OBJECT | ARRAY; |
| cur->value_object_array = _alloc_rep(); |
| prev = &cur->value_object_array; |
| } else { |
| (*prev)->next = _alloc_rep(); |
| prev = &(*prev)->next; |
| } |
| (*prev)->type = OBJECT; |
| (*prev)->next = 0; |
| oc_rep_t **obj = &(*prev)->value_object; |
| /* Process a series of properties that make up an object of the array */ |
| *err |= cbor_value_enter_container(&array, &map); |
| while (!cbor_value_at_end(&map)) { |
| oc_parse_rep_value(&map, obj, err); |
| obj = &(*obj)->next; |
| *err |= cbor_value_advance(&map); |
| } |
| break; |
| default: |
| break; |
| } |
| k++; |
| *err |= cbor_value_advance(&array); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| uint16_t |
| oc_parse_rep(struct os_mbuf *m, uint16_t payload_off, |
| uint16_t payload_size, oc_rep_t **out_rep) |
| { |
| CborParser parser; |
| CborValue root_value, cur_value, map; |
| CborError err = CborNoError; |
| struct cbor_mbuf_reader br; |
| |
| cbor_mbuf_reader_init(&br, m, payload_off); |
| err |= cbor_parser_init(&br.r, 0, &parser, &root_value); |
| if (cbor_value_is_map(&root_value)) { |
| err |= cbor_value_enter_container(&root_value, &cur_value); |
| *out_rep = 0; |
| oc_rep_t **cur = out_rep; |
| while (cbor_value_is_valid(&cur_value)) { |
| oc_parse_rep_value(&cur_value, cur, &err); |
| err |= cbor_value_advance(&cur_value); |
| cur = &(*cur)->next; |
| } |
| } else if (cbor_value_is_array(&root_value)) { |
| err |= cbor_value_enter_container(&root_value, &map); |
| err |= cbor_value_enter_container(&map, &cur_value); |
| *out_rep = 0; |
| oc_rep_t **cur = out_rep; |
| while (cbor_value_is_valid(&cur_value)) { |
| *cur = _alloc_rep(); |
| (*cur)->type = OBJECT; |
| oc_parse_rep_value(&cur_value, &(*cur)->value_object, &err); |
| err |= cbor_value_advance(&cur_value); |
| (*cur)->next = 0; |
| cur = &(*cur)->next; |
| } |
| } |
| return (uint16_t)err; |
| } |
| |
| void |
| oc_rep_init(void) |
| { |
| os_mempool_init(&oc_rep_objects, EST_NUM_REP_OBJECTS, |
| sizeof(oc_rep_t), oc_rep_objects_area, "oc_rep_o"); |
| } |
| #endif |