216 lines
4.2 KiB
C#
216 lines
4.2 KiB
C#
namespace Unity.IO.Compression
|
|
{
|
|
internal class HuffmanTree
|
|
{
|
|
internal const int MaxLiteralTreeElements = 288;
|
|
|
|
internal const int MaxDistTreeElements = 32;
|
|
|
|
internal const int EndOfBlockCode = 256;
|
|
|
|
internal const int NumberOfCodeLengthTreeElements = 19;
|
|
|
|
private int tableBits;
|
|
|
|
private short[] table;
|
|
|
|
private short[] left;
|
|
|
|
private short[] right;
|
|
|
|
private byte[] codeLengthArray;
|
|
|
|
private int tableMask;
|
|
|
|
private static HuffmanTree staticLiteralLengthTree;
|
|
|
|
private static HuffmanTree staticDistanceTree;
|
|
|
|
public static HuffmanTree StaticLiteralLengthTree
|
|
{
|
|
get
|
|
{
|
|
return staticLiteralLengthTree;
|
|
}
|
|
}
|
|
|
|
public static HuffmanTree StaticDistanceTree
|
|
{
|
|
get
|
|
{
|
|
return staticDistanceTree;
|
|
}
|
|
}
|
|
|
|
static HuffmanTree()
|
|
{
|
|
staticLiteralLengthTree = new HuffmanTree(GetStaticLiteralTreeLength());
|
|
staticDistanceTree = new HuffmanTree(GetStaticDistanceTreeLength());
|
|
}
|
|
|
|
public HuffmanTree(byte[] codeLengths)
|
|
{
|
|
codeLengthArray = codeLengths;
|
|
if (codeLengthArray.Length == 288)
|
|
{
|
|
tableBits = 9;
|
|
}
|
|
else
|
|
{
|
|
tableBits = 7;
|
|
}
|
|
tableMask = (1 << tableBits) - 1;
|
|
CreateTable();
|
|
}
|
|
|
|
private static byte[] GetStaticLiteralTreeLength()
|
|
{
|
|
byte[] array = new byte[288];
|
|
for (int i = 0; i <= 143; i++)
|
|
{
|
|
array[i] = 8;
|
|
}
|
|
for (int j = 144; j <= 255; j++)
|
|
{
|
|
array[j] = 9;
|
|
}
|
|
for (int k = 256; k <= 279; k++)
|
|
{
|
|
array[k] = 7;
|
|
}
|
|
for (int l = 280; l <= 287; l++)
|
|
{
|
|
array[l] = 8;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private static byte[] GetStaticDistanceTreeLength()
|
|
{
|
|
byte[] array = new byte[32];
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
array[i] = 5;
|
|
}
|
|
return array;
|
|
}
|
|
|
|
private uint[] CalculateHuffmanCode()
|
|
{
|
|
uint[] array = new uint[17];
|
|
byte[] array2 = codeLengthArray;
|
|
foreach (int num in array2)
|
|
{
|
|
array[num]++;
|
|
}
|
|
array[0] = 0u;
|
|
uint[] array3 = new uint[17];
|
|
uint num2 = 0u;
|
|
for (int j = 1; j <= 16; j++)
|
|
{
|
|
num2 = (array3[j] = num2 + array[j - 1] << 1);
|
|
}
|
|
uint[] array4 = new uint[288];
|
|
for (int k = 0; k < codeLengthArray.Length; k++)
|
|
{
|
|
int num3 = codeLengthArray[k];
|
|
if (num3 > 0)
|
|
{
|
|
array4[k] = FastEncoderStatics.BitReverse(array3[num3], num3);
|
|
array3[num3]++;
|
|
}
|
|
}
|
|
return array4;
|
|
}
|
|
|
|
private void CreateTable()
|
|
{
|
|
uint[] array = CalculateHuffmanCode();
|
|
table = new short[1 << tableBits];
|
|
left = new short[2 * codeLengthArray.Length];
|
|
right = new short[2 * codeLengthArray.Length];
|
|
short num = (short)codeLengthArray.Length;
|
|
for (int i = 0; i < codeLengthArray.Length; i++)
|
|
{
|
|
int num2 = codeLengthArray[i];
|
|
if (num2 <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
int num3 = (int)array[i];
|
|
if (num2 <= tableBits)
|
|
{
|
|
int num4 = 1 << num2;
|
|
if (num3 >= num4)
|
|
{
|
|
throw new InvalidDataException(SR.GetString("Invalid Huffman data"));
|
|
}
|
|
int num5 = 1 << tableBits - num2;
|
|
for (int j = 0; j < num5; j++)
|
|
{
|
|
table[num3] = (short)i;
|
|
num3 += num4;
|
|
}
|
|
continue;
|
|
}
|
|
int num6 = num2 - tableBits;
|
|
int num7 = 1 << tableBits;
|
|
int num8 = num3 & ((1 << tableBits) - 1);
|
|
short[] array2 = table;
|
|
do
|
|
{
|
|
short num9 = array2[num8];
|
|
if (num9 == 0)
|
|
{
|
|
array2[num8] = (short)(-num);
|
|
num9 = (short)(-num);
|
|
num++;
|
|
}
|
|
if (num9 > 0)
|
|
{
|
|
throw new InvalidDataException(SR.GetString("Invalid Huffman data"));
|
|
}
|
|
array2 = (((num3 & num7) != 0) ? right : left);
|
|
num8 = -num9;
|
|
num7 <<= 1;
|
|
num6--;
|
|
}
|
|
while (num6 != 0);
|
|
array2[num8] = (short)i;
|
|
}
|
|
}
|
|
|
|
public int GetNextSymbol(InputBuffer input)
|
|
{
|
|
uint num = input.TryLoad16Bits();
|
|
if (input.AvailableBits == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
int num2 = table[num & tableMask];
|
|
if (num2 < 0)
|
|
{
|
|
uint num3 = (uint)(1 << tableBits);
|
|
do
|
|
{
|
|
num2 = -num2;
|
|
num2 = (((num & num3) != 0) ? right[num2] : left[num2]);
|
|
num3 <<= 1;
|
|
}
|
|
while (num2 < 0);
|
|
}
|
|
int num4 = codeLengthArray[num2];
|
|
if (num4 <= 0)
|
|
{
|
|
throw new InvalidDataException(SR.GetString("Invalid Huffman data"));
|
|
}
|
|
if (num4 > input.AvailableBits)
|
|
{
|
|
return -1;
|
|
}
|
|
input.SkipBits(num4);
|
|
return num2;
|
|
}
|
|
}
|
|
}
|