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;
 
-		/// <summary>
-		/// The current decode mode
-		/// </summary>
-		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));
 		}
 
+		/// <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
