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 bitswitch( reader->ReadBit() ){case HP_LITERAL_PREFIX://// grab a literal from the compressed buffer//byChar = (BYTE)tree.QueryLiteralByBitSequence( reader );*p = byChar;// adapt the Huffman treetree.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 refdwDelta = 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 refDWORD 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;elsecbitBase = 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;elsedwSizeInc = 1;cbRef = GammaDecodeLength( reader ) + dwSizeInc;break;}// paste the referenced bytes a Pif ( dwDelta != 0 )MyMemCpy( p, (void*)((DWORD)p - dwDelta), cbRef );// adjust varsp += 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 1do{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 _WIN64std::memcpy(pDest, pSrc, cb);#else__asm{mov esi, pSrcmov edi, pDestmov ecx, cbrep movsb}return;#endif}#undef BUFF