2020-07-28 00:07:18 +01:00
|
|
|
#pragma once
|
|
|
|
|
2020-07-31 02:53:40 +01:00
|
|
|
#include "Common.h"
|
2020-08-01 01:49:07 +01:00
|
|
|
#include "util/ByteUtil.h"
|
2020-07-28 05:45:03 +01:00
|
|
|
|
2020-07-28 00:07:18 +01:00
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdint>
|
2020-07-28 05:45:03 +01:00
|
|
|
#include <string>
|
|
|
|
|
|
|
|
using std::string;
|
2020-07-28 00:07:18 +01:00
|
|
|
|
2020-07-31 02:53:40 +01:00
|
|
|
namespace Feather
|
2020-07-28 00:07:18 +01:00
|
|
|
{
|
|
|
|
// 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-07-28 00:07:18 +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>
|
2020-07-31 02:53:40 +01:00
|
|
|
inline T Peek()
|
|
|
|
{
|
2020-08-01 01:49:07 +01:00
|
|
|
T value = *reinterpret_cast<const T *const>(&m_data[m_offset]);
|
|
|
|
|
2020-08-03 06:07:32 +01:00
|
|
|
return (endianMode == Endian::Big) ? ReverseBytes(value) : value;
|
2020-07-31 02:53:40 +01:00
|
|
|
}
|
|
|
|
|
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>
|
2020-07-28 05:51:42 +01:00
|
|
|
inline T Read()
|
2020-07-28 00:07:18 +01:00
|
|
|
{
|
2020-08-01 01:49:07 +01:00
|
|
|
T value = Peek<T, endianMode>();
|
2020-07-28 05:51:42 +01:00
|
|
|
m_offset += sizeof(T);
|
|
|
|
return value;
|
2020-07-28 00:07:18 +01:00
|
|
|
}
|
|
|
|
|
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
|
2020-08-03 06:07:32 +01:00
|
|
|
m_legacy = length == 0xFE && PeekByte() == 0x01;
|
|
|
|
if (m_legacy)
|
|
|
|
return 1;
|
2020-08-01 05:45:39 +01:00
|
|
|
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
2020-07-31 02:53:40 +01:00
|
|
|
template <typename T = int32_t>
|
2020-08-01 05:53:22 +01:00
|
|
|
inline T ReadVarInt(uint32_t* outCount = nullptr)
|
2020-07-28 00:07:18 +01:00
|
|
|
{
|
2020-08-01 05:53:22 +01:00
|
|
|
uint32_t numRead = 0;
|
2020-07-31 02:53:40 +01:00
|
|
|
int32_t result = 0;
|
2020-07-28 00:07:18 +01:00
|
|
|
uint8_t read;
|
|
|
|
do
|
|
|
|
{
|
2020-08-01 01:49:07 +01:00
|
|
|
read = ReadByte();
|
2020-07-28 00:07:18 +01:00
|
|
|
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;
|
|
|
|
|
2020-07-31 02:53:40 +01:00
|
|
|
return static_cast<T>(result);
|
2020-07-28 00:07:18 +01:00
|
|
|
}
|
|
|
|
|
2020-07-28 05:45:03 +01:00
|
|
|
string ReadString()
|
|
|
|
{
|
|
|
|
int size = ReadVarInt();
|
|
|
|
string str;
|
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) {
|
2020-08-01 01:49:07 +01:00
|
|
|
str += ReadByte();
|
2020-07-28 05:45:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Length() const { return m_length; }
|
2020-08-01 05:53:22 +01:00
|
|
|
uint32_t Size() const { return m_length + m_lengthSize; }
|
2020-08-03 06:07:32 +01:00
|
|
|
|
|
|
|
bool IsLegacyPing() const { return m_legacy; }
|
|
|
|
|
2020-07-28 00:07:18 +01:00
|
|
|
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;
|
2020-08-03 06:07:32 +01:00
|
|
|
bool m_legacy;
|
2020-07-28 00:07:18 +01:00
|
|
|
};
|
|
|
|
|
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
|
|
|
}
|