< prev index next >

src/java.base/share/classes/java/util/jar/JarFile.java

Print this page
rev 16859 : 8176709: JarFileSystem::isMultiReleaseJar is incorrect
Reviewed-by: alanb, sherman, psandoz, mchung


 908                     : new JarFileEntry(manEntry.getName(), manEntry);
 909         }
 910         return manEntry;
 911     }
 912 
 913    /**
 914     * Returns {@code true} iff this JAR file has a manifest with the
 915     * Class-Path attribute
 916     */
 917     boolean hasClassPathAttribute() throws IOException {
 918         checkForSpecialAttributes();
 919         return hasClassPathAttribute;
 920     }
 921 
 922     /**
 923      * Returns true if the pattern {@code src} is found in {@code b}.
 924      * The {@code lastOcc} array is the precomputed bad character shifts.
 925      * Since there are no repeated substring in our search strings,
 926      * the good suffix shifts can be replaced with a comparison.
 927      */
 928     private int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) {
 929         int len = src.length;
 930         int last = b.length - len;
 931         int i = 0;
 932         next:
 933         while (i <= last) {
 934             for (int j = (len - 1); j >= 0; j--) {
 935                 byte c = b[i + j];
 936                 if (c >= ' ' && c <= 'z') {
 937                     if (c >= 'a') c -= 32; // Canonicalize
 938 
 939                     if (c != src[j]) {
 940                         // no match
 941                         int badShift = lastOcc[c - 32];
 942                         i += Math.max(j + 1 - badShift, optoSft[j]);
 943                         continue next;
 944                     }
 945                 } else {
 946                     // no match, character not valid for name
 947                     i += len;
 948                     continue next;


 955 
 956     /**
 957      * On first invocation, check if the JAR file has the Class-Path
 958      * and the Multi-Release attribute. A no-op on subsequent calls.
 959      */
 960     private void checkForSpecialAttributes() throws IOException {
 961         if (hasCheckedSpecialAttributes) {
 962             return;
 963         }
 964         synchronized (this) {
 965             if (hasCheckedSpecialAttributes) {
 966                 return;
 967             }
 968             JarEntry manEntry = getManEntry();
 969             if (manEntry != null) {
 970                 byte[] b = getBytes(manEntry);
 971                 hasClassPathAttribute = match(CLASSPATH_CHARS, b,
 972                         CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1;
 973                 // is this a multi-release jar file
 974                 if (MULTI_RELEASE_ENABLED) {


 975                     int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
 976                             MULTIRELEASE_OPTOSFT);
 977                     if (i != -1) {
 978                         i += MULTIRELEASE_CHARS.length;
 979                         if (i < b.length) {
 980                             byte c = b[i++];
 981                             // Check that the value is followed by a newline
 982                             // and does not have a continuation
 983                             if (c == '\n' &&
 984                                     (i == b.length || b[i] != ' ')) {
 985                                 isMultiRelease = true;
 986                             } else if (c == '\r') {
 987                                 if (i == b.length) {
 988                                     isMultiRelease = true;
 989                                 } else {
 990                                     c = b[i++];
 991                                     if (c == '\n') {
 992                                         if (i == b.length || b[i] != ' ') {
 993                                             isMultiRelease = true;
 994                                         }




 908                     : new JarFileEntry(manEntry.getName(), manEntry);
 909         }
 910         return manEntry;
 911     }
 912 
 913    /**
 914     * Returns {@code true} iff this JAR file has a manifest with the
 915     * Class-Path attribute
 916     */
 917     boolean hasClassPathAttribute() throws IOException {
 918         checkForSpecialAttributes();
 919         return hasClassPathAttribute;
 920     }
 921 
 922     /**
 923      * Returns true if the pattern {@code src} is found in {@code b}.
 924      * The {@code lastOcc} array is the precomputed bad character shifts.
 925      * Since there are no repeated substring in our search strings,
 926      * the good suffix shifts can be replaced with a comparison.
 927      */
 928     private static int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) {
 929         int len = src.length;
 930         int last = b.length - len;
 931         int i = 0;
 932         next:
 933         while (i <= last) {
 934             for (int j = (len - 1); j >= 0; j--) {
 935                 byte c = b[i + j];
 936                 if (c >= ' ' && c <= 'z') {
 937                     if (c >= 'a') c -= 32; // Canonicalize
 938 
 939                     if (c != src[j]) {
 940                         // no match
 941                         int badShift = lastOcc[c - 32];
 942                         i += Math.max(j + 1 - badShift, optoSft[j]);
 943                         continue next;
 944                     }
 945                 } else {
 946                     // no match, character not valid for name
 947                     i += len;
 948                     continue next;


 955 
 956     /**
 957      * On first invocation, check if the JAR file has the Class-Path
 958      * and the Multi-Release attribute. A no-op on subsequent calls.
 959      */
 960     private void checkForSpecialAttributes() throws IOException {
 961         if (hasCheckedSpecialAttributes) {
 962             return;
 963         }
 964         synchronized (this) {
 965             if (hasCheckedSpecialAttributes) {
 966                 return;
 967             }
 968             JarEntry manEntry = getManEntry();
 969             if (manEntry != null) {
 970                 byte[] b = getBytes(manEntry);
 971                 hasClassPathAttribute = match(CLASSPATH_CHARS, b,
 972                         CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1;
 973                 // is this a multi-release jar file
 974                 if (MULTI_RELEASE_ENABLED) {
 975                     // Keep this implementation up to date with 
 976                     // JarFileSystem::isMultiReleaseJar
 977                     int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
 978                             MULTIRELEASE_OPTOSFT);
 979                     if (i != -1) {
 980                         i += MULTIRELEASE_CHARS.length;
 981                         if (i < b.length) {
 982                             byte c = b[i++];
 983                             // Check that the value is followed by a newline
 984                             // and does not have a continuation
 985                             if (c == '\n' &&
 986                                     (i == b.length || b[i] != ' ')) {
 987                                 isMultiRelease = true;
 988                             } else if (c == '\r') {
 989                                 if (i == b.length) {
 990                                     isMultiRelease = true;
 991                                 } else {
 992                                     c = b[i++];
 993                                     if (c == '\n') {
 994                                         if (i == b.length || b[i] != ' ') {
 995                                             isMultiRelease = true;
 996                                         }


< prev index next >