Path: blob/master/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java
41159 views
/*1* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.jimage;2627import java.nio.ByteBuffer;28import java.util.Objects;2930/**31* @implNote This class needs to maintain JDK 8 source compatibility.32*33* It is used internally in the JDK to implement jimage/jrtfs access,34* but also compiled and delivered as part of the jrtfs.jar to support access35* to the jimage file provided by the shipped JDK by tools running on JDK 8.36*/37public class ImageLocation {38public static final int ATTRIBUTE_END = 0;39public static final int ATTRIBUTE_MODULE = 1;40public static final int ATTRIBUTE_PARENT = 2;41public static final int ATTRIBUTE_BASE = 3;42public static final int ATTRIBUTE_EXTENSION = 4;43public static final int ATTRIBUTE_OFFSET = 5;44public static final int ATTRIBUTE_COMPRESSED = 6;45public static final int ATTRIBUTE_UNCOMPRESSED = 7;46public static final int ATTRIBUTE_COUNT = 8;4748protected final long[] attributes;4950protected final ImageStrings strings;5152public ImageLocation(long[] attributes, ImageStrings strings) {53this.attributes = Objects.requireNonNull(attributes);54this.strings = Objects.requireNonNull(strings);55}5657ImageStrings getStrings() {58return strings;59}6061static long[] decompress(ByteBuffer bytes, int offset) {62Objects.requireNonNull(bytes);63long[] attributes = new long[ATTRIBUTE_COUNT];6465int limit = bytes.limit();66while (offset < limit) {67int data = bytes.get(offset++) & 0xFF;68if (data <= 0x7) { // ATTRIBUTE_END69break;70}71int kind = data >>> 3;72if (ATTRIBUTE_COUNT <= kind) {73throw new InternalError(74"Invalid jimage attribute kind: " + kind);75}7677int length = (data & 0x7) + 1;78attributes[kind] = readValue(length, bytes, offset, limit);79offset += length;80}81return attributes;82}8384public static byte[] compress(long[] attributes) {85Objects.requireNonNull(attributes);86ImageStream stream = new ImageStream(16);8788for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {89long value = attributes[kind];9091if (value != 0) {92int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;93stream.put((kind << 3) | n);9495for (int i = n; i >= 0; i--) {96stream.put((int)(value >> (i << 3)));97}98}99}100101stream.put(ATTRIBUTE_END << 3);102103return stream.toArray();104}105106public boolean verify(String name) {107return verify(name, attributes, strings);108}109110/**111* A simpler verification would be {@code name.equals(getFullName())}, but112* by not creating the full name and enabling early returns we allocate113* fewer objects.114*/115static boolean verify(String name, long[] attributes, ImageStrings strings) {116Objects.requireNonNull(name);117final int length = name.length();118int index = 0;119int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];120if (moduleOffset != 0 && length >= 1) {121int moduleLen = strings.match(moduleOffset, name, 1);122index = moduleLen + 1;123if (moduleLen < 0124|| length <= index125|| name.charAt(0) != '/'126|| name.charAt(index++) != '/') {127return false;128}129}130return verifyName(null, name, index, length, 0,131(int) attributes[ATTRIBUTE_PARENT],132(int) attributes[ATTRIBUTE_BASE],133(int) attributes[ATTRIBUTE_EXTENSION],134strings);135}136137static boolean verify(String module, String name, ByteBuffer locations,138int locationOffset, ImageStrings strings) {139int moduleOffset = 0;140int parentOffset = 0;141int baseOffset = 0;142int extOffset = 0;143144int limit = locations.limit();145while (locationOffset < limit) {146int data = locations.get(locationOffset++) & 0xFF;147if (data <= 0x7) { // ATTRIBUTE_END148break;149}150int kind = data >>> 3;151if (ATTRIBUTE_COUNT <= kind) {152throw new InternalError(153"Invalid jimage attribute kind: " + kind);154}155156int length = (data & 0x7) + 1;157switch (kind) {158case ATTRIBUTE_MODULE:159moduleOffset = (int) readValue(length, locations, locationOffset, limit);160break;161case ATTRIBUTE_BASE:162baseOffset = (int) readValue(length, locations, locationOffset, limit);163break;164case ATTRIBUTE_PARENT:165parentOffset = (int) readValue(length, locations, locationOffset, limit);166break;167case ATTRIBUTE_EXTENSION:168extOffset = (int) readValue(length, locations, locationOffset, limit);169break;170}171locationOffset += length;172}173return verifyName(module, name, 0, name.length(),174moduleOffset, parentOffset, baseOffset, extOffset, strings);175}176177private static long readValue(int length, ByteBuffer buffer, int offset, int limit) {178long value = 0;179for (int j = 0; j < length; j++) {180value <<= 8;181if (offset >= limit) {182throw new InternalError("Missing jimage attribute data");183}184value |= buffer.get(offset++) & 0xFF;185}186return value;187}188189static boolean verify(String module, String name, long[] attributes,190ImageStrings strings) {191Objects.requireNonNull(module);192Objects.requireNonNull(name);193return verifyName(module, name, 0, name.length(),194(int) attributes[ATTRIBUTE_MODULE],195(int) attributes[ATTRIBUTE_PARENT],196(int) attributes[ATTRIBUTE_BASE],197(int) attributes[ATTRIBUTE_EXTENSION],198strings);199}200201private static boolean verifyName(String module, String name, int index, int length,202int moduleOffset, int parentOffset, int baseOffset, int extOffset, ImageStrings strings) {203204if (moduleOffset != 0) {205if (strings.match(moduleOffset, module, 0) != module.length()) {206return false;207}208}209if (parentOffset != 0) {210int parentLen = strings.match(parentOffset, name, index);211if (parentLen < 0) {212return false;213}214index += parentLen;215if (length <= index || name.charAt(index++) != '/') {216return false;217}218}219int baseLen = strings.match(baseOffset, name, index);220if (baseLen < 0) {221return false;222}223index += baseLen;224if (extOffset != 0) {225if (length <= index226|| name.charAt(index++) != '.') {227return false;228}229230int extLen = strings.match(extOffset, name, index);231if (extLen < 0) {232return false;233}234index += extLen;235}236return length == index;237}238239long getAttribute(int kind) {240if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {241throw new InternalError(242"Invalid jimage attribute kind: " + kind);243}244return attributes[kind];245}246247String getAttributeString(int kind) {248if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {249throw new InternalError(250"Invalid jimage attribute kind: " + kind);251}252return getStrings().get((int)attributes[kind]);253}254255public String getModule() {256return getAttributeString(ATTRIBUTE_MODULE);257}258259public int getModuleOffset() {260return (int)getAttribute(ATTRIBUTE_MODULE);261}262263public String getBase() {264return getAttributeString(ATTRIBUTE_BASE);265}266267public int getBaseOffset() {268return (int)getAttribute(ATTRIBUTE_BASE);269}270271public String getParent() {272return getAttributeString(ATTRIBUTE_PARENT);273}274275public int getParentOffset() {276return (int)getAttribute(ATTRIBUTE_PARENT);277}278279public String getExtension() {280return getAttributeString(ATTRIBUTE_EXTENSION);281}282283public int getExtensionOffset() {284return (int)getAttribute(ATTRIBUTE_EXTENSION);285}286287public String getFullName() {288return getFullName(false);289}290291public String getFullName(boolean modulesPrefix) {292StringBuilder builder = new StringBuilder();293294if (getModuleOffset() != 0) {295if (modulesPrefix) {296builder.append("/modules");297}298299builder.append('/');300builder.append(getModule());301builder.append('/');302}303304if (getParentOffset() != 0) {305builder.append(getParent());306builder.append('/');307}308309builder.append(getBase());310311if (getExtensionOffset() != 0) {312builder.append('.');313builder.append(getExtension());314}315316return builder.toString();317}318319String buildName(boolean includeModule, boolean includeParent,320boolean includeName) {321StringBuilder builder = new StringBuilder();322323if (includeModule && getModuleOffset() != 0) {324builder.append("/modules/");325builder.append(getModule());326}327328if (includeParent && getParentOffset() != 0) {329builder.append('/');330builder.append(getParent());331}332333if (includeName) {334if (includeModule || includeParent) {335builder.append('/');336}337338builder.append(getBase());339340if (getExtensionOffset() != 0) {341builder.append('.');342builder.append(getExtension());343}344}345346return builder.toString();347}348349public long getContentOffset() {350return getAttribute(ATTRIBUTE_OFFSET);351}352353public long getCompressedSize() {354return getAttribute(ATTRIBUTE_COMPRESSED);355}356357public long getUncompressedSize() {358return getAttribute(ATTRIBUTE_UNCOMPRESSED);359}360361static ImageLocation readFrom(BasicImageReader reader, int offset) {362Objects.requireNonNull(reader);363long[] attributes = reader.getAttributes(offset);364ImageStringsReader strings = reader.getStrings();365366return new ImageLocation(attributes, strings);367}368}369370371