212 lines
4.7 KiB
C#
212 lines
4.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
using UniversalEditor.Compression.Modules.Deflate.Internal;
|
|
|
|
namespace UniversalEditor.Compression.Common
|
|
{
|
|
public class HuffmanTree
|
|
{
|
|
internal const int EndOfBlockCode = 256;
|
|
internal const int MaxDistTreeElements = 32;
|
|
internal const int MaxLiteralTreeElements = 288;
|
|
internal const int NumberOfCodeLengthTreeElements = 19;
|
|
private byte[] codeLengthArray;
|
|
private short[] left;
|
|
private short[] right;
|
|
private static HuffmanTree staticDistanceTree = new HuffmanTree(HuffmanTree.GetStaticDistanceTreeLength());
|
|
private static HuffmanTree staticLiteralLengthTree = new HuffmanTree(HuffmanTree.GetStaticLiteralTreeLength());
|
|
private short[] table;
|
|
private int tableBits;
|
|
private int tableMask;
|
|
public static HuffmanTree StaticDistanceTree
|
|
{
|
|
get
|
|
{
|
|
return HuffmanTree.staticDistanceTree;
|
|
}
|
|
}
|
|
public static HuffmanTree StaticLiteralLengthTree
|
|
{
|
|
get
|
|
{
|
|
return HuffmanTree.staticLiteralLengthTree;
|
|
}
|
|
}
|
|
public HuffmanTree(byte[] codeLengths)
|
|
{
|
|
this.codeLengthArray = codeLengths;
|
|
if (this.codeLengthArray.Length == 288)
|
|
{
|
|
this.tableBits = 9;
|
|
}
|
|
else
|
|
{
|
|
this.tableBits = 7;
|
|
}
|
|
this.tableMask = (1 << this.tableBits) - 1;
|
|
this.CreateTable();
|
|
}
|
|
private uint[] CalculateHuffmanCode()
|
|
{
|
|
uint[] numArray = new uint[17];
|
|
byte[] codeLengthArray = this.codeLengthArray;
|
|
for (int i = 0; i < codeLengthArray.Length; i++)
|
|
{
|
|
int index = (int)codeLengthArray[i];
|
|
numArray[index] += 1u;
|
|
}
|
|
numArray[0] = 0u;
|
|
uint[] numArray2 = new uint[17];
|
|
uint num2 = 0u;
|
|
for (int j = 1; j <= 16; j++)
|
|
{
|
|
numArray2[j] = num2 + numArray[j - 1] << 1;
|
|
}
|
|
uint[] numArray3 = new uint[288];
|
|
for (int k = 0; k < this.codeLengthArray.Length; k++)
|
|
{
|
|
int length = (int)this.codeLengthArray[k];
|
|
if (length > 0)
|
|
{
|
|
numArray3[k] = DecodeHelper.BitReverse(numArray2[length], length);
|
|
numArray2[length] += 1u;
|
|
}
|
|
}
|
|
return numArray3;
|
|
}
|
|
private void CreateTable()
|
|
{
|
|
uint[] numArray = this.CalculateHuffmanCode();
|
|
this.table = new short[1 << this.tableBits];
|
|
this.left = new short[2 * this.codeLengthArray.Length];
|
|
this.right = new short[2 * this.codeLengthArray.Length];
|
|
short length = (short)this.codeLengthArray.Length;
|
|
for (int i = 0; i < this.codeLengthArray.Length; i++)
|
|
{
|
|
int num3 = (int)this.codeLengthArray[i];
|
|
if (num3 > 0)
|
|
{
|
|
int index = (int)numArray[i];
|
|
if (num3 <= this.tableBits)
|
|
{
|
|
int num4 = 1 << num3;
|
|
if (index >= num4)
|
|
{
|
|
throw new System.IO.InvalidDataException("InvalidHuffmanData");
|
|
}
|
|
int num5 = 1 << this.tableBits - num3;
|
|
for (int j = 0; j < num5; j++)
|
|
{
|
|
this.table[index] = (short)i;
|
|
index += num4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int num6 = num3 - this.tableBits;
|
|
int num7 = 1 << this.tableBits;
|
|
int num8 = index & (1 << this.tableBits) - 1;
|
|
short[] table = this.table;
|
|
do
|
|
{
|
|
short num9 = table[num8];
|
|
if (num9 == 0)
|
|
{
|
|
table[num8] = (short)(-length);
|
|
num9 = (short)(-length);
|
|
length += 1;
|
|
}
|
|
if ((index & num7) == 0)
|
|
{
|
|
table = this.left;
|
|
}
|
|
else
|
|
{
|
|
table = this.right;
|
|
}
|
|
num8 = (int)(-(int)num9);
|
|
num7 <<= 1;
|
|
num6--;
|
|
}
|
|
while (num6 != 0);
|
|
table[num8] = (short)i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public int GetNextSymbol(InputBuffer input)
|
|
{
|
|
uint num = input.TryLoad16Bits();
|
|
int result;
|
|
if (input.AvailableBits == 0)
|
|
{
|
|
result = -1;
|
|
}
|
|
else
|
|
{
|
|
int index = (int)this.table[(int)((IntPtr)((long)((ulong)num & (ulong)((long)this.tableMask))))];
|
|
if (index < 0)
|
|
{
|
|
uint num2 = 1u << this.tableBits;
|
|
do
|
|
{
|
|
index = -index;
|
|
if ((num & num2) == 0u)
|
|
{
|
|
index = (int)this.left[index];
|
|
}
|
|
else
|
|
{
|
|
index = (int)this.right[index];
|
|
}
|
|
num2 <<= 1;
|
|
}
|
|
while (index < 0);
|
|
}
|
|
if ((int)this.codeLengthArray[index] > input.AvailableBits)
|
|
{
|
|
result = -1;
|
|
}
|
|
else
|
|
{
|
|
input.SkipBits((int)this.codeLengthArray[index]);
|
|
result = index;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
private static byte[] GetStaticDistanceTreeLength()
|
|
{
|
|
byte[] buffer = new byte[32];
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
buffer[i] = 5;
|
|
}
|
|
return buffer;
|
|
}
|
|
private static byte[] GetStaticLiteralTreeLength()
|
|
{
|
|
byte[] buffer = new byte[288];
|
|
for (int i = 0; i <= 143; i++)
|
|
{
|
|
buffer[i] = 8;
|
|
}
|
|
for (int j = 144; j <= 255; j++)
|
|
{
|
|
buffer[j] = 9;
|
|
}
|
|
for (int k = 256; k <= 279; k++)
|
|
{
|
|
buffer[k] = 7;
|
|
}
|
|
for (int l = 280; l <= 287; l++)
|
|
{
|
|
buffer[l] = 8;
|
|
}
|
|
return buffer;
|
|
}
|
|
}
|
|
}
|