aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md9
-rw-r--r--project.conf9
-rw-r--r--sibs/SafeDeserializer.hpp90
-rw-r--r--sibs/SafeSerializer.hpp44
-rw-r--r--tests/main.cpp40
-rw-r--r--types.hpp22
-rwxr-xr-xutils.hpp6
8 files changed, 220 insertions, 2 deletions
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 <cstring>
+#include <stdexcept>
+
+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 <typename T>
+ 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 <vector>
+#include <cstring>
+
+namespace sibs
+{
+ /**
+ * Endian independent serializer
+ */
+ class SafeSerializer
+ {
+ DISABLE_COPY(SafeSerializer);
+ public:
+ SafeSerializer(){}
+
+ template <typename T>
+ 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<u8>& getBuffer()
+ {
+ return buffer;
+ }
+ private:
+ std::vector<u8> 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 <cstdio>
+#include <cstdlib>
+#include <sibs/SafeSerializer.hpp>
+#include <sibs/SafeDeserializer.hpp>
+#include <cstdint>
+
+#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<uint32_t>() == 3563634);
+ REQUIRE(deserializer.extract<uint64_t>() == 204232532533423632);
+ REQUIRE(deserializer.extract<uint8_t>() == 2);
+ char str[6];
+ str[5] = '\0';
+ deserializer.extract((uint8_t*)str, 5);
+ REQUIRE(strcmp(str, "hello") == 0);
+ REQUIRE(deserializer.empty());
+
+ try
+ {
+ deserializer.extract<uint8_t>();
+ 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 <cstdint>
+
+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;