Replace ZipInputstream by ZipFile

- ZipInputStream does not allow to read STORED entries that have data
descriptor and it raises a ZipException. ZipInputStream seems to be
compliant with an old PKZIP specification where this constraint was
relaxed in later revision. Using ZipFile does not raise this error.

Bug: 65010447
Change-Id: I38f8c417639f20df766cbd59b940fc312b50fd6b
diff --git a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
index 0c33273..20b656e 100644
--- a/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
+++ b/src/main/java/com/android/tools/r8/compatdx/CompatDx.java
@@ -36,11 +36,11 @@
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipInputStream;
+import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 import joptsimple.OptionParser;
 import joptsimple.OptionSet;
@@ -529,16 +529,16 @@
         // For each input archive file, add all class files within.
         for (Path input : inputs) {
           if (isArchive(input)) {
-            try (ZipInputStream in = new ZipInputStream(Files.newInputStream(input))) {
-              ZipEntry entry;
-              while ((entry = in.getNextEntry()) != null) {
+            try (ZipFile zipFile = new ZipFile(input.toFile())) {
+              final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+              while (entries.hasMoreElements()) {
+                ZipEntry entry = entries.nextElement();
                 if (isClassFile(Paths.get(entry.getName()))) {
-                  addEntry(entry.getName(), in, out);
+                  try (InputStream entryStream = zipFile.getInputStream(entry)) {
+                    addEntry(entry.getName(), entryStream, out);
+                  }
                 }
               }
-            } catch (ZipException e) {
-              throw new CompilationError(
-                  "Zip error while reading '" + input + "': " + e.getMessage(), e);
             }
           }
         }
diff --git a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
index 07c136d..5ea2a30 100644
--- a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
@@ -16,15 +16,16 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipException;
-import java.util.zip.ZipInputStream;
+import java.util.zip.ZipFile;
 
 /** Lazy Java class file resource provider based on preloaded/prebuilt context. */
 public final class PreloadedClassFileProvider implements ClassFileResourceProvider {
@@ -52,17 +53,17 @@
   public static ClassFileResourceProvider fromArchive(Path archive) throws IOException {
     assert isArchive(archive);
     Builder builder = builder();
-    try (ZipInputStream stream = new ZipInputStream(new FileInputStream(archive.toFile()))) {
-      ZipEntry entry;
-      while ((entry = stream.getNextEntry()) != null) {
+    try (ZipFile zipFile = new ZipFile(archive.toFile())) {
+      final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
         String name = entry.getName();
         if (isClassFile(Paths.get(name))) {
-          builder.addResource(guessTypeDescriptor(name), ByteStreams.toByteArray(stream));
+          try (InputStream entryStream = zipFile.getInputStream(entry)) {
+            builder.addResource(guessTypeDescriptor(name), ByteStreams.toByteArray(entryStream));
+          }
         }
       }
-    } catch (ZipException e) {
-      throw new CompilationError(
-          "Zip error while reading '" + archive + "': " + e.getMessage(), e);
     }
 
     return builder.build();
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
index 8341921..79ab853 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
@@ -10,17 +10,18 @@
 import com.android.tools.r8.Resource;
 import com.android.tools.r8.errors.CompilationError;
 import com.google.common.io.ByteStreams;
-import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
-import java.util.zip.ZipInputStream;
+import java.util.zip.ZipFile;
 
 class ProgramFileArchiveReader {
 
@@ -38,21 +39,24 @@
     assert isArchive(archive);
     dexResources = new ArrayList<>();
     classResources = new ArrayList<>();
-    try (ZipInputStream stream = new ZipInputStream(new FileInputStream(archive.toFile()))) {
-      ZipEntry entry;
-      while ((entry = stream.getNextEntry()) != null) {
-        Path name = Paths.get(entry.getName());
-        if (isDexFile(name)) {
-          if (!ignoreDexInArchive) {
-            Resource resource =
-                new OneShotByteResource(Resource.Kind.DEX, ByteStreams.toByteArray(stream), null);
-            dexResources.add(resource);
+    try (ZipFile zipFile = new ZipFile(archive.toFile())) {
+      final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
+        try (InputStream stream = zipFile.getInputStream(entry)) {
+          Path name = Paths.get(entry.getName());
+          if (isDexFile(name)) {
+            if (!ignoreDexInArchive) {
+              Resource resource =
+                  new OneShotByteResource(Resource.Kind.DEX, ByteStreams.toByteArray(stream), null);
+              dexResources.add(resource);
+            }
+          } else if (isClassFile(name)) {
+            String descriptor = PreloadedClassFileProvider.guessTypeDescriptor(name);
+            Resource resource = new OneShotByteResource(Resource.Kind.CLASSFILE,
+                ByteStreams.toByteArray(stream), Collections.singleton(descriptor));
+            classResources.add(resource);
           }
-        } else if (isClassFile(name)) {
-          String descriptor = PreloadedClassFileProvider.guessTypeDescriptor(name);
-          Resource resource = new OneShotByteResource(Resource.Kind.CLASSFILE,
-              ByteStreams.toByteArray(stream), Collections.singleton(descriptor));
-          classResources.add(resource);
         }
       }
     } catch (ZipException e) {
diff --git a/src/main/java/com/android/tools/r8/utils/ZipUtils.java b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
index 47d8e01..ca9a404 100644
--- a/src/main/java/com/android/tools/r8/utils/ZipUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ZipUtils.java
@@ -6,27 +6,31 @@
 import com.android.tools.r8.errors.CompilationError;
 import com.google.common.io.ByteStreams;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
+import java.util.zip.ZipFile;
 
 public class ZipUtils {
 
   public interface OnEntryHandler {
-    void onEntry(ZipEntry entry, ZipInputStream input) throws IOException;
+    void onEntry(ZipEntry entry, InputStream input) throws IOException;
   }
 
-  public static void iter(String zipFile, OnEntryHandler handler) throws IOException {
-    try (ZipInputStream input = new ZipInputStream(new FileInputStream(zipFile))){
-      ZipEntry entry;
-      while ((entry = input.getNextEntry()) != null) {
-        handler.onEntry(entry, input);
+  public static void iter(String zipFileStr, OnEntryHandler handler) throws IOException {
+    try (ZipFile zipFile = new ZipFile(zipFileStr)) {
+      final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
+        try (InputStream entryStream = zipFile.getInputStream(entry)) {
+          handler.onEntry(entry, entryStream);
+        }
       }
     }
   }
diff --git a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
index a02a186..5ad5787 100644
--- a/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/includedescriptorclasses/IncludeDescriptorClassesTest.java
@@ -13,15 +13,15 @@
 import com.android.tools.r8.utils.DexInspector;
 import com.google.common.collect.ImmutableList;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
+import java.util.zip.ZipFile;
 import org.junit.Test;
 
 public class IncludeDescriptorClassesTest extends TestBase {
@@ -51,14 +51,14 @@
 
   private Set<String> readJarClasses(Path jar) throws IOException {
     Set<String> result = new HashSet<>();
-    try (ZipInputStream in = new ZipInputStream(new FileInputStream(jar.toFile()))) {
-      ZipEntry entry = in.getNextEntry();
-      while (entry != null) {
+    try (ZipFile zipFile = new ZipFile(jar.toFile())) {
+      final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
         String name = entry.getName();
         if (name.endsWith(".class")) {
           result.add(name.substring(0, name.length() - ".class".length()).replace('/', '.'));
         }
-        entry = in.getNextEntry();
       }
     }
     return result;