4813885: RFE: GZIPOutputStream should implement flush using Z_SYNC_FLUSH
authorsherman
Mon, 17 May 2010 12:19:49 -0700
changeset 5607 f01eda72e178
parent 5606 63aa4b61c0a8
child 5608 6771207f52b4
4813885: RFE: GZIPOutputStream should implement flush using Z_SYNC_FLUSH Summary: Added new constructors to allow flush() work in Z_SYNC_FLUSH mode Reviewed-by: martin
jdk/src/share/classes/java/util/zip/GZIPOutputStream.java
jdk/test/java/util/zip/InflateIn_DeflateOut.java
--- a/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java	Sun May 16 21:22:07 2010 -0700
+++ b/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java	Mon May 17 12:19:49 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,25 +54,82 @@
 
     /**
      * Creates a new output stream with the specified buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor GZIPOutputStream(out, size, false).
+     *
      * @param out the output stream
      * @param size the output buffer size
      * @exception IOException If an I/O error has occurred.
      * @exception IllegalArgumentException if size is <= 0
+
      */
     public GZIPOutputStream(OutputStream out, int size) throws IOException {
-        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
+        this(out, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified buffer size and
+     * flush mode.
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     * @exception IOException If an I/O error has occurred.
+     * @exception IllegalArgumentException if size is <= 0
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, int size, boolean syncFlush)
+        throws IOException
+    {
+        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true),
+              size,
+              syncFlush);
         usesDefaultDeflater = true;
         writeHeader();
         crc.reset();
     }
 
+
     /**
      * Creates a new output stream with a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor GZIPOutputStream(out, false).
+     *
      * @param out the output stream
      * @exception IOException If an I/O error has occurred.
      */
     public GZIPOutputStream(OutputStream out) throws IOException {
-        this(out, 512);
+        this(out, 512, false);
+    }
+
+    /**
+     * Creates a new output stream with a default buffer size and
+     * the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @exception IOException If an I/O error has occurred.
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, boolean syncFlush)
+        throws IOException
+    {
+        this(out, 512, syncFlush);
     }
 
     /**
--- a/jdk/test/java/util/zip/InflateIn_DeflateOut.java	Sun May 16 21:22:07 2010 -0700
+++ b/jdk/test/java/util/zip/InflateIn_DeflateOut.java	Mon May 17 12:19:49 2010 -0700
@@ -23,8 +23,8 @@
 
 /**
  * @test
- * @bug 4206909
- * @summary Test basic functionality of DeflaterOutputStream and InflaterInputStream including flush
+ * @bug 4206909 4813885
+ * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream and GZIPOutputStream/GZIPInputStream, including flush
  */
 
 import java.io.*;
@@ -79,23 +79,23 @@
     }
 
     private static class PairedOutputStream extends ByteArrayOutputStream {
-      private PairedInputStream pairedStream = null;
+        private PairedInputStream pairedStream = null;
 
-      public PairedOutputStream(PairedInputStream inputPair) {
-        super();
-        this.pairedStream = inputPair;
-      }
+        public PairedOutputStream(PairedInputStream inputPair) {
+            super();
+            this.pairedStream = inputPair;
+        }
 
-      public void flush() {
-        if (count > 0) {
-          pairedStream.addBytes(buf, count);
-          reset();
+        public void flush() {
+            if (count > 0) {
+                pairedStream.addBytes(buf, count);
+                reset();
+            }
         }
-      }
 
-      public void close() {
-        flush();
-      }
+        public void close() {
+            flush();
+        }
     }
 
     private static boolean readFully(InputStream in, byte[] buf, int length)
@@ -146,27 +146,20 @@
         check(Arrays.equals(data, buf));
     }
 
