Toyomasa Watarai
/
Mbed-example-WS-W27
simple-mbed-cloud-client/mbed-cloud-client/mbed-client/source/m2mtlvdeserializer.cpp
- Committer:
- MACRUM
- Date:
- 2018-06-30
- Revision:
- 0:119624335925
File content as of revision 0:119624335925:
/* * Copyright (c) 2015 ARM Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * 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. */ // Needed for PRIu64 on FreeRTOS #include <stdio.h> // Note: this macro is needed on armcc to get the the limit macros like UINT16_MAX #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif // Note: this macro is needed on armcc to get the the PRI*32 macros // from inttypes.h in a C++ code. #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include "include/m2mtlvdeserializer.h" #include "mbed-client/m2mconstants.h" #include "mbed-trace/mbed_trace.h" #define TRACE_GROUP "mClt" #define BUFFER_SIZE 10 bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv) { return is_object_instance(tlv, 0); } bool M2MTLVDeserializer::is_resource(const uint8_t *tlv) { return is_resource(tlv, 0); } bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv) { return is_multiple_resource(tlv, 0); } bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv) { return is_resource_instance(tlv, 0); } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialise_object_instances(const uint8_t* tlv, uint32_t tlv_size, M2MObject &object, M2MTLVDeserializer::Operation operation) { M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; if (is_object_instance(tlv) ) { tr_debug("M2MTLVDeserializer::deserialise_object_instances"); error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,false); if(M2MTLVDeserializer::None == error) { error = deserialize_object_instances(tlv, tlv_size, 0, object,operation,true); } } else { tr_debug("M2MTLVDeserializer::deserialise_object_instances ::NotValid"); error = M2MTLVDeserializer::NotValid; } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, uint32_t tlv_size, M2MObjectInstance &object_instance, M2MTLVDeserializer::Operation operation) { M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; if (!is_resource(tlv) && !is_multiple_resource(tlv)) { error = M2MTLVDeserializer::NotValid; } else { error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,false); if(M2MTLVDeserializer::None == error) { if (M2MTLVDeserializer::Put == operation) { remove_resources(tlv, tlv_size, object_instance, 0); } error = deserialize_resources(tlv, tlv_size, 0, object_instance, operation,true); } } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, uint32_t tlv_size, M2MResource &resource, M2MTLVDeserializer::Operation operation) { M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; if (!is_multiple_resource(tlv)) { error = M2MTLVDeserializer::NotValid; } else { tr_debug("M2MTLVDeserializer::deserialize_resource_instances()"); uint8_t offset = 2; ((tlv[0] & 0x20) == 0) ? offset : offset++; uint8_t length = tlv[0] & 0x18; if(length == 0x08) { offset += 1; } else if(length == 0x10) { offset += 2; } else if(length == 0x18) { offset += 3; } tr_debug("M2MTLVDeserializer::deserialize_resource_instances() Offset %d", offset); error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,false); if(M2MTLVDeserializer::None == error) { if (M2MTLVDeserializer::Put == operation) { remove_resource_instances(tlv, tlv_size, resource, offset); } error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation,true); } } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_object_instances(const uint8_t *tlv, uint32_t tlv_size, uint32_t offset, M2MObject &object, M2MTLVDeserializer::Operation operation, bool update_value) { tr_debug("M2MTLVDeserializer::deserialize_object_instances()"); M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; const M2MObjectInstanceList &list = object.instances(); M2MObjectInstanceList::const_iterator it; it = list.begin(); if (TYPE_OBJECT_INSTANCE == til._type) { for (; it!=list.end(); it++) { if((*it)->instance_id() == til._id) { error = deserialize_resources(tlv, tlv_size, offset, (**it),operation, update_value); } } offset += til._length; if(offset < tlv_size) { error = deserialize_object_instances(tlv, tlv_size, offset, object, operation, update_value); } } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resources(const uint8_t *tlv, uint32_t tlv_size, uint32_t offset, M2MObjectInstance &object_instance, M2MTLVDeserializer::Operation operation, bool update_value) { tr_debug("M2MTLVDeserializer::deserialize_resources()"); M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; const M2MResourceList &list = object_instance.resources(); M2MResourceList::const_iterator it; it = list.begin(); bool found = false; bool multi = false; if (TYPE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { multi = false; for (; it!=list.end(); it++) { if((*it)->name_id() == til._id){ tr_debug("M2MTLVDeserializer::deserialize_resources() - Resource ID %d ", til._id); found = true; if(update_value) { if(til._length > 0) { tr_debug("M2MTLVDeserializer::deserialize_resources() - Update value"); if (!set_resource_instance_value((*it), tlv+offset, til._length)) { error = M2MTLVDeserializer::OutOfMemory; break; } } else { tr_debug("M2MTLVDeserializer::deserialize_resources() - Clear Value"); (*it)->clear_value(); } break; } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { tr_debug("M2MTLVDeserializer::deserialize_resources() - NOT_ALLOWED"); error = M2MTLVDeserializer::NotAllowed; break; } } } } else if (TYPE_MULTIPLE_RESOURCE == til._type) { multi = true; for (; it!=list.end(); it++) { if((*it)->supports_multiple_instances() && (*it)->name_id() == til._id) { found = true; error = deserialize_resource_instances(tlv, tlv_size, offset, (**it), object_instance, operation, update_value); } } } else { error = M2MTLVDeserializer::NotValid; return error; } if(!found) { if(M2MTLVDeserializer::Post == operation) { //Create a new Resource String id; id.append_int(til._id); M2MResource *resource = object_instance.create_dynamic_resource(id,"",M2MResourceInstance::OPAQUE,true,multi); if(resource) { resource->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); } if( TYPE_MULTIPLE_RESOURCE == til._type ) { error = deserialize_resource_instances(tlv, tlv_size, offset, (*resource), object_instance, operation, update_value); } } else if(M2MTLVDeserializer::Put == operation) { error = M2MTLVDeserializer::NotFound; } } offset += til._length; if(offset < tlv_size) { error = deserialize_resources(tlv, tlv_size, offset, object_instance, operation, update_value); } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, uint32_t tlv_size, uint32_t offset, M2MResource &resource, M2MObjectInstance &object_instance, M2MTLVDeserializer::Operation operation, bool update_value) { M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; if (TYPE_MULTIPLE_RESOURCE == til._type || TYPE_RESOURCE_INSTANCE == til._type) { const M2MResourceInstanceList &list = resource.resource_instances(); M2MResourceInstanceList::const_iterator it; it = list.begin(); bool found = false; for (; it!=list.end(); it++) { if((*it)->instance_id() == til._id && TYPE_RESOURCE_INSTANCE == til._type) { found = true; if(update_value) { if(til._length > 0) { if (!set_resource_instance_value((*it), tlv+offset, til._length)) { error = M2MTLVDeserializer::OutOfMemory; break; } } else { (*it)->clear_value(); } break; } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { error = M2MTLVDeserializer::NotAllowed; break; } } } if(!found) { if(M2MTLVDeserializer::Post == operation) { // Create a new Resource Instance M2MResourceInstance *res_instance = object_instance.create_dynamic_resource_instance(resource.name(),"", resource.resource_instance_type(), true, til._id); if(res_instance) { res_instance->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED); } } else if(M2MTLVDeserializer::Put == operation) { error = M2MTLVDeserializer::NotFound; } } } else { error = M2MTLVDeserializer::NotValid; return error; } offset += til._length; if(offset < tlv_size) { error = deserialize_resource_instances(tlv, tlv_size, offset, resource, object_instance, operation, update_value); } return error; } M2MTLVDeserializer::Error M2MTLVDeserializer::deserialize_resource_instances(const uint8_t *tlv, uint32_t tlv_size, uint32_t offset, M2MResource &resource, M2MTLVDeserializer::Operation operation, bool update_value) { M2MTLVDeserializer::Error error = M2MTLVDeserializer::None; TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; if (TYPE_RESOURCE_INSTANCE == til._type) { const M2MResourceInstanceList &list = resource.resource_instances(); M2MResourceInstanceList::const_iterator it; it = list.begin(); bool found = false; for (; it!=list.end(); it++) { if((*it)->instance_id() == til._id) { found = true; if(update_value) { if(til._length > 0) { if (!set_resource_instance_value((*it),tlv+offset, til._length)) { error = M2MTLVDeserializer::OutOfMemory; break; } } else { (*it)->clear_value(); } break; } else if(0 == ((*it)->operation() & SN_GRS_PUT_ALLOWED)) { error = M2MTLVDeserializer::NotAllowed; break; } } } if(!found) { if(M2MTLVDeserializer::Post == operation) { error = M2MTLVDeserializer::NotAllowed; } else if(M2MTLVDeserializer::Put == operation) { error = M2MTLVDeserializer::NotFound; } } } else { error = M2MTLVDeserializer::NotValid; return error; } offset += til._length; if(offset < tlv_size) { error = deserialize_resource_instances(tlv, tlv_size, offset, resource, operation, update_value); } return error; } bool M2MTLVDeserializer::is_object_instance(const uint8_t *tlv, uint32_t offset) { bool ret = false; if (tlv) { uint8_t value = tlv[offset]; ret = (TYPE_OBJECT_INSTANCE == (value & TYPE_RESOURCE)); } return ret; } uint16_t M2MTLVDeserializer::instance_id(const uint8_t *tlv) { TypeIdLength til(tlv, 0); til.deserialize(); uint16_t id = til._id; return id; } bool M2MTLVDeserializer::is_resource(const uint8_t *tlv, uint32_t offset) { bool ret = false; if (tlv) { ret = (TYPE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); } return ret; } bool M2MTLVDeserializer::is_multiple_resource(const uint8_t *tlv, uint32_t offset) { bool ret = false; if (tlv) { ret = (TYPE_MULTIPLE_RESOURCE == (tlv[offset] & TYPE_RESOURCE)); } return ret; } bool M2MTLVDeserializer::is_resource_instance(const uint8_t *tlv, uint32_t offset) { bool ret = false; if (tlv) { ret = (TYPE_RESOURCE_INSTANCE == (tlv[offset] & TYPE_RESOURCE)); } return ret; } bool M2MTLVDeserializer::set_resource_instance_value(M2MResourceBase *res, const uint8_t *tlv, const uint32_t size) { int64_t value = 0; bool success = true; switch (res->resource_instance_type()) { case M2MResourceBase::INTEGER: case M2MResourceBase::BOOLEAN: case M2MResourceBase::TIME: value = String::convert_array_to_integer(tlv, size); if (!res->set_value(value)) { success = false; } break; // Todo! implement conversion for other types as well case M2MResourceBase::STRING: case M2MResourceBase::FLOAT: case M2MResourceBase::OPAQUE: case M2MResourceBase::OBJLINK: if (!res->set_value(tlv, size)) { success = false; } break; default: break; } return success; } void M2MTLVDeserializer::remove_resources(const uint8_t *tlv, uint32_t tlv_size, M2MObjectInstance &object_instance, uint32_t offset_size) { tr_debug("M2MTLVDeserializer::remove_resources"); uint32_t offset = offset_size; const M2MResourceList &list = object_instance.resources(); M2MResourceList::const_iterator it; it = list.begin(); for (; it!=list.end();) { bool found = false; while(offset < tlv_size) { TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; offset += til._length; if((*it)->name_id() == til._id){ offset = offset_size; found = true; break; } } offset = offset_size; // Remove resource if not part of the TLV message if (!found) { tr_debug("M2MTLVDeserializer::remove_resources - remove resource %" PRId32, (*it)->name_id()); object_instance.remove_resource((*it)->name()); } else { ++it; } } } void M2MTLVDeserializer::remove_resource_instances(const uint8_t *tlv, uint32_t tlv_size, M2MResource &resource, uint32_t offset_size) { tr_debug("M2MTLVDeserializer::remove_resource_instances"); uint32_t offset = offset_size; const M2MResourceInstanceList &list = resource.resource_instances(); M2MResourceInstanceList::const_iterator it; it = list.begin(); for (; it!=list.end();) { bool found = false; while (offset < tlv_size) { TypeIdLength til(tlv, offset); til.deserialize(); offset = til._offset; offset += til._length; if ((*it)->instance_id() == til._id){ offset = offset_size; found = true; break; } } offset = offset_size; // Remove resource instance if not part of the TLV message if (!found) { tr_debug("M2MTLVDeserializer::remove_resource_instances - remove resource instance %d", (*it)->instance_id()); resource.remove_resource_instance((*it)->instance_id()); } else { ++it; } } } TypeIdLength::TypeIdLength(const uint8_t *tlv, uint32_t offset) : _tlv(tlv), _offset(offset), _type(tlv[offset] & 0xC0), _id(0), _length(0) { } void TypeIdLength::deserialize() { uint32_t idLength = _tlv[_offset] & ID16; uint32_t lengthType = _tlv[_offset] & LENGTH24; if (0 == lengthType) { _length = _tlv[_offset] & 0x07; } _offset++; deserialiseID(idLength); deserialiseLength(lengthType); } void TypeIdLength::deserialiseID(uint32_t idLength) { _id = _tlv[_offset++] & 0xFF; if (ID16 == idLength) { _id = (_id << 8) + (_tlv[_offset++] & 0xFF); } } void TypeIdLength::deserialiseLength(uint32_t lengthType) { if (lengthType > 0) { _length = _tlv[_offset++] & 0xFF; } if (lengthType > LENGTH8) { _length = (_length << 8) + (_tlv[_offset++] & 0xFF); } if (lengthType > LENGTH16) { _length = (_length << 8) + (_tlv[_offset++] & 0xFF); } }