/// <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;
   int bits;
   if ((lookahead = input.PeekBits(9)) >= 0)
   {
     if ((symbol = tree[lookahead]) >= 0)
     {
       input.DropBits(symbol & 15);
       return symbol >> 4;
     }
     var subtree = -(symbol >> 4);
     var bitlen = symbol & 15;
     if ((lookahead = input.PeekBits(bitlen)) >= 0)
     {
       symbol = tree[subtree | (lookahead >> 9)];
       input.DropBits(symbol & 15);
       return symbol >> 4;
     }
     bits = input.AvailableBits;
     lookahead = input.PeekBits(bits);
     symbol = tree[subtree | (lookahead >> 9)];
     if ((symbol & 15) <= bits)
     {
       input.DropBits(symbol & 15);
       return symbol >> 4;
     }
     return -1;
   }
   bits = input.AvailableBits;
   lookahead = input.PeekBits(bits);
   symbol = tree[lookahead];
   if (symbol >= 0 && (symbol & 15) <= bits)
   {
     input.DropBits(symbol & 15);
     return symbol >> 4;
   }
   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)
            {
              var 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 SharpZipBaseException();
              }
            }
            repSymbol = symbol - 16;
          }
            mode = REPS;
            goto case REPS; // fall through
          case REPS:
          {
            var bits = repBits[repSymbol];
            var 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;
            }
          }
            mode = LENS;
            goto decode_loop;
        }
      }
    }