/Utilities/Compression/Deflaters/DeflaterHuffman.cs
C# | 1141 lines | 746 code | 126 blank | 269 comment | 100 complexity | 0160422a148c39304785d4d1ff431651 MD5 | raw file
Possible License(s): Apache-2.0
- // Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
- // Authors of the original java version: Jochen Hoenicke, John Leuner
- // See http://www.ISeeSharpCode.com for more information.
-
- using System;
-
- namespace Delta.Utilities.Compression.Deflaters
- {
- /// <summary>
- /// This is the DeflaterHuffman class. This class is <i>not</i> thread safe.
- /// This is inherent in the API, due to the split of deflate and setInput.
- /// </summary>
- public class DeflaterHuffman
- {
- #region Tree Class
- /// <summary>
- /// Tree
- /// </summary>
- public class Tree
- {
- #region freqs (Public)
- /// <summary>
- /// Frequencies
- /// </summary>
- public short[] freqs;
- #endregion
-
- #region length (Public)
- /// <summary>
- /// Length
- /// </summary>
- public byte[] length;
- #endregion
-
- #region minNumCodes (Public)
- /// <summary>
- /// Number of codes.
- /// </summary>
- public int minNumCodes;
- #endregion
-
- #region numCodes (Public)
- /// <summary>
- /// Number of codes.
- /// </summary>
- public int numCodes;
- #endregion
-
- #region Private
-
- #region codes (Private)
- private short[] codes;
- #endregion
-
- #region bl_counts (Private)
- private readonly int[] bl_counts;
- #endregion
-
- #region maxLength (Private)
- private readonly int maxLength;
- #endregion
-
- #region dh (Private)
- private readonly DeflaterHuffman dh;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create tree
- /// </summary>
- /// <param name="dh">Dh</param>
- /// <param name="elems">Elems</param>
- /// <param name="minCodes">Min codes</param>
- /// <param name="maxLength">Max length</param>
- public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength)
- {
- this.dh = dh;
- minNumCodes = minCodes;
- this.maxLength = maxLength;
- freqs = new short[elems];
- bl_counts = new int[maxLength];
- }
- #endregion
-
- // Tree(dh, elems, minCodes)
-
- #region Reset (Public)
- /// <summary>
- /// Reset
- /// </summary>
- public void Reset()
- {
- for (int i = 0; i < freqs.Length; i++)
- {
- freqs[i] = 0;
- } // for (int)
- codes = null;
- length = null;
- }
- #endregion
-
- // Reset()
-
- #region WriteSymbol (Public)
- /// <summary>
- /// Write symbol
- /// </summary>
- /// <param name="code">code</param>
- public void WriteSymbol(int code)
- {
- //if (DeflaterConstants.DEBUGGING)
- //{
- // freqs[code]--;
- // // Console.Write("writeSymbol("+freqs.length+","+code+"): ");
- //}
- dh.pending.WriteBits(codes[code] & 0xffff, length[code]);
- }
- #endregion
-
- // WriteSymbol(code)
-
- #region CheckEmpty (Public)
- /// <summary>
- /// Check empty
- /// </summary>
- public void CheckEmpty()
- {
- bool empty = true;
- for (int i = 0; i < freqs.Length; i++)
- {
- if (freqs[i] != 0)
- {
- //Console.WriteLine("freqs["+i+"] == "+freqs[i]);
- empty = false;
- } // if (freqs[i])
- } // for (int)
- if (!empty)
- {
- throw new Exception();
- } // if ()
- //Console.WriteLine("checkEmpty suceeded!");
- }
- #endregion
-
- // CheckEmpty()
-
- #region SetStaticCodes (Public)
- /// <summary>
- /// Set static codes
- /// </summary>
- /// <param name="stCodes">St codes</param>
- /// <param name="stLength">St length</param>
- public void SetStaticCodes(short[] stCodes, byte[] stLength)
- {
- codes = stCodes;
- length = stLength;
- }
- #endregion
-
- // SetStaticCodes(stCodes, stLength)
-
- #region BuildCodes (Public)
- /// <summary>
- /// Build codes
- /// </summary>
- public void BuildCodes()
- {
- //never used: int numSymbols = freqs.Length;
- int[] nextCode = new int[maxLength];
- int code = 0;
- codes = new short[freqs.Length];
-
- //if (DeflaterConstants.DEBUGGING)
- //{
- // //Console.WriteLine("buildCodes: "+freqs.Length);
- //}
-
- for (int bits = 0; bits < maxLength; bits++)
- {
- nextCode[bits] = code;
- code += bl_counts[bits] << (15 - bits);
- //if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("bits: "+(bits+1)+" count: "+bl_counts[bits]
- // +" nextCode: "+code);
- //}
- } // for (bits)
- //if (DeflaterConstants.DEBUGGING && code != 65536) {
- // throw new Exception("Inconsistent bl_counts!");
- //}
-
- for (int i = 0; i < numCodes; i++)
- {
- int bits = length[i];
- if (bits > 0)
- {
- //if (DeflaterConstants.DEBUGGING) {
- // +bits);
- //}
- codes[i] = BitReverse(nextCode[bits - 1]);
- nextCode[bits - 1] += 1 << (16 - bits);
- } // if (bits)
- } // for (int)
- }
- #endregion
-
- // BuildCodes()
-
- // BuildLength(childs)
-
- #region BuildTree (Public)
- /// <summary>
- /// Build tree
- /// </summary>
- public void BuildTree()
- {
- int numSymbols = freqs.Length;
-
- // heap is a priority queue, sorted by frequency, least frequent
- // nodes first. The heap is a binary tree, with the property, that
- // the parent node is smaller than both child nodes. This assures
- // that the smallest node is the first parent.
- //
- // The binary tree is encoded in an array: 0 is root node and
- // the nodes 2*n+1, 2*n+2 are the child nodes of node n.
- int[] heap = new int[numSymbols];
- int heapLen = 0;
- int maxCode = 0;
- for (int n = 0; n < numSymbols; n++)
- {
- int freq = freqs[n];
- if (freq != 0)
- {
- /* Insert n into heap */
- int pos = heapLen++;
- int ppos;
- while (pos > 0 &&
- freqs[heap[ppos = (pos - 1) / 2]] > freq)
- {
- heap[pos] = heap[ppos];
- pos = ppos;
- } // while (pos)
- heap[pos] = n;
-
- maxCode = n;
- } // if (freq)
- } // for (int)
-
- // We could encode a single literal with 0 bits but then we
- // don't see the literals. Therefore we force at least two
- // literals to avoid this case. We don't care about order in
- // this case, both literals get a 1 bit code.
- while (heapLen < 2)
- {
- int node = maxCode < 2
- ? ++maxCode
- : 0;
- heap[heapLen++] = node;
- } // while (heapLen)
-
- numCodes = Math.Max(maxCode + 1, minNumCodes);
-
- int numLeafs = heapLen;
- int[] childs = new int[4 * heapLen - 2];
- int[] values = new int[2 * heapLen - 1];
- int numNodes = numLeafs;
- for (int i = 0; i < heapLen; i++)
- {
- int node = heap[i];
- childs[2 * i] = node;
- childs[2 * i + 1] = -1;
- values[i] = freqs[node] << 8;
- heap[i] = i;
- } // for (int)
-
- // Construct the Huffman tree by repeatedly combining the least two
- // frequent nodes.
- do
- {
- int first = heap[0];
- int last = heap[--heapLen];
-
- // Propagate the hole to the leafs of the heap
- int ppos = 0;
- int path = 1;
-
- while (path < heapLen)
- {
- if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]])
- {
- path++;
- } // if (path)
-
- heap[ppos] = heap[path];
- ppos = path;
- path = path * 2 + 1;
- } // while (path)
-
- // Now propagate the last element down along path. Normally
- // it shouldn't go too deep.
- int lastVal = values[last];
- while ((path = ppos) > 0 &&
- values[heap[ppos = (path - 1) / 2]] > lastVal)
- {
- heap[path] = heap[ppos];
- } // while ()
- heap[path] = last;
-
- int second = heap[0];
-
- // Create a new node father of first and second
- last = numNodes++;
- childs[2 * last] = first;
- childs[2 * last + 1] = second;
- int mindepth = Math.Min(values[first] & 0xff, values[second] & 0xff);
- values[last] = lastVal = values[first] + values[second] - mindepth + 1;
-
- // Again, propagate the hole to the leafs
- ppos = 0;
- path = 1;
-
- while (path < heapLen)
- {
- if (path + 1 < heapLen && values[heap[path]] > values[heap[path + 1]])
- {
- path++;
- } // if (path)
-
- heap[ppos] = heap[path];
- ppos = path;
- path = ppos * 2 + 1;
- } // while (path)
-
- // Now propagate the new element down along path
- while ((path = ppos) > 0 &&
- values[heap[ppos = (path - 1) / 2]] > lastVal)
- {
- heap[path] = heap[ppos];
- } // while ()
- heap[path] = last;
- } while (heapLen > 1);
-
- if (heap[0] != childs.Length / 2 - 1)
- {
- throw new Exception("Weird!");
- } // if (heap[0])
- BuildLength(childs);
- }
- #endregion
-
- // BuildTree()
-
- #region GetEncodedLength (Public)
- /// <summary>
- /// Get encoded length
- /// </summary>
- /// <returns>Int</returns>
- public int GetEncodedLength()
- {
- int len = 0;
- for (int i = 0; i < freqs.Length; i++)
- {
- len += freqs[i] * length[i];
- } // for (int)
- return len;
- }
- #endregion
-
- // GetEncodedLength()
-
- #region CalcBLFreq (Public)
- /// <summary>
- /// Calc BL freq
- /// </summary>
- /// <param name="blTree">Bl tree</param>
- public void CalcBLFreq(Tree blTree)
- {
- // max repeat count
- int max_count;
- // min repeat count
- int min_count;
- // repeat count of the current code
- int count;
- // length of current code
- int curlen = -1;
-
- int i = 0;
- while (i < numCodes)
- {
- count = 1;
- int nextlen = length[i];
- if (nextlen == 0)
- {
- max_count = 138;
- min_count = 3;
- } // if (nextlen)
- else
- {
- max_count = 6;
- min_count = 3;
- if (curlen != nextlen)
- {
- blTree.freqs[nextlen]++;
- count = 0;
- } // if (curlen)
- } // else
- curlen = nextlen;
- i++;
-
- while (i < numCodes &&
- curlen == length[i])
- {
- i++;
- if (++count >= max_count)
- {
- break;
- } // if (++count)
- } // while (i)
-
- if (count < min_count)
- {
- blTree.freqs[curlen] += (short)count;
- } // if (count)
- else if (curlen != 0)
- {
- blTree.freqs[Rep3_6]++;
- } // else if
- else if (count <= 10)
- {
- blTree.freqs[Rep3_10]++;
- } // else if
- else
- {
- blTree.freqs[Rep11_138]++;
- } // else
- } // while (i)
- }
- #endregion
-
- // CalcBLFreq(blTree)
-
- #region WriteTree (Public)
- /// <summary>
- /// Write tree
- /// </summary>
- /// <param name="blTree">Bl tree</param>
- public void WriteTree(Tree blTree)
- {
- // max repeat count
- int max_count;
- // min repeat count
- int min_count;
- // repeat count of the current code
- int count;
- // length of current code
- int curlen = -1;
-
- int i = 0;
- while (i < numCodes)
- {
- count = 1;
- int nextlen = length[i];
- if (nextlen == 0)
- {
- max_count = 138;
- min_count = 3;
- } // if (nextlen)
- else
- {
- max_count = 6;
- min_count = 3;
- if (curlen != nextlen)
- {
- blTree.WriteSymbol(nextlen);
- count = 0;
- } // if (curlen)
- } // else
- curlen = nextlen;
- i++;
-
- while (i < numCodes &&
- curlen == length[i])
- {
- i++;
- if (++count >= max_count)
- {
- break;
- } // if (++count)
- } // while (i)
-
- if (count < min_count)
- {
- while (count-- > 0)
- {
- blTree.WriteSymbol(curlen);
- } // while (count--)
- } // if (count)
- else if (curlen != 0)
- {
- blTree.WriteSymbol(Rep3_6);
- dh.pending.WriteBits(count - 3, 2);
- } // else if
- else if (count <= 10)
- {
- blTree.WriteSymbol(Rep3_10);
- dh.pending.WriteBits(count - 3, 3);
- } // else if
- else
- {
- blTree.WriteSymbol(Rep11_138);
- dh.pending.WriteBits(count - 11, 7);
- } // else
- } // while (i)
- }
- #endregion
-
- #region Methods (Private)
-
- #region BuildLength
- /// <summary>
- /// Build length
- /// </summary>
- /// <param name="childs">Childs</param>
- private void BuildLength(int[] childs)
- {
- length = new byte[freqs.Length];
- int numNodes = childs.Length / 2;
- int numLeafs = (numNodes + 1) / 2;
- int overflow = 0;
-
- for (int i = 0; i < maxLength; i++)
- {
- bl_counts[i] = 0;
- } // for (int)
-
- // First calculate optimal bit lengths
- int[] lengths = new int[numNodes];
- lengths[numNodes - 1] = 0;
-
- for (int i = numNodes - 1; i >= 0; i--)
- {
- if (childs[2 * i + 1] != -1)
- {
- int bitLength = lengths[i] + 1;
- if (bitLength > maxLength)
- {
- bitLength = maxLength;
- overflow++;
- } // if (bitLength)
- lengths[childs[2 * i]] = lengths[childs[2 * i + 1]] = bitLength;
- } // if (childs[2)
- else
- {
- // A leaf node
- int bitLength = lengths[i];
- bl_counts[bitLength - 1]++;
- length[childs[2 * i]] = (byte)lengths[i];
- } // else
- } // for (int)
-
- //if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("Tree "+freqs.Length+" lengths:");
- // for (int i=0; i < numLeafs; i++) {
- // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
- // + " len: "+length[childs[2*i]]);
- // }
- //}
-
- if (overflow == 0)
- {
- return;
- } // if (overflow)
-
- int incrBitLen = maxLength - 1;
- do
- {
- // Find the first bit length which could increase:
- while (bl_counts[--incrBitLen] == 0)
- {
- ;
- }
-
- // Move this node one down and remove a corresponding
- // amount of overflow nodes.
- do
- {
- bl_counts[incrBitLen]--;
- bl_counts[++incrBitLen]++;
- overflow -= 1 << (maxLength - 1 - incrBitLen);
- } while (overflow > 0 &&
- incrBitLen < maxLength - 1);
- } while (overflow > 0);
-
- // We may have overshot above. Move some nodes from maxLength to
- // maxLength-1 in that case.
- bl_counts[maxLength - 1] += overflow;
- bl_counts[maxLength - 2] -= overflow;
-
- // Now recompute all bit lengths, scanning in increasing
- // frequency. It is simpler to reconstruct all lengths instead of
- // fixing only the wrong ones. This idea is taken from 'ar'
- // written by Haruhiko Okumura.
- //
- // The nodes were inserted with decreasing frequency into the childs
- // array.
- int nodePtr = 2 * numLeafs;
- for (int bits = maxLength; bits != 0; bits--)
- {
- int n = bl_counts[bits - 1];
- while (n > 0)
- {
- int childPtr = 2 * childs[nodePtr++];
- if (childs[childPtr + 1] == -1)
- {
- /* We found another leaf */
- length[childs[childPtr]] = (byte)bits;
- n--;
- } // if (childs[childPtr)
- } // while (n)
- } // for (bits)
- //if (DeflaterConstants.DEBUGGING) {
- // //Console.WriteLine("*** After overflow elimination. ***");
- // for (int i=0; i < numLeafs; i++) {
- // //Console.WriteLine("Node "+childs[2*i]+" freq: "+freqs[childs[2*i]]
- // + " len: "+length[childs[2*i]]);
- // }
- //}
- }
- #endregion
-
- #endregion
-
- // WriteTree(blTree)
- }
- #endregion
-
- #region Constants
- /// <summary>
- /// Buffer size
- /// </summary>
- /// <returns>16384</returns>
- private const int BufferSize = 1 << (DeflaterConstants.DefaultMemoryLevel + 6);
-
- /// <summary>
- /// Litteral number
- /// </summary>
- /// <returns>286</returns>
- private const int LiteralNum = 286;
-
- /// <summary>
- /// Distance number
- /// </summary>
- /// <returns>30</returns>
- private const int DistanceNum = 30;
-
- /// <summary>
- /// Bit length number
- /// </summary>
- /// <returns>19</returns>
- private const int BitLengthNum = 19;
-
- /// <summary>
- /// REP 3_6
- /// </summary>
- /// <returns>16</returns>
- private const int Rep3_6 = 16;
-
- /// <summary>
- /// REP 3_10
- /// </summary>
- /// <returns>18</returns>
- private const int Rep3_10 = 17;
-
- /// <summary>
- /// REP 11_138
- /// </summary>
- /// <returns>18</returns>
- private const int Rep11_138 = 18;
-
- /// <summary>
- /// EOF Symbol
- /// </summary>
- /// <returns>256</returns>
- private const int EofSymbol = 256;
-
- /// <summary>
- /// BL Order
- /// </summary>
- private static readonly int[] BLOrder =
- {
- 16,
- 17,
- 18,
- 0,
- 8,
- 7,
- 9,
- 6,
- 10,
- 5,
- 11,
- 4,
- 12,
- 3,
- 13,
- 2,
- 14,
- 1,
- 15
- };
-
- /// <summary>
- /// Bit 4 reverse
- /// </summary>
- private static readonly byte[] Bit4Reverse =
- {
- 0,
- 8,
- 4,
- 12,
- 2,
- 10,
- 6,
- 14,
- 1,
- 9,
- 5,
- 13,
- 3,
- 11,
- 7,
- 15
- };
-
- private static readonly short[] staticLCodes;
-
- private static readonly byte[] staticLLength;
-
- private static readonly short[] staticDCodes;
-
- private static readonly byte[] staticDLength;
- #endregion
-
- #region BitReverse (Static)
- /// <summary>
- /// Reverse the bits of a 16 bit value.
- /// </summary>
- /// <param name="toReverse">Value to reverse bits</param>
- /// <returns>Value with bits reversed</returns>
- public static short BitReverse(int toReverse)
- {
- return (short)(Bit4Reverse[toReverse & 0xF] << 12 |
- Bit4Reverse[(toReverse >> 4) & 0xF] << 8 |
- Bit4Reverse[(toReverse >> 8) & 0xF] << 4 |
- Bit4Reverse[toReverse >> 12]);
- }
- #endregion
-
- #region pending (Public)
- /// <summary>
- /// Pending buffer to use
- /// </summary>
- public DeflaterPending pending;
- #endregion
-
- #region Private
-
- #region literalTree (Private)
- private readonly Tree literalTree;
- #endregion
-
- #region distTree (Private)
- private readonly Tree distTree;
- #endregion
-
- #region blTree (Private)
- private readonly Tree blTree;
- #endregion
-
- #region d_buf (Private)
- private readonly short[] d_buf;
- #endregion
-
- #region l_buf (Private)
- private readonly byte[] l_buf;
- #endregion
-
- #region last_lit (Private)
- private int last_lit;
- #endregion
-
- #region extra_bits (Private)
- private int extra_bits;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create deflater huffman
- /// </summary>
- static DeflaterHuffman()
- {
- // See RFC 1951 3.2.6
- // Literal codes
- staticLCodes = new short[LiteralNum];
- staticLLength = new byte[LiteralNum];
- int i = 0;
- while (i < 144)
- {
- staticLCodes[i] = BitReverse((0x030 + i) << 8);
- staticLLength[i++] = 8;
- } // while (i)
- while (i < 256)
- {
- staticLCodes[i] = BitReverse((0x190 - 144 + i) << 7);
- staticLLength[i++] = 9;
- } // while (i)
- while (i < 280)
- {
- staticLCodes[i] = BitReverse((0x000 - 256 + i) << 9);
- staticLLength[i++] = 7;
- } // while (i)
- while (i < LiteralNum)
- {
- staticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8);
- staticLLength[i++] = 8;
- } // while (i)
-
- // Distant codes
- staticDCodes = new short[DistanceNum];
- staticDLength = new byte[DistanceNum];
- for (i = 0; i < DistanceNum; i++)
- {
- staticDCodes[i] = BitReverse(i << 11);
- staticDLength[i] = 5;
- } // for (i)
- }
-
- // DeflaterHuffman()
-
- /// <summary>
- /// Construct instance with pending buffer
- /// </summary>
- /// <param name="pending">Pending buffer to use</param>
- public DeflaterHuffman(DeflaterPending pending)
- {
- this.pending = pending;
-
- literalTree = new Tree(this, LiteralNum, 257, 15);
- distTree = new Tree(this, DistanceNum, 1, 15);
- blTree = new Tree(this, BitLengthNum, 4, 7);
-
- d_buf = new short[BufferSize];
- l_buf = new byte[BufferSize];
- }
- #endregion
-
- #region Reset (Public)
- /// <summary>
- /// Reset internal state
- /// </summary>
- public void Reset()
- {
- last_lit = 0;
- extra_bits = 0;
- literalTree.Reset();
- distTree.Reset();
- blTree.Reset();
- }
- #endregion
-
- #region SendAllTrees (Public)
- /// <summary>
- /// Write all trees to pending buffer
- /// </summary>
- public void SendAllTrees(int blTreeCodes)
- {
- blTree.BuildCodes();
- literalTree.BuildCodes();
- distTree.BuildCodes();
- pending.WriteBits(literalTree.numCodes - 257, 5);
- pending.WriteBits(distTree.numCodes - 1, 5);
- pending.WriteBits(blTreeCodes - 4, 4);
- for (int rank = 0; rank < blTreeCodes; rank++)
- {
- pending.WriteBits(blTree.length[BLOrder[rank]], 3);
- } // for (rank)
- literalTree.WriteTree(blTree);
- distTree.WriteTree(blTree);
- }
- #endregion
-
- #region CompressBlock (Public)
- /// <summary>
- /// Compress current buffer writing data to pending buffer
- /// </summary>
- public void CompressBlock()
- {
- for (int i = 0; i < last_lit; i++)
- {
- int litlen = l_buf[i] & 0xff;
- int dist = d_buf[i];
- if (dist-- != 0)
- {
- int lc = Lcode(litlen);
- literalTree.WriteSymbol(lc);
-
- int bits = (lc - 261) / 4;
- if (bits > 0 && bits <= 5)
- {
- pending.WriteBits(litlen & ((1 << bits) - 1), bits);
- } // if (bits)
-
- int dc = Dcode(dist);
- distTree.WriteSymbol(dc);
-
- bits = dc / 2 - 1;
- if (bits > 0)
- {
- pending.WriteBits(dist & ((1 << bits) - 1), bits);
- } // if (bits)
- } // if (dist--)
- else
- {
- literalTree.WriteSymbol(litlen);
- } // else
- } // for (int)
- literalTree.WriteSymbol(EofSymbol);
- }
- #endregion
-
- #region FlushStoredBlock (Public)
- /// <summary>
- /// Flush block to output with no compression
- /// </summary>
- /// <param name="stored">Data to write</param>
- /// <param name="storedOffset">Index of first byte to write</param>
- /// <param name="storedLength">Count of bytes to write</param>
- /// <param name="lastBlock">True if this is the last block</param>
- public void FlushStoredBlock(byte[] stored, int storedOffset,
- int storedLength, bool lastBlock)
- {
- pending.WriteBits((DeflaterConstants.StoredBlock << 1) +
- (lastBlock
- ? 1
- : 0), 3);
- pending.AlignToByte();
- pending.WriteShort(storedLength);
- pending.WriteShort(~storedLength);
- pending.WriteBlock(stored, storedOffset, storedLength);
- Reset();
- }
- #endregion
-
- #region FlushBlock (Public)
- /// <summary>
- /// Flush block to output with compression
- /// </summary>
- /// <param name="stored">Data to flush</param>
- /// <param name="storedOffset">Index of first byte to flush</param>
- /// <param name="storedLength">Count of bytes to flush</param>
- /// <param name="lastBlock">True if this is the last block</param>
- public void FlushBlock(byte[] stored, int storedOffset,
- int storedLength, bool lastBlock)
- {
- literalTree.freqs[EofSymbol]++;
-
- // Build trees
- literalTree.BuildTree();
- distTree.BuildTree();
-
- // Calculate bitlen frequency
- literalTree.CalcBLFreq(blTree);
- distTree.CalcBLFreq(blTree);
-
- // Build bitlen tree
- blTree.BuildTree();
-
- int blTreeCodes = 4;
- for (int i = 18; i > blTreeCodes; i--)
- {
- if (blTree.length[BLOrder[i]] > 0)
- {
- blTreeCodes = i + 1;
- } // if (blTree.length[BLOrder[i]])
- } // for (int)
- int opt_len = 14 + blTreeCodes * 3 + blTree.GetEncodedLength() +
- literalTree.GetEncodedLength() + distTree.GetEncodedLength() +
- extra_bits;
-
- int static_len = extra_bits;
- for (int i = 0; i < LiteralNum; i++)
- {
- static_len += literalTree.freqs[i] * staticLLength[i];
- } // for (int)
- for (int i = 0; i < DistanceNum; i++)
- {
- static_len += distTree.freqs[i] * staticDLength[i];
- } // for (int)
- if (opt_len >= static_len)
- {
- // Force static trees
- opt_len = static_len;
- } // if (opt_len)
-
- if (storedOffset >= 0 && storedLength + 4 < opt_len >> 3)
- {
- // Store Block
- FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
- } // if (storedOffset)
- else if (opt_len == static_len)
- {
- // Encode with static tree
- pending.WriteBits((DeflaterConstants.StaticTrees << 1) +
- (lastBlock
- ? 1
- : 0), 3);
- literalTree.SetStaticCodes(staticLCodes, staticLLength);
- distTree.SetStaticCodes(staticDCodes, staticDLength);
- CompressBlock();
- Reset();
- } // else if
- else
- {
- // Encode with dynamic tree
- pending.WriteBits((DeflaterConstants.DynamicTrees << 1) +
- (lastBlock
- ? 1
- : 0), 3);
- SendAllTrees(blTreeCodes);
- CompressBlock();
- Reset();
- } // else
- }
- #endregion
-
- #region IsFull (Public)
- /// <summary>
- /// Get value indicating if internal buffer is full
- /// </summary>
- /// <returns>true if buffer is full</returns>
- public bool IsFull()
- {
- return last_lit >= BufferSize;
- }
- #endregion
-
- #region TallyLit (Public)
- /// <summary>
- /// Add literal to buffer
- /// </summary>
- /// <param name="lit"></param>
- /// <returns>Value indicating internal buffer is full</returns>
- public bool TallyLit(int lit)
- {
- d_buf[last_lit] = 0;
- l_buf[last_lit++] = (byte)lit;
- literalTree.freqs[lit]++;
- return IsFull();
- }
- #endregion
-
- #region TallyDist (Public)
- /// <summary>
- /// Add distance code and length to literal and distance trees
- /// </summary>
- /// <param name="dist">Distance code</param>
- /// <param name="len">Length</param>
- /// <returns>Value indicating if internal buffer is full</returns>
- public bool TallyDist(int dist, int len)
- {
- d_buf[last_lit] = (short)dist;
- l_buf[last_lit++] = (byte)(len - 3);
-
- int lc = Lcode(len - 3);
- literalTree.freqs[lc]++;
- if (lc >= 265 && lc < 285)
- {
- extra_bits += (lc - 261) / 4;
- } // if (lc)
-
- int dc = Dcode(dist - 1);
- distTree.freqs[dc]++;
- if (dc >= 4)
- {
- extra_bits += dc / 2 - 1;
- } // if (dc)
- return IsFull();
- }
- #endregion
-
- #region Methods (Private)
-
- #region Lcode
- /// <summary>
- /// Lcode
- /// </summary>
- /// <param name="len">Len</param>
- /// <returns>Int</returns>
- private int Lcode(int len)
- {
- if (len == 255)
- {
- return 285;
- } // if (len)
-
- int code = 257;
- while (len >= 8)
- {
- code += 4;
- len >>= 1;
- } // while (len)
- return code + len;
- }
- #endregion
-
- // Lcode(len)
-
- #region Dcode
- /// <summary>
- /// Dcode
- /// </summary>
- /// <param name="distance">Distance</param>
- /// <returns>Int</returns>
- private int Dcode(int distance)
- {
- int code = 0;
- while (distance >= 4)
- {
- code += 2;
- distance >>= 1;
- } // while (distance)
- return code + distance;
- }
- #endregion
-
- #endregion
- }
- }