diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs index 31a366da6..b7c5c3f33 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/InflaterDynHeader.cs @@ -6,15 +6,6 @@ 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 }; @@ -22,148 +13,93 @@ class InflaterDynHeader 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; - /// - /// The current decode mode - /// - int mode; int lnum, dnum, blnum, num; - int repSymbol; - byte lastLen; - int ptr; #endregion } diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs index 4485a4ee7..cd73fbb15 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/InflaterInputStream.cs @@ -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; diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs index e73a50c54..80a26c428 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/StreamManipulator.cs @@ -41,6 +41,18 @@ public int PeekBits(int bitCount) return (int)(buffer_ & ((1 << bitCount) - 1)); } + /// + /// Grabs the next n bits from the input and throws if is false and the result is 0. + /// + 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; + } + /// /// 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