diff --git a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java index 3fca6a1b759..85ba968dc9b 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java @@ -57,6 +57,26 @@ import java.io.IOException; * @since 1.1 */ public class DeflaterOutputStream extends FilterOutputStream { + + /* + * The default size of the output buffer + */ + static final int DEFAULT_BUF_SIZE = 512; + + /* + * When calling Deflater.deflate() with Deflater.SYNC_FLUSH or Deflater.FULL_FLUSH, + * the callers are expected to ensure that the size of the buffer is greater than 6. + * This expectation comes from the underlying zlib library which in its zlib.h + * states: + * "If deflate returns with avail_out == 0, this function must be called again + * with the same value of the flush parameter and more output space (updated + * avail_out), until the flush is complete (deflate returns with non-zero + * avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + * avail_out is greater than six when the flush marker begins, in order to avoid + * repeated flush markers upon calling deflate() again when avail_out == 0." + */ + private static final int SYNC_FLUSH_MIN_BUF_SIZE = 7; + /** * Compressor for this stream. */ @@ -152,7 +172,7 @@ public class DeflaterOutputStream extends FilterOutputStream { public DeflaterOutputStream(OutputStream out, Deflater def, boolean syncFlush) { - this(out, def, 512, syncFlush); + this(out, def, DEFAULT_BUF_SIZE, syncFlush); } @@ -171,7 +191,7 @@ public class DeflaterOutputStream extends FilterOutputStream { * @param def the compressor ("deflater") */ public DeflaterOutputStream(OutputStream out, Deflater def) { - this(out, def, 512, false); + this(out, def, DEFAULT_BUF_SIZE, false); } boolean usesDefaultDeflater = false; @@ -195,7 +215,7 @@ public class DeflaterOutputStream extends FilterOutputStream { * @since 1.7 */ public DeflaterOutputStream(OutputStream out, boolean syncFlush) { - this(out, out != null ? new Deflater() : null, 512, syncFlush); + this(out, out != null ? new Deflater() : null, DEFAULT_BUF_SIZE, syncFlush); usesDefaultDeflater = true; } @@ -342,10 +362,16 @@ public class DeflaterOutputStream extends FilterOutputStream { public void flush() throws IOException { if (syncFlush && !def.finished()) { int len = 0; - while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0) - { - out.write(buf, 0, len); - if (len < buf.length) + // For SYNC_FLUSH, the Deflater.deflate() expects the callers + // to use a buffer whose length is greater than 6 to avoid + // flush marker (5 bytes) being repeatedly output to the output buffer + // every time it is invoked. + final byte[] flushBuf = buf.length < SYNC_FLUSH_MIN_BUF_SIZE + ? new byte[DEFAULT_BUF_SIZE] + : buf; + while ((len = def.deflate(flushBuf, 0, flushBuf.length, Deflater.SYNC_FLUSH)) > 0) { + out.write(flushBuf, 0, len); + if (len < flushBuf.length) break; } } diff --git a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java index cea0880fca6..12abd53350f 100644 --- a/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/GZIPOutputStream.java @@ -113,7 +113,7 @@ public class GZIPOutputStream extends DeflaterOutputStream { * @throws IOException If an I/O error has occurred. */ public GZIPOutputStream(OutputStream out) throws IOException { - this(out, 512, false); + this(out, DeflaterOutputStream.DEFAULT_BUF_SIZE, false); } /** @@ -135,7 +135,7 @@ public class GZIPOutputStream extends DeflaterOutputStream { public GZIPOutputStream(OutputStream out, boolean syncFlush) throws IOException { - this(out, 512, syncFlush); + this(out, DeflaterOutputStream.DEFAULT_BUF_SIZE, syncFlush); } /**