/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package jdk.internal.util.jar; /** * Simple utility methods for checking Jar file attributes. */ public class JarAttributes { // No can has instance! private JarAttributes() {} // Statics for hand-coded Boyer-Moore search private static final byte[] CLASSPATH_CHARS = {'C','L','A','S','S','-','P','A','T','H', ':', ' '}; // The bad character shift for "class-path: " private static final byte[] CLASSPATH_LASTOCC; // The good suffix shift for "class-path: " private static final byte[] CLASSPATH_OPTOSFT; 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 { CLASSPATH_LASTOCC = new byte[64]; CLASSPATH_OPTOSFT = new byte[12]; CLASSPATH_LASTOCC[(int)'C' - 32] = 1; CLASSPATH_LASTOCC[(int)'L' - 32] = 2; CLASSPATH_LASTOCC[(int)'S' - 32] = 5; CLASSPATH_LASTOCC[(int)'-' - 32] = 6; CLASSPATH_LASTOCC[(int)'P' - 32] = 7; CLASSPATH_LASTOCC[(int)'A' - 32] = 8; CLASSPATH_LASTOCC[(int)'T' - 32] = 9; CLASSPATH_LASTOCC[(int)'H' - 32] = 10; CLASSPATH_LASTOCC[(int)':' - 32] = 11; CLASSPATH_LASTOCC[(int)' ' - 32] = 12; for (int i = 0; i < 11; i++) { CLASSPATH_OPTOSFT[i] = 12; } CLASSPATH_OPTOSFT[11] = 1; 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; } public static boolean hasClassPathAttribute(final byte[] manifestEntry) { return match(CLASSPATH_CHARS, manifestEntry, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1; } public static boolean isMultiRelease(final byte[] manifest) { // is this a multi-release jar file int i = match(MULTIRELEASE_CHARS, manifest, MULTIRELEASE_LASTOCC, MULTIRELEASE_OPTOSFT); if (i != -1) { i += MULTIRELEASE_CHARS.length; if (i < manifest.length) { byte c = manifest[i++]; // Check that the value is followed by a newline // and does not have a continuation if (c == '\n' && (i == manifest.length || manifest[i] != ' ')) { return true; } else if (c == '\r') { if (i == manifest.length) { return true; } else { c = manifest[i++]; if (c == '\n') { if (i == manifest.length || manifest[i] != ' ') { return true; } } else if (c != ' ') { return true; } } } } } return false; } /** * 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; } }