//////////////////////////////////////////////////////////////////// // Build code array from bit length frequency distribution //////////////////////////////////////////////////////////////////// public void BuildCodes() { // build bit length frequency array Array.Clear(BitLengthFreq, 0, BitLengthFreq.Length); for (Int32 Code = 0; Code < MaxUsedCodes; Code++) { if (CodeLength[Code] != 0) { BitLengthFreq[CodeLength[Code] - 1]++; } } // build array of initial code for each block of codes Int32 InitCode = 0; for (Int32 BitNo = 0; BitNo < MaxBitLength; BitNo++) { // save the initial code of the block FirstCode[BitNo] = InitCode; // advance the code by the frequancy times 2 to the power of 15 less bit length InitCode += BitLengthFreq[BitNo] << (15 - BitNo); } // it must add up to 2 ** 16 if (InitCode != 65536) { throw new ApplicationException("Inconsistent bl_counts!"); } // now fill up the entire code array Array.Clear(Codes, 0, Codes.Length); for (Int32 Index = 0; Index < MaxUsedCodes; Index++) { Int32 Bits = CodeLength[Index]; if (Bits > 0) { Codes[Index] = BitReverse.Reverse16Bits(FirstCode[Bits - 1]); FirstCode[Bits - 1] += 1 << (16 - Bits); } } // exit return; }
/// <summary> /// Build code array from bit length frequency distribution /// </summary> /// <exception cref="System.Exception">Inconsistent bl_counts!</exception> public void BuildCodes() { // build bit length frequency array Array.Clear(_bitLengthFreq, 0, _bitLengthFreq.Length); for (int code = 0; code < MaxUsedCodes; code++) { if (_codeLength[code] != 0) { _bitLengthFreq[_codeLength[code] - 1]++; } } // build array of initial code for each block of codes int initCode = 0; for (int bitNo = 0; bitNo < _maxBitLength; bitNo++) { // save the initial code of the block _firstCode[bitNo] = initCode; // advance the code by the frequancy times 2 to the power of 15 less bit length initCode += _bitLengthFreq[bitNo] << (15 - bitNo); } // it must add up to 2 ** 16 if (initCode != 65536) { throw new Exception("Inconsistent bl_counts!"); } // now fill up the entire code array Array.Clear(_codes, 0, _codes.Length); for (int index = 0; index < MaxUsedCodes; index++) { int bits = _codeLength[index]; if (bits > 0) { _codes[index] = BitReverse.Reverse16Bits(_firstCode[bits - 1]); _firstCode[bits - 1] += 1 << (16 - bits); } } }
//////////////////////////////////////////////////////////////////// // Constructs a Huffman tree from the array of code lengths. //////////////////////////////////////////////////////////////////// public void BuildTree ( Byte[] CodeLengths, Int32 Offset, Int32 Length ) { // Build frequency array for bit length 1 to 15 // Note: BitLengthCount[0] will never be used. // All elements of CodeLength are greater than zero. // In other words no code has zero length Array.Clear(BitLengthCount, 0, BitLengthCount.Length); for (Int32 Index = 0; Index < Length; Index++) { BitLengthCount[CodeLengths[Offset + Index]]++; } // build array of inital codes for each group of equal code length Int32 InitCode = 0; for (Int32 Bits = 1; Bits <= MAX_BITLEN; Bits++) { InitialCode[Bits] = InitCode; InitCode += BitLengthCount[Bits] << (16 - Bits); } if (InitCode != 65536) { throw new ApplicationException("Code lengths don't add up properly."); } // longest code bit count Int32 MaxBits; for (MaxBits = MAX_BITLEN; BitLengthCount[MaxBits] == 0; MaxBits--) { ; } // number of hash bits at the root of the decode tree // the longest code but no more than 9 bits Int32 ActiveHashBits = Math.Min(9, MaxBits); // the decoding process is using this bit mask ActiveBitMask = 1 << ActiveHashBits; // hash table at the begining of the tree Array.Clear(ActiveTree, 0, ActiveTree.Length); // pointer to the area above the hash table for codes longer than hash bits Int32 EndPtr = ActiveBitMask; // fill the tree for (Int32 Index = 0; Index < Length; Index++) { // code length in bits Int32 Bits = CodeLengths[Offset + Index]; // code not in use if (Bits == 0) { continue; } // reverse the code from the most significant part to the least significant part of the integer Int32 Code = BitReverse.Reverse16Bits(InitialCode[Bits]); // the number of bits is less than the hash bits // we need to add artificial entries for the missing bits if (Bits < ActiveHashBits) { Int32 NextInc = (1 << Bits); for (Int32 Next = Code; Next < ActiveBitMask; Next += NextInc) { ActiveTree[Next] = ~(Index << 4 | Bits); } } // the number of bits is equal to the hash bits else if (Bits == ActiveHashBits) { ActiveTree[Code] = ~(Index << 4 | Bits); } // the number of bits is greater than the hash bits else { // hash pointer to the start of the tree table Int32 HashPtr = Code & (ActiveBitMask - 1); // get the value at this location Int32 Next = ActiveTree[HashPtr]; // the location is not initialized if (Next == 0) { // get a free node at the area above the hash area and link it to the tree ActiveTree[HashPtr] = EndPtr; Next = EndPtr; EndPtr += 2; } // navigate through the tree above the hash area // add empty nodes as required Int32 BitMaskEnd = 1 << (Bits - 1); for (Int32 BitMask = ActiveBitMask; BitMask != BitMaskEnd; BitMask <<= 1) { // current bit is one, adjust the next pointer if ((Code & BitMask) != 0) { Next++; } // get the value at this location Int32 Next1 = ActiveTree[Next]; // the location was initialized before, continue to follow the path if (Next1 > 0) { Next = Next1; continue; } // add free node from the area above the hash table and link it to the tree ActiveTree[Next] = EndPtr; Next = EndPtr; EndPtr += 2; } // we are now at a leaf point, add the symbol and the number of bits if ((Code & BitMaskEnd) != 0) { Next++; } ActiveTree[Next] = ~(Index << 4 | Bits); } // update initial code for the next code with the same number of bits InitialCode[Bits] += 1 << (16 - Bits); } // exit return; }
/// <summary> /// Constructs a Huffman tree from the array of code lengths. /// </summary> /// <param name="codeLengths">The code lengths.</param> /// <param name="offset">The offset.</param> /// <param name="length">The length.</param> public void BuildTree(byte[] codeLengths, int offset, int length) { // Build frequency array for bit length 1 to 15 // Note: BitLengthCount[0] will never be used. // All elements of CodeLength are greater than zero. // In other words no code has zero length Array.Clear(_bitLengthCount, 0, _bitLengthCount.Length); for (int index = 0; index < length; index++) { _bitLengthCount[codeLengths[offset + index]]++; } // build array of inital codes for each group of equal code length int initCode = 0; for (int bits = 1; bits <= MaxBitlen; bits++) { _initialCode[bits] = initCode; initCode += _bitLengthCount[bits] << (16 - bits); } // Warning // If BitLengthCount array was constructed properly InitCode should be equal to 65536. // During all my initial testing of decompressing ZIP archives coming from other programs // that was the case. I finally run into one file that was compressed by old version // of PKZIP version 2.50 4-15-1998 that the following commented statement threw exception. // I would strongly recomment to anyone making modification to the compression/decompression // software to activate this statement during the testing. // //if(InitCode != 65536) throw new Exception("Code lengths don't add up properly."); // // longest code bit count int maxBits; for (maxBits = MaxBitlen; _bitLengthCount[maxBits] == 0; maxBits--) { } // number of hash bits at the root of the decode tree // the longest code but no more than 9 bits int activeHashBits = Math.Min(9, maxBits); // the decoding process is using this bit mask ActiveBitMask = 1 << activeHashBits; // hash table at the begining of the tree Array.Clear(ActiveTree, 0, ActiveTree.Length); // pointer to the area above the hash table for codes longer than hash bits int endPtr = ActiveBitMask; // fill the tree for (int index = 0; index < length; index++) { // code length in bits int Bits = codeLengths[offset + index]; // code not in use if (Bits == 0) { continue; } // reverse the code from the most significant part to the least significant part of the integer int code = BitReverse.Reverse16Bits(_initialCode[Bits]); // the number of bits is less than the hash bits // we need to add artificial entries for the missing bits if (Bits < activeHashBits) { int nextInc = (1 << Bits); for (int next = code; next < ActiveBitMask; next += nextInc) { ActiveTree[next] = ~(index << 4 | Bits); } } // the number of bits is equal to the hash bits else if (Bits == activeHashBits) { ActiveTree[code] = ~(index << 4 | Bits); } // the number of bits is greater than the hash bits else { // hash pointer to the start of the tree table int hashPtr = code & (ActiveBitMask - 1); // get the value at this location int next = ActiveTree[hashPtr]; // the location is not initialized if (next == 0) { // get a free node at the area above the hash area and link it to the tree ActiveTree[hashPtr] = endPtr; next = endPtr; endPtr += 2; } // navigate through the tree above the hash area // add empty nodes as required int bitMaskEnd = 1 << (Bits - 1); for (int bitMask = ActiveBitMask; bitMask != bitMaskEnd; bitMask <<= 1) { // current bit is one, adjust the next pointer if ((code & bitMask) != 0) { next++; } // get the value at this location int next1 = ActiveTree[next]; // the location was initialized before, continue to follow the path if (next1 > 0) { next = next1; continue; } // add free node from the area above the hash table and link it to the tree ActiveTree[next] = endPtr; next = endPtr; endPtr += 2; } // we are now at a leaf point, add the symbol and the number of bits if ((code & bitMaskEnd) != 0) { next++; } ActiveTree[next] = ~(index << 4 | Bits); } // update initial code for the next code with the same number of bits _initialCode[Bits] += 1 << (16 - Bits); } }