Disallow filenames containing NUL bytes.

C code gets confused by such filenames, and even if we can handle them,
they're a misleading and of questionable utility because a valid pathname
can't contain a NUL byte.

Bug: https://code.google.com/p/android/issues/detail?id=58465
Bug: 10148349
Change-Id: I3f7e1a17c526b6bb5752dae82610125ad2648d54
(cherry picked from commit b1d05573ae20cdd3d5b4e25f905ce44c8f7d5c0e)
diff --git a/luni/src/main/java/java/util/zip/ZipEntry.java b/luni/src/main/java/java/util/zip/ZipEntry.java
index ee68b66..e91c73e 100644
--- a/luni/src/main/java/java/util/zip/ZipEntry.java
+++ b/luni/src/main/java/java/util/zip/ZipEntry.java
@@ -21,6 +21,7 @@
 import java.io.InputStream;
 import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
@@ -383,6 +384,9 @@
 
         byte[] nameBytes = new byte[nameLength];
         Streams.readFully(in, nameBytes, 0, nameBytes.length);
+        if (containsNulByte(nameBytes)) {
+            throw new ZipException("Filename contains NUL byte: " + Arrays.toString(nameBytes));
+        }
         name = new String(nameBytes, 0, nameBytes.length, StandardCharsets.UTF_8);
 
         // The RI has always assumed UTF-8. (If GPBF_UTF8_FLAG isn't set, the encoding is
@@ -398,4 +402,13 @@
             Streams.readFully(in, extra, 0, extraLength);
         }
     }
+
+    private static boolean containsNulByte(byte[] bytes) {
+        for (byte b : bytes) {
+            if (b == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
index dec074e..fd27ea8 100644
--- a/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
+++ b/luni/src/test/java/libcore/java/util/zip/ZipFileTest.java
@@ -33,7 +33,6 @@
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 import junit.framework.TestCase;
-import libcore.io.IoUtils;
 
 public final class ZipFileTest extends TestCase {
     /**
@@ -379,6 +378,26 @@
         assertEquals(null, zipFile.getComment());
     }
 
+    // https://code.google.com/p/android/issues/detail?id=58465
+    public void test_NUL_in_filename() throws Exception {
+        File file = createTemporaryZipFile();
+
+        // We allow creation of a ZipEntry whose name contains a NUL byte,
+        // mainly because it's not likely to happen by accident and it's useful for testing.
+        ZipOutputStream out = createZipOutputStream(file);
+        out.putNextEntry(new ZipEntry("hello"));
+        out.putNextEntry(new ZipEntry("hello\u0000"));
+        out.close();
+
+        // But you can't open a ZIP file containing such an entry, because we reject it
+        // when we find it in the central directory.
+        try {
+            ZipFile zipFile = new ZipFile(file);
+            fail();
+        } catch (ZipException expected) {
+        }
+    }
+
     public void testNameLengthChecks() throws IOException {
         // Is entry name length checking done on bytes or characters?
         // Really it should be bytes, but the RI only checks characters at construction time.