Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.ning.compress.lzf.util;
  
  import java.io.*;
  
Helper class that allows use of LZF compression even if a library requires use of java.io.FileInputStream.

Note that use of this class is not recommended unless you absolutely must use a java.io.FileInputStream instance; otherwise basic com.ning.compress.lzf.LZFInputStream (which uses aggregation for underlying streams) is more appropriate

Implementation note: much of the code is just copied from com.ning.compress.lzf.LZFInputStream, so care must be taken to keep implementations in sync if there are fixes.

Since:
0.8
 
 public class LZFFileInputStream
     extends FileInputStream
 {
    
Underlying decoder in use.
 
     protected final ChunkDecoder _decompressor;
    
    
Object that handles details of buffer recycling
 
     protected final BufferRecycler _recycler;

    
Flag that indicates if we have already called 'inputStream.close()' (to avoid calling it multiple times)
 
     protected boolean _inputStreamClosed;
    
    
Flag that indicates whether we force full reads (reading of as many bytes as requested), or 'optimal' reads (up to as many as available, but at least one). Default is false, meaning that 'optimal' read is used.
 
     protected boolean _cfgFullReads = false;
        
    
the current buffer of compressed bytes (from which to decode)
 
     protected byte[] _inputBuffer;
        
    
the buffer of uncompressed bytes from which content is read
 
     protected byte[] _decodedBytes;
        
    
The current position (next char to output) in the uncompressed bytes buffer.
 
     protected int _bufferPosition = 0;
    
    
Length of the current uncompressed bytes buffer
 
     protected int _bufferLength = 0;

    
Wrapper object we use to allow decoder to read directly from the stream, without ending in infinite loop...
 
     protected final Wrapper _wrapper;
     
     /*
     ///////////////////////////////////////////////////////////////////////
     // Construction, configuration
     ///////////////////////////////////////////////////////////////////////
      */
 
     public LZFFileInputStream(File filethrows FileNotFoundException {
         this(file, ChunkDecoderFactory.optimalInstance());
     }
 
     public LZFFileInputStream(FileDescriptor fdObj) {
         this(fdObj, ChunkDecoderFactory.optimalInstance());
     }
 
     public LZFFileInputStream(String namethrows FileNotFoundException {
         this(name, ChunkDecoderFactory.optimalInstance());
     }
     
     public LZFFileInputStream(File fileChunkDecoder decompressorthrows FileNotFoundException
     {
         super(file);
          = decompressor;
          = BufferRecycler.instance();
          = false;
         = new Wrapper();
    }
    public LZFFileInputStream(FileDescriptor fdObjChunkDecoder decompressor)
    {
        super(fdObj);
         = decompressor;
         = BufferRecycler.instance();
         = false;
         = new Wrapper();
    }
    public LZFFileInputStream(String nameChunkDecoder decompressorthrows FileNotFoundException
    {
        super(name);
         = decompressor;
         = BufferRecycler.instance();
         = false;
         = new Wrapper();
    }

    
Method that can be used define whether reads should be "full" or "optimal": former means that full compressed blocks are read right away as needed, optimal that only smaller chunks are read at a time, more being read as needed.
    public void setUseFullReads(boolean b) {
         = b;
    }
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // FileInputStream overrides
    ///////////////////////////////////////////////////////////////////////
     */
    @Override
    public int available()
    {
        if () { // javadocs suggest 0 for closed as well (not -1)
            return 0;
        }
        int left = ( - );
        return (left <= 0) ? 0 : left;
    }
    @Override
    public void close() throws IOException
    {
         =  = 0;
        byte[] buf = ;
        if (buf != null) {
             = null;
            .releaseInputBuffer(buf);
        }
        buf = ;
        if (buf != null) {
             = null;
            .releaseDecodeBuffer(buf);
        }
        if (!) {
             = true;
            super.close();
        }
    }
    // fine as is: don't override
    // public FileChannel getChannel();
    // final, can't override:
    //public FileDescriptor getFD();
    @Override
    public int read() throws IOException
    {
        if (!readyBuffer()) {
            return -1;
        }
        return [++] & 255;
    }
    @Override
    public int read(byte[] bthrows IOException
    {
        return read(b, 0, b.length);
    }
    @Override
    public int read(byte[] bufferint offsetint lengththrows IOException
    {
        if (!readyBuffer()) {
            return -1;
        }
        if (length < 1) {
            return 0;
        }
        // First let's read however much data we happen to have...
        int chunkLength = Math.min( - length);
        System.arraycopy(bufferoffsetchunkLength);
         += chunkLength;
        if (chunkLength == length || !) {
            return chunkLength;
        }
        // Need more data, then
        int totalRead = chunkLength;
        do {
            offset += chunkLength;
            if (!readyBuffer()) {
                break;
            }
            chunkLength = Math.min( - , (length - totalRead));
            System.arraycopy(bufferoffsetchunkLength);
             += chunkLength;
            totalRead += chunkLength;
        } while (totalRead < length);
        return totalRead;
    }

    
Overridden to just skip at most a single chunk at a time
    /*
    @Override
    public long skip(long n) throws IOException
    {
        if (!readyBuffer()) {
            return -1L;
        }
        int left = (_bufferLength - _bufferPosition);
        // either way, just skip whatever we have decoded
        if (left > n) {
            left = (int) n;
        }
        _bufferPosition += left;
        return left;
    }
    */

    
Overridden to implement efficient skipping by skipping full chunks whenever possible.
    @Override
    public long skip(long nthrows IOException
    {
        if () {
            return -1;
        }
        if (n <= 0L) {
            return n;
        }
        long skipped;
        // if any left to skip, just return that for simplicity
        if ( < ) {
            int left = ( - );
            if (n <= left) { // small skip, fulfilled from what we already got
                 += (intn;
                return n;
            }
             = ;
            skipped = left;
            n -= left;
        } else {
            skipped = 0L;
        }
        // and then full-chunk skipping, if possible
        while (true) {
            int amount = .skipOrDecodeChunk(n);
            if (amount >= 0) { // successful skipping of the chunk
                skipped += amount;
                n -= amount;
                if (n <= 0L) {
                    return skipped;
                }
                continue;
            }
            if (amount == -1) { // EOF
                close();
                return skipped;
            }
            // decoded buffer-full, more than max skip
             = -(amount+1);
            skipped += n;
             = (intn;
            return skipped;
        }
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Extended public API
    ///////////////////////////////////////////////////////////////////////
     */
    
    
Convenience method that will read and uncompress all data available, and write it using given java.io.OutputStream. This avoids having to make an intermediate copy of uncompressed data which would be needed when doing the same manually.

Parameters:
out OutputStream to use for writing content
Returns:
Number of bytes written (uncompressed)
Since:
0.9.3
    public int readAndWrite(OutputStream outthrows IOException
    {
        int total = 0;
        while (readyBuffer()) {
            int avail =  - ;
            out.write(avail);
             += avail// to ensure it looks like we consumed it all
            total += avail;
        }
        return total;
    }
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Internal methods
    ///////////////////////////////////////////////////////////////////////
     */

    
Fill the uncompressed bytes buffer by reading the underlying inputStream.

    protected boolean readyBuffer() throws IOException
    {
        if () {
            throw new IOException("Input stream closed");
        }
        if ( < ) {
            return true;
        }
        if ( < 0) {
            close();
            return false;
        }
         = 0;
        return ( < );
    }
    protected final int readRaw(byte[] bufferint offsetint lengththrows IOException {
        return super.read(bufferoffsetlength);
    }
    protected final long skipRaw(long amountthrows IOException {
        return super.skip(amount);
    }
    
    /*
    ///////////////////////////////////////////////////////////////////////
    // Helper class(es)
    ///////////////////////////////////////////////////////////////////////
     */


    
This simple wrapper is needed to re-route read calls so that they will use "raw" reads
    private final class Wrapper extends InputStream
    {
        @Override
        public void close() throws IOException {
            throw new UnsupportedOperationException();
        }
        @Override
        public int read() throws IOException {
            throw new UnsupportedOperationException();
        }
        @Override
        public int read(byte[] bufferint offsetint lengththrows IOException {
            return readRaw(bufferoffsetlength);
        }
        @Override
        public int read(byte[] bufferthrows IOException {
            return readRaw(buffer, 0, buffer.length);
        }
        @Override
        public long skip(long nthrows IOException {
            return skipRaw(n);
        }
    }
New to GrepCode? Check out our FAQ X