mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
332
utils/lzma/lzma.cpp
Normal file
332
utils/lzma/lzma.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// LZMA Codec interface for engine. Based largely on LzmaUtil.c in SDK
|
||||
//
|
||||
// LZMA SDK 9.38 beta
|
||||
// 2015-01-03 : Igor Pavlov : Public domain
|
||||
// http://www.7-zip.org/
|
||||
//
|
||||
//========================================================================//
|
||||
|
||||
#ifdef POSIX
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "tier0/memdbgon.h"
|
||||
#include "../../public/tier1/lzmaDecoder.h"
|
||||
#include "C/7zTypes.h"
|
||||
#include "C/LzmaEnc.h"
|
||||
#include "C/LzmaDec.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// Allocator to pass to LZMA functions
|
||||
static void *SzAlloc(void *p, size_t size) { return malloc(size); }
|
||||
static void SzFree(void *p, void *address) { free(address); }
|
||||
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
|
||||
|
||||
// lzma buffers will have a 13 byte trivial header
|
||||
// [0] reserved
|
||||
// [1..4] dictionary size, little endian
|
||||
// [5..8] uncompressed size, little endian low word
|
||||
// [9..12] uncompressed size, little endian high word
|
||||
// [13..] lzma compressed data
|
||||
#define LZMA_ORIGINAL_HEADER_SIZE 13
|
||||
|
||||
SRes CInStreamRam_StaticRead(void *p, void *buf, size_t *size );
|
||||
size_t COutStreamRam_StaticWrite(void *p, const void *buf, size_t size);
|
||||
|
||||
class CInStreamRam : public ISeqInStream
|
||||
{
|
||||
const Byte *Data;
|
||||
size_t Size;
|
||||
size_t Pos;
|
||||
|
||||
public:
|
||||
void Init(const Byte *data, size_t size)
|
||||
{
|
||||
Data = data;
|
||||
Size = size;
|
||||
Pos = 0;
|
||||
Read = CInStreamRam_StaticRead;
|
||||
}
|
||||
|
||||
SRes DoRead( void *buf, size_t *size )
|
||||
{
|
||||
size_t inSize = *size;
|
||||
UInt32 remain = Size - Pos;
|
||||
if (inSize > remain)
|
||||
inSize = remain;
|
||||
|
||||
for (UInt32 i = 0; i < inSize; i++)
|
||||
((Byte *)buf)[i] = Data[Pos + i];
|
||||
|
||||
Pos += inSize;
|
||||
|
||||
*size = inSize;
|
||||
|
||||
return SZ_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class COutStreamRam: public ISeqOutStream
|
||||
{
|
||||
size_t Size;
|
||||
|
||||
public:
|
||||
Byte *Data;
|
||||
size_t Pos;
|
||||
bool Overflow;
|
||||
|
||||
void Init(Byte *data, size_t size)
|
||||
{
|
||||
Data = data;
|
||||
Size = size;
|
||||
Pos = 0;
|
||||
Overflow = false;
|
||||
Write = COutStreamRam_StaticWrite;
|
||||
}
|
||||
|
||||
size_t DoWrite( const void *buf, size_t size )
|
||||
{
|
||||
UInt32 i;
|
||||
for (i = 0; i < size && Pos < Size; i++)
|
||||
Data[Pos++] = ((const Byte *)buf)[i];
|
||||
if (i != size)
|
||||
{
|
||||
Overflow = true;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
};
|
||||
|
||||
SRes CInStreamRam_StaticRead(void *p, void *buf, size_t *size )
|
||||
{
|
||||
return reinterpret_cast<CInStreamRam *>(p)->DoRead( buf, size );
|
||||
}
|
||||
|
||||
size_t COutStreamRam_StaticWrite(void *p, const void *buf, size_t size)
|
||||
{
|
||||
return reinterpret_cast<COutStreamRam *>(p)->DoWrite( buf, size );
|
||||
}
|
||||
|
||||
SRes
|
||||
LzmaEncode( const Byte *inBuffer,
|
||||
size_t inSize,
|
||||
Byte *outBuffer,
|
||||
size_t outSize,
|
||||
size_t *outSizeProcessed )
|
||||
{
|
||||
// Based on Encode helper in SDK/LzmaUtil
|
||||
*outSizeProcessed = 0;
|
||||
|
||||
const size_t kMinDestSize = LZMA_ORIGINAL_HEADER_SIZE;
|
||||
if ( outSize < kMinDestSize )
|
||||
{
|
||||
return SZ_ERROR_FAIL;
|
||||
}
|
||||
|
||||
CLzmaEncHandle enc;
|
||||
SRes res;
|
||||
CLzmaEncProps props;
|
||||
|
||||
enc = LzmaEnc_Create( &g_Alloc );
|
||||
if ( !enc )
|
||||
{
|
||||
return SZ_ERROR_FAIL;
|
||||
}
|
||||
|
||||
LzmaEncProps_Init( &props );
|
||||
res = LzmaEnc_SetProps( enc, &props );
|
||||
|
||||
if ( res != SZ_OK )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
COutStreamRam outStream;
|
||||
|
||||
outStream.Init( outBuffer, outSize );
|
||||
|
||||
Byte header[LZMA_PROPS_SIZE + 8];
|
||||
size_t headerSize = LZMA_PROPS_SIZE;
|
||||
int i;
|
||||
|
||||
res = LzmaEnc_WriteProperties( enc, header, &headerSize );
|
||||
if ( res != SZ_OK )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// Uncompressed size after properties in header
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
header[headerSize++] = (Byte)(inSize >> (8 * i));
|
||||
}
|
||||
|
||||
if ( outStream.DoWrite( header, headerSize ) != headerSize )
|
||||
{
|
||||
res = SZ_ERROR_WRITE;
|
||||
}
|
||||
else if ( res == SZ_OK )
|
||||
{
|
||||
CInStreamRam inStream;
|
||||
inStream.Init( inBuffer, inSize );
|
||||
res = LzmaEnc_Encode( enc, &outStream, &inStream, NULL, &g_Alloc, &g_Alloc );
|
||||
|
||||
if ( outStream.Overflow )
|
||||
{
|
||||
res = SZ_ERROR_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outSizeProcessed = outStream.Pos;
|
||||
}
|
||||
}
|
||||
|
||||
LzmaEnc_Destroy( enc, &g_Alloc, &g_Alloc );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Encoding glue. Returns non-null Compressed buffer if successful.
|
||||
// Caller must free.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char *LZMA_Compress( unsigned char *pInput,
|
||||
unsigned int inputSize,
|
||||
unsigned int *pOutputSize )
|
||||
{
|
||||
*pOutputSize = 0;
|
||||
|
||||
// using same work buffer calcs as the SDK 105% + 64K
|
||||
unsigned outSize = inputSize/20 * 21 + (1<<16);
|
||||
unsigned char *pOutputBuffer = (unsigned char*)malloc( outSize );
|
||||
if ( !pOutputBuffer )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// compress, skipping past our header
|
||||
size_t compressedSize;
|
||||
int result = LzmaEncode( pInput, inputSize, pOutputBuffer + sizeof( lzma_header_t ), outSize - sizeof( lzma_header_t ), &compressedSize );
|
||||
if ( result != SZ_OK )
|
||||
{
|
||||
Warning( "LZMA encode failed (%i)\n", result );
|
||||
Assert( result == SZ_OK );
|
||||
free( pOutputBuffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// construct our header, strip theirs
|
||||
lzma_header_t *pHeader = (lzma_header_t *)pOutputBuffer;
|
||||
pHeader->id = LZMA_ID;
|
||||
pHeader->actualSize = inputSize;
|
||||
pHeader->lzmaSize = compressedSize - LZMA_ORIGINAL_HEADER_SIZE;
|
||||
memcpy( pHeader->properties, pOutputBuffer + sizeof( lzma_header_t ), LZMA_PROPS_SIZE );
|
||||
|
||||
// shift the compressed data into place
|
||||
memmove( pOutputBuffer + sizeof( lzma_header_t ),
|
||||
pOutputBuffer + sizeof( lzma_header_t ) + LZMA_ORIGINAL_HEADER_SIZE,
|
||||
compressedSize - LZMA_ORIGINAL_HEADER_SIZE );
|
||||
|
||||
// final output size is our header plus compressed bits
|
||||
*pOutputSize = sizeof( lzma_header_t ) + compressedSize - LZMA_ORIGINAL_HEADER_SIZE;
|
||||
|
||||
return pOutputBuffer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Above, but returns null if compression would not yield a size improvement
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char *LZMA_OpportunisticCompress( unsigned char *pInput,
|
||||
unsigned int inputSize,
|
||||
unsigned int *pOutputSize )
|
||||
{
|
||||
unsigned char *pRet = LZMA_Compress( pInput, inputSize, pOutputSize );
|
||||
if ( *pOutputSize <= inputSize )
|
||||
{
|
||||
// compression got worse or stayed the same
|
||||
free( pRet );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pRet;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Decoding glue. Returns TRUE if succesful.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool LZMA_Uncompress( unsigned char *pInBuffer,
|
||||
unsigned char **ppOutBuffer,
|
||||
unsigned int *pOutSize )
|
||||
{
|
||||
*ppOutBuffer = NULL;
|
||||
*pOutSize = 0;
|
||||
|
||||
lzma_header_t *pHeader = (lzma_header_t *)pInBuffer;
|
||||
if ( pHeader->id != LZMA_ID )
|
||||
{
|
||||
// not ours
|
||||
return false;
|
||||
}
|
||||
|
||||
CLzmaDec state;
|
||||
|
||||
LzmaDec_Construct(&state);
|
||||
|
||||
if ( LzmaDec_Allocate(&state, pHeader->properties, LZMA_PROPS_SIZE, &g_Alloc) != SZ_OK )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char *pOutBuffer = (unsigned char *)malloc( pHeader->actualSize );
|
||||
if ( !pOutBuffer )
|
||||
{
|
||||
LzmaDec_Free(&state, &g_Alloc);
|
||||
return false;
|
||||
}
|
||||
|
||||
// These are in/out variables
|
||||
SizeT outProcessed = pHeader->actualSize;
|
||||
SizeT inProcessed = pHeader->lzmaSize;
|
||||
ELzmaStatus status;
|
||||
SRes result = LzmaDecode( (Byte *)pOutBuffer, &outProcessed, (Byte *)(pInBuffer + sizeof( lzma_header_t ) ),
|
||||
&inProcessed, (Byte *)pHeader->properties, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc );
|
||||
|
||||
|
||||
LzmaDec_Free(&state, &g_Alloc);
|
||||
|
||||
if ( result != SZ_OK || pHeader->actualSize != outProcessed )
|
||||
{
|
||||
free( pOutBuffer );
|
||||
return false;
|
||||
}
|
||||
|
||||
*ppOutBuffer = pOutBuffer;
|
||||
*pOutSize = pHeader->actualSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LZMA_IsCompressed( unsigned char *pInput )
|
||||
{
|
||||
lzma_header_t *pHeader = (lzma_header_t *)pInput;
|
||||
if ( pHeader && pHeader->id == LZMA_ID )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// unrecognized
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int LZMA_GetActualSize( unsigned char *pInput )
|
||||
{
|
||||
lzma_header_t *pHeader = (lzma_header_t *)pInput;
|
||||
if ( pHeader && pHeader->id == LZMA_ID )
|
||||
{
|
||||
return pHeader->actualSize;
|
||||
}
|
||||
|
||||
// unrecognized
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user