OSDN Git Service

Update archive to the r802921 from Harmony.
[android-x86/dalvik.git] / libcore / archive / src / main / java / java / util / zip / ZipInputStream.java
index 8c6a4c5..fd78e4c 100644 (file)
@@ -17,7 +17,6 @@
 
 package java.util.zip;
 
-
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,18 +35,14 @@ import org.apache.harmony.luni.util.Util;
  * the so called ZIP entries. Therefore when reading from a {@code
  * ZipInputStream} first the entry's attributes will be retrieved with {@code
  * getNextEntry} before its data is read.
- * </p>
  * <p>
  * While {@code InflaterInputStream} can read a compressed <i>ZIP-archive</i>
  * entry, this extension can read uncompressed entries as well.
- * </p>
  * <p>
  * Use {@code ZipFile} if you can access the archive as a file directly.
- * </p>
- * 
+ *
  * @see ZipEntry
  * @see ZipFile
- * @since Android 1.0
  */
 public class ZipInputStream extends InflaterInputStream implements ZipConstants {
     static final int DEFLATED = 8;
@@ -58,7 +53,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
 
     static final int ZIPLocalHeaderVersionNeeded = 20;
 
-    private boolean zipClosed = false;
+    // BEGIN android-removed
+    // private boolean zipClosed = false;
+    // END android-removed
 
     private boolean entriesEnd = false;
 
@@ -80,10 +77,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
 
     /**
      * Constructs a new {@code ZipInputStream} from the specified input stream.
-     * 
+     *
      * @param stream
      *            the input stream to representing a ZIP archive.
-     * @since Android 1.0
      */
     public ZipInputStream(InputStream stream) {
         super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
@@ -94,31 +90,32 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
 
     /**
      * Closes this {@code ZipInputStream}.
-     * 
+     *
      * @throws IOException
      *             if an {@code IOException} occurs.
-     * @since Android 1.0
      */
     @Override
     public void close() throws IOException {
-        if (zipClosed != true) {
+        // BEGIN android-changed
+        if (closed != true) {
             closeEntry(); // Close the current entry
-            zipClosed = true;
             super.close();
         }
+        // END android-changed
     }
 
     /**
      * Closes the current ZIP entry and positions to read the next entry.
-     * 
+     *
      * @throws IOException
      *             if an {@code IOException} occurs.
-     * @since Android 1.0
      */
     public void closeEntry() throws IOException {
-        if (zipClosed) {
+        // BEGIN android-changed
+        if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
+        // END android-changed
         if (currentEntry == null) {
             return;
         }
@@ -128,8 +125,24 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
                 return;
             }
         }
+
+        /*
+         * The following code is careful to leave the ZipInputStream in a
+         * consistent state, even when close() results in an exception. It does
+         * so by:
+         *  - pushing bytes back into the source stream
+         *  - reading a data descriptor footer from the source stream
+         *  - resetting fields that manage the entry being closed
+         */
+
         // Ensure all entry bytes are read
-        skip(Long.MAX_VALUE);
+        Exception failure = null;
+        try {
+            skip(Long.MAX_VALUE);
+        } catch (Exception e) {
+            failure = e;
+        }
+
         int inB, out;
         if (currentEntry.compressionMethod == DEFLATED) {
             inB = inf.getTotalIn();
@@ -138,12 +151,38 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
             inB = inRead;
             out = inRead;
         }
-        int diff = 0;
+        int diff = entryIn - inB;
         // Pushback any required bytes
-        if ((diff = entryIn - inB) != 0) {
+        if (diff != 0) {
             ((PushbackInputStream) in).unread(buf, len - diff, diff);
         }
 
+        try {
+            readAndVerifyDataDescriptor(inB, out);
+        } catch (Exception e) {
+            if (failure == null) { // otherwise we're already going to throw
+                failure = e;
+            }
+        }
+
+        inf.reset();
+        lastRead = inRead = entryIn = len = 0;
+        crc.reset();
+        currentEntry = null;
+
+        if (failure != null) {
+            if (failure instanceof IOException) {
+                throw (IOException) failure;
+            } else if (failure instanceof RuntimeException) {
+                throw (RuntimeException) failure;
+            }
+            AssertionError error = new AssertionError();
+            error.initCause(failure);
+            throw error;
+        }
+    }
+
+    private void readAndVerifyDataDescriptor(int inB, int out) throws IOException {
         if (hasDD) {
             in.read(hdrBuf, 0, EXTHDR);
             if (getLong(hdrBuf, 0) != EXTSIG) {
@@ -159,27 +198,19 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
         if (currentEntry.compressedSize != inB || currentEntry.size != out) {
             throw new ZipException(Messages.getString("archive.21")); //$NON-NLS-1$
         }
-
-        inf.reset();
-        lastRead = inRead = entryIn = len = 0;
-        crc.reset();
-        currentEntry = null;
     }
 
     /**
-     * Reads the next entry from this {@code ZipInputStream}.
-     * 
+     * Reads the next entry from this {@code ZipInputStream} or {@code null} if
+     * no more entries are present.
+     *
      * @return the next {@code ZipEntry} contained in the input stream.
      * @throws IOException
-     *             if the stream is not positioned at the beginning of an entry
-     *             or if an other {@code IOException} occurs.
+     *             if an {@code IOException} occurs.
      * @see ZipEntry
-     * @since Android 1.0
      */
     public ZipEntry getNextEntry() throws IOException {
-        if (currentEntry != null) {
-            closeEntry();
-        }
+        closeEntry();
         if (entriesEnd) {
             return null;
         }
@@ -261,16 +292,33 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
             }
             currentEntry.setExtra(e);
         }
+        // BEGIN android-added
+        eof = false;
+        // END android-added
         return currentEntry;
     }
 
     /* Read 4 bytes from the buffer and store it as an int */
 
+    /**
+     * Reads up to the specified number of uncompressed bytes into the buffer
+     * starting at the offset.
+     *
+     * @param buffer
+     *            a byte array
+     * @param start
+     *            the starting offset into the buffer
+     * @param length
+     *            the number of bytes to read
+     * @return the number of bytes read
+     */
     @Override
     public int read(byte[] buffer, int start, int length) throws IOException {
-        if (zipClosed) {
+        // BEGIN android-changed
+        if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
+        // END android-changed
         if (inf.finished() || currentEntry == null) {
             return -1;
         }
@@ -280,11 +328,17 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
             if (currentEntry.compressionMethod == STORED) {
                 int csize = (int) currentEntry.size;
                 if (inRead >= csize) {
+                    // BEGIN android-added
+                    eof = true;
+                    // END android-added
                     return -1;
                 }
                 if (lastRead >= len) {
                     lastRead = 0;
                     if ((len = in.read(buf)) == -1) {
+                        // BEGIN android-added
+                        eof = true;
+                        // END android-added
                         return -1;
                     }
                     entryIn += len;
@@ -324,13 +378,12 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
 
     /**
      * Skips up to the specified number of bytes in the current ZIP entry.
-     * 
+     *
      * @param value
      *            the number of bytes to skip.
      * @return the number of bytes skipped.
      * @throws IOException
      *             if an {@code IOException} occurs.
-     * @since Android 1.0
      */
     @Override
     public long skip(long value) throws IOException {
@@ -348,43 +401,34 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
             return skipped;
         }
         throw new IllegalArgumentException();
-}
+    }
 
     /**
      * Returns 0 if the {@code EOF} has been reached, otherwise returns 1.
-     * 
+     *
      * @return 0 after {@code EOF} of current entry, 1 otherwise.
      * @throws IOException
      *             if an IOException occurs.
-     * @since Android 1.0
      */
     @Override
     public int available() throws IOException {
-        if (zipClosed) {
+        // BEGIN android-changed
+        if (closed) {
             throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
         }
         if (currentEntry == null) {
             return 1;
         }
-        if (currentEntry.compressionMethod == STORED) {
-            if (inRead >= currentEntry.size) {
-                return 0;
-            }
-        } else {
-            if (inf.finished()) {
-                return 0;
-            }
-        }
-        return 1;
+        return super.available();
+        // END android-changed
     }
 
     /**
      * creates a {@link ZipEntry } with the given name.
-     * 
+     *
      * @param name
      *            the name of the entry.
      * @return the created {@code ZipEntry}.
-     * @since Android 1.0
      */
     protected ZipEntry createZipEntry(String name) {
         return new ZipEntry(name);