Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.ning.compress.gzip;
  
  
com.ning.compress.Uncompressor implementation for uncompressing GZIP encoded data in "push" mode, in which input is not read using java.io.InputStream but rather pushed to uncompressor in variable length chunks.
 
 public class GZIPUncompressor extends Uncompressor
 {
     /*
     ///////////////////////////////////////////////////////////////////////
     // GZIP constants
     ///////////////////////////////////////////////////////////////////////
      */
 
     // little-endian marker bytes:
     protected final static int GZIP_MAGIC = 0x8b1f;
 
     protected final static byte GZIP_MAGIC_0 = (byte) ( & 0xFF);
     protected final static byte GZIP_MAGIC_1 = (byte) ( >> 8);
     
     // // // File header flags.
 
     //protected final static int FTEXT    = 1;    // Extra text
     protected final static int FHCRC      = 2;    // Header CRC
     protected final static int FEXTRA     = 4;    // Extra field
     protected final static int FNAME      = 8;    // File name
     protected final static int FCOMMENT   = 16;   // File comment
 
    
Size of input chunks fed to underlying decoder. Since it is not 100% clear what its effects are on
 
     protected final static int DEFAULT_CHUNK_SIZE = 4096;

    
For decoding we should use buffer that is big enough to contain typical amount of decoded data; 64k seems like a nice big number
 
     protected final static int DECODE_BUFFER_SIZE = 0xFFFF;
         
     /*
     ///////////////////////////////////////////////////////////////////////
     // State constants
     ///////////////////////////////////////////////////////////////////////
      */

    
State in which a new compression stream can start.
 
     protected final static int STATE_INITIAL = 0;
 
     // State in which first byte of signature has been matched, second exepcted
     protected final static int STATE_HEADER_SIG1 = 1;
 
     // State in which 'compression type' byte is expected
     protected final static int STATE_HEADER_COMP_TYPE = 2;
     // State in which flag byte is expected
     protected final static int STATE_HEADER_FLAGS = 3;
     // State in which we are to skip 6 bytes 
     protected final static int STATE_HEADER_SKIP = 4;
     protected final static int STATE_HEADER_EXTRA0 = 5;
     protected final static int STATE_HEADER_EXTRA1 = 6;
     protected final static int STATE_HEADER_FNAME = 7;
     protected final static int STATE_HEADER_COMMENT = 8;
     protected final static int STATE_HEADER_CRC0 = 9;
     protected final static int STATE_HEADER_CRC1 = 10;
 
     protected final static int STATE_TRAILER_INITIAL = 11;
     protected final static int STATE_TRAILER_CRC1 = 12;
     protected final static int STATE_TRAILER_CRC2 = 13;
     protected final static int STATE_TRAILER_CRC3 = 14;
     protected final static int STATE_TRAILER_LEN0 = 15;
     protected final static int STATE_TRAILER_LEN1 = 16;
     protected final static int STATE_TRAILER_LEN2 = 17;
     protected final static int STATE_TRAILER_LEN3 = 18;

    
State in which we are buffering compressed data for decompression
 
     protected final static int STATE_BODY = 20;
     
     /*
     ///////////////////////////////////////////////////////////////////////
     // Configuration, helper objects
     ///////////////////////////////////////////////////////////////////////
      */

    
Handler that will receive uncompressed data.
    protected final DataHandler _handler;

    
Object that handles details of buffer recycling
    protected final BufferRecycler _recycler;
    protected final GZIPRecycler _gzipRecycler;
    protected Inflater _inflater;
    
    protected final CRC32 _crc;
   
    protected final int _inputChunkLength;
    
    
Buffer used for data uncompressed from _inputBuffer.
    protected byte[] _decodeBuffer;
    
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Decoder state
    ///////////////////////////////////////////////////////////////////////
     */
    
    
Current decoding state, which determines meaning of following byte(s).
    protected int _state = ;

    
Flag set if com.ning.compress.DataHandler indicates that processing should be terminated.
    protected boolean _terminated;

    
Header flags read from gzip header
    protected int _flags;

    
Expected CRC for header, from gzip file itself.
    protected int _headerCRC;
    
    
Simple counter used when skipping fixed number of bytes
    protected int _skippedBytes;
    
    
CRC container in trailer, should match calculated CRC over data
    protected int _trailerCRC;

    
Number of bytes that trailer indicates preceding data stream should have had.
    protected int _trailerCount;
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Instance creation
    ///////////////////////////////////////////////////////////////////////
     */
    
    public GZIPUncompressor(DataHandler h)
    {
        this(h);
    }
    
    public GZIPUncompressor(DataHandler hint inputChunkLength)
    {
         = inputChunkLength;
         = h;
         = BufferRecycler.instance();
         = GZIPRecycler.instance();
         = new CRC32();
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Uncompressor API implementation
    ///////////////////////////////////////////////////////////////////////
     */
    @Override
    public boolean feedCompressedData(byte[] compint offsetint lenthrows IOException
    {
        if () {
            return false;
        }
        
        final int end = offset + len;
        if ( != ) {
            if ( < ) { // header
                offset = _handleHeader(compoffsetend);
                if (offset >= end) { // not fully handled yet
                    return true;
                }
                // fall through to body
            } else { // trailer
                offset = _handleTrailer(compoffsetend);
                if (offset < end) { // sanity check
                    _throwInternal();
                }
                // either way, we are done
                return true;
            }
        }
        // Ok, decode...
        while (true) {
            // first: if input is needed, give some
            if (.needsInput()) {
                final int left = end-offset;
                if (left < 1) { // need input but nothing to give, leve
                    return true;
                }
                final int amount = Math.min(left);
                .setInput(compoffsetamount);
                offset += amount;
            }
            // and then see what we can get out if anything
            while (true) {
                int decoded;
                try {
                    decoded = .inflate();
                } catch (DataFormatException e) {
                    throw new GZIPException("Problems inflating gzip data: "+e.getMessage(), e);
                }
                if (decoded == 0) {
                    break;
                }
                .update(, 0, decoded);
                if (!.handleData(, 0, decoded)) {
                     = true;
                    return false;
                }
            }
            if (.finished() || .needsDictionary()) {
                 = ;
                // also: push back some of data that is buffered
                int remains = .getRemaining();
                if (remains > 0) {
                    offset -= remains;
                }
                break;
            }
        }
        
        // finally; handle trailer if we got this far
        offset = _handleTrailer(compoffsetend);
        if (offset < end) { // sanity check
            _throwInternal();
        }
        return !;
    }
    @Override
    public void complete() throws IOException
    {
        byte[] b = ;
        if (b != null) {
             = null;
            .releaseDecodeBuffer(b);
        }
        Inflater i = ;
        if (i != null) {
             = null;
            .releaseInflater(i);
        }
        // 24-May-2012, tatu: Should we call this here; or fail with exception?
        .allDataHandled();
        if (!) {
            if ( != ) {
                if ( >= ) {
                    if ( == ) {
                        throw new GZIPException("Invalid GZIP stream: end-of-input in the middle of compressed data");
                    }
                    throw new GZIPException("Invalid GZIP stream: end-of-input in the trailer (state: "++")");
                }
                throw new GZIPException("Invalid GZIP stream: end-of-input in header (state: "++")");
            }
        }
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Helper methods, header/trailer
    ///////////////////////////////////////////////////////////////////////
     */
    protected final boolean _hasFlag(int flag) {
        return ( & flag) == flag;
    }
    private final int _handleHeader(byte[] compint offsetfinal int endthrows IOException
    {
        
        main_loop:
        while (offset < end) {
            byte b = comp[offset++];
            .update(b);
            
            switch () {
            case :
                if (b != ) {
                    _reportBadHeader(compoffsetend, 0);
                }
                if (offset >= end) {
                     = ;
                    break;
                }
                b = comp[offset++];
                .update(b);
                // fall through
            case :
                if (b != ) {
                    _reportBadHeader(compoffsetend, 1);
                }
                if (offset >= end) {
                     = ;
                    break;
                }
                b = comp[offset++];
                .update(b);
                // fall through
            case :
                if (b != .) {
                    _reportBadHeader(compoffsetend, 1);
                }
                if (offset >= end) {
                     = ;
                    break;
                }
                b = comp[offset++];
                .update(b);
                // fall through
            case :
                 = b// should we validate these?
                 = 0;
                 = ;
                if (offset >= end) {
                    break;
                }
                b = comp[offset++];
                .update(b);
                // fall through
            case :
                while (++ < 6) {
                    if (offset >= end) {
                        break main_loop;
                    }
                    b = comp[offset++];
                    .update(b);
                }
                if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else { // no extras... body, I guess?
                     = ;
                    break main_loop;
                }
                // let's keep things simple, do explicit re-loop to sort it out:
                continue;
            case :
                 = ;
                break;
            case :
                if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else {
                     = ;
                    break main_loop;
                }
                break;
            case // skip until zero
                while (b != 0) {
                    if (offset >= end) {
                        break main_loop;
                    }
                    b = comp[offset++];
                    .update(b);
                }
                if (_hasFlag()) {
                     = ;
                } else if (_hasFlag()) {
                     = ;
                } else {
                     = ;
                    break main_loop;
                }
                break;
            case :
                while (b != 0) {
                    if (offset >= end) {
                        break main_loop;
                    }
                    b = comp[offset++];
                }
                if (_hasFlag()) {
                     = ;
                } else {
                     = ;
                    break main_loop;
                }
                break;
            case :
                 = b & 0xFF;
                if (offset >= end) {
                     = ;
                    break;
                }
                b = comp[offset++];
                .update(b);
                // fall through
            case :
                 += ((b & 0xFF) << 8);
                int act = (int).getValue() & 0xffff;
                if (act != ) {
                    throw new GZIPException("Corrupt GZIP header: header CRC 0x"
                                          +Integer.toHexString(act)+", expected 0x "
                                          +Integer.toHexString());
                }
                 = ;
                break main_loop;
            default:
                _throwInternal("Unknown header state: "+);
            }
        }
        if ( == ) {
            .reset();
        }
        return offset;
    }
    
    private final int _handleTrailer(byte[] compint offsetfinal int endthrows IOException
    {
        while (offset < end) {
            byte b = comp[offset++];
            switch () {
            case :
                 = b & 0xFF;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 8;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 16;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 24;
                final int actCRC = (int.getValue();
                // verify CRC:
                if ( != actCRC) {
                    throw new GZIPException("Corrupt block or trailer: expected CRC "
                            +Integer.toHexString()+", computed "+Integer.toHexString(actCRC));
                }
                 = ;
                break;
            case :
                 = b & 0xFF;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 8;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 16;
                 = ;
                break;
            case :
                 += (b & 0xFF) << 24;
                 = ;
                // Verify count...
                int actCount32 = (int.getBytesWritten();
                if (actCount32 != ) {
                    throw new GZIPException("Corrupt block or trailed: expected byte count "++", read "+actCount32);
                }
                break;
            default:
                _throwInternal("Unknown trailer state: "+);
            }
        }
        return offset;
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Helper methods, other
    ///////////////////////////////////////////////////////////////////////
     */
    protected void _throwInternal() throws GZIPException {
        throw new GZIPException("Internal error");
    }
    
    protected void _throwInternal(String msgthrows GZIPException {
        throw new GZIPException("Internal error: "+msg);
    }
    
    protected void _reportBadHeader(byte[] compint nextOffsetint endint relative)
        throws GZIPException
    {
        String byteStr = "0x"+Integer.toHexString(comp[nextOffset] & 0xFF);
        if (relative <= 1) {
            int exp = (relative == 0) ? ( & 0xFF) : ( >> 8);
            --nextOffset;
            throw new GZIPException("Bad GZIP stream: byte #"+relative+" of header not '"
                    +exp+"' (0x"+Integer.toHexString(exp)+") but "+byteStr);
        }
        if (relative == 2) { // odd that 
            throw new GZIPException("Bad GZIP stream: byte #2 of header invalid: type "+byteStr
                    +" not supported, 0x"+Integer.toHexString(.)
                    +" expected");
        }
        throw new GZIPException("Bad GZIP stream: byte #"+relative+" of header invalid: "+byteStr);
    }
New to GrepCode? Check out our FAQ X