FeatherMC/src/PacketReader.h

134 lines
3.5 KiB
C
Raw Normal View History

#pragma once
#include "Common.h"
2020-08-01 01:49:07 +01:00
#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:
2020-07-28 05:40:47 +01:00
PacketReader(const uint8_t *const dataPtr)
2020-08-01 05:45:39 +01:00
: m_data(dataPtr), m_offset(0), m_length(ReadLength())
2020-07-28 01:26:46 +01:00
{
}
2020-08-01 01:49:07 +01:00
// 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()
{
2020-08-01 01:49:07 +01:00
T value = *reinterpret_cast<const T *const>(&m_data[m_offset]);
return (endianMode == Endian::Big) ? ReverseBytes(value) : value;
}
2020-08-01 01:49:07 +01:00
// Read the next value
// If big endian (the default), will reverse byte order.
template <typename T, Endian endianMode = Endian::Big>
inline T Read()
{
2020-08-01 01:49:07 +01:00
T value = Peek<T, endianMode>();
m_offset += sizeof(T);
return value;
}
// Read bool as 1 byte
template <>
inline bool Read<bool>()
{
// TODO: Could warn on non-bool value
return (ReadByte() != 0x00);
}
2020-08-01 01:49:07 +01:00
// 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++]; }
2020-08-01 05:45:39 +01:00
inline int32_t ReadLength()
{
2020-08-01 05:53:22 +01:00
int32_t length = ReadVarInt(&m_lengthSize);
2020-08-01 05:45:39 +01:00
// HACK: handle Legacy Server List Ping
m_legacy = length == 0xFE && PeekByte() == 0x01;
if (m_legacy)
return 1;
2020-08-01 05:45:39 +01:00
return length;
}
template <typename T = int32_t>
2020-08-01 05:53:22 +01:00
inline T ReadVarInt(uint32_t* outCount = nullptr)
{
2020-08-01 05:53:22 +01:00
uint32_t numRead = 0;
int32_t result = 0;
uint8_t read;
do
{
2020-08-01 01:49:07 +01:00
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);
2020-08-01 05:53:22 +01:00
if (outCount != nullptr)
*outCount = numRead;
return static_cast<T>(result);
}
// can be assigned to string&, string_view
string ReadString()
{
int size = ReadVarInt();
string str;
for (int i = 0; i < size; i++) {
2020-08-01 01:49:07 +01:00
str += ReadByte();
}
return str;
}
inline BlockPos ReadPosition()
{
return BlockPos(Read<int64_t>());
}
uint32_t Length() const { return m_length; }
2020-08-01 05:53:22 +01:00
uint32_t Size() const { return m_length + m_lengthSize; }
bool IsLegacyPing() const { return m_legacy; }
private:
2020-07-28 05:40:47 +01:00
const uint8_t *const m_data;
2020-07-28 05:59:53 +01:00
uint32_t m_offset;
2020-07-28 05:29:02 +01:00
const uint32_t m_length;
2020-08-01 05:53:22 +01:00
uint32_t m_lengthSize;
bool m_legacy;
};
2020-08-01 01:49:07 +01:00
// 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(); }
2020-08-01 00:57:33 +01:00
}