From 6fd8decb98ce81fd71cebd0226e30b0024ffd77c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 1 Feb 2018 20:56:03 +0100 Subject: Initial commit --- .gitignore | 2 ++ README.md | 9 +++-- project.conf | 9 +++++ sibs/SafeDeserializer.hpp | 90 +++++++++++++++++++++++++++++++++++++++++++++++ sibs/SafeSerializer.hpp | 44 +++++++++++++++++++++++ tests/main.cpp | 40 +++++++++++++++++++++ types.hpp | 22 ++++++++++++ utils.hpp | 6 ++++ 8 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 project.conf create mode 100644 sibs/SafeDeserializer.hpp create mode 100644 sibs/SafeSerializer.hpp create mode 100644 tests/main.cpp create mode 100644 types.hpp create mode 100755 utils.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f2d790 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +sibs-build/ +.vscode/ diff --git a/README.md b/README.md index aa22c39..fec9380 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ -# serializer -Safe serializer +# Note +Using this library to serialize non plain old data types will result in platform defined behavior unless you specify +padding for the struct yourself. If you want to serialize non plain old data types, then it is recommended to serialize +each field manually (also when deserializing) + +# TODO +Add more tests \ No newline at end of file diff --git a/project.conf b/project.conf new file mode 100644 index 0000000..6badb64 --- /dev/null +++ b/project.conf @@ -0,0 +1,9 @@ +[package] +name = "sibs-serializer" +version = "0.1.0" +type = "static" +platforms = ["any"] +tests = "tests" + +[config] +expose_include_dirs = ["."] \ No newline at end of file diff --git a/sibs/SafeDeserializer.hpp b/sibs/SafeDeserializer.hpp new file mode 100644 index 0000000..3d83042 --- /dev/null +++ b/sibs/SafeDeserializer.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include "../types.hpp" +#include "../utils.hpp" +#include +#include + +namespace sibs +{ + class DeserializeException : public std::runtime_error + { + public: + DeserializeException(const std::string &errMsg) : std::runtime_error(errMsg) {} + }; + + /** + * Endian independent deserializer + */ + class SafeDeserializer + { + DISABLE_COPY(SafeDeserializer); + public: + SafeDeserializer(const u8 *_data, usize _size) : + data(_data), + size(_size) + { + + } + + /* + * Throws DeserializeException on failure + */ + template + T&& extract() + { + constexpr usize typeSize = sizeof(T); + verifyExtractSize(typeSize); + size -= typeSize; + T result; + memcpy(&result, data, typeSize); + data += typeSize; + return std::move(result); + } + + /* + * Throws DeserializeException on failure + */ + void extract(u8 *destination, usize destinationSize) + { + if(destinationSize > 0) + { + verifyExtractSize(destinationSize); + size -= destinationSize; + memcpy(destination, data, destinationSize); + data += destinationSize; + } + } + + bool empty() const + { + return size == 0; + } + + const u8* getBuffer() + { + return data; + } + + usize getSize() const + { + return size; + } + private: + void verifyExtractSize(usize typeSize) const + { + if(typeSize > size) + { + std::string errMsg = "Unable to extract "; + errMsg += std::to_string(typeSize); + errMsg += " bytes, only "; + errMsg += std::to_string(size); + errMsg += " bytes left in buffer"; + throw DeserializeException(errMsg); + } + } + private: + const u8 *data; + usize size; + }; +} diff --git a/sibs/SafeSerializer.hpp b/sibs/SafeSerializer.hpp new file mode 100644 index 0000000..94bcdc5 --- /dev/null +++ b/sibs/SafeSerializer.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "../types.hpp" +#include "../utils.hpp" +#include +#include + +namespace sibs +{ + /** + * Endian independent serializer + */ + class SafeSerializer + { + DISABLE_COPY(SafeSerializer); + public: + SafeSerializer(){} + + template + void add(const T &data) + { + usize offset = buffer.size(); + buffer.resize(buffer.size() + sizeof(data)); + memcpy(&buffer[offset], &data, sizeof(data)); + } + + void add(const u8 *data, usize size) + { + if(size > 0) + { + usize offset = buffer.size(); + buffer.resize(buffer.size() + size); + memcpy(&buffer[offset], data, size); + } + } + + std::vector& getBuffer() + { + return buffer; + } + private: + std::vector buffer; + }; +} diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..e495b3a --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +#define REQUIRE(statement) do { if(!(statement)) { fprintf(stderr, "Assertion failed:\n%s\n", #statement); exit(1); } } while(0) +#define FAIL(str) do { fprintf(stderr, "Failed:\n%s\n", (str)); exit(1); } while(0) + +int main() +{ + sibs::SafeSerializer serializer; + serializer.add((uint32_t)3563634); + serializer.add((uint64_t)204232532533423632); + serializer.add((uint8_t)2); + serializer.add((uint8_t*)"hello", 5); + REQUIRE(serializer.getBuffer().size() == 18); + + sibs::SafeDeserializer deserializer(serializer.getBuffer().data(), serializer.getBuffer().size()); + REQUIRE(deserializer.extract() == 3563634); + REQUIRE(deserializer.extract() == 204232532533423632); + REQUIRE(deserializer.extract() == 2); + char str[6]; + str[5] = '\0'; + deserializer.extract((uint8_t*)str, 5); + REQUIRE(strcmp(str, "hello") == 0); + REQUIRE(deserializer.empty()); + + try + { + deserializer.extract(); + FAIL("Expected extract to fail since we have extracted all data"); + } + catch (sibs::DeserializeException &e) + { + + } + + return 0; +} \ No newline at end of file diff --git a/types.hpp b/types.hpp new file mode 100644 index 0000000..0379100 --- /dev/null +++ b/types.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace sibs +{ + typedef int8_t i8; + typedef int16_t i16; + typedef int32_t i32; + typedef int64_t i64; + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef float f32; + typedef double f64; + + typedef intptr_t isize; + typedef uintptr_t usize; +} diff --git a/utils.hpp b/utils.hpp new file mode 100755 index 0000000..01e478d --- /dev/null +++ b/utils.hpp @@ -0,0 +1,6 @@ +#pragma once + +// Disable copying for a class or struct +#define DISABLE_COPY(ClassName) \ + ClassName(ClassName&) = delete; \ + ClassName& operator = (ClassName&) = delete; -- cgit v1.2.3