Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 63 additions & 127 deletions src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,164 +6,100 @@ namespace ICSharpCode.SharpZipLib.Zip.Compression
class InflaterDynHeader
{
#region Constants
const int LNUM = 0;
const int DNUM = 1;
const int BLNUM = 2;
const int BLLENS = 3;
const int LENS = 4;
const int REPS = 5;

static readonly int[] repMin = { 3, 3, 11 };
static readonly int[] repBits = { 2, 3, 7 };

static readonly int[] BL_ORDER =
{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
#endregion

public bool Decode(StreamManipulator input)
{
decode_loop:
for (;;) {
switch (mode) {
case LNUM:
lnum = input.PeekBits(5);
if (lnum < 0) {
return false;
}
lnum += 257;
input.DropBits(5);
// System.err.println("LNUM: "+lnum);
mode = DNUM;
goto case DNUM; // fall through
case DNUM:
dnum = input.PeekBits(5);
if (dnum < 0) {
return false;
}
dnum++;
input.DropBits(5);
// System.err.println("DNUM: "+dnum);
num = lnum + dnum;
litdistLens = new byte[num];
mode = BLNUM;
goto case BLNUM; // fall through
case BLNUM:
blnum = input.PeekBits(4);
if (blnum < 0) {
return false;
}
blnum += 4;
input.DropBits(4);
blLens = new byte[19];
ptr = 0;
// System.err.println("BLNUM: "+blnum);
mode = BLLENS;
goto case BLLENS; // fall through
case BLLENS:
while (ptr < blnum) {
int len = input.PeekBits(3);
if (len < 0) {
return false;
}
input.DropBits(3);
// System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
blLens[BL_ORDER[ptr]] = (byte)len;
ptr++;
try
{
lnum = input.GrabBits(5) + 257;
dnum = input.GrabBits(5) + 1;
blnum = input.GrabBits(4) + 4;
num = lnum + dnum;

lengths = new byte[19];

for (int i = 0; i < blnum; i++)
{
lengths[BL_ORDER[i]] = (byte)input.GrabBits(3, true);
}
blTree = new InflaterHuffmanTree(lengths);
lengths = new byte[num];

int index = 0;
while (index < lnum + dnum)
{
byte len;

int symbol = blTree.GetSymbol(input);
if (symbol < 0)
return false;
if (symbol < 16)
lengths[index++] = (byte)symbol;
else
{
len = 0;
if (symbol == 16)
{
if (index == 0)
return false; // No last length!
len = lengths[index - 1];
symbol = input.GrabBits(2, true) + 3;
}
blTree = new InflaterHuffmanTree(blLens);
blLens = null;
ptr = 0;
mode = LENS;
goto case LENS; // fall through
case LENS: {
int symbol;
while (((symbol = blTree.GetSymbol(input)) & ~15) == 0) {
/* Normal case: symbol in [0..15] */

// System.err.println("litdistLens["+ptr+"]: "+symbol);
litdistLens[ptr++] = lastLen = (byte)symbol;

if (ptr == num) {
/* Finished */
return true;
}
}

/* need more input ? */
if (symbol < 0) {
return false;
}

/* otherwise repeat code */
if (symbol >= 17) {
/* repeat zero */
// System.err.println("repeating zero");
lastLen = 0;
} else {
if (ptr == 0) {
throw new SharpZipBaseException();
}
}
repSymbol = symbol - 16;
else if (symbol == 17)
{
// repeat zero 3..10 times
symbol = input.GrabBits(3, true) + 3;
}
mode = REPS;
goto case REPS; // fall through
case REPS: {
int bits = repBits[repSymbol];
int count = input.PeekBits(bits);
if (count < 0) {
return false;
}
input.DropBits(bits);
count += repMin[repSymbol];
// System.err.println("litdistLens repeated: "+count);

if (ptr + count > num) {
throw new SharpZipBaseException();
}
while (count-- > 0) {
litdistLens[ptr++] = lastLen;
}

if (ptr == num) {
/* Finished */
return true;
}
else
{
// (symbol == 18), repeat zero 11..138 times
symbol = input.GrabBits(7, true) + 11;
}
mode = LENS;
goto decode_loop;

if (index + symbol > lnum + dnum)
return false; // too many lengths!

// repeat last or zero symbol times
while (symbol-- > 0)
lengths[index++] = len;
}
}

if (lengths[256] == 0)
return false; // No end-of-block code!

return true;
}
catch (Exception x)
{
return false;
}
}

public InflaterHuffmanTree BuildLitLenTree()
{
byte[] litlenLens = new byte[lnum];
Array.Copy(litdistLens, 0, litlenLens, 0, lnum);
Array.Copy(lengths, 0, litlenLens, 0, lnum);
return new InflaterHuffmanTree(litlenLens);
}

public InflaterHuffmanTree BuildDistTree()
{
byte[] distLens = new byte[dnum];
Array.Copy(litdistLens, lnum, distLens, 0, dnum);
Array.Copy(lengths, lnum, distLens, 0, dnum);
return new InflaterHuffmanTree(distLens);
}

#region Instance Fields
byte[] blLens;
byte[] litdistLens;
byte[] lengths;

InflaterHuffmanTree blTree;

/// <summary>
/// The current decode mode
/// </summary>
int mode;
int lnum, dnum, blnum, num;
int repSymbol;
byte lastLen;
int ptr;
#endregion

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ public override int Read(byte[] buffer, int offset, int count)
if (inf.IsNeedingInput) {
Fill();
} else if (bytesRead == 0) {
throw new ZipException("Dont know what to do");
throw new ZipException("Invalid input data");
}
}
return count - remainingBytes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ public int PeekBits(int bitCount)
return (int)(buffer_ & ((1 << bitCount) - 1));
}

/// <summary>
/// Grabs the next n bits from the input and throws if <paramref name="allowZero"/> is false and the result is 0.
/// </summary>
public int GrabBits(int bitCount, bool allowZero = false)
{
var val = PeekBits(bitCount);
if (!allowZero && val == 0)
throw new SharpZipBaseException(bitCount + "-bit value cannot be zero");
DropBits(bitCount);
return val;
}

/// <summary>
/// Drops the next n bits from the input. You should have called PeekBits
/// with a bigger or equal n before, to make sure that enough bits are in
Expand Down