From 821eb27e1899a81a3b3e196e4f3fa634ebaa1e4e Mon Sep 17 00:00:00 2001 From: hama Date: Fri, 27 Mar 2015 01:10:33 +0100 Subject: [PATCH] ReSerializable --- base/ReByteBuffer.hpp | 104 +++++++++++++++++++++ base/ReSerializable.cpp | 22 +++++ base/ReSerializable.hpp | 200 ++++++++++++++++++++++++++++++++++++++++ base/rebase.hpp | 1 + 4 files changed, 327 insertions(+) create mode 100644 base/ReSerializable.cpp create mode 100644 base/ReSerializable.hpp diff --git a/base/ReByteBuffer.hpp b/base/ReByteBuffer.hpp index 461ec69..8f98f15 100644 --- a/base/ReByteBuffer.hpp +++ b/base/ReByteBuffer.hpp @@ -46,6 +46,64 @@ public: ReByteBuffer& append(const Byte* source, size_t length = -1); ReByteBuffer& append(const ReByteBuffer& source); ReByteBuffer& append(double, const char* format = "%f"); + /** Appends a 8 bit value in an architecture independent way. + * @param value character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendBits8(int value){ + setLength(m_length + 1); + m_buffer[m_length - 1] = (char) value; + return *this; + } + /** Appends a 16 bit value in an architecture independent way. + * @param value character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendBits16(int value){ + setLength(m_length + 2); + m_buffer[m_length - 2] = char(value >> 8); + m_buffer[m_length - 1] = char(value); + return *this; + } + /** Appends a 24 bit value in an architecture independent way. + * @param value character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendBits24(int value){ + setLength(m_length + 3); + m_buffer[m_length - 3] = char(value >> 16); + m_buffer[m_length - 2] = char(value >> 8); + m_buffer[m_length - 1] = char(value); + return *this; + } + /** Appends a 24 bit value in an architecture independent way. + * @param value character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendBits32(int value){ + setLength(m_length + 4); + m_buffer[m_length - 4] = char(value >> 24); + m_buffer[m_length - 3] = char(value >> 16); + m_buffer[m_length - 2] = char(value >> 8); + m_buffer[m_length - 1] = char(value); + return *this; + } + /** Appends a 24 bit value in an architecture independent way. + * @param value character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendBits64(int64_t value){ + setLength(m_length + 8); + m_buffer[m_length - 8] = char(value >> 56); + m_buffer[m_length - 7] = char(value >> 48); + m_buffer[m_length - 6] = char(value >> 40); + m_buffer[m_length - 5] = char(value >> 32); + m_buffer[m_length - 4] = char(value >> 24); + m_buffer[m_length - 3] = char(value >> 16); + m_buffer[m_length - 2] = char(value >> 8); + m_buffer[m_length - 1] = char(value); + return *this; + } /** Appends a character. * @param aChar character to append * @return *this (for chaining) @@ -55,6 +113,52 @@ public: m_buffer[m_length - 1] = aChar; return *this; } + /** Appends 2 characters. + * @param char1 first character to append + * @param char2 2nd character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendChar2(char char1, char char2) { + setLength(m_length + 2); + m_buffer[m_length - 2] = char1; + m_buffer[m_length - 1] = char2; + return *this; + } + /** Appends 4 characters. + * @param char1 first character to append + * @param char2 2nd character to append + * @param char3 3rd character to append + * @param char4 4th character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendChar(char char1, char char2, char char3, char char4) { + setLength(m_length + 4); + m_buffer[m_length - 4] = char1; + m_buffer[m_length - 3] = char2; + m_buffer[m_length - 2] = char3; + m_buffer[m_length - 1] = char4; + return *this; + } + /** Appends 4 characters. + * @param char1 first character to append + * @param char2 2nd character to append + * @param char3 3rd character to append + * @param char4 4th character to append + * @return *this (for chaining) + */ + inline ReByteBuffer& appendChar(char char1, char char2, char char3, + char char4, char char5, char char6, char char7, char char8) { + setLength(m_length + 8); + m_buffer[m_length - 8] = char1; + m_buffer[m_length - 7] = char2; + m_buffer[m_length - 6] = char3; + m_buffer[m_length - 5] = char4; + m_buffer[m_length - 4] = char5; + m_buffer[m_length - 3] = char6; + m_buffer[m_length - 2] = char7; + m_buffer[m_length - 1] = char8; + return *this; + } /** Appends a character at least one time. * @param aChar character to append * @param count number of times to append diff --git a/base/ReSerializable.cpp b/base/ReSerializable.cpp new file mode 100644 index 0000000..d08c6d8 --- /dev/null +++ b/base/ReSerializable.cpp @@ -0,0 +1,22 @@ +/* + * ReSerializable.cpp + * + * License: Public domain + * Do what you want. + * No warranties and disclaimer of any damages. + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" + +/** + * Constructor. + * + * @param length the + */ +ReSerializationLengthException::ReSerializationLengthException(int currentLength, + int expectedlength) : + ReSerializationException(), + m_currentLength(currentLength), + m_expectedLength(expectedlength){ +} diff --git a/base/ReSerializable.hpp b/base/ReSerializable.hpp new file mode 100644 index 0000000..dc013bd --- /dev/null +++ b/base/ReSerializable.hpp @@ -0,0 +1,200 @@ +/* + * ReSerializable.hpp + * + * License: Public domain + * Do what you want. + * No warranties and disclaimer of any damages. + * The latest sources: https://github.com/republib + */ + +#ifndef BASE_RESERIALIZABLE_HPP_ +#define BASE_RESERIALIZABLE_HPP_ + +/** + * Base class for all serialization/deserialization errors. + */ +class ReSerializationException: public ReException { +}; +/** + * The length is not enough for the deserialization. + */ +class ReSerializationLengthException : public ReSerializationException { +public: + ReSerializationLengthException(int currentLength, int expectedLength); +public: + int m_currentLength; + int m_expectedLength; +}; +/** + * Unexpected data found while unpacking. + */ +class ReSerializeFormatException : public ReSerializationException { +}; +/** + * Abstract base class for serializing. + * + * Serializing packs a class into a sequence of bytes. + * Deserializing converts a sequence of bytes into the members of the instance. + */ +class ReSerializable { +public: + virtual ~ReSerializable() { + } +public: + /** Appends a boolean value. + * @param buffer IN/OUT: the buffer with the serialized values + * @param value the value to serialize + */ + inline void packBool(ReByteBuffer& buffer, bool value) { + buffer.appendChar(value ? 't' : 'f'); + } + /** Appends a string with a maximal length of 255 to the buffer. + * @param buffer IN/OUT: the buffer with the serialized values + * @param value the value to serialize + */ + inline void packString8(ReByteBuffer& buffer, ReByteBuffer& value) { + buffer.appendBits8(value.length()).append(value); + } + /** Appends a string with a maximal length of 64KiByte to the buffer. + * @param buffer IN/OUT: the buffer with the serialized values + * @param value the value to serialize + */ + inline void appendString16(ReByteBuffer& buffer, ReByteBuffer& value) { + buffer.appendBits16(value.length()).append(value); + } + /** Appends a string with a maximal length of 4GiByte to the buffer. + * @param buffer IN/OUT: the buffer with the serialized values + * @param value the value to serialize + */ + inline void appendString32(ReByteBuffer& buffer, ReByteBuffer& value) { + buffer.appendBits32(value.length()).append(value); + } + /** Sets the members of the instance from the byte sequence. + * + * @param sequence IN: a byte sequence starting with the serialized members + * of the instance
+ * OUT: the byte sequence behind the serialized members + * @param length IN: the length of sequence
+ * OUT: the length of sequence without the + * serialized members + */ + virtual void deserialize(uint8_t*& sequence, size_t& length) = 0; + /** Appends the class members to the end of the buffer. + * + * @param buffer IN/OUT: the buffer containing the serialized bytes + * @return the buffer (for chaining) + */ + virtual ReByteBuffer& serialize(ReByteBuffer& buffer) = 0; + /** Reads a 8 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackBool(uint8_t*& sequence, size_t& length, bool& value) { + if (length < 1) + throw ReSerializationLengthException(length, 1); + char cc = *sequence++; + if (cc != 't' && cc != 'f') + throw ReSerializeFormatException(i18n("not a boolean value")); + value = cc == 't'; + length--; + } + /** Reads a 8 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackInt8(uint8_t*& sequence, size_t& length, int& value) { + if (length < 1) + throw ReSerializationLengthException(length, 1); + value = *sequence++; + length--; + } + /** Reads a 16 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackInt16(uint8_t*& sequence, size_t& length, int& value) { + if (length < 2) + throw ReSerializationLengthException(length, 2); + value = (*sequence++ << 8) + *sequence++; + length -= 2; + } + /** Reads a 24 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackInt24(uint8_t*& sequence, size_t& length, int& value) { + if (length < 3) + throw ReSerializationLengthException(length, 3); + value = (*sequence++ << 16) + (*sequence++ << 8) + *sequence++; + length -= 3; + } + /** Reads a 32 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackInt32(uint8_t*& sequence, size_t& length, int& value) { + if (length < 4) + throw ReSerializationLengthException(length, 4); + value = (*sequence++ << 24) + (*sequence++ << 16) + (*sequence++ << 8) + + *sequence++; + length -= 4; + } + /** Reads a 64 bit integer from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackInt64(uint8_t*& sequence, size_t& length, int64_t& value) { + if (length < 8) + throw ReSerializationLengthException(length, 8); + value = (int64_t(*sequence++) << 56) + (int64_t(*sequence++) << 48) + + (int64_t(*sequence++) << 40) + (int64_t(*sequence++) << 32) + + (int64_t(*sequence++) << 24) + (int64_t(*sequence++) << 16) + + (int64_t(*sequence++) << 8) + int64_t(*sequence++); + length -= 8; + } + /** Reads a string with a max. length of 255 from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackString255(uint8_t*& sequence, size_t& length, ReByteBuffer& value) { + size_t strLen = 0; + if (length == 0 || (strLen = *sequence) > length) + throw ReSerializationLengthException(length, 1 + strLen); + value.set(reinterpret_cast(sequence), strLen); + length -= strLen - 1; + } + /** Reads a string with a max. length of 64KiByte from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackString64k(uint8_t*& sequence, size_t& length, ReByteBuffer& value) { + size_t strLen = 0; + if (length == 0 || (strLen = (sequence[0] << 8) + sequence[1]) > length) + throw ReSerializationLengthException(length, 1 + strLen); + value.set(reinterpret_cast(sequence), strLen); + length -= strLen - 1; + } + /** Reads a string with a max. length of 64KiByte from the serialized byte sequence. + * @param sequence IN/OUT: the byte sequence with the serialized data + * @param length IN/OUT: the length of sequence + * @param value OUT: the value read from the sequence + */ + inline void unpackString4t(uint8_t*& sequence, size_t& length, ReByteBuffer& value) { + size_t strLen = 0; + if (length == 0 || (strLen = (sequence[0] << 24) + (sequence[1] << 16) + + (sequence[2] << 8) + sequence[3]) > length) + throw ReSerializationLengthException(length, 1 + strLen); + value.set(reinterpret_cast(sequence), strLen); + length -= strLen - 1; + } +}; + +#endif /* BASE_RESERIALIZABLE_HPP_ */ diff --git a/base/rebase.hpp b/base/rebase.hpp index a358798..f035848 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -120,6 +120,7 @@ inline int max(int a, int b){ } #include "base/ReMutex.hpp" #include "base/ReByteBuffer.hpp" +#include "base/ReSerializable.hpp" #include "base/ReVarArgs.hpp" #include "base/ReLogger.hpp" #include "base/ReThread.hpp" -- 2.39.5