Path: blob/master/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java
41159 views
/*1* Copyright (c) 2016, 2017, 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.jmod;2627import java.io.IOException;28import java.io.InputStream;29import java.io.OutputStream;30import java.nio.file.Files;31import java.nio.file.Path;32import java.util.Arrays;33import java.util.Map;34import java.util.function.Function;35import java.util.stream.Collectors;36import java.util.stream.Stream;37import java.util.zip.ZipEntry;38import java.util.zip.ZipFile;3940/**41* Helper class to read JMOD file42*/43public class JmodFile implements AutoCloseable {44// jmod magic number and version number45private static final int JMOD_MAJOR_VERSION = 0x01;46private static final int JMOD_MINOR_VERSION = 0x00;47private static final byte[] JMOD_MAGIC_NUMBER = {480x4A, 0x4D, /* JM */49JMOD_MAJOR_VERSION, JMOD_MINOR_VERSION, /* version 1.0 */50};5152public static void checkMagic(Path file) throws IOException {53try (InputStream in = Files.newInputStream(file)) {54// validate the header55byte[] magic = in.readNBytes(4);56if (magic.length != 4) {57throw new IOException("Invalid JMOD file: " + file);58}59if (magic[0] != JMOD_MAGIC_NUMBER[0] ||60magic[1] != JMOD_MAGIC_NUMBER[1]) {61throw new IOException("Invalid JMOD file: " + file.toString());62}63if (magic[2] > JMOD_MAJOR_VERSION ||64(magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {65throw new IOException("Unsupported jmod version: " +66magic[2] + "." + magic[3] + " in " + file.toString());67}68}69}7071/**72* JMOD sections73*/74public static enum Section {75CLASSES("classes"),76CONFIG("conf"),77HEADER_FILES("include"),78LEGAL_NOTICES("legal"),79MAN_PAGES("man"),80NATIVE_LIBS("lib"),81NATIVE_CMDS("bin");8283private final String jmodDir;84private Section(String jmodDir) {85this.jmodDir = jmodDir;86}8788/**89* Returns the directory name in the JMOD file corresponding to90* this section91*/92public String jmodDir() { return jmodDir; }93}9495/**96* JMOD file entry.97*98* Each entry corresponds to a ZipEntry whose name is:99* Section::jmodDir + '/' + name100*/101public static class Entry {102private final ZipEntry zipEntry;103private final Section section;104private final String name;105106private Entry(ZipEntry e) {107String name = e.getName();108int i = name.indexOf('/');109if (i <= 1) {110throw new RuntimeException("invalid jmod entry: " + name);111}112113this.zipEntry = e;114this.section = section(name.substring(0, i));115this.name = name.substring(i+1);116}117118/**119* Returns the section of this entry.120*/121public Section section() {122return section;123}124125/**126* Returns the name of this entry.127*/128public String name() {129return name;130}131132/**133* Returns true if the entry is a directory in the JMOD file.134*/135public boolean isDirectory() {136return zipEntry.isDirectory();137}138139/**140* Returns the size of this entry.141*/142public long size() {143return zipEntry.getSize();144}145146public ZipEntry zipEntry() {147return zipEntry;148}149150@Override151public String toString() {152return section.jmodDir() + "/" + name;153}154155/*156* A map from the jmodDir name to Section157*/158static final Map<String, Section> NAME_TO_SECTION =159Arrays.stream(Section.values())160.collect(Collectors.toMap(Section::jmodDir, Function.identity()));161162static Section section(String name) {163if (!NAME_TO_SECTION.containsKey(name)) {164throw new IllegalArgumentException("invalid section: " + name);165166}167return NAME_TO_SECTION.get(name);168}169170}171172private final Path file;173private final ZipFile zipfile;174175/**176* Constructs a {@code JmodFile} from a given path.177*/178public JmodFile(Path file) throws IOException {179checkMagic(file);180this.file = file;181this.zipfile = new ZipFile(file.toFile());182}183184public static void writeMagicNumber(OutputStream os) throws IOException {185os.write(JMOD_MAGIC_NUMBER);186}187188/**189* Returns the {@code Entry} for a resource in a JMOD file section190* or {@code null} if not found.191*/192public Entry getEntry(Section section, String name) {193String entry = section.jmodDir() + "/" + name;194ZipEntry ze = zipfile.getEntry(entry);195return (ze != null) ? new Entry(ze) : null;196}197198/**199* Opens an {@code InputStream} for reading the named entry of the given200* section in this JMOD file.201*202* @throws IOException if the named entry is not found, or I/O error203* occurs when reading it204*/205public InputStream getInputStream(Section section, String name)206throws IOException207{208String entry = section.jmodDir() + "/" + name;209ZipEntry e = zipfile.getEntry(entry);210if (e == null) {211throw new IOException(name + " not found: " + file);212}213return zipfile.getInputStream(e);214}215216/**217* Opens an {@code InputStream} for reading an entry in the JMOD file.218*219* @throws IOException if an I/O error occurs220*/221public InputStream getInputStream(Entry entry) throws IOException {222return zipfile.getInputStream(entry.zipEntry());223}224225/**226* Returns a stream of entries in this JMOD file.227*/228public Stream<Entry> stream() {229return zipfile.stream()230.map(Entry::new);231}232233@Override234public void close() throws IOException {235if (zipfile != null) {236zipfile.close();237}238}239}240241242