ZlibCodec.java
/*
* This file is part of Waarp Project (named also Waarp or GG).
*
* Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
* tags. See the COPYRIGHT.txt in the distribution for a full listing of
* individual contributors.
*
* All Waarp Project is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.compress.zlib;
import io.netty.buffer.ByteBuf;
import org.waarp.common.file.FileUtils;
import org.waarp.compress.CompressorCodec;
import org.waarp.compress.MalformedInputException;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream;
/**
* ZSTD JNI Codec implementation
*/
public class ZlibCodec implements CompressorCodec {
@Override
public final int maxCompressedLength(final int uncompressedSize) {
return uncompressedSize;
}
@Override
public final byte[] compress(final byte[] input, final int inputLength) {
ByteArrayOutputStream bos = null;
DeflaterOutputStream out = null;
try {
bos = new ByteArrayOutputStream(inputLength + 1024);
out = new DeflaterOutputStream(bos);
out.write(input, 0, inputLength);
out.close();
bos.close();
return bos.toByteArray();
} catch (final Exception e) {
throw new MalformedInputException(e);
} finally {
FileUtils.close(out);
FileUtils.close(bos);
}
}
@Override
public final int compress(final byte[] input, final int inputLength,
final byte[] output, final int maxOutputLength)
throws MalformedInputException {
try {
final byte[] bytes = compress(input, inputLength);
System.arraycopy(bytes, 0, output, 0, bytes.length);
return bytes.length;
} catch (final Exception e) {
throw new MalformedInputException(e);
}
}
@Override
public final long compress(final File input, final File output)
throws MalformedInputException {
InputStream inputStream = null;
OutputStream outputStream = null;
DeflaterOutputStream out = null;
try {
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(output);
out = new DeflaterOutputStream(outputStream);
FileUtils.copy(64 * 1024, inputStream, out);
out = null;
return output.length();
} catch (final Exception e) {
throw new MalformedInputException(e);
} finally {
FileUtils.close(out);
FileUtils.close(inputStream);
FileUtils.close(outputStream);
}
}
@Override
public final byte[] decompress(final byte[] compressed, final int length)
throws MalformedInputException {
ByteArrayOutputStream bos = null;
InflaterOutputStream out = null;
try {
bos = new ByteArrayOutputStream(length << 2);
out = new InflaterOutputStream(bos);
out.write(compressed, 0, length);
out.close();
bos.close();
return bos.toByteArray();
} catch (final Exception e) {
throw new MalformedInputException(e);
} finally {
FileUtils.close(out);
FileUtils.close(bos);
}
}
@Override
public final int decompress(final byte[] input, final int inputLength,
final byte[] output, final int maxOutputLength)
throws MalformedInputException {
try {
final byte[] bytes = decompress(input, inputLength);
System.arraycopy(bytes, 0, output, 0, bytes.length);
return bytes.length;
} catch (final Exception e) {
throw new MalformedInputException(e);
}
}
@Override
public final long decompress(final File input, final File output)
throws MalformedInputException {
InputStream inputStream = null;
OutputStream outputStream = null;
InflaterOutputStream out = null;
try {
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(output);
out = new InflaterOutputStream(outputStream);
FileUtils.copy(64 * 1024, inputStream, out);
out = null;
return output.length();
} catch (final Exception e) {
throw new MalformedInputException(e);
} finally {
FileUtils.close(out);
FileUtils.close(inputStream);
FileUtils.close(outputStream);
}
}
@Override
public final int getDecompressedSize(final byte[] compressed,
final int length) {
return 0;
}
private ByteArrayOutputStream byteArrayOutputStream = null;
private DeflaterOutputStream deflaterOutputStream = null;
private InflaterOutputStream inflaterOutputStream = null;
private static final byte[] EMPTY_BYTES = {};
/**
* Allow to specify a block size for CoDec
*
* @param defaultBlockSize
*/
public void initializeCodecForStream(final int defaultBlockSize) {
byteArrayOutputStream = new ByteArrayOutputStream(defaultBlockSize);
}
/**
* Write an uncompressed data for compression
*
* @param uncompressed
*
* @throws IOException
*/
public synchronized void writeForCompression(final byte[] uncompressed)
throws IOException {
if (byteArrayOutputStream == null) {
byteArrayOutputStream = new ByteArrayOutputStream(1024 * 1024);
}
if (deflaterOutputStream == null) {
deflaterOutputStream = new DeflaterOutputStream(byteArrayOutputStream);
}
deflaterOutputStream.write(uncompressed);
deflaterOutputStream.flush();
}
/**
* Write an uncompressed data for compression
*
* @param uncompressed
*
* @throws IOException
*/
public void writeForCompression(final ByteBuf uncompressed)
throws IOException {
final byte[] buffer = new byte[uncompressed.readableBytes()];
uncompressed.readBytes(buffer);
writeForCompression(buffer);
}
/**
* Write a compressed data for decompression
*
* @param compressed
*
* @throws IOException
*/
public synchronized void writeForDecompression(final byte[] compressed)
throws IOException {
if (byteArrayOutputStream == null) {
byteArrayOutputStream = new ByteArrayOutputStream(1024 * 1024);
}
if (inflaterOutputStream == null) {
inflaterOutputStream = new InflaterOutputStream(byteArrayOutputStream);
}
inflaterOutputStream.write(compressed);
inflaterOutputStream.flush();
}
/**
* Write a compressed data for decompression
*
* @param compressed
*
* @throws IOException
*/
public synchronized void writeForDecompression(final ByteBuf compressed)
throws IOException {
final byte[] buffer = new byte[compressed.readableBytes()];
compressed.readBytes(buffer);
writeForDecompression(buffer);
}
/**
* @return the current available block byte array (releasing it immediately)
*/
public synchronized byte[] readCodec() {
if (deflaterOutputStream == null && inflaterOutputStream == null) {
return EMPTY_BYTES;
}
if (byteArrayOutputStream == null) {
return EMPTY_BYTES;
}
final byte[] bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.reset();
return bytes;
}
/**
* Finish the CoDec operation. The Codec is ready to be reused.<br>
* <br>
* <b>Important: calling this method is mandatory to prevent OOME</b>
*
* @return the final block byte array
*
* @throws IOException
*/
public synchronized byte[] finishCodec() throws IOException {
if (deflaterOutputStream != null) {
deflaterOutputStream.flush();
deflaterOutputStream.finish();
deflaterOutputStream.close();
deflaterOutputStream = null;
} else if (inflaterOutputStream != null) {
inflaterOutputStream.flush();
inflaterOutputStream.finish();
inflaterOutputStream.close();
inflaterOutputStream = null;
}
if (byteArrayOutputStream != null) {
final byte[] bytes = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
byteArrayOutputStream = null;
return bytes;
}
return EMPTY_BYTES;
}
}