• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

DS_HuffmanEncodingTree.cpp

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 #include "DS_HuffmanEncodingTree.h"
00009 #include "DS_Queue.h"
00010 #include "BitStream.h"
00011 #include "RakAssert.h" 
00012 
00013 #ifdef _MSC_VER
00014 #pragma warning( push )
00015 #endif
00016 
00017 HuffmanEncodingTree::HuffmanEncodingTree()
00018 {
00019         root = 0;
00020 }
00021 
00022 HuffmanEncodingTree::~HuffmanEncodingTree()
00023 {
00024         FreeMemory();
00025 }
00026 
00027 void HuffmanEncodingTree::FreeMemory( void )
00028 {
00029         if ( root == 0 )
00030                 return ;
00031 
00032         // Use an in-order traversal to delete the tree
00033         DataStructures::Queue<HuffmanEncodingTreeNode *> nodeQueue;
00034 
00035         HuffmanEncodingTreeNode *node;
00036 
00037         nodeQueue.Push( root, __FILE__, __LINE__  );
00038 
00039         while ( nodeQueue.Size() > 0 )
00040         {
00041                 node = nodeQueue.Pop();
00042 
00043                 if ( node->left )
00044                         nodeQueue.Push( node->left, __FILE__, __LINE__  );
00045 
00046                 if ( node->right )
00047                         nodeQueue.Push( node->right, __FILE__, __LINE__  );
00048 
00049                 RakNet::OP_DELETE(node, __FILE__, __LINE__);
00050         }
00051 
00052         // Delete the encoding table
00053         for ( int i = 0; i < 256; i++ )
00054                 rakFree_Ex(encodingTable[ i ].encoding, __FILE__, __LINE__ );
00055 
00056         root = 0;
00057 }
00058 
00059 
00061 
00062 // Given a frequency table of 256 elements, all with a frequency of 1 or more, generate the tree
00063 void HuffmanEncodingTree::GenerateFromFrequencyTable( unsigned int frequencyTable[ 256 ] )
00064 {
00065         int counter;
00066         HuffmanEncodingTreeNode * node;
00067         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
00068         // 1.  Make 256 trees each with a weight equal to the frequency of the corresponding character
00069         DataStructures::LinkedList<HuffmanEncodingTreeNode *> huffmanEncodingTreeNodeList;
00070 
00071         FreeMemory();
00072 
00073         for ( counter = 0; counter < 256; counter++ )
00074         {
00075                 node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( __FILE__, __LINE__ );
00076                 node->left = 0;
00077                 node->right = 0;
00078                 node->value = (unsigned char) counter;
00079                 node->weight = frequencyTable[ counter ];
00080 
00081                 if ( node->weight == 0 )
00082                         node->weight = 1; // 0 weights are illegal
00083 
00084                 leafList[ counter ] = node; // Used later to generate the encryption table
00085 
00086                 InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList ); // Insert and maintain sort order.
00087         }
00088 
00089 
00090         // 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
00091         // children of a new node, where the new node has the weight the sum of the weight of the left and right child nodes.
00092 #ifdef _MSC_VER
00093 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
00094 #endif
00095         while ( 1 )
00096         {
00097                 huffmanEncodingTreeNodeList.Beginning();
00098                 HuffmanEncodingTreeNode *lesser, *greater;
00099                 lesser = huffmanEncodingTreeNodeList.Pop();
00100                 greater = huffmanEncodingTreeNodeList.Pop();
00101                 node = RakNet::OP_NEW<HuffmanEncodingTreeNode>( __FILE__, __LINE__ );
00102                 node->left = lesser;
00103                 node->right = greater;
00104                 node->weight = lesser->weight + greater->weight;
00105                 lesser->parent = node;  // This is done to make generating the encryption table easier
00106                 greater->parent = node;  // This is done to make generating the encryption table easier
00107 
00108                 if ( huffmanEncodingTreeNodeList.Size() == 0 )
00109                 {
00110                         // 3. Assign the one remaining node in the list to the root node.
00111                         root = node;
00112                         root->parent = 0;
00113                         break;
00114                 }
00115 
00116                 // Put the new node back into the list at the correct spot to maintain the sort.  Linear search time
00117                 InsertNodeIntoSortedList( node, &huffmanEncodingTreeNodeList );
00118         }
00119 
00120         bool tempPath[ 256 ]; // Maximum path length is 256
00121         unsigned short tempPathLength;
00122         HuffmanEncodingTreeNode *currentNode;
00123         RakNet::BitStream bitStream;
00124 
00125         // Generate the encryption table. From before, we have an array of pointers to all the leaves which contain pointers to their parents.
00126         // This can be done more efficiently but this isn't bad and it's way easier to program and debug
00127 
00128         for ( counter = 0; counter < 256; counter++ )
00129         {
00130                 // Already done at the end of the loop and before it!
00131                 tempPathLength = 0;
00132 
00133                 // Set the current node at the leaf
00134                 currentNode = leafList[ counter ];
00135 
00136                 do
00137                 {
00138                         if ( currentNode->parent->left == currentNode )   // We're storing the paths in reverse order.since we are going from the leaf to the root
00139                                 tempPath[ tempPathLength++ ] = false;
00140                         else
00141                                 tempPath[ tempPathLength++ ] = true;
00142 
00143                         currentNode = currentNode->parent;
00144                 }
00145 
00146                 while ( currentNode != root );
00147 
00148                 // 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
00149                 while ( tempPathLength-- > 0 )
00150                 {
00151                         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
00152                                 bitStream.Write1();
00153                         else
00154                                 bitStream.Write0();
00155                 }
00156 
00157                 // 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
00158                 encodingTable[ counter ].bitLength = ( unsigned char ) bitStream.CopyData( &encodingTable[ counter ].encoding );
00159 
00160                 // Reset the bitstream for the next iteration
00161                 bitStream.Reset();
00162         }
00163 }
00164 
00165 // Pass an array of bytes to array and a preallocated BitStream to receive the output
00166 void HuffmanEncodingTree::EncodeArray( unsigned char *input, size_t sizeInBytes, RakNet::BitStream * output )
00167 {               
00168         unsigned counter;
00169 
00170         // For each input byte, Write out the corresponding series of 1's and 0's that give the encoded representation
00171         for ( counter = 0; counter < sizeInBytes; counter++ )
00172         {
00173                 output->WriteBits( encodingTable[ input[ counter ] ].encoding, encodingTable[ input[ counter ] ].bitLength, false ); // Data is left aligned
00174         }
00175 
00176         // Byte align the output so the unassigned remaining bits don't equate to some actual value
00177         if ( output->GetNumberOfBitsUsed() % 8 != 0 )
00178         {
00179                 // Find an input that is longer than the remaining bits.  Write out part of it to pad the output to be byte aligned.
00180                 unsigned char remainingBits = (unsigned char) ( 8 - ( output->GetNumberOfBitsUsed() % 8 ) );
00181 
00182                 for ( counter = 0; counter < 256; counter++ )
00183                         if ( encodingTable[ counter ].bitLength > remainingBits )
00184                         {
00185                                 output->WriteBits( encodingTable[ counter ].encoding, remainingBits, false ); // Data is left aligned
00186                                 break;
00187                         }
00188 
00189 #ifdef _DEBUG
00190                         RakAssert( counter != 256 );  // Given 256 elements, we should always be able to find an input that would be >= 7 bits
00191 
00192 #endif
00193 
00194         }
00195 }
00196 
00197 unsigned HuffmanEncodingTree::DecodeArray( RakNet::BitStream * input, BitSize_t sizeInBits, size_t maxCharsToWrite, unsigned char *output )
00198 {
00199         HuffmanEncodingTreeNode * currentNode;
00200 
00201         unsigned outputWriteIndex;
00202         outputWriteIndex = 0;
00203         currentNode = root;
00204 
00205         // 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
00206 
00207         for ( unsigned counter = 0; counter < sizeInBits; counter++ )
00208         {
00209                 if ( input->ReadBit() == false )   // left!
00210                         currentNode = currentNode->left;
00211                 else
00212                         currentNode = currentNode->right;
00213 
00214                 if ( currentNode->left == 0 && currentNode->right == 0 )   // Leaf
00215                 {
00216 
00217                         if ( outputWriteIndex < maxCharsToWrite )
00218                                 output[ outputWriteIndex ] = currentNode->value;
00219 
00220                         outputWriteIndex++;
00221 
00222                         currentNode = root;
00223                 }
00224         }
00225 
00226         return outputWriteIndex;
00227 }
00228 
00229 // Pass an array of encoded bytes to array and a preallocated BitStream to receive the output
00230 void HuffmanEncodingTree::DecodeArray( unsigned char *input, BitSize_t sizeInBits, RakNet::BitStream * output )
00231 {
00232         HuffmanEncodingTreeNode * currentNode;
00233 
00234         if ( sizeInBits <= 0 )
00235                 return ;
00236 
00237         RakNet::BitStream bitStream( input, BITS_TO_BYTES(sizeInBits), false );
00238 
00239         currentNode = root;
00240 
00241         // 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
00242         for ( unsigned counter = 0; counter < sizeInBits; counter++ )
00243         {
00244                 if ( bitStream.ReadBit() == false )   // left!
00245                         currentNode = currentNode->left;
00246                 else
00247                         currentNode = currentNode->right;
00248 
00249                 if ( currentNode->left == 0 && currentNode->right == 0 )   // Leaf
00250                 {
00251                         output->WriteBits( &( currentNode->value ), sizeof( char ) * 8, true ); // Use WriteBits instead of Write(char) because we want to avoid TYPE_CHECKING
00252                         currentNode = root;
00253                 }
00254         }
00255 }
00256 
00257 // Insertion sort.  Slow but easy to write in this case
00258 void HuffmanEncodingTree::InsertNodeIntoSortedList( HuffmanEncodingTreeNode * node, DataStructures::LinkedList<HuffmanEncodingTreeNode *> *huffmanEncodingTreeNodeList ) const
00259 {
00260         if ( huffmanEncodingTreeNodeList->Size() == 0 )
00261         {
00262                 huffmanEncodingTreeNodeList->Insert( node );
00263                 return ;
00264         }
00265 
00266         huffmanEncodingTreeNodeList->Beginning();
00267 
00268         unsigned counter = 0;
00269 #ifdef _MSC_VER
00270 #pragma warning( disable : 4127 ) // warning C4127: conditional expression is constant
00271 #endif
00272         while ( 1 )
00273         {
00274                 if ( huffmanEncodingTreeNodeList->Peek()->weight < node->weight )
00275                         ++( *huffmanEncodingTreeNodeList );
00276                 else
00277                 {
00278                         huffmanEncodingTreeNodeList->Insert( node );
00279                         break;
00280                 }
00281 
00282                 // Didn't find a spot in the middle - add to the end
00283                 if ( ++counter == huffmanEncodingTreeNodeList->Size() )
00284                 {
00285                         huffmanEncodingTreeNodeList->End();
00286 
00287                         huffmanEncodingTreeNodeList->Add( node )
00288 
00289                                 ; // Add to the end
00290                         break;
00291                 }
00292         }
00293 }
00294 
00295 #ifdef _MSC_VER
00296 #pragma warning( pop )
00297 #endif

Generated on Thu Sep 30 2010 01:27:22 for RakNet by  doxygen 1.7.1