Files
mir_server/sdk/srvlib/include/DataPacket.hpp
aixianling 5c9f1dae4a init
2025-01-09 17:45:40 +08:00

309 lines
8.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
/************************************************************************
基于内存的数据包读写类
实现方式与MemoryStream相同写入数据的时候写入到内存中如果写入数据的空间超出现有
内存块长度则会自动增长内存。
数据包的内存申请时通过内存池对象CBufferAllocator进行的以使用更有效率的内存管理。
★数据包中的字符串
数据包含有一种字符串读写机制包括ANSI字符串以及UNICODE16字符串。将一个字符串写入
到数据包后其内存结构为:
[2字节字符长度数据][字符串字节数据字符串长度在65536以内][字符串终止字符0]
************************************************************************/
#include "ObjectCounter.h"
#include "DataPacketReader.hpp"
class CDataPacket : public CDataPacketReader, public Counter<CDataPacket>
{
public:
/* 写入二进制数据
* lpBuffer 指向二进制数据内存的指针
* dwSize 数据的字节长度
*/
inline void writeBuf(LPCVOID lpBuffer, size_t dwSize)
{
size_t dwMemSize = m_pMemoryEnd - m_pOffset;
if ( dwMemSize < dwSize )
{
setSize(m_pMemoryEnd - m_pMemory + dwSize);
}
memcpy(m_pOffset, lpBuffer, dwSize);
m_pOffset += dwSize;
//如果读写指针超过长度指针的位置,则调整长度指针为读写指针的位置
if ( m_pOffset > m_pDataEnd )
m_pDataEnd = m_pOffset;
}
/* 写入原子类型数据
* bool,char,short,int,__int64,float,double,void*这些数据类型为原子类型
*/
template <typename T>
inline void writeAtom(T data)
{
size_t dwMemSize = m_pMemoryEnd - m_pOffset;
if ( dwMemSize < sizeof(data) )
{
setSize(m_pMemoryEnd - m_pMemory + sizeof(data));
}
*(T*)m_pOffset = data;
m_pOffset += sizeof(data);
//如果读写指针超过长度指针的位置,则调整长度指针为读写指针的位置
if ( m_pOffset > m_pDataEnd )
m_pDataEnd = m_pOffset;
}
inline void writeString(const char *str, size_t len = -1)
{
rawWriteStringLen<unsigned short>(str, len);
}
/* 写入UNICODE16字符串数据字符串长度必须在65536以内超过65535的部分将不会被写入
* 在字符串之前写入两个字节的字符串长度,且会再字符串末尾写入终止字符
* len 如果值为-1则自动计算str的长度
*/
inline void writeWideString(const wchar_t *str, size_t len = -1)
{
rawWriteWideStringLen<unsigned short>(str, len);
}
public:
/* 设置数据包的数据长度
* 如果设置的长度比当前长度小且读写偏移指针超过新的长度,则会将读写偏移指针调整到与新长度一致
* 如果新的长度比当前的长度要则会自动扩展内存块大小
*/
inline void setLength(size_t newLength)
{
if ( newLength > (size_t)(m_pMemoryEnd - m_pMemory) )
setSize(newLength);
m_pDataEnd = m_pMemory + newLength;
//如果调整数据长度后偏移位置超出长度位置,则调整偏移位置为长度位置
if ( m_pOffset > m_pDataEnd )
m_pOffset = m_pDataEnd;
}
/* 设置数据包当前读写位置字节偏移量,
* 如果新的偏移量比当前内存块长度要大则函数会与setLength一样进行内存块的扩展操作
*/
inline size_t setPosition(size_t newPos)
{
size_t dwMemSize = m_pMemoryEnd - m_pMemory;
if ( newPos > dwMemSize )
setSize(newPos);
m_pOffset = m_pMemory + newPos;
//如果读写指针超过长度指针的位置,则调整长度指针为读写指针的位置
if ( m_pOffset > m_pDataEnd )
m_pDataEnd = m_pOffset;
return newPos;
}
/* 基于当前读写指针偏移位置调整偏移量
* nOffsetToAdjust 要调整的偏移量大小,负数则表示向内存开始处调整(降低偏移)
* 函数内会限制调整后的偏移位置必须大于等于内存开头,
* 如果调整后的便宜超过现有内存长度,则会自动增长内存到欲求调整的位置
*/
inline size_t adjustOffset(INT64 nOffsetToAdjust)
{
m_pOffset += nOffsetToAdjust;
if ( m_pOffset < m_pMemory )
m_pOffset = m_pMemory;
else if ( m_pOffset > m_pMemoryEnd )
setSize(m_pOffset - m_pMemory);
if ( m_pOffset > m_pDataEnd )
m_pDataEnd = m_pOffset;
return m_pOffset - m_pMemory;
}
/*
* 扩展内存缓存区长度
*/
inline size_t reserve(size_t nSize)
{
size_t Result = m_pMemoryEnd - m_pMemory;
if ( Result < nSize )
setSize(nSize);
return Result;
}
/*
* 获取当前缓冲长度下的可用字节数
*/
inline size_t getAvaliableCapacity()
{
return m_pMemoryEnd - m_pOffset;
}
//获取当前占有的内存的物理长度
inline size_t getMemorySize()
{
return m_pMemoryEnd - m_pMemory;
}
public:
/*
* Comment: 适用于在通过开启预定义宏_DPPACK_MEM_CHK_的情况下对数据包进行内存越界检查
* @Return void:
*/
inline void _Assert()
{
#ifdef _DPPACK_MEM_CHK_
DbgAssert(!m_pMemoryEnd || *(PINT)m_pMemoryEnd == 0xCCDDCCEE);
#endif
}
/*
* 检查引用赋值
*/
inline CDataPacket& operator = (const CDataPacket& an)
{
//禁止引用赋值!
#ifdef WIN32
Assert(false);
#else
return *this;
#endif
}
public:
/* 写入原子数据的运算符重载 */
template <typename T>
inline CDataPacket& operator << (T val)
{
if ( sizeof(val) <= sizeof(INT_PTR) )
writeAtom<T>(val);
else writeBuf(&val, sizeof(val));
return *this;
}
inline CDataPacket& operator << (const char* val)
{
writeString(val, strlen(val));
return *this;
}
inline CDataPacket& operator << (char* val)
{
writeString(val, strlen(val));
return *this;
}
inline CDataPacket& operator << (const wchar_t* val)
{
#ifdef WIN32
writeWideString(val, wcslen(val));
#endif
return *this;
}
inline CDataPacket& operator << (wchar_t* val)
{
#ifdef WIN32
writeWideString(val, wcslen(val));
#endif
return *this;
}
public:
typedef CDataPacketReader Inherited;
CDataPacket()
:Inherited()
{
m_pAllocator = NULL;
}
CDataPacket(const CDataPacket &another)
{
//为了防止将引用赋值给一个对象,此处禁止从另一个对象中构造
#ifdef WIN32
Assert(FALSE);
#else
//return *this;
#endif
}
CDataPacket(LPCVOID lpDataPtr, size_t dwSize)
:Inherited(lpDataPtr, dwSize)
{
m_pDataEnd = m_pMemory;
m_pAllocator = NULL;
}
CDataPacket(CBufferAllocator *pAllocator)
:Inherited()
{
m_pAllocator = pAllocator;
}
~CDataPacket()
{
if ( m_pMemory && m_pAllocator )
{
m_pAllocator->FreeBuffer(m_pMemory);
m_pMemory = m_pMemoryEnd = m_pOffset = m_pDataEnd = NULL;
}
}
// 设置分配器
inline void setAllocator(CBufferAllocator *pAllocator) { m_pAllocator = pAllocator; }
protected:
/* 重新设定数据包内存空间大小 */
void setSize(size_t dwNewSize)
{
char *pOldMemory = m_pMemory;
//内存长度按CDataPacket::MemoryAlginmentSize字节对齐
//数据长度增加4字节用于增加0终止以便进行字符串的结尾调试
dwNewSize = (dwNewSize + MemoryAlginmentSize) & (~(MemoryAlginmentSize - 1));
#ifdef _DPPACK_MEM_CHK_
char *pMemory = (char*)m_pAllocator->AllocBuffer(dwNewSize + sizeof(INT));
#else
char *pMemory = (char*)m_pAllocator->AllocBuffer(dwNewSize);
#endif
size_t dwOffset = m_pOffset - m_pMemory;
size_t dwLength = m_pDataEnd - m_pMemory;
if ( dwLength > 0 )
{
memcpy(pMemory, m_pMemory, __min(dwNewSize, dwLength));
}
//重设数据指针
m_pMemory = pMemory;
m_pMemoryEnd = m_pMemory + dwNewSize;
#ifdef _DPPACK_MEM_CHK_
*(PINT)m_pMemoryEnd = 0xCCDDCCEE;
#endif
m_pOffset = m_pMemory + dwOffset;
m_pDataEnd = m_pMemory + dwLength;
//销毁原有数据内存
if ( pOldMemory )
{
_Assert();
m_pAllocator->FreeBuffer(pOldMemory);
}
}
/* 写入ANSI短字符串以及字符串数据
* 字符串的数据格式为:[2字节字符长度数据][字符串字节数据字符串长度在65536以内][字符串终止字符0]字符串中超过索引65535后的部分将被忽略
* 在字符串之前写入sizeof(TL)字节的长度值,且会再字符串末尾写入终止字符
* <TL> 定义字符串长度描述数据的数据类型对于短字符串应当为unsigned char否则即是unsigned short
* len 如果值为-1则自动计算str的长度
*/
template <typename TL>
void rawWriteStringLen(const char* str, size_t len)
{
if ( len == -1 )
len = str?(TL)strlen(str):0;
writeAtom<TL>((TL)len);//写入长度
writeBuf(str, len * sizeof(*str));
writeAtom<char>(0);//写入终止字符
}
/* 写入UNICODE16短字符串以及字符串数据
* 规则与rawWriteLengthString相同
*/
template <typename TL>
void rawWriteWideStringLen(const wchar_t* str, size_t len)
{
#ifdef WIN32
if ( len == -1 )
len = str?(TL)wcslen(str):0;
writeAtom<TL>((TL)len);//写入长度
writeBuf(str, len * sizeof(*str));
writeAtom<wchar_t>(0);//写入终止字符
#endif
}
protected:
CBufferAllocator *m_pAllocator; //内存申请器
private:
static const size_t MemoryAlginmentSize = 256; //数据包内存长度对齐边界
};