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.

228 lines
5.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "compression.h"
  5. #include "replay/ienginereplay.h"
  6. #include "replay/replayutils.h"
  7. #include "convar.h"
  8. #include "filesystem.h"
  9. #include "fmtstr.h"
  10. #include "../utils/bzip2/bzlib.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. //----------------------------------------------------------------------------------------
  14. extern IEngineReplay *g_pEngine;
  15. //----------------------------------------------------------------------------------------
  16. const char *g_pCompressorTypes[ NUM_COMPRESSOR_TYPES ] =
  17. {
  18. "lzss",
  19. "bz2",
  20. };
  21. //----------------------------------------------------------------------------------------
  22. class CCompressor_Lzss : public ICompressor
  23. {
  24. public:
  25. virtual bool Compress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
  26. {
  27. return g_pEngine->LZSS_Compress( pDest, pDestLen, pSource, nSourceLen );
  28. }
  29. virtual bool Decompress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
  30. {
  31. return g_pEngine->LZSS_Decompress( pDest, pDestLen, pSource, nSourceLen );
  32. }
  33. virtual int GetEstimatedCompressionSize( unsigned int nSourceLen )
  34. {
  35. return nSourceLen;
  36. }
  37. };
  38. //----------------------------------------------------------------------------------------
  39. #define BZ2_DEFAULT_BLOCKSIZE100k 9 // Highest compression rate, but uses the most memory
  40. #define BZ2_DEFAULT_WORKFACTOR 0 // Default work factor - same as using 30
  41. //----------------------------------------------------------------------------------------
  42. class CCompressor_Bz2 : public ICompressor
  43. {
  44. public:
  45. CCompressor_Bz2(
  46. int nBlockSize100k = BZ2_DEFAULT_BLOCKSIZE100k,
  47. int nWorkFactor = BZ2_DEFAULT_WORKFACTOR
  48. )
  49. : m_nBlockSize100k( nBlockSize100k ),
  50. m_nWorkFactor( nWorkFactor )
  51. {
  52. }
  53. virtual bool Compress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
  54. {
  55. return BZ_OK == BZ2_bzBuffToBuffCompress(
  56. pDest,
  57. pDestLen,
  58. const_cast< char *>( pSource ),
  59. nSourceLen,
  60. m_nBlockSize100k,
  61. 0, // Silent verbosity
  62. m_nWorkFactor
  63. );
  64. }
  65. virtual bool Decompress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
  66. {
  67. return BZ_OK == BZ2_bzBuffToBuffDecompress(
  68. pDest,
  69. pDestLen,
  70. const_cast< char * >( pSource ),
  71. nSourceLen,
  72. 0, // Don't use smaller decompressor (half as fast)
  73. 0 // Quiet
  74. );
  75. }
  76. virtual int GetEstimatedCompressionSize( unsigned int nSourceLen )
  77. {
  78. return (int)( 1.1f * nSourceLen ) + 600;
  79. }
  80. private:
  81. int m_nBlockSize100k;
  82. int m_nWorkFactor;
  83. };
  84. //----------------------------------------------------------------------------------------
  85. ICompressor *CreateCompressor( CompressorType_t nType )
  86. {
  87. switch ( nType )
  88. {
  89. case COMPRESSORTYPE_BZ2: return new CCompressor_Bz2();
  90. case COMPRESSORTYPE_LZSS: return new CCompressor_Lzss();
  91. }
  92. return NULL;
  93. }
  94. const char *GetCompressorNameSafe( CompressorType_t nType )
  95. {
  96. if ( nType < 0 || nType >= NUM_COMPRESSOR_TYPES )
  97. return "Unknown compressor type";
  98. return g_pCompressorTypes[ nType ];
  99. }
  100. //----------------------------------------------------------------------------------------
  101. #ifdef _DEBUG
  102. CON_COMMAND( replay_testcompress, "Test compression" )
  103. {
  104. if ( args.ArgC() < 3 )
  105. {
  106. Warning( "replay_testcompress <lzss|bz2> <file to compress>" );
  107. return;
  108. }
  109. const char *pInFilename = args[ 2 ];
  110. const char *pCompressionTypeName = args[ 1 ];
  111. CompressorType_t nCompressorType = COMPRESSORTYPE_INVALID;
  112. for ( int i = 0; i < (int)NUM_COMPRESSOR_TYPES; ++i )
  113. {
  114. if ( !V_stricmp( pCompressionTypeName, g_pCompressorTypes[ i ] ) )
  115. {
  116. nCompressorType = (CompressorType_t)i;
  117. break;
  118. }
  119. }
  120. if ( nCompressorType == COMPRESSORTYPE_INVALID )
  121. {
  122. Warning( "Invalid compression type specified. Use \"bz2\" or \"lzss\"\n" );
  123. return;
  124. }
  125. const unsigned int nInFileSize = g_pFullFileSystem->Size( pInFilename );
  126. if ( !nInFileSize )
  127. {
  128. Warning( "Zero length file.\n" );
  129. return;
  130. }
  131. FileHandle_t hInFile = g_pFullFileSystem->Open( pInFilename, "rb" );
  132. if ( !hInFile )
  133. {
  134. Warning( "Failed to open file, %s\n", pInFilename );
  135. return;
  136. }
  137. char *pUncompressed = new char[ nInFileSize ];
  138. if ( !pUncompressed )
  139. {
  140. Warning( "Failed to alloc %u bytes\n", nInFileSize );
  141. return;
  142. }
  143. if ( g_pFullFileSystem->Read( pUncompressed, nInFileSize, hInFile ) != (int)nInFileSize )
  144. {
  145. Warning( "Failed to read file %s\n", pInFilename );
  146. }
  147. else
  148. {
  149. ICompressor *pCompressor = CreateCompressor( nCompressorType );
  150. unsigned int nCompressedSize = pCompressor->GetEstimatedCompressionSize( nInFileSize );
  151. char *pCompressed = new char[ nCompressedSize ];
  152. if ( !pCompressed )
  153. {
  154. Warning( "Failed to allocate %u bytes for compressed buffer.\n", nCompressedSize );
  155. return;
  156. }
  157. // Compress
  158. if ( !pCompressor->Compress( pCompressed, &nCompressedSize, pUncompressed, nInFileSize ) )
  159. {
  160. Warning( "Compression failed.\n" );
  161. }
  162. else
  163. {
  164. CFmtStr fmtOutFilename( "%s.%s", pInFilename, pCompressionTypeName );
  165. FileHandle_t hOutFile = g_pFullFileSystem->Open( fmtOutFilename.Access(), "wb+" );
  166. if ( !hOutFile )
  167. {
  168. Warning( "Failed to open out file, %s\n", fmtOutFilename.Access() );
  169. }
  170. else
  171. {
  172. if ( g_pFullFileSystem->Write( pCompressed, nCompressedSize, hOutFile ) != (int)nCompressedSize )
  173. {
  174. Warning( "Failed to write compressed data to %s\n", fmtOutFilename.Access() );
  175. }
  176. else
  177. {
  178. const float flRatio = (float)nInFileSize / nCompressedSize;
  179. Warning( "Wrote compressed file to successfully (%s) - ratio: %.2f:1\n", fmtOutFilename.Access(), flRatio );
  180. }
  181. g_pFullFileSystem->Close( hOutFile );
  182. }
  183. }
  184. delete [] pCompressed;
  185. }
  186. g_pFullFileSystem->Close( hInFile );
  187. }
  188. #endif // _DEBUG
  189. //----------------------------------------------------------------------------------------