/*
* Ascent MMORPG Server
* Copyright (C) 2005-2007 Ascent Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef _STACKBUFFER_H
#define _STACKBUFFER_H
#include "Common.h"
#include "WoWGuid.h"
#include "LocationVector.h"
/* This is needed because of template gayness. */
class SERVER_DECL StackBufferBase
{
public:
virtual ~StackBufferBase() {}
virtual uint8 * GetBufferPointer() = 0;
virtual uint16 GetOpcode() { return 0; }
virtual uint32 GetSize() = 0;
};
template
class SERVER_DECL StackBuffer : public StackBufferBase
{
protected:
uint8 m_stackBuffer[Size];
uint32 m_readPos;
uint32 m_writePos;
uint8 * m_bufferPointer;
uint8 * m_heapBuffer;
uint32 m_space;
public:
/** Constructor, sets buffer pointers and zeros write/read positions.
*/
StackBuffer() : m_readPos(0), m_writePos(0), m_bufferPointer(&m_stackBuffer[0]), m_heapBuffer(0), m_space(Size) {}
/** Destructor, frees heap buffer if it exists
*/
~StackBuffer() { if(m_heapBuffer) free(m_heapBuffer); }
/** Re-allocates the buffer on the heap. This allows it to expand past the original specified size.
* This is only a failsafe and should be avoided at all costs, as it is quite heavy.
*/
void ReallocateOnHeap()
{
if(m_heapBuffer) // Reallocate with 200 bytes larger size
m_heapBuffer = (uint8*)realloc(m_heapBuffer, 200);
else
{
m_heapBuffer = (uint8*)malloc(m_space + 200);
memcpy(m_heapBuffer, m_stackBuffer, m_writePos);
m_space += 200;
m_bufferPointer = m_heapBuffer;
}
}
/** Gets the buffer pointer
* @return the buffer pointer
*/
uint8 * GetBufferPointer() { return m_bufferPointer; }
/** Gets the buffer size.
*/
uint32 GetBufferSize() { return m_writePos; }
/** Reads sizeof(T) bytes from the buffer
* @return the bytes read
*/
template
T Read()
{
if(m_readPos + sizeof(T) <= m_writePos)
return (T)0;
T ret = *(T*)&m_bufferPointer[m_readPos];
m_readPos += sizeof(T);
return ret;
}
/** Writes sizeof(T) bytes to the buffer, while checking for overflows.
* @param T data The data to be written
*/
template
void Write(T data)
{
if(m_writePos + sizeof(T) > m_space)
{
// Whoooops. We have to reallocate on the heap.
ReallocateOnHeap();
}
*(T*)&m_bufferPointer[m_writePos] = data;
m_writePos += sizeof(T);
}
/** writes x bytes to the buffer, while checking for overflows
* @param ptr the data to be written
* @param size byte count
*/
void Write(uint8 * data, size_t size)
{
if(m_writePos + size > m_space)
ReallocateOnHeap();
memcpy(&m_bufferPointer[m_writePos], data, size);
m_writePos += size;
}
/** Ensures the buffer is big enough to fit the specified number of bytes.
* @param bytes number of bytes to fit
*/
inline void EnsureBufferSize(uint32 Bytes)
{
if(m_writePos + Bytes > m_space)
ReallocateOnHeap();
}
/** These are the default read/write operators.
*/
#define DEFINE_BUFFER_READ_OPERATOR(type) void operator >> (type& dest) { dest = Read(); }
#define DEFINE_BUFFER_WRITE_OPERATOR(type) void operator << (type src) { Write(src); }
/** Fast read/write operators without using the templated read/write functions.
*/
#define DEFINE_FAST_READ_OPERATOR(type, size) StackBuffer& operator >> (type& dest) { if(m_readPos + size > m_writePos) { dest = (type)0; } else { dest = *(type*)&m_bufferPointer[m_readPos]; m_readPos += size; return *this; } }
#define DEFINE_FAST_WRITE_OPERATOR(type, size) StackBuffer& operator << (type src) { if(m_writePos + size > m_space) { ReallocateOnHeap(); } *(type*)&m_bufferPointer[m_writePos] = src; m_writePos += size; return *this; }
/** Integer/float r/w operators
*/
DEFINE_FAST_READ_OPERATOR(uint64, 8);
DEFINE_FAST_READ_OPERATOR(uint32, 4);
DEFINE_FAST_READ_OPERATOR(uint16, 2);
DEFINE_FAST_READ_OPERATOR(uint8, 1);
DEFINE_FAST_READ_OPERATOR(float, 4);
DEFINE_FAST_READ_OPERATOR(double, 8);
DEFINE_FAST_WRITE_OPERATOR(uint64, 8);
DEFINE_FAST_WRITE_OPERATOR(uint32, 4);
DEFINE_FAST_WRITE_OPERATOR(uint16, 2);
DEFINE_FAST_WRITE_OPERATOR(uint8, 1);
DEFINE_FAST_WRITE_OPERATOR(float, 4);
DEFINE_FAST_WRITE_OPERATOR(double, 8);
/** boolean (1-byte) read/write operators
*/
DEFINE_FAST_WRITE_OPERATOR(bool, 1);
StackBuffer& operator >> (bool & dst) { dst = (Read() > 0 ? true : false); return *this; }
/** string (null-terminated) operators
*/
StackBuffer& operator << (std::string & value) { EnsureBufferSize(value.length() + 1); memcpy(&m_bufferPointer[m_writePos], value.c_str(), value.length()+1); m_writePos += (value.length() + 1); return *this; }
StackBuffer& operator >> (std::string & dest)
{
dest.clear();
char c;
for(;;)
{
c = Read();
if(c == 0) break;
dest += c;
}
return *this;
}
/** WoWGuid read/write operators
*/
StackBuffer& operator << (const WoWGuid & value)
{
EnsureBufferSize(value.GetNewGuidLen() + 1);
Write(value.GetNewGuidMask());
memcpy(&m_bufferPointer[m_writePos], value.GetNewGuid(), value.GetNewGuidLen());
m_writePos += value.GetNewGuidLen();
return *this;
}
StackBuffer& operator >> (WoWGuid & value)
{
uint8 mask = Read();
value.Init(mask);
for(uint32 i = 0; i < BitCount8(mask); ++i)
value.AppendField(Read());
return *this;
}
/** LocationVector read/write operators
*/
StackBuffer& operator << (LocationVector & val)
{
// espire: I would've done this as one memcpy.. but we don't know how the struct alignment is gonna come out :/
Write(val.x);
Write(val.y);
Write(val.z);
return *this;
}
StackBuffer& operator >> (LocationVector & dst)
{
dst.x = Read();
dst.y = Read();
dst.z = Read();
return *this;
}
/** Clears the buffer
*/
void Clear() { m_writePos = m_readPos = 0; }
/** Gets the write position
* @return buffer size
*/
uint32 GetSize() { return m_writePos; }
};
#endif