summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Szyndela <adrian.s@samsung.com>2020-10-26 08:59:21 +0100
committerAdrian Szyndela <adrian.s@samsung.com>2020-10-30 13:23:17 +0100
commit64518947c0104ba5ede353344f98aefcf1848b8d (patch)
tree8c4cdfbbaede46f60759f66a15493d6ff27a348f
parent28f67fa5d0f4d00b924bedca2bdddf3a44fa5226 (diff)
downloadlibdbuspolicy-64518947c0104ba5ede353344f98aefcf1848b8d.tar.gz
libdbuspolicy-64518947c0104ba5ede353344f98aefcf1848b8d.tar.bz2
libdbuspolicy-64518947c0104ba5ede353344f98aefcf1848b8d.zip
serialization: add direct backend
Change-Id: I5c9345310f58fa62c7fec3d8a1ccc56978e4c53a
-rw-r--r--Makefile.am2
-rw-r--r--src/internal/serialization_backend.hpp10
-rw-r--r--src/internal/serialized.hpp259
-rw-r--r--src/internal/serializer_direct.cpp170
-rw-r--r--src/internal/serializer_direct.hpp37
-rw-r--r--src/internal/storage_backend_direct.cpp31
-rw-r--r--src/internal/storage_backend_direct.hpp636
7 files changed, 1144 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index f17af0b..da4f145 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -64,8 +64,10 @@ COMMON_SRC =\
src/internal/tslog.cpp \
src/internal/serializer.cpp \
src/internal/serializer_flatbuffers.cpp \
+ src/internal/serializer_direct.cpp \
src/internal/policy_containers.cpp \
src/internal/print_content.cpp \
+ src/internal/storage_backend_direct.cpp \
src/internal/storage_backend_flatbuffers.cpp \
src/internal/storage_backend_serialized.cpp \
src/internal/storage_backend_xml.cpp
diff --git a/src/internal/serialization_backend.hpp b/src/internal/serialization_backend.hpp
index 2b3395a..159ae0d 100644
--- a/src/internal/serialization_backend.hpp
+++ b/src/internal/serialization_backend.hpp
@@ -22,6 +22,9 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. */
+#include "serializer_direct.hpp"
+#include "storage_backend_direct.hpp"
+
#include "serializer_flatbuffers.hpp"
#include "storage_backend_flatbuffers.hpp"
@@ -32,6 +35,11 @@ struct SerializationBackendFlatbuffers {
typedef ldp_serializer::SerializerFlatbuffers Serializer;
};
-typedef SerializationBackendFlatbuffers SerializationBackend;
+struct SerializationBackendDirect {
+ typedef ldp_serialized::StorageBackendDirect Storage;
+ typedef ldp_serializer::SerializerDirect Serializer;
+};
+
+typedef SerializationBackendDirect SerializationBackend;
}
diff --git a/src/internal/serialized.hpp b/src/internal/serialized.hpp
new file mode 100644
index 0000000..70589af
--- /dev/null
+++ b/src/internal/serialized.hpp
@@ -0,0 +1,259 @@
+#pragma once
+
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include <cassert>
+#include <boost/utility/string_ref.hpp>
+#include <string>
+#include <vector>
+
+namespace ldp_serializer {
+
+/* The Serialized class represents serialized data created from some structures.
+ * It serializes values of the following types:
+ * - uint32_t;
+ * - enum types (serialized as uint32_t);
+ * - bool type (serialized as uint32_t)
+ * - container types (maps, sets, vectors, serialized as a kind of array, needs special preparation, see below);
+ * - string types, as a special case of container types.
+ *
+ * Usage: prepare your data, and pass them to the constructor.
+ * Example: if your data is:
+ * - single integer: 123;
+ * - single enum value: MyEnumValue;
+ * - single string: "MyString";
+ * - a single, already serialized object Already;
+ * - a map v: int->string;
+ * you may serialize the data by writing:
+ * auto serialized = Serialized{123, MyEnumValue, "MyString", Already,
+ * serialize_container(v, [](const auto &elem) {
+ * return Serialized{elem.first, elem.second};
+ * })};
+ * const uint8_t *data = serialized.releaseData(); // or better const auto *data = ...
+ *
+ * when you're done serializing, get your data with releaseData() method. You're now responsible for
+ * freeing the data. The Serialized object can be now disposed.
+ *
+ * NOTE: Never try to serialize just a single already serialized object, as this probably won't work.
+ * It may destroy your object.
+ * ... and it makes little sense. It would just wrap it in another, unnecessary layer.
+ * Unfortunately, I didn't come up with a way to prevent it yet.
+ *
+ * The map above is serialized with helper function serialize_container, which takes 2 arguments:
+ * - a container;
+ * - a function object used to prepare a serialized element of the container.
+ * This is all for the special preparation. It creates a Serialized vector of Serialized elements,
+ * which you can pass as an argument for further serialization.
+ *
+ * Internal layout:
+ * Each Serialized object data contains a data buffer.
+ * A data buffer contains a number of fields and additional data.
+ * The number of fields is equal to the number of the parameters of the constructor.
+ * Each field is the same size as uint32_t.
+ * Any integer, enum, or bool is serialized as a field.
+ * Every other type is serialized like this:
+ * - the data is appended directly after the fields.
+ * - the corresponding field contains offset (from the start of the buffer) of the start of the data.
+ * The appended data may be a string. String data is serialized as:
+ * - a single uint32_t value, the string's length;
+ * - the characters;
+ * - nul byte;
+ * - padding.
+ * The appended data may be a vector. Vector data is serialized as fields:
+ * - field at index 0 contains number of elements in the vector;
+ * - first input element is serialized as a field at index 1, taking into account the rules
+ * above, that is integer = in-place field, other type = offset + data.
+ * - the indexes are relative to the first field at which vector is appended. The idea is
+ * that a vector should serialized to its own Serialized object, and then to another Serialized object as a field,
+ * but it should also work with serializing it "inline", as a series of fields.
+ */
+
+class Serialized {
+ typedef uint32_t HeaderFieldType;
+ constexpr size_t alignment() { return sizeof(HeaderFieldType); }
+
+ std::unique_ptr<uint8_t[]> _data;
+ size_t _size{0}; // keeps the total allocated _data size
+ size_t _done{0}; // indicates how many fields were already written
+ size_t _done_bytes{0}; // indicates an offset where another field's data can be written
+
+ HeaderFieldType *fields() { return reinterpret_cast<HeaderFieldType*>(_data.get()); }
+ uint8_t *buf() { return &_data[_done_bytes]; }
+
+ void startNextDataField() {
+ fields()[_done++] = _done_bytes;
+ }
+
+ void written(size_t len) {
+ _done_bytes += len;
+ }
+
+ template <typename T>
+ void writeContainerData(T iterator, T end_iterator) {
+ std::copy(iterator, end_iterator, buf());
+ written((end_iterator - iterator) * sizeof(*iterator));
+ }
+
+ template <typename T>
+ void writeString(const T &field) {
+ startNextDataField();
+
+ // write string length (without nul-byte)
+ *reinterpret_cast<uint32_t *>(buf()) = field.size();
+ written(sizeof(uint32_t));
+
+ writeContainerData(field.begin(), field.end());
+
+ // add nul byte and padding
+ do {
+ *buf() = 0;
+ written(1);
+ } while (_done_bytes % alignment() != 0);
+ }
+
+ template <typename ...Args>
+ size_t computeSize(const Serialized &s, const Args &...args)
+ { return s.size() + computeSize(args...); }
+
+ inline size_t strSize(size_t length) {
+ uint32_t size = length + 1 + sizeof(uint32_t); // 1: nul byte; placeholder for string length
+ return size + alignment() - (size%alignment()); // padding to alignment boundary
+ }
+
+ template <typename ...Args>
+ size_t computeSize(const std::string &s, const Args &...args)
+ { return strSize(s.size()) + computeSize(args...); }
+
+ template <typename ...Args>
+ size_t computeSize(boost::string_ref s, const Args &...args)
+ { return strSize(s.size()) + computeSize(args...); }
+
+ template <typename ...Args>
+ size_t computeSize(uint32_t, const Args &...args)
+ { return computeSize(args...); }
+
+ template <typename T, typename ...Args>
+ size_t computeSize(const std::vector<T> &v, const Args &...args) {
+ size_t size = sizeof(uint32_t);
+ for (const auto &elem: v)
+ size += computeSize(elem);
+ return size + computeSize(args...);
+ }
+
+ template <typename T,
+ typename = std::enable_if_t<std::is_enum<T>::value>,
+ typename ...Args>
+ size_t computeSize(T, const Args &...args)
+ { return computeSize(args...); }
+
+ size_t computeSize() { return 0; }
+
+ template <typename T, typename ...Args>
+ size_t computeNumOfFields(const T &, const Args &...args)
+ { return 1 + computeNumOfFields(args...); }
+
+ template <typename ...Args>
+ size_t computeNumOfFields(const Serialized &s, const Args &...args)
+ { return (s.size() ? 1 : 0) + computeNumOfFields(args...); }
+
+ template <typename T, typename ...Args>
+ size_t computeNumOfFields(const std::vector<T> &v, const Args &...args)
+ { return 1 + v.size() + computeNumOfFields(args...); } // 1 for list size
+
+ size_t computeNumOfFields() { return 0; }
+
+ template <typename T, typename ...Args>
+ void writeFields(const T &t, const Args &...args) {
+ writeField(t);
+ writeFields(args...);
+ }
+
+ void writeFields() {}
+
+ void writeField(const Serialized &field) {
+ // we ignore empty fields
+ if (field.size() == 0)
+ return;
+ assert(field.data());
+
+ startNextDataField();
+
+ writeContainerData(field.data(), field.data() + field.size());
+ }
+ void writeField(const std::string &field) {
+ writeString(field);
+ }
+ void writeField(boost::string_ref field) {
+ writeString(field);
+ }
+ void writeField(uint32_t field) {
+ fields()[_done++] = field;
+ }
+ template <typename T>
+ void writeField(const std::vector<T> &v) {
+ writeField(v.size());
+ for (const auto &elem: v)
+ writeField(elem);
+ }
+ template <typename T,
+ typename = std::enable_if_t<std::is_enum<T>::value>,
+ typename ...Args>
+ void writeField(T field) {
+ writeField(static_cast<uint32_t>(field));
+ }
+ const uint8_t *data() const { return _data.get(); }
+public:
+ // NOTE: never serialize single Serialized object into Serialized object as it may just swap data
+ // ... and it makes little sense anyway
+ Serialized(Serialized &&s) : _data{s._data.release()}, _size{s._size}, _done{s._done}, _done_bytes{s._done_bytes} {}
+
+ template <typename ...Args>
+ explicit Serialized(const Args &...args)
+ {
+ _done_bytes = computeNumOfFields(args...) * sizeof(uint32_t);
+ _size = _done_bytes + computeSize(args...);
+ if (_size)
+ _data = std::make_unique<uint8_t[]>(_size);
+
+ writeFields(args...);
+ }
+
+ uint32_t size() const { return _size; }
+
+ const uint8_t *releaseData() {
+ return _data.release();
+ }
+};
+
+template <typename T, typename F>
+Serialized serialize_container(const T &container, const F &serialize_elem_fun) {
+ std::vector<Serialized> sx;
+ sx.reserve(container.size());
+
+ for (const auto &e: container)
+ sx.push_back(serialize_elem_fun(e));
+
+ return Serialized{sx};
+}
+
+}
diff --git a/src/internal/serializer_direct.cpp b/src/internal/serializer_direct.cpp
new file mode 100644
index 0000000..d74ce9b
--- /dev/null
+++ b/src/internal/serializer_direct.cpp
@@ -0,0 +1,170 @@
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include "policy_containers.hpp"
+#include "serialization_traits.hpp"
+#include "serialized.hpp"
+#include "serializer_direct.hpp"
+
+using namespace ldp_serializer;
+using ldp_serializer::Serialized;
+using ldp_serializer::serialize_container;
+
+class SerializerDirectImpl {
+ const ldp_xml::StorageBackendXML &_db;
+
+ template <typename ItemType>
+ Serialized serializeItem(const ItemType &v);
+
+ template <typename ItemType>
+ Serialized serializeItems(const std::vector<ItemType> &v) {
+ return serialize_container(v,
+ [&](const auto &item) {
+ return serializeItem(item);
+ });
+ }
+
+ template <typename PolicyType>
+ Serialized serializePolicy(const PolicyType &policy);
+
+ template <typename PolicyType>
+ Serialized serializeUserGroup(const std::map<uid_t, PolicyType> &m) {
+ return serialize_container(m,
+ [&](const auto &u) {
+ return Serialized{
+ u.first,
+ this->serializePolicy(u.second)};
+ });
+ }
+
+ Serialized serializeDecisionItem(const ldp_xml_parser::DecisionItem &item) {
+ return Serialized{
+ item.getDecision(),
+ item.getPrivilege()};
+ }
+
+ Serialized serializeTree(const std::shared_ptr<ldp_xml_parser::TreeNode> &node) {
+ return Serialized{
+ node->getToken(),
+ serializeDecisionItem(node->getOwnPrefixDecisionItem()),
+ serializeDecisionItem(node->getOwnDecisionItem()),
+ serialize_container(node->getChildren(),
+ [&](const auto &child) {
+ return serializeTree(child.second);
+ })
+ };
+ }
+
+ template <typename PolicyType>
+ Serialized serializeSet();
+
+public:
+ SerializerDirectImpl(const ldp_xml::StorageBackendXML &db)
+ : _db{db}
+ {}
+
+ const uint8_t *serialize(size_t &size);
+};
+
+template <typename ItemType>
+Serialized SerializerDirectImpl::serializeItem(const ItemType &item) {
+ return Serialized{
+ serializeDecisionItem(item.getDecision()),
+ item.getName(),
+ item.getInterface(),
+ item.getMember(),
+ item.getPath(),
+ item.getType(),
+ item.isNamePrefix()};
+}
+
+template <>
+Serialized SerializerDirectImpl::serializeItem(const ldp_xml_parser::ItemAccess &item) {
+ return Serialized{
+ serializeDecisionItem(item.getDecision()),
+ item.getUid(),
+ item.getGid(),
+ item.getType()};
+}
+
+template <typename PolicyType>
+Serialized SerializerDirectImpl::serializePolicy(const PolicyType &policy) {
+ return serializeItems(policy.getItems());
+}
+
+template <>
+Serialized SerializerDirectImpl::serializePolicy(const ldp_xml_parser::PolicyOwn &policy) {
+ return serializeTree(policy.getTree().getRoot());
+}
+
+template <>
+Serialized SerializerDirectImpl::serializePolicy(const ldp_xml_parser::PolicySend &policy) {
+ return Serialized{
+ serializeItems(policy.getItems()),
+ serialize_container(policy.getIndex(),
+ [&](const auto &elem) {
+ return Serialized{
+ elem.first,
+ elem.second.m_bestScore,
+ Serialized{elem.second.m_itemRefs}
+ };
+ }),
+ Serialized{policy.getPrefixIndex()}};
+}
+
+template <typename PolicyType>
+Serialized SerializerDirectImpl::serializeSet() {
+ return Serialized{
+ serializePolicy(_db.getPolicyContextMandatory<PolicyType>()),
+ serializePolicy(_db.getPolicyContextDefault<PolicyType>()),
+ serializeUserGroup(_db.getPoliciesUser<PolicyType>()),
+ serializeUserGroup(_db.getPoliciesGroup<PolicyType>())
+ };
+}
+
+template <>
+Serialized SerializerDirectImpl::serializeSet<ldp_xml_parser::PolicyAccess>() {
+ return Serialized{
+ serializePolicy(_db.getPolicyContextMandatory<ldp_xml_parser::PolicyAccess>()),
+ serializePolicy(_db.getPolicyContextDefault<ldp_xml_parser::PolicyAccess>())
+ };
+}
+
+const uint8_t *SerializerDirectImpl::serialize(size_t &size) {
+ Serialized r{
+ serializeSet<ldp_xml_parser::PolicyOwn>(),
+ serializeSet<ldp_xml_parser::PolicySend>(),
+ serializeSet<ldp_xml_parser::PolicyReceive>(),
+ serializeSet<ldp_xml_parser::PolicyAccess>()};
+
+ size = r.size();
+ return r.releaseData();
+}
+
+SerializerDirect::SerializerDirect()
+{}
+
+const uint8_t *SerializerDirect::serialize(const ldp_xml::StorageBackendXML &db, size_t &size) {
+ SerializerDirectImpl impl{db};
+ _data.reset(impl.serialize(size));
+ return _data.get();
+}
diff --git a/src/internal/serializer_direct.hpp b/src/internal/serializer_direct.hpp
new file mode 100644
index 0000000..8b75d19
--- /dev/null
+++ b/src/internal/serializer_direct.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include "storage_backend_xml.hpp"
+#include <memory>
+
+namespace ldp_serializer {
+
+class SerializerDirect {
+ std::unique_ptr<const uint8_t> _data;
+public:
+ SerializerDirect();
+ const uint8_t *serialize(const ldp_xml::StorageBackendXML &db, size_t &size);
+};
+
+}
diff --git a/src/internal/storage_backend_direct.cpp b/src/internal/storage_backend_direct.cpp
new file mode 100644
index 0000000..455f443
--- /dev/null
+++ b/src/internal/storage_backend_direct.cpp
@@ -0,0 +1,31 @@
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include "storage_backend_direct.hpp"
+
+using namespace ldp_serialized;
+
+bool StorageBackendDirect::initFromData(const uint8_t *mem, size_t , bool ) {
+
+ file = reinterpret_cast<const File*>(mem);
+ return file != nullptr;
+}
diff --git a/src/internal/storage_backend_direct.hpp b/src/internal/storage_backend_direct.hpp
new file mode 100644
index 0000000..4b3b47b
--- /dev/null
+++ b/src/internal/storage_backend_direct.hpp
@@ -0,0 +1,636 @@
+#pragma once
+
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include "serialized_convert.hpp"
+#include "serialization_traits.hpp"
+#include <cassert>
+
+namespace ldp_serialized {
+
+/* This file contains definition of classes that help with deserializing data
+ * serialized with Serialized objects.
+ *
+ * It works like this:
+ * - the objects are not created in the traditional way (with constructors);
+ * - instead they are "mapped" into their serialized data - so they should not have
+ * any data members;
+ * - an existing object operates on its "this" pointer to compute offsets proper
+ * to the object class to find pointers to contained types, or copy integer
+ * values.
+ *
+ * It all starts with File object, which is mapped directly into the first byte of
+ * the serialized data. Then the File object knows how to find further pointers.
+ * This is roughly the schema for the data:
+ *
+ * File {
+ * OwnSet {
+ * context_default: PolicyOwn;
+ * context_mandatory: PolicyOwn;
+ * user: array of {id, PolicyOwn};
+ * group: array of {id, PolicyOwn};
+ *
+ * // id = integer, mapped to respectively uid_t and gid_t
+ * define PolicyOwn = {
+ * tree: PolicyOwnNode;
+ *
+ * define PolicyOwnNode = {
+ * token: string;
+ * prefix_decision_item: DecisionItem;
+ * decision_item: DecisionItem;
+ * children: array of PolicyOwnNode;
+ * }
+ * }
+ * }
+ * SendSet {
+ * context_default: PolicySend;
+ * context_mandatory: PolicySend;
+ * user: array of {id, PolicySend};
+ * group: array of {id, PolicySend};
+ *
+ * define PolicySend = {
+ * items: array of {
+ * define ItemSend = {
+ * decision: DecisionItem;
+ * name: string;
+ * interface: string;
+ * member: string;
+ * path: string;
+ * type: MessageType;
+ * is_name_prefix: bool;
+ * }
+ * }
+ * index: array of {
+ * name: string;
+ * best_score: uint32_t;
+ * item_refs: array of {uint32_t};
+ * }
+ * prefix_index: array of {uint32_t};
+ * }
+ * }
+ * ReceiveSet {
+ * context_default: PolicyReceive;
+ * context_mandatory: PolicyReceive;
+ * user: array of {id, PolicyReceive};
+ * group: array of {id, PolicyReceive};
+ *
+ * define PolicyReceive = {
+ * items: array of {
+ * define ItemReceive = {
+ * decision: DecisionItem;
+ * name: string;
+ * interface: string;
+ * member: string;
+ * path: string;
+ * type: MessageType;
+ * is_name_prefix: bool;
+ * }
+ * }
+ * }
+ * AccessSet {
+ * context_default: PolicyAccess;
+ * context_mandatory: PolicyAccess;
+ *
+ * define PolicyAccess = {
+ * items: array of {
+ * define ItemAccess = {
+ * uid: uint;
+ * gid: uint;
+ * decision: DecisionItem;
+ * type: BusAccessType;
+ * }
+ * }
+ * }
+ * }
+ *
+ * define DecisionItem = {
+ * decision: Decision;
+ * privilege: string;
+ * }
+ * }
+ *
+ */
+
+/* This class is a base for all the data extractors just to provide them some handy helpers.
+ */
+class BufferBase {
+ BufferBase() = delete;
+protected:
+ // a short-typing caster
+ template <typename Type, typename AnyType>
+ const Type *T(const AnyType *t) const
+ { return reinterpret_cast<const Type *>(t); }
+
+ // this gives pointer to the buffer with a given offset
+ const uint8_t *buf(size_t offset=0) const { return T<uint8_t>(this) + offset; }
+ // this gives value of specified field 'num' - either the field itself
+ // or offset to additional data
+ uint32_t offset(size_t num) const { return T<uint32_t>(this)[num]; }
+
+ // this gives pointer to additional data of the field 'num'
+ template <typename Type>
+ const Type *ptr(size_t num) const
+ { return T<Type>(buf(offset(num))); }
+};
+
+// String extracting class
+class Str : private BufferBase {
+public:
+ typedef uint32_t SizeType;
+
+ const char *c_str() const
+ { return T<char>(buf(sizeof(SizeType))); }
+ SizeType size() const
+ { return offset(0); }
+ const boost::string_ref toStringRef() const
+ { return boost::string_ref(c_str(), size()); }
+};
+
+// Simple array extracting class - works for arrays of integers
+template <typename Elem = uint32_t>
+class SimpleList : protected BufferBase {
+public:
+ // first uint32_t is size (number of elements in the list)
+ size_t size() const { return offset(0); }
+ // iterators are plain pointers
+ const Elem *begin() const
+ { return T<Elem>(buf(sizeof(uint32_t))); }
+ const Elem *end() const
+ { return begin() + size(); }
+ // at() returns by value, because SimpleList is used only for uint32_t anyway
+ Elem at(size_t idx) const
+ { return begin()[idx]; }
+};
+
+// Iterator for non-simple arrays
+template <typename Elem>
+class Iterator {
+ const uint8_t *_root;
+ size_t _pos{0};
+ uint32_t offset(size_t num) const { return reinterpret_cast<const uint32_t *>(_root)[num]; }
+public:
+ Iterator(const uint8_t *buf, size_t pos) : _root{buf}, _pos{pos} {}
+
+ const Elem *operator*() const
+ { return reinterpret_cast<const Elem *>(&_root[offset(_pos)]); }
+
+ Iterator &operator++() {
+ _pos++;
+ return *this;
+ }
+ Iterator operator++(int)
+ { return Iterator(_root, _pos++); }
+ Iterator &operator--() {
+ _pos--;
+ return *this;
+ }
+ Iterator operator--(int)
+ { return Iterator(_root, _pos--); }
+ bool operator!=(const Iterator &rhs)
+ { return _pos != rhs._pos; }
+
+ int operator-(Iterator rhs)
+ { return static_cast<int>(_pos) - rhs._pos; }
+ void operator+=(int val)
+ { _pos += val; }
+
+ // This Iterator class lacks some operators (counterparts "==" , "+", "-=" to the above)
+ // only because we don't need them for our goals.
+ // This is very internal code, so we don't push it to be nice to everyone.
+};
+
+// Non-simple array extracting class
+template <typename Elem>
+class List : protected BufferBase {
+public:
+ size_t size() const { return offset(0); }
+ auto begin() const
+ { return Iterator<Elem>(BufferBase::buf(), 1); }
+ auto end() const
+ { return Iterator<Elem>(BufferBase::buf(), size()+1); }
+ const auto *at(size_t idx) const
+ { return *Iterator<Elem>(buf(), idx+1); }
+};
+
+class DecisionItem : private BufferBase {
+public:
+ auto getDecision() const
+ { return makeDecision(offset(0)); }
+ const auto *getPrivilege() const
+ { return ptr<Str>(1); }
+};
+
+class PolicyOwnNode : private BufferBase {
+public:
+ typedef DecisionItem DecisionItemType;
+ typedef List<PolicyOwnNode> ChildrenType;
+
+ const auto *getToken() const
+ { return ptr<Str>(0); }
+ const auto *getPrefixDecisionItem() const
+ { return ptr<DecisionItemType>(1); }
+ const auto *getDecisionItem() const
+ { return ptr<DecisionItemType>(2); }
+ const auto *getChildren() const
+ { return ptr<ChildrenType>(3); }
+};
+
+class NameScoresPair : private BufferBase {
+public:
+ const auto *getName() const
+ { return ptr<Str>(0); }
+ uint32_t getBestScore() const
+ { return offset(1); }
+ const auto *getItemRefs() const
+ { return ptr<SimpleList<>>(2); }
+};
+
+class ItemAccess : private BufferBase {
+public:
+ const auto *getDecisionItem() const
+ { return ptr<DecisionItem>(0); }
+ auto getUid() const
+ { return static_cast<uid_t>(offset(1)); }
+ auto getGid() const
+ { return static_cast<gid_t>(offset(2)); }
+ auto getType() const
+ { return makeBusAccessType(offset(3)); }
+};
+
+class ItemSR : private BufferBase {
+public:
+ const auto *getDecisionItem() const
+ { return ptr<DecisionItem>(0); }
+ auto getName() const
+ { return ptr<Str>(1); }
+ auto getInterface() const
+ { return ptr<Str>(2); }
+ auto getMember() const
+ { return ptr<Str>(3); }
+ auto getPath() const
+ { return ptr<Str>(4); }
+ auto getMessageType() const
+ { return makeMessageType(offset(5)); }
+ auto getIsNamePrefix() const
+ { return !!offset(6); }
+};
+
+class ItemSend : public ItemSR {};
+class ItemReceive : public ItemSR {};
+
+class PolicyOwn : private BufferBase {
+public:
+ const auto *getTree() const
+ { return T<PolicyOwnNode>(this); }
+};
+
+template <typename ItemType>
+class Policy : protected BufferBase {
+public:
+ typedef List<ItemType> ListType;
+
+ const auto *getItems() const
+ { return T<ListType>(this); }
+};
+
+using PolicyAccess = Policy<ItemAccess>;
+using PolicyReceive = Policy<ItemReceive>;
+
+class PolicySend : protected BufferBase {
+public:
+ typedef List<ItemSend> ListType;
+ typedef NameScoresPair IndexElemType;
+ typedef List<IndexElemType> IndexType;
+ typedef SimpleList<> PrefixIndexType;
+
+ const auto *getItems() const
+ { return ptr<ListType>(0); }
+ const auto *getIndex() const
+ { return ptr<IndexType>(1); }
+ const auto *getPrefixIndex() const
+ { return ptr<PrefixIndexType>(2); }
+};
+
+template <typename PolicyType>
+class PolicyPair : private BufferBase {
+public:
+ id_t getId() const
+ { return static_cast<id_t>(offset(0)); }
+
+ const auto *getPolicy() const
+ { return ptr<PolicyType>(1); }
+};
+
+template <typename PolicyType>
+class Set : private BufferBase {
+public:
+ typedef List<PolicyPair<PolicyType>> ListType;
+
+ const auto *getContextMandatory() const
+ { return ptr<PolicyType>(0); }
+ const auto *getContextDefault() const
+ { return ptr<PolicyType>(1); }
+ const auto *getUser() const
+ { return ptr<ListType>(2); }
+ const auto *getGroup() const
+ { return ptr<ListType>(3); }
+};
+
+class File : private BufferBase {
+public:
+ typedef Set<PolicyOwn> OwnSetType;
+ typedef Set<PolicySend> SendSetType;
+ typedef Set<PolicyReceive> ReceiveSetType;
+ typedef Set<PolicyAccess> AccessSetType;
+
+ const auto *getOwnSet() const
+ { return ptr<OwnSetType>(0); }
+ const auto *getSendSet() const
+ { return ptr<SendSetType>(1); }
+ const auto *getReceiveSet() const
+ { return ptr<ReceiveSetType>(2); }
+ const auto *getAccessSet() const
+ { return ptr<AccessSetType>(3); }
+};
+
+class StorageBackendDirect {
+ // this private subclass is needed for looking up elements in containers by their key with std::lower_bound
+ template <typename ExtractKey>
+ class Comparator {
+ ExtractKey _f;
+ public:
+ Comparator(const ExtractKey &fun) : _f{fun} {}
+ template <typename R, typename K>
+ bool operator()(const R &r, const K &k) {
+ return _f(r) < k;
+ }
+ };
+
+ template <typename T>
+ auto makeComparator(const T &fun) const { return Comparator<T>{fun}; }
+
+ template <typename T, typename K, typename E>
+ auto containerLookupByKey(const T *container, const K &key, const E &extractKey) const {
+ assert(container->size());
+ auto found = std::lower_bound(container->begin(), container->end(), key, makeComparator(extractKey));
+ if (found != container->end() && extractKey(*found) == key)
+ return std::make_pair(true, *found);
+ return std::make_pair(false, *container->begin());
+ }
+public:
+ bool initFromData(const uint8_t *serialized_data, size_t size, bool verify = false);
+ void release() {}
+
+ auto getFile() const
+ { return file; }
+
+ auto fileGetOwnSet(const File *file) const
+ { return file->getOwnSet(); }
+ auto fileGetSendSet(const File *file) const
+ { return file->getSendSet(); }
+ auto fileGetReceiveSet(const File *file) const
+ { return file->getReceiveSet(); }
+ auto fileGetAccessSet(const File *file) const
+ { return file->getAccessSet(); }
+
+ template <typename PolicyType>
+ auto setGetContextDefault(const Set<PolicyType> *set) const
+ { return set->getContextDefault(); }
+
+ template <typename PolicyType>
+ auto setGetContextMandatory(const Set<PolicyType> *set) const
+ { return set->getContextMandatory(); }
+
+ template <typename PolicyType>
+ auto setGetUser(const Set<PolicyType> *set) const
+ { return set->getUser(); }
+
+ template <typename PolicyType>
+ auto setGetGroup(const Set<PolicyType> *set) const
+ { return set->getGroup(); }
+
+ template <typename PolicyType>
+ int setUserGroupGetId(const PolicyPair<PolicyType> *set_user_group) const
+ { return set_user_group->getId(); }
+
+ template <typename PolicyType>
+ auto setUserGroupGetPolicy(const PolicyPair<PolicyType> *set_user_group) const
+ { return set_user_group->getPolicy(); }
+
+ auto policyGetTree(const PolicyOwn *policy) const
+ { return policy->getTree(); }
+
+ template <typename PolicyType>
+ auto policyGetItems(const PolicyType *policy) const
+ { return policy->getItems(); }
+
+ auto policyHasIndex(const PolicySend *policy) const
+ { return policy->getIndex()->size() > 0; }
+
+ auto policyGetIndex(const PolicySend *policy) const
+ { return policy->getIndex(); }
+
+ auto policyGetPrefixIndex(const PolicySend *policy) const
+ { return policy->getPrefixIndex(); }
+
+ auto policyIndexGetName(const NameScoresPair *p) const
+ { return p->getName(); }
+
+ auto policyIndexGetBestScore(const NameScoresPair *p) const
+ { return p->getBestScore(); }
+
+ auto policyIndexGetItemRefs(const NameScoresPair *p) const
+ { return p->getItemRefs(); }
+
+ template <typename Container>
+ auto containerGetReverseIterator(const Container *container) const
+ { return makeReverseIterator(container->end()); }
+
+ template <typename Container>
+ auto containerGetReverseIteratorEnd(const Container *container) const
+ { return makeReverseIterator(container->begin()); }
+
+ template <typename Container>
+ auto containerGetIterator(const Container *container) const
+ { return container->begin(); }
+
+ template <typename Container>
+ auto containerGetIteratorEnd(const Container *container) const
+ { return container->end(); }
+
+ template <typename Container>
+ auto containerGetSize(const Container *container) const
+ { return container->size(); }
+
+ template <typename Container>
+ auto containerLookupByIndex(const Container *container, size_t index) const
+ { return container->at(index); }
+
+ template <typename Container>
+ auto containerEmpty(const Container *container) const
+ { return container->size() == 0; }
+
+ auto containerLookupByKey(const List<PolicyOwnNode> *container, const char *key) const {
+ return containerLookupByKey(container, key,
+ [](const auto *node) { return node->getToken()->toStringRef(); });
+ }
+
+ template <typename ContainerType>
+ auto containerLookupByKey(const ContainerType *container, id_t id) const {
+ return containerLookupByKey(container, id,
+ [](const auto *elem) { return static_cast<id_t>(elem->getId()); });
+ }
+
+ auto containerLookupByKey(const List<NameScoresPair> *container, const char *key) const {
+ return containerLookupByKey(container, key,
+ [](const auto *elem) { return elem->getName()->toStringRef(); });
+ }
+
+ auto decisionItemGetDecision(const DecisionItem *item) const
+ { return item->getDecision(); }
+
+ auto decisionItemGetPrivilege(const DecisionItem *item) const
+ { return item->getPrivilege(); }
+
+ auto ownNodeGetToken(const PolicyOwnNode *node) const
+ { return node->getToken(); }
+
+ auto ownNodeGetDecisionItem(const PolicyOwnNode *node) const
+ { return node->getDecisionItem(); }
+
+ auto ownNodeGetPrefixDecisionItem(const PolicyOwnNode *node) const
+ { return node->getPrefixDecisionItem(); }
+
+ auto ownNodeGetChildren(const PolicyOwnNode *node) const
+ { return node->getChildren(); }
+
+ auto itemAccessGetType(const ItemAccess *item) const
+ { return item->getType(); }
+
+ auto itemAccessGetUid(const ItemAccess *item) const
+ { return item->getUid(); }
+
+ auto itemAccessGetGid(const ItemAccess *item) const
+ { return item->getGid(); }
+
+ auto itemSrGetName(const ItemSR *item) const
+ { return item->getName(); }
+
+ auto itemSrGetIsNamePrefix(const ItemSR *item) const
+ { return item->getIsNamePrefix(); }
+
+ auto itemSrGetInterface(const ItemSR *item) const
+ { return item->getInterface(); }
+
+ auto itemSrGetMember(const ItemSR *item) const
+ { return item->getMember(); }
+
+ auto itemSrGetPath(const ItemSR *item) const
+ { return item->getPath(); }
+
+ template <typename ItemSR>
+ auto itemSrGetMessageType(const ItemSR *item) const
+ { return item->getMessageType(); }
+
+ template <typename Item>
+ auto itemGetDecisionItem(const Item *item) const
+ { return item->getDecisionItem(); }
+
+ const char *stringGetCStr(const Str *str) const
+ { return str->c_str(); }
+
+ size_t stringGetSize(const Str *str) const
+ { return str->size(); }
+
+private:
+ const File *file{nullptr};
+ template <typename T>
+ class ReverseIterator {
+ T __iterator;
+ public:
+ ReverseIterator(const T &iterator) : __iterator{iterator} {}
+
+ // note: we copy the element here, but it is ok (FOR US!)
+ // because it is pointer anyway
+ auto operator*() {
+ auto tmp = __iterator;
+ return *--tmp;
+ }
+
+ auto operator++() { return __iterator--; }
+ auto operator++(int) {
+ auto tmp = __iterator;
+ __iterator--;
+ return tmp;
+ }
+ auto operator!=(const ReverseIterator<T> &rhs) { return __iterator != rhs.__iterator; }
+ };
+
+ template <typename T>
+ auto makeReverseIterator(const T &iterator) const
+ { return ReverseIterator<T>(iterator); }
+};
+
+}
+
+namespace std {
+
+template <typename Elem>
+struct iterator_traits<typename ldp_serialized::Iterator<Elem>>
+ : public std::iterator<std::random_access_iterator_tag, const Elem *, int> {};
+
+} // namespace std
+
+namespace ldp_serialization {
+template <>
+struct HasUserGroup<const ldp_serialized::File::OwnSetType *>
+{ typedef std::true_type result; };
+template <>
+struct HasUserGroup<const ldp_serialized::File::SendSetType *>
+{ typedef std::true_type result; };
+template <>
+struct HasUserGroup<const ldp_serialized::File::ReceiveSetType *>
+{ typedef std::true_type result; };
+template <>
+struct HasUserGroup<const ldp_serialized::File::AccessSetType *>
+{ typedef std::false_type result; };
+
+template <> struct PolicyContentType<const ldp_serialized::PolicyOwn *>
+{ typedef TreeType result; };
+template <> struct PolicyContentType<const ldp_serialized::PolicySend *>
+{ typedef ItemsType result; };
+template <> struct PolicyContentType<const ldp_serialized::PolicyReceive *>
+{ typedef ItemsType result; };
+template <> struct PolicyContentType<const ldp_serialized::PolicyAccess *>
+{ typedef ItemsType result; };
+
+template <> struct PolicyHasIndex<const ldp_serialized::PolicySend *>
+{ typedef std::true_type result; };
+
+template <> struct ItemType<const ldp_serialized::ItemSend *>
+{ typedef SendType result; };
+template <> struct ItemType<const ldp_serialized::ItemReceive *>
+{ typedef ReceiveType result; };
+template <> struct ItemType<const ldp_serialized::ItemAccess *>
+{ typedef AccessType result; };
+}