You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by eb...@apache.org on 2013/12/19 13:30:01 UTC

svn commit: r1552293 - in /commons/proper/compress/trunk/src: changes/changes.xml main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java

Author: ebourg
Date: Thu Dec 19 12:30:01 2013
New Revision: 1552293

URL: http://svn.apache.org/r1552293
Log:
Support shrunk entries in ZipArchiveInputStream

Modified:
    commons/proper/compress/trunk/src/changes/changes.xml
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java

Modified: commons/proper/compress/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/changes/changes.xml?rev=1552293&r1=1552292&r2=1552293&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/changes/changes.xml (original)
+++ commons/proper/compress/trunk/src/changes/changes.xml Thu Dec 19 12:30:01 2013
@@ -61,7 +61,7 @@ The <action> type attribute can be add,u
         Read-Only support for .Z compressed files.
       </action> 
       <action type="add" date="2013-12-06" due-to="Damjan Jovanovic">
-        ZipFile now supports reading entries compressed using the
+        ZipFile and ZipArchiveInputStream now support reading entries compressed using the
         SHRINKING method.
       </action> 
       <action issue="COMPRESS-245" type="fix" date="2013-12-06">

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java?rev=1552293&r1=1552292&r2=1552293&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java (original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java Thu Dec 19 12:30:01 2013
@@ -271,6 +271,12 @@ public class ZipArchiveInputStream exten
         }
 
         processZip64Extra(size, cSize);
+        
+        if (current.entry.getCompressedSize() != -1 
+                && current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) {
+            current.in = new UnshrinkingInputStream(new BoundedInputStream(in, current.entry.getCompressedSize()));
+        }
+        
         entriesRead++;
         return current.entry;
     }
@@ -369,6 +375,8 @@ public class ZipArchiveInputStream exten
             read = readStored(buffer, offset, length);
         } else if (current.entry.getMethod() == ZipArchiveOutputStream.DEFLATED) {
             read = readDeflated(buffer, offset, length);
+        } else if (current.entry.getMethod() == ZipMethod.UNSHRINKING.getCode()) {
+            read = current.in.read(buffer, offset, length);
         } else {
             throw new UnsupportedZipFeatureException(ZipMethod.getMethodByCode(current.entry.getMethod()),
                     current.entry);
@@ -970,5 +978,88 @@ public class ZipArchiveInputStream exten
          * The checksum calculated as the current entry is read.
          */
         private final CRC32 crc = new CRC32();
+
+        /**
+         * The input stream decompressing the data for shrunk and imploded entries.
+         */
+        private InputStream in;
+    }
+
+    /**
+     * Bounded input stream adapted from commons-io
+     */
+    private class BoundedInputStream extends InputStream {
+
+        /** the wrapped input stream */
+        private final InputStream in;
+
+        /** the max length to provide */
+        private final long max;
+
+        /** the number of bytes already returned */
+        private long pos = 0;
+    
+        /**
+         * Creates a new <code>BoundedInputStream</code> that wraps the given input
+         * stream and limits it to a certain size.
+         *
+         * @param in The wrapped input stream
+         * @param size The maximum number of bytes to return
+         */
+        public BoundedInputStream(final InputStream in, final long size) {
+            this.max = size;
+            this.in = in;
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (max >= 0 && pos >= max) {
+                return -1;
+            }
+            final int result = in.read();
+            pos++;
+            count(1);
+            current.bytesReadFromStream++;
+            return result;
+        }
+
+        @Override
+        public int read(final byte[] b) throws IOException {
+            return this.read(b, 0, b.length);
+        }
+
+        @Override
+        public int read(final byte[] b, final int off, final int len) throws IOException {
+            if (max >= 0 && pos >= max) {
+                return -1;
+            }
+            final long maxRead = max >= 0 ? Math.min(len, max - pos) : len;
+            final int bytesRead = in.read(b, off, (int) maxRead);
+
+            if (bytesRead == -1) {
+                return -1;
+            }
+
+            pos += bytesRead;
+            count(bytesRead);
+            current.bytesReadFromStream += bytesRead;
+            return bytesRead;
+        }
+
+        @Override
+        public long skip(final long n) throws IOException {
+            final long toSkip = max >= 0 ? Math.min(n, max - pos) : n;
+            final long skippedBytes = in.skip(toSkip);
+            pos += skippedBytes;
+            return skippedBytes;
+        }
+    
+        @Override
+        public int available() throws IOException {
+            if (max >= 0 && pos >= max) {
+                return 0;
+            }
+            return in.available();
+        }
     }
 }

Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java?rev=1552293&r1=1552292&r2=1552293&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java (original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java Thu Dec 19 12:30:01 2013
@@ -27,6 +27,8 @@ import java.io.BufferedInputStream;
 import java.io.FileInputStream;
 import java.io.InputStream;
 import java.io.IOException;
+
+import org.apache.commons.compress.utils.IOUtils;
 import org.junit.Test;
 
 public class ZipArchiveInputStreamTest {
@@ -120,4 +122,29 @@ public class ZipArchiveInputStreamTest {
             zae = in.getNextZipEntry();
         }
     }
+
+    @Test
+    public void testUnshrinkEntry() throws Exception {
+        ZipArchiveInputStream in = new ZipArchiveInputStream(new FileInputStream(getFile("SHRUNK.ZIP")));
+        
+        ZipArchiveEntry entry = in.getNextZipEntry();
+        assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
+        
+        FileInputStream original = new FileInputStream(getFile("test1.xml"));
+        try {
+            assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
+        } finally {
+            original.close();
+        }
+        
+        entry = in.getNextZipEntry();
+        assertEquals("method", ZipMethod.UNSHRINKING.getCode(), entry.getMethod());
+        
+        original = new FileInputStream(getFile("test2.xml"));
+        try {
+            assertArrayEquals(IOUtils.toByteArray(original), IOUtils.toByteArray(in));
+        } finally {
+            original.close();
+        }
+    }
 }