ReGameDLL_CS/regamedll/public/utlbuffer.cpp
2017-11-01 18:30:47 +03:00

414 lines
7.7 KiB
C++

/*
*
* 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 2 of the License, or (at
* your option) 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, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#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;
}
}