Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

415 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Engine specific CRC functions
  4. //
  5. //=============================================================================//
  6. #include "checksum_engine.h"
  7. #include "bspfile.h"
  8. #include "filesystem.h"
  9. #include "filesystem_engine.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //-----------------------------------------------------------------------------
  13. // Purpose: For proxy protecting
  14. // Turns the passed data into a
  15. // single byte block CRC based on current network sequence number.
  16. // Input : *base -
  17. // length -
  18. // sequence -
  19. // Output : byte COM_BlockSequenceCRCByte
  20. //-----------------------------------------------------------------------------
  21. byte COM_BlockSequenceCRCByte( byte *base, int length, int sequence )
  22. {
  23. CRC32_t crc;
  24. byte *p;
  25. byte chkb[60 + 4];
  26. if (sequence < 0)
  27. {
  28. Sys_Error("sequence < 0, in COM_BlockSequenceCRCByte\n");
  29. }
  30. CRC32_t entry;
  31. entry = CRC32_GetTableEntry( ( sequence + 1 ) % ( 256 * sizeof(CRC32_t) - 4 ) );
  32. p = (byte *)&entry;
  33. // Use up to the first 60 bytes of data and a 4 byte value from the
  34. // CRC lookup table (divided into the sequence)
  35. if (length > 60)
  36. {
  37. length = 60;
  38. }
  39. memcpy (chkb, base, length);
  40. chkb[length+0] = p[0];
  41. chkb[length+1] = p[1];
  42. chkb[length+2] = p[2];
  43. chkb[length+3] = p[3];
  44. length += 4;
  45. // Compute a crc based on the buffer.
  46. CRC32_Init(&crc);
  47. CRC32_ProcessBuffer(&crc, chkb, length);
  48. CRC32_Final(&crc);
  49. // Chop down to byte size
  50. return (byte)(crc & 0xFF);
  51. }
  52. // YWB: 5/18
  53. /*
  54. ===================
  55. bool CRC_File(unsigned short *crcvalue, char *pszFileName)
  56. Computes CRC for given file. If there is an error opening/reading the file, returns false,
  57. otherwise returns true and sets the crc value passed to it. The value should be initialized
  58. with CRC_Init
  59. ==================
  60. */
  61. bool CRC_File(CRC32_t *crcvalue, const char *pszFileName)
  62. {
  63. // Always re-init the CRC buffer
  64. CRC32_Init( crcvalue );
  65. FileHandle_t fp;
  66. byte chunk[1024];
  67. int nBytesRead;
  68. int nSize;
  69. nSize = COM_OpenFile(pszFileName, &fp);
  70. if ( !fp || ( nSize == -1 ) )
  71. return FALSE;
  72. // Now read in 1K chunks
  73. while (nSize > 0)
  74. {
  75. if (nSize > 1024)
  76. nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
  77. else
  78. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  79. // If any data was received, CRC it.
  80. if (nBytesRead > 0)
  81. {
  82. nSize -= nBytesRead;
  83. CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
  84. }
  85. // We we are end of file, break loop and return
  86. if ( g_pFileSystem->EndOfFile( fp ) )
  87. {
  88. g_pFileSystem->Close( fp );
  89. fp = 0;
  90. break;
  91. }
  92. // If there was a disk error, indicate failure.
  93. else if ( nBytesRead <= 0 || !g_pFileSystem->IsOk(fp) )
  94. {
  95. if ( fp )
  96. g_pFileSystem->Close(fp);
  97. return FALSE;
  98. }
  99. }
  100. if ( fp )
  101. g_pFileSystem->Close(fp);
  102. return TRUE;
  103. }
  104. // YWB: 5/18
  105. /*
  106. ===================
  107. bool CRC_MapFile(unsigned short *crcvalue, char *pszFileName)
  108. Computes CRC for given map file. If there is an error opening/reading the file, returns false,
  109. otherwise returns true and sets the crc value passed to it. The value should be initialized
  110. with CRC_Init
  111. For map (.bsp) files, the entity lump is not included in the CRC.
  112. //FIXME make this work
  113. ==================
  114. */
  115. bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
  116. {
  117. FileHandle_t fp;
  118. byte chunk[1024];
  119. int i, l;
  120. int nBytesRead;
  121. dheader_t header;
  122. int nSize;
  123. lump_t *curLump;
  124. long startOfs;
  125. nSize = COM_OpenFile(pszFileName, &fp);
  126. if ( !fp || ( nSize == -1 ) )
  127. return false;
  128. startOfs = g_pFileSystem->Tell(fp);
  129. // Don't CRC the header.
  130. if (g_pFileSystem->Read(&header, sizeof(dheader_t), fp) == 0)
  131. {
  132. ConMsg("Could not read BSP header for map [%s].\n", pszFileName);
  133. g_pFileSystem->Close(fp);
  134. return false;
  135. }
  136. i = header.version;
  137. if ( i < MINBSPVERSION || i > BSPVERSION )
  138. {
  139. g_pFileSystem->Close(fp);
  140. ConMsg("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, i, BSPVERSION);
  141. return false;
  142. }
  143. if ( IsX360() )
  144. {
  145. // 360 bsp's store the pc checksum in the flags lump header
  146. g_pFileSystem->Close(fp);
  147. *crcvalue = header.lumps[LUMP_MAP_FLAGS].version;
  148. return true;
  149. }
  150. // CRC across all lumps except for the Entities lump
  151. for (l = 0; l < HEADER_LUMPS; l++)
  152. {
  153. if (l == LUMP_ENTITIES)
  154. continue;
  155. curLump = &header.lumps[l];
  156. nSize = curLump->filelen;
  157. g_pFileSystem->Seek( fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD );
  158. // Now read in 1K chunks
  159. while (nSize > 0)
  160. {
  161. if (nSize > 1024)
  162. nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
  163. else
  164. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  165. // If any data was received, CRC it.
  166. if (nBytesRead > 0)
  167. {
  168. nSize -= nBytesRead;
  169. CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
  170. }
  171. // If there was a disk error, indicate failure.
  172. if ( !g_pFileSystem->IsOk(fp) )
  173. {
  174. if ( fp )
  175. g_pFileSystem->Close(fp);
  176. return false;
  177. }
  178. }
  179. }
  180. if ( fp )
  181. g_pFileSystem->Close(fp);
  182. return true;
  183. }
  184. bool MD5_MapFile(MD5Value_t *md5value, const char *pszFileName)
  185. {
  186. FileHandle_t fp;
  187. byte chunk[1024];
  188. int i, l;
  189. int nBytesRead;
  190. dheader_t header;
  191. int nSize;
  192. lump_t *curLump;
  193. long startOfs;
  194. nSize = COM_OpenFile(pszFileName, &fp);
  195. if ( !fp || ( nSize == -1 ) )
  196. return false;
  197. MD5Context_t ctx;
  198. V_memset( &ctx, 0, sizeof(MD5Context_t) );
  199. MD5Init( &ctx );
  200. startOfs = g_pFileSystem->Tell(fp);
  201. // Don't MD5 the header.
  202. if (g_pFileSystem->Read(&header, sizeof(dheader_t), fp) == 0)
  203. {
  204. ConMsg("Could not read BSP header for map [%s].\n", pszFileName);
  205. g_pFileSystem->Close(fp);
  206. return false;
  207. }
  208. i = header.version;
  209. if ( i < MINBSPVERSION || i > BSPVERSION )
  210. {
  211. g_pFileSystem->Close(fp);
  212. ConMsg("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, i, BSPVERSION);
  213. return false;
  214. }
  215. if ( IsX360() )
  216. {
  217. // 360 bsp's store the pc checksum in the flags lump header
  218. g_pFileSystem->Close(fp);
  219. char versionString[65] = {0};
  220. V_snprintf( versionString, ARRAYSIZE(versionString), "%d", header.lumps[LUMP_MAP_FLAGS].version );
  221. V_memcpy( md5value->bits, versionString, MD5_DIGEST_LENGTH );
  222. return true;
  223. }
  224. // MD5 across all lumps except for the Entities lump
  225. for (l = 0; l < HEADER_LUMPS; l++)
  226. {
  227. if (l == LUMP_ENTITIES)
  228. continue;
  229. curLump = &header.lumps[l];
  230. nSize = curLump->filelen;
  231. g_pFileSystem->Seek( fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD );
  232. // Now read in 1K chunks
  233. while (nSize > 0)
  234. {
  235. if (nSize > 1024)
  236. nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
  237. else
  238. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  239. // If any data was received, CRC it.
  240. if (nBytesRead > 0)
  241. {
  242. nSize -= nBytesRead;
  243. MD5Update( &ctx, chunk, nBytesRead );
  244. }
  245. // If there was a disk error, indicate failure.
  246. if ( !g_pFileSystem->IsOk(fp) )
  247. {
  248. if ( fp )
  249. g_pFileSystem->Close(fp);
  250. return false;
  251. }
  252. }
  253. }
  254. if ( fp )
  255. g_pFileSystem->Close(fp);
  256. MD5Final( md5value->bits, &ctx );
  257. return true;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. // Input : digest[16] -
  262. // *pszFileName -
  263. // bSeed -
  264. // seed[4] -
  265. // Output : Returns true on success, false on failure.
  266. //-----------------------------------------------------------------------------
  267. bool MD5_Hash_File(unsigned char digest[16], const char *pszFileName, bool bSeed /* = FALSE */, unsigned int seed[4] /* = NULL */)
  268. {
  269. FileHandle_t fp;
  270. byte chunk[1024];
  271. int nBytesRead;
  272. MD5Context_t ctx;
  273. int nSize;
  274. nSize = COM_OpenFile( pszFileName, &fp );
  275. if ( !fp || ( nSize == -1 ) )
  276. return false;
  277. memset(&ctx, 0, sizeof(MD5Context_t));
  278. MD5Init(&ctx);
  279. if (bSeed)
  280. {
  281. // Seed the hash with the seed value
  282. MD5Update( &ctx, (const unsigned char *)&seed[0], 16 );
  283. }
  284. // Now read in 1K chunks
  285. while (nSize > 0)
  286. {
  287. if (nSize > 1024)
  288. nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
  289. else
  290. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  291. // If any data was received, CRC it.
  292. if (nBytesRead > 0)
  293. {
  294. nSize -= nBytesRead;
  295. MD5Update(&ctx, chunk, nBytesRead);
  296. }
  297. // We we are end of file, break loop and return
  298. if ( g_pFileSystem->EndOfFile( fp ) )
  299. {
  300. g_pFileSystem->Close( fp );
  301. fp = NULL;
  302. break;
  303. }
  304. // If there was a disk error, indicate failure.
  305. else if ( !g_pFileSystem->IsOk(fp) )
  306. {
  307. if ( fp )
  308. g_pFileSystem->Close(fp);
  309. return FALSE;
  310. }
  311. }
  312. if ( fp )
  313. g_pFileSystem->Close(fp);
  314. MD5Final(digest, &ctx);
  315. return TRUE;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. //-----------------------------------------------------------------------------
  320. bool MD5_Hash_Buffer( unsigned char pDigest[16], const unsigned char *pBuffer, int nSize, bool bSeed /* = FALSE */, unsigned int seed[4] /* = NULL */ )
  321. {
  322. MD5Context_t ctx;
  323. if ( !pBuffer || !nSize )
  324. return false;
  325. memset( &ctx, 0, sizeof( MD5Context_t ) );
  326. MD5Init( &ctx );
  327. if ( bSeed )
  328. {
  329. // Seed the hash with the seed value
  330. MD5Update( &ctx, (const unsigned char *)&seed[0], 16 );
  331. }
  332. // Now read in 1024 chunks
  333. const unsigned char *pChunk = pBuffer;
  334. while ( nSize > 0 )
  335. {
  336. const int nChunkSize = MIN( 1024, nSize );
  337. MD5Update( &ctx, pChunk, nChunkSize );
  338. nSize -= nChunkSize;
  339. pChunk += nChunkSize; AssertValidReadPtr( pChunk );
  340. }
  341. MD5Final( pDigest, &ctx );
  342. return true;
  343. }