forked from KolibriOS/kolibrios
225 lines
5.3 KiB
C
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);
|
||
|
}
|