Counter Strike : Global Offensive Source Code
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.

359 lines
8.2 KiB

  1. //========= Copyright � 1996-2005, 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. #if defined(_X360)
  53. const int CRC_BUFSIZE = 16384;
  54. #else
  55. const int CRC_BUFSIZE = 65536;
  56. #endif
  57. // YWB: 5/18
  58. /*
  59. ===================
  60. bool CRC_File(unsigned short *crcvalue, char *pszFileName)
  61. Computes CRC for given file. If there is an error opening/reading the file, returns false,
  62. otherwise returns true and sets the crc value passed to it. The value should be initialized
  63. with CRC_Init
  64. ==================
  65. */
  66. bool CRC_File(CRC32_t *crcvalue, const char *pszFileName)
  67. {
  68. // Always re-init the CRC buffer
  69. CRC32_Init( crcvalue );
  70. FileHandle_t fp;
  71. byte chunk[CRC_BUFSIZE];
  72. int nBytesRead;
  73. int nSize;
  74. nSize = COM_OpenFile(pszFileName, &fp);
  75. if ( !fp || ( nSize == -1 ) )
  76. return FALSE;
  77. // Now read in chunks
  78. while (nSize > 0)
  79. {
  80. if (nSize > sizeof(chunk))
  81. nBytesRead = g_pFileSystem->Read(chunk, sizeof(chunk), fp);
  82. else
  83. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  84. // If any data was received, CRC it.
  85. if (nBytesRead > 0)
  86. {
  87. nSize -= nBytesRead;
  88. CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
  89. }
  90. // We we are end of file, break loop and return
  91. if ( g_pFileSystem->EndOfFile( fp ) )
  92. {
  93. g_pFileSystem->Close( fp );
  94. fp = 0;
  95. break;
  96. }
  97. // If there was a disk error, indicate failure.
  98. else if ( !g_pFileSystem->IsOk(fp) )
  99. {
  100. if ( fp )
  101. g_pFileSystem->Close(fp);
  102. return FALSE;
  103. }
  104. }
  105. if ( fp )
  106. g_pFileSystem->Close(fp);
  107. return TRUE;
  108. }
  109. static BSPHeader_t *g_pMapHeader = NULL;
  110. int __cdecl LumpCompare( const void *pElem0, const void *pElem1 )
  111. {
  112. const int *pLump0 = (const int *)pElem0;
  113. const int *pLump1 = (const int *)pElem1;
  114. return g_pMapHeader->lumps[*pLump0].fileofs - g_pMapHeader->lumps[*pLump1].fileofs;
  115. }
  116. // YWB: 5/18
  117. /*
  118. ===================
  119. bool CRC_MapFile(unsigned short *crcvalue, char *pszFileName)
  120. Computes CRC for given map file. If there is an error opening/reading the file, returns false,
  121. otherwise returns true and sets the crc value passed to it. The value should be initialized
  122. with CRC_Init
  123. For map (.bsp) files, the entity lump is not included in the CRC.
  124. //FIXME make this work
  125. ==================
  126. */
  127. ConVar debug_map_crc( "debug_map_crc", "0", FCVAR_RELEASE, "Prints CRC for each map lump loaded" );
  128. bool CRC_MapFile(CRC32_t *crcvalue, const char *pszFileName)
  129. {
  130. FileHandle_t fp;
  131. byte chunk[CRC_BUFSIZE];
  132. int nBytesRead;
  133. BSPHeader_t header;
  134. int nSize;
  135. lump_t *curLump;
  136. long startOfs;
  137. nSize = COM_OpenFile(pszFileName, &fp);
  138. if ( !fp || ( nSize == -1 ) )
  139. return false;
  140. startOfs = g_pFileSystem->Tell(fp);
  141. // Don't CRC the header.
  142. if (g_pFileSystem->Read(&header, sizeof(BSPHeader_t), fp) == 0)
  143. {
  144. ConMsg("Could not read BSP header for map [%s].\n", pszFileName);
  145. g_pFileSystem->Close(fp);
  146. return false;
  147. }
  148. if ( header.m_nVersion < MINBSPVERSION || header.m_nVersion > BSPVERSION )
  149. {
  150. g_pFileSystem->Close(fp);
  151. ConMsg("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, header.m_nVersion, BSPVERSION);
  152. return false;
  153. }
  154. if ( IsX360() )
  155. {
  156. // 360 bsp's store the pc checksum in the flags lump header
  157. g_pFileSystem->Close(fp);
  158. *crcvalue = header.lumps[LUMP_MAP_FLAGS].version;
  159. return true;
  160. }
  161. static char gamedir[MAX_OSPATH];
  162. Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
  163. g_pMapHeader = &header;
  164. int lumpList[HEADER_LUMPS];
  165. for ( int i = 0; i < HEADER_LUMPS; i++ )
  166. {
  167. lumpList[i] = i;
  168. }
  169. qsort( lumpList, HEADER_LUMPS, sizeof(lumpList[0]), LumpCompare );
  170. CRC32_t lumpCRC;
  171. // CRC across all lumps except for the Entities lump
  172. for (int i = 0; i < HEADER_LUMPS; i++)
  173. {
  174. int l = lumpList[i];
  175. if (l == LUMP_ENTITIES)
  176. continue;
  177. CRC32_Init(&lumpCRC);
  178. // INFESTED_DLL - Alien Swarm wants a more relaxed CRC check so each client can compile the map themselves
  179. if ( !Q_stricmp( gamedir, "infested" ) )
  180. {
  181. if ( l == LUMP_LIGHTING ||
  182. l == LUMP_DISPINFO ||
  183. l == LUMP_GAME_LUMP ||
  184. l == LUMP_PRIMITIVES ||
  185. l == LUMP_LEAF_AMBIENT_INDEX_HDR ||
  186. l == LUMP_LEAF_AMBIENT_INDEX ||
  187. l == LUMP_LEAF_AMBIENT_LIGHTING_HDR ||
  188. l == LUMP_LEAF_AMBIENT_LIGHTING ||
  189. l == LUMP_PAKFILE ||
  190. l == LUMP_PHYSCOLLIDE ||
  191. l == LUMP_TEXINFO ||
  192. l == LUMP_PHYSDISP )
  193. continue;
  194. }
  195. curLump = &header.lumps[l];
  196. nSize = curLump->filelen;
  197. if ( nSize <= 0 )
  198. continue;
  199. g_pFileSystem->Seek( fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD );
  200. // Now read chunks
  201. while (nSize > 0)
  202. {
  203. if (nSize > sizeof(chunk))
  204. nBytesRead = g_pFileSystem->Read(chunk, sizeof(chunk), fp);
  205. else
  206. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  207. // If any data was received, CRC it.
  208. if (nBytesRead > 0)
  209. {
  210. nSize -= nBytesRead;
  211. CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead);
  212. if ( debug_map_crc.GetBool() )
  213. {
  214. CRC32_ProcessBuffer(&lumpCRC, chunk, nBytesRead);
  215. }
  216. }
  217. // If there was a disk error, indicate failure.
  218. if ( !g_pFileSystem->IsOk(fp) )
  219. {
  220. if ( fp )
  221. g_pFileSystem->Close(fp);
  222. return false;
  223. }
  224. }
  225. if ( debug_map_crc.GetBool() )
  226. {
  227. Msg( "Lump %d crc %lu\n", l, lumpCRC );
  228. }
  229. }
  230. if ( fp )
  231. g_pFileSystem->Close(fp);
  232. if ( debug_map_crc.GetBool() )
  233. {
  234. Msg( "Map file '%s' CRC = %lu\n", pszFileName, *crcvalue );
  235. }
  236. return true;
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose:
  240. // Input : digest[16] -
  241. // *pszFileName -
  242. // bSeed -
  243. // seed[4] -
  244. // Output : Returns true on success, false on failure.
  245. //-----------------------------------------------------------------------------
  246. bool MD5_Hash_File(unsigned char digest[16], char *pszFileName, bool bSeed /* = FALSE */, unsigned int seed[4] /* = NULL */)
  247. {
  248. FileHandle_t fp;
  249. byte chunk[1024];
  250. int nBytesRead;
  251. MD5Context_t ctx;
  252. int nSize;
  253. nSize = COM_OpenFile( pszFileName, &fp );
  254. if ( !fp || ( nSize == -1 ) )
  255. return false;
  256. memset(&ctx, 0, sizeof(MD5Context_t));
  257. MD5Init(&ctx);
  258. if (bSeed)
  259. {
  260. // Seed the hash with the seed value
  261. MD5Update( &ctx, (const unsigned char *)&seed[0], 16 );
  262. }
  263. // Now read in 1K chunks
  264. while (nSize > 0)
  265. {
  266. if (nSize > 1024)
  267. nBytesRead = g_pFileSystem->Read(chunk, 1024, fp);
  268. else
  269. nBytesRead = g_pFileSystem->Read(chunk, nSize, fp);
  270. // If any data was received, CRC it.
  271. if (nBytesRead > 0)
  272. {
  273. nSize -= nBytesRead;
  274. MD5Update(&ctx, chunk, nBytesRead);
  275. }
  276. // We we are end of file, break loop and return
  277. if ( g_pFileSystem->EndOfFile( fp ) )
  278. {
  279. g_pFileSystem->Close( fp );
  280. fp = NULL;
  281. break;
  282. }
  283. // If there was a disk error, indicate failure.
  284. else if ( !g_pFileSystem->IsOk(fp) )
  285. {
  286. if ( fp )
  287. g_pFileSystem->Close(fp);
  288. return FALSE;
  289. }
  290. }
  291. if ( fp )
  292. g_pFileSystem->Close(fp);
  293. MD5Final(digest, &ctx);
  294. return TRUE;
  295. }