Subversion Repositories spk

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 cycrow 1
#include "literalhufftree.h"
2
#include <math.h>
3
#include <crtdbg.h>
4
#include <stdio.h>
5
#include "ByteReader.h"
6
#include "Macros.h"
7
 
8
//#include "WarnOff.h"
9
 
10
extern bool g_bError;
11
 
12
LiteralHuffTree::LiteralHuffTree(void)
13
{
14
	ZERO( m_dwOccurr );
15
	ZERO( m_tree );
16
	m_ucTreeItems           = 0;
17
}
18
 
19
LiteralHuffTree::~LiteralHuffTree(void)
20
{
21
}
22
 
23
//
24
// Purpose:
25
//   A root procedure
26
//
27
BOOL LiteralHuffTree::Generate( PBYTE buff, DWORD cb )
28
{
29
	if ( !buff || !cb )
30
		return FALSE; // ERR
31
 
32
	GetByteOccurrences( buff, cb );
33
 
34
	BuildInternalTree();
35
 
36
	LinkTreeElements();
37
 
38
	GenerateBitSequences();
39
 
40
	return TRUE; // OK
41
}
42
 
43
//
44
// Purpose:
45
//   A root procedure
46
//
47
 
48
BOOL LiteralHuffTree::GenerateWithOccurrences()
49
{
50
	BuildInternalTree();
51
 
52
	LinkTreeElements();
53
 
54
	return GenerateBitSequences();
55
}
56
 
57
//
58
// Purpose:
59
//   A root procedure
60
//
61
 
62
 
63
BOOL LiteralHuffTree::GenerateAdaptiveModel()
64
{
65
	//
66
	// init the occurrences with 1 for each symbol in the alphabet
67
	//
68
	for ( UINT i = 0; i < ARRAY_ITEMS(m_dwOccurr); i++ )
69
		m_dwOccurr[i] = 1;
70
 
71
	//
72
	// generate the tree, ...
73
	//
74
	BuildInternalTree();
75
 
76
	LinkTreeElements();
77
 
78
	GenerateBitSequences();
79
 
80
	return TRUE; // OK
81
}
82
 
83
 
84
//
85
// Purpose:
86
//   Scan the specified buffer and log the occurrence
87
//   of each byte
88
//
89
 
90
void LiteralHuffTree::GetByteOccurrences( PBYTE pby, DWORD cb )
91
{
92
	ZERO( m_dwOccurr );
93
	while( cb )
94
	{
95
		m_dwOccurr[ *pby ]++;
96
		--cb;
97
		++pby;
98
	}
99
 
100
	return;
101
}
102
 
103
//
104
// Purpose:
105
//   Transfer the occurrences array into m_tree items
106
//
107
void LiteralHuffTree::BuildInternalTree()
108
{
109
	ZERO( m_tree );
110
	for ( UINT u = 0; u < 256; u++ )
111
	{
112
		m_tree[u].id            = u;
113
		m_tree[u].dwcOccurr     = m_dwOccurr[u];
114
		m_tree[u].dwRightId     = (DWORD)-1;        // indicates the end of a branch
115
		m_tree[u].dwLeftId      = (DWORD)-1;        // indicates the end of a branch
116
	}
117
	m_ucTreeItems = 256;
118
 
119
	return;
120
}
121
 
