//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-/// @file OCRepresentation.cpp
+/**
+ * @file
+ *
+ * This file contains the implementation of classes and its members related
+ * to OCRepresentation.
+ */
-/// @brief This file contains the implementation of classes and its members
-/// related to OCRepresentation
-
-#ifdef __ANDROID__
-#include "OCAndroid.h"
-#endif
#include <OCRepresentation.h>
#include <boost/lexical_cast.hpp>
-#include <cereal/cereal.hpp>
-#include <cereal/types/map.hpp>
-#include <cereal/types/vector.hpp>
-#include <cereal/types/utility.hpp>
-#include <OicJsonSerializer.hpp>
#include <algorithm>
+#include <iomanip>
+#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 Archive>
- 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<class T>
- 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<const OCRepPayload*>(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 <class Archive>
- void serialize(Archive&, OC::NullType t)
- {}
-
- template<class Archive>
- void save(Archive& ar, const std::map<std::string, OC::AttributeValue>& 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<Archive> 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<OCRepresentation>& MessageContainer::representations() const
+ {
+ return m_reps;
}
- template<class Archive>
- void load(Archive& ar, std::map<std::string, OC::AttributeValue>& 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<typename T>
+ 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 unsigned char* payload)
- {
- setJSONRepresentation(std::string(reinterpret_cast<const char*>(payload)));
- }
+ template<typename T>
+ void operator()(std::vector<T>& arr)
+ {
+ root_size_calc<T>();
+ 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);
+
+ for(size_t i = 0; i < dimensions[0]; ++i)
+ {
+ copy_to_array(arr[i], array, i);
+ }
- // 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<typename T>
+ void operator()(std::vector<std::vector<T>>& arr)
{
- if(f == OCInfoFormat::IncludeOC)
+ root_size_calc<T>();
+ 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<OCRepresentation>::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<typename T>
+ void operator()(std::vector<std::vector<std::vector<T>>>& arr)
+ {
+ root_size_calc<T>();
+ 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<OCRepresentation>& 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<typename T>
+ 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<typename T>
+ 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<int>()
{
- m_children.push_back(rep);
+ root_size = sizeof(int64_t);
}
- void OCRepresentation::clearChildren()
+ template<>
+ void get_payload_array::root_size_calc<std::string>()
{
- m_children.clear();
+ root_size = sizeof(char*);
}
- const std::vector<OCRepresentation>& OCRepresentation::getChildren() const
+ template<>
+ void get_payload_array::root_size_calc<OC::OCRepresentation>()
{
- return m_children;
+ root_size = sizeof(OCRepPayload*);
}
- void OCRepresentation::setUri(const std::string& uri)
+ template<>
+ void get_payload_array::copy_to_array(int item, void* array, size_t pos)
{
- m_uri = uri;
+ ((int64_t*)array)[pos] = item;
}
- std::string OCRepresentation::getUri() const
+#if !(defined(_MSC_VER) || defined(__APPLE__))
+ template<>
+ void get_payload_array::copy_to_array(std::_Bit_reference br, void* array, size_t pos)
{
- return m_uri;
+ ((bool*)array)[pos] = static_cast<bool>(br);
}
+#endif
- const std::vector<std::string>& 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<std::string>& resourceTypes)
+ template<>
+ void get_payload_array::copy_to_array(std::string& item, void* array, size_t pos)
{
- m_resourceTypes = resourceTypes;
+ ((char**)array)[pos] = OICStrdup(item.c_str());
}
- const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
+ template<>
+ void get_payload_array::copy_to_array(const std::string& item, void* array, size_t pos)
{
- return m_interfaces;
+ ((char**)array)[pos] = OICStrdup(item.c_str());
}
- void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& 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(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(const OCByteString &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;
+ ((OCByteString *)array)[pos] = item;
}
- int OCRepresentation::numberOfAttributes() const
+ template<>
+ void get_payload_array::copy_to_array(OC::OCRepresentation item, void* array, size_t pos)
{
- return m_values.size();
+ ((OCRepPayload**)array)[pos] = item.getPayload();
}
- bool OCRepresentation::erase(const std::string& str)
+ void OCRepresentation::getPayloadArray(OCRepPayload* payload,
+ const OCRepresentation::AttributeItem& item) const
{
- return m_values.erase(str);
- }
+ get_payload_array vis{};
+ boost::apply_visitor(vis, m_values[item.attrname()]);
- 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 <class Archive, class Val>
- 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<int>(val));
+ break;
+ case AttributeType::Double:
+ OCRepPayloadSetPropDouble(root, val.attrname().c_str(),
+ val.getValue<double>());
+ break;
+ case AttributeType::Boolean:
+ OCRepPayloadSetPropBool(root, val.attrname().c_str(), val.getValue<bool>());
+ break;
+ case AttributeType::String:
+ OCRepPayloadSetPropString(root, val.attrname().c_str(),
+ static_cast<std::string>(val).c_str());
+ break;
+ case AttributeType::OCByteString:
+ OCRepPayloadSetPropByteString(root, val.attrname().c_str(), val.getValue<OCByteString>());
+ break;
+ case AttributeType::OCRepresentation:
+ OCRepPayloadSetPropObjectAsOwner(root, val.attrname().c_str(),
+ static_cast<OCRepresentation>(val).getPayload());
+ break;
+ case AttributeType::Vector:
+ getPayloadArray(root, val);
+ break;
+ case AttributeType::Binary:
+ OCRepPayloadSetPropByteString(root, val.attrname().c_str(),
+ OCByteString{const_cast<uint8_t*>(val.getValue<std::vector<uint8_t>>().data()),
+ val.getValue<std::vector<uint8_t>>().size()});
+ break;
+ default:
+ throw std::logic_error(std::string("Getpayload: Not Implemented") +
+ std::to_string((int)val.type()));
+ break;
+ }
}
+
+ return root;
}
- template<class Archive>
- 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<std::string>& rt(m_resourceTypes);
- const std::vector<std::string>& intf(m_interfaces);
- Prop temp(const_cast<std::vector<std::string>&>(rt),
- const_cast<std::vector<std::string>&>(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<class Archive>
- 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<class Archive>
- void OCRepresentation::Prop::save(Archive& ar) const
+ template<typename T>
+ 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<int>(size_t index, const OCRepPayloadValue* pl)
+ {
+ return pl->arr.iArray[index];
+ }
+ template<>
+ double OCRepresentation::payload_array_helper_copy<double>(size_t index, const OCRepPayloadValue* pl)
+ {
+ return pl->arr.dArray[index];
+ }
+ template<>
+ bool OCRepresentation::payload_array_helper_copy<bool>(size_t index, const OCRepPayloadValue* pl)
{
- if(m_types.size() > 0)
+ return pl->arr.bArray[index];
+ }
+ template<>
+ std::string OCRepresentation::payload_array_helper_copy<std::string>(
+ size_t index, const OCRepPayloadValue* pl)
+ {
+ 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<class Archive>
- void OCRepresentation::Prop::load(Archive& ar)
+ template<>
+ OCByteString OCRepresentation::payload_array_helper_copy<OCByteString>(
+ 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<OCRepresentation>(
+ size_t index, const OCRepPayloadValue* pl)
{
- enum class typeTag:uint8_t
+ OCRepresentation r;
+ if (pl->arr.objArray[index])
{
- 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)
- {
- // 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<typename T>
+ 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<T> 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<T>(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<std::vector<T>> 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)
- {
- rep.setUri(boost::get<std::string>(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<std::vector<std::string>>(
- parseAttributeValue(itr->value)));
- }
- else if(keyName == OC::Key::PROPERTYKEY)
- {
- rep.setResourceInterfaces(
- boost::get<std::vector<std::string>>(
- parseAttributeValue(itr->value)));
- }
- }
- }
- else if (keyName == OC::Key::REPKEY)
+ val[i].resize(pl->arr.dimensions[1]);
+ for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
{
- 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<T>(
+ 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())
- {
- t = typeTag::_string;
- return std::string(v.GetString());
- }
- else if (v.IsNumber())
+ std::vector<std::vector<std::vector<T>>> val(pl->arr.dimensions[0]);
+ for(size_t i = 0; i < pl->arr.dimensions[0]; ++i)
{
- if(v.IsDouble())
+ val[i].resize(pl->arr.dimensions[1]);
+ for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
{
- t = typeTag::_double;
- return double(v.GetDouble());
- }
- else if (v.IsInt())
- {
- 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<T>(
+ 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<AttributeValue> gatherArrayContents(const GenericValue& v,
- const unsigned int curLevel, unsigned int& maxDepth, typeTag& t)
+ else
{
- std::vector<AttributeValue> 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");
}
+ }
- template<class OutT>
- struct valueToConcrete
+ void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
+ {
+
+ switch(pl->arr.type)
{
- OutT operator()(const AttributeValue& v)
- {
- return boost::get<OutT>(v);
- }
+ case OCREP_PROP_INT:
+ payload_array_helper<int>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_DOUBLE:
+ payload_array_helper<double>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_BOOL:
+ payload_array_helper<bool>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_STRING:
+ payload_array_helper<std::string>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_BYTE_STRING:
+ payload_array_helper<OCByteString>(pl, calcArrayDepth(pl->arr.dimensions));
+ break;
+ case OCREP_PROP_OBJECT:
+ payload_array_helper<OCRepresentation>(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 <class OutSeqT>
- OutSeqT valuesToConcreteVectors(const std::vector<AttributeValue>& 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<typename OutSeqT::value_type>());
- return ret;
+ ll = pl->interfaces;
+ while(ll)
+ {
+ addResourceInterface(ll->value);
+ ll = ll->next;
}
- template<class valueType>
- AttributeValue remapArrayDepth(const unsigned int curLevel,
- const std::vector<OC::AttributeValue>& vs)
+ OCRepPayloadValue* val = pl->values;
+
+ while(val)
{
- switch(curLevel)
+ switch(val->type)
{
- default:
- throw OC::OCException(OC::Exception::INVALID_JSON_ARRAY_DEPTH);
+ case OCREP_PROP_NULL:
+ setNULL(val->name);
break;
- case 1:
- return valuesToConcreteVectors<std::vector<valueType>>(vs);
+ case OCREP_PROP_INT:
+ setValue<int>(val->name, val->i);
break;
- case 2:
- return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
+ case OCREP_PROP_DOUBLE:
+ setValue<double>(val->name, val->d);
break;
- case 3:
- return valuesToConcreteVectors
- <std::vector<std::vector<std::vector<valueType>>>>(vs);
+ case OCREP_PROP_BOOL:
+ setValue<bool>(val->name, val->b);
break;
- }
- }
-
- AttributeValue convertArrayToConcretes(const typeTag t,
- const unsigned int curLevel, const std::vector<OC::AttributeValue>& 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_STRING:
+ setValue<std::string>(val->name, val->str);
break;
- case typeTag::_string:
- return remapArrayDepth<std::string>(curLevel, vs);
- break;
- case typeTag::_int:
- return remapArrayDepth<int>(curLevel, vs);
+ case OCREP_PROP_OBJECT:
+ {
+ OCRepresentation cur;
+ cur.setPayload(val->obj);
+ setValue<OCRepresentation>(val->name, cur);
+ }
break;
- case typeTag::_double:
- return remapArrayDepth<double>(curLevel, vs);
+ case OCREP_PROP_ARRAY:
+ setPayloadArray(val);
break;
- case typeTag::_bool:
- return remapArrayDepth<bool>(curLevel, vs);
+ case OCREP_PROP_BYTE_STRING:
+ setValue(val->name,
+ std::vector<uint8_t>
+ (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len)
+ );
break;
- case typeTag::_representation:
- return remapArrayDepth<OCRepresentation>(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>& OCRepresentation::getChildren() const
+ {
+ return m_children;
+ }
+
+ void OCRepresentation::setChildren(const std::vector<OCRepresentation>& 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)
{
- const unsigned int max_level = 3;
+ ss << COAPS;
+ }
+ else if (devAddr.adapter & OC_ADAPTER_TCP)
+ {
+ ss << COAP_TCP;
+ }
+ else
+ {
+ ss << COAP;
+ }
+ if (devAddr.flags & OC_IP_USE_V6)
+ {
+ 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;
+ }
+
+ 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;
+ }
- auto arrayItems = gatherArrayContents(v, curLevel, maxDepth, t);
- const int remapLevel = maxDepth - (curLevel -1);
- return convertArrayToConcretes(t, remapLevel, arrayItems);
+ const std::vector<std::string>& OCRepresentation::getResourceTypes() const
+ {
+ return m_resourceTypes;
+ }
+
+ void OCRepresentation::setResourceTypes(const std::vector<std::string>& resourceTypes)
+ {
+ m_resourceTypes = resourceTypes;
+ }
+
+ void OCRepresentation::addResourceType(const std::string& str)
+ {
+ m_resourceTypes.push_back(str);
+ }
+
+ const std::vector<std::string>& OCRepresentation::getResourceInterfaces() const
+ {
+ return m_interfaces;
+ }
+
+ void OCRepresentation::addResourceInterface(const std::string& str)
+ {
+ m_interfaces.push_back(str);
+ }
+
+ void OCRepresentation::setResourceInterfaces(const std::vector<std::string>& resourceInterfaces)
+ {
+ m_interfaces = resourceInterfaces;
+ }
+
+ const std::vector<std::string>& 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<std::string, OC::AttributeValue>& 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
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;
}
// 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<T>::type;
// contains the AttributeType for this base-type
- constexpr static AttributeType enum_base_type =
+ BOOST_STATIC_CONSTEXPR AttributeType enum_base_type =
AttributeTypeConvert<T>::type;
// depth of the vector
- constexpr static size_t depth = 0;
+ BOOST_STATIC_CONSTEXPR size_t depth = 0;
};
template<typename T>
- struct type_info<T, typename std::enable_if<is_vector<T>::value>::type>
+ struct type_info<
+ T,
+ typename std::enable_if<
+ is_vector<T>::value &&
+ !std::is_same<uint8_t, typename T::value_type>::value
+ >::type
+ >
{
typedef T type;
typedef typename type_info<typename T::value_type>::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<typename T::value_type>::enum_base_type;
- constexpr static size_t depth = 1 +
+ BOOST_STATIC_CONSTEXPR size_t depth = 1 +
type_info<typename T::value_type>::depth;
};
+ // special case for binary data, which is a std::vector<uint8_t>
+ template<>
+ struct type_info<std::vector<uint8_t>, void>
+ {
+ typedef std::vector<uint8_t> type;
+ typedef std::vector<uint8_t> 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;
type(AttributeType::Null), base_type(AttributeType::Null), depth(0){}
template <typename T>
- void operator()(T const& item)
+ void operator()(T const& /*item*/)
{
type = type_info<T>::enum_type;
base_type = type_info<T>::enum_base_type;
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;
}
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;
}
}
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<uint8_t> 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<uint8_t> 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";
}
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);