--- /dev/null
+
+/*] Copyright (c) 2009-2010, Charles McGarvey [**************************
+**] All rights reserved.
+*
+* vi:ts=4 sw=4 tw=75
+*
+* Distributable under the terms and conditions of the 2-clause BSD license;
+* see the file COPYING for a complete text of the license.
+*
+**************************************************************************/
+
+/**
+ * \file Packet.hh
+ * Classes for building and interpreting datagram packets.
+ */
+
+#ifndef _MOOF_PACKET_HH_
+#define _MOOF_PACKET_HH_
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+
+namespace Mf {
+
+
+/**
+ * Represents a packet of serialized variables ready for transfer over the
+ * network. This method is most suitable for representing datagram
+ * packets, but it may also be useful for seralizing data for persistent
+ * state storage. The semantics are similar to that of a FIFO queue or
+ * stream where packets are written and read by inserting and extracting
+ * variables to and from the packet, although the actual order of the
+ * variables in the buffer may be different. At any time, a pointer to a
+ * buffer and the size of the buffer can be retrieved. This class also
+ * handles endian differences by serializing variables in network byte
+ * order (big endian).
+ */
+class Packet
+{
+public:
+
+ /**
+ * Packet flags.
+ */
+ enum Flags
+ {
+ PEEK = 0x01 /// Do not actually remove anything.
+ };
+
+
+ /**
+ * Construct a packet with an initial capacity.
+ * \param capacity Initial capacity of the packet.
+ */
+ Packet(size_t capacity = PAGE_SIZE);
+
+ /**
+ * Construct a packet with some bytes from a buffer. The bytes will be
+ * copied into the packet, so you don't need to keep the original
+ * buffer.
+ * \param data The bytes.
+ * \param size The number of bytes.
+ */
+ Packet(const char* data, size_t size);
+
+
+ /**
+ * Insert a variable into the packet, serializing it. This usually
+ * increases the size of the packet by the size of the data type.
+ * \param value The value to insert.
+ * \return This.
+ */
+ bool put(bool value);
+ bool put(int8_t value);
+ bool put(int16_t value);
+ bool put(int32_t value);
+ bool put(int64_t value);
+ bool put(uint8_t value);
+ bool put(uint16_t value);
+ bool put(uint32_t value);
+ bool put(uint64_t value);
+ bool put(float value);
+ bool put(double value);
+
+ bool put(const char* value)
+ {
+ uint16_t length = strlen(value);
+ if (put(length))
+ {
+ size_t numBytes = write(value, length);
+ return numBytes == length;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool put(const std::basic_string<T>& value)
+ {
+ if (put(uint16_t(value.length())))
+ {
+ size_t byteLength = value.length() * sizeof(T);
+ size_t numBytes = write(value.data(), byteLength);
+ return numBytes == byteLength;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool put(const std::vector<T>& value)
+ {
+ if (put(uint16_t(value.size())))
+ {
+ typename std::vector<T>::const_iterator it;
+ for (it = value.begin(); it != value.end(); ++it)
+ {
+ if (!put(*it)) return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Write some bytes to the packet.
+ * \param bytes The bytes.
+ * \param size The number of bytes.
+ * return The number of bytes actually written.
+ */
+ size_t write(const void* bytes, size_t size);
+
+
+ /**
+ * Extract a variable from the packet. This usually decreases the size
+ * of the packet by the size of the data type.
+ * \param value Reference to the variable to extract.
+ * \return This.
+ */
+ bool get(bool& value, int flags = 0);
+ bool get(int8_t& value, int flags = 0);
+ bool get(int16_t& value, int flags = 0);
+ bool get(int32_t& value, int flags = 0);
+ bool get(int64_t& value, int flags = 0);
+ bool get(uint8_t& value, int flags = 0);
+ bool get(uint16_t& value, int flags = 0);
+ bool get(uint32_t& value, int flags = 0);
+ bool get(uint64_t& value, int flags = 0);
+ bool get(float& value, int flags = 0);
+ bool get(double& value, int flags = 0);
+
+ template <class T>
+ bool get(std::basic_string<T>& value, int flags = 0)
+ {
+ uint16_t length = 0;
+ if (get(length, flags))
+ {
+ size_t byteLength = length * sizeof(T);
+ T str[length];
+ size_t numBytes = read(str, byteLength, flags);
+ value.assign(str, numBytes);
+ return numBytes == byteLength;
+ }
+ return false;
+ }
+
+ template <class T>
+ bool get(std::vector<T>& value, int flags = 0)
+ {
+ uint16_t size = 0;
+ if (get(size, flags))
+ {
+ value.clear();
+ for (uint16_t i = 0; i < size; ++i)
+ {
+ T item;
+ if (get(item, flags)) value.push_back(item);
+ else return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Read some bytes from the packet.
+ * \param bytes The buffer to hold the bytes read.
+ * \param size The size of the read buffer.
+ * \return The number of bytes actually read.
+ */
+ size_t read(void* bytes, size_t size, int flags = 0);
+
+
+ /**
+ * Clear the contents of the packet, setting the size of the packet to
+ * zero.
+ */
+ void clear();
+
+
+ /**
+ * Reset the read/write markers to their initial positions, putting the
+ * packet in the state it was at right after construction.
+ */
+ void reset();
+
+
+ /**
+ * Get a pointer to an internal structure holding the serialized bytes
+ * of the packet.
+ * return The pointer.
+ */
+ const char* bytes() const
+ {
+ return mBuffer + mR;
+ }
+
+ /**
+ * Get the size of the buffer holding the serialized bytes of the
+ * packet.
+ * \return The number of bytes.
+ */
+ size_t size() const
+ {
+ return mW - mR;
+ }
+
+ // The rest of this stuff is just to implement correct copy semantics.
+
+ Packet(const Packet& copy);
+ Packet& operator=(const Packet& copy);
+ ~Packet();
+
+
+private:
+
+ char* mBuffer;
+ size_t mSize;
+
+ size_t mR;
+ size_t mW;
+ size_t mOriginalW;
+
+ size_t mBoolR;
+ size_t mBoolW;
+ size_t mBoolNumR;
+ size_t mBoolNumW;
+};
+
+
+} // namespace Mf
+
+#endif // _MOOF_PACKET_HH_
+