6338N/A/*
6338N/A * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
6338N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6338N/A *
6338N/A * This code is free software; you can redistribute it and/or modify it
6338N/A * under the terms of the GNU General Public License version 2 only, as
6338N/A * published by the Free Software Foundation.
6338N/A *
6338N/A * This code is distributed in the hope that it will be useful, but WITHOUT
6338N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6338N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
6338N/A * version 2 for more details (a copy is included in the LICENSE file that
6338N/A * accompanied this code).
6338N/A *
6338N/A * You should have received a copy of the GNU General Public License version
6338N/A * 2 along with this work; if not, write to the Free Software Foundation,
6338N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
6338N/A *
6338N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
6338N/A * or visit www.oracle.com if you need additional information or have any
6338N/A * questions.
6338N/A */
6338N/A
6338N/Aimport com.sun.tools.classfile.ClassFile;
6338N/Aimport com.sun.tools.classfile.ConstantPoolException;
6338N/Aimport java.io.*;
6338N/Aimport java.nio.file.FileVisitResult;
6338N/Aimport java.nio.file.Files;
6338N/Aimport java.nio.file.Path;
6338N/Aimport java.nio.file.SimpleFileVisitor;
6338N/Aimport java.nio.file.attribute.BasicFileAttributes;
6338N/Aimport java.util.*;
6338N/Aimport java.util.jar.JarEntry;
6338N/Aimport java.util.jar.JarFile;
6338N/A
6338N/A/**
6338N/A * ClassFileReader reads ClassFile(s) of a given path that can be
6338N/A * a .class file, a directory, or a JAR file.
6338N/A */
6338N/Apublic class ClassFileReader {
6338N/A /**
6338N/A * Returns a ClassFileReader instance of a given path.
6338N/A */
6338N/A public static ClassFileReader newInstance(File path) throws IOException {
6338N/A if (!path.exists()) {
6338N/A throw new FileNotFoundException(path.getAbsolutePath());
6338N/A }
6338N/A
6338N/A if (path.isDirectory()) {
6338N/A return new DirectoryReader(path.toPath());
6338N/A } else if (path.getName().endsWith(".jar")) {
6338N/A return new JarFileReader(path.toPath());
6338N/A } else {
6338N/A return new ClassFileReader(path.toPath());
6338N/A }
6338N/A }
6338N/A
6338N/A /**
6338N/A * Returns a ClassFileReader instance of a given JarFile.
6338N/A */
6338N/A public static ClassFileReader newInstance(Path path, JarFile jf) throws IOException {
6338N/A return new JarFileReader(path, jf);
6338N/A }
6338N/A
6338N/A protected final Path path;
6338N/A protected final String baseFileName;
6338N/A private ClassFileReader(Path path) {
6338N/A this.path = path;
6338N/A this.baseFileName = path.getFileName() != null
6338N/A ? path.getFileName().toString()
6338N/A : path.toString();
6338N/A }
6338N/A
6338N/A public String getFileName() {
6338N/A return baseFileName;
6338N/A }
6338N/A
6338N/A /**
6338N/A * Returns the ClassFile matching the given binary name
6338N/A * or a fully-qualified class name.
6338N/A */
6338N/A public ClassFile getClassFile(String name) throws IOException {
6338N/A if (name.indexOf('.') > 0) {
6338N/A int i = name.lastIndexOf('.');
6338N/A String pathname = name.replace('.', File.separatorChar) + ".class";
6338N/A if (baseFileName.equals(pathname) ||
6338N/A baseFileName.equals(pathname.substring(0, i) + "$" +
6338N/A pathname.substring(i+1, pathname.length()))) {
6338N/A return readClassFile(path);
6338N/A }
6338N/A } else {
6338N/A if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) {
6338N/A return readClassFile(path);
6338N/A }
6338N/A }
6338N/A return null;
6338N/A }
6338N/A
6338N/A public Iterable<ClassFile> getClassFiles() throws IOException {
6338N/A return new Iterable<ClassFile>() {
6338N/A public Iterator<ClassFile> iterator() {
6338N/A return new FileIterator();
6338N/A }
6338N/A };
6338N/A }
6338N/A
6338N/A protected ClassFile readClassFile(Path p) throws IOException {
6338N/A InputStream is = null;
6338N/A try {
6338N/A is = Files.newInputStream(p);
6338N/A return ClassFile.read(is);
6338N/A } catch (ConstantPoolException e) {
6338N/A throw new ClassFileError(e);
6338N/A } finally {
6338N/A if (is != null) {
6338N/A is.close();
6338N/A }
6338N/A }
6338N/A }
6338N/A
6338N/A class FileIterator implements Iterator<ClassFile> {
6338N/A int count;
6338N/A FileIterator() {
6338N/A this.count = 0;
6338N/A }
6338N/A public boolean hasNext() {
6338N/A return count == 0 && baseFileName.endsWith(".class");
6338N/A }
6338N/A
6338N/A public ClassFile next() {
6338N/A if (!hasNext()) {
6338N/A throw new NoSuchElementException();
6338N/A }
6338N/A try {
6338N/A ClassFile cf = readClassFile(path);
6338N/A count++;
6338N/A return cf;
6338N/A } catch (IOException e) {
6338N/A throw new ClassFileError(e);
6338N/A }
6338N/A }
6338N/A
6338N/A public void remove() {
6338N/A throw new UnsupportedOperationException("Not supported yet.");
6338N/A }
6338N/A }
6338N/A
6338N/A public String toString() {
6338N/A return path.toString();
6338N/A }
6338N/A
6338N/A private static class DirectoryReader extends ClassFileReader {
6338N/A DirectoryReader(Path path) throws IOException {
6338N/A super(path);
6338N/A }
6338N/A
6338N/A public ClassFile getClassFile(String name) throws IOException {
6338N/A if (name.indexOf('.') > 0) {
6338N/A int i = name.lastIndexOf('.');
6338N/A String pathname = name.replace('.', File.separatorChar) + ".class";
6338N/A Path p = path.resolve(pathname);
6338N/A if (!p.toFile().exists()) {
6338N/A p = path.resolve(pathname.substring(0, i) + "$" +
6338N/A pathname.substring(i+1, pathname.length()));
6338N/A }
6338N/A if (p.toFile().exists()) {
6338N/A return readClassFile(p);
6338N/A }
6338N/A } else {
6338N/A Path p = path.resolve(name + ".class");
6338N/A if (p.toFile().exists()) {
6338N/A return readClassFile(p);
6338N/A }
6338N/A }
6338N/A return null;
6338N/A }
6338N/A
6338N/A public Iterable<ClassFile> getClassFiles() throws IOException {
6338N/A final Iterator<ClassFile> iter = new DirectoryIterator();
6338N/A return new Iterable<ClassFile>() {
6338N/A public Iterator<ClassFile> iterator() {
6338N/A return iter;
6338N/A }
6338N/A };
6338N/A }
6338N/A
6338N/A private List<Path> walkTree(Path dir) throws IOException {
6338N/A final List<Path> files = new ArrayList<Path>();
6338N/A Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
6338N/A public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
6338N/A throws IOException {
6338N/A if (file.toFile().getName().endsWith(".class")) {
6338N/A files.add(file);
6338N/A }
6338N/A return FileVisitResult.CONTINUE;
6338N/A }
6338N/A });
6338N/A return files;
6338N/A }
6338N/A
6338N/A class DirectoryIterator implements Iterator<ClassFile> {
6338N/A private List<Path> entries;
6338N/A private int index = 0;
6338N/A DirectoryIterator() throws IOException {
6338N/A entries = walkTree(path);
6338N/A index = 0;
6338N/A }
6338N/A
6338N/A public boolean hasNext() {
6338N/A return index != entries.size();
6338N/A }
6338N/A
6338N/A public ClassFile next() {
6338N/A if (!hasNext()) {
6338N/A throw new NoSuchElementException();
6338N/A }
6338N/A Path path = entries.get(index++);
6338N/A try {
6338N/A return readClassFile(path);
6338N/A } catch (IOException e) {
6338N/A throw new ClassFileError(e);
6338N/A }
6338N/A }
6338N/A
6338N/A public void remove() {
6338N/A throw new UnsupportedOperationException("Not supported yet.");
6338N/A }
6338N/A }
6338N/A }
6338N/A
6338N/A private static class JarFileReader extends ClassFileReader {
6338N/A final JarFile jarfile;
6338N/A JarFileReader(Path path) throws IOException {
6338N/A this(path, new JarFile(path.toFile()));
6338N/A }
6338N/A JarFileReader(Path path, JarFile jf) throws IOException {
6338N/A super(path);
6338N/A this.jarfile = jf;
6338N/A }
6338N/A
6338N/A public ClassFile getClassFile(String name) throws IOException {
6338N/A if (name.indexOf('.') > 0) {
6338N/A int i = name.lastIndexOf('.');
6338N/A String entryName = name.replace('.', '/') + ".class";
6338N/A JarEntry e = jarfile.getJarEntry(entryName);
6338N/A if (e == null) {
6338N/A e = jarfile.getJarEntry(entryName.substring(0, i) + "$"
6338N/A + entryName.substring(i + 1, entryName.length()));
6338N/A }
6338N/A if (e != null) {
6338N/A return readClassFile(e);
6338N/A }
6338N/A } else {
6338N/A JarEntry e = jarfile.getJarEntry(name + ".class");
6338N/A if (e != null) {
6338N/A return readClassFile(e);
6338N/A }
6338N/A }
6338N/A return null;
6338N/A }
6338N/A
6338N/A private ClassFile readClassFile(JarEntry e) throws IOException {
6338N/A InputStream is = null;
6338N/A try {
6338N/A is = jarfile.getInputStream(e);
6338N/A return ClassFile.read(is);
6338N/A } catch (ConstantPoolException ex) {
6338N/A throw new IOException(ex);
6338N/A } finally {
6338N/A if (is != null)
6338N/A is.close();
6338N/A }
6338N/A }
6338N/A
6338N/A public Iterable<ClassFile> getClassFiles() throws IOException {
6338N/A final Iterator<ClassFile> iter = new JarFileIterator();
6338N/A return new Iterable<ClassFile>() {
6338N/A public Iterator<ClassFile> iterator() {
6338N/A return iter;
6338N/A }
6338N/A };
6338N/A }
6338N/A
6338N/A class JarFileIterator implements Iterator<ClassFile> {
6338N/A private Enumeration<JarEntry> entries;
6338N/A private JarEntry nextEntry;
6338N/A JarFileIterator() {
6338N/A this.entries = jarfile.entries();
6338N/A while (entries.hasMoreElements()) {
6338N/A JarEntry e = entries.nextElement();
6338N/A String name = e.getName();
6338N/A if (name.endsWith(".class")) {
6338N/A this.nextEntry = e;
6338N/A break;
6338N/A }
6338N/A }
6338N/A }
6338N/A
6338N/A public boolean hasNext() {
6338N/A return nextEntry != null;
6338N/A }
6338N/A
6338N/A public ClassFile next() {
6338N/A if (!hasNext()) {
6338N/A throw new NoSuchElementException();
6338N/A }
6338N/A
6338N/A ClassFile cf;
6338N/A try {
6338N/A cf = readClassFile(nextEntry);
6338N/A } catch (IOException e) {
6338N/A throw new ClassFileError(e);
6338N/A }
6338N/A JarEntry entry = nextEntry;
6338N/A nextEntry = null;
6338N/A while (entries.hasMoreElements()) {
6338N/A JarEntry e = entries.nextElement();
6338N/A String name = e.getName();
6338N/A if (name.endsWith(".class")) {
6338N/A nextEntry = e;
6338N/A break;
6338N/A }
6338N/A }
6338N/A return cf;
6338N/A }
6338N/A
6338N/A public void remove() {
6338N/A throw new UnsupportedOperationException("Not supported yet.");
6338N/A }
6338N/A }
6338N/A }
6338N/A
6338N/A public static class ClassFileError extends Error {
6338N/A public ClassFileError(Throwable t) {
6338N/A super(t);
6338N/A }
6338N/A }
6338N/A}