< prev index next >

test/java/util/zip/InflateIn_DeflateOut.java

Print this page

        

@@ -21,11 +21,11 @@
  * questions.
  */
 
 /**
  * @test
- * @bug 4206909 4813885
+ * @bug 4206909 4813885 8189789
  * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream and GZIPOutputStream/GZIPInputStream, including flush
  */
 
 import java.io.*;
 import java.util.*;

@@ -144,10 +144,51 @@
         }
         check(readFully(iis, buf, buf.length));
         check(Arrays.equals(data, buf));
     }
 
+    private static void TestFlushableGZIPOutputStream() throws Throwable {
+        Random random = new Random(new Date().getTime());
+
+        ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
+        OutputStream output = new FlushableGZIPOutputStream(byteOutStream);
+
+        byte[] data = new byte[random.nextInt(1024 * 1024)];
+        byte[] buf = new byte[data.length];
+        random.nextBytes(data);
+
+        output.write(data);
+        for (int i=0; i<data.length; i++) {
+            output.write(data[i]);
+        }
+        output.flush();
+        for (int i=0; i<data.length; i++) {
+            output.write(data[i]);
+        }
+        output.write(data);
+        output.close();
+
+        ByteArrayInputStream byteInStream =
+                new ByteArrayInputStream(byteOutStream.toByteArray());
+
+        GZIPInputStream gzis = new GZIPInputStream(byteInStream);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int numRead;
+        byte[] b = new byte[4 * 1024];
+        try {
+            while ((numRead = gzis.read(buf)) >= 0) {
+                baos.write(b, 0, numRead);
+            } 
+        } finally {
+            baos.close();
+        }
+
+        byte[] decompressedBytes = baos.toByteArray();
+
+        check(decompressedBytes.length == data.length * 4);
+    }
+
     private static void check(InputStream is, OutputStream os)
         throws Throwable
     {
         Random random = new Random(new Date().getTime());
        // Large writes

@@ -265,10 +306,11 @@
         WriteCloseRead();
         WriteFlushRead();
         LineOrientedProtocol();
         GZWriteFlushRead();
         GZLineOrientedProtocol();
+        TestFlushableGZIPOutputStream();
     }
 
     //--------------------- Infrastructure ---------------------------
     static volatile int passed = 0, failed = 0;
     static void pass() {passed++;}

@@ -281,6 +323,83 @@
         else fail(x + " not equal to " + y);}
     public static void main(String[] args) throws Throwable {
         try {realMain(args);} catch (Throwable t) {unexpected(t);}
         System.out.println("\nPassed = " + passed + " failed = " + failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
+}
+
+class FlushableGZIPOutputStream extends GZIPOutputStream {
+    public FlushableGZIPOutputStream(OutputStream os) throws IOException {
+        super(os);
+    }
+
+    private static final byte[] EMPTYBYTEARRAY = new byte[0];
+    private boolean hasData = false;
+
+    /**
+     * Here we make sure we have received data, so that the header has been for
+     * sure written to the output stream already.
+     */
+    @Override
+    public synchronized void write(byte[] bytes, int i, int i1)
+            throws IOException {
+        super.write(bytes, i, i1);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void write(int i) throws IOException {
+        super.write(i);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void write(byte[] bytes) throws IOException {
+        super.write(bytes);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void flush() throws IOException {
+        if (!hasData) {
+            return; // do not allow the gzip header to be flushed on its own
+        }
+
+        // trick the deflater to flush
+        /**
+         * 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
+         */
+        if (!def.finished()) {
+            def.setInput(EMPTYBYTEARRAY, 0, 0);
+
+            def.setLevel(Deflater.NO_COMPRESSION);
+            deflate();
+
+            def.setLevel(Deflater.DEFAULT_COMPRESSION);
+            deflate();
+
+            out.flush();
+        }
+
+        hasData = false; // no more data to flush
+    }
+
+    /*
+     * Keep on calling deflate until it runs dry. The default implementation
+     * only does it once and can therefore hold onto data when they need to be
+     * flushed out.
+     */
+    @Override
+    protected void deflate() throws IOException {
+        int len;
+        do {
+            len = def.deflate(buf, 0, buf.length);
+            if (len > 0) {
+                out.write(buf, 0, len);
+            }
+        } while (len != 0);
+    }
+
 }
< prev index next >