Subversion Repositories spk

Rev

Rev 4 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 cycrow 1
#include "hippack.h"
2
#include <math.h>
3
#include <stdio.h>
4
#include <crtdbg.h>
5
#include "LiteralHuffTree.h"
6
#include "CRC32.h"
284 cycrow 7
#include <cstring>
4 cycrow 8
 
9
// #pragma optimize( "", off )
10
 
11
//
12
// constants/macros
13
//
14
#define BUFF ((PBYTE)m_pBuff)
15
 
16
HipPack::HipPack( void* pInBuff, DWORD cbInBuff )
17
{
18
	//
19
	// member variable initializations
20
	//
21
	this->m_pBuff      = pInBuff;
22
	this->m_cbBuff     = cbInBuff;
23
 
24
	m_pOut             = NULL;
25
	m_pbyValidHEntries = NULL;
26
	m_Callback         = NULL;
27
}
28
 
29
HipPack::~HipPack()
30
{
31
	Dispose();
32
}
33
 
34
//
35
// Purpose:
36
//   Perform all class-internal cleanups
37
//
38
void HipPack::Dispose()
39
{
40
	FreeOutBuff();
41
 
42
	return;
43
}
44
 
45
//
46
// Purpose:
47
//   Deallocate output buffer's member if allocated
48
//
49
void HipPack::FreeOutBuff()
50
{
51
	if ( m_pOut ) // sth allocated ?
52
	{
53
		free( m_pOut );
54
		m_pOut = NULL;
55
	}
56
 
57
	return;
58
}
59
 
60
//
61
// Purpose:
62
//   Stamps the decompressed data block into a buffer
63
//   and returns its pointer and size
64
//
65
// Returns:
66
//   FALSE - not enough memory
67
//
68
BOOL HipPack::PerformDecompression( OUT void** ppCompBlock, OUT DWORD* pdwcbBlock )
69
{
70
	BYTE*           p, *pAlloc;
71
	DWORD           dwcbMax, cbOut, cbRef, dwDelta;
72
	BYTE            byChar;
73
	PByteReader     reader;
74
	LiteralHuffTree tree;
75
	PHIP_HEADER     pHdr;
76
	BYTE              byCBIteration = 0;
77
 
78
	//
79
	// allocate enough memory
80
	//
81
	FreeOutBuff();
82
	pHdr    = (PHIP_HEADER)m_pBuff;
83
	dwcbMax = pHdr->cbUncompressed;
84
	pAlloc  = p = (PBYTE)malloc( dwcbMax );
85
	if ( !p )
86
		return FALSE; // ERR
87
 
88
#define BUFF ((PBYTE)m_pBuff)
89
 
90
	//
91
	// get Huffman table
92
	//
93
	DWORD cbHuffTbl;
94
//	cbHuffTbl = tree.RipEmittedTree(
95
//		BUFF + sizeof(HIP_HEADER), m_cbBuff - sizeof(HIP_HEADER) );
96
 
97
	tree.GenerateAdaptiveModel();
98
	cbHuffTbl = 0;
99
 
100
	bool notdone = false;
101
	//
102
	// Decompress !
103
	//
104
	cbOut                 = 0;
105
	reader                = new ByteReader(
106
		MakePtr( PVOID, m_pBuff, sizeof(HIP_HEADER) + cbHuffTbl ),
107
		m_cbBuff - sizeof(HIP_HEADER) + cbHuffTbl );
108
	DWORD dwHuffIteration = 0;
109
	while( cbOut < dwcbMax )
110
	{
111
		if ( m_Callback )
112
		{
113
			byCBIteration++;
114
			if ( byCBIteration == HIP_ITERATION_FOR_CALLBACK || cbOut == dwcbMax ) 
115
			{
116
				byCBIteration = 0;
117
				if ( !m_Callback( cbOut, dwcbMax ) )
118
				{
119
					notdone = true;
120
					break;
121
				}
122
			}
123
		}
124
 
125
 
126
		// firstly we read the indicator bit
127
		switch( reader->ReadBit() )
128
		{
129
		case HP_LITERAL_PREFIX:
130
			//
131
			// grab a literal from the compressed buffer
132
			//
133
			byChar = (BYTE)tree.QueryLiteralByBitSequence( reader );
134
			*p = byChar;
135
 
136
			// adapt the Huffman tree
137
			tree.m_dwOccurr[ byChar ]++;
138
			dwHuffIteration++;
139
			if ( dwHuffIteration % HP_HUFF_ADAPT_ITERATION == 0 )
140
				tree.GenerateWithOccurrences();
141
 
142
			++p;
143
			++cbOut;
144
			break;
145
 
146
		case HP_PTRSIZE_PREFIX:
147
			//
148
			// grab a ptr/size pair from the compressed buffer
149
			//
150
			switch( reader->ReadBit() )
151
			{
152
			case 0: // short ref
153
				dwDelta = reader->ReadBits( HP_SHORTREF_PTR_BIT_COUNT );
154
				if ( dwDelta == 0 )
155
				{
156
					//
157
					// decode a literal block
158
					//
159
					DWORD cb = GammaDecodeLength( reader ) - 2 + HP_MIN_LITERALS_IN_BLOCK;
160
					for ( UINT i = 0; i < cb; i++ )
161
					{
162
						BYTE by = reader->ReadByte();
163
						p[i] = by;
164
					}
165
					cbRef    = cb;
166
				}
167
				else
168
				{
169
					//
170
					// decode usual short reference
171
					//
172
                    cbRef   = reader->ReadBits( 2 ) + 2;				
173
				}
174
				break;
175
 
176
			case 1: // normal ref
177
				DWORD cbitBase;
178
				if ( cbOut > HP_BASE3_WIN )
179
					cbitBase = HP_BASE3;
180
				if ( cbOut > HP_BASE2_WIN )
181
					cbitBase = HP_BASE2;
182
				if ( cbOut > HP_BASE1_WIN )
183
					cbitBase = HP_BASE1;
184
				else 
185
					cbitBase = HP_INITAL_BASE;
186
 
187
				dwDelta = GammaDecodeDistance( reader, cbitBase ) + HP_NORMALREF_BASE;
188
 
189
				DWORD dwSizeInc;
190
				if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX4 )
191
					dwSizeInc = 4;
192
				else if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX3 )
193
					dwSizeInc = 3;
194
				else if ( dwDelta >= HP_NREF_SIZE_DEC_INDEX2 )
195
					dwSizeInc = 2;
196
				else
197
					dwSizeInc = 1;
198
                cbRef   = GammaDecodeLength( reader ) + dwSizeInc;
199
				break;
200
			}
201
 
202
			// paste the referenced bytes a P
203
			if ( dwDelta != 0 )
204
                MyMemCpy( p, (void*)((DWORD)p - dwDelta), cbRef );
205
			// adjust vars
206
			p      += cbRef;
207
			cbOut  += cbRef;
208
			break;
209
		}
