DeflaterOutputStream.java
/*
* Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. The names of the authors may not be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JCRAFT, INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jcraft.jsch.jzlib;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
final class DeflaterOutputStream extends FilterOutputStream {
protected final Deflater deflater;
protected byte[] buffer;
private boolean closed = false;
private boolean syncFlush = false;
private final byte[] buf1 = new byte[1];
protected boolean mydeflater = false;
private boolean close_out = true;
protected static final int DEFAULT_BUFSIZE = 512;
DeflaterOutputStream(OutputStream out) throws IOException {
this(out, new Deflater(JZlib.Z_DEFAULT_COMPRESSION), DEFAULT_BUFSIZE, true);
mydeflater = true;
}
DeflaterOutputStream(OutputStream out, Deflater def) throws IOException {
this(out, def, DEFAULT_BUFSIZE, true);
}
DeflaterOutputStream(OutputStream out, Deflater deflater, int size) throws IOException {
this(out, deflater, size, true);
}
DeflaterOutputStream(OutputStream out, Deflater deflater, int size, boolean close_out)
throws IOException {
super(out);
if (out == null || deflater == null) {
throw new NullPointerException();
} else if (size <= 0) {
throw new IllegalArgumentException("buffer size must be greater than 0");
}
this.deflater = deflater;
buffer = new byte[size];
this.close_out = close_out;
}
@Override
public void write(int b) throws IOException {
buf1[0] = (byte) (b & 0xff);
write(buf1, 0, 1);
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
if (deflater.finished()) {
throw new IOException("finished");
} else if (off < 0 || len < 0 || off + len > b.length) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
} else {
int flush = syncFlush ? JZlib.Z_SYNC_FLUSH : JZlib.Z_NO_FLUSH;
deflater.setInput(b, off, len, true);
while (deflater.avail_in > 0) {
int err = deflate(flush);
if (err == JZlib.Z_STREAM_END)
break;
}
}
}
void finish() throws IOException {
while (!deflater.finished()) {
deflate(JZlib.Z_FINISH);
}
}
@Override
public void close() throws IOException {
if (!closed) {
finish();
if (mydeflater) {
deflater.end();
}
if (close_out)
out.close();
closed = true;
}
}
@SuppressWarnings("fallthrough")
protected int deflate(int flush) throws IOException {
deflater.setOutput(buffer, 0, buffer.length);
int err = deflater.deflate(flush);
switch (err) {
case JZlib.Z_OK:
case JZlib.Z_STREAM_END:
break;
case JZlib.Z_BUF_ERROR:
if (deflater.avail_in <= 0 && flush != JZlib.Z_FINISH) {
// flush() without any data
break;
}
default:
throw new IOException(
"failed to deflate: error=" + err + " avail_out=" + deflater.avail_out);
}
int len = deflater.next_out_index;
if (len > 0) {
out.write(buffer, 0, len);
}
return err;
}
@Override
public void flush() throws IOException {
if (syncFlush && !deflater.finished()) {
while (true) {
int err = deflate(JZlib.Z_SYNC_FLUSH);
if (deflater.next_out_index < buffer.length)
break;
if (err == JZlib.Z_STREAM_END)
break;
}
}
out.flush();
}
long getTotalIn() {
return deflater.getTotalIn();
}
long getTotalOut() {
return deflater.getTotalOut();
}
void setSyncFlush(boolean syncFlush) {
this.syncFlush = syncFlush;
}
boolean getSyncFlush() {
return this.syncFlush;
}
Deflater getDeflater() {
return deflater;
}
}