COMPRESS-380 Deflate64CompressorInputStream#available promised too much

Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/07cc1a27
Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/07cc1a27
Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/07cc1a27

Branch: refs/heads/master
Commit: 07cc1a278b217d45cb090ff6cb3a7934105cb2d0
Parents: 79e76d5
Author: Stefan Bodewig <bode...@apache.org>
Authored: Thu Jan 4 16:51:20 2018 +0100
Committer: Stefan Bodewig <bode...@apache.org>
Committed: Thu Jan 4 16:51:20 2018 +0100

----------------------------------------------------------------------
 .../commons/compress/archivers/zip/ZipFile.java |  2 +-
 .../Deflate64CompressorInputStream.java         | 21 ++------
 .../compressors/deflate64/HuffmanDecoder.java   | 20 +++++++
 .../commons/compress/utils/BitInputStream.java  | 10 ++++
 .../Deflate64CompressorInputStreamTest.java     | 56 ++++++++------------
 5 files changed, 58 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-compress/blob/07cc1a27/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java 
b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
index c661eeb..f77339b 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
@@ -504,7 +504,7 @@ public class ZipFile implements Closeable {
             case BZIP2:
                 return new BZip2CompressorInputStream(bis);
             case ENHANCED_DEFLATED:
-                return new Deflate64CompressorInputStream(bis, ze.getSize());
+                return new Deflate64CompressorInputStream(bis);
             case AES_ENCRYPTED:
             case EXPANDING_LEVEL_1:
             case EXPANDING_LEVEL_2:

http://git-wip-us.apache.org/repos/asf/commons-compress/blob/07cc1a27/src/main/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java
 
b/src/main/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java
index c097ab3..e909f13 100644
--- 
a/src/main/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java
+++ 
b/src/main/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStream.java
@@ -30,21 +30,17 @@ import static 
org.apache.commons.compress.utils.IOUtils.closeQuietly;
  */
 public class Deflate64CompressorInputStream extends CompressorInputStream {
     private HuffmanDecoder decoder;
-    private long uncompressedSize;
-    private long totalRead = 0;
 
     /**
      * Constructs a Deflate64CompressorInputStream.
      *
      * @param in the stream to read from
-     * @param uncompressedSize the uncompressed size of the data to be read 
from in
      */
-    public Deflate64CompressorInputStream(InputStream in, long 
uncompressedSize) {
-        this(new HuffmanDecoder(in), uncompressedSize);
+    public Deflate64CompressorInputStream(InputStream in) {
+        this(new HuffmanDecoder(in));
     }
 
-    Deflate64CompressorInputStream(HuffmanDecoder decoder, long 
uncompressedSize) {
-        this.uncompressedSize = uncompressedSize;
+    Deflate64CompressorInputStream(HuffmanDecoder decoder) {
         this.decoder = decoder;
     }
 
@@ -74,8 +70,6 @@ public class Deflate64CompressorInputStream extends 
CompressorInputStream {
             count(read);
             if (read == -1) {
                 close();
-            } else {
-                totalRead += read;
             }
         }
         return read;
@@ -83,14 +77,7 @@ public class Deflate64CompressorInputStream extends 
CompressorInputStream {
 
     @Override
     public int available() throws IOException {
-        long available = 0;
-        if (decoder != null) {
-            available = uncompressedSize - totalRead;
-            if (Long.compare(available, Integer.MAX_VALUE) > 0) {
-                available = Integer.MAX_VALUE;
-            }
-        }
-        return (int) available;
+        return decoder != null ? decoder.available() : 0;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/commons-compress/blob/07cc1a27/src/main/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java
 
b/src/main/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java
index de909db..3a41613 100644
--- 
a/src/main/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java
+++ 
b/src/main/java/org/apache/commons/compress/compressors/deflate64/HuffmanDecoder.java
@@ -168,6 +168,9 @@ class HuffmanDecoder implements Closeable {
         return -1;
     }
 
+    int available() throws IOException {
+        return state == null ? 0 : state.available();
+    }
 
     private static abstract class DecoderState {
         abstract HuffmanState state();
@@ -175,6 +178,8 @@ class HuffmanDecoder implements Closeable {
         abstract int read(byte[] b, int off, int len) throws IOException;
 
         abstract boolean hasData();
+
+        abstract int available() throws IOException ;
     }
 
     private class UncompressedState extends DecoderState {
@@ -205,6 +210,11 @@ class HuffmanDecoder implements Closeable {
         boolean hasData() {
             return read < blockLength;
         }
+
+        @Override
+        int available() throws IOException {
+            return (int) Math.min(blockLength - read, reader.bitsAvailable() / 
Byte.SIZE);
+        }
     }
 
     private class InitialState extends DecoderState {
@@ -222,6 +232,11 @@ class HuffmanDecoder implements Closeable {
         boolean hasData() {
             return false;
         }
+
+        @Override
+        int available() {
+            return 0;
+        }
     }
 
     private class HuffmanCodes extends DecoderState {
@@ -301,6 +316,11 @@ class HuffmanDecoder implements Closeable {
         boolean hasData() {
             return !endOfBlock;
         }
+
+        @Override
+        int available() {
+            return runBuffer.length - runBufferPos;
+        }
     }
 
     private static int nextSymbol(BitInputStream reader, BinaryTreeNode tree) 
throws IOException {

http://git-wip-us.apache.org/repos/asf/commons-compress/blob/07cc1a27/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/compress/utils/BitInputStream.java 
b/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
index 45d30ec..f4beaae 100644
--- a/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
+++ b/src/main/java/org/apache/commons/compress/utils/BitInputStream.java
@@ -100,6 +100,16 @@ public class BitInputStream implements Closeable {
         return bitsOut;
     }
 
+    /**
+     * Returns an estimate of the number of bits that can be read from
+     * this input stream without blocking by the next invocation of a
+     * method for this input stream.
+     * @since 1.16
+     */
+    public long bitsAvailable() throws IOException {
+        return bitsCachedSize + 8l * in.available();
+    }
+
     private long processBitsGreater57(final int count) throws IOException {
         final long bitsOut;
         int overflowBits = 0;

http://git-wip-us.apache.org/repos/asf/commons-compress/blob/07cc1a27/src/test/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStreamTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStreamTest.java
 
b/src/test/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStreamTest.java
index 92e7b90..1e32b42 100644
--- 
a/src/test/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStreamTest.java
+++ 
b/src/test/java/org/apache/commons/compress/compressors/deflate64/Deflate64CompressorInputStreamTest.java
@@ -40,8 +40,7 @@ public class Deflate64CompressorInputStreamTest {
    @Test
    public void readWhenClosed() throws Exception
    {
-      long size = Integer.MAX_VALUE - 1;
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(nullDecoder, size);
+      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(nullDecoder);
       assertEquals(-1, input.read());
       assertEquals(-1, input.read(new byte[1]));
       assertEquals(-1, input.read(new byte[1], 0, 1));
@@ -50,47 +49,24 @@ public class Deflate64CompressorInputStreamTest {
    @Test
    public void properSizeWhenClosed() throws Exception
    {
-      long size = Integer.MAX_VALUE - 1;
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(nullDecoder, size);
+      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(nullDecoder);
       assertEquals(0, input.available());
    }
 
    @Test
-   public void properSizeWhenInRange() throws Exception
+   public void delegatesAvailable() throws Exception
    {
-      long size = Integer.MAX_VALUE - 1;
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder, size);
-      assertEquals(size, input.available());
-   }
-
-   @Test
-   public void properSizeWhenOutOfRange() throws Exception
-   {
-      long size = Integer.MAX_VALUE + 1L;
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder, size);
-      assertEquals(Integer.MAX_VALUE, input.available());
-   }
+      Mockito.when(decoder.available()).thenReturn(1024);
 
-   @Test
-   public void properSizeAfterReading() throws Exception
-   {
-      byte[] buf = new byte[4096];
-      int offset = 1000;
-      int length = 3096;
-
-      Mockito.when(decoder.decode(buf, offset, length)).thenReturn(2048);
-
-      long size = Integer.MAX_VALUE + 2047L;
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder, size);
-      assertEquals(2048, input.read(buf, offset, length));
-      assertEquals(Integer.MAX_VALUE - 1, input.available());
+      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder);
+      assertEquals(1024, input.available());
    }
 
    @Test
    public void closeCallsDecoder() throws Exception
    {
 
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder, 10);
+      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder);
       input.close();
 
       Mockito.verify(decoder, times(1)).close();
@@ -100,7 +76,7 @@ public class Deflate64CompressorInputStreamTest {
    public void closeIsDelegatedJustOnce() throws Exception
    {
 
-      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder, 10);
+      Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(decoder);
 
       input.close();
       input.close();
@@ -116,7 +92,7 @@ public class Deflate64CompressorInputStreamTest {
          'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'
       };
 
-      try (Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(new ByteArrayInputStream(data), 11);
+      try (Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(new ByteArrayInputStream(data));
            BufferedReader br = new BufferedReader(new 
InputStreamReader(input)))
       {
          assertEquals("Hello World", br.readLine());
@@ -124,4 +100,18 @@ public class Deflate64CompressorInputStreamTest {
       }
    }
 
+   @Test
+   public void uncompressedBlockAvailable() throws Exception
+   {
+      byte[] data = {
+         1, 11, 0, -12, -1,
+         'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'
+      };
+
+      try (Deflate64CompressorInputStream input = new 
Deflate64CompressorInputStream(new ByteArrayInputStream(data))) {
+          assertEquals('H', input.read());
+          assertEquals(10, input.available());
+      }
+   }
+
 }

Reply via email to