2021-05-07 22:05:11 -04:00

295 lines
8.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using UniversalEditor.Compression.Common;
namespace UniversalEditor.Compression.Modules.Deflate.Internal
{
internal class FastEncoder
{
internal class Output
{
private uint bitBuf;
private int bitCount;
private static byte[] distLookup;
private byte[] outputBuf;
private int outputPos;
internal int BytesWritten
{
get
{
return this.outputPos;
}
}
internal int FreeBytes
{
get
{
return this.outputBuf.Length - this.outputPos;
}
}
static Output()
{
FastEncoder.Output.distLookup = new byte[512];
FastEncoder.Output.GenerateSlotTables();
}
internal void FlushBits()
{
while (this.bitCount >= 8)
{
int CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)this.bitBuf;
this.bitCount -= 8;
this.bitBuf >>= 8;
}
if (this.bitCount > 0)
{
int CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)this.bitBuf;
this.bitCount = 0;
}
}
internal static void GenerateSlotTables()
{
int num = 0;
int index;
for (index = 0; index < 16; index++)
{
for (int i = 0; i < 1 << (int)FastEncoderStatics.ExtraDistanceBits[index]; i++)
{
num++;
FastEncoder.Output.distLookup[num] = (byte)index;
}
}
num >>= 7;
while (index < 30)
{
for (int j = 0; j < 1 << (int)(FastEncoderStatics.ExtraDistanceBits[index] - 7); j++)
{
num++;
FastEncoder.Output.distLookup[256 + num] = (byte)index;
}
index++;
}
}
internal int GetSlot(int pos)
{
return (int)FastEncoder.Output.distLookup[(pos < 256) ? pos : (256 + (pos >> 7))];
}
internal bool SafeToWriteTo()
{
return this.outputBuf.Length - this.outputPos > 16;
}
internal void UpdateBuffer(byte[] output)
{
this.outputBuf = output;
this.outputPos = 0;
}
internal void WriteBits(int n, uint bits)
{
this.bitBuf |= bits << this.bitCount;
this.bitCount += n;
if (this.bitCount >= 16)
{
int CS_0_ = this.outputPos++;
this.outputBuf[CS_0_] = (byte)this.bitBuf;
CS_0_ = this.outputPos++;
this.outputBuf[CS_0_] = (byte)(this.bitBuf >> 8);
this.bitCount -= 16;
this.bitBuf >>= 16;
}
}
internal void WriteChar(byte b)
{
uint num = FastEncoderStatics.FastEncoderLiteralCodeInfo[(int)b];
this.WriteBits((int)(num & 31u), num >> 5);
}
internal void WriteGzipFooter(uint gzipCrc32, uint inputStreamSize)
{
int CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(gzipCrc32 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(gzipCrc32 >> 8 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(gzipCrc32 >> 16 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(gzipCrc32 >> 24 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(inputStreamSize & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(inputStreamSize >> 8 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(inputStreamSize >> 16 & 255u);
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = (byte)(inputStreamSize >> 24 & 255u);
}
internal void WriteGzipHeader(int compression_level)
{
int CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 31;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 139;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 8;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
if (compression_level == 10)
{
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 2;
}
else
{
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 4;
}
CS_0_0 = this.outputPos++;
this.outputBuf[CS_0_0] = 0;
}
internal void WriteMatch(int matchLen, int matchPos)
{
uint num = FastEncoderStatics.FastEncoderLiteralCodeInfo[254 + matchLen];
int i = (int)(num & 31u);
if (i <= 16)
{
this.WriteBits(i, num >> 5);
}
else
{
this.WriteBits(16, num >> 5 & 65535u);
this.WriteBits(i - 16, num >> 21);
}
num = FastEncoderStatics.FastEncoderDistanceCodeInfo[this.GetSlot(matchPos)];
this.WriteBits((int)(num & 15u), num >> 8);
int num2 = (int)(num >> 4 & 15u);
if (num2 != 0)
{
this.WriteBits(num2, (uint)(matchPos & (int)FastEncoderStatics.BitMask[num2]));
}
}
internal void WritePreamble()
{
Array.Copy(FastEncoderStatics.FastEncoderTreeStructureData, 0, this.outputBuf, this.outputPos, FastEncoderStatics.FastEncoderTreeStructureData.Length);
this.outputPos += FastEncoderStatics.FastEncoderTreeStructureData.Length;
this.bitCount = 9;
this.bitBuf = 34u;
}
}
private Match currentMatch;
private uint gzipCrc32;
private bool hasBlockHeader;
private bool hasGzipHeader;
private DeflateInput inputBuffer;
private uint inputStreamSize;
private FastEncoderWindow inputWindow;
private bool needsEOB;
private FastEncoder.Output output;
private bool usingGzip;
public FastEncoder(bool doGZip)
{
this.usingGzip = doGZip;
this.inputWindow = new FastEncoderWindow();
this.inputBuffer = new DeflateInput();
this.output = new FastEncoder.Output();
this.currentMatch = new Match();
}
public int Finish(byte[] outputBuffer)
{
this.output.UpdateBuffer(outputBuffer);
if (this.needsEOB)
{
uint num = FastEncoderStatics.FastEncoderLiteralCodeInfo[256];
int i = (int)(num & 31u);
this.output.WriteBits(i, num >> 5);
this.output.FlushBits();
if (this.usingGzip)
{
this.output.WriteGzipFooter(this.gzipCrc32, this.inputStreamSize);
}
}
return this.output.BytesWritten;
}
public int GetCompressedOutput(byte[] outputBuffer)
{
this.output.UpdateBuffer(outputBuffer);
if (this.usingGzip && !this.hasGzipHeader)
{
this.output.WriteGzipHeader(3);
this.hasGzipHeader = true;
}
if (!this.hasBlockHeader)
{
this.hasBlockHeader = true;
this.output.WritePreamble();
}
while (true)
{
int count = (this.inputBuffer.Count < this.inputWindow.FreeWindowSpace) ? this.inputBuffer.Count : this.inputWindow.FreeWindowSpace;
if (count > 0)
{
this.inputWindow.CopyBytes(this.inputBuffer.Buffer, this.inputBuffer.StartIndex, count);
if (this.usingGzip)
{
this.gzipCrc32 = DecodeHelper.UpdateCrc32(this.gzipCrc32, this.inputBuffer.Buffer, this.inputBuffer.StartIndex, count);
uint num2 = this.inputStreamSize + (uint)count;
if (num2 < this.inputStreamSize)
{
break;
}
this.inputStreamSize = num2;
}
this.inputBuffer.ConsumeBytes(count);
}
while (this.inputWindow.BytesAvailable > 0 && this.output.SafeToWriteTo())
{
this.inputWindow.GetNextSymbolOrMatch(this.currentMatch);
if (this.currentMatch.State == MatchState.HasSymbol)
{
this.output.WriteChar(this.currentMatch.Symbol);
}
else
{
if (this.currentMatch.State == MatchState.HasMatch)
{
this.output.WriteMatch(this.currentMatch.Length, this.currentMatch.Position);
}
else
{
this.output.WriteChar(this.currentMatch.Symbol);
this.output.WriteMatch(this.currentMatch.Length, this.currentMatch.Position);
}
}
}
if (!this.output.SafeToWriteTo() || this.NeedsInput())
{
goto Block_13;
}
}
throw new InvalidDataException("StreamSizeOverflow");
Block_13:
this.needsEOB = true;
return this.output.BytesWritten;
}
public bool NeedsInput()
{
return this.inputBuffer.Count == 0 && this.inputWindow.BytesAvailable == 0;
}
public void SetInput(byte[] input, int startIndex, int count)
{
this.inputBuffer.Buffer = input;
this.inputBuffer.Count = count;
this.inputBuffer.StartIndex = startIndex;
}
}
}