From dff846799aaf072493f7294ee7cda49542ac8510 Mon Sep 17 00:00:00 2001 From: Rogiel Sulzbach Date: Tue, 30 May 2017 14:44:14 -0300 Subject: [PATCH] Initial commit --- .gitignore | 2 + .gitmodules | 32 ++ CMakeLists.txt | 50 +++ Catch | 1 + LICENSE | 30 ++ README.md | 63 +++ example/main.cpp | 125 ++++++ include/PacketBuffer/ObjectSerializer.h | 185 ++++++++ include/PacketBuffer/Packer.h | 321 ++++++++++++++ include/PacketBuffer/PacketBuffer.h | 34 ++ include/PacketBuffer/Serializer/Std.h | 43 ++ include/PacketBuffer/Serializer/Std/Array.h | 127 ++++++ include/PacketBuffer/Serializer/Std/Chrono.h | 87 ++++ .../Serializer/Std/Experimental.h | 35 ++ .../Serializer/Std/Experimental/Optional.h | 73 ++++ include/PacketBuffer/Serializer/Std/List.h | 74 ++++ include/PacketBuffer/Serializer/Std/Map.h | 113 +++++ include/PacketBuffer/Serializer/Std/Pair.h | 62 +++ include/PacketBuffer/Serializer/Std/Set.h | 112 +++++ include/PacketBuffer/Serializer/Std/String.h | 97 ++++ include/PacketBuffer/Serializer/Std/Tuple.h | 80 ++++ include/PacketBuffer/Serializer/Std/Vector.h | 73 ++++ include/PacketBuffer/Unpacker.h | 320 ++++++++++++++ tests/Packer.cpp | 397 +++++++++++++++++ tests/Serializer/Std/Array.cpp | 113 +++++ tests/Serializer/Std/String.cpp | 109 +++++ tests/Unpacker.cpp | 413 ++++++++++++++++++ tests/main.cpp | 32 ++ 28 files changed, 3203 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 160000 Catch create mode 100644 LICENSE create mode 100644 README.md create mode 100644 example/main.cpp create mode 100644 include/PacketBuffer/ObjectSerializer.h create mode 100644 include/PacketBuffer/Packer.h create mode 100644 include/PacketBuffer/PacketBuffer.h create mode 100644 include/PacketBuffer/Serializer/Std.h create mode 100644 include/PacketBuffer/Serializer/Std/Array.h create mode 100644 include/PacketBuffer/Serializer/Std/Chrono.h create mode 100644 include/PacketBuffer/Serializer/Std/Experimental.h create mode 100644 include/PacketBuffer/Serializer/Std/Experimental/Optional.h create mode 100644 include/PacketBuffer/Serializer/Std/List.h create mode 100644 include/PacketBuffer/Serializer/Std/Map.h create mode 100644 include/PacketBuffer/Serializer/Std/Pair.h create mode 100644 include/PacketBuffer/Serializer/Std/Set.h create mode 100644 include/PacketBuffer/Serializer/Std/String.h create mode 100644 include/PacketBuffer/Serializer/Std/Tuple.h create mode 100644 include/PacketBuffer/Serializer/Std/Vector.h create mode 100644 include/PacketBuffer/Unpacker.h create mode 100644 tests/Packer.cpp create mode 100644 tests/Serializer/Std/Array.cpp create mode 100644 tests/Serializer/Std/String.cpp create mode 100644 tests/Unpacker.cpp create mode 100644 tests/main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ebfe039 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cmake-build-* +/.idea diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b0ca01d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,32 @@ +# +# Copyright (c) 2017, Rogiel Sulzbach +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Rogiel Sulzbach nor the names of contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +[submodule "Catch"] + path = Catch + url = https://github.com/philsquared/Catch.git diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d75a46f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# Copyright (c) 2017, Rogiel Sulzbach +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of Rogiel Sulzbach nor the names of contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +cmake_minimum_required(VERSION 3.8) +project(PacketBuffer) + +set(CMAKE_CXX_STANDARD 14) + +add_library(PacketBuffer INTERFACE) +target_include_directories(PacketBuffer INTERFACE include) + +option(PACKET_BUFFER_EXAMPLES "Enable to build examples" OFF) +if(PACKET_BUFFER_EXAMPLES) + add_executable(PacketBuffer.Example example/main.cpp) + target_link_libraries(PacketBuffer.Example PacketBuffer) +endif() + +option(PACKET_BUFFER_TESTS "Enable to build tests" OFF) +if(PACKET_BUFFER_TESTS) + file(GLOB_RECURSE TESTS_SRC tests/*.cpp) + add_executable(PacketBuffer.Tests ${TESTS_SRC}) + target_link_libraries(PacketBuffer.Tests PacketBuffer) + target_include_directories(PacketBuffer.Tests PRIVATE Catch/include) +endif() diff --git a/Catch b/Catch new file mode 160000 index 0000000..3e328f5 --- /dev/null +++ b/Catch @@ -0,0 +1 @@ +Subproject commit 3e328f55fc39c9663b70c890763c4aac3932b031 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc11e02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ +The BSD 3-Clause ("BSD New" or "BSD Simplified") License +======================================================== + +Copyright (c) 2017, Rogiel Sulzbach +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the Rogiel Sulzbach nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5b20595 --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +PacketBuffer - Lightning fast packet parsing library +======================================================== + +PacketBuffer is a C++14 header-only library designed specifically to be really fast at processing binary network packets. It supports many of the C++ standard containers, including: + + * [`std::array`](include/PacketBuffer/Serializer/Std/Array.h) + * [`T[S]` (statically sized arrays)](include/PacketBuffer/Serializer/Std/Array.h) + * [`std::chrono::duration`](include/PacketBuffer/Serializer/Std/Chrono.h) + * [`std::chrono::time_point`](include/PacketBuffer/Serializer/Std/Chrono.h) + * [`std::vector`](include/PacketBuffer/Serializer/Std/Vector.h) + * [`std::map`](include/PacketBuffer/Serializer/Std/Map.h) + * [`std::unordered_map`](include/PacketBuffer/Serializer/Std/Map.h) + * [`std::list`](include/PacketBuffer/Serializer/Std/List.h) + * [`std::set`](include/PacketBuffer/Serializer/Std/Set.h) + * [`std::unoredered_set`](include/PacketBuffer/Serializer/Std/Set.h) + * [`std::string`](include/PacketBuffer/Serializer/Std/String.h) + * [`std::tuple`](include/PacketBuffer/Serializer/Std/Tuple.h) + * [`std::pair`](include/PacketBuffer/Serializer/Std/Pair.h) + * [`std::experimental::optional`](include/PacketBuffer/Serializer/Std/Experimental/Optional.h) + +It also supports endian swapping the following types: + `uint8_t`, `int8_t`, + `uint16_t`, `int16_t`, + `uint32_t`, `int32_t`, + `uint64_t`, `int64_t`. + +## Getting Started +```````` +using namespace PacketBuffer; + +std::stringstream ss; +Packer packer(ss); +packer.pack(uint8_t(100)); +```````` + +That's it! + +But wait, you probably want something more than just packing a `uint8_t`, right? What about some custom structs? + +### Packing structs +``` c++ +using namespace PacketBuffer; + +struct MyPacket { + uint8_t id; + std::string name; + uint8_t age; + + template + void pack(Packer& packer) const { packer(id, name, age); } + + template + void unpack(Unpacker& unpacker) { unpacker(id, name, age); } +}; + +std::stringstream ss; +Packer packer(ss); + +MyPacket packet; +packer.pack(packet); +``` + +Seriously, that is it! You can now serialize and deserialize your structure on any machine with whatever byte order it has! \ No newline at end of file diff --git a/example/main.cpp b/example/main.cpp new file mode 100644 index 0000000..93b7042 --- /dev/null +++ b/example/main.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include +#include + +using namespace PacketBuffer; + +struct HELLO_MESSAGE { + uint8_t id; + uint8_t kind; + + unsigned char payload[64]; + std::array test; + + std::vector vec; + + std::tuple tuple; + std::pair pair; + + std::map mapping; + std::unordered_map umapping; + + std::list list; + std::list flist; + std::set set; + std::unordered_set uset; + + std::chrono::seconds durationSec; + std::chrono::hours durationHour; + + std::chrono::system_clock::time_point time; + + std::experimental::optional oName; + + std::string name; + + template + void pack(Packer& packer) const { + packer( + id, kind, payload, test, vec, tuple, pair, mapping, umapping, list, flist, set, uset, name, durationSec, + durationHour, time, oName + ); + } + + template + void unpack(Unpacker& unpacker) { + unpacker( + id, kind, payload, test, vec, tuple, pair, mapping, umapping, list, flist, set, uset, name, durationSec, + durationHour, time, oName + ); + } +}; + +int main(int argc, const char** argv) { + std::stringstream ss; + Packer packer(ss); + + { + HELLO_MESSAGE hello; + hello.id = 20; + hello.kind = 2; + memset(hello.payload, 'A', sizeof(hello.payload)); + + hello.vec = {1, 2, 3}; + hello.mapping[1] = 200; + hello.mapping[2] = 300; + + hello.name = "It Works!"; +// hello.wname = L"Teste"; + hello.oName = std::string(";)"); + + packer.pack(hello); + } + + std::cout << "Serialized message has " << ss.str().size() << std::endl; + + { + Unpacker unpacker(ss); + HELLO_MESSAGE unpacked; + + unpacker.unpack(unpacked); + + std::cout << "id: " << (int) unpacked.id << std::endl; + std::cout << "kind: " << (int) unpacked.kind << std::endl; + std::cout << "payload: " << std::string((char*) unpacked.payload, 64) << std::endl; + std::cout << "vec: " << unpacked.vec.size() << std::endl; + std::cout << "name: " << unpacked.name << std::endl; + + std::cout << "mapping: " << std::endl; + for(auto& entry : unpacked.mapping) { + std::cout << " " << (int) entry.first << " = " << entry.second << std::endl; + } + + } +} \ No newline at end of file diff --git a/include/PacketBuffer/ObjectSerializer.h b/include/PacketBuffer/ObjectSerializer.h new file mode 100644 index 0000000..b67858f --- /dev/null +++ b/include/PacketBuffer/ObjectSerializer.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_OBJECTSERIALIZER_H +#define PACKETBUFFER_OBJECTSERIALIZER_H + +namespace PacketBuffer { + + template + struct HasIntrusivePackMethod { + template + struct SFINAE; + + template + static char test(SFINAE*); + + template + static int test(...); + + static const bool value = sizeof(test(0)) == sizeof(char); + }; + + template + struct HasIntrusiveUnpackMethod { + template + struct SFINAE; + + template + static char test(SFINAE*); + + template + static int test(...); + + static const bool value = sizeof(test(0)) == sizeof(char); + }; + + /** + * The ObjectSerializer class template is responsible for implementing the serialization logic + * for non-primitive types. + * + * A user can provide a specialization for any type it wishes to add custom serialization code. + * + * By default, the ObjectSerializer will call the intrusive pack() and unpack() methods on the + * user given object. If these methods are not available, compilation will fail with a error + * message describing which of the required methods are missing. + * + * A custom ObjectSerialization specialization can be provided as follows: + * + * @code + * struct UserDefinedType { + * uint64_t id; + * std::string name; + * } + * + * namespace PacketBuffer { + * template<> + * class ObjectSerializer { + * public: + * template + * static void pack(Packer& packer, const T& object) { + * packer(object.id, object.name); + * } + * + * template + * static void unpack(Unpacker& unpacker, T& object) { + * unpacker(object.id, object.name); + * } + * } + * } + * @endcode + * + * If more convenient, a user can also provide a set of **intrusive** methods that allow + * packing and unpacking objects: + * + * @code + * struct UserDefinedType { + * uint64_t id; + * std::string name; + * + * template + * void pack(Packer& packer) const { + * packer(id, name); + * } + * + * template + * void unpack(Unpacker& unpacker) { + * unpacker(id, name); + * } + * } + * @endcode + * + * @tparam T the type of the object to be packed and/or unpacked + */ + template + class ObjectSerializer { + public: + /** + * Packs a object to its packed representation. + * + * This is a default implementation whose only job is to forward to the intrusive implementation, + * and if this is not available, fail at compile time. + * + * @tparam Packer the packer type + * @param packer the packer to write data from + * @param object the object to be packed + */ + template + static inline void pack(Packer& packer, const T& object) { + /* + * If you are getting an error here, this means that one of your objects being serialized does not implement + * a pack() method. A pack method can be implemented as follows: + * + * template + * void pack(Packer& packer) const { + * packer( + * a, b, c + * ); + * } + */ + static_assert(HasIntrusivePackMethod::value, + "The object of type T does not have a ObjectSerializer " + "specialization and does not implement a intrusive pack(Packer&) method."); + object.pack(packer); + } + + /** + * Unpacks a object from its packet representation. + * + * This is a default implementation whose only job is to forward to the intrusive implementation, + * and if this is not available, fail at compile time. + * + * @tparam Unpacker the unpacker type + * @param unpacker the unpacker to read data from + * @param object the object to unpack to + */ + template + static inline void unpack(Unpacker& unpacker, T& object) { + /* + * If you are getting an error here, this means that one of your objects being serialized does not implement + * a unpack() method. A unpack method can be implemented as follows: + * + * template + * void unpack(Unpacker& unpacker) { + * unpacker( + * a, b, c + * ); + * } + */ + static_assert(HasIntrusiveUnpackMethod::value, + "The object of type T does not have a ObjectSerializer " + "specialization and does not implement a intrusive unpack(Unpacker&) method."); + object.unpack(unpacker); + } + }; + +} + + +#endif //PACKETBUFFER_OBJECTSERIALIZER_H diff --git a/include/PacketBuffer/Packer.h b/include/PacketBuffer/Packer.h new file mode 100644 index 0000000..d44bd06 --- /dev/null +++ b/include/PacketBuffer/Packer.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_PACKER_H +#define PACKETBUFFER_PACKER_H + +#include + +#include "ObjectSerializer.h" + +namespace PacketBuffer { + + /** + * The Packer template class is responsible for converting C++ primitive types like integers and raw buffers + * into a platform independent raw buffer. + * + * By default, all integers are encoded as little endian, this, however can be changed by setting "Endianess" + * template parameter to something else. + * + * The Buffer class must implement a write with the following signature: + * @code + * void write(const char* data, size_t length); + * @endcode + * + * @tparam Buffer the buffer type to write data to + * @tparam Endianess the endianess used to encode integer types + */ + template + class Packer { + private: + /** + * A reference to the buffer in which packed data is written to + */ + Buffer& buffer; + + public: + /** + * Creates a new Packer instance with the given buffer reference. Packed data will be written + * into the given buffer object. + * + * @param buffer the buffer object to write data to + */ + explicit Packer(Buffer& buffer) : buffer(buffer) {}; + + /** + * Deleted copy constructor. + */ + Packer(const Packer& other) = delete; + + /** + * Deleted copy assignment operator. + */ + Packer& operator=(const Packer& other) = delete; + + /** + * Deleted move constructor. + */ + Packer(Packer&& other) = delete; + + /** + * Deleted move assignment operator. + */ + Packer& operator=(Packer&& other) = delete; + + /** + * Default destructor. + */ + ~Packer() = default; + + public: // Helper methods + /** + * A helper & operator overload. Calls the pack() method for the given type. + * + * @tparam T the data type to pack + * @param v the value to be packed + * + * @return this + */ + template + inline Packer& operator&(const T& v) { + return pack(v); + } + + /** + * A helper << operator overload that behaves similarly to ostreams operator. Calls the + * pack() method for given type. + * + * @tparam T the data type to pack + * @param v the value to be packed + * + * @return this + */ + template + inline Packer& operator<<(const T& v) { + return pack(v); + } + + /** + * A helper call operator overload. Calls pack() method for the given types. + * + * @tparam Ts the types to be packed + * @param vs the values to be packed. The values will be packed in the given order. + * + * @return this + */ + template + inline Packer& operator()(const Ts& ... vs) { + return pack(vs...); + } + + public: // Object serialization + /** + * Packs a sequence of objects of types T and Ts.... + * + * The objects will be packed in the given order. + * + * @tparam T the type of the first object to be packed + * @tparam Ts the type of the remaining objects to be packed + * @param v the value of the first object to be packed + * @param vs the value of the remaining objects to be packed + * + * @return this + */ + template + inline Packer& pack(const T& v, const Ts& ... vs) { + pack(v); + pack(vs...); + return *this; + } + + /** + * Packs a single object of type T. + * + * @tparam T the type of the object to be packed + * @param object the value of the object to be packed + * + * @return this + */ + template + inline Packer& pack(const T& object) { + ObjectSerializer::pack(*this, object); + return *this; + } + + public: // Integer types + /** + * Packs a uint8_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(uint8_t i) { + static_assert(sizeof(i) == 1, "uint8_t size must be 1 byte"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a int8_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(int8_t i) { + static_assert(sizeof(i) == 1, "int8_t size must be 1 byte"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a uint16_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(uint16_t i) { + static_assert(sizeof(i) == 2, "uint16_t size must be 2 byte2"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a int16_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(int16_t i) { + static_assert(sizeof(i) == 2, "int16_t size must be 2 byte2"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a uint32_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(uint32_t i) { + static_assert(sizeof(i) == 4, "uint32_t size must be 4 bytes"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a int32_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(int32_t i) { + static_assert(sizeof(i) == 4, "int32_t size must be 4 bytes"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a uint64_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(uint64_t i) { + static_assert(sizeof(i) == 8, "uint64_t size must be 8 bytes"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a int64_t integer value. + * + * @param i the integer value to pack + * + * @return this + */ + inline Packer& pack(int64_t i) { + static_assert(sizeof(i) == 8, "int64_t size must be 8 bytes"); + boost::endian::conditional_reverse_inplace(i); + return pack(reinterpret_cast(&i), sizeof(i)); + } + + /** + * Packs a boolean value. + * + * @param b the boolean value to pack + * + * @return this + */ + inline Packer& pack(bool b) { + static_assert(sizeof(b) == 1, "bool size must be 1 byte"); + boost::endian::conditional_reverse_inplace(b); + return pack(reinterpret_cast(&b), sizeof(b)); + } + + public: // write operation + /** + * Packs a char-pointer gives by ptr with length given by size. + * + * @param ptr the char pointer to be packed + * @param size the char pointer length + * + * @return this + */ + inline Packer& pack(const char* ptr, size_t size) { + buffer.write(ptr, size); + return *this; + } + + /** + * Packs a char-pointer givem by ptr with length given by size. + * + * @param ptr the char pointer to be packed + * @param size the char pointer length + * + * @return this + */ + inline Packer& pack(const unsigned char* ptr, size_t size) { + buffer.write(ptr, size); + return *this; + } + + }; + +} + + +#endif //PACKETBUFFER_PACKER_H diff --git a/include/PacketBuffer/PacketBuffer.h b/include/PacketBuffer/PacketBuffer.h new file mode 100644 index 0000000..72608cf --- /dev/null +++ b/include/PacketBuffer/PacketBuffer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "Packer.h" +#include "Unpacker.h" + +#include "ObjectSerializer.h" +#include "Serializer/Std.h" diff --git a/include/PacketBuffer/Serializer/Std.h b/include/PacketBuffer/Serializer/Std.h new file mode 100644 index 0000000..1c49700 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_H +#define PACKETBUFFER_SERIALIZER_STD_H + +#include "Std/Array.h" +#include "Std/Chrono.h" +#include "Std/List.h" +#include "Std/Map.h" +#include "Std/Pair.h" +#include "Std/Set.h" +#include "Std/String.h" +#include "Std/Tuple.h" +#include "Std/Vector.h" + +#endif //PACKETBUFFER_SERIALIZER_STD_H diff --git a/include/PacketBuffer/Serializer/Std/Array.h b/include/PacketBuffer/Serializer/Std/Array.h new file mode 100644 index 0000000..d8a20d4 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Array.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_ARRAY_H +#define PACKETBUFFER_SERIALIZER_STD_ARRAY_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for a statically sized array of type T + * with size of S. + * + * @note This serializer does not include the size of the original array + * when serialized. Further changing the size of the array will cause a + * change in the binary format of the packet. + * + * @tparam T the array type + * @tparam S the array fixed size + */ + template + class ObjectSerializer::type> { + public: + template + static inline void pack(Packer& packer, T const array[S]) { + for(int i = 0; i < S; i++) { + packer(array[i]); + } + } + + template + static inline void unpack(Unpacker& unpacker, T array[S]) { + for(int i = 0; i < S; i++) { + unpacker(array[i]); + } + } + }; + + /** + * A ObjectSerializer for a statically sized array of type T + * with size of S. + * + * This implementation is specialized for object whose size is 1 byte. + * + * @note This serializer does not include the size of the original array + * when serialized. Further changing the size of the array will cause a + * change in the binary format of the packet. + * + * @tparam T the array type + * @tparam S the array fixed size + */ + template + class ObjectSerializer::type> { + public: + template + static inline void pack(Packer& packer, T const array[S]) { + packer.pack(reinterpret_cast(array), S); + } + + template + static inline void unpack(Unpacker& unpacker, T array[S]) { + unpacker.unpack(reinterpret_cast(array), S); + } + }; + + /** + * A ObjectSerializer for a statically sized array of type T + * with size of S. + * + * @note This serializer does not include the size of the original array + * when serialized. Further changing the size of the array will cause a + * change in the binary format of the packet. + * + * @tparam T the array type + * @tparam S the array fixed size + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::array& array) { + for(int i = 0; i < S; i++) { + packer(array[i]); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::array& array) { + for(int i = 0; i < S; i++) { + unpacker(array[i]); + } + } + }; + + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_ARRAY_H diff --git a/include/PacketBuffer/Serializer/Std/Chrono.h b/include/PacketBuffer/Serializer/Std/Chrono.h new file mode 100644 index 0000000..d8ec839 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Chrono.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_CHRONO_H +#define PACKETBUFFER_SERIALIZER_STD_CHRONO_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::chrono::duration values with representation + * of type R and period type of P. + * + * @tparam R the duration representation type + * @tparam P the duration period type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::chrono::duration& duration) { + packer((int64_t) duration.count()); + } + + template + static inline void unpack(Unpacker& unpacker, std::chrono::duration& duration) { + int64_t r; + unpacker(r); + duration = std::chrono::duration(r); + } + }; + + /** + * A ObjectSerializer for std::chrono::time_point values with clock + * of type Clock and duration type of Duration. + * + * @tparam Clock the time_point clock type + * @tparam Duration the time_point duration type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::chrono::time_point& point) { + packer(point.time_since_epoch()); + } + + template + static inline void unpack(Unpacker& unpacker, std::chrono::time_point& point) { + Duration d; + unpacker(d); + point = std::chrono::time_point(d); + } + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_CHRONO_H diff --git a/include/PacketBuffer/Serializer/Std/Experimental.h b/include/PacketBuffer/Serializer/Std/Experimental.h new file mode 100644 index 0000000..5c0b837 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Experimental.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_H +#define PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_H + +#include "Experimental/Optional.h" + +#endif //PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_H diff --git a/include/PacketBuffer/Serializer/Std/Experimental/Optional.h b/include/PacketBuffer/Serializer/Std/Experimental/Optional.h new file mode 100644 index 0000000..ff67661 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Experimental/Optional.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_OPTIONAL_H +#define PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_OPTIONAL_H + +#include "PacketBuffer/ObjectSerializer.h" + +#if __has_include() + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::optional of type T. + * + * @tparam T the optional type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::experimental::optional& optional) { + if(optional) { + packer(true); + packer(*optional); + } else { + packer(false); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::experimental::optional& optional) { + bool hasValue; + unpacker(hasValue); + if(hasValue) { + unpacker(*optional); + } + } + }; + + +} +#endif + +#endif //PACKETBUFFER_SERIALIZER_STD_EXPERIMENTAL_OPTIONAL_H diff --git a/include/PacketBuffer/Serializer/Std/List.h b/include/PacketBuffer/Serializer/Std/List.h new file mode 100644 index 0000000..2cb27bc --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/List.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_LIST_H +#define PACKETBUFFER_SERIALIZER_STD_LIST_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::list with elements of type R + * using an allocator of type Allocator. + * + * @tparam T the list element type + * @tparam Allocator the list allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::list& list) { + auto items = static_cast(list.size()); + packer(items); + for(auto& entry : list) { + packer(entry); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::list& list) { + uint64_t items; + unpacker(items); + + for(int i = 0; i < items; i++) { + T v; + unpacker(v); + list.push_back(v); + } + } + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_LIST_H diff --git a/include/PacketBuffer/Serializer/Std/Map.h b/include/PacketBuffer/Serializer/Std/Map.h new file mode 100644 index 0000000..26f2e5b --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Map.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_MAP_H +#define PACKETBUFFER_SERIALIZER_STD_MAP_H + +#include "PacketBuffer/ObjectSerializer.h" +#include "PacketBuffer/Serializer/Std/Pair.h" + +#include +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::map with keys of type K, + * values of type T, comparison functor of type + * Compare and using an allocator of type Allocator. + * + * @tparam K the map element key + * @tparam V the map element value + * @tparam Compare the map comparison functor + * @tparam Allocator the map allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::map& map) { + auto items = static_cast(map.size()); + packer(items); + for(const std::pair& entry : map) { + packer(entry); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::map& map) { + uint64_t items; + unpacker(items); + + for(int i = 0; i < items; i++) { + std::pair entry; + unpacker(entry); + map.insert(std::move(entry)); + } + } + }; + + /** + * A ObjectSerializer for std::unordered_map with keys of type K, + * values of type T, comparison functor of type Compare + * and using an allocator of type Allocator. + * + * @tparam K the map element key + * @tparam V the map element value + * @tparam Compare the map comparison functor + * @tparam Allocator the map allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::unordered_map& map) { + auto items = static_cast(map.size()); + packer(items); + for(const std::pair& entry : map) { + packer(entry); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::unordered_map& map) { + uint64_t items; + unpacker(items); + + for(int i = 0; i < items; i++) { + std::pair entry; + unpacker(entry); + map.insert(std::move(entry)); + } + } + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_MAP_H diff --git a/include/PacketBuffer/Serializer/Std/Pair.h b/include/PacketBuffer/Serializer/Std/Pair.h new file mode 100644 index 0000000..9f852bc --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Pair.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_PAIR_H +#define PACKETBUFFER_SERIALIZER_STD_PAIR_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::pair of types T1 and T2. + * + * @tparam T1 the pair first type + * @tparam T2 the pair second type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::pair& pair) { + packer(pair.first, pair.second); + } + + template + static inline void unpack(Unpacker& unpacker, std::pair& pair) { + unpacker(pair.first, pair.second); + } + }; + + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_PAIR_H diff --git a/include/PacketBuffer/Serializer/Std/Set.h b/include/PacketBuffer/Serializer/Std/Set.h new file mode 100644 index 0000000..7f7c547 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Set.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_SET_H +#define PACKETBUFFER_SERIALIZER_STD_SET_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::set with elements of type T, + * comparison functor of type Compare and using an allocator + * of type Allocator. + * + * @tparam T the set element key + * @tparam Compare the set comparison functor + * @tparam Allocator the set allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::set& set) { + auto items = static_cast(set.size()); + packer(items); + for(auto& entry : set) { + packer(entry); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::set& set) { + uint64_t items; + unpacker(items); + + for(int i = 0; i < items; i++) { + T v; + unpacker(v); + set.insert(v); + } + } + }; + + /** + * A ObjectSerializer for std::unordered_set with elements of type + * T, hash functor of type Hash, predicate of type + * Predicate and using an allocator of type Allocator. + * + * @tparam T the set element key + * @tparam Hash the set hash functor + * @tparam Predicate the set predicate functor + * @tparam Allocator the set allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::unordered_set& set) { + auto items = static_cast(set.size()); + packer(items); + for(auto& entry : set) { + packer(entry); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::unordered_set& set) { + uint64_t items; + unpacker(items); + + set.reserve(items); + for(int i = 0; i < items; i++) { + T v; + unpacker(v); + set.insert(v); + } + } + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_SET_H diff --git a/include/PacketBuffer/Serializer/Std/String.h b/include/PacketBuffer/Serializer/Std/String.h new file mode 100644 index 0000000..c3fcadf --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/String.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_STRING_H +#define PACKETBUFFER_SERIALIZER_STD_STRING_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::basic_string with character of type + * T, traits of type Traits and using an allocator + * of type Allocator. + * + * @tparam T the string character type + * @tparam Traits the string traits + * @tparam Allocator the string character allocator + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::basic_string& string) { + auto length = static_cast(string.size()); + packer(length); + for(int i = 0; i < length; i++) { + packer(string[i]); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::basic_string& string) { + uint64_t length; + unpacker(length); + + string.resize(length); + for(int i = 0; i < length; i++) { + unpacker(string[i]); + } + } + }; + + /** + * A ObjectSerializer for std::string. + */ + template<> + class ObjectSerializer { + public: + template + static inline void pack(Packer& packer, const std::string& string) { + auto length = static_cast(string.size()); + packer(length); + packer.pack(string.data(), string.size()); + } + + template + static inline void unpack(Unpacker& unpacker, std::string& string) { + uint64_t length; + unpacker(length); + + string.resize(length); + unpacker.unpack(&string[0], string.size()); + } + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_STRING_H diff --git a/include/PacketBuffer/Serializer/Std/Tuple.h b/include/PacketBuffer/Serializer/Std/Tuple.h new file mode 100644 index 0000000..5ebb336 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Tuple.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_TUPLE_H +#define PACKETBUFFER_SERIALIZER_STD_TUPLE_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::tuple with elements of type Ts. + * + * @tparam Ts the tuple element types + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::tuple& tuple) { + packImpl(packer, tuple); + } + + template + static inline void unpack(Unpacker& unpacker, std::tuple& tuple) { + unpackImpl(unpacker, tuple); + } + + private: + template + static inline void packImpl(Packer& packer, const std::tuple& tuple) { + packer(std::get(tuple)); + packImpl(packer, tuple); + } + + template + static inline void packImpl(Packer& packer, const std::tuple& tuple) {} + + template + static inline void unpackImpl(Unpacker& unpacker, std::tuple& tuple) { + unpacker(std::get(tuple)); + unpackImpl(unpacker, tuple); + } + + template + static inline void unpackImpl(Unpacker& unpacker, std::tuple& tuple) {} + + }; + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_TUPLE_H diff --git a/include/PacketBuffer/Serializer/Std/Vector.h b/include/PacketBuffer/Serializer/Std/Vector.h new file mode 100644 index 0000000..0dad2f7 --- /dev/null +++ b/include/PacketBuffer/Serializer/Std/Vector.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_SERIALIZER_STD_VECTOR_H +#define PACKETBUFFER_SERIALIZER_STD_VECTOR_H + +#include "PacketBuffer/ObjectSerializer.h" + +#include + +namespace PacketBuffer { + + /** + * A ObjectSerializer for std::vector with elements of type R + * using an allocator of type Allocator. + * + * @tparam T the vector element type + * @tparam Allocator the vector allocator type + */ + template + class ObjectSerializer> { + public: + template + static inline void pack(Packer& packer, const std::vector& vector) { + auto items = static_cast(vector.size()); + packer(items); + for(int i = 0; i < items; i++) { + packer(vector[i]); + } + } + + template + static inline void unpack(Unpacker& unpacker, std::vector& vector) { + uint64_t items; + unpacker(items); + + vector.resize(items); + for(int i = 0; i < items; i++) { + unpacker(vector[i]); + } + } + }; + + +} + +#endif //PACKETBUFFER_SERIALIZER_STD_VECTOR_H diff --git a/include/PacketBuffer/Unpacker.h b/include/PacketBuffer/Unpacker.h new file mode 100644 index 0000000..97146c4 --- /dev/null +++ b/include/PacketBuffer/Unpacker.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PACKETBUFFER_UNPACKER_H +#define PACKETBUFFER_UNPACKER_H + +#include + +#include "ObjectSerializer.h" + +namespace PacketBuffer { + + template + class Unpacker { + private: + Buffer& buffer; + + public: + Unpacker(Buffer& buffer) : buffer(buffer) {}; + + /** + * Deleted copy constructor. + */ + Unpacker(const Unpacker& other) = delete; + + /** + * Deleted copy assignment operator. + */ + Unpacker& operator=(const Unpacker& other) = delete; + + /** + * Deleted move constructor. + */ + Unpacker(Unpacker&& other) = delete; + + /** + * Deleted move assignment operator. + */ + Unpacker& operator=(Unpacker&& other) = delete; + + /** + * Default destructor. + */ + ~Unpacker() = default; + + public: // Helper methods + /** + * A helper & operator overload. Calls the unpack() method for the given type. + * + * @tparam T the data type to unpack + * @param v the value to unpack to + * + * @return this + */ + template + Unpacker& operator&(T& v) { + return unpack(v); + } + + /** + * A helper >> operator overload that behaves similarly to ostreams operator. Calls the + * unpack() method for given type. + * + * @tparam T the data type to unpack + * @param v the value to unpack to + * + * @return this + */ + template + Unpacker& operator>>(T& v) { + return unpack(v); + } + + /** + * A helper call operator overload. Calls unpack() method for the given types. + * + * @tparam Ts the types to be unpacked + * @param vs the values to be unpacked. The values will be unpacked in the given order. + * + * @return this + */ + template + Unpacker& operator()(Ts& ... vs) { + return unpack(vs...); + } + + /** + * Creates a default constructible object of type T and unpacks the data into it. + * + * @tparam T the type to be unpacked + * + * @return the unpacked object + */ + template + T unpack() { + T v; + unpack(v); + return v; + } + + public: // Object serialization + /** + * Unpacks a sequence of objects of types T and Ts.... + * + * The objects will be unpacked in the given order. + * + * @tparam T the type of the first object to be unpacked + * @tparam Ts the type of the remaining objects to be unpacked + * @param v the value of the first object to be unpacked + * @param vs the value of the remaining objects to be unpacked + * + * @return this + */ + template + Unpacker& unpack(T& v, Ts& ... vs) { + unpack(v); + unpack(vs...); + return *this; + } + + /** + * Unpacks a single object of type T. + * + * @tparam T the type of the object to be unpacked + * @param object the value of the object to be unpacked + * + * @return this + */ + template + Unpacker& unpack(T& object) { + ObjectSerializer::unpack(*this, object); + return *this; + } + + public: // Integer types + /** + * Unpacks a uint8_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(uint8_t& i) { + static_assert(sizeof(i) == 1, "uint8_t size must be 1 byte"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a int8_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(int8_t& i) { + static_assert(sizeof(i) == 1, "int8_t size must be 1 byte"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a uint16_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(uint16_t& i) { + static_assert(sizeof(i) == 2, "uint16_t size must be 2 byte2"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a int16_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(int16_t& i) { + static_assert(sizeof(i) == 2, "int16_t size must be 2 byte2"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a uint32_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(uint32_t& i) { + static_assert(sizeof(i) == 4, "uint32_t size must be 4 bytes"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a int32_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(int32_t& i) { + static_assert(sizeof(i) == 4, "int32_t size must be 4 bytes"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a uint64_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(uint64_t& i) { + static_assert(sizeof(i) == 8, "uint64_t size must be 8 bytes"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a int64_t integer value. + * + * @param i the integer value to unpack + * + * @return this + */ + Unpacker& unpack(int64_t& i) { + static_assert(sizeof(i) == 8, "int64_t size must be 8 bytes"); + unpack(reinterpret_cast(&i), sizeof(i)); + boost::endian::conditional_reverse_inplace(i); + return *this; + } + + /** + * Unpacks a boolean value. + * + * @param b the boolean value to unpack + * + * @return this + */ + Unpacker& unpack(bool& b) { + static_assert(sizeof(b) == 1, "bool size must be 1 byte"); + unpack(reinterpret_cast(&b), sizeof(b)); + boost::endian::conditional_reverse_inplace(b); + return *this; + } + + public: // write operation + /** + * Unpacks a char-pointer given by ptr with length given by size. + * + * @param ptr the char pointer to be unpacked + * @param size the char pointer length + * + * @return this + */ + Unpacker& unpack(char* ptr, size_t size) { + buffer.read(ptr, size); + return *this; + } + + /** + * Unpacks a char-pointer given by ptr with length given by size. + * + * @param ptr the char pointer to be unpacked + * @param size the char pointer length + * + * @return this + */ + Unpacker& unpack(unsigned char* ptr, size_t size) { + buffer.read(ptr, size); + return *this; + } + + }; + +} + + +#endif //PACKETBUFFER_UNPACKER_H diff --git a/tests/Packer.cpp b/tests/Packer.cpp new file mode 100644 index 0000000..709d3e6 --- /dev/null +++ b/tests/Packer.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +std::string string_to_hex(const std::string& input) { + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve(2 * len); + for(size_t i = 0; i < len; ++i) { + const unsigned char c = input[i]; + output.push_back(lut[c >> 4]); + output.push_back(lut[c & 15]); + } + return output; +} + +TEST_CASE("Packer", "[packer]") { + + std::stringstream ss; + + SECTION("little endian") { + PacketBuffer::Packer packer(ss); + + SECTION("uint8_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "00"); + } + + SECTION("one") { + packer.pack(uint8_t(1)); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FF"); + } + } + + SECTION("int8_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "80"); + } + + SECTION("zero") { + packer.pack(int8_t(0)); + CHECK(string_to_hex(ss.str()) == "00"); + } + + SECTION("one") { + packer.pack(int8_t(1)); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "7F"); + } + } + + SECTION("uint16_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0000"); + } + + SECTION("one") { + packer.pack(uint16_t(1)); + CHECK(string_to_hex(ss.str()) == "0100"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFF"); + } + } + + SECTION("int16_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0080"); + } + + SECTION("zero") { + packer.pack(int16_t(0)); + CHECK(string_to_hex(ss.str()) == "0000"); + } + + SECTION("one") { + packer.pack(int16_t(1)); + CHECK(string_to_hex(ss.str()) == "0100"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FF7F"); + } + } + + SECTION("uint32_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "00000000"); + } + + SECTION("one") { + packer.pack(uint32_t(1)); + CHECK(string_to_hex(ss.str()) == "01000000"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFFFF"); + } + } + + SECTION("int32_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "00000080"); + } + + SECTION("zero") { + packer.pack(int32_t(0)); + CHECK(string_to_hex(ss.str()) == "00000000"); + } + + SECTION("one") { + packer.pack(int32_t(1)); + CHECK(string_to_hex(ss.str()) == "01000000"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFF7F"); + } + } + + SECTION("uint64_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0000000000000000"); + } + + SECTION("one") { + packer.pack(uint64_t(1)); + CHECK(string_to_hex(ss.str()) == "0100000000000000"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFFFFFFFFFFFF"); + } + } + + SECTION("int64_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0000000000000080"); + } + + SECTION("zero") { + packer.pack(int64_t(0)); + CHECK(string_to_hex(ss.str()) == "0000000000000000"); + } + + SECTION("one") { + packer.pack(int64_t(1)); + CHECK(string_to_hex(ss.str()) == "0100000000000000"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFFFFFFFFFF7F"); + } + } + + SECTION("bool") { + SECTION("true") { + packer.pack(true); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("false") { + packer.pack(false); + CHECK(string_to_hex(ss.str()) == "00"); + } + } + } + + SECTION("big endian") { + PacketBuffer::Packer packer(ss); + + SECTION("uint8_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "00"); + } + + SECTION("one") { + packer.pack(uint8_t(1)); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FF"); + } + } + + SECTION("int8_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "80"); + } + + SECTION("zero") { + packer.pack(int8_t(0)); + CHECK(string_to_hex(ss.str()) == "00"); + } + + SECTION("one") { + packer.pack(int8_t(1)); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "7F"); + } + } + + SECTION("uint16_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0000"); + } + + SECTION("one") { + packer.pack(uint16_t(1)); + CHECK(string_to_hex(ss.str()) == "0001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFF"); + } + } + + SECTION("int16_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "8000"); + } + + SECTION("zero") { + packer.pack(int16_t(0)); + CHECK(string_to_hex(ss.str()) == "0000"); + } + + SECTION("one") { + packer.pack(int16_t(1)); + CHECK(string_to_hex(ss.str()) == "0001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "7FFF"); + } + } + + SECTION("uint32_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "00000000"); + } + + SECTION("one") { + packer.pack(uint32_t(1)); + CHECK(string_to_hex(ss.str()) == "00000001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFFFF"); + } + } + + SECTION("int32_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "80000000"); + } + + SECTION("zero") { + packer.pack(int32_t(0)); + CHECK(string_to_hex(ss.str()) == "00000000"); + } + + SECTION("one") { + packer.pack(int32_t(1)); + CHECK(string_to_hex(ss.str()) == "00000001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "7FFFFFFF"); + } + } + + SECTION("uint64_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "0000000000000000"); + } + + SECTION("one") { + packer.pack(uint64_t(1)); + CHECK(string_to_hex(ss.str()) == "0000000000000001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "FFFFFFFFFFFFFFFF"); + } + } + + SECTION("int64_t") { + SECTION("min") { + packer.pack(std::numeric_limits::min()); + CHECK(string_to_hex(ss.str()) == "8000000000000000"); + } + + SECTION("zero") { + packer.pack(int64_t(0)); + CHECK(string_to_hex(ss.str()) == "0000000000000000"); + } + + SECTION("one") { + packer.pack(int64_t(1)); + CHECK(string_to_hex(ss.str()) == "0000000000000001"); + } + + SECTION("max") { + packer.pack(std::numeric_limits::max()); + CHECK(string_to_hex(ss.str()) == "7FFFFFFFFFFFFFFF"); + } + } + + SECTION("bool") { + SECTION("true") { + packer.pack(true); + CHECK(string_to_hex(ss.str()) == "01"); + } + + SECTION("false") { + packer.pack(false); + CHECK(string_to_hex(ss.str()) == "00"); + } + } + } + +} \ No newline at end of file diff --git a/tests/Serializer/Std/Array.cpp b/tests/Serializer/Std/Array.cpp new file mode 100644 index 0000000..d54eb3d --- /dev/null +++ b/tests/Serializer/Std/Array.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +namespace { + std::string string_to_hex(const std::string& input) { + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve(2 * len); + for(size_t i = 0; i < len; ++i) { + const unsigned char c = input[i]; + output.push_back(lut[c >> 4]); + output.push_back(lut[c & 15]); + } + return output; + } +} + +TEST_CASE("Serializer/Std/Array", "[serializer][std][array]") { + + std::stringstream ss; + PacketBuffer::Packer packer(ss); + PacketBuffer::Unpacker unpacker(ss); + + SECTION("empty array") { + SECTION("should be correctly packed") { + std::array array; + packer.pack(array); + + CHECK(string_to_hex(ss.str()) == ""); + + SECTION("and should unpack back") { + std::array unpacked; + unpacker.unpack(unpacked); + + CHECK(unpacked.size() == 0); + } + + } + } + + SECTION("should be correctly packed") { + std::array array = {100, 200}; + packer.pack(array); + + CHECK(string_to_hex(ss.str()) == "64C8"); + + SECTION("and should unpack back") { + std::array unpacked; + unpacker.unpack(unpacked); + + REQUIRE(unpacked.size() == 2); + CHECK(unpacked == array); + } + } + +} + +TEST_CASE("Serializer/Std/CArray", "[serializer][std][c-array]") { + std::stringstream ss; + PacketBuffer::Packer packer(ss); + PacketBuffer::Unpacker unpacker(ss); + + SECTION("should be correctly packed") { + uint8_t array[4] = {1, 2, 3, 4}; + packer.pack(array); + + CHECK(string_to_hex(ss.str()) == "01020304"); + + SECTION("and should unpack back") { + uint8_t unpacked[4]; + unpacker.unpack(unpacked); + + CHECK(unpacked[0] == array[0]); + CHECK(unpacked[1] == array[1]); + CHECK(unpacked[2] == array[2]); + CHECK(unpacked[3] == array[3]); + } + } + +} \ No newline at end of file diff --git a/tests/Serializer/Std/String.cpp b/tests/Serializer/Std/String.cpp new file mode 100644 index 0000000..f9cc6f6 --- /dev/null +++ b/tests/Serializer/Std/String.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include + +namespace { + std::string string_to_hex(const std::string& input) { + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + + std::string output; + output.reserve(2 * len); + for(size_t i = 0; i < len; ++i) { + const unsigned char c = input[i]; + output.push_back(lut[c >> 4]); + output.push_back(lut[c & 15]); + } + return output; + } +} + +TEST_CASE("Serializer/Std/String", "[serializer][std][string]") { + + std::stringstream ss; + PacketBuffer::Packer packer(ss); + PacketBuffer::Unpacker unpacker(ss); + + SECTION("empty string") { + SECTION("should be correctly packed") { + std::string string = ""; + packer.pack(string); + + CHECK(string_to_hex(ss.str()) == "0000000000000000"); + + SECTION("and should unpack back") { + std::string unpacked; + unpacker.unpack(unpacked); + + CHECK(unpacked.size() == 0); + CHECK(unpacked == string); + } + + } + } + + SECTION("should be correctly packed") { + std::string string = "Hello Testing World"; + packer.pack(string); + + CHECK(string_to_hex(ss.str()) == "130000000000000048656C6C6F2054657374696E6720576F726C64"); + + SECTION("and should unpack back") { + std::string unpacked; + unpacker.unpack(unpacked); + + REQUIRE(unpacked.size() == 19); + CHECK(unpacked == string); + } + } + + SECTION("with NULL character") { + SECTION("should be correctly packed") { + std::string string = "Hey"; + string.resize(4); + string[3] = 0x00; + packer.pack(string); + + CHECK(string_to_hex(ss.str()) == "040000000000000048657900"); + + SECTION("and should unpack back") { + std::string unpacked; + unpacker.unpack(unpacked); + + REQUIRE(unpacked.size() == 4); + CHECK(unpacked == string); + } + } + } + +} \ No newline at end of file diff --git a/tests/Unpacker.cpp b/tests/Unpacker.cpp new file mode 100644 index 0000000..af95582 --- /dev/null +++ b/tests/Unpacker.cpp @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include + +std::string hex_to_string(const std::string& input) { + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + if(len & 1) throw std::invalid_argument("odd length"); + + std::string output; + output.reserve(len / 2); + for(size_t i = 0; i < len; i += 2) { + char a = input[i]; + const char* p = std::lower_bound(lut, lut + 16, a); + if(*p != a) throw std::invalid_argument("not a hex digit"); + + char b = input[i + 1]; + const char* q = std::lower_bound(lut, lut + 16, b); + if(*q != b) throw std::invalid_argument("not a hex digit"); + + output.push_back(((p - lut) << 4) | (q - lut)); + } + return output; +} + +TEST_CASE("Unpacker", "[unpacker]") { + + std::stringstream ss; + + SECTION("little endian") { + PacketBuffer::Unpacker unpacker(ss); + + SECTION("uint8_t") { + SECTION("min") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FF")); + CHECK(unpacker.unpack() == 255); + } + } + + SECTION("int8_t") { + SECTION("min") { + ss.str(hex_to_string("80")); + CHECK(unpacker.unpack() == -128); + } + + SECTION("zero") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("7F")); + CHECK(unpacker.unpack() == 127); + } + } + + SECTION("uint16_t") { + SECTION("min") { + ss.str(hex_to_string("0000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0100")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFF")); + CHECK(unpacker.unpack() == 65535); + } + } + + SECTION("int16_t") { + SECTION("min") { + ss.str(hex_to_string("0080")); + CHECK(unpacker.unpack() == -32768); + } + + SECTION("zero") { + ss.str(hex_to_string("0000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0100")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FF7F")); + CHECK(unpacker.unpack() == 32767); + } + } + + SECTION("uint32_t") { + SECTION("min") { + ss.str(hex_to_string("00000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01000000")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFFFF")); + CHECK(unpacker.unpack() == 4294967295); + } + } + + SECTION("int32_t") { + SECTION("min") { + ss.str(hex_to_string("00000080")); + CHECK(unpacker.unpack() == -2147483648); + } + + SECTION("zero") { + ss.str(hex_to_string("00000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01000000")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFF7F")); + CHECK(unpacker.unpack() == 2147483647); + } + } + + SECTION("uint64_t") { + SECTION("min") { + ss.str(hex_to_string("0000000000000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0100000000000000")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFFFFFFFFFFFF")); + CHECK(unpacker.unpack() == 18446744073709551615UL); + } + } + + SECTION("int64_t") { + SECTION("min") { + ss.str(hex_to_string("0000000000000080")); + CHECK(unpacker.unpack() == -9223372036854775808L); + } + + SECTION("zero") { + ss.str(hex_to_string("0000000000000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0100000000000000")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFFFFFFFFFF7F")); + CHECK(unpacker.unpack() == 9223372036854775807L); + } + } + + SECTION("bool") { + SECTION("true") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == true); + } + + SECTION("false") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == false); + } + } + } + + SECTION("big endian") { + PacketBuffer::Unpacker unpacker(ss); + + SECTION("uint8_t") { + SECTION("min") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FF")); + CHECK(unpacker.unpack() == 255); + } + } + + SECTION("int8_t") { + SECTION("min") { + ss.str(hex_to_string("80")); + CHECK(unpacker.unpack() == -128); + } + + SECTION("zero") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("7F")); + CHECK(unpacker.unpack() == 127); + } + } + + SECTION("uint16_t") { + SECTION("min") { + ss.str(hex_to_string("0000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFF")); + CHECK(unpacker.unpack() == 65535); + } + } + + SECTION("int16_t") { + SECTION("min") { + ss.str(hex_to_string("8000")); + CHECK(unpacker.unpack() == -32768); + } + + SECTION("zero") { + ss.str(hex_to_string("0000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("7FFF")); + CHECK(unpacker.unpack() == 32767); + } + } + + SECTION("uint32_t") { + SECTION("min") { + ss.str(hex_to_string("00000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("00000001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFFFF")); + CHECK(unpacker.unpack() == 4294967295); + } + } + + SECTION("int32_t") { + SECTION("min") { + ss.str(hex_to_string("80000000")); + CHECK(unpacker.unpack() == -2147483648); + } + + SECTION("zero") { + ss.str(hex_to_string("00000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("00000001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("7FFFFFFF")); + CHECK(unpacker.unpack() == 2147483647); + } + } + + SECTION("uint64_t") { + SECTION("min") { + ss.str(hex_to_string("0000000000000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0000000000000001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("FFFFFFFFFFFFFFFF")); + CHECK(unpacker.unpack() == 18446744073709551615UL); + } + } + + SECTION("int64_t") { + SECTION("min") { + ss.str(hex_to_string("8000000000000000")); + CHECK(unpacker.unpack() == -9223372036854775808L); + } + + SECTION("zero") { + ss.str(hex_to_string("0000000000000000")); + CHECK(unpacker.unpack() == 0); + } + + SECTION("one") { + ss.str(hex_to_string("0000000000000001")); + CHECK(unpacker.unpack() == 1); + } + + SECTION("max") { + ss.str(hex_to_string("7FFFFFFFFFFFFFFF")); + CHECK(unpacker.unpack() == 9223372036854775807L); + } + } + + SECTION("bool") { + SECTION("true") { + ss.str(hex_to_string("01")); + CHECK(unpacker.unpack() == true); + } + + SECTION("false") { + ss.str(hex_to_string("00")); + CHECK(unpacker.unpack() == false); + } + } + } + + SECTION("should throw an error on overflow") { + PacketBuffer::Unpacker unpacker(ss); + +// REQUIRE_THROWS(unpacker.unpack()); + } + + +} \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..17239c7 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Rogiel Sulzbach + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Rogiel Sulzbach nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define CATCH_CONFIG_MAIN + +#include "catch.hpp"