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]);
+ }
}