FeatherMC/src/PacketReader.h

113 lines
2.8 KiB
C++

#pragma once
#include "Common.h"
#include "util/ByteUtil.h"
#include <cstdio>
#include <cstdint>
#include <string>
using std::string;
namespace Feather
{
// Class to read packet data, such as is produced by NetworkMessage
class PacketReader
{
public:
PacketReader(const uint8_t *const dataPtr)
: m_data(dataPtr), m_offset(0), m_length(ReadLength())
{
}
// Peek the next value to be read
// If big endian (the default), will reverse byte order.
template <typename T, Endian endianMode = Endian::Big>
inline T Peek()
{
T value = *reinterpret_cast<const T *const>(&m_data[m_offset]);
return (endianMode == Endian::Big) ? ReverseBytes<T>(value) : value;
}
// Read the next value
// If big endian (the default), will reverse byte order.
template <typename T, Endian endianMode = Endian::Big>
inline T Read()
{
T value = Peek<T, endianMode>();
m_offset += sizeof(T);
return value;
}
// Fast way to peek the next byte
inline uint8_t PeekByte() { return m_data[m_offset]; }
// Fast way to read a byte
inline uint8_t ReadByte() { return m_data[m_offset++]; }
inline int32_t ReadLength()
{
int32_t length = ReadVarInt();
// HACK: handle Legacy Server List Ping
if (length == 0xFE) {
if (PeekByte() == 0x01) {
return 2;
}
}
return length;
}
template <typename T = int32_t>
inline T ReadVarInt()
{
int32_t numRead = 0;
int32_t result = 0;
uint8_t read;
do
{
read = ReadByte();
int value = (read & 0b01111111);
result |= (value << (7 * numRead));
numRead++;
if (numRead > 5)
{
// complain
//throw new RuntimeException("VarInt is too big");
}
} while ((read & 0b10000000) != 0);
return static_cast<T>(result);
}
string ReadString()
{
int size = ReadVarInt();
string str;
for (int i = 0; i < size; i++) {
str += ReadByte();
}
return str;
}
uint32_t Length() const { return m_length; }
private:
const uint8_t *const m_data;
uint32_t m_offset;
const uint32_t m_length;
};
// Use fast Read and Peek for uint8_t
template <>
inline uint8_t PacketReader::Peek<uint8_t>() { return PeekByte(); }
template<>
inline uint8_t PacketReader::Read<uint8_t>() { return ReadByte(); }
}