CBZip2InputStream
using Org.BouncyCastle.Utilities.IO;
using System;
using System.IO;
namespace Org.BouncyCastle.Utilities.Bzip2
{
public class CBZip2InputStream : BaseInputStream
{
private int last;
private int origPtr;
private int blockSize100k;
private int bsBuff;
private int bsLive;
private readonly CRC m_blockCrc = new CRC();
private int nInUse;
private byte[] seqToUnseq = new byte[256];
private byte[] m_selectors = new byte[18002];
private int[] tt;
private byte[] ll8;
private int[] unzftab = new int[256];
private int[][] limit = CreateIntArray(6, 21);
private int[][] basev = CreateIntArray(6, 21);
private int[][] perm = CreateIntArray(6, 258);
private int[] minLens = new int[6];
private Stream bsStream;
private bool streamEnd;
private int currentByte = -1;
private const int RAND_PART_B_STATE = 1;
private const int RAND_PART_C_STATE = 2;
private const int NO_RAND_PART_B_STATE = 3;
private const int NO_RAND_PART_C_STATE = 4;
private int currentState;
private int m_expectedBlockCrc;
private int m_expectedStreamCrc;
private int m_streamCrc;
private int i2;
private int count;
private int chPrev;
private int ch2;
private int i;
private int tPos;
private int rNToGo;
private int rTPos;
private int j2;
private int z;
public CBZip2InputStream(Stream zStream)
{
ll8 = null;
tt = null;
bsStream = zStream;
bsLive = 0;
bsBuff = 0;
int num = bsStream.ReadByte();
int num2 = bsStream.ReadByte();
int num3 = bsStream.ReadByte();
int num4 = bsStream.ReadByte();
if (num4 < 0)
throw new EndOfStreamException();
if ((num != 66) | (num2 != 90) | (num3 != 104) | (num4 < 49) | (num4 > 57))
throw new IOException("Invalid stream header");
blockSize100k = num4 - 48;
int num5 = 100000 * blockSize100k;
ll8 = new byte[num5];
tt = new int[num5];
m_streamCrc = 0;
BeginBlock();
}
public override int Read(byte[] buffer, int offset, int count)
{
Streams.ValidateBufferArguments(buffer, offset, count);
int num = 0;
while (num < count) {
int num2 = ReadByte();
if (num2 < 0)
break;
buffer[offset + num++] = (byte)num2;
}
return num;
}
public override int ReadByte()
{
if (streamEnd)
return -1;
int result = currentByte;
switch (currentState) {
case 1:
SetupRandPartB();
break;
case 2:
SetupRandPartC();
break;
case 3:
SetupNoRandPartB();
break;
case 4:
SetupNoRandPartC();
break;
default:
throw new InvalidOperationException();
}
return result;
}
private void BeginBlock()
{
switch (BsGetLong48()) {
default:
throw new IOException("Block header error");
case 25779555029136:
m_expectedStreamCrc = BsGetInt32();
if (m_expectedStreamCrc != m_streamCrc)
throw new IOException("Stream CRC error");
streamEnd = true;
break;
case 54156738319193: {
m_expectedBlockCrc = BsGetInt32();
bool flag = BsGetBit() == 1;
GetAndMoveToFrontDecode();
m_blockCrc.Initialise();
int[] array = new int[257];
int num = 0;
array[0] = 0;
for (i = 0; i < 256; i++) {
num += unzftab[i];
array[i + 1] = num;
}
if (num != last + 1)
throw new InvalidOperationException();
for (i = 0; i <= last; i++) {
byte b = ll8[i];
tt[array[b]++] = i;
}
tPos = tt[origPtr];
count = 0;
i2 = 0;
ch2 = 256;
if (flag) {
rNToGo = 0;
rTPos = 0;
SetupRandPartA();
} else
SetupNoRandPartA();
break;
}
}
}
private void EndBlock()
{
int final = m_blockCrc.GetFinal();
if (m_expectedBlockCrc != final)
throw new IOException("Block CRC error");
m_streamCrc = (Integers.RotateLeft(m_streamCrc, 1) ^ final);
}
protected void Detach(bool disposing)
{
if (disposing)
ImplDisposing(false);
base.Dispose(disposing);
}
protected override void Dispose(bool disposing)
{
if (disposing)
ImplDisposing(true);
base.Dispose(disposing);
}
private void ImplDisposing(bool disposeInput)
{
if (bsStream != null) {
if (disposeInput)
bsStream.Dispose();
bsStream = null;
}
}
private int BsGetBit()
{
if (bsLive == 0) {
bsBuff = RequireByte();
bsLive = 7;
return (int)((uint)bsBuff >> 7);
}
bsLive--;
return (bsBuff >> bsLive) & 1;
}
private int BsGetBits(int n)
{
while (bsLive < n) {
bsBuff = ((bsBuff << 8) | RequireByte());
bsLive += 8;
}
bsLive -= n;
return (bsBuff >> bsLive) & ((1 << n) - 1);
}
private int BsGetBitsSmall(int n)
{
if (bsLive < n) {
bsBuff = ((bsBuff << 8) | RequireByte());
bsLive += 8;
}
bsLive -= n;
return (bsBuff >> bsLive) & ((1 << n) - 1);
}
private int BsGetInt32()
{
return (BsGetBits(16) << 16) | BsGetBits(16);
}
private long BsGetLong48()
{
return ((long)BsGetBits(24) << 24) | BsGetBits(24);
}
private void HbCreateDecodeTables(int[] limit, int[] basev, int[] perm, byte[] length, int minLen, int maxLen, int alphaSize)
{
Array.Clear(basev, 0, basev.Length);
Array.Clear(limit, 0, limit.Length);
int num = 0;
int num2 = 0;
for (int i = minLen; i <= maxLen; i++) {
for (int j = 0; j < alphaSize; j++) {
if (length[j] == i)
perm[num++] = j;
}
basev[i] = num2;
limit[i] = num2 + num;
num2 += num2 + num;
}
}
private int RecvDecodingTables()
{
nInUse = 0;
int num = BsGetBits(16);
for (int i = 0; i < 16; i++) {
if ((num & (32768 >> i)) != 0) {
int num2 = BsGetBits(16);
int num3 = i * 16;
for (int j = 0; j < 16; j++) {
if ((num2 & (32768 >> j)) != 0)
seqToUnseq[nInUse++] = (byte)(num3 + j);
}
}
}
if (nInUse < 1)
throw new InvalidOperationException();
int num4 = nInUse + 2;
int num5 = BsGetBitsSmall(3);
if (num5 < 2 || num5 > 6)
throw new InvalidOperationException();
int num6 = BsGetBits(15);
if (num6 < 1)
throw new InvalidOperationException();
uint num7 = 5517840;
for (int i = 0; i < num6; i++) {
int num8 = 0;
while (BsGetBit() == 1) {
if (++num8 >= num5)
throw new InvalidOperationException();
}
if (i < 18002) {
switch (num8) {
case 1:
num7 = (((num7 >> 4) & 15) | ((num7 << 4) & 240) | (num7 & 16776960));
break;
case 2:
num7 = (((num7 >> 8) & 15) | ((num7 << 4) & 4080) | (num7 & 16773120));
break;
case 3:
num7 = (((num7 >> 12) & 15) | ((num7 << 4) & 65520) | (num7 & 16711680));
break;
case 4:
num7 = (((num7 >> 16) & 15) | ((num7 << 4) & 1048560) | (num7 & 15728640));
break;
case 5:
num7 = (((num7 >> 20) & 15) | ((num7 << 4) & 16777200));
break;
default:
throw new InvalidOperationException();
case 0:
break;
}
m_selectors[i] = (byte)(num7 & 15);
}
}
byte[] array = new byte[num4];
for (int k = 0; k < num5; k++) {
int num9 = 0;
int num10 = 32;
int num11 = BsGetBitsSmall(5);
if ((num11 < 1) | (num11 > 20))
throw new InvalidOperationException();
for (int i = 0; i < num4; i++) {
int num13;
for (int num12 = BsGetBit(); num12 != 0; num12 = (num13 & 1)) {
num13 = BsGetBitsSmall(2);
num11 += 1 - (num13 & 2);
if ((num11 < 1) | (num11 > 20))
throw new InvalidOperationException();
}
array[i] = (byte)num11;
num9 = System.Math.Max(num9, num11);
num10 = System.Math.Min(num10, num11);
}
HbCreateDecodeTables(limit[k], basev[k], perm[k], array, num10, num9, num4);
minLens[k] = num10;
}
return num6;
}
private void GetAndMoveToFrontDecode()
{
int num = 100000 * blockSize100k;
origPtr = BsGetBits(24);
if (origPtr > 10 + num)
throw new InvalidOperationException();
int num2 = RecvDecodingTables();
int num3 = nInUse + 2;
int num4 = nInUse + 1;
Array.Clear(unzftab, 0, unzftab.Length);
byte[] array = new byte[nInUse];
for (int i = 0; i < nInUse; i++) {
array[i] = seqToUnseq[i];
}
last = -1;
int num5 = 0;
int num6 = 49;
int num7 = m_selectors[num5];
int num8 = minLens[num7];
int[] array2 = limit[num7];
int[] array3 = perm[num7];
int[] array4 = basev[num7];
int num9 = num8;
int num10;
for (num10 = BsGetBits(num8); num10 >= array2[num9]; num10 = ((num10 << 1) | BsGetBit())) {
if (++num9 > 20)
throw new InvalidOperationException();
}
int num11 = num10 - array4[num9];
if (num11 >= num3)
throw new InvalidOperationException();
int num12 = array3[num11];
while (num12 != num4) {
if (num12 <= 1) {
int num13 = 1;
int num14 = 0;
do {
if (num13 > 1048576)
throw new InvalidOperationException();
num14 += num13 << num12;
num13 <<= 1;
if (num6 == 0) {
if (++num5 >= num2)
throw new InvalidOperationException();
num6 = 50;
num7 = m_selectors[num5];
num8 = minLens[num7];
array2 = limit[num7];
array3 = perm[num7];
array4 = basev[num7];
}
num6--;
int num15 = num8;
int num16;
for (num16 = BsGetBits(num8); num16 >= array2[num15]; num16 = ((num16 << 1) | BsGetBit())) {
if (++num15 > 20)
throw new InvalidOperationException();
}
int num17 = num16 - array4[num15];
if (num17 >= num3)
throw new InvalidOperationException();
num12 = array3[num17];
} while (num12 <= 1);
byte b = array[0];
unzftab[b] += num14;
if (last >= num - num14)
throw new InvalidOperationException("Block overrun");
while (--num14 >= 0) {
ll8[++last] = b;
}
} else {
if (++last >= num)
throw new InvalidOperationException("Block overrun");
byte b2 = array[num12 - 1];
unzftab[b2]++;
ll8[last] = b2;
if (num12 <= 16) {
for (int num18 = num12 - 1; num18 > 0; num18--) {
array[num18] = array[num18 - 1];
}
} else
Array.Copy(array, 0, array, 1, num12 - 1);
array[0] = b2;
if (num6 == 0) {
if (++num5 >= num2)
throw new InvalidOperationException();
num6 = 50;
num7 = m_selectors[num5];
num8 = minLens[num7];
array2 = limit[num7];
array3 = perm[num7];
array4 = basev[num7];
}
num6--;
int num19 = num8;
int num20;
for (num20 = BsGetBits(num8); num20 >= array2[num19]; num20 = ((num20 << 1) | BsGetBit())) {
if (++num19 > 20)
throw new InvalidOperationException();
}
int num21 = num20 - array4[num19];
if (num21 >= num3)
throw new InvalidOperationException();
num12 = array3[num21];
}
}
if (origPtr > last)
throw new InvalidOperationException();
int num22 = last + 1;
int num23 = 0;
for (int i = 0; i <= 255; i++) {
int num24 = unzftab[i];
num23 |= num24;
num23 |= num22 - num24;
}
if (num23 < 0)
throw new InvalidOperationException();
}
private int RequireByte()
{
int num = bsStream.ReadByte();
if (num < 0)
throw new EndOfStreamException();
return num & 255;
}
private void SetupRandPartA()
{
if (i2 <= last) {
chPrev = ch2;
ch2 = ll8[tPos];
tPos = tt[tPos];
if (rNToGo == 0) {
rNToGo = CBZip2OutputStream.RNums[rTPos++];
rTPos &= 511;
}
rNToGo--;
ch2 ^= ((rNToGo == 1) ? 1 : 0);
i2++;
currentByte = ch2;
currentState = 1;
m_blockCrc.Update((byte)ch2);
} else {
EndBlock();
BeginBlock();
}
}
private void SetupNoRandPartA()
{
if (i2 <= last) {
chPrev = ch2;
ch2 = ll8[tPos];
tPos = tt[tPos];
i2++;
currentByte = ch2;
currentState = 3;
m_blockCrc.Update((byte)ch2);
} else {
EndBlock();
BeginBlock();
}
}
private void SetupRandPartB()
{
if (ch2 != chPrev) {
count = 1;
SetupRandPartA();
} else if (++count < 4) {
SetupRandPartA();
} else {
z = ll8[tPos];
tPos = tt[tPos];
if (rNToGo == 0) {
rNToGo = CBZip2OutputStream.RNums[rTPos++];
rTPos &= 511;
}
rNToGo--;
z ^= ((rNToGo == 1) ? 1 : 0);
j2 = 0;
currentState = 2;
SetupRandPartC();
}
}
private void SetupNoRandPartB()
{
if (ch2 != chPrev) {
count = 1;
SetupNoRandPartA();
} else if (++count < 4) {
SetupNoRandPartA();
} else {
z = ll8[tPos];
tPos = tt[tPos];
currentState = 4;
j2 = 0;
SetupNoRandPartC();
}
}
private void SetupRandPartC()
{
if (j2 < z) {
currentByte = ch2;
m_blockCrc.Update((byte)ch2);
j2++;
} else {
i2++;
count = 0;
SetupRandPartA();
}
}
private void SetupNoRandPartC()
{
if (j2 < z) {
currentByte = ch2;
m_blockCrc.Update((byte)ch2);
j2++;
} else {
i2++;
count = 0;
SetupNoRandPartA();
}
}
internal static int[][] CreateIntArray(int n1, int n2)
{
int[][] array = new int[n1][];
for (int i = 0; i < n1; i++) {
array[i] = new int[n2];
}
return array;
}
}
}