Fix Manifest behavior with Manifest-Version/Signature-Version.

Bug: 8444077
Change-Id: Ic78afc36f94fccc6a473893b0c218cd07b441dc7
diff --git a/luni/src/main/java/java/util/jar/InitManifest.java b/luni/src/main/java/java/util/jar/InitManifest.java
index c82a1e4..ade4790 100644
--- a/luni/src/main/java/java/util/jar/InitManifest.java
+++ b/luni/src/main/java/java/util/jar/InitManifest.java
@@ -37,15 +37,8 @@
     private final UnsafeByteSequence valueBuffer = new UnsafeByteSequence(80);
     private int consecutiveLineBreaks = 0;
 
-    InitManifest(byte[] buf, Attributes main, Attributes.Name ver) throws IOException {
+    InitManifest(byte[] buf, Attributes main) throws IOException {
         this.buf = buf;
-
-        // check a version attribute
-        if (!readHeader() || (ver != null && !name.equals(ver))) {
-            throw new IOException("Missing version attribute: " + ver);
-        }
-
-        main.put(name, value);
         while (readHeader()) {
             main.put(name, value);
         }
diff --git a/luni/src/main/java/java/util/jar/JarVerifier.java b/luni/src/main/java/java/util/jar/JarVerifier.java
index dc37b72..81938fa 100644
--- a/luni/src/main/java/java/util/jar/JarVerifier.java
+++ b/luni/src/main/java/java/util/jar/JarVerifier.java
@@ -314,12 +314,17 @@
         Attributes attributes = new Attributes();
         HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
         try {
-            InitManifest im = new InitManifest(sfBytes, attributes, Attributes.Name.SIGNATURE_VERSION);
+            InitManifest im = new InitManifest(sfBytes, attributes);
             im.initEntries(entries, null);
         } catch (IOException e) {
             return;
         }
 
+        // Do we actually have any signatures to look at?
+        if (entries.get(Attributes.Name.SIGNATURE_VERSION) == null) {
+            return;
+        }
+
         boolean createdBySigntool = false;
         String createdBy = attributes.getValue("Created-By");
         if (createdBy != null) {
diff --git a/luni/src/main/java/java/util/jar/Manifest.java b/luni/src/main/java/java/util/jar/Manifest.java
index d46aea3..723aa99 100644
--- a/luni/src/main/java/java/util/jar/Manifest.java
+++ b/luni/src/main/java/java/util/jar/Manifest.java
@@ -174,11 +174,10 @@
     }
 
     /**
-     * Writes out the attribute information of the receiver to the specified
-     * {@code OutputStream}.
+     * Writes this {@code Manifest}'s name/attributes pairs to the given {@code OutputStream}.
+     * The {@code MANIFEST_VERSION} or {@code SIGNATURE_VERSION} attribute must be set before
+     * calling this method, or no attributes will be written.
      *
-     * @param os
-     *            The {@code OutputStream} to write to.
      * @throws IOException
      *             If an error occurs writing the {@code Manifest}.
      */
@@ -214,9 +213,7 @@
             buf[buf.length - 1] = '\n';
         }
 
-        // Attributes.Name.MANIFEST_VERSION is not used for
-        // the second parameter for RI compatibility
-        InitManifest im = new InitManifest(buf, mainAttributes, null);
+        InitManifest im = new InitManifest(buf, mainAttributes);
         mainEnd = im.getPos();
         im.initEntries(entries, chunks);
     }
@@ -308,13 +305,18 @@
         CharsetEncoder encoder = Charsets.UTF_8.newEncoder();
         ByteBuffer buffer = ByteBuffer.allocate(LINE_LENGTH_LIMIT);
 
-        String version = manifest.mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION);
+        Attributes.Name versionName = Attributes.Name.MANIFEST_VERSION;
+        String version = manifest.mainAttributes.getValue(versionName);
+        if (version == null) {
+            versionName = Attributes.Name.SIGNATURE_VERSION;
+            version = manifest.mainAttributes.getValue(versionName);
+        }
         if (version != null) {
-            writeEntry(out, Attributes.Name.MANIFEST_VERSION, version, encoder, buffer);
+            writeEntry(out, versionName, version, encoder, buffer);
             Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
             while (entries.hasNext()) {
                 Attributes.Name name = (Attributes.Name) entries.next();
-                if (!name.equals(Attributes.Name.MANIFEST_VERSION)) {
+                if (!name.equals(versionName)) {
                     writeEntry(out, name, manifest.mainAttributes.getValue(name), encoder, buffer);
                 }
             }
@@ -324,11 +326,11 @@
         while (i.hasNext()) {
             String key = i.next();
             writeEntry(out, NAME_ATTRIBUTE, key, encoder, buffer);
-            Attributes attrib = manifest.entries.get(key);
-            Iterator<?> entries = attrib.keySet().iterator();
+            Attributes attributes = manifest.entries.get(key);
+            Iterator<?> entries = attributes.keySet().iterator();
             while (entries.hasNext()) {
                 Attributes.Name name = (Attributes.Name) entries.next();
-                writeEntry(out, name, attrib.getValue(name), encoder, buffer);
+                writeEntry(out, name, attributes.getValue(name), encoder, buffer);
             }
             out.write(LINE_SEPARATOR);
         }
diff --git a/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java b/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
index 9552aef..e5c3bdb 100644
--- a/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
@@ -141,4 +141,44 @@
         assertTrue(manifest1.equals(manifest2));
     }
 
+    public void test_write_no_version() throws Exception {
+        // If you write a manifest with no MANIFEST_VERSION, your attributes don't get written out.
+        assertEquals(null, doRoundTrip(null));
+        // But they do if you supply a MANIFEST_VERSION.
+        assertEquals("image/pr0n", doRoundTrip(Attributes.Name.MANIFEST_VERSION));
+        assertEquals("image/pr0n", doRoundTrip("Signature-Version"));
+        assertEquals(null, doRoundTrip("Random-String-Version"));
+    }
+
+    private String doRoundTrip(Object versionName) throws Exception {
+        Manifest m1 = new Manifest();
+        m1.getMainAttributes().put(Attributes.Name.CONTENT_TYPE, "image/pr0n");
+        if (versionName != null) {
+            m1.getMainAttributes().putValue(versionName.toString(), "1.2.3");
+        }
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        m1.write(os);
+
+        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+        Manifest m2 = new Manifest();
+        m2.read(is);
+        return (String) m2.getMainAttributes().get(Attributes.Name.CONTENT_TYPE);
+    }
+
+    public void test_write_two_versions() throws Exception {
+        // It's okay to have two versions.
+        Manifest m1 = new Manifest();
+        m1.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+        m1.getMainAttributes().put(Attributes.Name.SIGNATURE_VERSION, "2.0");
+        m1.getMainAttributes().putValue("Aardvark-Version", "3.0");
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        m1.write(os);
+
+        // The Manifest-Version takes precedence,
+        // and the Signature-Version gets no special treatment.
+        String[] lines = new String(os.toByteArray(), "UTF-8").split("\r\n");
+        assertEquals("Manifest-Version: 1.0", lines[0]);
+        assertEquals("Aardvark-Version: 3.0", lines[1]);
+        assertEquals("Signature-Version: 2.0", lines[2]);
+    }
 }