package com.limegroup.gnutella.util;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
/**
* Simulates zlib's Z_PARTIAL_FLUSH and Z_SYNC_FLUSH behaviour.
* This is a workaround for the following bugParade bugs:<br>
* http://developer.java.sun.com/developer/bugParade/bugs/4255743.html <br>
* http://developer.java.sun.com/developer/bugParade/bugs/4206909.html <br>
* The code was taken from the comments at those respective pages and
* modified slightly.
*/
public final class CompressingOutputStream extends DeflaterOutputStream {
public CompressingOutputStream (final OutputStream out, final Deflater flate) {
super(out, flate);
}
private static final byte [] EMPTYBYTEARRAY = new byte [0];
/**
* Insure all remaining data will be output.
*/
public void flush() throws IOException {
if( def.finished() ) return;
/**
* Now this is tricky: We force the Deflater to flush
* its data by switching compression level.
* As yet, a perplexingly simple workaround for
* http://developer.java.sun.com/developer/bugParade/bugs/4255743.html
*/
def.setInput(EMPTYBYTEARRAY, 0, 0);
def.setLevel(Deflater.NO_COMPRESSION);
deflate();
def.setLevel(Deflater.DEFAULT_COMPRESSION);
deflate();
super.flush();
}
protected void deflate() throws IOException {
try {
// DO NOT CALL super.deflate(), it is wrong.
// It incorrectly assumes that its buffer will be large enough
// to hold all data from a single deflate call. That is wrong.
// We need to loop until deflate returns <= 0, saying it couldn't
// deflate.
int deflated;
while( (deflated = def.deflate(buf, 0, buf.length)) > 0)
out.write(buf, 0, deflated);
} catch(NullPointerException e) {
//This will happen if 'end' was called on the deflater
//while we were deflating.
throw new IOException("deflater was ended");
}
}
} // class