kolibrios/contrib/games/opentyrian/src/sizebuf.c
turbocat a27452493c OpenTyrian: Sources uploaded
git-svn-id: svn://kolibrios.org@9169 a494cfbc-eb01-0410-851d-a64ba20cac60
2021-08-31 18:22:39 +00:00

225 lines
5.3 KiB
C

/*
* OpenTyrian: A modern cross-platform port of Tyrian
* Copyright (C) 2007-2009 The OpenTyrian Development 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* This file is largely based on (and named after) a set of common reading/
* writing functions used in Quake engines. Its purpose is to allow extraction
* of bytes, words, and dwords in a safe, endian adjused environment and should
* probably be used in any situation where checking for buffer overflows
* manually makes the code a godawful mess.
*
* Currently this is only used by the animation decoding.
*
* This file is written with the intention of being easily converted into a
* class capable of throwing exceptions if data is out of range.
*
* If an operation fails, subsequent operations will also fail. The sizebuf
* is assumed to be in an invalid state. This COULD be changed pretty easily
* and in normal Quake IIRC it is. But our MO is to bail on failure, not
* figure out what went wrong (making throws perfect).
*/
#include "sizebuf.h"
#include "SDL_endian.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
/* Construct buffer with the passed array and size */
void SZ_Init(sizebuf_t * sz, Uint8 * buf, unsigned int size)
{
sz->data = buf;
sz->bufferLen = size;
sz->bufferPos = 0;
sz->error = false;
}
/* Check error flags */
bool SZ_Error(sizebuf_t * sz)
{
return(sz->error);
}
/* mimic memset */
void SZ_Memset(sizebuf_t * sz, int value, size_t count)
{
/* Do bounds checking before writing */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
/* Memset and increment pointer */
memset(sz->data + sz->bufferPos, value, count);
sz->bufferPos += count;
}
/* Mimic memcpy. Two versions, one for buffers, one for sizebuf objects.
* Overload in C++. */
void SZ_Memcpy(sizebuf_t * sz, const Uint8 * buf, size_t count)
{
/* State checking */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
/* Memcpy & increment */
memcpy(sz->data + sz->bufferPos, buf, count);
sz->bufferPos += count;
}
void SZ_Memcpy2(sizebuf_t * sz, sizebuf_t * bf, size_t count)
{
/* State checking */
if (sz->error || sz->bufferPos + count > sz->bufferLen)
{
sz->error = true;
return;
}
if (bf->error || bf->bufferPos + count > bf->bufferLen)
{
bf->error = true;
return;
}
/* Memcpy & increment */
memcpy(sz->data + sz->bufferPos, bf->data + bf->bufferPos, count);
sz->bufferPos += count;
bf->bufferPos += count;
}
/* Reposition buffer pointer */
void SZ_Seek(sizebuf_t * sz, long count, int mode)
{
/* Okay, it's reasonable to reset the error bool on seeking... */
switch(mode)
{
case SEEK_SET:
sz->bufferPos = count;
break;
case SEEK_CUR:
sz->bufferPos += count;
break;
case SEEK_END:
sz->bufferPos = sz->bufferLen - count;
break;
default:
assert(false);
}
/* Check errors */
if (sz->bufferPos > sz->bufferLen)
{
sz->error = true;
} else {
sz->error = false;
}
}
const Uint8 * SZ_GetCurBufferPtr (sizebuf_t * sz)
{
return(sz->data);
}
/* The code below makes use of pointer casts, similar to what is in efread.
* It's not the ONLY way to write ints to a stream, but it's probably the
* cleanest of the lot. Better to have it here than littered all over the code.
*/
void MSG_WriteByte(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
{
sz->error = true;
return;
}
sz->data[sz->bufferPos] = value;
sz->bufferPos++;
}
void MSG_WriteWord(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
{
sz->error = true;
return;
}
*((Uint16 *)(sz->data + sz->bufferPos)) = SDL_SwapLE16( ((Uint16)value) );
sz->bufferPos += 2;
}
void MSG_WriteDWord(sizebuf_t * sz, unsigned int value)
{
if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
{
sz->error = true;
return;
}
*((Uint32 *)(sz->data + sz->bufferPos)) = SDL_SwapLE32( ((Uint32)value) );
sz->bufferPos += 4;
}
unsigned int MSG_ReadByte(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = sz->data[sz->bufferPos];
sz->bufferPos += 1;
return(ret);
}
unsigned int MSG_ReadWord(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = SDL_SwapLE16(*((Uint16 *)(sz->data + sz->bufferPos)));
sz->bufferPos += 2;
return(ret);
}
unsigned int MSG_ReadDWord(sizebuf_t * sz)
{
unsigned int ret;
if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
{
sz->error = true;
return(0);
}
ret = SDL_SwapLE32(*((Uint32 *)(sz->data + sz->bufferPos)));
sz->bufferPos += 4;
return(ret);
}