Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * OpenTyrian: A modern cross-platform port of Tyrian
  3.  * Copyright (C) 2007-2009  The OpenTyrian Development Team
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License
  7.  * as published by the Free Software Foundation; either version 2
  8.  * of the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  18.  */
  19.  
  20. /*
  21.  * This file is largely based on (and named after) a set of common reading/
  22.  * writing functions used in Quake engines.  Its purpose is to allow extraction
  23.  * of bytes, words, and dwords in a safe, endian adjused environment and should
  24.  * probably be used in any situation where checking for buffer overflows
  25.  * manually makes the code a godawful mess.
  26.  *
  27.  * Currently this is only used by the animation decoding.
  28.  *
  29.  * This file is written with the intention of being easily converted into a
  30.  * class capable of throwing exceptions if data is out of range.
  31.  *
  32.  * If an operation fails, subsequent operations will also fail.  The sizebuf
  33.  * is assumed to be in an invalid state.  This COULD be changed pretty easily
  34.  * and in normal Quake IIRC it is.  But our MO is to bail on failure, not
  35.  * figure out what went wrong (making throws perfect).
  36.  */
  37. #include "sizebuf.h"
  38.  
  39. #include "SDL_endian.h"
  40.  
  41. #include <assert.h>
  42. #include <stdio.h>
  43. #include <string.h>
  44.  
  45. /* Construct buffer with the passed array and size */
  46. void SZ_Init(sizebuf_t * sz, Uint8 * buf, unsigned int size)
  47. {
  48.         sz->data = buf;
  49.         sz->bufferLen = size;
  50.         sz->bufferPos = 0;
  51.         sz->error = false;
  52. }
  53. /* Check error flags */
  54. bool SZ_Error(sizebuf_t * sz)
  55. {
  56.         return(sz->error);
  57. }
  58. /* mimic memset */
  59. void SZ_Memset(sizebuf_t * sz, int value, size_t count)
  60. {
  61.         /* Do bounds checking before writing */
  62.         if (sz->error || sz->bufferPos + count > sz->bufferLen)
  63.         {
  64.                 sz->error = true;
  65.                 return;
  66.         }
  67.  
  68.         /* Memset and increment pointer */
  69.         memset(sz->data + sz->bufferPos, value, count);
  70.         sz->bufferPos += count;
  71. }
  72. /* Mimic memcpy.  Two versions, one for buffers, one for sizebuf objects.
  73.  * Overload in C++. */
  74. void SZ_Memcpy(sizebuf_t * sz, const Uint8 * buf, size_t count)
  75. {
  76.         /* State checking */
  77.         if (sz->error || sz->bufferPos + count > sz->bufferLen)
  78.         {
  79.                 sz->error = true;
  80.                 return;
  81.         }
  82.  
  83.         /* Memcpy & increment */
  84.         memcpy(sz->data + sz->bufferPos, buf, count);
  85.         sz->bufferPos += count;
  86. }
  87. void SZ_Memcpy2(sizebuf_t * sz, sizebuf_t * bf, size_t count)
  88. {
  89.         /* State checking */
  90.         if (sz->error || sz->bufferPos + count > sz->bufferLen)
  91.         {
  92.                 sz->error = true;
  93.                 return;
  94.         }
  95.         if (bf->error || bf->bufferPos + count > bf->bufferLen)
  96.         {
  97.                 bf->error = true;
  98.                 return;
  99.         }
  100.  
  101.         /* Memcpy & increment */
  102.         memcpy(sz->data + sz->bufferPos, bf->data + bf->bufferPos, count);
  103.         sz->bufferPos += count;
  104.         bf->bufferPos += count;
  105. }
  106. /* Reposition buffer pointer */
  107. void SZ_Seek(sizebuf_t * sz, long count, int mode)
  108. {
  109.         /* Okay, it's reasonable to reset the error bool on seeking... */
  110.  
  111.         switch(mode)
  112.         {
  113.                 case SEEK_SET:
  114.                         sz->bufferPos = count;
  115.                         break;
  116.                 case SEEK_CUR:
  117.                         sz->bufferPos += count;
  118.                         break;
  119.                 case SEEK_END:
  120.                         sz->bufferPos = sz->bufferLen - count;
  121.                         break;
  122.                 default:
  123.                         assert(false);
  124.         }
  125.  
  126.         /* Check errors */
  127.         if (sz->bufferPos > sz->bufferLen)
  128.         {
  129.                 sz->error = true;
  130.         } else {
  131.                 sz->error = false;
  132.         }
  133. }
  134. const Uint8 * SZ_GetCurBufferPtr (sizebuf_t * sz)
  135. {
  136.         return(sz->data);
  137. }
  138.  
  139. /* The code below makes use of pointer casts, similar to what is in efread.
  140.  * It's not the ONLY way to write ints to a stream, but it's probably the
  141.  * cleanest of the lot.  Better to have it here than littered all over the code.
  142.  */
  143. void MSG_WriteByte(sizebuf_t * sz, unsigned int value)
  144. {
  145.         if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
  146.         {
  147.                 sz->error = true;
  148.                 return;
  149.         }
  150.  
  151.         sz->data[sz->bufferPos] = value;
  152.         sz->bufferPos++;
  153. }
  154. void MSG_WriteWord(sizebuf_t * sz, unsigned int value)
  155. {
  156.         if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
  157.         {
  158.                 sz->error = true;
  159.                 return;
  160.         }
  161.  
  162.         *((Uint16 *)(sz->data + sz->bufferPos)) = SDL_SwapLE16( ((Uint16)value) );
  163.         sz->bufferPos += 2;
  164. }
  165. void MSG_WriteDWord(sizebuf_t * sz, unsigned int value)
  166. {
  167.         if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
  168.         {
  169.                 sz->error = true;
  170.                 return;
  171.         }
  172.  
  173.         *((Uint32 *)(sz->data + sz->bufferPos)) = SDL_SwapLE32( ((Uint32)value) );
  174.         sz->bufferPos += 4;
  175. }
  176.  
  177. unsigned int MSG_ReadByte(sizebuf_t * sz)
  178. {
  179.         unsigned int ret;
  180.  
  181.  
  182.         if (sz->error || sz->bufferPos + 1 > sz->bufferLen)
  183.         {
  184.                 sz->error = true;
  185.                 return(0);
  186.         }
  187.  
  188.         ret = sz->data[sz->bufferPos];
  189.         sz->bufferPos += 1;
  190.  
  191.         return(ret);
  192. }
  193. unsigned int MSG_ReadWord(sizebuf_t * sz)
  194. {
  195.         unsigned int ret;
  196.  
  197.  
  198.         if (sz->error || sz->bufferPos + 2 > sz->bufferLen)
  199.         {
  200.                 sz->error = true;
  201.                 return(0);
  202.         }
  203.  
  204.         ret = SDL_SwapLE16(*((Uint16 *)(sz->data + sz->bufferPos)));
  205.         sz->bufferPos += 2;
  206.  
  207.         return(ret);
  208. }
  209. unsigned int MSG_ReadDWord(sizebuf_t * sz)
  210. {
  211.         unsigned int ret;
  212.  
  213.  
  214.         if (sz->error || sz->bufferPos + 4 > sz->bufferLen)
  215.         {
  216.                 sz->error = true;
  217.                 return(0);
  218.         }
  219.  
  220.         ret = SDL_SwapLE32(*((Uint32 *)(sz->data + sz->bufferPos)));
  221.         sz->bufferPos += 4;
  222.  
  223.         return(ret);
  224. }
  225.