Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
   * file except in compliance with the License. You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software distributed under
   * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
   * OF ANY KIND, either express or implied. See the License for the specific language
   * governing permissions and limitations under the License.
  */
 
 package com.ning.compress.lzf;
 
 
Class that handles actual encoding of individual chunks. Resulting chunks can be compressed or non-compressed; compression is only used if it actually reduces chunk size (including overhead of additional header bytes)

Note that instances are stateful and hence not thread-safe; one instance is meant to be used for processing a sequence of chunks where total length is known.

Author(s):
Tatu Saloranta (tatu.saloranta@iki.fi)
 
 public abstract class ChunkEncoder
     implements Closeable
 {
     // // // Constants
     
     // Beyond certain point we won't be able to compress; let's use 16 bytes as cut-off
     protected static final int MIN_BLOCK_TO_COMPRESS = 16;
 
     protected static final int MIN_HASH_SIZE = 256;
 
     // Not much point in bigger tables, with 8k window
     protected static final int MAX_HASH_SIZE = 16384;
 
     protected static final int MAX_OFF = 1 << 13; // 8k
     protected static final int MAX_REF = (1 << 8) + (1 << 3); // 264
 
    
How many tail bytes are we willing to just copy as is, to simplify loop end checks? 4 is bare minimum, may be raised to 8?
 
     protected static final int TAIL_LENGTH = 4;
 
     // // // Encoding tables etc
 
     protected final BufferRecycler _recycler;

    
Hash table contains lookup based on 3-byte sequence; key is hash of such triplet, value is offset in buffer.
 
     protected int[] _hashTable;
     
     protected final int _hashModulo;

    
Buffer in which encoded content is stored during processing
 
     protected byte[] _encodeBuffer;

    
Small buffer passed to LZFChunk, needed for writing chunk header
 
     protected byte[] _headerBuffer;

    

Parameters:
totalLength Total encoded length; used for calculating size of hash table to use
 
     protected ChunkEncoder(int totalLength)
     {
         // Need room for at most a single full chunk
         int largestChunkLen = Math.min(totalLength.);       
         int suggestedHashLen = calcHashLen(largestChunkLen);
          = BufferRecycler.instance();
          = .allocEncodingHash(suggestedHashLen);
          = . - 1;
         // Ok, then, what's the worst case output buffer length?
         // length indicator for each 32 literals, so:
         // 21-Feb-2013, tatu: Plus we want to prepend chunk header in place:
         int bufferLen = largestChunkLen + ((largestChunkLen + 31) >> 5) + .;
          = .allocEncodingBuffer(bufferLen);
     }

    
Alternate constructor used when we want to avoid allocation encoding buffer, in cases where caller wants full control over allocations.
 
    protected ChunkEncoder(int totalLengthboolean bogus)
    {
        int largestChunkLen = Math.max(totalLength.);
        int suggestedHashLen = calcHashLen(largestChunkLen);
         = BufferRecycler.instance();
         = .allocEncodingHash(suggestedHashLen);
         = . - 1;
         = null;
    }
    private static int calcHashLen(int chunkSize)
    {
        // in general try get hash table size of 2x input size
        chunkSize += chunkSize;
        // but no larger than max size:
        if (chunkSize >= ) {
            return ;
        }
        // otherwise just need to round up to nearest 2x
        int hashLen = ;
        while (hashLen < chunkSize) {
            hashLen += hashLen;
        }
        return hashLen;
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Public API
    ///////////////////////////////////////////////////////////////////////
     */

    
Method to close once encoder is no longer in use. Note: after calling this method, further calls to encodeChunk(byte[],int,int) will fail
    @Override
    public final void close()
    {
        byte[] buf = ;
        if (buf != null) {
             = null;
            .releaseEncodeBuffer(buf);
        }
        int[] ibuf = ;
        if (ibuf != null) {
             = null;
            .releaseEncodingHash(ibuf);
        }
    }
    
Method for compressing (or not) individual chunks
    public LZFChunk encodeChunk(byte[] dataint offsetint len)
    {
        if (len >= ) {
            /* If we have non-trivial block, and can compress it by at least
             * 2 bytes (since header is 2 bytes longer), let's compress:
             */
            int compLen = tryCompress(dataoffsetoffset+len, 0);
            if (compLen < (len-2)) { // nah; just return uncompressed
                return LZFChunk.createCompressed(len, 0, compLen);
            }
        }
        // Otherwise leave uncompressed:
        return LZFChunk.createNonCompressed(dataoffsetlen);
    }

    
Alternate chunk compression method that will append encoded chunk in pre-allocated buffer. Note that caller must ensure that the buffer is large enough to hold not just encoded result but also intermediate result; latter may be up to 4% larger than input; caller may use LZFEncoder.estimateMaxWorkspaceSize(int) to calculate necessary buffer size.

Returns:
Offset in output buffer after appending the encoded chunk
Since:
0.9.7
    public int appendEncodedChunk(final byte[] inputfinal int inputPtrfinal int inputLen,
            final byte[] outputBufferfinal int outputPos)
    {
        if (inputLen >= ) {
            /* If we have non-trivial block, and can compress it by at least
             * 2 bytes (since header is 2 bytes longer), use as-is
             */
            final int compStart = outputPos + .;
            final int end = tryCompress(inputinputPtrinputPtr+inputLenoutputBuffercompStart);
            final int uncompEnd = (outputPos + .) + inputLen;
            if (end < uncompEnd) { // yes, compressed by at least one byte
                final int compLen = end - compStart;
                LZFChunk.appendCompressedHeader(inputLencompLenoutputBufferoutputPos);
                return end;
            }
        }
        // Otherwise append as non-compressed chunk instead (length + 5):
        return LZFChunk.appendNonCompressed(inputinputPtrinputLenoutputBufferoutputPos);
    }
    
    
Method for encoding individual chunk, writing it to given output stream.
    public void encodeAndWriteChunk(byte[] dataint offsetint lenOutputStream out)
        throws IOException
    {
        if (len >= ) {
            // If we have non-trivial block, and can compress it by at least
            // 2 bytes (since header is 2 bytes longer), let's compress:
            int compEnd = tryCompress(dataoffsetoffset+len.);
            final int compLen = compEnd - .;
            if (compLen < (len-2)) { // yes, compressed block is smaller (consider header is 2 bytes longer)
                LZFChunk.appendCompressedHeader(lencompLen, 0);
                out.write(, 0, compEnd);
                return;
            }
        }
        // Otherwise leave uncompressed:
        byte[] headerBuf = ;
        if (headerBuf == null) {
             = headerBuf = new byte[.];
        }
        LZFChunk.writeNonCompressedHeader(lenoutheaderBuf);
        out.write(dataoffsetlen);
    }
    /*
    ///////////////////////////////////////////////////////////////////////
    // Abstract methods for sub-classes
    ///////////////////////////////////////////////////////////////////////
     */

    
Main workhorse method that will try to compress given chunk, and return end position (offset to byte after last included byte)

Returns:
Output pointer after handling content, such that result - originalOutPost is the actual length of compressed chunk (without header)
    protected abstract int tryCompress(byte[] inint inPosint inEndbyte[] outint outPos);
    /*
    ///////////////////////////////////////////////////////////////////////
    // Shared helper methods
    ///////////////////////////////////////////////////////////////////////
     */
    protected final int hash(int h) {
        // or 184117; but this seems to give better hashing?
        return ((h * 57321) >> 9) & ;
        // original lzf-c.c used this:
        //return (((h ^ (h << 5)) >> (24 - HLOG) - h*5) & _hashModulo;
        // but that didn't seem to provide better matches
    }
New to GrepCode? Check out our FAQ X