/// <summary>
		/// Reads the next symbol from input.  The symbol is encoded using the
		/// huffman tree.
		/// </summary>
		/// <param name="input">
		/// input the input source.
		/// </param>
		/// <returns>
		/// the next symbol, or -1 if not enough input is available.
		/// </returns>
		public int GetSymbol(StreamManipulator input)
		{
			int lookahead, symbol;
			if ((lookahead = input.PeekBits(9)) >= 0)
			{
				if ((symbol = tree[lookahead]) >= 0)
				{
					input.DropBits(symbol & 15);
					return symbol >> 4;
				}
				int subtree = -(symbol >> 4);
				int bitlen = symbol & 15;
				if ((lookahead = input.PeekBits(bitlen)) >= 0)
				{
					symbol = tree[subtree | (lookahead >> 9)];
					input.DropBits(symbol & 15);
					return symbol >> 4;
				}
				else
				{
					int bits = input.AvailableBits;
					lookahead = input.PeekBits(bits);
					symbol = tree[subtree | (lookahead >> 9)];
					if ((symbol & 15) <= bits)
					{
						input.DropBits(symbol & 15);
						return symbol >> 4;
					}
					else
					{
						return -1;
					}
				}
			}
			else
			{
				int bits = input.AvailableBits;
				lookahead = input.PeekBits(bits);
				symbol = tree[lookahead];
				if (symbol >= 0 && (symbol & 15) <= bits)
				{
					input.DropBits(symbol & 15);
					return symbol >> 4;
				}
				else
				{
					return -1;
				}
			}
		}
		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++;
						}
						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 ZipBaseException();
								}
							}
							repSymbol = symbol - 16;
						}
						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 ZipBaseException();
							}
							while (count-- > 0)
							{
								litdistLens[ptr++] = lastLen;
							}

							if (ptr == num)
							{
								/* Finished */
								return true;
							}
						}
						mode = LENS;
						goto decode_loop;
				}
			}
		}