SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DS_HuffmanEncodingTree.cpp
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2016-2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
16 #include "slikenet/DS_HuffmanEncodingTree.h"
17 #include "slikenet/DS_Queue.h"
18 #include "slikenet/BitStream.h"
19 #include "slikenet/assert.h"
20
21 using namespace SLNet;
22
23 HuffmanEncodingTree::HuffmanEncodingTree()
24 {
25 root = 0;
26 }
27
28 HuffmanEncodingTree::~HuffmanEncodingTree()
29 {
30 FreeMemory();
31 }
32
33 void HuffmanEncodingTree::FreeMemory( void )
34 {
35 if ( root == 0 )
36 return ;
37
38 // Use an in-order traversal to delete the tree
39 DataStructures::Queue<HuffmanEncodingTreeNode *> nodeQueue;
40
41 HuffmanEncodingTreeNode *node;
42
43 nodeQueue.Push( root, _FILE_AND_LINE_ );
44
45 while ( nodeQueue.Size() > 0 )
46 {
47 node = nodeQueue.Pop();
48
49 if ( node->left )
50 nodeQueue.Push( node->left, _FILE_AND_LINE_ );
51
52 if ( node->right )
53 nodeQueue.Push( node->right, _FILE_AND_LINE_ );
54
55 SLNet::OP_DELETE(node, _FILE_AND_LINE_);
56 }
57
58 // Delete the encoding table
59 for ( int i = 0; i < 256; i++ )
60 rakFree_Ex(encodingTable[ i ].encoding, _FILE_AND_LINE_ );
61
62 root = 0;
63 }
64
65
67
68 // Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
69 void HuffmanEncodingTree::GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] )
70 {
71 int counter;
72 HuffmanEncodingTreeNode * node;
73 HuffmanEncodingTreeNode *leafList[ 256 ]; // Keep a copy of the pointers to all the leaves so we can generate the encryption table bottom-up, which is easier
74 // 1. Make 256 trees each with a weight equal to the frequency of the corresponding character
75 DataStructures::LinkedList<HuffmanEncodingTreeNode *> huffmanEncodingTreeNodeList;
76
77 FreeMemory();
78
79 for ( counter = 0; counter < 256; counter++ )
80 {
81 node = SLNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ );
82 node->left = 0;
83 node->right = 0;
84 node->value = (unsigned char) counter;
85 node->weight = frequencyTable[ counter ];
86
87 if ( node->weight == 0 )
88 node->weight = 1; // 0 weights are illegal
89
90 leafList[ counter ] = node; // Used later to generate the encryption table
91
92 InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); // Insert and maintain sort order.
93 }
94
95
96 // 2. While there is more than one tree, take the two smallest trees and merge them so that the two trees are the left and right
97 // children of a new node, where the new node has the weight the sum of the weight of the left and right child nodes.
98 for(;;)
99 {
100 huffmanEncodingTreeNodeList.Beginning();
101 HuffmanEncodingTreeNode *lesser, *greater;
102 lesser = huffmanEncodingTreeNodeList.Pop();
103 greater = huffmanEncodingTreeNodeList.Pop();
104 node = SLNet::OP_NEW<HuffmanEncodingTreeNode>( _FILE_AND_LINE_ );
105 node->left = lesser;
106 node->right = greater;
107 node->weight = lesser->weight + greater->weight;
108 lesser->parent = node; // This is done to make generating the encryption table easier
109 greater->parent = node; // This is done to make generating the encryption table easier
110
111 if ( huffmanEncodingTreeNodeList.Size() == 0 )
112 {
113 // 3. Assign the one remaining node in the list to the root node.
114 root = node;
115 root->parent = 0;
116 break;
117 }
118
119 // Put the new node back into the list at the correct spot to maintain the sort. Linear search time
120 InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList );
121 }
122
123 bool tempPath[ 256 ]; // Maximum path length is 256
124 unsigned short tempPathLength;
125 HuffmanEncodingTreeNode *currentNode;
126 SLNet::BitStream bitStream;
127
128 // Generate the encryption table. From before, we have an array of pointers to all the leaves which contain pointers to their parents.
129 // This can be done more efficiently but this isn't bad and it's way easier to program and debug
130
131 for ( counter = 0; counter < 256; counter++ )
132 {
133 // Already done at the end of the loop and before it!
134 tempPathLength = 0;
135
136 // Set the current node at the leaf
137 currentNode = leafList[ counter ];
138
139 do
140 {
141 if ( currentNode->parent->left == currentNode ) // We're storing the paths in reverse order.since we are going from the leaf to the root
142 tempPath[ tempPathLength++ ] = false;
143 else
144 tempPath[ tempPathLength++ ] = true;
145
146 currentNode = currentNode->parent;
147 }
148
149 while ( currentNode != root );
150
151 // Write to the bitstream in the reverse order that we stored the path, which gives us the correct order from the root to the leaf
152 while ( tempPathLength-- > 0 )
153 {
154 if ( tempPath[ tempPathLength ] ) // Write 1's and 0's because writing a bool will write the BitStream TYPE_CHECKING validation bits if that is defined along with the actual data bit, which is not what we want
155 bitStream.Write1();
156 else
157 bitStream.Write0();
158 }
159
160 // Read data from the bitstream, which is written to the encoding table in bits and bitlength. Note this function allocates the encodingTable[counter].encoding pointer
161 encodingTable[ counter ].bitLength = ( unsigned char ) bitStream.CopyData( &encodingTable[ counter ].encoding );
162
163 // Reset the bitstream for the next iteration
164 bitStream.Reset();
165 }
166 }
167
168 // Pass an array of bytes to array and a preallocated BitStream to receive the output
169 void HuffmanEncodingTree::EncodeArray( unsigned char *input, size_t sizeInBytes, SLNet::BitStream * output )
170 {
171 unsigned counter;
172
173 // For each input byte, Write out the corresponding series of 1's and 0's that give the encoded representation
174 for ( counter = 0; counter < sizeInBytes; counter++ )
175 {
176 output->WriteBits( encodingTable[ input[ counter ] ].encoding, encodingTable[ input[ counter ] ].bitLength, false ); // Data is left aligned
177 }
178
179 // Byte align the output so the unassigned remaining bits don't equate to some actual value
180 if ( output->GetNumberOfBitsUsed() % 8 != 0 )
181 {
182 // Find an input that is longer than the remaining bits. Write out part of it to pad the output to be byte aligned.
183 unsigned char remainingBits = (unsigned char) ( 8 - ( output->GetNumberOfBitsUsed() % 8 ) );
184
185 for ( counter = 0; counter < 256; counter++ )
186 if ( encodingTable[ counter ].bitLength > remainingBits )
187 {
188 output->WriteBits( encodingTable[ counter ].encoding, remainingBits, false ); // Data is left aligned
189 break;
190 }
191
192 #ifdef _DEBUG
193 RakAssert( counter != 256 ); // Given 256 elements, we should always be able to find an input that would be >= 7 bits
194
195 #endif
196
197 }
198 }
199
200 unsigned HuffmanEncodingTree::DecodeArray(SLNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output )
201 {
202 HuffmanEncodingTreeNode * currentNode;
203
204 unsigned outputWriteIndex;
205 outputWriteIndex = 0;
206 currentNode = root;
207
208 // For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
209
210 for ( unsigned counter = 0; counter < sizeInBits; counter++ )
211 {
212 if ( input->ReadBit() == false ) // left!
213 currentNode = currentNode->left;
214 else
215 currentNode = currentNode->right;
216
217 if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
218 {
219
220 if ( outputWriteIndex < maxCharsToWrite )
221 output[ outputWriteIndex ] = currentNode->value;
222
223 outputWriteIndex++;
224
225 currentNode = root;
226 }
227 }
228
229 return outputWriteIndex;
230 }
231
232 // Pass an array of encoded bytes to array and a preallocated BitStream to receive the output
233 void HuffmanEncodingTree::DecodeArray( unsigned char *input, BitSize_t sizeInBits, SLNet::BitStream * output )
234 {
235 HuffmanEncodingTreeNode * currentNode;
236
237 if ( sizeInBits <= 0 )
238 return ;
239
240 SLNet::BitStream bitStream( input, BITS_TO_BYTES(sizeInBits), false );
241
242 currentNode = root;
243
244 // For each bit, go left if it is a 0 and right if it is a 1. When we reach a leaf, that gives us the desired value and we restart from the root
245 for ( unsigned counter = 0; counter < sizeInBits; counter++ )
246 {
247 if ( bitStream.ReadBit() == false ) // left!
248 currentNode = currentNode->left;
249 else
250 currentNode = currentNode->right;
251
252 if ( currentNode->left == 0 && currentNode->right == 0 ) // Leaf
253 {
254 output->WriteBits( &( currentNode->value ), sizeof( char ) * 8, true ); // Use WriteBits instead of Write(char) because we want to avoid TYPE_CHECKING
255 currentNode = root;
256 }
257 }
258 }
259
260 // Insertion sort. Slow but easy to write in this case
261 void HuffmanEncodingTree::InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const
262 {
263 if ( huffmanEncodingTreeNodeList->Size() == 0 )
264 {
265 huffmanEncodingTreeNodeList->Insert( node );
266 return ;
267 }
268
269 huffmanEncodingTreeNodeList->Beginning();
270
271 unsigned counter = 0;
272 for(;;)
273 {
274 if ( huffmanEncodingTreeNodeList->Peek()->weight < node->weight )
275 ++( *huffmanEncodingTreeNodeList );
276 else
277 {
278 huffmanEncodingTreeNodeList->Insert( node );
279 break;
280 }
281
282 // Didn't find a spot in the middle - add to the end
283 if ( ++counter == huffmanEncodingTreeNodeList->Size() )
284 {
285 huffmanEncodingTreeNodeList->End();
286
287 huffmanEncodingTreeNodeList->Add( node )
288
289 ; // Add to the end
290 break;
291 }
292 }
293 }