X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fsrc%2FOCRepresentation.cpp;h=3d42719c187b4171f3ec48712eaabe1a103ed1b0;hb=7f00f942c39b7bc27c7eeecf213a239c3fe4173c;hp=5fc23ff9d4b80961a1e8c6ce55269e8b7db11443;hpb=8b62aff1ce32afd5961107bb42b53750aa4bab41;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/src/OCRepresentation.cpp b/resource/src/OCRepresentation.cpp index 5fc23ff..3d42719 100644 --- a/resource/src/OCRepresentation.cpp +++ b/resource/src/OCRepresentation.cpp @@ -29,627 +29,778 @@ #include #include -#include -#include -#include -#include -#include #include +#include +#include "ocpayload.h" +#include "ocrandom.h" +#include "oic_malloc.h" +#include "oic_string.h" +#include "ocstack.h" -// code needed to serialize a string=>Attribute value map namespace OC { - namespace detail + static const char COAP[] = "coap://"; + static const char COAPS[] = "coaps://"; + static const char COAP_TCP[] = "coap+tcp://"; + + void MessageContainer::setPayload(const OCPayload* rep) { - template - class WriteAttributeValue : public boost::static_visitor<> + if (rep == nullptr) { - public: - WriteAttributeValue(const std::string& name, Archive& ar) - :m_name(name), m_archive(ar) - {} + return; + } - template - void operator()(const T& value) const - { - m_archive(cereal::make_nvp(m_name, value)); - } - private: - std::string m_name; - Archive& m_archive; - }; + switch(rep->type) + { + case PAYLOAD_TYPE_REPRESENTATION: + setPayload(reinterpret_cast(rep)); + break; + default: + throw OC::OCException("Invalid Payload type in setPayload"); + break; + } } -} - -namespace cereal -{ - // take no action when serializing the null type, because the 'save' below - // doesn't use the visitor for this type. - template - void serialize(Archive&, OC::NullType t) - {} - template - void save(Archive& ar, const std::map& vals) + void MessageContainer::setPayload(const OCRepPayload* payload) { - for(const auto& kv : vals) + const OCRepPayload* pl = payload; + while (pl) { - const auto& k = kv.first; - const auto& v = kv.second; + OCRepresentation cur; + cur.setPayload(pl); + + pl = pl->next; + this->addRepresentation(cur); + } + } - if(v.which() != OC::AttributeValueNullIndex) + OCRepPayload* MessageContainer::getPayload() const + { + OCRepPayload* root = nullptr; + for(const auto& r : representations()) + { + if (!root) { - OC::detail::WriteAttributeValue writer(k,ar); - boost::apply_visitor(writer, v); + root = r.getPayload(); } else { - ar.setNextName(k.c_str()); - ar.writeName(); - ar.saveValue(); + OCRepPayloadAppend(root, r.getPayload()); } } + + return root; + } + + const std::vector& MessageContainer::representations() const + { + return m_reps; } - template - void load(Archive& ar, std::map& vals) + void MessageContainer::addRepresentation(const OCRepresentation& rep) { - ar.loadAttributeValues(vals); + m_reps.push_back(rep); } } namespace OC { - typedef cereal::JSONOutputArchive OutputArchiveType; - typedef cereal::JSONInputArchive InputArchiveType; - - void MessageContainer::setJSONRepresentation(const std::string& payload) + struct get_payload_array: boost::static_visitor<> { - std::stringstream os(payload); + template + void operator()(T& /*arr*/) { - InputArchiveType archive(os); - archive(cereal::make_nvp(OC::Key::OCKEY, m_reps)); + throw std::logic_error("Invalid calc_dimensions_visitor type"); } - } - void MessageContainer::setJSONRepresentation(const char* payload) - { - setJSONRepresentation(std::string(payload)); - } + template + void operator()(std::vector& arr) + { + root_size_calc(); + dimensions[0] = arr.size(); + dimensions[1] = 0; + dimensions[2] = 0; + dimTotal = calcDimTotal(dimensions); - std::string MessageContainer::getJSONRepresentation(OCInfoFormat f) const - { - std::stringstream os; + array = (void*)OICMalloc(dimTotal * root_size); - // note: the block is required because cereal closes the JSON string - // upon destruction, so the archive needs to be destroyed before accessing - // the data + for(size_t i = 0; i < dimensions[0]; ++i) + { + copy_to_array(arr[i], array, i); + } + + } + template + void operator()(std::vector>& arr) { - if(f == OCInfoFormat::IncludeOC) + root_size_calc(); + dimensions[0] = arr.size(); + dimensions[1] = 0; + dimensions[2] = 0; + for(size_t i = 0; i < arr.size(); ++i) { - OutputArchiveType archive(os); - archive(cereal::make_nvp(OC::Key::OCKEY, m_reps)); + dimensions[1] = std::max(dimensions[1], arr[i].size()); } - else if(f== OCInfoFormat::ExcludeOC) + dimTotal = calcDimTotal(dimensions); + array = (void*)OICCalloc(1, dimTotal * root_size); + + for(size_t i = 0; i < dimensions[0]; ++i) { - bool firstPrinted = false; - for(std::vector::size_type i = 0; i< m_reps.size();++i) + for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j) { - if(!m_reps[i].emptyData()) - { - if(firstPrinted) - { - os<<','; - } - firstPrinted=true; - os << m_reps[i].getJSONRepresentation(); - } + copy_to_array(arr[i][j], array, i*dimensions[1] + j); } } } - return os.str(); - } + template + void operator()(std::vector>>& arr) + { + root_size_calc(); + dimensions[0] = arr.size(); + dimensions[1] = 0; + dimensions[2] = 0; + for(size_t i = 0; i < arr.size(); ++i) + { + dimensions[1] = std::max(dimensions[1], arr[i].size()); - const std::vector& MessageContainer::representations() const - { - return m_reps; - } + for(size_t j = 0; j < arr[i].size(); ++j) + { + dimensions[2] = std::max(dimensions[2], arr[i][j].size()); + } + } - void MessageContainer::addRepresentation(const OCRepresentation& rep) - { - m_reps.push_back(rep); - } -} + dimTotal = calcDimTotal(dimensions); + array = (void*)OICCalloc(1, dimTotal * root_size); -namespace OC -{ - std::string OCRepresentation::getJSONRepresentation() const - { - if(emptyData()) - { - return "{}"; + for(size_t i = 0; i < dimensions[0]; ++i) + { + for(size_t j = 0; j < dimensions[1] && j < arr[i].size(); ++j) + { + for(size_t k = 0; k < dimensions[2] && k < arr[i][j].size(); ++k) + { + copy_to_array(arr[i][j][k], array, + dimensions[2] * j + + dimensions[2] * dimensions[1] * i + + k); + } + } + } } - std::stringstream os; + template + void root_size_calc() + { + root_size = sizeof(T); + } - // note: the block is required because cereal closes the JSON string - // upon destruction, so the archive needs to be destroyed before accessing - // the data + template + void copy_to_array(T item, void* array, size_t pos) { - OutputArchiveType archive (os); - save(archive); + ((T*)array)[pos] = item; } - return os.str(); - } + size_t dimensions[MAX_REP_ARRAY_DEPTH]; + size_t root_size; + size_t dimTotal; + void* array; + }; - void OCRepresentation::addChild(const OCRepresentation& rep) + template<> + void get_payload_array::root_size_calc() { - m_children.push_back(rep); + root_size = sizeof(int64_t); } - void OCRepresentation::clearChildren() + template<> + void get_payload_array::root_size_calc() { - m_children.clear(); + root_size = sizeof(char*); } - const std::vector& OCRepresentation::getChildren() const + template<> + void get_payload_array::root_size_calc() { - return m_children; + root_size = sizeof(OCRepPayload*); } - void OCRepresentation::setChildren(const std::vector& children) + template<> + void get_payload_array::copy_to_array(int item, void* array, size_t pos) { - m_children = children; + ((int64_t*)array)[pos] = item; } - void OCRepresentation::setUri(const std::string& uri) +#if !(defined(_MSC_VER) || defined(__APPLE__)) + template<> + void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos) { - m_uri = uri; + ((bool*)array)[pos] = static_cast(br); } +#endif - std::string OCRepresentation::getUri() const + template<> + void get_payload_array::copy_to_array(std::string item, void* array, size_t pos) { - return m_uri; + ((char**)array)[pos] = OICStrdup(item.c_str()); } - const std::vector& OCRepresentation::getResourceTypes() const + template<> + void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos) { - return m_resourceTypes; + ((char**)array)[pos] = OICStrdup(item.c_str()); } - void OCRepresentation::setResourceTypes(const std::vector& resourceTypes) + template<> + void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos) { - m_resourceTypes = resourceTypes; + ((char**)array)[pos] = OICStrdup(item.c_str()); } - const std::vector& OCRepresentation::getResourceInterfaces() const + template<> + void get_payload_array::copy_to_array(OCByteString item, void *array, size_t pos) { - return m_interfaces; + ((OCByteString *)array)[pos] = item; } - void OCRepresentation::setResourceInterfaces(const std::vector& resourceInterfaces) + template<> + void get_payload_array::copy_to_array(OCByteString &item, void *array, size_t pos) { - m_interfaces = resourceInterfaces; + ((OCByteString *)array)[pos] = item; } - bool OCRepresentation::hasAttribute(const std::string& str) const + template<> + void get_payload_array::copy_to_array(const OCByteString &item, void *array, size_t pos) { - return m_values.find(str) != m_values.end(); + ((OCByteString *)array)[pos] = item; } - bool OCRepresentation::emptyData() const + template<> + void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos) { - // This logic is meant to determine whether based on the JSON serialization rules - // if this object will result in empty JSON. URI is only serialized if there is valid - // data, ResourceType and Interfaces are only serialized if we are a nothing, a - // child of a default or link item. - // Our values array is only printed in the if we are the child of a Batch resource, - // the parent in a 'default' situation, or not in a child/parent relationship. - if(!m_uri.empty()) - { - return false; - } - else if ((m_interfaceType == InterfaceType::None - || m_interfaceType==InterfaceType::DefaultChild - || m_interfaceType==InterfaceType::LinkChild) - && (m_resourceTypes.size()>0 || m_interfaces.size()>0)) - { - return false; - } - else if((m_interfaceType == InterfaceType::None - || m_interfaceType == InterfaceType::BatchChild - || m_interfaceType == InterfaceType::DefaultParent) - && m_values.size()>0) - { - return false; - } - - if(m_children.size() > 0) - { - return false; - } - - return true; + ((OCRepPayload**)array)[pos] = item.getPayload(); } - int OCRepresentation::numberOfAttributes() const + void OCRepresentation::getPayloadArray(OCRepPayload* payload, + const OCRepresentation::AttributeItem& item) const { - return m_values.size(); - } + get_payload_array vis{}; + boost::apply_visitor(vis, m_values[item.attrname()]); - bool OCRepresentation::erase(const std::string& str) - { - return m_values.erase(str); - } - void OCRepresentation::setNULL(const std::string& str) - { - m_values[str] = OC::NullType(); + switch(item.base_type()) + { + case AttributeType::Integer: + OCRepPayloadSetIntArrayAsOwner(payload, item.attrname().c_str(), + (int64_t*)vis.array, + vis.dimensions); + break; + case AttributeType::Double: + OCRepPayloadSetDoubleArrayAsOwner(payload, item.attrname().c_str(), + (double*)vis.array, + vis.dimensions); + break; + case AttributeType::Boolean: + OCRepPayloadSetBoolArrayAsOwner(payload, item.attrname().c_str(), + (bool*)vis.array, + vis.dimensions); + break; + case AttributeType::String: + OCRepPayloadSetStringArrayAsOwner(payload, item.attrname().c_str(), + (char**)vis.array, + vis.dimensions); + break; + case AttributeType::OCByteString: + OCRepPayloadSetByteStringArrayAsOwner(payload, item.attrname().c_str(), + (OCByteString *)vis.array, vis.dimensions); + break; + case AttributeType::OCRepresentation: + OCRepPayloadSetPropObjectArrayAsOwner(payload, item.attrname().c_str(), + (OCRepPayload**)vis.array, vis.dimensions); + break; + default: + throw std::logic_error(std::string("GetPayloadArray: Not Implemented") + + std::to_string((int)item.base_type())); + } } - bool OCRepresentation::isNULL(const std::string& str) const + OCRepPayload* OCRepresentation::getPayload() const { - auto x = m_values.find(str); - - if(m_values.end() != x) + OCRepPayload* root = OCRepPayloadCreate(); + if (!root) { - return x->second.which() == AttributeValueNullIndex; + throw std::bad_alloc(); } - else + + OCRepPayloadSetUri(root, getUri().c_str()); + + for(const std::string& type : getResourceTypes()) { - throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str); + OCRepPayloadAddResourceType(root, type.c_str()); } - } -} -namespace OC -{ - template - void OCRepresentation::optional_load(Archive& ar, Val&& v) - { - try + for(const std::string& iface : getResourceInterfaces()) { - ar(v); + OCRepPayloadAddInterface(root, iface.c_str()); } - catch(cereal::Exception& e) + + for(auto& val : *this) { - ar.setNextName(nullptr); - // Loading a key that doesn't exist results in an exception - // Since "Not Found" is a valid condition for us, we swallow - // this exception and the archive will not load anything + switch(val.type()) + { + case AttributeType::Null: + OCRepPayloadSetNull(root, val.attrname().c_str()); + break; + case AttributeType::Integer: + OCRepPayloadSetPropInt(root, val.attrname().c_str(), static_cast(val)); + break; + case AttributeType::Double: + OCRepPayloadSetPropDouble(root, val.attrname().c_str(), + val.getValue()); + break; + case AttributeType::Boolean: + OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue()); + break; + case AttributeType::String: + OCRepPayloadSetPropString(root, val.attrname().c_str(), + static_cast(val).c_str()); + break; + case AttributeType::OCByteString: + OCRepPayloadSetPropByteString(root, val.attrname().c_str(), val.getValue()); + break; + case AttributeType::OCRepresentation: + OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(), + static_cast(val).getPayload()); + break; + case AttributeType::Vector: + getPayloadArray(root, val); + break; + case AttributeType::Binary: + OCRepPayloadSetPropByteString(root, val.attrname().c_str(), + OCByteString{const_cast(val.getValue>().data()), + val.getValue>().size()}); + break; + default: + throw std::logic_error(std::string("Getpayload: Not Implemented") + + std::to_string((int)val.type())); + break; + } } + + return root; } - template - void OCRepresentation::save(Archive& ar) const + size_t calcArrayDepth(const size_t dimensions[MAX_REP_ARRAY_DEPTH]) { - // printed for all interface types - if(!m_uri.empty()) + if (dimensions[0] == 0) { - ar(cereal::make_nvp(Key::URIKEY, m_uri)); + throw std::logic_error("invalid calcArrayDepth"); } - - if((m_interfaceType == InterfaceType::None - || m_interfaceType==InterfaceType::DefaultChild - || m_interfaceType==InterfaceType::LinkChild) - && (m_resourceTypes.size()>0 || m_interfaces.size()>0)) + else if (dimensions[1] == 0) { - // The Prop object requires that it refer to non-const vectors - // so that it can alter them in the 'load' case. In the save case - // (initiated here) it will not modify the object. So, to keep the - // compiler happy, removing the 'const' context here is necessary. - const std::vector& rt(m_resourceTypes); - const std::vector& intf(m_interfaces); - Prop temp(const_cast&>(rt), - const_cast&>(intf)); - ar(cereal::make_nvp(Key::PROPERTYKEY, temp)); + return 1; } - - // printed only for BatchChildren and DefaultParent - if((m_interfaceType == InterfaceType::None - || m_interfaceType == InterfaceType::BatchChild - || m_interfaceType == InterfaceType::DefaultParent) - && m_values.size()>0) + else if (dimensions[2] == 0) { - ar(cereal::make_nvp(Key::REPKEY, m_values)); + return 2; } - } - - template - void OCRepresentation::load(Archive& ar) - { - optional_load(ar, cereal::make_nvp(Key::URIKEY, m_uri)); + else { - Prop temp(m_resourceTypes, m_interfaces); - optional_load(ar, cereal::make_nvp(Key::PROPERTYKEY, temp)); + return 3; } - optional_load(ar, cereal::make_nvp(Key::REPKEY, m_values)); } - template - void OCRepresentation::Prop::save(Archive& ar) const + template + T OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) + { + throw std::logic_error("payload_array_helper_copy: unsupported type"); + } + template<> + int OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) + { + return pl->arr.iArray[index]; + } + template<> + double OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) + { + return pl->arr.dArray[index]; + } + template<> + bool OCRepresentation::payload_array_helper_copy(size_t index, const OCRepPayloadValue* pl) + { + return pl->arr.bArray[index]; + } + template<> + std::string OCRepresentation::payload_array_helper_copy( + size_t index, const OCRepPayloadValue* pl) { - if(m_types.size() > 0) + if (pl->arr.strArray[index]) { - ar(cereal::make_nvp(Key::RESOURCETYPESKEY, m_types)); + return std::string(pl->arr.strArray[index]); } - - if(m_interfaces.size()>0) + else { - ar(cereal::make_nvp(Key::INTERFACESKEY, m_interfaces)); + return std::string{}; } } - template - void OCRepresentation::Prop::load(Archive& ar) + template<> + OCByteString OCRepresentation::payload_array_helper_copy( + size_t index, const OCRepPayloadValue *pl) { - optional_load(ar, cereal::make_nvp(Key::RESOURCETYPESKEY, m_types)); - optional_load(ar, cereal::make_nvp(Key::INTERFACESKEY, m_interfaces)); + OCByteString result {NULL, 0}; + if (pl->arr.ocByteStrArray[index].len) + { + result = (pl->arr.ocByteStrArray[index]); + } + return result; } -} -// note: the below is used to load an AttributeValue map out of JSON -namespace OC -{ - namespace detail + template<> + OCRepresentation OCRepresentation::payload_array_helper_copy( + size_t index, const OCRepPayloadValue* pl) { - enum class typeTag:uint8_t - { - NOTHING = 0, - _string, - _int, - _double, - _bool, - _representation - }; - - typedef rapidjson::Document::GenericValue GenericValue; - - AttributeValue parseAttributeValue(const GenericValue& v); - AttributeValue parseAttributeValue(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t); - AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t); - AttributeValue parseAttributeValueArray(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t); - AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t); - - AttributeValue parseAttributeValue(const GenericValue& v) + OCRepresentation r; + if (pl->arr.objArray[index]) { - // base entrance, start everything at '0' - unsigned int max_depth {0}; - typeTag t {typeTag::NOTHING}; - - return parseAttributeValue(v, 0, max_depth, t); + r.setPayload(pl->arr.objArray[index]); } + return r; + } - AttributeValue parseAttributeValue(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t) + template + void OCRepresentation::payload_array_helper(const OCRepPayloadValue* pl, size_t depth) + { + if (depth == 1) { - if(v.IsObject()) - { - return parseAttributeValueObject(v, t); - } - else if(v.IsArray()) - { - return parseAttributeValueArray(v, curLevel + 1, maxDepth, t); - } - else + std::vector val(pl->arr.dimensions[0]); + + for(size_t i = 0; i < pl->arr.dimensions[0]; ++i) { - return parseAttributeValuePrimitive(v,t); + val[i] = payload_array_helper_copy(i, pl); } + this->setValue(std::string(pl->name), val); } - - AttributeValue parseAttributeValueObject(const GenericValue& v, typeTag& t) + else if (depth == 2) { - typedef rapidjson::Value::ConstMemberIterator CMI; - t = typeTag::_representation; - OC::OCRepresentation rep; - - for(CMI itr = v.MemberBegin(); itr!= v.MemberEnd(); ++itr) + std::vector> val(pl->arr.dimensions[0]); + for(size_t i = 0; i < pl->arr.dimensions[0]; ++i) { - std::string keyName = itr->name.GetString(); - - if(keyName == OC::Key::URIKEY) + val[i].resize(pl->arr.dimensions[1]); + for(size_t j = 0; j < pl->arr.dimensions[1]; ++j) { - rep.setUri(boost::get(parseAttributeValue(itr->value))); - } - else if (keyName == OC::Key::PROPERTYKEY) - { - for(CMI itr2 = itr->value.MemberBegin(); - itr->value.MemberEnd()!=itr2; - ++itr2) - { - if(keyName == OC::Key::RESOURCETYPESKEY) - { - rep.setResourceTypes( - boost::get>( - parseAttributeValue(itr->value))); - } - else if(keyName == OC::Key::PROPERTYKEY) - { - rep.setResourceInterfaces( - boost::get>( - parseAttributeValue(itr->value))); - } - } - } - else if (keyName == OC::Key::REPKEY) - { - for(CMI itr2 = itr->value.MemberBegin(); - itr->value.MemberEnd()!=itr2; - ++itr2) - { - rep.setValue(itr2->name.GetString(), - parseAttributeValue(itr2->value)); - } + val[i][j] = payload_array_helper_copy( + i * pl->arr.dimensions[1] + j, pl); } } - - return rep; + this->setValue(std::string(pl->name), val); } - - AttributeValue parseAttributeValuePrimitive(const GenericValue& v, typeTag& t) + else if (depth == 3) { - if(v.IsString()) + std::vector>> val(pl->arr.dimensions[0]); + for(size_t i = 0; i < pl->arr.dimensions[0]; ++i) { - t = typeTag::_string; - return std::string(v.GetString()); - } - else if (v.IsNumber()) - { - if(v.IsDouble()) - { - t = typeTag::_double; - return double(v.GetDouble()); - } - else if (v.IsInt()) + val[i].resize(pl->arr.dimensions[1]); + for(size_t j = 0; j < pl->arr.dimensions[1]; ++j) { - t = typeTag::_int; - return int(v.GetInt()); - } - else - { - throw OC::OCException(OC::Exception::INVALID_JSON_NUMERIC - + std::to_string(v.GetType())); + val[i][j].resize(pl->arr.dimensions[2]); + for(size_t k = 0; k < pl->arr.dimensions[2]; ++k) + { + val[i][j][k] = payload_array_helper_copy( + pl->arr.dimensions[2] * j + + pl->arr.dimensions[2] * pl->arr.dimensions[1] * i + + k, + pl); + } } } - else if(v.IsBool_()) - { - t=typeTag::_bool; - return bool(v.GetBool_()); - } - else if(v.IsNull_()) - { - return OC::NullType(); - } - else - { - throw OC::OCException(OC::Exception::INVALID_JSON_TYPE - + std::to_string(v.GetType())); - } + this->setValue(std::string(pl->name), val); } - - std::vector gatherArrayContents(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t) + else { - std::vector out; - - std::transform(v.Begin(), v.End(), back_inserter(out), - [curLevel, &maxDepth, &t](const GenericValue& x) - { - return parseAttributeValue(x, curLevel, maxDepth, t); - }); - return out; + throw std::logic_error("Invalid depth in payload_array_helper"); } + } + + void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl) + { - template - struct valueToConcrete + switch(pl->arr.type) { - OutT operator()(const AttributeValue& v) - { - return boost::get(v); - } + case OCREP_PROP_INT: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_DOUBLE: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_BOOL: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_STRING: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_BYTE_STRING: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + case OCREP_PROP_OBJECT: + payload_array_helper(pl, calcArrayDepth(pl->arr.dimensions)); + break; + default: + throw std::logic_error("setPayload array invalid type"); + break; + } + } - }; + void OCRepresentation::setPayload(const OCRepPayload* pl) + { + setUri(pl->uri); - template - OutSeqT valuesToConcreteVectors(const std::vector& vs) + OCStringLL* ll = pl->types; + while(ll) { - OutSeqT ret; + addResourceType(ll->value); + ll = ll->next; + } - std::transform(begin(vs),end(vs), back_inserter(ret), - valueToConcrete()); - return ret; + ll = pl->interfaces; + while(ll) + { + addResourceInterface(ll->value); + ll = ll->next; } - template - AttributeValue remapArrayDepth(const unsigned int curLevel, - const std::vector& vs) + OCRepPayloadValue* val = pl->values; + + while(val) { - switch(curLevel) + switch(val->type) { - default: - throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH); - break; - case 1: - return valuesToConcreteVectors>(vs); + case OCREP_PROP_NULL: + setNULL(val->name); break; - case 2: - return valuesToConcreteVectors>>(vs); + case OCREP_PROP_INT: + setValue(val->name, val->i); break; - case 3: - return valuesToConcreteVectors - >>>(vs); + case OCREP_PROP_DOUBLE: + setValue(val->name, val->d); break; - } - } - - AttributeValue convertArrayToConcretes(const typeTag t, - const unsigned int curLevel, const std::vector& vs) - { - // This function converts a std::vector of AttributeValue to a std::vector - // of concrete types. Since we don't use a recursive Variant, we need - // to get back to a 'base' primitive type - switch(t) - { - default: - case typeTag::NOTHING: - throw OC::OCException(OC::Exception::INVALID_JSON_TYPE_TAG); + case OCREP_PROP_BOOL: + setValue(val->name, val->b); break; - case typeTag::_string: - return remapArrayDepth(curLevel, vs); + case OCREP_PROP_STRING: + setValue(val->name, val->str); break; - case typeTag::_int: - return remapArrayDepth(curLevel, vs); + case OCREP_PROP_OBJECT: + { + OCRepresentation cur; + cur.setPayload(val->obj); + setValue(val->name, cur); + } break; - case typeTag::_double: - return remapArrayDepth(curLevel, vs); + case OCREP_PROP_ARRAY: + setPayloadArray(val); break; - case typeTag::_bool: - return remapArrayDepth(curLevel, vs); + case OCREP_PROP_BYTE_STRING: + setValue(val->name, + std::vector + (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len) + ); break; - case typeTag::_representation: - return remapArrayDepth(curLevel, vs); + default: + throw std::logic_error(std::string("Not Implemented!") + + std::to_string((int)val->type)); break; } + val = val->next; } + } + + void OCRepresentation::addChild(const OCRepresentation& rep) + { + m_children.push_back(rep); + } + + void OCRepresentation::clearChildren() + { + m_children.clear(); + } + + const std::vector& OCRepresentation::getChildren() const + { + return m_children; + } + + void OCRepresentation::setChildren(const std::vector& children) + { + m_children = children; + } - AttributeValue parseAttributeValueArray(const GenericValue& v, - const unsigned int curLevel, unsigned int& maxDepth, typeTag& t) + void OCRepresentation::setDevAddr(const OCDevAddr& devAddr) + { + std::ostringstream ss; + if (devAddr.flags & OC_SECURE) + { + ss << COAPS; + } + else if (devAddr.adapter & OC_ADAPTER_TCP) + { + ss << COAP_TCP; + } + else + { + ss << COAP; + } + if (devAddr.flags & OC_IP_USE_V6) { - const unsigned int max_level = 3; + char addressEncoded[128] = {0}; - if(curLevel > max_level) + OCStackResult result = OCEncodeAddressForRFC6874(addressEncoded, + sizeof(addressEncoded), + devAddr.addr); + if (OC_STACK_OK != result) { - throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH); + throw OC::OCException("Invalid address in setDevAddr"); } + ss << '[' << addressEncoded << ']'; + } + else + { + ss << devAddr.addr; + } + if (devAddr.port) + { + ss << ':' << devAddr.port; + } + m_host = ss.str(); + } - if(curLevel > maxDepth) - { - maxDepth = curLevel; - } + const std::string OCRepresentation::getHost() const + { + return m_host; + } - auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t); - const int remapLevel = maxDepth - (curLevel -1); - return convertArrayToConcretes(t, remapLevel, arrayItems); + void OCRepresentation::setUri(const char* uri) + { + m_uri = uri ? uri : ""; + } + + void OCRepresentation::setUri(const std::string& uri) + { + m_uri = uri; + } + + std::string OCRepresentation::getUri() const + { + return m_uri; + } + + const std::vector& OCRepresentation::getResourceTypes() const + { + return m_resourceTypes; + } + + void OCRepresentation::setResourceTypes(const std::vector& resourceTypes) + { + m_resourceTypes = resourceTypes; + } + + void OCRepresentation::addResourceType(const std::string& str) + { + m_resourceTypes.push_back(str); + } + + const std::vector& OCRepresentation::getResourceInterfaces() const + { + return m_interfaces; + } + + void OCRepresentation::addResourceInterface(const std::string& str) + { + m_interfaces.push_back(str); + } + + void OCRepresentation::setResourceInterfaces(const std::vector& resourceInterfaces) + { + m_interfaces = resourceInterfaces; + } + + const std::vector& OCRepresentation::getDataModelVersions() const + { + return m_dataModelVersions; + } + + void OCRepresentation::addDataModelVersion(const std::string& str) + { + m_dataModelVersions.push_back(str); + } + + bool OCRepresentation::hasAttribute(const std::string& str) const + { + return m_values.find(str) != m_values.end(); + } + + bool OCRepresentation::emptyData() const + { + // This logic is meant to determine whether based on the JSON serialization rules + // if this object will result in empty JSON. URI is only serialized if there is valid + // data, ResourceType and Interfaces are only serialized if we are a nothing, a + // child of a default or link item. + // Our values array is only printed in the if we are the child of a Batch resource, + // the parent in a 'default' situation, or not in a child/parent relationship. + if (!m_uri.empty()) + { + return false; + } + else if ((m_interfaceType == InterfaceType::None + || m_interfaceType==InterfaceType::DefaultChild + || m_interfaceType==InterfaceType::LinkChild) + && (m_resourceTypes.size()>0 || m_interfaces.size()>0 + || m_dataModelVersions.size()>0)) + { + return false; } + else if ((m_interfaceType == InterfaceType::None + || m_interfaceType == InterfaceType::BatchChild + || m_interfaceType == InterfaceType::DefaultParent) + && m_values.size()>0) + { + return false; + } + + if (m_children.size() > 0) + { + return false; + } + + return true; } -} -namespace cereal -{ - void JSONInputArchive::loadAttributeValues(std::map& map) - { - for(auto&b = itsIteratorStack.back(); - b.Member && b.itsMemberItEnd != b.itsMemberItBegin+b.itsIndex; - ++b) - { - std::string key = b.itsMemberItBegin[b.itsIndex].name.GetString(); - const GenericValue& v = itsIteratorStack.back().value(); - map[key] = OC::detail::parseAttributeValue(v); - } - } + int OCRepresentation::numberOfAttributes() const + { + return m_values.size(); + } + + bool OCRepresentation::erase(const std::string& str) + { + return m_values.erase(str); + } + + void OCRepresentation::setNULL(const std::string& str) + { + m_values[str] = OC::NullType(); + } + + bool OCRepresentation::isNULL(const std::string& str) const + { + auto x = m_values.find(str); + + if (m_values.end() != x) + { + return x->second.which() == AttributeValueNullIndex; + } + else + { + throw OCException(OC::Exception::INVALID_ATTRIBUTE+ str); + } + } } namespace OC @@ -673,12 +824,17 @@ namespace OC case AttributeType::String: os << "String"; break; + case AttributeType::OCByteString: + os << "OCByteString"; + break; case AttributeType::OCRepresentation: os << "OCRepresentation"; break; case AttributeType::Vector: os << "Vector"; break; + case AttributeType::Binary: + os<< "Binary"; } return os; } @@ -716,27 +872,45 @@ namespace OC // contains the inner most vector-type typedef T base_type; // contains the AttributeType for this item - constexpr static AttributeType enum_type = + BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeTypeConvert::type; // contains the AttributeType for this base-type - constexpr static AttributeType enum_base_type = + BOOST_STATIC_CONSTEXPR AttributeType enum_base_type = AttributeTypeConvert::type; // depth of the vector - constexpr static size_t depth = 0; + BOOST_STATIC_CONSTEXPR size_t depth = 0; }; template - struct type_info::value>::type> + struct type_info< + T, + typename std::enable_if< + is_vector::value && + !std::is_same::value + >::type + > { typedef T type; typedef typename type_info::base_type base_type; - constexpr static AttributeType enum_type = AttributeType::Vector; - constexpr static AttributeType enum_base_type = + BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Vector; + BOOST_STATIC_CONSTEXPR AttributeType enum_base_type = type_info::enum_base_type; - constexpr static size_t depth = 1 + + BOOST_STATIC_CONSTEXPR size_t depth = 1 + type_info::depth; }; + // special case for binary data, which is a std::vector + template<> + struct type_info, void> + { + typedef std::vector type; + typedef std::vector base_type; + BOOST_STATIC_CONSTEXPR AttributeType enum_type = AttributeType::Binary; + BOOST_STATIC_CONSTEXPR AttributeType enum_base_type = AttributeType::Binary; + BOOST_STATIC_CONSTEXPR size_t depth = 0; + }; + + struct type_introspection_visitor : boost::static_visitor<> { AttributeType type; @@ -747,7 +921,7 @@ namespace OC type(AttributeType::Null), base_type(AttributeType::Null), depth(0){} template - void operator()(T const& item) + void operator()(T const& /*item*/) { type = type_info::enum_type; base_type = type_info::enum_base_type; @@ -863,7 +1037,7 @@ namespace OC OCRepresentation::iterator& OCRepresentation::iterator::operator++() { m_iterator++; - if(m_iterator != m_item.m_values.end()) + if (m_iterator != m_item.m_values.end()) { m_item.m_attrName = m_iterator->first; } @@ -877,7 +1051,7 @@ namespace OC OCRepresentation::const_iterator& OCRepresentation::const_iterator::operator++() { m_iterator++; - if(m_iterator != m_item.m_values.end()) + if (m_iterator != m_item.m_values.end()) { m_item.m_attrName = m_iterator->first; } @@ -941,13 +1115,31 @@ namespace OC } template<> - void to_string_visitor::operator()(NullType const& item) + void to_string_visitor::operator()(NullType const& /*item*/) { str = "(null)"; } + template <> + void to_string_visitor::operator()(std::vector const &item) + { + std::ostringstream stream; + for (size_t i = 0; i < item.size(); i++ ) + { + stream << "\\x" << std::hex << (int) item[i]; + } + str = stream.str(); + } + + template<> + void to_string_visitor::operator()(OCByteString const &item) + { + std::vector v(item.bytes, item.bytes + item.len); + operator()(v); + } + template<> - void to_string_visitor::operator()(OCRepresentation const& item) + void to_string_visitor::operator()(OCRepresentation const& /*item*/) { str = "OC::OCRepresentation"; } @@ -955,7 +1147,7 @@ namespace OC std::string OCRepresentation::getValueToString(const std::string& key) const { auto x = m_values.find(key); - if(x != m_values.end()) + if (x != m_values.end()) { to_string_visitor vis; boost::apply_visitor(vis, x->second); @@ -978,4 +1170,3 @@ namespace OC return os; } } -