123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- using System.Diagnostics;
- using System.IO;
- namespace SharpCompress.Compressors.Deflate64
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- internal sealed class HuffmanTree
- {
- internal const int MAX_LITERAL_TREE_ELEMENTS = 288;
- internal const int MAX_DIST_TREE_ELEMENTS = 32;
- internal const int END_OF_BLOCK_CODE = 256;
- internal const int NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS = 19;
- private readonly int _tableBits;
- private readonly short[] _table;
- private readonly short[] _left;
- private readonly short[] _right;
- private readonly byte[] _codeLengthArray;
- #if DEBUG
- private uint[] _codeArrayDebug;
- #endif
- private readonly int _tableMask;
-
- public static HuffmanTree StaticLiteralLengthTree { get; } = new HuffmanTree(GetStaticLiteralTreeLength());
- public static HuffmanTree StaticDistanceTree { get; } = new HuffmanTree(GetStaticDistanceTreeLength());
- public HuffmanTree(byte[] codeLengths)
- {
- Debug.Assert(
- codeLengths.Length == MAX_LITERAL_TREE_ELEMENTS ||
- codeLengths.Length == MAX_DIST_TREE_ELEMENTS ||
- codeLengths.Length == NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS,
- "we only expect three kinds of Length here");
- _codeLengthArray = codeLengths;
- if (_codeLengthArray.Length == MAX_LITERAL_TREE_ELEMENTS)
- {
-
- _tableBits = 9;
- }
- else
- {
-
- _tableBits = 7;
- }
- _tableMask = (1 << _tableBits) - 1;
- _table = new short[1 << _tableBits];
-
-
- _left = new short[2 * _codeLengthArray.Length];
- _right = new short[2 * _codeLengthArray.Length];
- CreateTable();
- }
-
-
- private static byte[] GetStaticLiteralTreeLength()
- {
- byte[] literalTreeLength = new byte[MAX_LITERAL_TREE_ELEMENTS];
- for (int i = 0; i <= 143; i++)
- literalTreeLength[i] = 8;
- for (int i = 144; i <= 255; i++)
- literalTreeLength[i] = 9;
- for (int i = 256; i <= 279; i++)
- literalTreeLength[i] = 7;
- for (int i = 280; i <= 287; i++)
- literalTreeLength[i] = 8;
- return literalTreeLength;
- }
- private static byte[] GetStaticDistanceTreeLength()
- {
- byte[] staticDistanceTreeLength = new byte[MAX_DIST_TREE_ELEMENTS];
- for (int i = 0; i < MAX_DIST_TREE_ELEMENTS; i++)
- {
- staticDistanceTreeLength[i] = 5;
- }
- return staticDistanceTreeLength;
- }
-
-
- private uint[] CalculateHuffmanCode()
- {
- uint[] bitLengthCount = new uint[17];
- foreach (int codeLength in _codeLengthArray)
- {
- bitLengthCount[codeLength]++;
- }
- bitLengthCount[0] = 0;
- uint[] nextCode = new uint[17];
- uint tempCode = 0;
- for (int bits = 1; bits <= 16; bits++)
- {
- tempCode = (tempCode + bitLengthCount[bits - 1]) << 1;
- nextCode[bits] = tempCode;
- }
- uint[] code = new uint[MAX_LITERAL_TREE_ELEMENTS];
- for (int i = 0; i < _codeLengthArray.Length; i++)
- {
- int len = _codeLengthArray[i];
- if (len > 0)
- {
- code[i] = FastEncoderStatics.BitReverse(nextCode[len], len);
- nextCode[len]++;
- }
- }
- return code;
- }
- private void CreateTable()
- {
- uint[] codeArray = CalculateHuffmanCode();
- #if DEBUG
- _codeArrayDebug = codeArray;
- #endif
- short avail = (short)_codeLengthArray.Length;
- for (int ch = 0; ch < _codeLengthArray.Length; ch++)
- {
-
- int len = _codeLengthArray[ch];
- if (len > 0)
- {
-
- int start = (int)codeArray[ch];
- if (len <= _tableBits)
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- int increment = 1 << len;
- if (start >= increment)
- {
- throw new InvalidDataException("Deflate64: invalid Huffman data");
- }
-
- int locs = 1 << (_tableBits - len);
- for (int j = 0; j < locs; j++)
- {
- _table[start] = (short)ch;
- start += increment;
- }
- }
- else
- {
-
-
- int overflowBits = len - _tableBits;
- int codeBitMask = 1 << _tableBits;
-
-
-
-
-
- int index = start & ((1 << _tableBits) - 1);
- short[] array = _table;
- do
- {
- short value = array[index];
- if (value == 0)
- {
-
- array[index] = (short)-avail;
- value = (short)-avail;
- avail++;
- }
- if (value > 0)
- {
-
- throw new InvalidDataException("Deflate64: invalid Huffman data");
- }
- Debug.Assert(value < 0, "CreateTable: Only negative numbers are used for tree pointers!");
- if ((start & codeBitMask) == 0)
- {
-
- array = _left;
- }
- else
- {
-
- array = _right;
- }
- index = -value;
- codeBitMask <<= 1;
- overflowBits--;
- } while (overflowBits != 0);
- array[index] = (short)ch;
- }
- }
- }
- }
-
-
-
-
-
- public int GetNextSymbol(InputBuffer input)
- {
-
-
-
- uint bitBuffer = input.TryLoad16Bits();
- if (input.AvailableBits == 0)
- {
- return -1;
- }
-
- int symbol = _table[bitBuffer & _tableMask];
- if (symbol < 0)
- {
-
- uint mask = (uint)1 << _tableBits;
- do
- {
- symbol = -symbol;
- if ((bitBuffer & mask) == 0)
- symbol = _left[symbol];
- else
- symbol = _right[symbol];
- mask <<= 1;
- } while (symbol < 0);
- }
- int codeLength = _codeLengthArray[symbol];
-
- if (codeLength <= 0)
- {
- throw new InvalidDataException("Deflate64: invalid Huffman data");
- }
-
-
-
-
-
- if (codeLength > input.AvailableBits)
- {
-
-
- return -1;
- }
- input.SkipBits(codeLength);
- return symbol;
- }
- }
- }
|