Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.ning.compress.lzf;
  
Decoder that handles decoding of sequence of encoded LZF chunks, combining them into a single contiguous result byte array.

Note that instances have no state, so they are fully thread-safe and reusable.

Author(s):
Tatu Saloranta (tatu.saloranta@iki.fi)
 
 public abstract class ChunkDecoder
 {
     protected final static byte BYTE_NULL = 0;
     protected final static int HEADER_BYTES = 5;
 
     public ChunkDecoder() { }
 
     /*
     ///////////////////////////////////////////////////////////////////////
     // Public API
     ///////////////////////////////////////////////////////////////////////
      */

    
Method for decompressing a block of input data encoded in LZF block structure (compatible with lzf command line utility), and can consist of any number of blocks. Note that input MUST consists of a sequence of one or more complete chunks; partial chunks can not be handled.
 
     public final byte[] decode(final byte[] inputBufferthrows LZFException
     {
         byte[] result = new byte[calculateUncompressedSize(inputBuffer, 0, inputBuffer.length)];
         decode(inputBuffer, 0, inputBuffer.lengthresult);
         return result;
     }

    
Method for decompressing a block of input data encoded in LZF block structure (compatible with lzf command line utility), and can consist of any number of blocks. Note that input MUST consists of a sequence of one or more complete chunks; partial chunks can not be handled.
 
     public final byte[] decode(final byte[] inputBufferint inputPtrint inputLenthrows LZFException
     {
         byte[] result = new byte[calculateUncompressedSize(inputBufferinputPtrinputLen)];
         decode(inputBufferinputPtrinputLenresult);
         return result;
     }
    
    
Method for decompressing a block of input data encoded in LZF block structure (compatible with lzf command line utility), and can consist of any number of blocks. Note that input MUST consists of a sequence of one or more complete chunks; partial chunks can not be handled.
 
     public final int decode(final byte[] inputBufferfinal byte[] targetBufferthrows LZFException
     {
         return decode(inputBuffer, 0, inputBuffer.lengthtargetBuffer);
     }

    
Method for decompressing a block of input data encoded in LZF block structure (compatible with LZF command line utility), and can consist of any number of blocks. Note that input MUST consists of a sequence of one or more complete chunks; partial chunks can not be handled.
 
     public int decode(final byte[] sourceBufferint inPtrint inLength,
             final byte[] targetBufferthrows LZFException
     {
         int outPtr = 0;
         int blockNr = 0;
 
         final int end = inPtr + inLength - 1; // -1 to offset possible end marker
         
         while (inPtr < end) {
             // let's do basic sanity checks; no point in skimping with these checks
             if (sourceBuffer[inPtr] != . || sourceBuffer[inPtr+1] != .) {
                 throw new LZFException("Corrupt input data, block #"+blockNr+" (at offset "+inPtr+"): did not start with 'ZV' signature bytes");
             }
             inPtr += 2;
             int type = sourceBuffer[inPtr++];
             int len = uint16(sourceBufferinPtr);
             inPtr += 2;
             if (type == .) { // uncompressed
                 if ((outPtr + len) > targetBuffer.length) {
                     _reportArrayOverflow(targetBufferoutPtrlen);
                 }
                 System.arraycopy(sourceBufferinPtrtargetBufferoutPtrlen);
                 outPtr += len;
             } else { // compressed
                 int uncompLen = uint16(sourceBufferinPtr);
                if ((outPtr + uncompLen) > targetBuffer.length) {
                    _reportArrayOverflow(targetBufferoutPtruncompLen);
                }
                inPtr += 2;
                decodeChunk(sourceBufferinPtrtargetBufferoutPtroutPtr+uncompLen);
                outPtr += uncompLen;
            }
            inPtr += len;
            ++blockNr;
        }
        return outPtr;
    }

    
Main decode from a stream. Decompressed bytes are placed in the outputBuffer, inputBuffer is a "scratch-area".

Parameters:
is An input stream of LZF compressed bytes
inputBuffer A byte array used as a scratch area.
outputBuffer A byte array in which the result is returned
Returns:
The number of bytes placed in the outputBuffer.
    public abstract int decodeChunk(final InputStream isfinal byte[] inputBufferfinal byte[] outputBuffer
        throws IOException;
    
    
Main decode method for individual chunks.
    public abstract void decodeChunk(byte[] inint inPosbyte[] outint outPosint outEnd)
        throws LZFException;

    

Returns:
If positive number, number of bytes skipped; if -1, end-of-stream was reached; otherwise, amount of content decoded (using formula of returnValue = -(decodedAmount + 2))
    public abstract int skipOrDecodeChunk(final InputStream isfinal byte[] inputBuffer,
            final byte[] outputBufferfinal long maxToSkip)
        throws IOException;
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Public static methods
    ///////////////////////////////////////////////////////////////////////
     */

    
Helper method that will calculate total uncompressed size, for sequence of one or more LZF blocks stored in given byte array. Will do basic sanity checking, so that this method can be called to verify against some types of corruption.
    public static int calculateUncompressedSize(byte[] dataint ptrint lengththrows LZFException
    {
        int uncompressedSize = 0;
        int blockNr = 0;
        final int end = ptr + length;
        while (ptr < end) {
            // can use optional end marker
            if (ptr == (data.length + 1) && data[ptr] == ) {
                ++ptr// so that we'll be at end
                break;
            }
            // simpler to handle bounds checks by catching exception here...
            try {
                if (data[ptr] != . || data[ptr+1] != .) {
                    throw new LZFException("Corrupt input data, block #"+blockNr+" (at offset "+ptr+"): did not start with 'ZV' signature bytes");
                }
                int type = (intdata[ptr+2];
                int blockLen = uint16(dataptr+3);
                if (type == .) { // uncompressed
                    ptr += 5;
                    uncompressedSize += blockLen;
                } else if (type == .) { // compressed
                    uncompressedSize += uint16(dataptr+5);
                    ptr += 7;
                } else { // unknown... CRC-32 would be 2, but that's not implemented by cli tool
                    throw new LZFException("Corrupt input data, block #"+blockNr+" (at offset "+ptr+"): unrecognized block type "+(type & 0xFF));
                }
                ptr += blockLen;
            } catch (ArrayIndexOutOfBoundsException e) {
                throw new LZFException("Corrupt input data, block #"+blockNr+" (at offset "+ptr+"): truncated block header");
            }
            ++blockNr;
        }
        // one more sanity check:
        if (ptr != end) {
            throw new LZFException("Corrupt input data: block #"+blockNr+" extends "+(data.length - ptr)+" beyond end of input");
        }
        return uncompressedSize;
    }
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Internal methods
    ///////////////////////////////////////////////////////////////////////
     */
    
    protected final static int uint16(byte[] dataint ptr) {
        return ((data[ptr] & 0xFF) << 8) + (data[ptr+1] & 0xFF);
    }    

    
Helper method to forcibly load header bytes that must be read before chunk can be handled.
    protected final static int readHeader(final InputStream isfinal byte[] inputBuffer)
        throws IOException
    {
        // Ok: simple case first, where we just get all data we need
        int needed = ;
        int count = is.read(inputBuffer, 0, needed);
        
        if (count == needed) {
            return count;
        }
        if (count <= 0) {
            return 0;
        }
        // if not, a source that trickles data (network etc); must loop
        int offset = count;
        needed -= count;
        do {
            count = is.read(inputBufferoffsetneeded);
            if (count <= 0) {
                break;
            }
            offset += count;
            needed -= count;
        } while (needed > 0);
        return offset;
    }
    
    protected final static void readFully(InputStream isboolean compressed,
            byte[] outputBufferint offsetint lenthrows IOException
    {
        int left = len;
        while (left > 0) {
            int count = is.read(outputBufferoffsetleft);
            if (count < 0) { // EOF not allowed here
                throw new LZFException("EOF in "+len+" byte ("
                        +(compressed ? "" : "un")+"compressed) block: could only read "
                        +(len-left)+" bytes");
            }
            offset += count;
            left -= count;
        }
    }
    protected final static void skipFully(final InputStream isint amountthrows IOException
    {
        final int orig = amount;
        while (amount > 0) {
            long skipped = is.skip(amount);
            if (skipped <= 0) {
                throw new LZFException("Input problem: failed to skip "+orig+" bytes in input stream, only skipped "
                        +(orig-amount));
            }
            amount -= (intskipped;
        }
    }
    
    protected void _reportCorruptHeader() throws LZFException {
        throw new LZFException("Corrupt input data, block did not start with 2 byte signature ('ZV') followed by type byte, 2-byte length)");
    }
    
    
Helper method called when it is determined that the target buffer can not hold all data to copy or uncompress
    protected void _reportArrayOverflow(byte[] targetBufferint outPtrint dataLen)
        throws LZFException
    {
        throw new LZFException("Target buffer too small ("+targetBuffer.length+"): can not copy/uncompress "
                +dataLen+" bytes to offset "+outPtr);
    }
New to GrepCode? Check out our FAQ X