mirror of
https://github.com/corda/corda.git
synced 2025-01-05 20:54:13 +00:00
fix bugs in Deflater and DeflaterOutputStream
Previously, Deflater.deflate would pass Z_SYNC_FLUSH to zlib unconditionally, which caused the output to be enormous when setInput was called repeatedly with very small input buffers. In order to allow zlib to buffer output and thereby maximize compression, we must use Z_NO_FLUSH until Deflater.finish is called, at which point we switch to Z_FINISH. We also modify DeflaterOutputStream.close to call Deflater.finish and write any remaining output to the wrapped stream.
This commit is contained in:
parent
e788a18bc7
commit
d4da92d300
@ -121,7 +121,7 @@ Java_java_util_zip_Deflater_deflate
|
|||||||
(JNIEnv* e, jclass, jlong peer,
|
(JNIEnv* e, jclass, jlong peer,
|
||||||
jbyteArray input, jint inputOffset, jint inputLength,
|
jbyteArray input, jint inputOffset, jint inputLength,
|
||||||
jbyteArray output, jint outputOffset, jint outputLength,
|
jbyteArray output, jint outputOffset, jint outputLength,
|
||||||
jintArray results)
|
jboolean finish, jintArray results)
|
||||||
{
|
{
|
||||||
z_stream* s = reinterpret_cast<z_stream*>(peer);
|
z_stream* s = reinterpret_cast<z_stream*>(peer);
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ Java_java_util_zip_Deflater_deflate
|
|||||||
s->next_out = reinterpret_cast<Bytef*>(out);
|
s->next_out = reinterpret_cast<Bytef*>(out);
|
||||||
s->avail_out = outputLength;
|
s->avail_out = outputLength;
|
||||||
|
|
||||||
int r = deflate(s, Z_SYNC_FLUSH);
|
int r = deflate(s, finish ? Z_FINISH : Z_NO_FLUSH);
|
||||||
jint resultArray[3]
|
jint resultArray[3]
|
||||||
= { r, inputLength - s->avail_in, outputLength - s->avail_out };
|
= { r, inputLength - s->avail_in, outputLength - s->avail_out };
|
||||||
|
|
||||||
|
@ -27,14 +27,19 @@ public class Deflater {
|
|||||||
private boolean needDictionary;
|
private boolean needDictionary;
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
private final boolean nowrap;
|
private final boolean nowrap;
|
||||||
|
private boolean finish;
|
||||||
|
|
||||||
public Deflater(boolean nowrap) {
|
public Deflater(int level, boolean nowrap) {
|
||||||
this.nowrap = nowrap;
|
this.nowrap = nowrap;
|
||||||
peer = make(nowrap, DEFAULT_LEVEL);
|
peer = make(nowrap, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Deflater(int level) {
|
||||||
|
this(level, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Deflater() {
|
public Deflater() {
|
||||||
this(false);
|
this(DEFAULT_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void check() {
|
private void check() {
|
||||||
@ -85,16 +90,15 @@ public class Deflater {
|
|||||||
peer = make(nowrap, DEFAULT_LEVEL);
|
peer = make(nowrap, DEFAULT_LEVEL);
|
||||||
input = null;
|
input = null;
|
||||||
offset = length = 0;
|
offset = length = 0;
|
||||||
|
finish = false;
|
||||||
needDictionary = finished = false;
|
needDictionary = finished = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int deflate(byte[] output) throws DataFormatException {
|
public int deflate(byte[] output) {
|
||||||
return deflate(output, 0, output.length);
|
return deflate(output, 0, output.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int deflate(byte[] output, int offset, int length)
|
public int deflate(byte[] output, int offset, int length) {
|
||||||
throws DataFormatException
|
|
||||||
{
|
|
||||||
final int zlibResult = 0;
|
final int zlibResult = 0;
|
||||||
final int inputCount = 1;
|
final int inputCount = 1;
|
||||||
final int outputCount = 2;
|
final int outputCount = 2;
|
||||||
@ -110,10 +114,10 @@ public class Deflater {
|
|||||||
int[] results = new int[3];
|
int[] results = new int[3];
|
||||||
deflate(peer,
|
deflate(peer,
|
||||||
input, this.offset, this.length,
|
input, this.offset, this.length,
|
||||||
output, offset, length, results);
|
output, offset, length, finish, results);
|
||||||
|
|
||||||
if (results[zlibResult] < 0) {
|
if (results[zlibResult] < 0) {
|
||||||
throw new DataFormatException();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (results[zlibResult]) {
|
switch (results[zlibResult]) {
|
||||||
@ -132,10 +136,15 @@ public class Deflater {
|
|||||||
return results[outputCount];
|
return results[outputCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
finish = true;
|
||||||
|
}
|
||||||
|
|
||||||
private static native void deflate
|
private static native void deflate
|
||||||
(long peer,
|
(long peer,
|
||||||
byte[] input, int inputOffset, int inputLength,
|
byte[] input, int inputOffset, int inputLength,
|
||||||
byte[] output, int outputOffset, int outputLength,
|
byte[] output, int outputOffset, int outputLength,
|
||||||
|
boolean finish,
|
||||||
int[] results);
|
int[] results);
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
@ -52,23 +52,25 @@ public class DeflaterOutputStream extends OutputStream {
|
|||||||
} else if (length == 0) {
|
} else if (length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < length; i+= buffer.length) {
|
deflater.setInput(b, offset, length);
|
||||||
deflater.setInput(b, offset + i, Math.min(buffer.length, length - i));
|
while (deflater.getRemaining() > 0) {
|
||||||
while (deflater.getRemaining() > 0) {
|
deflate();
|
||||||
try {
|
}
|
||||||
int len = deflater.deflate(buffer, 0, buffer.length);
|
}
|
||||||
if (len > 0) {
|
|
||||||
out.write(buffer, 0, len);
|
private void deflate() throws IOException {
|
||||||
}
|
int len = deflater.deflate(buffer, 0, buffer.length);
|
||||||
} catch (DataFormatException e) {
|
if (len > 0) {
|
||||||
e.printStackTrace();
|
out.write(buffer, 0, len);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
deflater.finish();
|
||||||
|
while (! deflater.finished()) {
|
||||||
|
deflate();
|
||||||
|
}
|
||||||
out.close();
|
out.close();
|
||||||
deflater.dispose();
|
deflater.dispose();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user