mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
355 lines
7.3 KiB
C++
355 lines
7.3 KiB
C++
#pragma once
|
|
|
|
#include <brynet/base/NonCopyable.hpp>
|
|
#include <brynet/base/endian/Endian.hpp>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
class BasePacketWriter : public NonCopyable {
|
|
public:
|
|
BasePacketWriter(char *buffer, size_t len, bool useBigEndian = false, bool isAutoMalloc = false) :
|
|
mIsAutoMalloc(isAutoMalloc), mBigEndian(useBigEndian) {
|
|
mMaxLen = len;
|
|
mPos = 0;
|
|
mBuffer = buffer;
|
|
mMallocBuffer = nullptr;
|
|
}
|
|
|
|
virtual ~BasePacketWriter() {
|
|
if (mMallocBuffer != nullptr) {
|
|
free(mMallocBuffer);
|
|
mMallocBuffer = nullptr;
|
|
}
|
|
}
|
|
|
|
void init() {
|
|
mPos = 0;
|
|
}
|
|
|
|
size_t getMaxLen() const {
|
|
return mMaxLen;
|
|
}
|
|
|
|
size_t getPos() const {
|
|
return mPos;
|
|
}
|
|
|
|
const char *getData() const {
|
|
return mBuffer;
|
|
}
|
|
|
|
bool isAutoGrow() const {
|
|
return mIsAutoMalloc;
|
|
}
|
|
|
|
bool writeBool(bool value) {
|
|
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeINT8(int8_t value) {
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeUINT8(uint8_t value) {
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeINT16(int16_t value) {
|
|
value = hostToNetwork16(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeUINT16(uint16_t value) {
|
|
value = hostToNetwork16(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeINT32(int32_t value) {
|
|
value = hostToNetwork32(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeUINT32(uint32_t value) {
|
|
value = hostToNetwork32(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeINT64(int64_t value) {
|
|
value = hostToNetwork64(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
bool writeUINT64(uint64_t value) {
|
|
value = hostToNetwork64(value, mBigEndian);
|
|
return writeBuffer((char *)&value, sizeof(value));
|
|
}
|
|
|
|
bool writeBinary(const std::string &binary) {
|
|
return writeBuffer(binary.c_str(), binary.size());
|
|
}
|
|
bool writeBinary(const char *binary, size_t binaryLen) {
|
|
return writeBuffer(binary, binaryLen);
|
|
}
|
|
bool writeBuffer(const char *buffer, size_t len) {
|
|
growBuffer(len);
|
|
|
|
if (mMaxLen < (mPos + len)) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(mBuffer + mPos, buffer, len);
|
|
mPos += len;
|
|
return true;
|
|
}
|
|
|
|
BasePacketWriter &operator<<(const bool &v) {
|
|
writeBool(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const uint8_t &v) {
|
|
writeUINT8(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const int8_t &v) {
|
|
writeINT8(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const int16_t &v) {
|
|
writeINT16(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const uint16_t &v) {
|
|
writeUINT16(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const int32_t &v) {
|
|
writeINT32(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const uint32_t &v) {
|
|
writeUINT32(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const int64_t &v) {
|
|
writeINT64(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const uint64_t &v) {
|
|
writeUINT64(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const char *const &v) {
|
|
writeBinary(v);
|
|
return *this;
|
|
}
|
|
BasePacketWriter &operator<<(const std::string &v) {
|
|
writeBinary(v);
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
// 为了避免直接<<导致没有指定字节序导致隐藏BUG,因为此函数设置为私有
|
|
template <typename T>
|
|
BasePacketWriter &operator<<(const T &v) {
|
|
static_assert(!std::is_pointer<T>::value, "T must is't a pointer");
|
|
static_assert(std::is_class<T>::value, "T must a class or struct type");
|
|
static_assert(std::is_pod<T>::value, "T must a pod type");
|
|
writeBuffer((const char *)&v, sizeof(v));
|
|
return *this;
|
|
}
|
|
|
|
template <typename Arg1, typename... Args>
|
|
void writev(const Arg1 &arg1, const Args &...args) {
|
|
this->operator<<(arg1);
|
|
writev(args...);
|
|
}
|
|
|
|
void writev() {
|
|
}
|
|
|
|
protected:
|
|
void growBuffer(size_t len) {
|
|
if (!mIsAutoMalloc || (mPos + len) <= mMaxLen) {
|
|
return;
|
|
}
|
|
|
|
auto newBuffer = (char *)malloc(mMaxLen + len);
|
|
if (newBuffer == nullptr) {
|
|
return;
|
|
}
|
|
|
|
memcpy(newBuffer, mBuffer, mPos);
|
|
|
|
if (mMallocBuffer != nullptr) {
|
|
free(mMallocBuffer);
|
|
mMallocBuffer = nullptr;
|
|
}
|
|
|
|
mMaxLen += len;
|
|
mMallocBuffer = newBuffer;
|
|
mBuffer = newBuffer;
|
|
}
|
|
|
|
protected:
|
|
const bool mIsAutoMalloc;
|
|
bool mBigEndian;
|
|
size_t mPos;
|
|
size_t mMaxLen;
|
|
char *mBuffer;
|
|
char *mMallocBuffer;
|
|
};
|
|
|
|
class BasePacketReader {
|
|
public:
|
|
BasePacketReader(const char *buffer,
|
|
size_t len,
|
|
bool useBigEndian = false) :
|
|
mBigEndian(useBigEndian),
|
|
mSize(len) {
|
|
mPos = 0;
|
|
mSavedPos = 0;
|
|
mBuffer = buffer;
|
|
}
|
|
|
|
virtual ~BasePacketReader() = default;
|
|
|
|
void useBigEndian() {
|
|
mBigEndian = true;
|
|
}
|
|
|
|
void useLittleEndian() {
|
|
mBigEndian = false;
|
|
}
|
|
|
|
void savePos() {
|
|
mSavedPos = mPos;
|
|
}
|
|
|
|
size_t savedPos() const {
|
|
return mSavedPos;
|
|
}
|
|
|
|
size_t getLeft() const {
|
|
if (mPos > mSize) {
|
|
throw std::out_of_range("current pos is greater than max len");
|
|
}
|
|
return mSize - mPos;
|
|
}
|
|
|
|
bool enough(size_t len) const {
|
|
if (mPos > mSize) {
|
|
return false;
|
|
}
|
|
return (mSize - mPos) >= len;
|
|
}
|
|
|
|
const char *begin() const {
|
|
return mBuffer;
|
|
}
|
|
|
|
const char *currentBuffer() const {
|
|
return mBuffer + mPos;
|
|
}
|
|
|
|
void consumeAll() {
|
|
mPos = mSize;
|
|
savePos();
|
|
}
|
|
|
|
size_t currentPos() const {
|
|
return mPos;
|
|
}
|
|
|
|
size_t size() const {
|
|
return mSize;
|
|
}
|
|
|
|
void addPos(size_t diff) {
|
|
const auto tmpPos = mPos + diff;
|
|
if (tmpPos > mSize) {
|
|
throw std::out_of_range("diff is to big");
|
|
}
|
|
|
|
mPos = tmpPos;
|
|
}
|
|
|
|
bool readBool() {
|
|
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
|
bool value = false;
|
|
read(value);
|
|
return value;
|
|
}
|
|
int8_t readINT8() {
|
|
int8_t value = 0;
|
|
read(value);
|
|
return value;
|
|
}
|
|
uint8_t readUINT8() {
|
|
uint8_t value = 0;
|
|
read(value);
|
|
return value;
|
|
}
|
|
int16_t readINT16() {
|
|
int16_t value = 0;
|
|
read(value);
|
|
return networkToHost16(value, mBigEndian);
|
|
}
|
|
uint16_t readUINT16() {
|
|
uint16_t value = 0;
|
|
read(value);
|
|
return networkToHost16(value, mBigEndian);
|
|
}
|
|
int32_t readINT32() {
|
|
int32_t value = 0;
|
|
read(value);
|
|
return networkToHost32(value, mBigEndian);
|
|
}
|
|
uint32_t readUINT32() {
|
|
uint32_t value = 0;
|
|
read(value);
|
|
return networkToHost32(value, mBigEndian);
|
|
}
|
|
int64_t readINT64() {
|
|
int64_t value = 0;
|
|
read(value);
|
|
return networkToHost64(value, mBigEndian);
|
|
}
|
|
uint64_t readUINT64() {
|
|
uint64_t value = 0;
|
|
read(value);
|
|
return networkToHost64(value, mBigEndian);
|
|
}
|
|
|
|
private:
|
|
// 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有
|
|
template <typename T>
|
|
void read(T &value) {
|
|
static_assert(std::is_same<T, typename std::remove_pointer<T>::type>::value,
|
|
"T must a normal type");
|
|
static_assert(std::is_pod<T>::value,
|
|
"T must a pod type");
|
|
|
|
if ((mPos + sizeof(value)) > mSize) {
|
|
throw std::out_of_range("T size is to big");
|
|
}
|
|
|
|
value = *(T *)(mBuffer + mPos);
|
|
mPos += sizeof(value);
|
|
}
|
|
|
|
protected:
|
|
bool mBigEndian;
|
|
const size_t mSize;
|
|
const char *mBuffer;
|
|
size_t mPos;
|
|
size_t mSavedPos;
|
|
};
|
|
|
|
template <size_t SIZE>
|
|
class AutoMallocPacket : public BasePacketWriter {
|
|
public:
|
|
explicit AutoMallocPacket(bool useBigEndian = false,
|
|
bool isAutoMalloc = false) :
|
|
BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc) {}
|
|
|
|
private:
|
|
char mData[SIZE];
|
|
};
|
|
|
|
using BigPacket = AutoMallocPacket<32 * 1024>;
|