sources/huffman/huffcodec.cpp

changeset 76
6de6d9a64ebd
parent 75
5f8a03274d75
child 77
32ef969adeed
equal deleted inserted replaced
75:5f8a03274d75 76:6de6d9a64ebd
1 /*
2 * skulltag::HuffmanCodec class - Huffman encoder and decoder.
3 *
4 * Copyright 2009 Timothy Landers
5 * email: code.vortexcortex@gmail.com
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include "huffcodec.h"
27
28 /** Prevents naming convention problems via encapsulation. */
29 namespace skulltag {
30
31 // HuffmanCodec Implementation
32
33 /** Reverses the order of bits in a byte.
34 * EG: The statement <code>reverseMap[0xAF] == 0xF5</code> is <code>true</code>. <br>
35 * The index <code>10101111</code> stores the reverse value: <code>11110101</code>. <br>
36 * Note: One array lookup is much faster than Eight bit manipulating loop iterations. */
37 unsigned char const HuffmanCodec::reverseMap[] = {
38 0,128, 64,192, 32,160, 96,224, 16,144, 80,208, 48,176,112,240,
39 8,136, 72,200, 40,168,104,232, 24,152, 88,216, 56,184,120,248,
40 4,132, 68,196, 36,164,100,228, 20,148, 84,212, 52,180,116,244,
41 12,140, 76,204, 44,172,108,236, 28,156, 92,220, 60,188,124,252,
42 2,130, 66,194, 34,162, 98,226, 18,146, 82,210, 50,178,114,242,
43 10,138, 74,202, 42,170,106,234, 26,154, 90,218, 58,186,122,250,
44 6,134, 70,198, 38,166,102,230, 22,150, 86,214, 54,182,118,246,
45 14,142, 78,206, 46,174,110,238, 30,158, 94,222, 62,190,126,254,
46 1,129, 65,193, 33,161, 97,225, 17,145, 81,209, 49,177,113,241,
47 9,137, 73,201, 41,169,105,233, 25,153, 89,217, 57,185,121,249,
48 5,133, 69,197, 37,165,101,229, 21,149, 85,213, 53,181,117,245,
49 13,141, 77,205, 45,173,109,237, 29,157, 93,221, 61,189,125,253,
50 3,131, 67,195, 35,163, 99,227, 19,147, 83,211, 51,179,115,243,
51 11,139, 75,203, 43,171,107,235, 27,155, 91,219, 59,187,123,251,
52 7,135, 71,199, 39,167,103,231, 23,151, 87,215, 55,183,119,247,
53 15,143, 79,207, 47,175,111,239, 31,159, 95,223, 63,191,127,255
54 };
55
56 /** Creates a new HuffmanCodec
57 * @param treeData char array containing the tree data to use.
58 * @param dataLength number of chars in treeData. */
59 HuffmanCodec::HuffmanCodec(
60 unsigned char const * const treeData,
61 int dataLength
62 ) : Codec() {
63 init();
64 // init code table (256 pointers to Huffman Leaf Nodes.)
65 codeTable = new HuffmanNode*[256];
66 for (int i = 0; i < 256; i++) codeTable[i] = 0;
67 // build root node
68 root = new HuffmanNode;
69 root->bitCount = 0;
70 root->code = 0;
71 root->value = -1;
72 // recursive Huffman tree builder.
73 buildTree( root, treeData, 0, dataLength, codeTable, 256 );
74 huffResourceOwner = true;
75 }
76
77
78 /** Creates a new HuffmanCodec that uses the specified Huffman resources.
79 * @param treeRootNode The root node of a valid huffman tree.
80 * @param leafCodeTable A code lookup table where references to HuffmanNodes are stored with their array index equal to their value.
81 * Note: The tree nodes will not be released upon destruction of this HuffmanCodec. */
82 HuffmanCodec::HuffmanCodec(
83 HuffmanNode * treeRootNode,
84 HuffmanNode ** leafCodeTable
85 ){
86 init();
87 // assign values -- no table building or allocations.
88 root = treeRootNode;
89 codeTable = leafCodeTable;
90 huffResourceOwner = false;
91 }
92
93 /** Checks the ownership state of this HuffmanCodec's resources.
94 * @return true if the tree & code table will be released upon destruction of this HuffmanCodec. <br>
95 * A false return value means this HuffmanCodec is not responsible for deleting its resources. */
96 bool HuffmanCodec::huffmanResourceOwner(){
97 return huffResourceOwner;
98 }
99
100 /** Perform initialization procedures common to all constructors. */
101 void HuffmanCodec::init(){
102 writer = new BitWriter();
103 reverseBits = false;
104 expandable = true;
105 huffResourceOwner = false;
106 }
107
108 /** Increases a codeLength up to the longest Huffman code bit length found in the node or any of its children. <br>
109 * Set to Zero before calling to determine maximum code bit length.
110 * @param node in: The node to begin searching at.
111 * @param codeLength out: Variable to hold the longest code bit length found. */
112 void HuffmanCodec::maxCodeLength( HuffmanNode const * const node, int &codeLength ){
113 // [TL] We must walk each tree node since the codeTable may not contain the set of all leaf nodes.
114 // bail on NULL node (tree is corrupt).
115 if ( node == 0) return;
116 // Recurse across children if they exist.
117 if ( node->branch != 0 ){
118 maxCodeLength( &(node->branch[0]), codeLength );
119 maxCodeLength( &(node->branch[1]), codeLength );
120 } else if ( codeLength < node->bitCount ){
121 // set codeLength if it's smaller than current node's bitCount.
122 codeLength = node->bitCount;
123 }
124 }
125
126 /** Decreases a codeLength to the shortest Huffman code bit length found in the node or any of its children. <br>
127 * Set to Zero before calling to determine minimum code bit length.
128 * @param node in: The node to begin searching at.
129 * @param codeLength out: Variable to hold the longest code bit length found. */
130 void HuffmanCodec::minCodeLength( HuffmanNode const * const node, int &codeLength ){
131 /* [TL] Do not optimize under the assumption child nodes will have longer code Lengths!
132 * Future subclasses may have trees that diverge from Huffman specs. */
133 // bail on NULL node (tree is corrupt).
134 if ( node == 0 ) return;
135 // Recurse across children if they exist.
136 if ( node->branch != 0 ){
137 minCodeLength( &(node->branch[0]), codeLength );
138 minCodeLength( &(node->branch[1]), codeLength );
139 } else if ( (codeLength > node->bitCount) || (codeLength == 0) ) {
140 // set codeLength if it's Zero or larger than current node's bitCount.
141 codeLength = node->bitCount;
142 }
143 }
144
145 /** Recursively builds a Huffman Tree. <br>
146 * The initial root node should have the following field values: <br>
147 * <pre>
148 * bitCount : 0
149 * code : 0
150 * value : -1
151 * branch : 0 (NULL)
152 * </pre>
153 * @param node in/out: branch node of the Huffman Tree.
154 * @param treeData in: char array containing the Huffman Tree's byte representation.
155 * @param index in: Current array element to read the next tree node from.
156 * @param dataLength in: Length of treeData
157 * @param codeTable in/out: array of pointers to HuffmanNode structs.
158 * @param tableLength in: maximum index allowed in the codeTable.
159 * @return the next index to read from or -1 if an error occurs.
160 * */
161 int HuffmanCodec::buildTree(
162 HuffmanNode * node,
163 unsigned char const * const treeData,
164 int index,
165 int dataLength,
166 HuffmanNode ** const &codeTable,
167 int tableLength
168 ){
169 if ( index >= dataLength ) return -1;
170 // Read the branch description bit field
171 int desc = treeData[index];
172 index++;
173
174 // Create the array that will hold L/R child nodes of this branch.
175 node->branch = new HuffmanNode[2];
176
177 // Read the child Nodes for this branch.
178 for ( int i = 0; i < 2; i++ ){
179 // Increase bit count, and update huffman code to match the node's tree position.
180 node->branch[i].bitCount = node->bitCount + 1;
181 node->branch[i].code = (node->code << 1) | i; // appends a 0 or 1 depending on L/R branch.
182 node->branch[i].value = -1; // default value.
183
184 // Test a bit from the branch description (least significant bit == left)
185 if ( (desc & (1 << i)) == 0 ){
186 // Child node is a branch; Recurse.
187 if ( (index = buildTree( &(node->branch[i]), treeData, index, dataLength, codeTable, tableLength )) < 0 ) return -1;
188 // This means the entire left sub tree will be read before the right sub tree gets read.
189 } else {
190 // Read leaf value and map its value/index in the nodes array.
191 if ( index >= dataLength ) return -1;
192 // set the nodes huffman code values.
193 node->branch[i].code = (node->code << 1) | i;
194 node->branch[i].bitCount = node->bitCount+1;
195 node->branch[i].value = treeData[index] & 0xff;
196 // NULL the child node's branch to mark it as a leaf.
197 node->branch[i].branch = 0;
198 // buffer overflow check.
199 if ( (node->branch[i].value >= 0) && (node->branch[i].value <= tableLength ) )
200 // store a pointer to the leaf node into the code table at the location of its byte value.
201 codeTable[ node->branch[i].value ] = &node->branch[i];
202 index++;
203 }
204 }
205
206 return index;
207 }
208
209 /** Decodes data read from an input buffer and stores the result in the output buffer.
210 * @return number of bytes stored in the output buffer or -1 if an error occurs while encoding. */
211 int HuffmanCodec::encode(
212 unsigned char const * const input, /**< in: pointer to the first byte to encode. */
213 unsigned char * const output, /**< out: pointer to an output buffer to store data. */
214 int const &inLength, /**< in: number of bytes of input buffer to encoded. */
215 int const &outLength /**< in: maximum length of data to output. */
216 ) const {
217 // setup the bit buffer to output. if not expandable Limit output to input length.
218 if ( expandable ) writer->outputBuffer( output, outLength );
219 else writer->outputBuffer( output, ((inLength + 1) < outLength) ? inLength + 1 : outLength );
220
221 writer->put( (unsigned char)0 ); // reserve place for padding signal.
222
223 HuffmanNode * node; // temp ptr cache;
224 for ( int i = 0; i < inLength; i++ ){
225 node = codeTable[ 0xff & input[i] ]; //lookup node
226 // Put the huffman code into the bit buffer and bail if error occurs.
227 if ( !writer->put( node->code, node->bitCount ) ) return -1;
228 }
229 int bytesWritten, padding;
230 if ( writer->finish( bytesWritten, padding ) ){
231 // write padding signal byte to begining of stream.
232 output[0] = (unsigned char)padding;
233 } else return -1;
234
235 // Reverse the bit order of each byte (Old Huffman Compatibility Mode)
236 if ( reverseBits ) for ( int i = 1; i < bytesWritten; i++ ){
237 output[i] = reverseMap[ 0xff & output[i] ];
238 }
239
240 return bytesWritten;
241 } // end function encode
242
243 /** Decodes data read from an input buffer and stores the result in the output buffer.
244 * @return number of bytes stored in the output buffer or -1 if an error occurs while decoding. */
245 int HuffmanCodec::decode(
246 unsigned char const * const input, /**< in: pointer to data that needs decoding. */
247 unsigned char * const output, /**< out: pointer to output buffer to store decoded data. */
248 int const &inLength, /**< in: number of bytes of input buffer to read. */
249 int const &outLength /**< in: maximum length of data to output. */
250 ){
251 if ( inLength < 1 ) return 0;
252 int bitsAvailable = ((inLength-1) << 3) - (0xff & input[0]);
253 int rIndex = 1; // read index of input buffer.
254 int wIndex = 0; // write index of output buffer.
255 char byte = 0; // bits of the current byte.
256 int bitsLeft = 0; // bits left in byte;
257
258 HuffmanNode * node = root;
259
260 // Traverse the tree, output values.
261 while ( (bitsAvailable > 0) && (node != 0) ){
262
263 // Get the next byte if we've run out.
264 if ( bitsLeft <= 0 ){
265 byte = input[rIndex++];
266 if ( reverseBits ) byte = reverseMap[ 0xff & byte ];
267 bitsLeft = 8;
268 }
269
270 // Traverse the tree according to the most significant bit.
271 node = &(node->branch[ ((byte >> 7) & 0x01) ]);
272
273 // Is the node Non NULL, and a leaf?
274 if ( (node != 0) && (node->branch == 0) ){
275 // buffer overflow prevention
276 if ( wIndex >= outLength ) return wIndex;
277 // Output leaf node's value and restart traversal at root node.
278 output[ wIndex++ ] = (unsigned char)(node->value & 0xff);
279 node = root;
280 }
281
282 byte <<= 1; // cue up the next bit
283 bitsLeft--; // use up one bit of byte
284 bitsAvailable--; // decrement total bits left
285 }
286
287 return wIndex;
288 } // end function decode
289
290 /** Deletes all sub nodes of a HuffmanNode by traversing and deleting its child nodes.
291 * @param treeNode pointer to a HuffmanNode whos children will be deleted. */
292 void HuffmanCodec::deleteTree( HuffmanNode * treeNode ){
293 if ( treeNode == 0 ) return;
294 if ( treeNode->branch != 0 ){
295 deleteTree( &(treeNode->branch[0]) );
296 deleteTree( &(treeNode->branch[1]) );
297 delete treeNode->branch;
298 }
299 }
300
301 /** Destructor - frees resources. */
302 HuffmanCodec::~HuffmanCodec() {
303 delete writer;
304 //check for resource ownership before deletion
305 if ( huffmanResourceOwner() ){
306 delete codeTable;
307 deleteTree( root );
308 delete root;
309 }
310 }
311
312 /** Enables or Disables backwards bit ordering of bytes.
313 * @param backwards "true" enables reversed bit order bytes, "false" uses standard byte bit ordering. */
314 void HuffmanCodec::reversedBytes( bool backwards ){ reverseBits = backwards; }
315
316 /** Check the state of backwards bit ordering for bytes.
317 * @return true: bits within bytes are reversed. false: bits within bytes are normal. */
318 bool HuffmanCodec::reversedBytes(){ return reverseBits; }
319
320 /** Enable or Disable data expansion during encoding.
321 * @param expandingAllowed "true" allows encoding to expand data. "false" causes failure upon expansion. */
322 void HuffmanCodec::allowExpansion( bool expandingAllowed ){ expandable = expandingAllowed; }
323
324 /** Check the state of data expandability.
325 * @return true: data expansion is allowed. false: data is not allowed to expand. */
326 bool HuffmanCodec::allowExpansion(){ return expandable; }
327
328
329 }; // end namespace skulltag

mercurial