Repository: commons-compress
Updated Branches:
  refs/heads/master 3baf454c2 -> 1d66f1208


Working version of deferred block decompression for skipped entries.


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

Branch: refs/heads/master
Commit: a53ab172b2a9b7c1a57be9f8d6dc82977af02bff
Parents: deb891f
Author: Dawid Weiss <dawid.we...@carrotsearch.com>
Authored: Tue Feb 23 16:19:25 2016 +0100
Committer: Stefan Bodewig <bode...@apache.org>
Committed: Wed Feb 24 15:42:19 2016 +0100

----------------------------------------------------------------------
 .../compress/archivers/sevenz/SevenZFile.java   | 72 +++++++++++---------
 1 file changed, 41 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-compress/blob/a53ab172/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java 
b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
index 90bda16..60ffea8 100644
--- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
+++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java
@@ -26,6 +26,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.RandomAccessFile;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.LinkedList;
@@ -74,9 +75,10 @@ public class SevenZFile implements Closeable {
     private int currentEntryIndex = -1;
     private int currentFolderIndex = -1;
     private InputStream currentFolderInputStream = null;
-    private InputStream currentEntryInputStream = null;
     private byte[] password;
-        
+
+    private ArrayList<InputStream> deferredBlockStreams = new 
ArrayList<InputStream>();
+
     static final byte[] sevenZSignature = {
         (byte)'7', (byte)'z', (byte)0xBC, (byte)0xAF, (byte)0x27, (byte)0x1C
     };
@@ -809,17 +811,25 @@ public class SevenZFile implements Closeable {
     private void buildDecodingStream() throws IOException {
         final int folderIndex = 
archive.streamMap.fileFolderIndex[currentEntryIndex];
         if (folderIndex < 0) {
-            currentEntryInputStream = new BoundedInputStream(
-                    new ByteArrayInputStream(new byte[0]), 0);
+               deferredBlockStreams.clear();
+            // TODO: previously it'd return an empty stream?
+               // new BoundedInputStream(new ByteArrayInputStream(new 
byte[0]), 0);
             return;
         }
         final SevenZArchiveEntry file = archive.files[currentEntryIndex];
         if (currentFolderIndex == folderIndex) {
+               // (COMPRESS-320).
+               // The current entry is within the same (potentially opened) 
folder. The
+               // previous stream has to be fully decoded before we can start 
reading
+               // but don't do it eagerly -- if the user skips over the entire 
folder nothing
+               // is effectively decompressed.
+
             // need to advance the folder input stream past the current file
-            drainPreviousEntry();
             file.setContentMethods(archive.files[currentEntryIndex - 
1].getContentMethods());
         } else {
+               // We're opening a new folder. Discard any queued streams/ 
folder stream.
             currentFolderIndex = folderIndex;
+               deferredBlockStreams.clear();
             if (currentFolderInputStream != null) {
                 currentFolderInputStream.close();
                 currentFolderInputStream = null;
@@ -831,26 +841,15 @@ public class SevenZFile implements Closeable {
                     archive.streamMap.packStreamOffsets[firstPackStreamIndex];
             currentFolderInputStream = buildDecoderStack(folder, folderOffset, 
firstPackStreamIndex, file);
         }
-        final InputStream fileStream = new BoundedInputStream(
-                currentFolderInputStream, file.getSize());
+
+        InputStream fileStream = new 
BoundedInputStream(currentFolderInputStream, file.getSize());
         if (file.getHasCrc()) {
-            currentEntryInputStream = new CRC32VerifyingInputStream(
-                    fileStream, file.getSize(), file.getCrcValue());
-        } else {
-            currentEntryInputStream = fileStream;
+            fileStream = new CRC32VerifyingInputStream(fileStream, 
file.getSize(), file.getCrcValue());
         }
         
+        deferredBlockStreams.add(fileStream);
     }
-    
-    private void drainPreviousEntry() throws IOException {
-        if (currentEntryInputStream != null) {
-            // return value ignored as IOUtils.skip ensures the stream is 
drained completely
-            IOUtils.skip(currentEntryInputStream, Long.MAX_VALUE);
-            currentEntryInputStream.close();
-            currentEntryInputStream = null;
-        }
-    }
-    
+
     private InputStream buildDecoderStack(final Folder folder, final long 
folderOffset,
                 final int firstPackStreamIndex, SevenZArchiveEntry entry) 
throws IOException {
         file.seek(folderOffset);
@@ -886,13 +885,27 @@ public class SevenZFile implements Closeable {
      *             if an I/O error has occurred
      */
     public int read() throws IOException {
-        if (currentEntryInputStream == null) {
-            throw new IllegalStateException("No current 7z entry");
-        }
-        return currentEntryInputStream.read();
+       return getCurrentStream().read();
     }
     
-    /**
+    private InputStream getCurrentStream() throws IOException {
+        if (deferredBlockStreams.isEmpty()) {
+            throw new IllegalStateException("No current 7z entry (call 
getNextEntry() first).");
+        }
+        
+        while (deferredBlockStreams.size() > 1) {
+               // In solid compression mode we need to decompress all leading 
folder' 
+               // streams to get access to an entry. We defer this until 
really needed
+               // so that entire blocks can be skipped without wasting time 
for decompression.
+               InputStream stream = deferredBlockStreams.remove(0);
+               IOUtils.skip(stream, Long.MAX_VALUE);
+               stream.close();
+        }
+
+               return deferredBlockStreams.get(0);
+       }
+
+       /**
      * Reads data into an array of bytes.
      * 
      * @param b the array to write data to
@@ -901,7 +914,7 @@ public class SevenZFile implements Closeable {
      *             if an I/O error has occurred
      */
     public int read(byte[] b) throws IOException {
-        return read(b, 0, b.length);
+       return read(b, 0, b.length);
     }
     
     /**
@@ -915,10 +928,7 @@ public class SevenZFile implements Closeable {
      *             if an I/O error has occurred
      */
     public int read(byte[] b, int off, int len) throws IOException {
-        if (currentEntryInputStream == null) {
-            throw new IllegalStateException("No current 7z entry");
-        }
-        return currentEntryInputStream.read(b, off, len);
+        return getCurrentStream().read(b, off, len);
     }
     
     private static long readUint64(final DataInput in) throws IOException {

Reply via email to