1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.util.jar; 27 28 /** 29 * Simple utility methods for checking Jar file attributes. 30 */ 31 32 public class JarAttributes { 33 34 // No can has instance! 35 private JarAttributes() {} 36 37 // Statics for hand-coded Boyer-Moore search 38 private static final byte[] CLASSPATH_CHARS = 39 {'C','L','A','S','S','-','P','A','T','H', ':', ' '}; 40 41 // The bad character shift for "class-path: " 42 private static final byte[] CLASSPATH_LASTOCC; 43 44 // The good suffix shift for "class-path: " 45 private static final byte[] CLASSPATH_OPTOSFT; 46 47 private static final byte[] MULTIRELEASE_CHARS = 48 {'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':', 49 ' ', 'T', 'R', 'U', 'E'}; 50 51 // The bad character shift for "multi-release: true" 52 private static final byte[] MULTIRELEASE_LASTOCC; 53 54 // The good suffix shift for "multi-release: true" 55 private static final byte[] MULTIRELEASE_OPTOSFT; 56 57 static { 58 CLASSPATH_LASTOCC = new byte[64]; 59 CLASSPATH_OPTOSFT = new byte[12]; 60 CLASSPATH_LASTOCC[(int)'C' - 32] = 1; 61 CLASSPATH_LASTOCC[(int)'L' - 32] = 2; 62 CLASSPATH_LASTOCC[(int)'S' - 32] = 5; 63 CLASSPATH_LASTOCC[(int)'-' - 32] = 6; 64 CLASSPATH_LASTOCC[(int)'P' - 32] = 7; 65 CLASSPATH_LASTOCC[(int)'A' - 32] = 8; 66 CLASSPATH_LASTOCC[(int)'T' - 32] = 9; 67 CLASSPATH_LASTOCC[(int)'H' - 32] = 10; 68 CLASSPATH_LASTOCC[(int)':' - 32] = 11; 69 CLASSPATH_LASTOCC[(int)' ' - 32] = 12; 70 for (int i = 0; i < 11; i++) { 71 CLASSPATH_OPTOSFT[i] = 12; 72 } 73 CLASSPATH_OPTOSFT[11] = 1; 74 75 MULTIRELEASE_LASTOCC = new byte[64]; 76 MULTIRELEASE_OPTOSFT = new byte[19]; 77 MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1; 78 MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5; 79 MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6; 80 MULTIRELEASE_LASTOCC[(int)'L' - 32] = 9; 81 MULTIRELEASE_LASTOCC[(int)'A' - 32] = 11; 82 MULTIRELEASE_LASTOCC[(int)'S' - 32] = 12; 83 MULTIRELEASE_LASTOCC[(int)':' - 32] = 14; 84 MULTIRELEASE_LASTOCC[(int)' ' - 32] = 15; 85 MULTIRELEASE_LASTOCC[(int)'T' - 32] = 16; 86 MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17; 87 MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18; 88 MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19; 89 for (int i = 0; i < 17; i++) { 90 MULTIRELEASE_OPTOSFT[i] = 19; 91 } 92 MULTIRELEASE_OPTOSFT[17] = 6; 93 MULTIRELEASE_OPTOSFT[18] = 1; 94 } 95 96 public static boolean hasClassPathAttribute(final byte[] manifestEntry) { 97 return match(CLASSPATH_CHARS, manifestEntry, 98 CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1; 99 } 100 101 public static boolean isMultiRelease(final byte[] manifest) { 102 // is this a multi-release jar file 103 int i = match(MULTIRELEASE_CHARS, manifest, MULTIRELEASE_LASTOCC, 104 MULTIRELEASE_OPTOSFT); 105 if (i != -1) { 106 i += MULTIRELEASE_CHARS.length; 107 if (i < manifest.length) { 108 byte c = manifest[i++]; 109 // Check that the value is followed by a newline 110 // and does not have a continuation 111 if (c == '\n' && 112 (i == manifest.length || manifest[i] != ' ')) { 113 return true; 114 } else if (c == '\r') { 115 if (i == manifest.length) { 116 return true; 117 } else { 118 c = manifest[i++]; 119 if (c == '\n') { 120 if (i == manifest.length || manifest[i] != ' ') { 121 return true; 122 } 123 } else if (c != ' ') { 124 return true; 125 } 126 } 127 } 128 } 129 } 130 return false; 131 } 132 /** 133 * Returns true if the pattern {@code src} is found in {@code b}. 134 * The {@code lastOcc} array is the precomputed bad character shifts. 135 * Since there are no repeated substring in our search strings, 136 * the good suffix shifts can be replaced with a comparison. 137 */ 138 private static int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) { 139 int len = src.length; 140 int last = b.length - len; 141 int i = 0; 142 next: 143 while (i <= last) { 144 for (int j = (len - 1); j >= 0; j--) { 145 byte c = b[i + j]; 146 if (c >= ' ' && c <= 'z') { 147 if (c >= 'a') c -= 32; // Canonicalize 148 149 if (c != src[j]) { 150 // no match 151 int badShift = lastOcc[c - 32]; 152 i += Math.max(j + 1 - badShift, optoSft[j]); 153 continue next; 154 } 155 } else { 156 // no match, character not valid for name 157 i += len; 158 continue next; 159 } 160 } 161 return i; 162 } 163 return -1; 164 } 165 }