static InflaterHuffmanTree() { try { byte[] codeLengths = new byte[ 288 ]; int i = 0; while( i < 144 ) { codeLengths[ i++ ] = 8; } while( i < 256 ) { codeLengths[ i++ ] = 9; } while( i < 280 ) { codeLengths[ i++ ] = 7; } while( i < 288 ) { codeLengths[ i++ ] = 8; } defLitLenTree = new InflaterHuffmanTree( codeLengths ); codeLengths = new byte[ 32 ]; i = 0; while( i < 32 ) { codeLengths[ i++ ] = 5; } defDistTree = new InflaterHuffmanTree( codeLengths ); } catch( Exception ) { throw new BlubbZipBaseException( "InflaterHuffmanTree: static tree length illegal" ); } }
/// <summary> /// Decodes the deflated stream. /// </summary> /// <returns> /// false if more input is needed, or if finished. /// </returns> /// <exception cref="BlubbZipBaseException"> /// if deflated stream is invalid. /// </exception> private bool Decode() { switch( mode ) { case DECODE_HEADER: return DecodeHeader(); case DECODE_DICT: return DecodeDict(); case DECODE_CHKSUM: return DecodeChksum(); case DECODE_BLOCKS: if( isLastBlock ) { if( noHeader ) { mode = FINISHED; return false; } else { input.SkipToByteBoundary(); neededBits = 32; mode = DECODE_CHKSUM; return true; } } int type = input.PeekBits( 3 ); if( type < 0 ) { return false; } input.DropBits( 3 ); if( ( type & 1 ) != 0 ) { isLastBlock = true; } switch( type >> 1 ) { case DeflaterConstants.STORED_BLOCK: input.SkipToByteBoundary(); mode = DECODE_STORED_LEN1; break; case DeflaterConstants.STATIC_TREES: litlenTree = InflaterHuffmanTree.defLitLenTree; distTree = InflaterHuffmanTree.defDistTree; mode = DECODE_HUFFMAN; break; case DeflaterConstants.DYN_TREES: dynHeader = new InflaterDynHeader(); mode = DECODE_DYN_HEADER; break; default: throw new BlubbZipBaseException( "Unknown block type " + type ); } return true; case DECODE_STORED_LEN1: { if( ( uncomprLen = input.PeekBits( 16 ) ) < 0 ) { return false; } input.DropBits( 16 ); mode = DECODE_STORED_LEN2; } goto case DECODE_STORED_LEN2; // fall through case DECODE_STORED_LEN2: { int nlen = input.PeekBits( 16 ); if( nlen < 0 ) { return false; } input.DropBits( 16 ); if( nlen != ( uncomprLen ^ 0xffff ) ) { throw new BlubbZipBaseException( "broken uncompressed block" ); } mode = DECODE_STORED; } goto case DECODE_STORED; // fall through case DECODE_STORED: { int more = outputWindow.CopyStored( input, uncomprLen ); uncomprLen -= more; if( uncomprLen == 0 ) { mode = DECODE_BLOCKS; return true; } return !input.IsNeedingInput; } case DECODE_DYN_HEADER: if( !dynHeader.Decode( input ) ) { return false; } litlenTree = dynHeader.BuildLitLenTree(); distTree = dynHeader.BuildDistTree(); mode = DECODE_HUFFMAN; goto case DECODE_HUFFMAN; // fall through case DECODE_HUFFMAN: case DECODE_HUFFMAN_LENBITS: case DECODE_HUFFMAN_DIST: case DECODE_HUFFMAN_DISTBITS: return DecodeHuffman(); case FINISHED: return false; default: throw new BlubbZipBaseException( "Inflater.Decode unknown mode" ); } }
/// <summary> /// Decodes the huffman encoded symbols in the input stream. /// </summary> /// <returns> /// false if more input is needed, true if output window is /// full or the current block ends. /// </returns> /// <exception cref="BlubbZipBaseException"> /// if deflated stream is invalid. /// </exception> private bool DecodeHuffman() { int free = outputWindow.GetFreeSpace(); while( free >= 258 ) { int symbol; switch( mode ) { case DECODE_HUFFMAN: // This is the inner loop so it is optimized a bit while( ( ( symbol = litlenTree.GetSymbol( input ) ) & ~0xff ) == 0 ) { outputWindow.Write( symbol ); if( --free < 258 ) { return true; } } if( symbol < 257 ) { if( symbol < 0 ) { return false; } else { // symbol == 256: end of block distTree = null; litlenTree = null; mode = DECODE_BLOCKS; return true; } } try { repLength = CPLENS[ symbol - 257 ]; neededBits = CPLEXT[ symbol - 257 ]; } catch( Exception ) { throw new BlubbZipBaseException( "Illegal rep length code" ); } goto case DECODE_HUFFMAN_LENBITS; // fall through case DECODE_HUFFMAN_LENBITS: if( neededBits > 0 ) { mode = DECODE_HUFFMAN_LENBITS; int i = input.PeekBits( neededBits ); if( i < 0 ) { return false; } input.DropBits( neededBits ); repLength += i; } mode = DECODE_HUFFMAN_DIST; goto case DECODE_HUFFMAN_DIST; // fall through case DECODE_HUFFMAN_DIST: symbol = distTree.GetSymbol( input ); if( symbol < 0 ) { return false; } try { repDist = CPDIST[ symbol ]; neededBits = CPDEXT[ symbol ]; } catch( Exception ) { throw new BlubbZipBaseException( "Illegal rep dist code" ); } goto case DECODE_HUFFMAN_DISTBITS; // fall through case DECODE_HUFFMAN_DISTBITS: if( neededBits > 0 ) { mode = DECODE_HUFFMAN_DISTBITS; int i = input.PeekBits( neededBits ); if( i < 0 ) { return false; } input.DropBits( neededBits ); repDist += i; } outputWindow.Repeat( repLength, repDist ); free -= repLength; mode = DECODE_HUFFMAN; break; default: throw new BlubbZipBaseException( "Inflater unknown mode" ); } } return true; }
/// <summary> /// Resets the inflater so that a new stream can be decompressed. All /// pending input and output will be discarded. /// </summary> public void Reset() { mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER; totalIn = 0; totalOut = 0; input.Reset(); outputWindow.Reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.Reset(); }
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 BlubbZipBaseException(); } } 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 BlubbZipBaseException(); } while( count-- > 0 ) { litdistLens[ ptr++ ] = lastLen; } if( ptr == num ) { /* Finished */ return true; } } mode = LENS; goto decode_loop; } } }