DeflaterOutputStream should output all available compressed data

In both the write and flush we were looping writing data from the
Deflater to the OutputStream until we needsInput was true. However, we
should have simply been looping until there were no bytes returned.

Bug: 4005091
Change-Id: I995ef0eeb3d3c500144f33456b5b2d15d374efcb
diff --git a/luni/src/main/java/java/util/zip/DeflaterOutputStream.java b/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
index 7cb47db..e49633f 100644
--- a/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
+++ b/luni/src/main/java/java/util/zip/DeflaterOutputStream.java
@@ -132,11 +132,10 @@
      *             If an error occurs during deflation.
      */
     protected void deflate() throws IOException {
-        int x = 0;
-        do {
-            x = def.deflate(buf);
-            out.write(buf, 0, x);
-        } while (!def.needsInput());
+        int byteCount;
+        while ((byteCount = def.deflate(buf)) != 0) {
+            out.write(buf, 0, byteCount);
+        }
     }
 
     /**
@@ -169,13 +168,12 @@
             return;
         }
         def.finish();
-        int x = 0;
         while (!def.finished()) {
             if (def.needsInput()) {
                 def.setInput(buf, 0, 0);
             }
-            x = def.deflate(buf);
-            out.write(buf, 0, x);
+            int byteCount = def.deflate(buf);
+            out.write(buf, 0, byteCount);
         }
         done = true;
     }
@@ -229,8 +227,10 @@
      */
     @Override public void flush() throws IOException {
         if (syncFlush) {
-            int count = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH);
-            out.write(buf, 0, count);
+            int byteCount;
+            while ((byteCount = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) != 0) {
+                out.write(buf, 0, byteCount);
+            }
         }
         out.flush();
     }
diff --git a/luni/src/test/java/libcore/java/util/zip/DeflaterOutputStreamTest.java b/luni/src/test/java/libcore/java/util/zip/DeflaterOutputStreamTest.java
index 55144ed..c8d6283 100644
--- a/luni/src/test/java/libcore/java/util/zip/DeflaterOutputStreamTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/DeflaterOutputStreamTest.java
@@ -16,13 +16,18 @@
 
 package libcore.java.util.zip;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
+import java.lang.reflect.Field;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.zip.Deflater;
 import java.util.zip.DeflaterOutputStream;
 import java.util.zip.InflaterInputStream;
 import junit.framework.TestCase;
@@ -34,6 +39,7 @@
         assertEquals(1, in.read());
         assertEquals(2, in.read());
         assertEquals(3, in.read());
+        in.close();
     }
 
     public void testSyncFlushDisabled() throws Exception {
@@ -43,6 +49,7 @@
             fail();
         } catch (IOException expected) {
         }
+        in.close();
     }
 
     /**
@@ -77,4 +84,56 @@
 
         return new InflaterInputStream(pin);
     }
+
+    /**
+     * Confirm that a DeflaterOutputStream constructed with Deflater
+     * with flushParm == SYNC_FLUSH does not need to to be flushed.
+     *
+     * http://4005091
+     */
+    public void testSyncFlushDeflater() throws Exception {
+        Deflater def = new Deflater();
+        Field f = def.getClass().getDeclaredField("flushParm");
+        f.setAccessible(true);
+        f.setInt(def, Deflater.SYNC_FLUSH);
+
+        final int deflaterBufferSize = 512;
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DeflaterOutputStream dos = new DeflaterOutputStream(baos, def, deflaterBufferSize);
+
+        // make output buffer large enough that even if compressed it
+        // won't all fit within the deflaterBufferSize.
+        final int outputBufferSize = 128 * deflaterBufferSize;
+        byte[] output = new byte[outputBufferSize];
+        for (int i = 0; i < output.length; i++) {
+            output[i] = (byte) i;
+        }
+
+        dos.write(output);
+        byte[] compressed = baos.toByteArray();
+        assertTrue("compressed=" + compressed.length
+                   + " but deflaterBufferSize=" + deflaterBufferSize,
+                   compressed.length > deflaterBufferSize);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(compressed);
+        InflaterInputStream iis = new InflaterInputStream(bais);
+        byte[] input = new byte[output.length];
+        int total = 0;
+        while (true)  {
+            int n = iis.read(input, total, input.length - total);
+            if (n == -1) {
+                break;
+            }
+            total += n;
+            if (total == input.length) {
+                try {
+                    iis.read();
+                    fail();
+                } catch (EOFException expected) {
+                    break;
+                }
+            }
+        }
+        assertEquals(output.length, total);
+    }
 }