122
//
123
// Purpose:
124
//   Builds the Huffman tree linkage by adding branch items in the chain
125
//
126
// Remarks:
127
//   (biggest probability first)
128
//
129
void LiteralHuffTree::LinkTreeElements()
130
{
131
	PLHT_ITEM   pitem1, pitem2, pitem, pLastLink;
132
	LHT_ITEM    branch, pseudoitem;
133
 
134
	if ( !m_ucTreeItems )
135
		return; // no items in our tree
136
 
137
	pseudoitem.dwcOccurr  = MAXDWORD;
138
	pLastLink             = NULL;
139
	for (;;)
140
	{
141
		//
142
		// search unlinked items with the lowest occurrences
143
		//
144
		pitem1 = NULL;
145
		pitem2 = NULL;
146
		pitem1 = &pseudoitem;
147
		UINT u;
148
		for ( u = 0; u < m_ucTreeItems; u++ )
149
		{
150
			pitem = &m_tree[u];
151
			if ( !pitem->bLinked && pitem->dwcOccurr > 0 && pitem->dwcOccurr < pitem1->dwcOccurr )
152
				pitem1           = pitem;
153
		}
154
		pitem1->bLinked = TRUE; // mark the found items linked !
155
		pitem2 = &pseudoitem;
156
		for ( u = 0; u < m_ucTreeItems; u++ )
157
		{
158
			pitem = &m_tree[u];
159
			if ( !pitem->bLinked && pitem->dwcOccurr > 0 && pitem->dwcOccurr < pitem2->dwcOccurr)
160
				pitem2           = pitem;
161
		}
162
 
163
		pitem2->bLinked = TRUE; // mark the found items linked !
164
 
165
		//
166
		// did we link all items ?
167
		//
168
		if ( pitem1->dwcOccurr == MAXDWORD || pitem2->dwcOccurr == MAXDWORD )
169
		{
170
			if ( pLastLink )
171
				pLastLink->dwDadId = MAXDWORD; // indicates root item
172
			break; // exit for(;;) loop
173
		}
174
 
175
		_ASSERT( m_ucTreeItems < ARRAY_ITEMS(m_tree) );
176
 
177
		//
178
		// add a branch item linking the 2
179
		//
180
		ZERO( branch )
181
		branch.id         = m_ucTreeItems;
182
		branch.bLinked    = FALSE;
183
		branch.dwLeftId   = pitem1->id;
184
		branch.dwRightId  = pitem2->id;
185
		branch.dwcOccurr  = pitem1->dwcOccurr + pitem2->dwcOccurr;
186
 
187
		pitem1->dwDadId   = pitem2->dwDadId = branch.id;
188
 
189
		m_tree[ m_ucTreeItems++ ] = branch;
190
		pLastLink = &m_tree[ m_ucTreeItems - 1 ];
191
	}
192
 
193
	return;
194
}
195
 
196
//
197
// Purpose:
198
//   Trace the tree for non-branch items to find out
199
//   their corresponding bit sequences
200
//
201
bool LiteralHuffTree::GenerateBitSequences()
202
{
203
	PLHT_ITEM  pitem, ptrace, ptrace2;
204
	DWORD      cbitsBig = 0, cbitsSmall = 0xFF;
205
 
206
	for ( UINT u = 0; u < m_ucTreeItems; u++ )
207
	{
208
		pitem = &m_tree[u];
209
		if ( !pitem->dwcOccurr )
210
			continue; // this literal is never used
211
		if ( pitem->dwLeftId == (DWORD)-1 && pitem->dwRightId == (DWORD)-1 )
212
		{
213
			//
214
			// handle a non-branch chain element
215
			//
216
			ptrace = pitem;
217
			while( ptrace->dwDadId != (DWORD)-1 )
218
			{
219
				ptrace2 = &m_tree[ ptrace->dwDadId ];
220
				if ( ptrace->id == ptrace2->dwRightId )
221
					pitem->dwSequence |= HT_RIGHT;
222
				else
223
					pitem->dwSequence |= HT_LEFT;
224
				++pitem->bySequLen;
225
				pitem->dwSequence <<= 1;
226
				ptrace = ptrace2;
227
			}			
228
			pitem->dwSequence >>= 1;
229
 
230
/*			if ( pitem->bySequLen >= 15 )
231
			{
232
				g_bError = true;
233
				return false;
234
			}*/
235
		}
236
	}
237
 
238
	return true;
239
}
240
 
241
//
242
// Purpose:
243
//   Calculates the number of bits that eats to
244
//   biggest occurrence value in the set
245
//
246
//
247
DWORD LiteralHuffTree::GetBitCountForOccurrence()
248
{
249
	DWORD dwMax = 0;
250
 
251
	// get the biggest occurrence value
252
	for ( UINT u = 0; u < 256; u++ )
253
		if ( m_tree[u].dwcOccurr > dwMax )
254
			dwMax = m_tree[u].dwcOccurr;
255
 
256
	// calculate how much bits we'll need to store this value
257
	float f = (float)log((double)dwMax) / (float)log(2.0f);
258
	DWORD c = (DWORD)f;
259
	if ( (float)c < f ) // is f a decimal number ?
260
		c++;
261
 
262
	return c;
263
}
264
 
265
//
266
// Purpose:
267
//   This routine returns the data field of the HT_ITEM structure
268
//   which is identified by reading bits form the ByteReader class
269
//
270
DWORD LiteralHuffTree::QueryLiteralByBitSequence( PByteReader reader )
271
{
272
	PLHT_ITEM pitem; 
273
 
274
	pitem = &m_tree[m_ucTreeItems - 1];
275
	while ( pitem->dwLeftId != -1 && pitem->dwRightId != -1 )
276
		switch( reader->ReadBit() )
277
		{
278
		case HT_LEFT:
279
			pitem = &m_tree[pitem->dwLeftId];
280
			break;
281
 
282
		case HT_RIGHT:
283
			pitem = &m_tree[pitem->dwRightId];
284
			break;
285
		}
286
 
287
	return pitem->id; 
288
}