COMPRESS-219 reading stored entries could try to read past the end of the internal buffer

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1448357 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index ff281f9..7d66d04 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -160,6 +160,10 @@
           Updated XZ for Java dependency to 1.2 as this version
           provides proper OSGi manifest attributes.
         </action>
+        <action type="fix" date="2013-02-20" issue="COMPRESS-219">
+          Fixed a potential ArrayIndexOutOfBoundsException when
+          reading STORED entries from ZipArchiveInputStream.
+        </action>
     </release>
     <release version="1.4.1" date="2012-05-23"
              description="Release 1.4.1">
diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
index 5ab0931..b2d14f5 100644
--- a/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStream.java
@@ -426,9 +426,8 @@
             current.bytesReadFromStream += buf.lengthOfLastRead;
         }
 
-        int toRead = length > buf.lengthOfLastRead
-            ? buf.lengthOfLastRead - buf.offsetInBuffer
-            : length;
+        int availableBytesInBuffer = buf.lengthOfLastRead - buf.offsetInBuffer;
+        int toRead = Math.min(availableBytesInBuffer, length);
         if ((csize - current.bytesRead) < toRead) {
             // if it is smaller than toRead then it fits into an int
             toRead = (int) (csize - current.bytesRead);
diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
index 7bd10e3..c1651d5 100644
--- a/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/zip/ZipArchiveInputStreamTest.java
@@ -19,15 +19,22 @@
 package org.apache.commons.compress.archivers.zip;
 
 import static org.apache.commons.compress.AbstractTestCase.getFile;
+import static org.apache.commons.compress.AbstractTestCase.mkdir;
+import static org.apache.commons.compress.AbstractTestCase.rmdir;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import java.io.BufferedInputStream;
+import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 
 import org.junit.Test;
+import org.apache.commons.compress.utils.IOUtils;
 
 public class ZipArchiveInputStreamTest {
 
@@ -93,4 +100,31 @@
         assertArrayEquals(expected, actual);
         zip.close();
     }
+
+    /**
+     * @see "https://issues.apache.org/jira/browse/COMPRESS-219"
+     */
+    @Test
+    public void shouldReadNestedZip() throws IOException {
+        ZipArchiveInputStream in = null;
+        try {
+            in = new ZipArchiveInputStream(new FileInputStream(getFile("COMPRESS-219.zip")));
+            extractZipInputStream(in);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+    private void extractZipInputStream(final ZipArchiveInputStream in)
+        throws IOException {
+        ZipArchiveEntry zae = in.getNextZipEntry();
+        while (zae != null) {
+            if (zae.getName().endsWith(".zip")) {
+                extractZipInputStream(new ZipArchiveInputStream(in));
+            }
+            zae = in.getNextZipEntry();
+        }
+    }
 }