Add tests and support for data resources to the dump file.

Change-Id: I48638f47cd93157a77d6e89fbbad2cca841ccfce
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 110308d..3f57203 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -443,7 +443,7 @@
           String entryName = dataResource.getName();
           try (InputStream dataStream = dataResource.getByteStream()) {
             byte[] bytes = ByteStreams.toByteArray(dataStream);
-            writeToZipStream(out, entryName, bytes, ZipEntry.DEFLATED);
+            writeToZipStream(archiveOutputStream, entryName, bytes, ZipEntry.DEFLATED);
           }
         }
         for (ProgramResourceProvider provider : programResourceProviders) {
@@ -616,6 +616,8 @@
               readClassFileDump(origin, input, this::addClasspathResourceProvider, "classpath");
             } else if (name.equals(dumpLibraryFileName)) {
               readClassFileDump(origin, input, this::addLibraryResourceProvider, "library");
+            } else {
+              System.out.println("WARNING: Unexpected dump file entry: " + entry.getName());
             }
           });
       return this;
@@ -667,6 +669,8 @@
     }
 
     private void readProgramDump(Origin origin, InputStream input) throws IOException {
+      List<ProgramResource> programResources = new ArrayList<>();
+      List<DataEntryResource> dataResources = new ArrayList<>();
       try (ZipInputStream stream = new ZipInputStream(input)) {
         ZipEntry entry;
         while (null != (entry = stream.getNextEntry())) {
@@ -680,18 +684,44 @@
                     entryOrigin,
                     ByteStreams.toByteArray(stream),
                     Collections.singleton(descriptor));
-            addProgramResources(resource);
+            programResources.add(resource);
           } else if (ZipUtils.isDexFile(name)) {
             Origin entryOrigin = new ArchiveEntryOrigin(name, origin);
             ProgramResource resource =
                 OneShotByteResource.create(
                     Kind.DEX, entryOrigin, ByteStreams.toByteArray(stream), null);
-            addProgramResources(resource);
+            programResources.add(resource);
           } else if (name.endsWith(".dup")) {
             System.out.println("WARNING: Duplicate program resource: " + name);
+          } else {
+            dataResources.add(
+                DataEntryResource.fromBytes(ByteStreams.toByteArray(stream), name, origin));
           }
         }
       }
+      if (!programResources.isEmpty() || !dataResources.isEmpty()) {
+        addProgramResourceProvider(
+            new ProgramResourceProvider() {
+              @Override
+              public Collection<ProgramResource> getProgramResources() throws ResourceException {
+                return programResources;
+              }
+
+              @Override
+              public DataResourceProvider getDataResourceProvider() {
+                return dataResources.isEmpty()
+                    ? null
+                    : new DataResourceProvider() {
+                      @Override
+                      public void accept(Visitor visitor) throws ResourceException {
+                        for (DataEntryResource dataResource : dataResources) {
+                          visitor.visit(dataResource);
+                        }
+                      }
+                    };
+              }
+            });
+      }
     }
 
     /** Add program file resources. */
diff --git a/src/test/java/com/android/tools/r8/AndroidAppDumpsTest.java b/src/test/java/com/android/tools/r8/AndroidAppDumpsTest.java
index 2579acb..04c4bf2 100644
--- a/src/test/java/com/android/tools/r8/AndroidAppDumpsTest.java
+++ b/src/test/java/com/android/tools/r8/AndroidAppDumpsTest.java
@@ -4,15 +4,21 @@
 package com.android.tools.r8;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
+import com.android.tools.r8.DataResourceProvider.Visitor;
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Reporter;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.file.Path;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 import org.junit.Test;
@@ -35,10 +41,14 @@
 
   @Test
   public void test() throws Exception {
+    Reporter reporter = new Reporter();
+
+    String dataResourceName = "my-resource.bin";
+    byte[] dataResourceData = new byte[] {1, 2, 3};
+
     Path dexForB =
         testForD8().addProgramClasses(B.class).setMinApi(AndroidApiLevel.B).compile().writeToZip();
 
-    Reporter reporter = new Reporter();
     AndroidApp appIn =
         AndroidApp.builder(reporter)
             .addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A"))
@@ -51,6 +61,9 @@
             .addLibraryResourceProvider(provider(C.class))
             .addLibraryResourceProvider(provider(C.class))
             .addLibraryResourceProvider(provider(C.class))
+            .addProgramResourceProvider(
+                createDataResourceProvider(
+                    dataResourceName, dataResourceData, origin(dataResourceName)))
             .build();
 
     Path dumpFile = temp.newFolder().toPath().resolve("dump.zip");
@@ -73,6 +86,62 @@
     assertEquals(
         DescriptorUtils.javaTypeToDescriptor(C.class.getTypeName()),
         appOut.getLibraryResourceProviders().get(0).getClassDescriptors().iterator().next());
+
+    Box<Boolean> foundData = new Box<>(false);
+    for (ProgramResourceProvider provider : appOut.getProgramResourceProviders()) {
+      DataResourceProvider dataProvider = provider.getDataResourceProvider();
+      if (dataProvider != null) {
+        dataProvider.accept(
+            new Visitor() {
+              @Override
+              public void visit(DataDirectoryResource directory) {}
+
+              @Override
+              public void visit(DataEntryResource file) {
+                if (file.getName().equals(dataResourceName)) {
+                  foundData.set(true);
+                }
+              }
+            });
+      }
+    }
+    assertTrue(foundData.get());
+  }
+
+  private ProgramResourceProvider createDataResourceProvider(
+      String name, byte[] content, Origin origin) {
+    return new ProgramResourceProvider() {
+      @Override
+      public Collection<ProgramResource> getProgramResources() throws ResourceException {
+        return Collections.emptyList();
+      }
+
+      @Override
+      public DataResourceProvider getDataResourceProvider() {
+        return new DataResourceProvider() {
+          @Override
+          public void accept(Visitor visitor) throws ResourceException {
+            visitor.visit(
+                new DataEntryResource() {
+                  @Override
+                  public InputStream getByteStream() throws ResourceException {
+                    return new ByteArrayInputStream(content);
+                  }
+
+                  @Override
+                  public String getName() {
+                    return name;
+                  }
+
+                  @Override
+                  public Origin getOrigin() {
+                    return origin;
+                  }
+                });
+          }
+        };
+      }
+    };
   }
 
   private Origin origin(String name) {