/* * Copyright (c) 2015, 2016, 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.jimage.decompressor; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Objects; import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider; /** * * A resource header for compressed resource. This class is handled internally, * you don't have to add header to the resource, headers are added automatically * for compressed resources. * * @implNote This class needs to maintain JDK 8 source compatibility. * * It is used internally in the JDK to implement jimage/jrtfs access, * but also compiled and delivered as part of the jrtfs.jar to support access * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public final class CompressedResourceHeader { private static final int SIZE = 29; public static final int MAGIC = 0xCAFEFAFA; private final long uncompressedSize; private final long compressedSize; private final int decompressorNameOffset; private final int contentOffset; private final boolean isTerminal; public CompressedResourceHeader(long compressedSize, long uncompressedSize, int decompressorNameOffset, int contentOffset, boolean isTerminal) { this.compressedSize = compressedSize; this.uncompressedSize = uncompressedSize; this.decompressorNameOffset = decompressorNameOffset; this.contentOffset = contentOffset; this.isTerminal = isTerminal; } public boolean isTerminal() { return isTerminal; } public int getDecompressorNameOffset() { return decompressorNameOffset; } public int getContentOffset() { return contentOffset; } public String getStoredContent(StringsProvider provider) { Objects.requireNonNull(provider); if(contentOffset == -1) { return null; } return provider.getString(contentOffset); } public long getUncompressedSize() { return uncompressedSize; } public long getResourceSize() { return compressedSize; } public byte[] getBytes(ByteOrder order) { Objects.requireNonNull(order); ByteBuffer buffer = ByteBuffer.allocate(SIZE); buffer.order(order); buffer.putInt(MAGIC); buffer.putLong(compressedSize); buffer.putLong(uncompressedSize); buffer.putInt(decompressorNameOffset); buffer.putInt(contentOffset); buffer.put(isTerminal ? (byte)1 : (byte)0); return buffer.array(); } public static int getSize() { return SIZE; } public static CompressedResourceHeader readFromResource(ByteOrder order, byte[] resource) { Objects.requireNonNull(order); Objects.requireNonNull(resource); if (resource.length < getSize()) { return null; } ByteBuffer buffer = ByteBuffer.wrap(resource, 0, SIZE); buffer.order(order); int magic = buffer.getInt(); if(magic != MAGIC) { return null; } long size = buffer.getLong(); long uncompressedSize = buffer.getLong(); int decompressorNameOffset = buffer.getInt(); int contentIndex = buffer.getInt(); byte isTerminal = buffer.get(); return new CompressedResourceHeader(size, uncompressedSize, decompressorNameOffset, contentIndex, isTerminal == 1); } }