summaryrefslogtreecommitdiff
path: root/engine/checksum_engine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/checksum_engine.cpp')
-rw-r--r--engine/checksum_engine.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/engine/checksum_engine.cpp b/engine/checksum_engine.cpp
new file mode 100644
index 0000000..9c06cd6
--- /dev/null
+++ b/engine/checksum_engine.cpp
@@ -0,0 +1,415 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Engine specific CRC functions
+//
+//=============================================================================//
+
+
+#include "checksum_engine.h"
+#include "bspfile.h"
+#include "filesystem.h"
+#include "filesystem_engine.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: For proxy protecting
+// Turns the passed data into a
+// single byte block CRC based on current network sequence number.
+// Input : *base -
+// length -
+// sequence -
+// Output : byte COM_BlockSequenceCRCByte
+//-----------------------------------------------------------------------------
+byte COM_BlockSequenceCRCByte( byte *base, int length, int sequence )
+{
+ CRC32_t crc;
+ byte *p;
+ byte chkb[60 + 4];
+
+ if (sequence < 0)
+ {
+ Sys_Error("sequence < 0, in COM_BlockSequenceCRCByte\n");
+ }
+
+ CRC32_t entry;
+ entry = CRC32_GetTableEntry( ( sequence + 1 ) % ( 256 * sizeof(CRC32_t) - 4 ) );
+ p = (byte *)&entry;
+
+ // Use up to the first 60 bytes of data and a 4 byte value from the
+ // CRC lookup table (divided into the sequence)
+
+ if (length > 60)
+ {
+ length = 60;
+ }
+
+ memcpy (chkb, base, length);
+
+ chkb[length+0] = p[0];
+ chkb[length+1] = p[1];
+ chkb[length+2] = p[2];
+ chkb[length+3] = p[3];
+
+ length += 4;
+
+ // Compute a crc based on the buffer.
+ CRC32_Init(&crc);
+ CRC32_ProcessBuffer(&crc, chkb, length);
+ CRC32_Final(&crc);
+
+ // Chop down to byte size
+ return (byte)(crc & 0xFF);
+}
+
+// YWB: 5/18
+/*
+===================
+bool CRC_File(unsigned short *crcvalue, char *pszFileName)
+
+ Computes CRC for given file. If there is an error opening/reading the file, returns false,
+ otherwise returns true and sets the crc value passed to it. The value should be initialized
+ with CRC_Init
+ ==================
+ */
+bool CRC_File(CRC32_t *crcvalue, const char *pszFileName)
+{
+ // Always re-init the CRC buffer
+ CRC32_Init( crcvalue );
+
+ FileHandle_t fp;
+ byte chunk[1024];
+ int nBytesRead;
+
+ int nSize;
+
+ nSize = COM_OpenFile(pszFileName, &fp);
+ if ( !fp || ( nSize == -1 ) )
+ return FALSE;
+
+ // Now read in 1K chunks
+ while (nSize > 0)
+ {
+ if (nSize > 1024)
+ nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
+ else
+ nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
+
+ // If any data was received, CRC it.
+ if (nBytesRead > 0)
+ {
+ nSize -= nBytesRead;
+ CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
+ }
+
+ // We we are end of file, break loop and return
+ if ( g_pFileSystem->EndOfFile( fp ) )
+ {
+ g_pFileSystem->Close( fp );
+ fp = 0;
+ break;
+ }
+ // If there was a disk error, indicate failure.
+ else if ( nBytesRead <= 0 || !g_pFileSystem->IsOk(fp) )
+ {
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return FALSE;
+ }
+ }
+
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return TRUE;
+}
+
+// YWB: 5/18
+/*
+===================
+bool CRC_MapFile(unsigned short *crcvalue, char *pszFileName)
+
+ Computes CRC for given map file. If there is an error opening/reading the file, returns false,
+ otherwise returns true and sets the crc value passed to it. The value should be initialized
+ with CRC_Init
+
+ For map (.bsp) files, the entity lump is not included in the CRC.
+ //FIXME make this work
+ ==================
+ */
+bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
+{
+ FileHandle_t fp;
+ byte chunk[1024];
+ int i, l;
+ int nBytesRead;
+ dheader_t header;
+ int nSize;
+ lump_t *curLump;
+ long startOfs;
+
+ nSize = COM_OpenFile(pszFileName, &fp);
+ if ( !fp || ( nSize == -1 ) )
+ return false;
+
+ startOfs = g_pFileSystem->Tell(fp);
+
+ // Don't CRC the header.
+ if (g_pFileSystem->Read(&header, sizeof(dheader_t), fp) == 0)
+ {
+ ConMsg("Could not read BSP header for map [%s].\n", pszFileName);
+ g_pFileSystem->Close(fp);
+ return false;
+ }
+
+ i = header.version;
+ if ( i < MINBSPVERSION || i > BSPVERSION )
+ {
+ g_pFileSystem->Close(fp);
+ ConMsg("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, i, BSPVERSION);
+ return false;
+ }
+
+ if ( IsX360() )
+ {
+ // 360 bsp's store the pc checksum in the flags lump header
+ g_pFileSystem->Close(fp);
+ *crcvalue = header.lumps[LUMP_MAP_FLAGS].version;
+ return true;
+ }
+
+ // CRC across all lumps except for the Entities lump
+ for (l = 0; l < HEADER_LUMPS; l++)
+ {
+ if (l == LUMP_ENTITIES)
+ continue;
+
+ curLump = &header.lumps[l];
+ nSize = curLump->filelen;
+
+ g_pFileSystem->Seek( fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD );
+
+ // Now read in 1K chunks
+ while (nSize > 0)
+ {
+ if (nSize > 1024)
+ nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
+ else
+ nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
+
+ // If any data was received, CRC it.
+ if (nBytesRead > 0)
+ {
+ nSize -= nBytesRead;
+ CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
+ }
+
+ // If there was a disk error, indicate failure.
+ if ( !g_pFileSystem->IsOk(fp) )
+ {
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return false;
+ }
+ }
+ }
+
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return true;
+}
+
+bool MD5_MapFile(MD5Value_t *md5value, const char *pszFileName)
+{
+ FileHandle_t fp;
+ byte chunk[1024];
+ int i, l;
+ int nBytesRead;
+ dheader_t header;
+ int nSize;
+ lump_t *curLump;
+ long startOfs;
+
+ nSize = COM_OpenFile(pszFileName, &fp);
+ if ( !fp || ( nSize == -1 ) )
+ return false;
+
+ MD5Context_t ctx;
+ V_memset( &ctx, 0, sizeof(MD5Context_t) );
+ MD5Init( &ctx );
+
+ startOfs = g_pFileSystem->Tell(fp);
+
+ // Don't MD5 the header.
+ if (g_pFileSystem->Read(&header, sizeof(dheader_t), fp) == 0)
+ {
+ ConMsg("Could not read BSP header for map [%s].\n", pszFileName);
+ g_pFileSystem->Close(fp);
+ return false;
+ }
+
+ i = header.version;
+ if ( i < MINBSPVERSION || i > BSPVERSION )
+ {
+ g_pFileSystem->Close(fp);
+ ConMsg("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, i, BSPVERSION);
+ return false;
+ }
+
+ if ( IsX360() )
+ {
+ // 360 bsp's store the pc checksum in the flags lump header
+ g_pFileSystem->Close(fp);
+ char versionString[65] = {0};
+ V_snprintf( versionString, ARRAYSIZE(versionString), "%d", header.lumps[LUMP_MAP_FLAGS].version );
+ V_memcpy( md5value->bits, versionString, MD5_DIGEST_LENGTH );
+ return true;
+ }
+
+ // MD5 across all lumps except for the Entities lump
+ for (l = 0; l < HEADER_LUMPS; l++)
+ {
+ if (l == LUMP_ENTITIES)
+ continue;
+
+ curLump = &header.lumps[l];
+ nSize = curLump->filelen;
+
+ g_pFileSystem->Seek( fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD );
+
+ // Now read in 1K chunks
+ while (nSize > 0)
+ {
+ if (nSize > 1024)
+ nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
+ else
+ nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
+
+ // If any data was received, CRC it.
+ if (nBytesRead > 0)
+ {
+ nSize -= nBytesRead;
+ MD5Update( &ctx, chunk, nBytesRead );
+ }
+
+ // If there was a disk error, indicate failure.
+ if ( !g_pFileSystem->IsOk(fp) )
+ {
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return false;
+ }
+ }
+ }
+
+ if ( fp )
+ g_pFileSystem->Close(fp);
+
+ MD5Final( md5value->bits, &ctx );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : digest[16] -
+// *pszFileName -
+// bSeed -
+// seed[4] -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool MD5_Hash_File(unsigned char digest[16], const char *pszFileName, bool bSeed /* = FALSE */, unsigned int seed[4] /* = NULL */)
+{
+ FileHandle_t fp;
+ byte chunk[1024];
+ int nBytesRead;
+ MD5Context_t ctx;
+
+ int nSize;
+
+ nSize = COM_OpenFile( pszFileName, &fp );
+ if ( !fp || ( nSize == -1 ) )
+ return false;
+
+ memset(&ctx, 0, sizeof(MD5Context_t));
+
+ MD5Init(&ctx);
+
+ if (bSeed)
+ {
+ // Seed the hash with the seed value
+ MD5Update( &ctx, (const unsigned char *)&seed[0], 16 );
+ }
+
+ // Now read in 1K chunks
+ while (nSize > 0)
+ {
+ if (nSize > 1024)
+ nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
+ else
+ nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
+
+ // If any data was received, CRC it.
+ if (nBytesRead > 0)
+ {
+ nSize -= nBytesRead;
+ MD5Update(&ctx, chunk, nBytesRead);
+ }
+
+ // We we are end of file, break loop and return
+ if ( g_pFileSystem->EndOfFile( fp ) )
+ {
+ g_pFileSystem->Close( fp );
+ fp = NULL;
+ break;
+ }
+ // If there was a disk error, indicate failure.
+ else if ( !g_pFileSystem->IsOk(fp) )
+ {
+ if ( fp )
+ g_pFileSystem->Close(fp);
+ return FALSE;
+ }
+ }
+
+ if ( fp )
+ g_pFileSystem->Close(fp);
+
+ MD5Final(digest, &ctx);
+
+ return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool MD5_Hash_Buffer( unsigned char pDigest[16], const unsigned char *pBuffer, int nSize, bool bSeed /* = FALSE */, unsigned int seed[4] /* = NULL */ )
+{
+ MD5Context_t ctx;
+
+ if ( !pBuffer || !nSize )
+ return false;
+
+ memset( &ctx, 0, sizeof( MD5Context_t ) );
+ MD5Init( &ctx );
+
+ if ( bSeed )
+ {
+ // Seed the hash with the seed value
+ MD5Update( &ctx, (const unsigned char *)&seed[0], 16 );
+ }
+
+ // Now read in 1024 chunks
+ const unsigned char *pChunk = pBuffer;
+ while ( nSize > 0 )
+ {
+ const int nChunkSize = MIN( 1024, nSize );
+ MD5Update( &ctx, pChunk, nChunkSize );
+ nSize -= nChunkSize;
+ pChunk += nChunkSize; AssertValidReadPtr( pChunk );
+ }
+
+ MD5Final( pDigest, &ctx );
+
+ return true;
+}