replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / resource / src / OCRepresentation.cpp
index 494f9aa..3d42719 100644 (file)
 #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 char* payload)
-    {
-        setJSONRepresentation(std::string(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);
 
-        // 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<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::setChildren(const std::vector<OCRepresentation>& 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<bool>(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<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(const 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(OCByteString item, void *array, size_t pos)
     {
-        return m_interfaces;
+        ((OCByteString *)array)[pos] = item;
     }
 
-    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(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 <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&)
+
+        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)
+    {
+        return pl->arr.bArray[index];
+    }
+    template<>
+    std::string OCRepresentation::payload_array_helper_copy<std::string>(
+            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<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
-        {
-            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<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)
+                val[i].resize(pl->arr.dimensions[1]);
+                for(size_t j = 0; j < pl->arr.dimensions[1]; ++j)
                 {
-                    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::INTERFACESKEY)
-                        {
-                            rep.setResourceInterfaces(
-                                    boost::get<std::vector<std::string>>(
-                                        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<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())
+            std::vector<std::vector<std::vector<T>>> 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<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");
         }
+    }
+
+    void OCRepresentation::setPayloadArray(const OCRepPayloadValue* pl)
+    {
 
-        template<class OutT>
-        struct valueToConcrete
+        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);
-                    break;
-                case 1:
-                    return valuesToConcreteVectors<std::vector<valueType>>(vs);
+                case OCREP_PROP_NULL:
+                    setNULL(val->name);
                     break;
-                case 2:
-                    return valuesToConcreteVectors<std::vector<std::vector<valueType>>>(vs);
+                case OCREP_PROP_INT:
+                    setValue<int>(val->name, val->i);
                     break;
-                case 3:
-                    return valuesToConcreteVectors
-                        <std::vector<std::vector<std::vector<valueType>>>>(vs);
+                case OCREP_PROP_DOUBLE:
+                    setValue<double>(val->name, val->d);
                     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_BOOL:
+                    setValue<bool>(val->name, val->b);
                     break;
-                case typeTag::_string:
-                    return remapArrayDepth<std::string>(curLevel, vs);
+                case OCREP_PROP_STRING:
+                    setValue<std::string>(val->name, val->str);
                     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)
+        {
+            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<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
@@ -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<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;
@@ -747,7 +921,7 @@ namespace OC
             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;
@@ -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<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";
     }
@@ -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;
     }
 }
-