Rev 4 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "hippack.h"
#include <math.h>
#include <stdio.h>
#include <crtdbg.h>
#include "LiteralHuffTree.h"
#include "CRC32.h"
#include <cstring>
// #pragma optimize( "", off )
//
// constants/macros
//
#define BUFF ((PBYTE)m_pBuff)
HipPack::HipPack( void* pInBuff, DWORD cbInBuff )
{
//
// member variable initializations
//
this->m_pBuff = pInBuff;
this->m_cbBuff = cbInBuff;
m_pOut = NULL;
m_pbyValidHEntries = NULL;
m_Callback = NULL;
}
HipPack::~HipPack()
{
Dispose();
}
//
// Purpose:
// Perform all class-internal cleanups
//
void HipPack::Dispose()
{
FreeOutBuff();
return;
}
//
// Purpose:
// Deallocate output buffer's member if allocated
//
void HipPack::FreeOutBuff()
{
if ( m_pOut ) // sth allocated ?
{
free( m_pOut );
m_pOut = NULL;
}
return;
}
//
// Purpose:
// Stamps the decompressed data block into a buffer
// and returns its pointer and size
//
// Returns:
// FALSE - not enough memory
//
BOOL HipPack::PerformDecompression( OUT void** ppCompBlock, OUT DWORD* pdwcbBlock )
{
BYTE* p, *pAlloc;
DWORD dwcbMax, cbOut, cbRef, dwDelta;
BYTE byChar;
PByteReader reader;
LiteralHuffTree tree;
PHIP_HEADER pHdr;
BYTE byCBIteration = 0;
//
// allocate enough memory
//
FreeOutBuff();
pHdr = (PHIP_HEADER)m_pBuff;
dwcbMax = pHdr->cbUncompressed;
pAlloc = p = (PBYTE)malloc( dwcbMax );
if ( !p )
return FALSE; // ERR
#define BUFF ((PBYTE)m_pBuff)
//
// get Huffman table
//
DWORD cbHuffTbl;
// cbHuffTbl = tree.RipEmittedTree(
// BUFF + sizeof(HIP_HEADER), m_cbBuff - sizeof(HIP_HEADER) );
tree.GenerateAdaptiveModel();
cbHuffTbl = 0;
bool notdone = false;
//
// Decompress !
//
cbOut = 0;
reader = new ByteReader(
MakePtr( PVOID, m_pBuff, sizeof(HIP_HEADER) + cbHuffTbl ),
m_cbBuff - sizeof(HIP_HEADER) + cbHuffTbl );
DWORD dwHuffIteration = 0;
while( cbOut < dwcbMax )
{
if ( m_Callback )
{
byCBIteration++;
if ( byCBIteration == HIP_ITERATION_FOR_CALLBACK || cbOut == dwcbMax )
{
byCBIteration = 0;
if ( !m_Callback( cbOut, dwcbMax ) )
{
notdone = true;
break;
}
}
}
// firstly we read the indicator bit
switch( reader->ReadBit() )
{
case HP_LITERAL_PREFIX:
//
// grab a literal from the compressed buffer
//
byChar = (BYTE)tree.QueryLiteralByBitSequence( reader );
*p = byChar;
// adapt the Huffman tree
tree.m_dwOccurr[ byChar ]++;
dwHuffIteration++;
if ( dwHuffIteration % HP_HUFF_ADAPT_ITERATION == 0 )
tree.GenerateWithOccurrences();
++p;
++cbOut;
break;
case HP_PTRSIZE_PREFIX:
//
// grab a ptr/size pair from the compressed buffer
//
switch( reader->ReadBit() )
{
case 0: // short ref
dwDelta = reader->ReadBits( HP_SHORTREF_PTR_BIT_COUNT );
if ( dwDelta == 0 )
{
//
// decode a literal block
//
DWORD cb = GammaDecodeLength( reader ) - 2 + HP_MIN_LITERALS_IN_BLOCK;
for ( UINT i = 0; i < cb; i++ )
{
BYTE by = reader->ReadByte();
p[i] = by;
}
cbRef = cb;
}
else
{
//
// decode usual short reference
//
cbRef = reader->ReadBits( 2 ) + 2;
}
break;
case 1: // normal ref
DWORD cbitBase;
if ( cbOut > HP_BASE3_WIN )
cbitBase = HP_BASE3;
if ( cbOut > HP_BASE2_WIN )
cbitBase = HP_BASE2;
if ( cbOut > HP_BASE1_WIN )
cbitBase = HP_BASE1;
else
cbitBase = HP_INITAL_BASE;
dwDelta = GammaDecodeDistance( reader, cbitBase ) + HP_NORMALREF_BASE;
DWORD dwSizeInc;
if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX4 )
dwSizeInc = 4;
else if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX3 )
dwSizeInc = 3;
else if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX2 )
dwSizeInc = 2;
else
dwSizeInc = 1;
cbRef = GammaDecodeLength( reader ) + dwSizeInc;
break;
}
// paste the referenced bytes a P
if ( dwDelta != 0 )
MyMemCpy( p, (void*)((DWORD)p - dwDelta), cbRef );
// adjust vars
p += cbRef;
cbOut += cbRef;
break;
}
}
//
// check CRC32
//
if ( !notdone )
{
DWORD dwCurCRC = CRC32::Generate( pAlloc, cbOut );
if ( dwCurCRC != pHdr->CRC )
notdone = true;
}
//
// handle output variables
//
*pdwcbBlock = cbOut;
*ppCompBlock = pAlloc;
//
// tidy up
//
delete reader;
if ( m_pbyValidHEntries )
delete [] m_pbyValidHEntries;
return !notdone;
}
//
// Purpose:
// Decode Gamma encoded delta
//
DWORD HipPack::GammaDecodeDistance( PByteReader reader, DWORD dwcBaseBits )
{
DWORD dwValue = GammaDecodeLength( reader ) - 2;
dwValue <<= dwcBaseBits;
dwValue |= reader->ReadBits( dwcBaseBits );
return dwValue;
}
//
// Purpose:
// Decode gamma encoded length
//
DWORD HipPack::GammaDecodeLength( PByteReader reader )
{
DWORD dwValue = 1; // MSB always 1
do
{
dwValue <<= 1;
dwValue |= reader->ReadBit();
}
while( reader->ReadBit() != 0);
return dwValue;
}
//
// Returns:
// The address of the callback that was set before
//
hpCompressCallback HipPack::SetCallback( hpCompressCallback proc )
{
hpCompressCallback procOldCB = m_Callback;
m_Callback = proc;
return procOldCB;
}
// Remarks:
// Because the memcpy runtime function performs special operations
// when pSrc + cb > pDest - the memory regions overlap - we hold it
// simply - thus working - and do a REP MOVSB by hand
//
void HipPack::MyMemCpy( void* pDest, const void* pSrc, DWORD cb )
{
#ifdef _WIN64
std::memcpy(pDest, pSrc, cb);
#else
__asm
{
mov esi, pSrc
mov edi, pDest
mov ecx, cb
rep movsb
}
return;
#endif
}
#undef BUFF