mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 06:36:54 +00:00
229 lines
5.9 KiB
C++
229 lines
5.9 KiB
C++
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
//=======================================================================================//
|
||
|
|
||
|
#include "compression.h"
|
||
|
#include "replay/ienginereplay.h"
|
||
|
#include "replay/replayutils.h"
|
||
|
#include "convar.h"
|
||
|
#include "filesystem.h"
|
||
|
#include "fmtstr.h"
|
||
|
#include "../utils/bzip2/bzlib.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
extern IEngineReplay *g_pEngine;
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
const char *g_pCompressorTypes[ NUM_COMPRESSOR_TYPES ] =
|
||
|
{
|
||
|
"lzss",
|
||
|
"bz2",
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
class CCompressor_Lzss : public ICompressor
|
||
|
{
|
||
|
public:
|
||
|
virtual bool Compress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
|
||
|
{
|
||
|
return g_pEngine->LZSS_Compress( pDest, pDestLen, pSource, nSourceLen );
|
||
|
}
|
||
|
|
||
|
virtual bool Decompress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
|
||
|
{
|
||
|
return g_pEngine->LZSS_Decompress( pDest, pDestLen, pSource, nSourceLen );
|
||
|
}
|
||
|
|
||
|
virtual int GetEstimatedCompressionSize( unsigned int nSourceLen )
|
||
|
{
|
||
|
return nSourceLen;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
#define BZ2_DEFAULT_BLOCKSIZE100k 9 // Highest compression rate, but uses the most memory
|
||
|
#define BZ2_DEFAULT_WORKFACTOR 0 // Default work factor - same as using 30
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
class CCompressor_Bz2 : public ICompressor
|
||
|
{
|
||
|
public:
|
||
|
CCompressor_Bz2(
|
||
|
int nBlockSize100k = BZ2_DEFAULT_BLOCKSIZE100k,
|
||
|
int nWorkFactor = BZ2_DEFAULT_WORKFACTOR
|
||
|
)
|
||
|
: m_nBlockSize100k( nBlockSize100k ),
|
||
|
m_nWorkFactor( nWorkFactor )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
virtual bool Compress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
|
||
|
{
|
||
|
return BZ_OK == BZ2_bzBuffToBuffCompress(
|
||
|
pDest,
|
||
|
pDestLen,
|
||
|
const_cast< char *>( pSource ),
|
||
|
nSourceLen,
|
||
|
m_nBlockSize100k,
|
||
|
0, // Silent verbosity
|
||
|
m_nWorkFactor
|
||
|
);
|
||
|
}
|
||
|
|
||
|
virtual bool Decompress( char *pDest, unsigned int *pDestLen, const char *pSource, unsigned int nSourceLen )
|
||
|
{
|
||
|
return BZ_OK == BZ2_bzBuffToBuffDecompress(
|
||
|
pDest,
|
||
|
pDestLen,
|
||
|
const_cast< char * >( pSource ),
|
||
|
nSourceLen,
|
||
|
0, // Don't use smaller decompressor (half as fast)
|
||
|
0 // Quiet
|
||
|
);
|
||
|
}
|
||
|
|
||
|
virtual int GetEstimatedCompressionSize( unsigned int nSourceLen )
|
||
|
{
|
||
|
return (int)( 1.1f * nSourceLen ) + 600;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
int m_nBlockSize100k;
|
||
|
int m_nWorkFactor;
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
ICompressor *CreateCompressor( CompressorType_t nType )
|
||
|
{
|
||
|
switch ( nType )
|
||
|
{
|
||
|
case COMPRESSORTYPE_BZ2: return new CCompressor_Bz2();
|
||
|
case COMPRESSORTYPE_LZSS: return new CCompressor_Lzss();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
const char *GetCompressorNameSafe( CompressorType_t nType )
|
||
|
{
|
||
|
if ( nType < 0 || nType >= NUM_COMPRESSOR_TYPES )
|
||
|
return "Unknown compressor type";
|
||
|
|
||
|
return g_pCompressorTypes[ nType ];
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
CON_COMMAND( replay_testcompress, "Test compression" )
|
||
|
{
|
||
|
if ( args.ArgC() < 3 )
|
||
|
{
|
||
|
Warning( "replay_testcompress <lzss|bz2> <file to compress>" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const char *pInFilename = args[ 2 ];
|
||
|
const char *pCompressionTypeName = args[ 1 ];
|
||
|
|
||
|
CompressorType_t nCompressorType = COMPRESSORTYPE_INVALID;
|
||
|
|
||
|
for ( int i = 0; i < (int)NUM_COMPRESSOR_TYPES; ++i )
|
||
|
{
|
||
|
if ( !V_stricmp( pCompressionTypeName, g_pCompressorTypes[ i ] ) )
|
||
|
{
|
||
|
nCompressorType = (CompressorType_t)i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( nCompressorType == COMPRESSORTYPE_INVALID )
|
||
|
{
|
||
|
Warning( "Invalid compression type specified. Use \"bz2\" or \"lzss\"\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const unsigned int nInFileSize = g_pFullFileSystem->Size( pInFilename );
|
||
|
if ( !nInFileSize )
|
||
|
{
|
||
|
Warning( "Zero length file.\n" );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FileHandle_t hInFile = g_pFullFileSystem->Open( pInFilename, "rb" );
|
||
|
if ( !hInFile )
|
||
|
{
|
||
|
Warning( "Failed to open file, %s\n", pInFilename );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
char *pUncompressed = new char[ nInFileSize ];
|
||
|
if ( !pUncompressed )
|
||
|
{
|
||
|
Warning( "Failed to alloc %u bytes\n", nInFileSize );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( g_pFullFileSystem->Read( pUncompressed, nInFileSize, hInFile ) != (int)nInFileSize )
|
||
|
{
|
||
|
Warning( "Failed to read file %s\n", pInFilename );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ICompressor *pCompressor = CreateCompressor( nCompressorType );
|
||
|
unsigned int nCompressedSize = pCompressor->GetEstimatedCompressionSize( nInFileSize );
|
||
|
char *pCompressed = new char[ nCompressedSize ];
|
||
|
if ( !pCompressed )
|
||
|
{
|
||
|
Warning( "Failed to allocate %u bytes for compressed buffer.\n", nCompressedSize );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Compress
|
||
|
if ( !pCompressor->Compress( pCompressed, &nCompressedSize, pUncompressed, nInFileSize ) )
|
||
|
{
|
||
|
Warning( "Compression failed.\n" );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CFmtStr fmtOutFilename( "%s.%s", pInFilename, pCompressionTypeName );
|
||
|
FileHandle_t hOutFile = g_pFullFileSystem->Open( fmtOutFilename.Access(), "wb+" );
|
||
|
if ( !hOutFile )
|
||
|
{
|
||
|
Warning( "Failed to open out file, %s\n", fmtOutFilename.Access() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( g_pFullFileSystem->Write( pCompressed, nCompressedSize, hOutFile ) != (int)nCompressedSize )
|
||
|
{
|
||
|
Warning( "Failed to write compressed data to %s\n", fmtOutFilename.Access() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const float flRatio = (float)nInFileSize / nCompressedSize;
|
||
|
Warning( "Wrote compressed file to successfully (%s) - ratio: %.2f:1\n", fmtOutFilename.Access(), flRatio );
|
||
|
}
|
||
|
|
||
|
g_pFullFileSystem->Close( hOutFile );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete [] pCompressed;
|
||
|
}
|
||
|
|
||
|
g_pFullFileSystem->Close( hInFile );
|
||
|
}
|
||
|
|
||
|
#endif // _DEBUG
|
||
|
|
||
|
//----------------------------------------------------------------------------------------
|