-DOSQUERY_BUILD_VERSION=${OSQUERY_VERSION}
-DOSQUERY_BUILD_SDK_VERSION=${OSQUERY_VERSION})
-INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}")
-INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/api")
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src")
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/tools/sqlite3")
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/osquery/include")
-INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/vist/tsqb")
-INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src/osquery/extensions/thrift/gen")
INCLUDE_DIRECTORIES("/usr/local/include")
ENABLE_TESTING()
--- /dev/null
+/*
+ * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/*
+ * @file archive.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Define archive interface for serializer and parameter-pack.
+ * @details 1. Serializer: Serialize/deserialize below types.
+ * (fundamental types, archival object, unique_ptr, shared_ptr)
+ * 2. Parameter-pack: Pack/unpack zero or more template arguments.
+ */
+
+#pragma once
+
+#include <vist/index-sequence.hpp>
+
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <memory>
+#include <tuple>
+
+namespace vist {
+
+class Archival;
+
+template<typename T>
+using IsFundamental = typename std::enable_if<std::is_fundamental<T>::value, int>::type;
+
+template<typename T>
+using IsArchival = typename std::enable_if<std::is_base_of<Archival, T>::value, int>::type;
+
+class Archive {
+public:
+ virtual ~Archive() = default;
+
+ template<typename Front, typename... Rest>
+ void pack(const Front& front, const Rest&... rest);
+ inline void pack(void) {}
+
+ template<typename Front, typename... Rest>
+ void unpack(Front& front, Rest&... rest);
+ inline void unpack(void) {}
+
+ template<typename... Ts>
+ void transform(std::tuple<Ts...>& tuple);
+
+ // serialize method
+ template<typename T, IsFundamental<T> = 0>
+ Archive& operator<<(const T& value);
+ template<typename T, IsArchival<T> = 0>
+ Archive& operator<<(const T& object);
+ template<typename T>
+ Archive& operator<<(const std::unique_ptr<T>& pointer);
+ template<typename T>
+ Archive& operator<<(const std::shared_ptr<T>& pointer);
+ Archive& operator<<(const std::string& value);
+ Archive& operator<<(const Archive& archive);
+
+ // deserialize method
+ template<typename T, IsFundamental<T> = 0>
+ Archive& operator>>(T& value);
+ template<typename T, IsArchival<T> = 0>
+ Archive& operator>>(T& object);
+ template<typename T>
+ Archive& operator>>(std::unique_ptr<T>& pointer);
+ template<typename T>
+ Archive& operator>>(std::shared_ptr<T>& pointer);
+ Archive& operator>>(std::string& value);
+ Archive& operator>>(Archive& archive);
+
+ unsigned char* get(void) noexcept;
+ std::size_t size(void) const noexcept;
+ void reserve(std::size_t size) noexcept;
+
+protected:
+ virtual void save(const void* bytes, std::size_t size);
+ virtual void load(void* bytes, std::size_t size);
+
+private:
+ template<typename T>
+ void transformImpl(T& tuple, EmptySequence);
+ template<typename T, std::size_t... I>
+ void transformImpl(T& tuple, IndexSequence<I...>);
+
+ std::vector<unsigned char> buffer;
+ std::size_t current = 0;
+};
+
+class Archival {
+public:
+ virtual ~Archival() = default;
+
+ virtual void pack(Archive& archive) const = 0;
+ virtual void unpack(Archive& archive) = 0;
+};
+
+template<typename Front, typename... Rest>
+void Archive::pack(const Front& front, const Rest&... rest)
+{
+ *this << front;
+ this->pack(rest...);
+}
+
+template<typename Front, typename... Rest>
+void Archive::unpack(Front& front, Rest&... rest)
+{
+ *this >> front;
+ this->unpack(rest...);
+}
+
+template<typename... Ts>
+void Archive::transform(std::tuple<Ts...>& tuple)
+{
+ constexpr auto size = std::tuple_size<std::tuple<Ts...>>::value;
+ this->transformImpl(tuple, make_index_sequence<size>());
+}
+
+template<typename T>
+void Archive::transformImpl(T& tuple, EmptySequence)
+{
+}
+
+template<typename T, std::size_t... I>
+void Archive::transformImpl(T& tuple, IndexSequence<I...>)
+{
+ this->unpack(std::get<I>(tuple)...);
+}
+
+template<typename T, IsFundamental<T>>
+Archive& Archive::operator<<(const T& value)
+{
+ this->save(reinterpret_cast<const void*>(&value), sizeof(value));
+
+ return *this;
+}
+
+template<typename T>
+Archive& Archive::operator<<(const std::unique_ptr<T>& pointer)
+{
+ return *this << *pointer;
+}
+
+template<typename T>
+Archive& Archive::operator<<(const std::shared_ptr<T>& pointer)
+{
+ return *this << *pointer;
+}
+
+template<typename T, IsArchival<T>>
+Archive& Archive::operator<<(const T& object)
+{
+ object.pack(*this);
+
+ return *this;
+}
+
+template<typename T, IsFundamental<T>>
+Archive& Archive::operator>>(T& value)
+{
+ this->load(reinterpret_cast<void*>(&value), sizeof(value));
+
+ return *this;
+}
+
+template<typename T>
+Archive& Archive::operator>>(std::unique_ptr<T>& pointer)
+{
+ if (pointer == nullptr)
+ pointer.reset(new T);
+
+ return *this >> *pointer;
+}
+
+template<typename T>
+Archive& Archive::operator>>(std::shared_ptr<T>& pointer)
+{
+ if (pointer == nullptr)
+ pointer.reset(new T);
+
+ return *this >> *pointer;
+}
+
+template<typename T, IsArchival<T>>
+Archive& Archive::operator>>(T& object)
+{
+ object.unpack(*this);
+
+ return *this;
+}
+
+} // namespace vist
INCLUDE_DIRECTORIES(SYSTEM . ${VIST_COMMON_DEPS_INCLUDE_DIRS})
-ADD_VIST_COMMON_LIBRARY(vist_common common.cpp)
+ADD_VIST_COMMON_LIBRARY(vist_common archive.cpp
+ common.cpp)
FILE(GLOB COMMON_TESTS "tests/*.cpp")
ADD_VIST_TEST(${COMMON_TESTS})
--- /dev/null
+/*
+ * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/*
+ * @file archive.cpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Implementation of archive.
+ */
+
+#include <vist/archive.hpp>
+
+#include <algorithm>
+#include <cstring>
+#include <iterator>
+
+namespace vist {
+
+Archive& Archive::operator<<(const Archive& archive)
+{
+ auto data = archive.buffer;
+ auto index = archive.current;
+ std::copy(data.begin() + index, data.end(), std::back_inserter(this->buffer));
+}
+
+Archive& Archive::operator<<(const std::string& value)
+{
+ std::size_t size = value.size();
+ this->save(reinterpret_cast<const void*>(&size), sizeof(size));
+ this->save(reinterpret_cast<const void*>(value.c_str()), value.size());
+
+ return *this;
+}
+
+Archive& Archive::operator>>(Archive& archive)
+{
+ auto data = this->buffer;
+ auto index = this->current;
+ std::copy(data.begin() + index, data.end(), std::back_inserter(archive.buffer));
+}
+
+Archive& Archive::operator>>(std::string& value)
+{
+ std::size_t size;
+ this->load(reinterpret_cast<void*>(&size), sizeof(size));
+
+ value.resize(size);
+ this->load(reinterpret_cast<void*>(&value.front()), size);
+
+ return *this;
+}
+
+unsigned char* Archive::get(void) noexcept
+{
+ return this->buffer.data();
+}
+
+std::size_t Archive::size(void) const noexcept
+{
+ return this->buffer.size();
+}
+
+void Archive::reserve(std::size_t size) noexcept
+{
+ this->buffer.reserve(size);
+}
+
+void Archive::save(const void* bytes, std::size_t size)
+{
+ auto binary = reinterpret_cast<unsigned char*>(const_cast<void*>(bytes));
+ std::vector<unsigned char> next(binary, binary + size);
+ std::copy(next.begin(), next.end(), std::back_inserter(this->buffer));
+}
+
+void Archive::load(void* bytes, std::size_t size)
+{
+ std::memcpy(bytes, reinterpret_cast<void*>(this->buffer.data() + current), size);
+ current += size;
+}
+
+} // namespace vist
--- /dev/null
+/*
+ * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+#include <gtest/gtest.h>
+
+#include <vist/archive.hpp>
+
+#include <memory>
+#include <limits>
+#include <string>
+#include <cassert>
+
+using namespace vist;
+
+TEST(ArchiveTests, serializer_fundamental_int)
+{
+ int input1 = std::numeric_limits<int>::lowest();
+ int input2 = std::numeric_limits<int>::max();
+
+ Archive archive;
+ archive << input1 << input2;
+
+ int output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_float)
+{
+ float input1 = std::numeric_limits<float>::lowest();
+ float input2 = std::numeric_limits<float>::max();
+
+ Archive archive;
+ archive << input1 << input2;
+
+ float output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_double)
+{
+ double input1 = std::numeric_limits<double>::lowest();
+ double input2 = std::numeric_limits<double>::max();
+
+ Archive archive;
+ archive << input1 << input2;
+
+ double output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_long_long_int)
+{
+ long long int input1 = std::numeric_limits<long long int>::lowest();
+ long long int input2 = std::numeric_limits<long long int>::max();
+
+ Archive archive;
+ archive << input1 << input2;
+
+ long long int output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_bool)
+{
+ bool input1 = true;
+ bool input2 = false;
+
+ Archive archive;
+ archive << input1 << input2;
+
+ bool output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_char)
+{
+ char input1 = 'a';
+ char input2 = 'Z';
+
+ Archive archive;
+ archive << input1 << input2;
+
+ char output1, output2;
+ archive >> output1 >> output2;
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+}
+
+TEST(ArchiveTests, serializer_fundamental_nullptr)
+{
+ std::nullptr_t input;
+
+ Archive archive;
+ archive << input;
+
+ std::nullptr_t output;
+ archive >> output;
+
+ assert(input == output);
+}
+
+TEST(ArchiveTests, serializer_fundamental_reference)
+{
+ int input = std::numeric_limits<int>::max();
+ int& refInput = input;
+
+ Archive archive;
+ archive << refInput;
+
+ int output;
+ int& refOutput = output;
+ archive >> refOutput;
+
+ EXPECT_EQ(input, output);
+ EXPECT_EQ(refInput, refOutput);
+}
+
+struct Object : public Archival {
+ void pack(Archive& archive) const override
+ {
+ archive << a << b << c;
+ }
+
+ void unpack(Archive& archive) override
+ {
+ archive >> a >> b >> c;
+ }
+
+ int a = 0;
+ bool b = true;
+ std::string c = "str";
+};
+
+TEST(ArchiveTests, archival)
+{
+ Object input;
+ input.a = 100;
+ input.b = false;
+ input.c = "archival string";
+
+ Archive archive;
+ archive << input;
+
+ Object output;
+ archive >> output;
+
+ EXPECT_EQ(input.a, output.a);
+ EXPECT_EQ(input.b, output.b);
+ EXPECT_EQ(input.c, output.c);
+}
+
+TEST(ArchiveTests, string)
+{
+ std::string input = "Archive string test";
+
+ Archive archive;
+ archive << input;
+
+ std::string output;
+ archive >> output;
+
+ EXPECT_EQ(input, output);
+}
+
+TEST(ArchiveTests, unique_ptr)
+{
+ std::unique_ptr<bool> input(new bool(true));
+
+ Archive archive;
+ archive << input;
+
+ std::unique_ptr<bool> output;
+ archive >> output;
+
+ EXPECT_EQ(*input, *output);
+}
+
+TEST(ArchiveTests, shared_ptr)
+{
+ std::shared_ptr<std::string> input = std::make_shared<std::string>();
+ *input = "Archive string test";
+
+ Archive archive;
+ archive << input;
+
+ std::shared_ptr<std::string> output;
+ archive >> output;
+
+ EXPECT_EQ(*input, *output);
+}
+
+TEST(ArchiveTests, archive)
+{
+ std::string input1 = "Archive string test1";
+ std::string input2 = "Archive string test2";
+ std::string input3 = "Archive string test3";
+
+ Archive archive1, archive2, archive3;
+ archive1 << input1;
+ archive2 << input2;
+ archive3 << input3;
+
+ archive1 << archive2;
+ archive1 >> archive3;
+
+ std::string output1;
+ std::string output2;
+ std::string output3;
+ archive3 >> output1 >> output2 >> output3;
+
+ EXPECT_EQ(output1, input3);
+ EXPECT_EQ(output2, input1);
+ EXPECT_EQ(output3, input2);
+}
+
+TEST(ArchiveTests, parameter_pack)
+{
+ int input1 = std::numeric_limits<int>::max();
+ float input2 = std::numeric_limits<float>::max();
+ double input3 = std::numeric_limits<double>::max();
+ std::string input4 = "Archive string test";
+ std::unique_ptr<bool> input5(new bool(true));
+
+ Archive archive;
+ archive.pack(input1, input2, input3, input4, input5);
+
+ int output1;
+ float output2;
+ double output3;
+ std::string output4;
+ std::unique_ptr<bool> output5;
+
+ archive.unpack(output1, output2, output3, output4, output5);
+
+ EXPECT_EQ(input1, output1);
+ EXPECT_EQ(input2, output2);
+ EXPECT_EQ(input3, output3);
+ EXPECT_EQ(input4, output4);
+ EXPECT_EQ(*input5, *output5);
+}
+
+TEST(ArchiveTests, parameter_pack_empty)
+{
+ Archive archive;
+ archive.pack();
+
+ archive.unpack();
+}
+
+TEST(ArchiveTests, parameter_pack_transform)
+{
+ int input1 = std::numeric_limits<int>::max();
+ float input2 = std::numeric_limits<float>::max();
+ double input3 = std::numeric_limits<double>::max();
+ std::string input4 = "Archive string test";
+ std::shared_ptr<bool> input5(new bool(true));
+
+ Archive archive;
+ archive.pack(input1, input2, input3, input4, input5);
+
+ int output1;
+ float output2;
+ double output3;
+ std::string raw;
+ std::string& output4 = raw;
+ std::shared_ptr<bool> output5;
+
+ auto tuple = std::make_tuple(output1, output2, output3, output4, output5);
+ archive.transform(tuple);
+
+ EXPECT_EQ(input1, std::get<0>(tuple));
+ EXPECT_EQ(input2, std::get<1>(tuple));
+ EXPECT_EQ(input3, std::get<2>(tuple));
+ EXPECT_EQ(input4, std::get<3>(tuple));
+ EXPECT_EQ(*input5, *(std::get<4>(tuple)));
+}
+
+TEST(ArchiveTests, parameter_pack_transform_empty)
+{
+ auto tuple = std::make_tuple();
+ Archive archive;
+ archive.transform(tuple);
+}
--- /dev/null
+/*
+ * Copyright (c) 2018-present Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+/*
+ * @file index-sequence.hpp
+ * @author Sangwan Kwon (sangwan.kwon@samsung.com)
+ * @brief Generate index sequence.
+ */
+
+#pragma once
+
+#include <cstddef>
+
+namespace vist {
+
+struct EmptySequence {};
+
+template<std::size_t...>
+struct IndexSequence {};
+
+namespace {
+
+template<std::size_t N, std::size_t... S>
+struct SequenceExpansion : SequenceExpansion<N-1, N-1, S...> {};
+
+template<std::size_t... S>
+struct SequenceExpansion<0, S...> { using Type = IndexSequence<S...>; };
+
+template<>
+struct SequenceExpansion<0> { using Type = EmptySequence; };
+
+} // anonymous namespace
+
+template<std::size_t N>
+using make_index_sequence = typename SequenceExpansion<N>::Type;
+
+} // namespace vist