blob: 11132203196c89071b74d4d49f1069c9ad19a9ad [file] [log] [blame]
/*
// 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