ReGameDLL_CS/regamedll/public/utlbuffer.cpp
2015-06-30 15:46:07 +06:00

426 lines
8.7 KiB
C++

//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// $Header: $
// $NoKeywords: $
//
// Serialization buffer
//=============================================================================
#include "precompiled.h"
#include <stdio.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
//-----------------------------------------------------------------------------
// constructors
//-----------------------------------------------------------------------------
CUtlBuffer::CUtlBuffer(int growSize, int initSize, bool text) :
m_Memory(growSize, initSize), m_Error(0)
{
m_Get = 0;
m_Put = 0;
m_Flags = 0;
if (text)
{
m_Flags |= TEXT_BUFFER;
}
}
CUtlBuffer::CUtlBuffer(void const* pBuffer, int size, bool text) :
m_Memory((unsigned char*)pBuffer, size), m_Error(0)
{
m_Get = 0;
m_Put = 0;
m_Flags = 0;
if (text)
m_Flags |= TEXT_BUFFER;
}
//-----------------------------------------------------------------------------
// Attaches the buffer to external memory....
//-----------------------------------------------------------------------------
void CUtlBuffer::SetExternalBuffer(void* pMemory, int numElements, bool text)
{
m_Memory.SetExternalBuffer((unsigned char*)pMemory, numElements);
// Reset all indices; we just changed memory
m_Get = 0;
m_Put = 0;
m_Flags = 0;
if (text)
m_Flags |= TEXT_BUFFER;
}
//-----------------------------------------------------------------------------
// Makes sure we've got at least this much memory
//-----------------------------------------------------------------------------
void CUtlBuffer::EnsureCapacity(int num)
{
m_Memory.EnsureCapacity(num);
}
//-----------------------------------------------------------------------------
// Base get method from which all others derive
//-----------------------------------------------------------------------------
void CUtlBuffer::Get(void* pMem, int size)
{
Assert(m_Get + size <= m_Memory.NumAllocated());
memcpy(pMem, &m_Memory[m_Get], size);
m_Get += size;
}
//-----------------------------------------------------------------------------
// Eats whitespace
//-----------------------------------------------------------------------------
void CUtlBuffer::EatWhiteSpace()
{
if (IsText() && IsValid())
{
int lastpos = Size();
while (m_Get < lastpos)
{
if (!isspace(*(char*)&m_Memory[m_Get]))
break;
m_Get += sizeof(char);
}
}
}
//-----------------------------------------------------------------------------
// Reads a null-terminated string
//-----------------------------------------------------------------------------
void CUtlBuffer::GetString(char* pString, int nMaxLen)
{
if (!IsValid())
{
*pString = 0;
return;
}
if (nMaxLen == 0)
{
nMaxLen = INT_MAX;
}
if (!IsText())
{
int len = strlen((char*)&m_Memory[m_Get]) + 1;
if (len <= nMaxLen)
{
Get(pString, len);
}
else
{
Get(pString, nMaxLen);
pString[nMaxLen - 1] = 0;
SeekGet(SEEK_CURRENT, len - nMaxLen);
}
}
else
{
// eat all whitespace
EatWhiteSpace();
// Eat characters
int nCount = 0;
int nLastPos = Size();
while (m_Get < nLastPos)
{
char c = *(char*)&m_Memory[m_Get];
if (isspace(c) || (!c))
break;
if (nCount < nMaxLen - 1)
{
*pString++ = c;
}
++nCount;
++m_Get;
}
// Terminate
*pString = 0;
}
}
//-----------------------------------------------------------------------------
// Checks if a get is ok
//-----------------------------------------------------------------------------
bool CUtlBuffer::CheckGet(int size)
{
if (m_Error)
return false;
if (m_Memory.NumAllocated() >= m_Get + size)
return true;
m_Error |= GET_OVERFLOW;
return false;
}
//-----------------------------------------------------------------------------
// Change where I'm reading
//-----------------------------------------------------------------------------
void CUtlBuffer::SeekGet(SeekType_t type, int offset)
{
switch (type)
{
case SEEK_HEAD:
m_Get = offset;
break;
case SEEK_CURRENT:
m_Get += offset;
break;
case SEEK_TAIL:
m_Get = m_Memory.NumAllocated() - offset;
break;
}
}
//-----------------------------------------------------------------------------
// Parse...
//-----------------------------------------------------------------------------
#pragma warning ( disable : 4706 )
int CUtlBuffer::VaScanf(char const* pFmt, va_list list)
{
Assert(pFmt);
if (m_Error || !IsText())
return 0;
int numScanned = 0;
char c;
char* pEnd;
while (c = *pFmt++)
{
// Stop if we hit the end of the buffer
if (m_Get >= Size())
{
m_Error |= GET_OVERFLOW;
break;
}
switch (c)
{
case ' ':
// eat all whitespace
EatWhiteSpace();
break;
case '%':
{
// Conversion character... try to convert baby!
char type = *pFmt++;
if (type == 0)
return numScanned;
switch (type)
{
case 'c':
{
char* ch = va_arg(list, char *);
*ch = (char)m_Memory[m_Get];
++m_Get;
}
break;
case 'i':
case 'd':
{
int* i = va_arg(list, int *);
*i = strtol((char*)PeekGet(), &pEnd, 10);
if (pEnd == PeekGet())
return numScanned;
m_Get = (int)pEnd - (int)Base();
}
break;
case 'x':
{
int* i = va_arg(list, int *);
*i = strtol((char*)PeekGet(), &pEnd, 16);
if (pEnd == PeekGet())
return numScanned;
m_Get = (int)pEnd - (int)Base();
}
break;
case 'u':
{
unsigned int* u = va_arg(list, unsigned int *);
*u = strtoul((char*)PeekGet(), &pEnd, 10);
if (pEnd == PeekGet())
return numScanned;
m_Get = (int)pEnd - (int)Base();
}
break;
case 'f':
{
float* f = va_arg(list, float *);
*f = (float)strtod((char*)PeekGet(), &pEnd);
if (pEnd == PeekGet())
return numScanned;
m_Get = (int)pEnd - (int)Base();
}
break;
case 's':
{
char* s = va_arg(list, char *);
GetString(s);
}
break;
default:
{
// unimplemented scanf type
Assert(0);
return numScanned;
}
break;
}
++numScanned;
}
break;
default:
{
// Here we have to match the format string character
// against what's in the buffer or we're done.
if (c != m_Memory[m_Get])
return numScanned;
++m_Get;
}
}
}
return numScanned;
}
#pragma warning ( default : 4706 )
int CUtlBuffer::Scanf(char const* pFmt, ...)
{
va_list args;
va_start(args, pFmt);
int count = VaScanf(pFmt, args);
va_end(args);
return count;
}
//-----------------------------------------------------------------------------
// Serialization
//-----------------------------------------------------------------------------
void CUtlBuffer::Put(void const* pMem, int size)
{
if (CheckPut(size))
{
memcpy(&m_Memory[m_Put], pMem, size);
m_Put += size;
}
}
//-----------------------------------------------------------------------------
// Writes a null-terminated string
//-----------------------------------------------------------------------------
void CUtlBuffer::PutString(char const* pString)
{
int len = strlen(pString);
// Not text? append a null at the end.
if (!IsText())
++len;
Put(pString, len);
}
void CUtlBuffer::VaPrintf(char const* pFmt, va_list list)
{
char temp[2048];
int len = vsprintf(temp, pFmt, list);
Assert(len < 2048);
// Not text? append a null at the end.
if (!IsText())
++len;
Put(temp, len);
}
void CUtlBuffer::Printf(char const* pFmt, ...)
{
va_list args;
va_start(args, pFmt);
VaPrintf(pFmt, args);
va_end(args);
}
//-----------------------------------------------------------------------------
// Checks if a put is ok
//-----------------------------------------------------------------------------
bool CUtlBuffer::CheckPut(int size)
{
if (m_Error)
return false;
while (m_Memory.NumAllocated() < m_Put + size)
{
if (m_Memory.IsExternallyAllocated())
{
m_Error |= PUT_OVERFLOW;
return false;
}
m_Memory.Grow();
}
return true;
}
void CUtlBuffer::SeekPut(SeekType_t type, int offset)
{
switch (type)
{
case SEEK_HEAD:
m_Put = offset;
break;
case SEEK_CURRENT:
m_Put += offset;
break;
case SEEK_TAIL:
m_Put = m_Memory.NumAllocated() - offset;
break;
}
}