package org.simantics.lz4; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import net.jpountz.lz4.LZ4Factory; import net.jpountz.util.Native; import org.simantics.compressions.impl.Buffers; import org.simantics.lz4.impl.LZ4InputStream; import org.simantics.lz4.impl.LZ4OutputStream; public class LZ4 { private static LZ4Factory INSTANCE = null; static { Native.load(); INSTANCE = LZ4Factory.fastestInstance(); } public static LZ4Factory getInstance() { return INSTANCE; } public static boolean isNativeInitialized() { return Native.isLoaded(); } /** * The output buffer must be at least 5% larger than the input buffer and * can not be smaller than 66 bytes. * * @param inputSize size of uncompressed input data in bytes * @return maximum amount of bytes needed for the compressed data */ public static int compressBound(int inputSize) { return INSTANCE.fastCompressor().maxCompressedLength(inputSize); } /** * Compress a block of data in the input buffer and returns the size of * compressed block. The size of input buffer is specified by length. The * minimum input buffer size is 16. * *

* The output buffer must be at least 5% larger than the input buffer and * can not be smaller than 66 bytes. * *

* If the input is not compressible, the return value might be larger than * length (input buffer size). * *

* The input buffer and the output buffer can not overlap. * *

* It is recommended to have both input buffers as direct or heap buffers, * not mixed. Mixing different types of buffers will hurt performance a lot. * If both buffers are direct byte buffers and native decompression is * available, it will be employed. */ public static int compressBuffer(ByteBuffer input, int inputOffset, int length, ByteBuffer output, int outputOffset) { if (output.isReadOnly()) throw new IllegalArgumentException("read-only output buffer"); if (input.isDirect() && output.isDirect()) { return INSTANCE.fastCompressor().compress(input, inputOffset, length, output, outputOffset, output.capacity() - outputOffset); } byte[] inarr = Buffers.getInputArray(input); byte[] outarr = Buffers.getOutputArray(output); int result = INSTANCE.fastCompressor().compress(inarr, inputOffset, length, outarr, outputOffset, outarr.length - outputOffset); Buffers.writeOutput(output, outarr); return result; } /** * Decompress a block of compressed data and returns the size of the * decompressed block. If error occurs, e.g. the compressed data is * corrupted or the output buffer is not large enough, then 0 (zero) will be * returned instead. * *

* The input buffer and the output buffer can not overlap. * *

* Decompression is memory safe and guaranteed not to write the output * buffer more than what is specified in maxout. * *

* It is recommended to have both input buffers as direct or heap buffers, * not mixed. Mixing different types of buffers will hurt performance a lot. * If both buffers are direct byte buffers and native decompression is * available, it will be employed. */ public static int decompressBuffer(ByteBuffer input, int inputOffset, int length, ByteBuffer output, int outputOffset, int maxout) { if (output.isReadOnly()) throw new IllegalArgumentException("read-only output buffer"); if (input.isDirect() && output.isDirect()) return INSTANCE.safeDecompressor().decompress(input, inputOffset, length, output, outputOffset, maxout); byte[] inarr = Buffers.getInputArray(input); byte[] outarr = Buffers.getOutputArray(output); int result = INSTANCE.safeDecompressor().decompress(inarr, inputOffset, length, outarr, outputOffset, maxout); Buffers.writeOutput(output, outarr); return result; } /** * @param file the FastLZ-compressed file to read * @return input stream that decompresses its output using the FastLZ * algorithm. Caller is responsible of closing the returned stream. * @throws FileNotFoundException see * {@link FileOutputStream#FileOutputStream(File)} for when this is * thrown */ public static InputStream read(File file) throws FileNotFoundException { return new LZ4InputStream(file); } /** * @param input * @return * @param input * the input stream to decompress * @return a stream that decompresses the specified FastLZ compressed input * stream */ public static InputStream read(InputStream input) { return new LZ4InputStream(input); } /** * @param file the FastLZ-compressed file to write * @return output stream that compresses its input using the FastLZ * algorithm. Caller is responsible of closing the returned stream. * @throws FileNotFoundException see * {@link FileOutputStream#FileOutputStream(File)} for when this is * thrown */ public static OutputStream write(File file) throws FileNotFoundException { return new LZ4OutputStream(file); } /** * @param output * the stream to write compressed output into * @return a stream that compresses into the specified output stream with * FastLZ */ public static OutputStream write(OutputStream output) { return new LZ4OutputStream(output); } }