-    /** Check that written, flushed and read */
-    private static void WriteFlushRead() throws Throwable {
+    private static void check(InputStream is, OutputStream os)
+        throws Throwable
+    {
         Random random = new Random(new Date().getTime());
-
-        PairedInputStream pis = new PairedInputStream();
-        InflaterInputStream iis = new InflaterInputStream(pis);
-
-        PairedOutputStream pos = new PairedOutputStream(pis);
-        pis.setPairedOutputStream(pos);
-        DeflaterOutputStream dos = new DeflaterOutputStream(pos, true);
-
-        // Large writes
+       // Large writes
         for (int x = 0; x < 200 ; x++) {
             // byte[] data = new byte[random.nextInt(1024 * 1024)];
             byte[] data = new byte[1024];
             byte[] buf = new byte[data.length];
             random.nextBytes(data);
 
-            dos.write(data);
-            dos.flush();
-            check(readFully(iis, buf, buf.length));
+            os.write(data);
+            os.flush();
+            check(readFully(is, buf, buf.length));
             check(Arrays.equals(data, buf));
         }
 
@@ -176,9 +169,9 @@
             byte[] buf = new byte[data.length];
             random.nextBytes(data);
 
-            dos.write(data);
-            dos.flush();
-            if (!readFully(iis, buf, buf.length)) {
+            os.write(data);
+            os.flush();
+            if (!readFully(is, buf, buf.length)) {
                 fail("Didn't read full buffer of " + buf.length);
             }
             check(Arrays.equals(data, buf));
@@ -187,14 +180,62 @@
         String quit = "QUIT\r\n";
 
         // Close it out
-        dos.write(quit.getBytes());
-        dos.close();
+        os.write(quit.getBytes());
+        os.close();
 
         StringBuilder sb = new StringBuilder();
-        check(readLineIfAvailable(iis, sb));
+        check(readLineIfAvailable(is, sb));
         equal(sb.toString(), quit);
     }
 
+    /** Check that written, flushed and read */
+    private static void WriteFlushRead() throws Throwable {
+        PairedInputStream pis = new PairedInputStream();
+        InflaterInputStream iis = new InflaterInputStream(pis);
+
+        PairedOutputStream pos = new PairedOutputStream(pis);
+        pis.setPairedOutputStream(pos);
+        DeflaterOutputStream dos = new DeflaterOutputStream(pos, true);
+
+        check(iis, dos);
+    }
+
+    private static void GZWriteFlushRead() throws Throwable {
+        PairedInputStream pis = new PairedInputStream();
+        PairedOutputStream pos = new PairedOutputStream(pis);
+        pis.setPairedOutputStream(pos);
+
+        GZIPOutputStream gos = new GZIPOutputStream(pos, true);
+        gos.flush();  // flush the head out, so gis can read
+        GZIPInputStream gis = new GZIPInputStream(pis);
+
+        check(gis, gos);
+    }
+
+    private static void checkLOP(InputStream is, OutputStream os)
+        throws Throwable
+    {
+        boolean flushed = false;
+        int count = 0;
+
+        // Do at least a certain number of lines, but too many without a
+        // flush means this test isn't testing anything
+        while ((count < 10 && flushed) || (count < 1000 && !flushed)) {
+            String command = "PING " + count + "\r\n";
+            os.write(command.getBytes());
+
+            StringBuilder buf = new StringBuilder();
+            if (!readLineIfAvailable(is, buf)) {
+                flushed = true;
+                os.flush();
+                check(readLineIfAvailable(is, buf));
+            }
+            equal(buf.toString(), command);
+            count++;
+        }
+        check(flushed);
+    }
+
     /** Validate that we need to use flush at least once on a line
      * oriented protocol */
     private static void LineOrientedProtocol() throws Throwable {
@@ -205,33 +246,27 @@
         pis.setPairedOutputStream(pos);
         DeflaterOutputStream dos = new DeflaterOutputStream(pos, true);
 
-        boolean flushed = false;
-        int count = 0;
-
-        // Do at least a certain number of lines, but too many without a
-        // flush means this test isn't testing anything
-        while ((count < 10 && flushed) || (count < 1000 && !flushed)) {
-            String command = "PING " + count + "\r\n";
-            dos.write(command.getBytes());
+        checkLOP(iis, dos);
+    }
 
-            StringBuilder buf = new StringBuilder();
-            if (!readLineIfAvailable(iis, buf)) {
-                flushed = true;
-                dos.flush();
-                check(readLineIfAvailable(iis, buf));
-            }
-            equal(buf.toString(), command);
-            count++;
-        }
-        check(flushed);
+    private static void GZLineOrientedProtocol() throws Throwable {
+        PairedInputStream pis = new PairedInputStream();
+        PairedOutputStream pos = new PairedOutputStream(pis);
+        pis.setPairedOutputStream(pos);
+
+        GZIPOutputStream gos = new GZIPOutputStream(pos, true);
+        gos.flush();  // flush the head out, so gis can read
+        GZIPInputStream gis = new GZIPInputStream(pis);
+
+        checkLOP(gis, gos);
     }
 
     public static void realMain(String[] args) throws Throwable {
         WriteCloseRead();
-
         WriteFlushRead();
-
         LineOrientedProtocol();
+        GZWriteFlushRead();
+        GZLineOrientedProtocol();
     }
 
     //--------------------- Infrastructure ---------------------------