< prev index next >
src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java
Print this page
rev 16859 : 8176709: JarFileSystem::isMultiReleaseJar is incorrect
Reviewed-by: alanb, sherman, psandoz, mchung
@@ -86,18 +86,112 @@
}
}
private boolean isMultiReleaseJar() {
try (InputStream is = newInputStream(getBytes("/META-INF/MANIFEST.MF"))) {
- return (new Manifest(is)).getMainAttributes()
- .containsKey(new Attributes.Name("Multi-Release"));
- // fixme change line above after JarFile integration to contain Attributes.Name.MULTI_RELEASE
+ byte[] b = is.readAllBytes();
+ // Keep this implementation up to date with
+ // JarFile::checkForSpecialAttributes
+ int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
+ MULTIRELEASE_OPTOSFT);
+ 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] != ' ')) {
+ return true;
+ } else if (c == '\r') {
+ if (i == b.length) {
+ return true;
+ } else {
+ c = b[i++];
+ if (c == '\n') {
+ if (i == b.length || b[i] != ' ') {
+ return true;
+ }
+ } else if (c != ' ') {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
} catch (IOException x) {
return false;
}
}
+ private static final byte[] MULTIRELEASE_CHARS =
+ {'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':',
+ ' ', 'T', 'R', 'U', 'E'};
+
+ // The bad character shift for "multi-release: true"
+ private static final byte[] MULTIRELEASE_LASTOCC;
+
+ // The good suffix shift for "multi-release: true"
+ private static final byte[] MULTIRELEASE_OPTOSFT;
+
+ static {
+ MULTIRELEASE_LASTOCC = new byte[64];
+ MULTIRELEASE_OPTOSFT = new byte[19];
+ MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1;
+ MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5;
+ MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6;
+ MULTIRELEASE_LASTOCC[(int)'L' - 32] = 9;
+ MULTIRELEASE_LASTOCC[(int)'A' - 32] = 11;
+ MULTIRELEASE_LASTOCC[(int)'S' - 32] = 12;
+ 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;
+ for (int i = 0; i < 17; i++) {
+ MULTIRELEASE_OPTOSFT[i] = 19;
+ }
+ MULTIRELEASE_OPTOSFT[17] = 6;
+ MULTIRELEASE_OPTOSFT[18] = 1;
+ }
+
+ /**
+ * Returns true if the pattern {@code src} is found in {@code b}.
+ * The {@code lastOcc} array is the precomputed bad character shifts.
+ * Since there are no repeated substring in our search strings,
+ * the good suffix shifts can be replaced with a comparison.
+ */
+ private static int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) {
+ int len = src.length;
+ int last = b.length - len;
+ int i = 0;
+ next:
+ while (i <= last) {
+ for (int j = (len - 1); j >= 0; j--) {
+ byte c = b[i + j];
+ if (c >= ' ' && c <= 'z') {
+ if (c >= 'a') c -= 32; // Canonicalize
+
+ if (c != src[j]) {
+ // no match
+ int badShift = lastOcc[c - 32];
+ i += Math.max(j + 1 - badShift, optoSft[j]);
+ continue next;
+ }
+ } else {
+ // no match, character not valid for name
+ i += len;
+ continue next;
+ }
+ }
+ return i;
+ }
+ return -1;
+ }
+
/**
* create a map of aliases for versioned entries, for example:
* version/PackagePrivate.class -> META-INF/versions/9/version/PackagePrivate.class
* version/PackagePrivate.java -> META-INF/versions/9/version/PackagePrivate.java
* version/Version.class -> META-INF/versions/10/version/Version.class
< prev index next >