mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 19:36:11 +00:00
f2ac1ece55
add
2390 lines
74 KiB
C#
2390 lines
74 KiB
C#
// Decompiled with JetBrains decompiler
|
|
// Type: SmartAssembly.Zip.SimpleZip
|
|
// Assembly: WinData, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
|
// MVID: 162322D2-FE3A-45B9-99E4-3519564A1D4D
|
|
// Assembly location: C:\Users\Administrateur\Downloads\Virusshare.00004-msil\Trojan-Ransom.Win32.Blocker.kkro-82cd479bb60c59525668e5016b400a8cc48f04b14a5c6cad5e2c6046b301e79d.exe
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace SmartAssembly.Zip
|
|
{
|
|
public sealed class SimpleZip
|
|
{
|
|
public static string ExceptionMessage;
|
|
|
|
private static bool PublicKeysMatch(Assembly executingAssembly, Assembly callingAssembly)
|
|
{
|
|
byte[] publicKey1 = executingAssembly.GetName().GetPublicKey();
|
|
byte[] publicKey2 = callingAssembly.GetName().GetPublicKey();
|
|
if (publicKey2 == null != (publicKey1 == null))
|
|
return false;
|
|
if (publicKey2 != null)
|
|
{
|
|
for (int index = 0; index < publicKey2.Length; ++index)
|
|
{
|
|
if ((int) publicKey2[index] != (int) publicKey1[index])
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static byte[] Unzip(byte[] buffer)
|
|
{
|
|
Assembly callingAssembly = Assembly.GetCallingAssembly();
|
|
Assembly executingAssembly = Assembly.GetExecutingAssembly();
|
|
if ((object) callingAssembly != (object) executingAssembly && !SimpleZip.PublicKeysMatch(executingAssembly, callingAssembly))
|
|
return (byte[]) null;
|
|
SimpleZip.ZipStream zipStream = new SimpleZip.ZipStream(buffer);
|
|
byte[] buf = new byte[0];
|
|
int num1 = zipStream.ReadInt();
|
|
if (num1 == 67324752)
|
|
{
|
|
short num2 = (short) zipStream.ReadShort();
|
|
int num3 = zipStream.ReadShort();
|
|
int num4 = zipStream.ReadShort();
|
|
if (num1 != 67324752 || num2 != (short) 20 || num3 != 0 || num4 != 8)
|
|
throw new FormatException("Wrong Header Signature");
|
|
zipStream.ReadInt();
|
|
zipStream.ReadInt();
|
|
zipStream.ReadInt();
|
|
int length = zipStream.ReadInt();
|
|
int count1 = zipStream.ReadShort();
|
|
int count2 = zipStream.ReadShort();
|
|
if (count1 > 0)
|
|
{
|
|
byte[] buffer1 = new byte[count1];
|
|
zipStream.Read(buffer1, 0, count1);
|
|
}
|
|
if (count2 > 0)
|
|
{
|
|
byte[] buffer2 = new byte[count2];
|
|
zipStream.Read(buffer2, 0, count2);
|
|
}
|
|
byte[] numArray = new byte[zipStream.Length - zipStream.Position];
|
|
zipStream.Read(numArray, 0, numArray.Length);
|
|
SimpleZip.Inflater inflater = new SimpleZip.Inflater(numArray);
|
|
buf = new byte[length];
|
|
inflater.Inflate(buf, 0, buf.Length);
|
|
}
|
|
else
|
|
{
|
|
int num5 = num1 >> 24;
|
|
if (num1 - (num5 << 24) != 8223355)
|
|
throw new FormatException("Unknown Header");
|
|
if (num5 == 1)
|
|
{
|
|
int length1 = zipStream.ReadInt();
|
|
buf = new byte[length1];
|
|
int len;
|
|
for (int offset = 0; offset < length1; offset += len)
|
|
{
|
|
int length2 = zipStream.ReadInt();
|
|
len = zipStream.ReadInt();
|
|
byte[] numArray = new byte[length2];
|
|
zipStream.Read(numArray, 0, numArray.Length);
|
|
new SimpleZip.Inflater(numArray).Inflate(buf, offset, len);
|
|
}
|
|
}
|
|
if (num5 == 2)
|
|
{
|
|
byte[] key = new byte[8]
|
|
{
|
|
(byte) 85,
|
|
(byte) 240,
|
|
(byte) 125,
|
|
(byte) 197,
|
|
(byte) 120,
|
|
(byte) 224,
|
|
(byte) 53,
|
|
(byte) 165
|
|
};
|
|
byte[] iv = new byte[8]
|
|
{
|
|
(byte) 169,
|
|
(byte) 210,
|
|
(byte) 146,
|
|
(byte) 41,
|
|
(byte) 1,
|
|
(byte) 34,
|
|
(byte) 222,
|
|
(byte) 163
|
|
};
|
|
using (DESCryptoIndirector cryptoIndirector = new DESCryptoIndirector())
|
|
{
|
|
using (ICryptoTransform desCryptoTransform = cryptoIndirector.GetDESCryptoTransform(key, iv, true))
|
|
buf = SimpleZip.Unzip(desCryptoTransform.TransformFinalBlock(buffer, 4, buffer.Length - 4));
|
|
}
|
|
}
|
|
if (num5 == 3)
|
|
{
|
|
byte[] key = new byte[16]
|
|
{
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1,
|
|
(byte) 1
|
|
};
|
|
byte[] iv = new byte[16]
|
|
{
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2,
|
|
(byte) 2
|
|
};
|
|
using (AESCryptoIndirector cryptoIndirector = new AESCryptoIndirector())
|
|
{
|
|
using (ICryptoTransform aesCryptoTransform = cryptoIndirector.GetAESCryptoTransform(key, iv, true))
|
|
buf = SimpleZip.Unzip(aesCryptoTransform.TransformFinalBlock(buffer, 4, buffer.Length - 4));
|
|
}
|
|
}
|
|
}
|
|
zipStream.Close();
|
|
return buf;
|
|
}
|
|
|
|
public static byte[] Zip(byte[] buffer) => SimpleZip.Zip(buffer, 1, (byte[]) null, (byte[]) null);
|
|
|
|
public static byte[] ZipAndEncrypt(byte[] buffer, byte[] key, byte[] iv) => SimpleZip.Zip(buffer, 2, key, iv);
|
|
|
|
public static byte[] ZipAndAES(byte[] buffer, byte[] key, byte[] iv) => SimpleZip.Zip(buffer, 3, key, iv);
|
|
|
|
private static byte[] Zip(byte[] buffer, int version, byte[] key, byte[] iv)
|
|
{
|
|
try
|
|
{
|
|
SimpleZip.ZipStream zipStream = new SimpleZip.ZipStream();
|
|
switch (version)
|
|
{
|
|
case 0:
|
|
SimpleZip.Deflater deflater1 = new SimpleZip.Deflater();
|
|
DateTime now = DateTime.Now;
|
|
long num1 = (long) ((uint) ((now.Year - 1980 & (int) sbyte.MaxValue) << 25 | now.Month << 21 | now.Day << 16 | now.Hour << 11 | now.Minute << 5) | (uint) now.Second >> 1);
|
|
uint[] numArray1 = new uint[256]
|
|
{
|
|
0U,
|
|
1996959894U,
|
|
3993919788U,
|
|
2567524794U,
|
|
124634137U,
|
|
1886057615U,
|
|
3915621685U,
|
|
2657392035U,
|
|
249268274U,
|
|
2044508324U,
|
|
3772115230U,
|
|
2547177864U,
|
|
162941995U,
|
|
2125561021U,
|
|
3887607047U,
|
|
2428444049U,
|
|
498536548U,
|
|
1789927666U,
|
|
4089016648U,
|
|
2227061214U,
|
|
450548861U,
|
|
1843258603U,
|
|
4107580753U,
|
|
2211677639U,
|
|
325883990U,
|
|
1684777152U,
|
|
4251122042U,
|
|
2321926636U,
|
|
335633487U,
|
|
1661365465U,
|
|
4195302755U,
|
|
2366115317U,
|
|
997073096U,
|
|
1281953886U,
|
|
3579855332U,
|
|
2724688242U,
|
|
1006888145U,
|
|
1258607687U,
|
|
3524101629U,
|
|
2768942443U,
|
|
901097722U,
|
|
1119000684U,
|
|
3686517206U,
|
|
2898065728U,
|
|
853044451U,
|
|
1172266101U,
|
|
3705015759U,
|
|
2882616665U,
|
|
651767980U,
|
|
1373503546U,
|
|
3369554304U,
|
|
3218104598U,
|
|
565507253U,
|
|
1454621731U,
|
|
3485111705U,
|
|
3099436303U,
|
|
671266974U,
|
|
1594198024U,
|
|
3322730930U,
|
|
2970347812U,
|
|
795835527U,
|
|
1483230225U,
|
|
3244367275U,
|
|
3060149565U,
|
|
1994146192U,
|
|
31158534U,
|
|
2563907772U,
|
|
4023717930U,
|
|
1907459465U,
|
|
112637215U,
|
|
2680153253U,
|
|
3904427059U,
|
|
2013776290U,
|
|
251722036U,
|
|
2517215374U,
|
|
3775830040U,
|
|
2137656763U,
|
|
141376813U,
|
|
2439277719U,
|
|
3865271297U,
|
|
1802195444U,
|
|
476864866U,
|
|
2238001368U,
|
|
4066508878U,
|
|
1812370925U,
|
|
453092731U,
|
|
2181625025U,
|
|
4111451223U,
|
|
1706088902U,
|
|
314042704U,
|
|
2344532202U,
|
|
4240017532U,
|
|
1658658271U,
|
|
366619977U,
|
|
2362670323U,
|
|
4224994405U,
|
|
1303535960U,
|
|
984961486U,
|
|
2747007092U,
|
|
3569037538U,
|
|
1256170817U,
|
|
1037604311U,
|
|
2765210733U,
|
|
3554079995U,
|
|
1131014506U,
|
|
879679996U,
|
|
2909243462U,
|
|
3663771856U,
|
|
1141124467U,
|
|
855842277U,
|
|
2852801631U,
|
|
3708648649U,
|
|
1342533948U,
|
|
654459306U,
|
|
3188396048U,
|
|
3373015174U,
|
|
1466479909U,
|
|
544179635U,
|
|
3110523913U,
|
|
3462522015U,
|
|
1591671054U,
|
|
702138776U,
|
|
2966460450U,
|
|
3352799412U,
|
|
1504918807U,
|
|
783551873U,
|
|
3082640443U,
|
|
3233442989U,
|
|
3988292384U,
|
|
2596254646U,
|
|
62317068U,
|
|
1957810842U,
|
|
3939845945U,
|
|
2647816111U,
|
|
81470997U,
|
|
1943803523U,
|
|
3814918930U,
|
|
2489596804U,
|
|
225274430U,
|
|
2053790376U,
|
|
3826175755U,
|
|
2466906013U,
|
|
167816743U,
|
|
2097651377U,
|
|
4027552580U,
|
|
2265490386U,
|
|
503444072U,
|
|
1762050814U,
|
|
4150417245U,
|
|
2154129355U,
|
|
426522225U,
|
|
1852507879U,
|
|
4275313526U,
|
|
2312317920U,
|
|
282753626U,
|
|
1742555852U,
|
|
4189708143U,
|
|
2394877945U,
|
|
397917763U,
|
|
1622183637U,
|
|
3604390888U,
|
|
2714866558U,
|
|
953729732U,
|
|
1340076626U,
|
|
3518719985U,
|
|
2797360999U,
|
|
1068828381U,
|
|
1219638859U,
|
|
3624741850U,
|
|
2936675148U,
|
|
906185462U,
|
|
1090812512U,
|
|
3747672003U,
|
|
2825379669U,
|
|
829329135U,
|
|
1181335161U,
|
|
3412177804U,
|
|
3160834842U,
|
|
628085408U,
|
|
1382605366U,
|
|
3423369109U,
|
|
3138078467U,
|
|
570562233U,
|
|
1426400815U,
|
|
3317316542U,
|
|
2998733608U,
|
|
733239954U,
|
|
1555261956U,
|
|
3268935591U,
|
|
3050360625U,
|
|
752459403U,
|
|
1541320221U,
|
|
2607071920U,
|
|
3965973030U,
|
|
1969922972U,
|
|
40735498U,
|
|
2617837225U,
|
|
3943577151U,
|
|
1913087877U,
|
|
83908371U,
|
|
2512341634U,
|
|
3803740692U,
|
|
2075208622U,
|
|
213261112U,
|
|
2463272603U,
|
|
3855990285U,
|
|
2094854071U,
|
|
198958881U,
|
|
2262029012U,
|
|
4057260610U,
|
|
1759359992U,
|
|
534414190U,
|
|
2176718541U,
|
|
4139329115U,
|
|
1873836001U,
|
|
414664567U,
|
|
2282248934U,
|
|
4279200368U,
|
|
1711684554U,
|
|
285281116U,
|
|
2405801727U,
|
|
4167216745U,
|
|
1634467795U,
|
|
376229701U,
|
|
2685067896U,
|
|
3608007406U,
|
|
1308918612U,
|
|
956543938U,
|
|
2808555105U,
|
|
3495958263U,
|
|
1231636301U,
|
|
1047427035U,
|
|
2932959818U,
|
|
3654703836U,
|
|
1088359270U,
|
|
936918000U,
|
|
2847714899U,
|
|
3736837829U,
|
|
1202900863U,
|
|
817233897U,
|
|
3183342108U,
|
|
3401237130U,
|
|
1404277552U,
|
|
615818150U,
|
|
3134207493U,
|
|
3453421203U,
|
|
1423857449U,
|
|
601450431U,
|
|
3009837614U,
|
|
3294710456U,
|
|
1567103746U,
|
|
711928724U,
|
|
3020668471U,
|
|
3272380065U,
|
|
1510334235U,
|
|
755167117U
|
|
};
|
|
uint maxValue = uint.MaxValue;
|
|
uint num2 = maxValue;
|
|
int num3 = 0;
|
|
int length = buffer.Length;
|
|
while (--length >= 0)
|
|
num2 = numArray1[(IntPtr) (uint) (((int) num2 ^ (int) buffer[num3++]) & (int) byte.MaxValue)] ^ num2 >> 8;
|
|
uint num4 = num2 ^ maxValue;
|
|
zipStream.WriteInt(67324752);
|
|
zipStream.WriteShort(20);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(8);
|
|
zipStream.WriteInt((int) num1);
|
|
zipStream.WriteInt((int) num4);
|
|
long position1 = zipStream.Position;
|
|
zipStream.WriteInt(0);
|
|
zipStream.WriteInt(buffer.Length);
|
|
byte[] bytes = Encoding.UTF8.GetBytes("{data}");
|
|
zipStream.WriteShort(bytes.Length);
|
|
zipStream.WriteShort(0);
|
|
zipStream.Write(bytes, 0, bytes.Length);
|
|
deflater1.SetInput(buffer);
|
|
while (!deflater1.IsNeedingInput)
|
|
{
|
|
byte[] numArray2 = new byte[512];
|
|
int count = deflater1.Deflate(numArray2);
|
|
if (count > 0)
|
|
zipStream.Write(numArray2, 0, count);
|
|
else
|
|
break;
|
|
}
|
|
deflater1.Finish();
|
|
while (!deflater1.IsFinished)
|
|
{
|
|
byte[] numArray3 = new byte[512];
|
|
int count = deflater1.Deflate(numArray3);
|
|
if (count > 0)
|
|
zipStream.Write(numArray3, 0, count);
|
|
else
|
|
break;
|
|
}
|
|
long totalOut = deflater1.TotalOut;
|
|
zipStream.WriteInt(33639248);
|
|
zipStream.WriteShort(20);
|
|
zipStream.WriteShort(20);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(8);
|
|
zipStream.WriteInt((int) num1);
|
|
zipStream.WriteInt((int) num4);
|
|
zipStream.WriteInt((int) totalOut);
|
|
zipStream.WriteInt(buffer.Length);
|
|
zipStream.WriteShort(bytes.Length);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteInt(0);
|
|
zipStream.WriteInt(0);
|
|
zipStream.Write(bytes, 0, bytes.Length);
|
|
zipStream.WriteInt(101010256);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(0);
|
|
zipStream.WriteShort(1);
|
|
zipStream.WriteShort(1);
|
|
zipStream.WriteInt(46 + bytes.Length);
|
|
zipStream.WriteInt((int) ((long) (30 + bytes.Length) + totalOut));
|
|
zipStream.WriteShort(0);
|
|
zipStream.Seek(position1, SeekOrigin.Begin);
|
|
zipStream.WriteInt((int) totalOut);
|
|
break;
|
|
case 1:
|
|
zipStream.WriteInt(25000571);
|
|
zipStream.WriteInt(buffer.Length);
|
|
byte[] numArray4;
|
|
for (int srcOffset = 0; srcOffset < buffer.Length; srcOffset += numArray4.Length)
|
|
{
|
|
numArray4 = new byte[Math.Min(2097151, buffer.Length - srcOffset)];
|
|
Buffer.BlockCopy((Array) buffer, srcOffset, (Array) numArray4, 0, numArray4.Length);
|
|
long position2 = zipStream.Position;
|
|
zipStream.WriteInt(0);
|
|
zipStream.WriteInt(numArray4.Length);
|
|
SimpleZip.Deflater deflater2 = new SimpleZip.Deflater();
|
|
deflater2.SetInput(numArray4);
|
|
while (!deflater2.IsNeedingInput)
|
|
{
|
|
byte[] numArray5 = new byte[512];
|
|
int count = deflater2.Deflate(numArray5);
|
|
if (count > 0)
|
|
zipStream.Write(numArray5, 0, count);
|
|
else
|
|
break;
|
|
}
|
|
deflater2.Finish();
|
|
while (!deflater2.IsFinished)
|
|
{
|
|
byte[] numArray6 = new byte[512];
|
|
int count = deflater2.Deflate(numArray6);
|
|
if (count > 0)
|
|
zipStream.Write(numArray6, 0, count);
|
|
else
|
|
break;
|
|
}
|
|
long position3 = zipStream.Position;
|
|
zipStream.Position = position2;
|
|
zipStream.WriteInt((int) deflater2.TotalOut);
|
|
zipStream.Position = position3;
|
|
}
|
|
break;
|
|
case 2:
|
|
zipStream.WriteInt(41777787);
|
|
byte[] inputBuffer1 = SimpleZip.Zip(buffer, 1, (byte[]) null, (byte[]) null);
|
|
using (DESCryptoIndirector cryptoIndirector = new DESCryptoIndirector())
|
|
{
|
|
using (ICryptoTransform desCryptoTransform = cryptoIndirector.GetDESCryptoTransform(key, iv, false))
|
|
{
|
|
byte[] buffer1 = desCryptoTransform.TransformFinalBlock(inputBuffer1, 0, inputBuffer1.Length);
|
|
zipStream.Write(buffer1, 0, buffer1.Length);
|
|
break;
|
|
}
|
|
}
|
|
case 3:
|
|
zipStream.WriteInt(58555003);
|
|
byte[] inputBuffer2 = SimpleZip.Zip(buffer, 1, (byte[]) null, (byte[]) null);
|
|
using (AESCryptoIndirector cryptoIndirector = new AESCryptoIndirector())
|
|
{
|
|
using (ICryptoTransform aesCryptoTransform = cryptoIndirector.GetAESCryptoTransform(key, iv, false))
|
|
{
|
|
byte[] buffer2 = aesCryptoTransform.TransformFinalBlock(inputBuffer2, 0, inputBuffer2.Length);
|
|
zipStream.Write(buffer2, 0, buffer2.Length);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
zipStream.Flush();
|
|
zipStream.Close();
|
|
return zipStream.ToArray();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SimpleZip.ExceptionMessage = "ERR 2003: " + ex.Message;
|
|
throw;
|
|
}
|
|
}
|
|
|
|
internal sealed class Inflater
|
|
{
|
|
private const int DECODE_HEADER = 0;
|
|
private const int DECODE_DICT = 1;
|
|
private const int DECODE_BLOCKS = 2;
|
|
private const int DECODE_STORED_LEN1 = 3;
|
|
private const int DECODE_STORED_LEN2 = 4;
|
|
private const int DECODE_STORED = 5;
|
|
private const int DECODE_DYN_HEADER = 6;
|
|
private const int DECODE_HUFFMAN = 7;
|
|
private const int DECODE_HUFFMAN_LENBITS = 8;
|
|
private const int DECODE_HUFFMAN_DIST = 9;
|
|
private const int DECODE_HUFFMAN_DISTBITS = 10;
|
|
private const int DECODE_CHKSUM = 11;
|
|
private const int FINISHED = 12;
|
|
private static readonly int[] CPLENS = new int[29]
|
|
{
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7,
|
|
8,
|
|
9,
|
|
10,
|
|
11,
|
|
13,
|
|
15,
|
|
17,
|
|
19,
|
|
23,
|
|
27,
|
|
31,
|
|
35,
|
|
43,
|
|
51,
|
|
59,
|
|
67,
|
|
83,
|
|
99,
|
|
115,
|
|
131,
|
|
163,
|
|
195,
|
|
227,
|
|
258
|
|
};
|
|
private static readonly int[] CPLEXT = new int[29]
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
2,
|
|
2,
|
|
2,
|
|
2,
|
|
3,
|
|
3,
|
|
3,
|
|
3,
|
|
4,
|
|
4,
|
|
4,
|
|
4,
|
|
5,
|
|
5,
|
|
5,
|
|
5,
|
|
0
|
|
};
|
|
private static readonly int[] CPDIST = new int[30]
|
|
{
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
7,
|
|
9,
|
|
13,
|
|
17,
|
|
25,
|
|
33,
|
|
49,
|
|
65,
|
|
97,
|
|
129,
|
|
193,
|
|
257,
|
|
385,
|
|
513,
|
|
769,
|
|
1025,
|
|
1537,
|
|
2049,
|
|
3073,
|
|
4097,
|
|
6145,
|
|
8193,
|
|
12289,
|
|
16385,
|
|
24577
|
|
};
|
|
private static readonly int[] CPDEXT = new int[30]
|
|
{
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
2,
|
|
2,
|
|
3,
|
|
3,
|
|
4,
|
|
4,
|
|
5,
|
|
5,
|
|
6,
|
|
6,
|
|
7,
|
|
7,
|
|
8,
|
|
8,
|
|
9,
|
|
9,
|
|
10,
|
|
10,
|
|
11,
|
|
11,
|
|
12,
|
|
12,
|
|
13,
|
|
13
|
|
};
|
|
private int mode;
|
|
private int neededBits;
|
|
private int repLength;
|
|
private int repDist;
|
|
private int uncomprLen;
|
|
private bool isLastBlock;
|
|
private SimpleZip.StreamManipulator input;
|
|
private SimpleZip.OutputWindow outputWindow;
|
|
private SimpleZip.InflaterDynHeader dynHeader;
|
|
private SimpleZip.InflaterHuffmanTree litlenTree;
|
|
private SimpleZip.InflaterHuffmanTree distTree;
|
|
|
|
public Inflater(byte[] bytes)
|
|
{
|
|
this.input = new SimpleZip.StreamManipulator();
|
|
this.outputWindow = new SimpleZip.OutputWindow();
|
|
this.mode = 2;
|
|
this.input.SetInput(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
private bool DecodeHuffman()
|
|
{
|
|
int freeSpace = this.outputWindow.GetFreeSpace();
|
|
while (freeSpace >= 258)
|
|
{
|
|
switch (this.mode)
|
|
{
|
|
case 7:
|
|
int symbol1;
|
|
while (((symbol1 = this.litlenTree.GetSymbol(this.input)) & -256) == 0)
|
|
{
|
|
this.outputWindow.Write(symbol1);
|
|
if (--freeSpace < 258)
|
|
return true;
|
|
}
|
|
if (symbol1 < 257)
|
|
{
|
|
if (symbol1 < 0)
|
|
return false;
|
|
this.distTree = (SimpleZip.InflaterHuffmanTree) null;
|
|
this.litlenTree = (SimpleZip.InflaterHuffmanTree) null;
|
|
this.mode = 2;
|
|
return true;
|
|
}
|
|
this.repLength = SimpleZip.Inflater.CPLENS[symbol1 - 257];
|
|
this.neededBits = SimpleZip.Inflater.CPLEXT[symbol1 - 257];
|
|
goto case 8;
|
|
case 8:
|
|
if (this.neededBits > 0)
|
|
{
|
|
this.mode = 8;
|
|
int num = this.input.PeekBits(this.neededBits);
|
|
if (num < 0)
|
|
return false;
|
|
this.input.DropBits(this.neededBits);
|
|
this.repLength += num;
|
|
}
|
|
this.mode = 9;
|
|
goto case 9;
|
|
case 9:
|
|
int symbol2 = this.distTree.GetSymbol(this.input);
|
|
if (symbol2 < 0)
|
|
return false;
|
|
this.repDist = SimpleZip.Inflater.CPDIST[symbol2];
|
|
this.neededBits = SimpleZip.Inflater.CPDEXT[symbol2];
|
|
goto case 10;
|
|
case 10:
|
|
if (this.neededBits > 0)
|
|
{
|
|
this.mode = 10;
|
|
int num = this.input.PeekBits(this.neededBits);
|
|
if (num < 0)
|
|
return false;
|
|
this.input.DropBits(this.neededBits);
|
|
this.repDist += num;
|
|
}
|
|
this.outputWindow.Repeat(this.repLength, this.repDist);
|
|
freeSpace -= this.repLength;
|
|
this.mode = 7;
|
|
continue;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool Decode()
|
|
{
|
|
switch (this.mode)
|
|
{
|
|
case 2:
|
|
if (this.isLastBlock)
|
|
{
|
|
this.mode = 12;
|
|
return false;
|
|
}
|
|
int num = this.input.PeekBits(3);
|
|
if (num < 0)
|
|
return false;
|
|
this.input.DropBits(3);
|
|
if ((num & 1) != 0)
|
|
this.isLastBlock = true;
|
|
switch (num >> 1)
|
|
{
|
|
case 0:
|
|
this.input.SkipToByteBoundary();
|
|
this.mode = 3;
|
|
break;
|
|
case 1:
|
|
this.litlenTree = SimpleZip.InflaterHuffmanTree.defLitLenTree;
|
|
this.distTree = SimpleZip.InflaterHuffmanTree.defDistTree;
|
|
this.mode = 7;
|
|
break;
|
|
case 2:
|
|
this.dynHeader = new SimpleZip.InflaterDynHeader();
|
|
this.mode = 6;
|
|
break;
|
|
}
|
|
return true;
|
|
case 3:
|
|
if ((this.uncomprLen = this.input.PeekBits(16)) < 0)
|
|
return false;
|
|
this.input.DropBits(16);
|
|
this.mode = 4;
|
|
goto case 4;
|
|
case 4:
|
|
if (this.input.PeekBits(16) < 0)
|
|
return false;
|
|
this.input.DropBits(16);
|
|
this.mode = 5;
|
|
goto case 5;
|
|
case 5:
|
|
this.uncomprLen -= this.outputWindow.CopyStored(this.input, this.uncomprLen);
|
|
if (this.uncomprLen != 0)
|
|
return !this.input.IsNeedingInput;
|
|
this.mode = 2;
|
|
return true;
|
|
case 6:
|
|
if (!this.dynHeader.Decode(this.input))
|
|
return false;
|
|
this.litlenTree = this.dynHeader.BuildLitLenTree();
|
|
this.distTree = this.dynHeader.BuildDistTree();
|
|
this.mode = 7;
|
|
goto case 7;
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
return this.DecodeHuffman();
|
|
case 12:
|
|
return false;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int Inflate(byte[] buf, int offset, int len)
|
|
{
|
|
int num1 = 0;
|
|
do
|
|
{
|
|
if (this.mode != 11)
|
|
{
|
|
int num2 = this.outputWindow.CopyOutput(buf, offset, len);
|
|
offset += num2;
|
|
num1 += num2;
|
|
len -= num2;
|
|
if (len == 0)
|
|
return num1;
|
|
}
|
|
}
|
|
while (this.Decode() || this.outputWindow.GetAvailable() > 0 && this.mode != 11);
|
|
return num1;
|
|
}
|
|
}
|
|
|
|
internal sealed class StreamManipulator
|
|
{
|
|
private byte[] window;
|
|
private int window_start = 0;
|
|
private int window_end = 0;
|
|
private uint buffer = 0;
|
|
private int bits_in_buffer = 0;
|
|
|
|
public int PeekBits(int n)
|
|
{
|
|
if (this.bits_in_buffer < n)
|
|
{
|
|
if (this.window_start == this.window_end)
|
|
return -1;
|
|
this.buffer |= (uint) (((int) this.window[this.window_start++] & (int) byte.MaxValue | ((int) this.window[this.window_start++] & (int) byte.MaxValue) << 8) << this.bits_in_buffer);
|
|
this.bits_in_buffer += 16;
|
|
}
|
|
return (int) ((long) this.buffer & (long) ((1 << n) - 1));
|
|
}
|
|
|
|
public void DropBits(int n)
|
|
{
|
|
this.buffer >>= n;
|
|
this.bits_in_buffer -= n;
|
|
}
|
|
|
|
public int AvailableBits => this.bits_in_buffer;
|
|
|
|
public int AvailableBytes => this.window_end - this.window_start + (this.bits_in_buffer >> 3);
|
|
|
|
public void SkipToByteBoundary()
|
|
{
|
|
this.buffer >>= this.bits_in_buffer & 7;
|
|
this.bits_in_buffer &= -8;
|
|
}
|
|
|
|
public bool IsNeedingInput => this.window_start == this.window_end;
|
|
|
|
public int CopyBytes(byte[] output, int offset, int length)
|
|
{
|
|
int num1 = 0;
|
|
while (this.bits_in_buffer > 0 && length > 0)
|
|
{
|
|
output[offset++] = (byte) this.buffer;
|
|
this.buffer >>= 8;
|
|
this.bits_in_buffer -= 8;
|
|
--length;
|
|
++num1;
|
|
}
|
|
if (length == 0)
|
|
return num1;
|
|
int num2 = this.window_end - this.window_start;
|
|
if (length > num2)
|
|
length = num2;
|
|
Array.Copy((Array) this.window, this.window_start, (Array) output, offset, length);
|
|
this.window_start += length;
|
|
if ((this.window_start - this.window_end & 1) != 0)
|
|
{
|
|
this.buffer = (uint) this.window[this.window_start++] & (uint) byte.MaxValue;
|
|
this.bits_in_buffer = 8;
|
|
}
|
|
return num1 + length;
|
|
}
|
|
|
|
public void Reset() => this.buffer = (uint) (this.window_start = this.window_end = this.bits_in_buffer = 0);
|
|
|
|
public void SetInput(byte[] buf, int off, int len)
|
|
{
|
|
if (this.window_start < this.window_end)
|
|
throw new InvalidOperationException();
|
|
int num = off + len;
|
|
if (0 > off || off > num || num > buf.Length)
|
|
throw new ArgumentOutOfRangeException();
|
|
if ((len & 1) != 0)
|
|
{
|
|
this.buffer |= (uint) (((int) buf[off++] & (int) byte.MaxValue) << this.bits_in_buffer);
|
|
this.bits_in_buffer += 8;
|
|
}
|
|
this.window = buf;
|
|
this.window_start = off;
|
|
this.window_end = num;
|
|
}
|
|
}
|
|
|
|
internal sealed class OutputWindow
|
|
{
|
|
private const int WINDOW_SIZE = 32768;
|
|
private const int WINDOW_MASK = 32767;
|
|
private byte[] window = new byte[32768];
|
|
private int windowEnd = 0;
|
|
private int windowFilled = 0;
|
|
|
|
public void Write(int abyte)
|
|
{
|
|
if (this.windowFilled++ == 32768)
|
|
throw new InvalidOperationException();
|
|
this.window[this.windowEnd++] = (byte) abyte;
|
|
this.windowEnd &= (int) short.MaxValue;
|
|
}
|
|
|
|
private void SlowRepeat(int repStart, int len, int dist)
|
|
{
|
|
while (len-- > 0)
|
|
{
|
|
this.window[this.windowEnd++] = this.window[repStart++];
|
|
this.windowEnd &= (int) short.MaxValue;
|
|
repStart &= (int) short.MaxValue;
|
|
}
|
|
}
|
|
|
|
public void Repeat(int len, int dist)
|
|
{
|
|
if ((this.windowFilled += len) > 32768)
|
|
throw new InvalidOperationException();
|
|
int num1 = this.windowEnd - dist & (int) short.MaxValue;
|
|
int num2 = 32768 - len;
|
|
if (num1 <= num2 && this.windowEnd < num2)
|
|
{
|
|
if (len <= dist)
|
|
{
|
|
Array.Copy((Array) this.window, num1, (Array) this.window, this.windowEnd, len);
|
|
this.windowEnd += len;
|
|
}
|
|
else
|
|
{
|
|
while (len-- > 0)
|
|
this.window[this.windowEnd++] = this.window[num1++];
|
|
}
|
|
}
|
|
else
|
|
this.SlowRepeat(num1, len, dist);
|
|
}
|
|
|
|
public int CopyStored(SimpleZip.StreamManipulator input, int len)
|
|
{
|
|
len = Math.Min(Math.Min(len, 32768 - this.windowFilled), input.AvailableBytes);
|
|
int length = 32768 - this.windowEnd;
|
|
int num;
|
|
if (len > length)
|
|
{
|
|
num = input.CopyBytes(this.window, this.windowEnd, length);
|
|
if (num == length)
|
|
num += input.CopyBytes(this.window, 0, len - length);
|
|
}
|
|
else
|
|
num = input.CopyBytes(this.window, this.windowEnd, len);
|
|
this.windowEnd = this.windowEnd + num & (int) short.MaxValue;
|
|
this.windowFilled += num;
|
|
return num;
|
|
}
|
|
|
|
public void CopyDict(byte[] dict, int offset, int len)
|
|
{
|
|
if (this.windowFilled > 0)
|
|
throw new InvalidOperationException();
|
|
if (len > 32768)
|
|
{
|
|
offset += len - 32768;
|
|
len = 32768;
|
|
}
|
|
Array.Copy((Array) dict, offset, (Array) this.window, 0, len);
|
|
this.windowEnd = len & (int) short.MaxValue;
|
|
}
|
|
|
|
public int GetFreeSpace() => 32768 - this.windowFilled;
|
|
|
|
public int GetAvailable() => this.windowFilled;
|
|
|
|
public int CopyOutput(byte[] output, int offset, int len)
|
|
{
|
|
int num1 = this.windowEnd;
|
|
if (len > this.windowFilled)
|
|
len = this.windowFilled;
|
|
else
|
|
num1 = this.windowEnd - this.windowFilled + len & (int) short.MaxValue;
|
|
int num2 = len;
|
|
int length = len - num1;
|
|
if (length > 0)
|
|
{
|
|
Array.Copy((Array) this.window, 32768 - length, (Array) output, offset, length);
|
|
offset += length;
|
|
len = num1;
|
|
}
|
|
Array.Copy((Array) this.window, num1 - len, (Array) output, offset, len);
|
|
this.windowFilled -= num2;
|
|
if (this.windowFilled < 0)
|
|
throw new InvalidOperationException();
|
|
return num2;
|
|
}
|
|
|
|
public void Reset() => this.windowFilled = this.windowEnd = 0;
|
|
}
|
|
|
|
internal sealed class InflaterHuffmanTree
|
|
{
|
|
private const int MAX_BITLEN = 15;
|
|
private short[] tree;
|
|
public static readonly SimpleZip.InflaterHuffmanTree defLitLenTree;
|
|
public static readonly SimpleZip.InflaterHuffmanTree defDistTree;
|
|
|
|
static InflaterHuffmanTree()
|
|
{
|
|
byte[] codeLengths1 = new byte[288];
|
|
int num1 = 0;
|
|
while (num1 < 144)
|
|
codeLengths1[num1++] = (byte) 8;
|
|
while (num1 < 256)
|
|
codeLengths1[num1++] = (byte) 9;
|
|
while (num1 < 280)
|
|
codeLengths1[num1++] = (byte) 7;
|
|
while (num1 < 288)
|
|
codeLengths1[num1++] = (byte) 8;
|
|
SimpleZip.InflaterHuffmanTree.defLitLenTree = new SimpleZip.InflaterHuffmanTree(codeLengths1);
|
|
byte[] codeLengths2 = new byte[32];
|
|
int num2 = 0;
|
|
while (num2 < 32)
|
|
codeLengths2[num2++] = (byte) 5;
|
|
SimpleZip.InflaterHuffmanTree.defDistTree = new SimpleZip.InflaterHuffmanTree(codeLengths2);
|
|
}
|
|
|
|
public InflaterHuffmanTree(byte[] codeLengths) => this.BuildTree(codeLengths);
|
|
|
|
private void BuildTree(byte[] codeLengths)
|
|
{
|
|
int[] numArray1 = new int[16];
|
|
int[] numArray2 = new int[16];
|
|
for (int index = 0; index < codeLengths.Length; ++index)
|
|
{
|
|
int codeLength = (int) codeLengths[index];
|
|
if (codeLength > 0)
|
|
++numArray1[codeLength];
|
|
}
|
|
int num1 = 0;
|
|
int length = 512;
|
|
for (int index = 1; index <= 15; ++index)
|
|
{
|
|
numArray2[index] = num1;
|
|
num1 += numArray1[index] << 16 - index;
|
|
if (index >= 10)
|
|
{
|
|
int num2 = numArray2[index] & 130944;
|
|
int num3 = num1 & 130944;
|
|
length += num3 - num2 >> 16 - index;
|
|
}
|
|
}
|
|
this.tree = new short[length];
|
|
int num4 = 512;
|
|
for (int index = 15; index >= 10; --index)
|
|
{
|
|
int num5 = num1 & 130944;
|
|
num1 -= numArray1[index] << 16 - index;
|
|
for (int toReverse = num1 & 130944; toReverse < num5; toReverse += 128)
|
|
{
|
|
this.tree[(int) SimpleZip.DeflaterHuffman.BitReverse(toReverse)] = (short) (-num4 << 4 | index);
|
|
num4 += 1 << index - 9;
|
|
}
|
|
}
|
|
for (int index1 = 0; index1 < codeLengths.Length; ++index1)
|
|
{
|
|
int codeLength = (int) codeLengths[index1];
|
|
if (codeLength != 0)
|
|
{
|
|
int toReverse = numArray2[codeLength];
|
|
int index2 = (int) SimpleZip.DeflaterHuffman.BitReverse(toReverse);
|
|
if (codeLength <= 9)
|
|
{
|
|
do
|
|
{
|
|
this.tree[index2] = (short) (index1 << 4 | codeLength);
|
|
index2 += 1 << codeLength;
|
|
}
|
|
while (index2 < 512);
|
|
}
|
|
else
|
|
{
|
|
int num6 = (int) this.tree[index2 & 511];
|
|
int num7 = 1 << (num6 & 15);
|
|
int num8 = -(num6 >> 4);
|
|
do
|
|
{
|
|
this.tree[num8 | index2 >> 9] = (short) (index1 << 4 | codeLength);
|
|
index2 += 1 << codeLength;
|
|
}
|
|
while (index2 < num7);
|
|
}
|
|
numArray2[codeLength] = toReverse + (1 << 16 - codeLength);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int GetSymbol(SimpleZip.StreamManipulator input)
|
|
{
|
|
int index;
|
|
if ((index = input.PeekBits(9)) >= 0)
|
|
{
|
|
int num1;
|
|
if ((num1 = (int) this.tree[index]) >= 0)
|
|
{
|
|
input.DropBits(num1 & 15);
|
|
return num1 >> 4;
|
|
}
|
|
int num2 = -(num1 >> 4);
|
|
int n = num1 & 15;
|
|
int num3;
|
|
if ((num3 = input.PeekBits(n)) >= 0)
|
|
{
|
|
int num4 = (int) this.tree[num2 | num3 >> 9];
|
|
input.DropBits(num4 & 15);
|
|
return num4 >> 4;
|
|
}
|
|
int availableBits = input.AvailableBits;
|
|
int num5 = input.PeekBits(availableBits);
|
|
int num6 = (int) this.tree[num2 | num5 >> 9];
|
|
if ((num6 & 15) > availableBits)
|
|
return -1;
|
|
input.DropBits(num6 & 15);
|
|
return num6 >> 4;
|
|
}
|
|
int availableBits1 = input.AvailableBits;
|
|
int num = (int) this.tree[input.PeekBits(availableBits1)];
|
|
if (num < 0 || (num & 15) > availableBits1)
|
|
return -1;
|
|
input.DropBits(num & 15);
|
|
return num >> 4;
|
|
}
|
|
}
|
|
|
|
internal sealed class InflaterDynHeader
|
|
{
|
|
private const int LNUM = 0;
|
|
private const int DNUM = 1;
|
|
private const int BLNUM = 2;
|
|
private const int BLLENS = 3;
|
|
private const int LENS = 4;
|
|
private const int REPS = 5;
|
|
private static readonly int[] repMin = new int[3]
|
|
{
|
|
3,
|
|
3,
|
|
11
|
|
};
|
|
private static readonly int[] repBits = new int[3]
|
|
{
|
|
2,
|
|
3,
|
|
7
|
|
};
|
|
private byte[] blLens;
|
|
private byte[] litdistLens;
|
|
private SimpleZip.InflaterHuffmanTree blTree;
|
|
private int mode;
|
|
private int lnum;
|
|
private int dnum;
|
|
private int blnum;
|
|
private int num;
|
|
private int repSymbol;
|
|
private byte lastLen;
|
|
private int ptr;
|
|
private static readonly int[] BL_ORDER = new int[19]
|
|
{
|
|
16,
|
|
17,
|
|
18,
|
|
0,
|
|
8,
|
|
7,
|
|
9,
|
|
6,
|
|
10,
|
|
5,
|
|
11,
|
|
4,
|
|
12,
|
|
3,
|
|
13,
|
|
2,
|
|
14,
|
|
1,
|
|
15
|
|
};
|
|
|
|
public bool Decode(SimpleZip.StreamManipulator input)
|
|
{
|
|
while (true)
|
|
{
|
|
switch (this.mode)
|
|
{
|
|
case 0:
|
|
this.lnum = input.PeekBits(5);
|
|
if (this.lnum >= 0)
|
|
{
|
|
this.lnum += 257;
|
|
input.DropBits(5);
|
|
this.mode = 1;
|
|
goto case 1;
|
|
}
|
|
else
|
|
goto label_2;
|
|
case 1:
|
|
this.dnum = input.PeekBits(5);
|
|
if (this.dnum >= 0)
|
|
{
|
|
++this.dnum;
|
|
input.DropBits(5);
|
|
this.num = this.lnum + this.dnum;
|
|
this.litdistLens = new byte[this.num];
|
|
this.mode = 2;
|
|
goto case 2;
|
|
}
|
|
else
|
|
goto label_5;
|
|
case 2:
|
|
this.blnum = input.PeekBits(4);
|
|
if (this.blnum >= 0)
|
|
{
|
|
this.blnum += 4;
|
|
input.DropBits(4);
|
|
this.blLens = new byte[19];
|
|
this.ptr = 0;
|
|
this.mode = 3;
|
|
goto case 3;
|
|
}
|
|
else
|
|
goto label_8;
|
|
case 3:
|
|
for (; this.ptr < this.blnum; ++this.ptr)
|
|
{
|
|
int num = input.PeekBits(3);
|
|
if (num < 0)
|
|
return false;
|
|
input.DropBits(3);
|
|
this.blLens[SimpleZip.InflaterDynHeader.BL_ORDER[this.ptr]] = (byte) num;
|
|
}
|
|
this.blTree = new SimpleZip.InflaterHuffmanTree(this.blLens);
|
|
this.blLens = (byte[]) null;
|
|
this.ptr = 0;
|
|
this.mode = 4;
|
|
goto case 4;
|
|
case 4:
|
|
int symbol;
|
|
while (((symbol = this.blTree.GetSymbol(input)) & -16) == 0)
|
|
{
|
|
this.litdistLens[this.ptr++] = this.lastLen = (byte) symbol;
|
|
if (this.ptr == this.num)
|
|
return true;
|
|
}
|
|
if (symbol >= 0)
|
|
{
|
|
if (symbol >= 17)
|
|
this.lastLen = (byte) 0;
|
|
this.repSymbol = symbol - 16;
|
|
this.mode = 5;
|
|
goto case 5;
|
|
}
|
|
else
|
|
goto label_19;
|
|
case 5:
|
|
int repBit = SimpleZip.InflaterDynHeader.repBits[this.repSymbol];
|
|
int num1 = input.PeekBits(repBit);
|
|
if (num1 >= 0)
|
|
{
|
|
input.DropBits(repBit);
|
|
int num2 = num1 + SimpleZip.InflaterDynHeader.repMin[this.repSymbol];
|
|
while (num2-- > 0)
|
|
this.litdistLens[this.ptr++] = this.lastLen;
|
|
if (this.ptr != this.num)
|
|
{
|
|
this.mode = 4;
|
|
continue;
|
|
}
|
|
goto label_29;
|
|
}
|
|
else
|
|
goto label_24;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
label_2:
|
|
return false;
|
|
label_5:
|
|
return false;
|
|
label_8:
|
|
return false;
|
|
label_19:
|
|
return false;
|
|
label_24:
|
|
return false;
|
|
label_29:
|
|
return true;
|
|
}
|
|
|
|
public SimpleZip.InflaterHuffmanTree BuildLitLenTree()
|
|
{
|
|
byte[] numArray = new byte[this.lnum];
|
|
Array.Copy((Array) this.litdistLens, 0, (Array) numArray, 0, this.lnum);
|
|
return new SimpleZip.InflaterHuffmanTree(numArray);
|
|
}
|
|
|
|
public SimpleZip.InflaterHuffmanTree BuildDistTree()
|
|
{
|
|
byte[] numArray = new byte[this.dnum];
|
|
Array.Copy((Array) this.litdistLens, this.lnum, (Array) numArray, 0, this.dnum);
|
|
return new SimpleZip.InflaterHuffmanTree(numArray);
|
|
}
|
|
}
|
|
|
|
internal sealed class Deflater
|
|
{
|
|
private const int IS_FLUSHING = 4;
|
|
private const int IS_FINISHING = 8;
|
|
private const int BUSY_STATE = 16;
|
|
private const int FLUSHING_STATE = 20;
|
|
private const int FINISHING_STATE = 28;
|
|
private const int FINISHED_STATE = 30;
|
|
private int state = 16;
|
|
private long totalOut = 0;
|
|
private SimpleZip.DeflaterPending pending;
|
|
private SimpleZip.DeflaterEngine engine;
|
|
|
|
public Deflater()
|
|
{
|
|
this.pending = new SimpleZip.DeflaterPending();
|
|
this.engine = new SimpleZip.DeflaterEngine(this.pending);
|
|
}
|
|
|
|
public long TotalOut => this.totalOut;
|
|
|
|
public void Finish() => this.state |= 12;
|
|
|
|
public bool IsFinished => this.state == 30 && this.pending.IsFlushed;
|
|
|
|
public bool IsNeedingInput => this.engine.NeedsInput();
|
|
|
|
public void SetInput(byte[] buffer) => this.engine.SetInput(buffer);
|
|
|
|
public int Deflate(byte[] output)
|
|
{
|
|
int offset = 0;
|
|
int length = output.Length;
|
|
int num1 = length;
|
|
while (true)
|
|
{
|
|
do
|
|
{
|
|
do
|
|
{
|
|
int num2 = this.pending.Flush(output, offset, length);
|
|
offset += num2;
|
|
this.totalOut += (long) num2;
|
|
length -= num2;
|
|
if (length == 0 || this.state == 30)
|
|
goto label_12;
|
|
}
|
|
while (this.engine.Deflate((this.state & 4) != 0, (this.state & 8) != 0));
|
|
if (this.state == 16)
|
|
return num1 - length;
|
|
if (this.state == 20)
|
|
{
|
|
for (int index = 8 + (-this.pending.BitCount & 7); index > 0; index -= 10)
|
|
this.pending.WriteBits(2, 10);
|
|
this.state = 16;
|
|
}
|
|
}
|
|
while (this.state != 28);
|
|
this.pending.AlignToByte();
|
|
this.state = 30;
|
|
}
|
|
label_12:
|
|
return num1 - length;
|
|
}
|
|
}
|
|
|
|
internal sealed class DeflaterHuffman
|
|
{
|
|
private const int BUFSIZE = 16384;
|
|
private const int LITERAL_NUM = 286;
|
|
private const int DIST_NUM = 30;
|
|
private const int BITLEN_NUM = 19;
|
|
private const int REP_3_6 = 16;
|
|
private const int REP_3_10 = 17;
|
|
private const int REP_11_138 = 18;
|
|
private const int EOF_SYMBOL = 256;
|
|
private static readonly int[] BL_ORDER = new int[19]
|
|
{
|
|
16,
|
|
17,
|
|
18,
|
|
0,
|
|
8,
|
|
7,
|
|
9,
|
|
6,
|
|
10,
|
|
5,
|
|
11,
|
|
4,
|
|
12,
|
|
3,
|
|
13,
|
|
2,
|
|
14,
|
|
1,
|
|
15
|
|
};
|
|
private static readonly byte[] bit4Reverse = new byte[16]
|
|
{
|
|
(byte) 0,
|
|
(byte) 8,
|
|
(byte) 4,
|
|
(byte) 12,
|
|
(byte) 2,
|
|
(byte) 10,
|
|
(byte) 6,
|
|
(byte) 14,
|
|
(byte) 1,
|
|
(byte) 9,
|
|
(byte) 5,
|
|
(byte) 13,
|
|
(byte) 3,
|
|
(byte) 11,
|
|
(byte) 7,
|
|
(byte) 15
|
|
};
|
|
private SimpleZip.DeflaterPending pending;
|
|
private SimpleZip.DeflaterHuffman.Tree literalTree;
|
|
private SimpleZip.DeflaterHuffman.Tree distTree;
|
|
private SimpleZip.DeflaterHuffman.Tree blTree;
|
|
private short[] d_buf;
|
|
private byte[] l_buf;
|
|
private int last_lit;
|
|
private int extra_bits;
|
|
private static readonly short[] staticLCodes = new short[286];
|
|
private static readonly byte[] staticLLength = new byte[286];
|
|
private static readonly short[] staticDCodes;
|
|
private static readonly byte[] staticDLength;
|
|
|
|
public static short BitReverse(int toReverse) => (short) ((int) SimpleZip.DeflaterHuffman.bit4Reverse[toReverse & 15] << 12 | (int) SimpleZip.DeflaterHuffman.bit4Reverse[toReverse >> 4 & 15] << 8 | (int) SimpleZip.DeflaterHuffman.bit4Reverse[toReverse >> 8 & 15] << 4 | (int) SimpleZip.DeflaterHuffman.bit4Reverse[toReverse >> 12]);
|
|
|
|
static DeflaterHuffman()
|
|
{
|
|
int index1;
|
|
for (index1 = 0; index1 < 144; SimpleZip.DeflaterHuffman.staticLLength[index1++] = (byte) 8)
|
|
SimpleZip.DeflaterHuffman.staticLCodes[index1] = SimpleZip.DeflaterHuffman.BitReverse(48 + index1 << 8);
|
|
for (; index1 < 256; SimpleZip.DeflaterHuffman.staticLLength[index1++] = (byte) 9)
|
|
SimpleZip.DeflaterHuffman.staticLCodes[index1] = SimpleZip.DeflaterHuffman.BitReverse(256 + index1 << 7);
|
|
for (; index1 < 280; SimpleZip.DeflaterHuffman.staticLLength[index1++] = (byte) 7)
|
|
SimpleZip.DeflaterHuffman.staticLCodes[index1] = SimpleZip.DeflaterHuffman.BitReverse(index1 - 256 << 9);
|
|
for (; index1 < 286; SimpleZip.DeflaterHuffman.staticLLength[index1++] = (byte) 8)
|
|
SimpleZip.DeflaterHuffman.staticLCodes[index1] = SimpleZip.DeflaterHuffman.BitReverse(index1 - 88 << 8);
|
|
SimpleZip.DeflaterHuffman.staticDCodes = new short[30];
|
|
SimpleZip.DeflaterHuffman.staticDLength = new byte[30];
|
|
for (int index2 = 0; index2 < 30; ++index2)
|
|
{
|
|
SimpleZip.DeflaterHuffman.staticDCodes[index2] = SimpleZip.DeflaterHuffman.BitReverse(index2 << 11);
|
|
SimpleZip.DeflaterHuffman.staticDLength[index2] = (byte) 5;
|
|
}
|
|
}
|
|
|
|
public DeflaterHuffman(SimpleZip.DeflaterPending pending)
|
|
{
|
|
this.pending = pending;
|
|
this.literalTree = new SimpleZip.DeflaterHuffman.Tree(this, 286, 257, 15);
|
|
this.distTree = new SimpleZip.DeflaterHuffman.Tree(this, 30, 1, 15);
|
|
this.blTree = new SimpleZip.DeflaterHuffman.Tree(this, 19, 4, 7);
|
|
this.d_buf = new short[16384];
|
|
this.l_buf = new byte[16384];
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
this.last_lit = 0;
|
|
this.extra_bits = 0;
|
|
}
|
|
|
|
private int Lcode(int len)
|
|
{
|
|
if (len == (int) byte.MaxValue)
|
|
return 285;
|
|
int num = 257;
|
|
for (; len >= 8; len >>= 1)
|
|
num += 4;
|
|
return num + len;
|
|
}
|
|
|
|
private int Dcode(int distance)
|
|
{
|
|
int num = 0;
|
|
for (; distance >= 4; distance >>= 1)
|
|
num += 2;
|
|
return num + distance;
|
|
}
|
|
|
|
public void SendAllTrees(int blTreeCodes)
|
|
{
|
|
this.blTree.BuildCodes();
|
|
this.literalTree.BuildCodes();
|
|
this.distTree.BuildCodes();
|
|
this.pending.WriteBits(this.literalTree.numCodes - 257, 5);
|
|
this.pending.WriteBits(this.distTree.numCodes - 1, 5);
|
|
this.pending.WriteBits(blTreeCodes - 4, 4);
|
|
for (int index = 0; index < blTreeCodes; ++index)
|
|
this.pending.WriteBits((int) this.blTree.length[SimpleZip.DeflaterHuffman.BL_ORDER[index]], 3);
|
|
this.literalTree.WriteTree(this.blTree);
|
|
this.distTree.WriteTree(this.blTree);
|
|
}
|
|
|
|
public void CompressBlock()
|
|
{
|
|
for (int index = 0; index < this.last_lit; ++index)
|
|
{
|
|
int num1 = (int) this.l_buf[index] & (int) byte.MaxValue;
|
|
int num2 = (int) this.d_buf[index];
|
|
int distance = num2 - 1;
|
|
if (num2 != 0)
|
|
{
|
|
int code1 = this.Lcode(num1);
|
|
this.literalTree.WriteSymbol(code1);
|
|
int count1 = (code1 - 261) / 4;
|
|
if (count1 > 0 && count1 <= 5)
|
|
this.pending.WriteBits(num1 & (1 << count1) - 1, count1);
|
|
int code2 = this.Dcode(distance);
|
|
this.distTree.WriteSymbol(code2);
|
|
int count2 = code2 / 2 - 1;
|
|
if (count2 > 0)
|
|
this.pending.WriteBits(distance & (1 << count2) - 1, count2);
|
|
}
|
|
else
|
|
this.literalTree.WriteSymbol(num1);
|
|
}
|
|
this.literalTree.WriteSymbol(256);
|
|
}
|
|
|
|
public void FlushStoredBlock(
|
|
byte[] stored,
|
|
int storedOffset,
|
|
int storedLength,
|
|
bool lastBlock)
|
|
{
|
|
this.pending.WriteBits(lastBlock ? 1 : 0, 3);
|
|
this.pending.AlignToByte();
|
|
this.pending.WriteShort(storedLength);
|
|
this.pending.WriteShort(~storedLength);
|
|
this.pending.WriteBlock(stored, storedOffset, storedLength);
|
|
this.Init();
|
|
}
|
|
|
|
public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock)
|
|
{
|
|
short[] freqs;
|
|
(freqs = this.literalTree.freqs)[256] = (short) ((int) freqs[256] + 1);
|
|
this.literalTree.BuildTree();
|
|
this.distTree.BuildTree();
|
|
this.literalTree.CalcBLFreq(this.blTree);
|
|
this.distTree.CalcBLFreq(this.blTree);
|
|
this.blTree.BuildTree();
|
|
int blTreeCodes = 4;
|
|
for (int index = 18; index > blTreeCodes; --index)
|
|
{
|
|
if (this.blTree.length[SimpleZip.DeflaterHuffman.BL_ORDER[index]] > (byte) 0)
|
|
blTreeCodes = index + 1;
|
|
}
|
|
int num = 14 + blTreeCodes * 3 + this.blTree.GetEncodedLength() + this.literalTree.GetEncodedLength() + this.distTree.GetEncodedLength() + this.extra_bits;
|
|
int extraBits = this.extra_bits;
|
|
for (int index = 0; index < 286; ++index)
|
|
extraBits += (int) this.literalTree.freqs[index] * (int) SimpleZip.DeflaterHuffman.staticLLength[index];
|
|
for (int index = 0; index < 30; ++index)
|
|
extraBits += (int) this.distTree.freqs[index] * (int) SimpleZip.DeflaterHuffman.staticDLength[index];
|
|
if (num >= extraBits)
|
|
num = extraBits;
|
|
if (storedOffset >= 0 && storedLength + 4 < num >> 3)
|
|
this.FlushStoredBlock(stored, storedOffset, storedLength, lastBlock);
|
|
else if (num == extraBits)
|
|
{
|
|
this.pending.WriteBits(2 + (lastBlock ? 1 : 0), 3);
|
|
this.literalTree.SetStaticCodes(SimpleZip.DeflaterHuffman.staticLCodes, SimpleZip.DeflaterHuffman.staticLLength);
|
|
this.distTree.SetStaticCodes(SimpleZip.DeflaterHuffman.staticDCodes, SimpleZip.DeflaterHuffman.staticDLength);
|
|
this.CompressBlock();
|
|
this.Init();
|
|
}
|
|
else
|
|
{
|
|
this.pending.WriteBits(4 + (lastBlock ? 1 : 0), 3);
|
|
this.SendAllTrees(blTreeCodes);
|
|
this.CompressBlock();
|
|
this.Init();
|
|
}
|
|
}
|
|
|
|
public bool IsFull() => this.last_lit >= 16384;
|
|
|
|
public bool TallyLit(int lit)
|
|
{
|
|
this.d_buf[this.last_lit] = (short) 0;
|
|
this.l_buf[this.last_lit++] = (byte) lit;
|
|
short[] freqs;
|
|
IntPtr index;
|
|
(freqs = this.literalTree.freqs)[(int) (index = (IntPtr) lit)] = (short) ((int) freqs[index] + 1);
|
|
return this.IsFull();
|
|
}
|
|
|
|
public bool TallyDist(int dist, int len)
|
|
{
|
|
this.d_buf[this.last_lit] = (short) dist;
|
|
this.l_buf[this.last_lit++] = (byte) (len - 3);
|
|
int num1 = this.Lcode(len - 3);
|
|
short[] freqs1;
|
|
IntPtr index1;
|
|
(freqs1 = this.literalTree.freqs)[(int) (index1 = (IntPtr) num1)] = (short) ((int) freqs1[index1] + 1);
|
|
if (num1 >= 265 && num1 < 285)
|
|
this.extra_bits += (num1 - 261) / 4;
|
|
int num2 = this.Dcode(dist - 1);
|
|
short[] freqs2;
|
|
IntPtr index2;
|
|
(freqs2 = this.distTree.freqs)[(int) (index2 = (IntPtr) num2)] = (short) ((int) freqs2[index2] + 1);
|
|
if (num2 >= 4)
|
|
this.extra_bits += num2 / 2 - 1;
|
|
return this.IsFull();
|
|
}
|
|
|
|
public sealed class Tree
|
|
{
|
|
public short[] freqs;
|
|
public byte[] length;
|
|
public int minNumCodes;
|
|
public int numCodes;
|
|
private short[] codes;
|
|
private int[] bl_counts;
|
|
private int maxLength;
|
|
private SimpleZip.DeflaterHuffman dh;
|
|
|
|
public Tree(SimpleZip.DeflaterHuffman dh, int elems, int minCodes, int maxLength)
|
|
{
|
|
this.dh = dh;
|
|
this.minNumCodes = minCodes;
|
|
this.maxLength = maxLength;
|
|
this.freqs = new short[elems];
|
|
this.bl_counts = new int[maxLength];
|
|
}
|
|
|
|
public void WriteSymbol(int code) => this.dh.pending.WriteBits((int) this.codes[code] & (int) ushort.MaxValue, (int) this.length[code]);
|
|
|
|
public void SetStaticCodes(short[] stCodes, byte[] stLength)
|
|
{
|
|
this.codes = stCodes;
|
|
this.length = stLength;
|
|
}
|
|
|
|
public void BuildCodes()
|
|
{
|
|
int length = this.freqs.Length;
|
|
int[] numArray = new int[this.maxLength];
|
|
int num1 = 0;
|
|
this.codes = new short[this.freqs.Length];
|
|
for (int index = 0; index < this.maxLength; ++index)
|
|
{
|
|
numArray[index] = num1;
|
|
num1 += this.bl_counts[index] << 15 - index;
|
|
}
|
|
for (int index = 0; index < this.numCodes; ++index)
|
|
{
|
|
int num2 = (int) this.length[index];
|
|
if (num2 > 0)
|
|
{
|
|
this.codes[index] = SimpleZip.DeflaterHuffman.BitReverse(numArray[num2 - 1]);
|
|
numArray[num2 - 1] += 1 << 16 - num2;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void BuildLength(int[] childs)
|
|
{
|
|
this.length = new byte[this.freqs.Length];
|
|
int length = childs.Length / 2;
|
|
int num1 = (length + 1) / 2;
|
|
int num2 = 0;
|
|
for (int index = 0; index < this.maxLength; ++index)
|
|
this.bl_counts[index] = 0;
|
|
int[] numArray1 = new int[length];
|
|
numArray1[length - 1] = 0;
|
|
for (int index = length - 1; index >= 0; --index)
|
|
{
|
|
if (childs[2 * index + 1] != -1)
|
|
{
|
|
int num3 = numArray1[index] + 1;
|
|
if (num3 > this.maxLength)
|
|
{
|
|
num3 = this.maxLength;
|
|
++num2;
|
|
}
|
|
numArray1[childs[2 * index]] = numArray1[childs[2 * index + 1]] = num3;
|
|
}
|
|
else
|
|
{
|
|
++this.bl_counts[numArray1[index] - 1];
|
|
this.length[childs[2 * index]] = (byte) numArray1[index];
|
|
}
|
|
}
|
|
if (num2 == 0)
|
|
return;
|
|
int index1 = this.maxLength - 1;
|
|
do
|
|
{
|
|
do
|
|
;
|
|
while (this.bl_counts[--index1] == 0);
|
|
do
|
|
{
|
|
--this.bl_counts[index1];
|
|
int[] blCounts;
|
|
int[] numArray2 = blCounts = this.bl_counts;
|
|
int index2;
|
|
index1 = index2 = index1 + 1;
|
|
int index3 = index2;
|
|
int num4 = numArray2[(IntPtr) index3] + 1;
|
|
blCounts[index2] = num4;
|
|
num2 -= 1 << this.maxLength - 1 - index1;
|
|
}
|
|
while (num2 > 0 && index1 < this.maxLength - 1);
|
|
}
|
|
while (num2 > 0);
|
|
this.bl_counts[this.maxLength - 1] += num2;
|
|
this.bl_counts[this.maxLength - 2] -= num2;
|
|
int num5 = 2 * num1;
|
|
for (int maxLength = this.maxLength; maxLength != 0; --maxLength)
|
|
{
|
|
int blCount = this.bl_counts[maxLength - 1];
|
|
while (blCount > 0)
|
|
{
|
|
int index4 = 2 * childs[num5++];
|
|
if (childs[index4 + 1] == -1)
|
|
{
|
|
this.length[childs[index4]] = (byte) maxLength;
|
|
--blCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void BuildTree()
|
|
{
|
|
int length = this.freqs.Length;
|
|
int[] numArray1 = new int[length];
|
|
int num1 = 0;
|
|
int num2 = 0;
|
|
for (int index1 = 0; index1 < length; ++index1)
|
|
{
|
|
int freq = (int) this.freqs[index1];
|
|
if (freq != 0)
|
|
{
|
|
int index2;
|
|
int index3;
|
|
for (index2 = num1++; index2 > 0 && (int) this.freqs[numArray1[index3 = (index2 - 1) / 2]] > freq; index2 = index3)
|
|
numArray1[index2] = numArray1[index3];
|
|
numArray1[index2] = index1;
|
|
num2 = index1;
|
|
}
|
|
}
|
|
int num3;
|
|
for (; num1 < 2; numArray1[num1++] = num3)
|
|
{
|
|
int num4;
|
|
if (num2 >= 2)
|
|
num4 = 0;
|
|
else
|
|
num2 = num4 = num2 + 1;
|
|
num3 = num4;
|
|
}
|
|
this.numCodes = Math.Max(num2 + 1, this.minNumCodes);
|
|
int num5 = num1;
|
|
int[] childs = new int[4 * num1 - 2];
|
|
int[] numArray2 = new int[2 * num1 - 1];
|
|
int num6 = num5;
|
|
for (int index4 = 0; index4 < num1; ++index4)
|
|
{
|
|
int index5 = numArray1[index4];
|
|
childs[2 * index4] = index5;
|
|
childs[2 * index4 + 1] = -1;
|
|
numArray2[index4] = (int) this.freqs[index5] << 8;
|
|
numArray1[index4] = index4;
|
|
}
|
|
do
|
|
{
|
|
int index6 = numArray1[0];
|
|
int index7 = numArray1[--num1];
|
|
int index8 = 0;
|
|
for (int index9 = 1; index9 < num1; index9 = index9 * 2 + 1)
|
|
{
|
|
if (index9 + 1 < num1 && numArray2[numArray1[index9]] > numArray2[numArray1[index9 + 1]])
|
|
++index9;
|
|
numArray1[index8] = numArray1[index9];
|
|
index8 = index9;
|
|
}
|
|
int num7 = numArray2[index7];
|
|
int index10;
|
|
while ((index10 = index8) > 0 && numArray2[numArray1[index8 = (index10 - 1) / 2]] > num7)
|
|
numArray1[index10] = numArray1[index8];
|
|
numArray1[index10] = index7;
|
|
int index11 = numArray1[0];
|
|
int index12 = num6++;
|
|
childs[2 * index12] = index6;
|
|
childs[2 * index12 + 1] = index11;
|
|
int num8 = Math.Min(numArray2[index6] & (int) byte.MaxValue, numArray2[index11] & (int) byte.MaxValue);
|
|
int num9;
|
|
numArray2[index12] = num9 = numArray2[index6] + numArray2[index11] - num8 + 1;
|
|
int index13 = 0;
|
|
for (int index14 = 1; index14 < num1; index14 = index13 * 2 + 1)
|
|
{
|
|
if (index14 + 1 < num1 && numArray2[numArray1[index14]] > numArray2[numArray1[index14 + 1]])
|
|
++index14;
|
|
numArray1[index13] = numArray1[index14];
|
|
index13 = index14;
|
|
}
|
|
int index15;
|
|
while ((index15 = index13) > 0 && numArray2[numArray1[index13 = (index15 - 1) / 2]] > num9)
|
|
numArray1[index15] = numArray1[index13];
|
|
numArray1[index15] = index12;
|
|
}
|
|
while (num1 > 1);
|
|
this.BuildLength(childs);
|
|
}
|
|
|
|
public int GetEncodedLength()
|
|
{
|
|
int encodedLength = 0;
|
|
for (int index = 0; index < this.freqs.Length; ++index)
|
|
encodedLength += (int) this.freqs[index] * (int) this.length[index];
|
|
return encodedLength;
|
|
}
|
|
|
|
public void CalcBLFreq(SimpleZip.DeflaterHuffman.Tree blTree)
|
|
{
|
|
int num1 = -1;
|
|
int index1 = 0;
|
|
while (index1 < this.numCodes)
|
|
{
|
|
int num2 = 1;
|
|
int num3 = (int) this.length[index1];
|
|
int num4;
|
|
int num5;
|
|
if (num3 == 0)
|
|
{
|
|
num4 = 138;
|
|
num5 = 3;
|
|
}
|
|
else
|
|
{
|
|
num4 = 6;
|
|
num5 = 3;
|
|
if (num1 != num3)
|
|
{
|
|
short[] freqs;
|
|
IntPtr index2;
|
|
(freqs = blTree.freqs)[(int) (index2 = (IntPtr) num3)] = (short) ((int) freqs[index2] + 1);
|
|
num2 = 0;
|
|
}
|
|
}
|
|
num1 = num3;
|
|
++index1;
|
|
while (index1 < this.numCodes && num1 == (int) this.length[index1])
|
|
{
|
|
++index1;
|
|
if (++num2 >= num4)
|
|
break;
|
|
}
|
|
if (num2 < num5)
|
|
{
|
|
short[] freqs;
|
|
IntPtr index3;
|
|
(freqs = blTree.freqs)[(int) (index3 = (IntPtr) num1)] = (short) ((int) freqs[index3] + (int) (short) num2);
|
|
}
|
|
else if (num1 != 0)
|
|
{
|
|
short[] freqs;
|
|
(freqs = blTree.freqs)[16] = (short) ((int) freqs[16] + 1);
|
|
}
|
|
else if (num2 <= 10)
|
|
{
|
|
short[] freqs;
|
|
(freqs = blTree.freqs)[17] = (short) ((int) freqs[17] + 1);
|
|
}
|
|
else
|
|
{
|
|
short[] freqs;
|
|
(freqs = blTree.freqs)[18] = (short) ((int) freqs[18] + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void WriteTree(SimpleZip.DeflaterHuffman.Tree blTree)
|
|
{
|
|
int code1 = -1;
|
|
int index = 0;
|
|
while (index < this.numCodes)
|
|
{
|
|
int num1 = 1;
|
|
int code2 = (int) this.length[index];
|
|
int num2;
|
|
int num3;
|
|
if (code2 == 0)
|
|
{
|
|
num2 = 138;
|
|
num3 = 3;
|
|
}
|
|
else
|
|
{
|
|
num2 = 6;
|
|
num3 = 3;
|
|
if (code1 != code2)
|
|
{
|
|
blTree.WriteSymbol(code2);
|
|
num1 = 0;
|
|
}
|
|
}
|
|
code1 = code2;
|
|
++index;
|
|
while (index < this.numCodes && code1 == (int) this.length[index])
|
|
{
|
|
++index;
|
|
if (++num1 >= num2)
|
|
break;
|
|
}
|
|
if (num1 < num3)
|
|
{
|
|
while (num1-- > 0)
|
|
blTree.WriteSymbol(code1);
|
|
}
|
|
else if (code1 != 0)
|
|
{
|
|
blTree.WriteSymbol(16);
|
|
this.dh.pending.WriteBits(num1 - 3, 2);
|
|
}
|
|
else if (num1 <= 10)
|
|
{
|
|
blTree.WriteSymbol(17);
|
|
this.dh.pending.WriteBits(num1 - 3, 3);
|
|
}
|
|
else
|
|
{
|
|
blTree.WriteSymbol(18);
|
|
this.dh.pending.WriteBits(num1 - 11, 7);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class DeflaterEngine
|
|
{
|
|
private const int MAX_MATCH = 258;
|
|
private const int MIN_MATCH = 3;
|
|
private const int WSIZE = 32768;
|
|
private const int WMASK = 32767;
|
|
private const int HASH_SIZE = 32768;
|
|
private const int HASH_MASK = 32767;
|
|
private const int HASH_SHIFT = 5;
|
|
private const int MIN_LOOKAHEAD = 262;
|
|
private const int MAX_DIST = 32506;
|
|
private const int TOO_FAR = 4096;
|
|
private int ins_h;
|
|
private short[] head;
|
|
private short[] prev;
|
|
private int matchStart;
|
|
private int matchLen;
|
|
private bool prevAvailable;
|
|
private int blockStart;
|
|
private int strstart;
|
|
private int lookahead;
|
|
private byte[] window;
|
|
private byte[] inputBuf;
|
|
private int totalIn;
|
|
private int inputOff;
|
|
private int inputEnd;
|
|
private SimpleZip.DeflaterPending pending;
|
|
private SimpleZip.DeflaterHuffman huffman;
|
|
|
|
public DeflaterEngine(SimpleZip.DeflaterPending pending)
|
|
{
|
|
this.pending = pending;
|
|
this.huffman = new SimpleZip.DeflaterHuffman(pending);
|
|
this.window = new byte[65536];
|
|
this.head = new short[32768];
|
|
this.prev = new short[32768];
|
|
this.blockStart = this.strstart = 1;
|
|
}
|
|
|
|
private void UpdateHash() => this.ins_h = (int) this.window[this.strstart] << 5 ^ (int) this.window[this.strstart + 1];
|
|
|
|
private int InsertString()
|
|
{
|
|
int index = (this.ins_h << 5 ^ (int) this.window[this.strstart + 2]) & (int) short.MaxValue;
|
|
short num;
|
|
this.prev[this.strstart & (int) short.MaxValue] = num = this.head[index];
|
|
this.head[index] = (short) this.strstart;
|
|
this.ins_h = index;
|
|
return (int) num & (int) ushort.MaxValue;
|
|
}
|
|
|
|
private void SlideWindow()
|
|
{
|
|
Array.Copy((Array) this.window, 32768, (Array) this.window, 0, 32768);
|
|
this.matchStart -= 32768;
|
|
this.strstart -= 32768;
|
|
this.blockStart -= 32768;
|
|
for (int index = 0; index < 32768; ++index)
|
|
{
|
|
int num = (int) this.head[index] & (int) ushort.MaxValue;
|
|
this.head[index] = num >= 32768 ? (short) (num - 32768) : (short) 0;
|
|
}
|
|
for (int index = 0; index < 32768; ++index)
|
|
{
|
|
int num = (int) this.prev[index] & (int) ushort.MaxValue;
|
|
this.prev[index] = num >= 32768 ? (short) (num - 32768) : (short) 0;
|
|
}
|
|
}
|
|
|
|
public void FillWindow()
|
|
{
|
|
if (this.strstart >= 65274)
|
|
this.SlideWindow();
|
|
int length;
|
|
for (; this.lookahead < 262 && this.inputOff < this.inputEnd; this.lookahead += length)
|
|
{
|
|
length = 65536 - this.lookahead - this.strstart;
|
|
if (length > this.inputEnd - this.inputOff)
|
|
length = this.inputEnd - this.inputOff;
|
|
Array.Copy((Array) this.inputBuf, this.inputOff, (Array) this.window, this.strstart + this.lookahead, length);
|
|
this.inputOff += length;
|
|
this.totalIn += length;
|
|
}
|
|
if (this.lookahead < 3)
|
|
return;
|
|
this.UpdateHash();
|
|
}
|
|
|
|
private bool FindLongestMatch(int curMatch)
|
|
{
|
|
int num1 = 128;
|
|
int num2 = 128;
|
|
short[] prev = this.prev;
|
|
int strstart = this.strstart;
|
|
int index = this.strstart + this.matchLen;
|
|
int val1 = Math.Max(this.matchLen, 2);
|
|
int num3 = Math.Max(this.strstart - 32506, 0);
|
|
int num4 = this.strstart + 258 - 1;
|
|
byte num5 = this.window[index - 1];
|
|
byte num6 = this.window[index];
|
|
if (val1 >= 8)
|
|
num1 >>= 2;
|
|
if (num2 > this.lookahead)
|
|
num2 = this.lookahead;
|
|
do
|
|
{
|
|
if ((int) this.window[curMatch + val1] == (int) num6 && (int) this.window[curMatch + val1 - 1] == (int) num5 && (int) this.window[curMatch] == (int) this.window[strstart] && (int) this.window[curMatch + 1] == (int) this.window[strstart + 1])
|
|
{
|
|
int num7 = curMatch + 2;
|
|
int num8 = strstart + 2;
|
|
int num9;
|
|
int num10;
|
|
int num11;
|
|
int num12;
|
|
int num13;
|
|
int num14;
|
|
int num15;
|
|
do
|
|
;
|
|
while ((int) this.window[++num8] == (int) this.window[num9 = num7 + 1] && (int) this.window[++num8] == (int) this.window[num10 = num9 + 1] && (int) this.window[++num8] == (int) this.window[num11 = num10 + 1] && (int) this.window[++num8] == (int) this.window[num12 = num11 + 1] && (int) this.window[++num8] == (int) this.window[num13 = num12 + 1] && (int) this.window[++num8] == (int) this.window[num14 = num13 + 1] && (int) this.window[++num8] == (int) this.window[num15 = num14 + 1] && (int) this.window[++num8] == (int) this.window[num7 = num15 + 1] && num8 < num4);
|
|
if (num8 > index)
|
|
{
|
|
this.matchStart = curMatch;
|
|
index = num8;
|
|
val1 = num8 - this.strstart;
|
|
if (val1 < num2)
|
|
{
|
|
num5 = this.window[index - 1];
|
|
num6 = this.window[index];
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
strstart = this.strstart;
|
|
}
|
|
}
|
|
while ((curMatch = (int) prev[curMatch & (int) short.MaxValue] & (int) ushort.MaxValue) > num3 && --num1 != 0);
|
|
this.matchLen = Math.Min(val1, this.lookahead);
|
|
return this.matchLen >= 3;
|
|
}
|
|
|
|
private bool DeflateSlow(bool flush, bool finish)
|
|
{
|
|
if (this.lookahead < 262 && !flush)
|
|
return false;
|
|
while (this.lookahead >= 262 || flush)
|
|
{
|
|
if (this.lookahead == 0)
|
|
{
|
|
if (this.prevAvailable)
|
|
this.huffman.TallyLit((int) this.window[this.strstart - 1] & (int) byte.MaxValue);
|
|
this.prevAvailable = false;
|
|
this.huffman.FlushBlock(this.window, this.blockStart, this.strstart - this.blockStart, finish);
|
|
this.blockStart = this.strstart;
|
|
return false;
|
|
}
|
|
if (this.strstart >= 65274)
|
|
this.SlideWindow();
|
|
int matchStart = this.matchStart;
|
|
int matchLen = this.matchLen;
|
|
if (this.lookahead >= 3)
|
|
{
|
|
int curMatch = this.InsertString();
|
|
if (curMatch != 0 && this.strstart - curMatch <= 32506 && this.FindLongestMatch(curMatch) && this.matchLen <= 5 && this.matchLen == 3 && this.strstart - this.matchStart > 4096)
|
|
this.matchLen = 2;
|
|
}
|
|
if (matchLen >= 3 && this.matchLen <= matchLen)
|
|
{
|
|
this.huffman.TallyDist(this.strstart - 1 - matchStart, matchLen);
|
|
int num = matchLen - 2;
|
|
do
|
|
{
|
|
++this.strstart;
|
|
--this.lookahead;
|
|
if (this.lookahead >= 3)
|
|
this.InsertString();
|
|
}
|
|
while (--num > 0);
|
|
++this.strstart;
|
|
--this.lookahead;
|
|
this.prevAvailable = false;
|
|
this.matchLen = 2;
|
|
}
|
|
else
|
|
{
|
|
if (this.prevAvailable)
|
|
this.huffman.TallyLit((int) this.window[this.strstart - 1] & (int) byte.MaxValue);
|
|
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;
|
|
}
|
|
|
|
public bool Deflate(bool flush, bool finish)
|
|
{
|
|
bool flag;
|
|
do
|
|
{
|
|
this.FillWindow();
|
|
flag = this.DeflateSlow(flush && this.inputOff == this.inputEnd, finish);
|
|
}
|
|
while (this.pending.IsFlushed && flag);
|
|
return flag;
|
|
}
|
|
|
|
public void SetInput(byte[] buffer)
|
|
{
|
|
this.inputBuf = buffer;
|
|
this.inputOff = 0;
|
|
this.inputEnd = buffer.Length;
|
|
}
|
|
|
|
public bool NeedsInput() => this.inputEnd == this.inputOff;
|
|
}
|
|
|
|
internal sealed class DeflaterPending
|
|
{
|
|
protected byte[] buf = new byte[65536];
|
|
private int start = 0;
|
|
private int end = 0;
|
|
private uint bits = 0;
|
|
private int bitCount = 0;
|
|
|
|
public void WriteShort(int s)
|
|
{
|
|
this.buf[this.end++] = (byte) s;
|
|
this.buf[this.end++] = (byte) (s >> 8);
|
|
}
|
|
|
|
public void WriteBlock(byte[] block, int offset, int len)
|
|
{
|
|
Array.Copy((Array) block, offset, (Array) this.buf, this.end, len);
|
|
this.end += len;
|
|
}
|
|
|
|
public int BitCount => this.bitCount;
|
|
|
|
public void AlignToByte()
|
|
{
|
|
if (this.bitCount > 0)
|
|
{
|
|
this.buf[this.end++] = (byte) this.bits;
|
|
if (this.bitCount > 8)
|
|
this.buf[this.end++] = (byte) (this.bits >> 8);
|
|
}
|
|
this.bits = 0U;
|
|
this.bitCount = 0;
|
|
}
|
|
|
|
public void WriteBits(int b, int count)
|
|
{
|
|
this.bits |= (uint) (b << this.bitCount);
|
|
this.bitCount += count;
|
|
if (this.bitCount < 16)
|
|
return;
|
|
this.buf[this.end++] = (byte) this.bits;
|
|
this.buf[this.end++] = (byte) (this.bits >> 8);
|
|
this.bits >>= 16;
|
|
this.bitCount -= 16;
|
|
}
|
|
|
|
public bool IsFlushed => this.end == 0;
|
|
|
|
public int Flush(byte[] output, int offset, int length)
|
|
{
|
|
if (this.bitCount >= 8)
|
|
{
|
|
this.buf[this.end++] = (byte) this.bits;
|
|
this.bits >>= 8;
|
|
this.bitCount -= 8;
|
|
}
|
|
if (length > this.end - this.start)
|
|
{
|
|
length = this.end - this.start;
|
|
Array.Copy((Array) this.buf, this.start, (Array) output, offset, length);
|
|
this.start = 0;
|
|
this.end = 0;
|
|
}
|
|
else
|
|
{
|
|
Array.Copy((Array) this.buf, this.start, (Array) output, offset, length);
|
|
this.start += length;
|
|
}
|
|
return length;
|
|
}
|
|
}
|
|
|
|
internal sealed class ZipStream : MemoryStream
|
|
{
|
|
public void WriteShort(int value)
|
|
{
|
|
this.WriteByte((byte) (value & (int) byte.MaxValue));
|
|
this.WriteByte((byte) (value >> 8 & (int) byte.MaxValue));
|
|
}
|
|
|
|
public void WriteInt(int value)
|
|
{
|
|
this.WriteShort(value);
|
|
this.WriteShort(value >> 16);
|
|
}
|
|
|
|
public int ReadShort() => this.ReadByte() | this.ReadByte() << 8;
|
|
|
|
public int ReadInt() => this.ReadShort() | this.ReadShort() << 16;
|
|
|
|
public ZipStream()
|
|
{
|
|
}
|
|
|
|
public ZipStream(byte[] buffer)
|
|
: base(buffer, false)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|