Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java
38899 views
/*1* Copyright (c) 2012, 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*/24package com.sun.tools.jdeps;2526import com.sun.tools.classfile.ClassFile;27import com.sun.tools.classfile.ConstantPoolException;28import com.sun.tools.classfile.Dependencies.ClassFileError;29import java.io.*;30import java.nio.file.FileVisitResult;31import java.nio.file.Files;32import java.nio.file.Path;33import java.nio.file.SimpleFileVisitor;34import java.nio.file.attribute.BasicFileAttributes;35import java.util.*;36import java.util.jar.Attributes;37import java.util.jar.JarEntry;38import java.util.jar.JarFile;39import java.util.jar.Manifest;4041/**42* ClassFileReader reads ClassFile(s) of a given path that can be43* a .class file, a directory, or a JAR file.44*/45public class ClassFileReader {46/**47* Returns a ClassFileReader instance of a given path.48*/49public static ClassFileReader newInstance(Path path) throws IOException {50if (!Files.exists(path)) {51throw new FileNotFoundException(path.toString());52}5354if (Files.isDirectory(path)) {55return new DirectoryReader(path);56} else if (path.getFileName().toString().endsWith(".jar")) {57return new JarFileReader(path);58} else {59return new ClassFileReader(path);60}61}6263/**64* Returns a ClassFileReader instance of a given JarFile.65*/66public static ClassFileReader newInstance(Path path, JarFile jf) throws IOException {67return new JarFileReader(path, jf);68}6970protected final Path path;71protected final String baseFileName;72protected final List<String> skippedEntries = new ArrayList<>();73protected ClassFileReader(Path path) {74this.path = path;75this.baseFileName = path.getFileName() != null76? path.getFileName().toString()77: path.toString();78}7980public String getFileName() {81return baseFileName;82}8384public List<String> skippedEntries() {85return skippedEntries;86}8788/**89* Returns the ClassFile matching the given binary name90* or a fully-qualified class name.91*/92public ClassFile getClassFile(String name) throws IOException {93if (name.indexOf('.') > 0) {94int i = name.lastIndexOf('.');95String pathname = name.replace('.', File.separatorChar) + ".class";96if (baseFileName.equals(pathname) ||97baseFileName.equals(pathname.substring(0, i) + "$" +98pathname.substring(i+1, pathname.length()))) {99return readClassFile(path);100}101} else {102if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) {103return readClassFile(path);104}105}106return null;107}108109public Iterable<ClassFile> getClassFiles() throws IOException {110return new Iterable<ClassFile>() {111public Iterator<ClassFile> iterator() {112return new FileIterator();113}114};115}116117protected ClassFile readClassFile(Path p) throws IOException {118InputStream is = null;119try {120is = Files.newInputStream(p);121return ClassFile.read(is);122} catch (ConstantPoolException e) {123throw new ClassFileError(e);124} finally {125if (is != null) {126is.close();127}128}129}130131class FileIterator implements Iterator<ClassFile> {132int count;133FileIterator() {134this.count = 0;135}136public boolean hasNext() {137return count == 0 && baseFileName.endsWith(".class");138}139140public ClassFile next() {141if (!hasNext()) {142throw new NoSuchElementException();143}144try {145ClassFile cf = readClassFile(path);146count++;147return cf;148} catch (IOException e) {149throw new ClassFileError(e);150}151}152153public void remove() {154throw new UnsupportedOperationException("Not supported yet.");155}156}157158public boolean isMultiReleaseJar() throws IOException { return false; }159160public String toString() {161return path.toString();162}163164private static class DirectoryReader extends ClassFileReader {165DirectoryReader(Path path) throws IOException {166super(path);167}168169public ClassFile getClassFile(String name) throws IOException {170if (name.indexOf('.') > 0) {171int i = name.lastIndexOf('.');172String pathname = name.replace('.', File.separatorChar) + ".class";173Path p = path.resolve(pathname);174if (!Files.exists(p)) {175p = path.resolve(pathname.substring(0, i) + "$" +176pathname.substring(i+1, pathname.length()));177}178if (Files.exists(p)) {179return readClassFile(p);180}181} else {182Path p = path.resolve(name + ".class");183if (Files.exists(p)) {184return readClassFile(p);185}186}187return null;188}189190public Iterable<ClassFile> getClassFiles() throws IOException {191final Iterator<ClassFile> iter = new DirectoryIterator();192return new Iterable<ClassFile>() {193public Iterator<ClassFile> iterator() {194return iter;195}196};197}198199private List<Path> walkTree(Path dir) throws IOException {200final List<Path> files = new ArrayList<Path>();201Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {202public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)203throws IOException {204if (file.getFileName().toString().endsWith(".class")) {205files.add(file);206}207return FileVisitResult.CONTINUE;208}209});210return files;211}212213class DirectoryIterator implements Iterator<ClassFile> {214private List<Path> entries;215private int index = 0;216DirectoryIterator() throws IOException {217entries = walkTree(path);218index = 0;219}220221public boolean hasNext() {222return index != entries.size();223}224225public ClassFile next() {226if (!hasNext()) {227throw new NoSuchElementException();228}229Path path = entries.get(index++);230try {231return readClassFile(path);232} catch (IOException e) {233throw new ClassFileError(e);234}235}236237public void remove() {238throw new UnsupportedOperationException("Not supported yet.");239}240}241}242243static class JarFileReader extends ClassFileReader {244private final JarFile jarfile;245JarFileReader(Path path) throws IOException {246this(path, new JarFile(path.toFile(), false));247}248249JarFileReader(Path path, JarFile jf) throws IOException {250super(path);251this.jarfile = jf;252}253254public ClassFile getClassFile(String name) throws IOException {255if (name.indexOf('.') > 0) {256int i = name.lastIndexOf('.');257String entryName = name.replace('.', '/') + ".class";258JarEntry e = jarfile.getJarEntry(entryName);259if (e == null) {260e = jarfile.getJarEntry(entryName.substring(0, i) + "$"261+ entryName.substring(i + 1, entryName.length()));262}263if (e != null) {264return readClassFile(jarfile, e);265}266} else {267JarEntry e = jarfile.getJarEntry(name + ".class");268if (e != null) {269return readClassFile(jarfile, e);270}271}272return null;273}274275protected ClassFile readClassFile(JarFile jarfile, JarEntry e) throws IOException {276InputStream is = null;277try {278is = jarfile.getInputStream(e);279return ClassFile.read(is);280} catch (ConstantPoolException ex) {281throw new ClassFileError(ex);282} finally {283if (is != null)284is.close();285}286}287288public Iterable<ClassFile> getClassFiles() throws IOException {289final Iterator<ClassFile> iter = new JarFileIterator(this, jarfile);290return new Iterable<ClassFile>() {291public Iterator<ClassFile> iterator() {292return iter;293}294};295}296297@Override298public boolean isMultiReleaseJar() throws IOException {299Manifest mf = this.jarfile.getManifest();300if (mf != null) {301Attributes atts = mf.getMainAttributes();302return "true".equalsIgnoreCase(atts.getValue("Multi-Release"));303}304return false;305}306}307308class JarFileIterator implements Iterator<ClassFile> {309protected final JarFileReader reader;310protected Enumeration<JarEntry> entries;311protected JarFile jf;312protected JarEntry nextEntry;313protected ClassFile cf;314JarFileIterator(JarFileReader reader) {315this(reader, null);316}317JarFileIterator(JarFileReader reader, JarFile jarfile) {318this.reader = reader;319setJarFile(jarfile);320}321322void setJarFile(JarFile jarfile) {323if (jarfile == null) return;324325this.jf = jarfile;326this.entries = jf.entries();327this.nextEntry = nextEntry();328}329330public boolean hasNext() {331if (nextEntry != null && cf != null) {332return true;333}334while (nextEntry != null) {335try {336cf = reader.readClassFile(jf, nextEntry);337return true;338} catch (ClassFileError | IOException ex) {339skippedEntries.add(nextEntry.getName());340}341nextEntry = nextEntry();342}343return false;344}345346public ClassFile next() {347if (!hasNext()) {348throw new NoSuchElementException();349}350ClassFile classFile = cf;351cf = null;352nextEntry = nextEntry();353return classFile;354}355356protected JarEntry nextEntry() {357while (entries.hasMoreElements()) {358JarEntry e = entries.nextElement();359String name = e.getName();360if (name.endsWith(".class")) {361return e;362}363}364return null;365}366367public void remove() {368throw new UnsupportedOperationException("Not supported yet.");369}370}371}372373374