#include <iostream>
#include <vector>
#include <stdexcept>
#include <cstdint>
class Packet
{
private:
std::vector<uint8_t> buffer;
int byteIndex;
int maxByteIndex;
public:
Packet() : byteIndex(0), maxByteIndex(0)
{
}
char* GetBuffer()
{
return reinterpret_cast<char*>(&buffer[0]);
}
int GetLength()
{
return buffer.size();
}
int GetByteIndex()
{
return byteIndex;
}
void SetByteIndex(int value)
{
if (value < 0 || value >= buffer.size())
{
throw std::out_of_range("ByteIndex must be an index in the Buffer");
}
byteIndex = value;
}
bool HasHeader()
{
return byteIndex >= 2;
}
bool HasData()
{
return byteIndex == maxByteIndex;
}
void Begin()
{
buffer.push_back(0);
buffer.push_back(0);
byteIndex += 2;
}
void End()
{
buffer[0] = static_cast<uint8_t>(buffer.size()) >> 8;
buffer[1] = static_cast<uint8_t>(buffer.size());
}
bool ReadHeader()
{
int previousByteIndex = byteIndex;
byteIndex = 0;
uint16_t length;
ReadUInt16(length);
maxByteIndex = length - 1;
byteIndex = previousByteIndex;
return maxByteIndex > 2;
}
void WriteEventID(uint8_t value)
{
buffer.push_back(value);
byteIndex++;
}
void WriteByte(uint8_t value)
{
buffer.push_back(value);
byteIndex++;
}
void WriteUInt16(uint16_t value)
{
buffer.push_back(static_cast<uint8_t>(value >> 8));
buffer.push_back(static_cast<uint8_t>(value));
byteIndex += 2;
}
void WriteString(std::string value, int maxLength = 255)
{
if (maxLength < 0 || maxLength > 65535)
{
throw std::out_of_range("maxLength must be in the range [0, 65535]");
}
if (value.length() > maxLength)
{
throw std::out_of_range("String length was over the given max length");
}
WriteUInt16(static_cast<uint16_t>(value.length()));
for (int i = 0; i < value.length(); ++i)
{
WriteByte(value[i]);
}
}
bool ReadEventID(uint8_t& value)
{
return ReadByte(value);
}
bool ReadByte(uint8_t& value)
{
value = 0;
if (byteIndex >= buffer.size())
{
return false;
}
value = buffer[byteIndex];
byteIndex++;
return true;
}
bool ReadUInt16(uint16_t& value)
{
value = 0;
if (byteIndex + 1 >= buffer.size())
{
return false;
}
value = static_cast<uint16_t>(buffer[byteIndex] << 8);
value |= static_cast<uint16_t>(buffer[byteIndex + 1]);
byteIndex += 2;
return true;
}
bool ReadString(std::string& value, int maxLength = 255)
{
value = "";
uint16_t length;
if (!ReadUInt16(length) || length > maxLength || byteIndex + length > buffer.size())
{
return false;
}
for (int i = 0; i < length; ++i)
{
value += static_cast<char>(buffer[byteIndex + i]);
}
byteIndex += length;
return true;
}
};
int main()
{
Packet packet;
packet.Begin();
packet.WriteEventID(42);
packet.WriteByte(43);
packet.WriteUInt16(65535);
packet.WriteString("Hello World", 20);
packet.End();
packet.SetByteIndex(2);
uint8_t eventID;
if (!packet.ReadEventID(eventID)) { std::cout << "Error reading" << std::endl; return -1; }
std::cout << static_cast<int>(eventID) << std::endl;
uint8_t byteValue;
if (!packet.ReadByte(byteValue)) { std::cout << "Error reading" << std::endl; return -1; }
std::cout << static_cast<int>(byteValue) << std::endl;
uint16_t ushortValue;
if (!packet.ReadUInt16(ushortValue)) { std::cout << "Error reading" << std::endl; return -1; }
std::cout << ushortValue << std::endl;
std::string stringValue;
if (!packet.ReadString(stringValue)) { std::cout << "Error reading" << std::endl; return -1; }
std::cout << stringValue << std::endl;
/*
To read from a TCP stream:
// packet is a per end point object that persists through read callbacks
for (int readByteIndex = 0; readByteIndex < receiveBufferSize; ++readByteIndex)
{
packet.WriteByte(receiveBuffer[readByteIndex]);
if (!packet.HasHeader())
{
if (!packet.ReadHeader())
{
DisconnectEndPoint();
}
}
if (!packet.HasData())
{
// Packets is a ConcurrentQueue
endPoint.Packets.Enqueue(packet);
packet = new Packet();
}
}
*/
return 0;
}