210
	}
211
 
212
	//
213
	// check CRC32
214
	//
215
	if ( !notdone )
216
	{
217
		DWORD dwCurCRC = CRC32::Generate( pAlloc, cbOut );
218
		if ( dwCurCRC != pHdr->CRC )
219
			notdone = true;
220
	}
221
 
222
	//
223
	// handle output variables
224
	//
225
	*pdwcbBlock   = cbOut;
226
	*ppCompBlock  = pAlloc;
227
 
228
	//
229
	// tidy up
230
	//
231
	delete reader;
232
 
233
	if ( m_pbyValidHEntries )
234
		delete [] m_pbyValidHEntries;
235
 
236
	return !notdone; 
237
}
238
 
239
//
240
// Purpose:
241
//   Decode Gamma encoded delta
242
//
243
DWORD HipPack::GammaDecodeDistance( PByteReader reader, DWORD dwcBaseBits )
244
{
245
	DWORD dwValue = GammaDecodeLength( reader ) - 2;
246
 
247
    dwValue <<= dwcBaseBits; 
248
	dwValue  |= reader->ReadBits( dwcBaseBits );
249
 
250
	return dwValue;
251
}
252
 
253
//
254
// Purpose:
255
//   Decode gamma encoded length
256
//
257
DWORD HipPack::GammaDecodeLength( PByteReader reader )
258
{
259
	DWORD  dwValue = 1; // MSB always 1
260
 
261
	do
262
	{
263
		dwValue <<= 1;
264
		dwValue  |= reader->ReadBit();
265
	}
266
	while( reader->ReadBit() != 0);
267
 
268
	return dwValue;
269
}
270
 
271
//
272
// Returns:
273
//   The address of the callback that was set before
274
//
275
hpCompressCallback HipPack::SetCallback( hpCompressCallback proc )
276
{
277
	hpCompressCallback  procOldCB = m_Callback;
278
 
279
	m_Callback = proc;
280
 
281
	return procOldCB;
282
}
283
 
284
// Remarks:
285
//   Because the memcpy runtime function performs special operations
286
//   when pSrc + cb > pDest - the memory regions overlap - we hold it
287
//   simply - thus working - and do a REP MOVSB by hand
288
//
289
void HipPack::MyMemCpy( void* pDest, const void* pSrc, DWORD cb )
290
{
284 cycrow 291
#ifdef _WIN64
292
	std::memcpy(pDest, pSrc, cb);
293
#else
4 cycrow 294
	__asm
295
	{
296
		mov     esi, pSrc
297
		mov     edi, pDest
298
		mov     ecx, cb
299
		rep     movsb
300
	}
301
	return;
284 cycrow 302
#endif
4 cycrow 303
}
304
 
305
#undef BUFF