You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

488 lines
18 KiB

namespace com.hitrust.util.Zip.Compression
{
using com.hitrust.util.Checksums;
using System;
public class DeflaterEngine : DeflaterConstants
{
private Adler32 adler;
private int blockStart;
private int comprFunc;
private int goodLength;
private short[] head;
private DeflaterHuffman huffman;
private byte[] inputBuf;
private int inputEnd;
private int inputOff;
private int ins_h;
private int lookahead;
private int matchLen;
private int matchStart;
private int max_chain;
private int max_lazy;
private int niceLength;
private DeflaterPending pending;
private short[] prev;
private bool prevAvailable;
private DeflateStrategy strategy;
private int strstart;
private static int TOO_FAR = 0x1000;
private int totalIn;
private byte[] window;
public DeflaterEngine(DeflaterPending pending)
{
this.pending = pending;
this.huffman = new DeflaterHuffman(pending);
this.adler = new Adler32();
this.window = new byte[0x10000];
this.head = new short[0x8000];
this.prev = new short[0x8000];
this.blockStart = this.strstart = 1;
}
public bool Deflate(bool flush, bool finish)
{
bool flag;
do
{
this.FillWindow();
bool flag2 = flush && (this.inputOff == this.inputEnd);
switch (this.comprFunc)
{
case 0:
flag = this.DeflateStored(flag2, finish);
break;
case 1:
flag = this.DeflateFast(flag2, finish);
break;
case 2:
flag = this.DeflateSlow(flag2, finish);
break;
default:
throw new InvalidOperationException("unknown comprFunc");
}
}
while (this.pending.IsFlushed && flag);
return flag;
}
private bool DeflateFast(bool flush, bool finish)
{
if ((this.lookahead >= 0x106) || flush)
{
while ((this.lookahead >= 0x106) || flush)
{
int num;
if (this.lookahead == 0)
{
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
if (this.strstart > 0xfefa)
{
this.SlideWindow();
}
if ((((this.lookahead >= 3) && ((num = this.InsertString()) != 0)) && ((this.strategy != DeflateStrategy.HuffmanOnly) && ((this.strstart - num) <= 0x7efa))) && this.FindLongestMatch(num))
{
if (this.huffman.TallyDist(this.strstart - this.matchStart, this.matchLen))
{
bool lastBlock = finish && (this.lookahead == 0);
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, lastBlock);
this.blockStart = this.strstart;
}
this.lookahead -= this.matchLen;
if ((this.matchLen <= this.max_lazy) && (this.lookahead >= 3))
{
while (--this.matchLen > 0)
{
this.strstart++;
this.InsertString();
}
this.strstart++;
}
else
{
this.strstart += this.matchLen;
if (this.lookahead >= 2)
{
this.UpdateHash();
}
}
this.matchLen = 2;
}
else
{
this.huffman.TallyLit(this.window[this.strstart] & 0xff);
this.strstart++;
this.lookahead--;
if (this.huffman.IsFull())
{
bool flag2 = finish && (this.lookahead == 0);
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, flag2);
this.blockStart = this.strstart;
return !flag2;
}
}
}
return true;
}
return false;
}
private bool DeflateSlow(bool flush, bool finish)
{
if ((this.lookahead >= 0x106) || flush)
{
while ((this.lookahead >= 0x106) || flush)
{
if (this.lookahead == 0)
{
if (this.prevAvailable)
{
this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
}
this.prevAvailable = false;
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
this.blockStart = this.strstart;
return false;
}
if (this.strstart >= 0xfefa)
{
this.SlideWindow();
}
int matchStart = this.matchStart;
int matchLen = this.matchLen;
if (this.lookahead >= 3)
{
int curMatch = this.InsertString();
if ((((this.strategy != DeflateStrategy.HuffmanOnly) && (curMatch != 0)) && (((this.strstart - curMatch) <= 0x7efa) && this.FindLongestMatch(curMatch))) && ((this.matchLen <= 5) && ((this.strategy == DeflateStrategy.Filtered) || ((this.matchLen == 3) && ((this.strstart - this.matchStart) > TOO_FAR)))))
{
this.matchLen = 2;
}
}
if ((matchLen >= 3) && (this.matchLen <= matchLen))
{
this.huffman.TallyDist((this.strstart - 1) - matchStart, matchLen);
matchLen -= 2;
do
{
this.strstart++;
this.lookahead--;
if (this.lookahead >= 3)
{
this.InsertString();
}
}
while (--matchLen > 0);
this.strstart++;
this.lookahead--;
this.prevAvailable = false;
this.matchLen = 2;
}
else
{
if (this.prevAvailable)
{
this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
}
this.prevAvailable = true;
this.strstart++;
this.lookahead--;
}
if (this.huffman.IsFull())
{
int storedLength = this.strstart - this.blockStart;
if (this.prevAvailable)
{
storedLength--;
}
bool lastBlock = (finish && (this.lookahead == 0)) && !this.prevAvailable;
this.huffman.FlushBlock(this.window, this.blockStart, storedLength, lastBlock);
this.blockStart += storedLength;
return !lastBlock;
}
}
return true;
}
return false;
}
private bool DeflateStored(bool flush, bool finish)
{
if (!flush && (this.lookahead == 0))
{
return false;
}
this.strstart += this.lookahead;
this.lookahead = 0;
int storedLength = this.strstart - this.blockStart;
if (((storedLength < DeflaterConstants.MAX_BLOCK_SIZE) && ((this.blockStart >= 0x8000) || (storedLength < 0x7efa))) && !flush)
{
return true;
}
bool lastBlock = finish;
if (storedLength > DeflaterConstants.MAX_BLOCK_SIZE)
{
storedLength = DeflaterConstants.MAX_BLOCK_SIZE;
lastBlock = false;
}
this.huffman.FlushStoredBlock(this.window, this.blockStart, storedLength, lastBlock);
this.blockStart += storedLength;
return !lastBlock;
}
public void FillWindow()
{
if (this.strstart >= 0xfefa)
{
this.SlideWindow();
}
while ((this.lookahead < 0x106) && (this.inputOff < this.inputEnd))
{
int length = (0x10000 - this.lookahead) - this.strstart;
if (length > (this.inputEnd - this.inputOff))
{
length = this.inputEnd - this.inputOff;
}
Array.Copy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, length);
this.adler.Update(this.inputBuf, this.inputOff, length);
this.inputOff += length;
this.totalIn += length;
this.lookahead += length;
}
if (this.lookahead >= 3)
{
this.UpdateHash();
}
}
private bool FindLongestMatch(int curMatch)
{
int num = this.max_chain;
int niceLength = this.niceLength;
short[] prev = this.prev;
int strstart = this.strstart;
int index = this.strstart + this.matchLen;
int num6 = Math.Max(this.matchLen, 2);
int num7 = Math.Max(this.strstart - 0x7efa, 0);
int num8 = (this.strstart + 0x102) - 1;
byte num9 = this.window[index - 1];
byte num10 = this.window[index];
if (num6 >= this.goodLength)
{
num = num >> 2;
}
if (niceLength > this.lookahead)
{
niceLength = this.lookahead;
}
do
{
if (((this.window[curMatch + num6] == num10) && (this.window[(curMatch + num6) - 1] == num9)) && ((this.window[curMatch] == this.window[strstart]) && (this.window[curMatch + 1] == this.window[strstart + 1])))
{
int num4 = curMatch + 2;
strstart += 2;
while ((((this.window[++strstart] == this.window[++num4]) && (this.window[++strstart] == this.window[++num4])) && ((this.window[++strstart] == this.window[++num4]) && (this.window[++strstart] == this.window[++num4]))) && (((this.window[++strstart] == this.window[++num4]) && (this.window[++strstart] == this.window[++num4])) && (((this.window[++strstart] == this.window[++num4]) && (this.window[++strstart] == this.window[++num4])) && (strstart < num8))))
{
}
if (strstart > index)
{
this.matchStart = curMatch;
index = strstart;
num6 = strstart - this.strstart;
if (num6 >= niceLength)
{
break;
}
num9 = this.window[index - 1];
num10 = this.window[index];
}
strstart = this.strstart;
}
}
while (((curMatch = prev[curMatch & 0x7fff] & 0xffff) > num7) && (--num != 0));
this.matchLen = Math.Min(num6, this.lookahead);
return (this.matchLen >= 3);
}
private int InsertString()
{
short num;
int index = ((this.ins_h << 5) ^ this.window[this.strstart + 2]) & 0x7fff;
this.prev[this.strstart & 0x7fff] = num = this.head[index];
this.head[index] = (short) this.strstart;
this.ins_h = index;
return (num & 0xffff);
}
public bool NeedsInput()
{
return (this.inputEnd == this.inputOff);
}
public void Reset()
{
this.huffman.Reset();
this.adler.Reset();
this.blockStart = this.strstart = 1;
this.lookahead = 0;
this.totalIn = 0;
this.prevAvailable = false;
this.matchLen = 2;
for (int i = 0; i < 0x8000; i++)
{
this.head[i] = 0;
}
for (int j = 0; j < 0x8000; j++)
{
this.prev[j] = 0;
}
}
public void ResetAdler()
{
this.adler.Reset();
}
public void SetDictionary(byte[] buffer, int offset, int length)
{
this.adler.Update(buffer, offset, length);
if (length >= 3)
{
if (length > 0x7efa)
{
offset += length - 0x7efa;
length = 0x7efa;
}
Array.Copy(buffer, offset, this.window, this.strstart, length);
this.UpdateHash();
length--;
while (--length > 0)
{
this.InsertString();
this.strstart++;
}
this.strstart += 2;
this.blockStart = this.strstart;
}
}
public void SetInput(byte[] buf, int off, int len)
{
if (this.inputOff < this.inputEnd)
{
throw new InvalidOperationException("Old input was not completely processed");
}
int num = off + len;
if (((0 > off) || (off > num)) || (num > buf.Length))
{
throw new ArgumentOutOfRangeException();
}
this.inputBuf = buf;
this.inputOff = off;
this.inputEnd = num;
}
public void SetLevel(int lvl)
{
this.goodLength = DeflaterConstants.GOOD_LENGTH[lvl];
this.max_lazy = DeflaterConstants.MAX_LAZY[lvl];
this.niceLength = DeflaterConstants.NICE_LENGTH[lvl];
this.max_chain = DeflaterConstants.MAX_CHAIN[lvl];
if (DeflaterConstants.COMPR_FUNC[lvl] != this.comprFunc)
{
switch (this.comprFunc)
{
case 0:
if (this.strstart > this.blockStart)
{
this.huffman.FlushStoredBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
this.UpdateHash();
break;
case 1:
if (this.strstart > this.blockStart)
{
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
break;
case 2:
if (this.prevAvailable)
{
this.huffman.TallyLit(this.window[this.strstart - 1] & 0xff);
}
if (this.strstart > this.blockStart)
{
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, false);
this.blockStart = this.strstart;
}
this.prevAvailable = false;
this.matchLen = 2;
break;
}
this.comprFunc = DeflaterConstants.COMPR_FUNC[lvl];
}
}
private void SlideWindow()
{
Array.Copy(this.window, 0x8000, this.window, 0, 0x8000);
this.matchStart -= 0x8000;
this.strstart -= 0x8000;
this.blockStart -= 0x8000;
for (int i = 0; i < 0x8000; i++)
{
int num2 = this.head[i] & 0xffff;
this.head[i] = (num2 >= 0x8000) ? ((short) (num2 - 0x8000)) : ((short) 0);
}
for (int j = 0; j < 0x8000; j++)
{
int num4 = this.prev[j] & 0xffff;
this.prev[j] = (num4 >= 0x8000) ? ((short) (num4 - 0x8000)) : ((short) 0);
}
}
private void UpdateHash()
{
this.ins_h = (this.window[this.strstart] << 5) ^ this.window[this.strstart + 1];
}
public int Adler
{
get
{
return (int) this.adler.Value;
}
}
public DeflateStrategy Strategy
{
get
{
return this.strategy;
}
set
{
this.strategy = value;
}
}
public int TotalIn
{
get
{
return this.totalIn;
}
}
}
}