diff --git a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java index 7f5726e3656..f28750c3a97 100644 --- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java @@ -894,7 +894,8 @@ class JarFile extends ZipFile { 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 @@ class JarFile extends ZipFile { 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 @@ class JarFile extends ZipFile { * 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 @@ class JarFile extends ZipFile { continue next; } } - return true; + return i; } - return false; + return -1; } /** @@ -1011,11 +1012,35 @@ class JarFile extends ZipFile { 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 --git a/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java b/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java index 548b4bace19..e6dd04c23af 100644 --- a/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java +++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java @@ -54,6 +54,7 @@ public class MultiReleaseJarAPI { 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 @@ public class MultiReleaseJarAPI { @BeforeClass public void initialize() throws Exception { - CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars(); creator.compileEntries(); creator.buildUnversionedJar(); creator.buildMultiReleaseJar(); @@ -82,6 +82,10 @@ public class MultiReleaseJarAPI { 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 @@ public class MultiReleaseJarAPI { 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 --git a/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java index 390c4fa0c69..672b7c2d205 100644 --- a/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java +++ b/jdk/test/lib/testlibrary/java/util/jar/CreateMultiReleaseTestJars.java @@ -88,8 +88,12 @@ public class CreateMultiReleaseTestJars { } 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"));