# HG changeset patch # User redestad # Date 1460478310 -7200 # Node ID 4c4141aac1463b666976fff955244a8eecf168b5 # Parent eb17ca049605d6b39a9675d2ff8da59b2f57f8a9 8153213: Jar manifest attribute "Multi-Release" accepts any value Reviewed-by: psandoz, redestad Contributed-by: steve.drach@oracle.com diff -r eb17ca049605 -r 4c4141aac146 jdk/src/java.base/share/classes/java/util/jar/JarFile.java --- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Apr 12 13:53:48 2016 +0800 +++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Apr 12 18:25:10 2016 +0200 @@ -894,7 +894,8 @@ private static final byte[] CLASSPATH_LASTOCC; private static final byte[] MULTIRELEASE_CHARS = - {'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':', ' '}; + {'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':', + ' ', 'T', 'R', 'U', 'E'}; // The bad character shift for "multi-release: " private static final byte[] MULTIRELEASE_LASTOCC; @@ -914,17 +915,17 @@ MULTIRELEASE_LASTOCC = new byte[64]; MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1; - MULTIRELEASE_LASTOCC[(int)'U' - 32] = 2; - MULTIRELEASE_LASTOCC[(int)'T' - 32] = 4; MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5; MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6; - MULTIRELEASE_LASTOCC[(int)'R' - 32] = 7; MULTIRELEASE_LASTOCC[(int)'L' - 32] = 9; MULTIRELEASE_LASTOCC[(int)'A' - 32] = 11; MULTIRELEASE_LASTOCC[(int)'S' - 32] = 12; - MULTIRELEASE_LASTOCC[(int)'E' - 32] = 13; MULTIRELEASE_LASTOCC[(int)':' - 32] = 14; MULTIRELEASE_LASTOCC[(int)' ' - 32] = 15; + MULTIRELEASE_LASTOCC[(int)'T' - 32] = 16; + MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17; + MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18; + MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19; } private JarEntry getManEntry() { @@ -966,7 +967,7 @@ * Since there are no repeated substring in our search strings, * the good suffix shifts can be replaced with a comparison. */ - private boolean match(byte[] src, byte[] b, byte[] lastOcc) { + private int match(byte[] src, byte[] b, byte[] lastOcc) { int len = src.length; int last = b.length - len; int i = 0; @@ -990,9 +991,9 @@ continue next; } } - return true; + return i; } - return false; + return -1; } /** @@ -1011,11 +1012,35 @@ if (manEntry != null) { byte[] b = getBytes(manEntry); hasClassPathAttribute = match(CLASSPATH_CHARS, b, - CLASSPATH_LASTOCC); + CLASSPATH_LASTOCC) != -1; // is this a multi-release jar file if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) { - isMultiRelease = match(MULTIRELEASE_CHARS, b, - MULTIRELEASE_LASTOCC); + int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC); + if (i != -1) { + i += MULTIRELEASE_CHARS.length; + if (i < b.length) { + byte c = b[i++]; + // Check that the value is followed by a newline + // and does not have a continuation + if (c == '\n' && + (i == b.length || b[i] != ' ')) { + isMultiRelease = true; + } else if (c == '\r') { + if (i == b.length) { + isMultiRelease = true; + } else { + c = b[i++]; + if (c == '\n') { + if (i == b.length || b[i] != ' ') { + isMultiRelease = true; + } + } else if (c != ' ') { + isMultiRelease = true; + } + } + } + } + } } } hasCheckedSpecialAttributes = true; diff -r eb17ca049605 -r 4c4141aac146 jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java --- a/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java Tue Apr 12 13:53:48 2016 +0800 +++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java Tue Apr 12 18:25:10 2016 +0200 @@ -54,6 +54,7 @@ static final int MAJOR_VERSION = Version.current().major(); String userdir = System.getProperty("user.dir","."); + CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); File unversioned = new File(userdir, "unversioned.jar"); File multirelease = new File(userdir, "multi-release.jar"); File signedmultirelease = new File(userdir, "signed-multi-release.jar"); @@ -62,7 +63,6 @@ @BeforeClass public void initialize() throws Exception { - CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); creator.compileEntries(); creator.buildUnversionedJar(); creator.buildMultiReleaseJar(); @@ -82,6 +82,10 @@ Assert.assertFalse(jf.isMultiRelease()); } + try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + Assert.assertFalse(jf.isMultiRelease()); + } + try (JarFile jf = new JarFile(multirelease)) { Assert.assertFalse(jf.isMultiRelease()); } @@ -89,6 +93,28 @@ try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) { Assert.assertTrue(jf.isMultiRelease()); } + + testCustomMultiReleaseValue("true", true); + testCustomMultiReleaseValue("true\r\nOther: value", true); + testCustomMultiReleaseValue("true\nOther: value", true); + testCustomMultiReleaseValue("true\rOther: value", true); + + testCustomMultiReleaseValue("false", false); + testCustomMultiReleaseValue(" true", false); + testCustomMultiReleaseValue("true ", false); + testCustomMultiReleaseValue("true\n ", false); + testCustomMultiReleaseValue("true\r ", false); + testCustomMultiReleaseValue("true\n true", false); + testCustomMultiReleaseValue("true\r\n true", false); + } + + private void testCustomMultiReleaseValue(String value, boolean expected) throws Exception { + creator.buildCustomMultiReleaseJar("custom-mr.jar", value); + File custom = new File(userdir, "custom-mr.jar"); + try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Release.RUNTIME)) { + Assert.assertEquals(jf.isMultiRelease(), expected); + } + Files.delete(custom.toPath()); } @Test diff -r eb17ca049605 -r 4c4141aac146 jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java --- a/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java Tue Apr 12 13:53:48 2016 +0800 +++ b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java Tue Apr 12 18:25:10 2016 +0200 @@ -88,8 +88,12 @@ } public void buildMultiReleaseJar() throws IOException { - JarBuilder jb = new JarBuilder("multi-release.jar"); - jb.addAttribute("Multi-Release", "true"); + buildCustomMultiReleaseJar("multi-release.jar", "true"); + } + + public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue) throws IOException { + JarBuilder jb = new JarBuilder(filename); + jb.addAttribute("Multi-Release", multiReleaseValue); jb.addEntry("README", readme8.getBytes()); jb.addEntry("version/Main.java", main.getBytes()); jb.addEntry("version/Main.class", rootClasses.get("version.Main"));