--- /dev/null 2012-10-24 11:46:27.564410214 +0200 +++ new/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java 2012-12-06 15:26:12.057771440 +0100 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2012, 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 com.sun.tools.jdeps; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Dependencies.ClassFileError; +import java.io.*; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * ClassFileReader reads ClassFile(s) of a given path that can be + * a .class file, a directory, or a JAR file. + */ +public class ClassFileReader { + /** + * Returns a ClassFileReader instance of a given path. + */ + public static ClassFileReader newInstance(File path) throws IOException { + if (!path.exists()) { + throw new FileNotFoundException(path.getAbsolutePath()); + } + + if (path.isDirectory()) { + return new DirectoryReader(path.toPath()); + } else if (path.getName().endsWith(".jar")) { + return new JarFileReader(path.toPath()); + } else { + return new ClassFileReader(path.toPath()); + } + } + + protected final Path path; + protected final String baseFileName; + private ClassFileReader(Path path) { + this.path = path; + this.baseFileName = path.getFileName().toString(); + } + + public String getFileName() { + return path.getFileName().toString(); + } + + public ClassFile getClassFile(String classname) { + String fn = classname.replace('.', File.separatorChar) + ".class"; + if (!fn.equals(baseFileName)) { + return null; + } + + try (InputStream is = Files.newInputStream(path)) { + return ClassFile.read(is); + } catch (IOException | ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public Iterable getClassFiles() throws IOException { + return new Iterable() { + public Iterator iterator() { + return new FileIterator(); + } + }; + } + + class FileIterator implements Iterator { + int count; + FileIterator() { + this.count = 0; + } + public boolean hasNext() { + return count == 0 && baseFileName.endsWith(".class"); + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + try (InputStream is = Files.newInputStream(path)) { + count++; + return ClassFile.read(is); + } catch (IOException | ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + public String toString() { + return path.toString(); + } + + private static class DirectoryReader extends ClassFileReader { + DirectoryReader(Path path) throws IOException { + super(path); + } + + @Override + public ClassFile getClassFile(String classname) { + String fn = classname.replace('.', '/') + ".class"; + Path p = path.resolve(fn); + if (!p.toFile().exists()) { + return null; + } + try (InputStream is = Files.newInputStream(p)) { + return ClassFile.read(is); + } catch (IOException | ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public Iterable getClassFiles() throws IOException { + final Iterator iter = new DirectoryIterator(); + return new Iterable() { + public Iterator iterator() { + return iter; + } + }; + } + + private List walkTree(Path dir) throws IOException { + final List files = new ArrayList<>(); + Files.walkFileTree(dir, new SimpleFileVisitor() { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (file.toFile().getName().endsWith(".class")) { + files.add(file); + } + return FileVisitResult.CONTINUE; + } + }); + return files; + } + + class DirectoryIterator implements Iterator { + private List entries; + private int index = 0; + DirectoryIterator() throws IOException { + entries = walkTree(path); + index = 0; + } + + public boolean hasNext() { + return index != entries.size(); + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + Path path = entries.get(index++); + try (InputStream is = Files.newInputStream(path)) { + return ClassFile.read(is); + } catch (IOException | ConstantPoolException e) { + throw new ClassFileError(e); + } + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + } + + private static class JarFileReader extends ClassFileReader { + final JarFile jarfile; + JarFileReader(Path path) throws IOException { + super(path); + this.jarfile = new JarFile(path.toFile()); + } + + public ClassFile getClassFile(String classname) { + String fn = classname.replace('.', '/') + ".class"; + JarEntry e = jarfile.getJarEntry(fn); + if (e == null) { + return null; + } + + try (InputStream is = jarfile.getInputStream(e)) { + return ClassFile.read(is); + } catch (IOException | ConstantPoolException ex) { + throw new ClassFileError(ex); + } + } + + public Iterable getClassFiles() throws IOException { + final Iterator iter = new JarFileIterator(); + return new Iterable() { + public Iterator iterator() { + return iter; + } + }; + } + + class JarFileIterator implements Iterator { + private Enumeration entries; + private JarEntry nextEntry; + JarFileIterator() { + this.entries = jarfile.entries(); + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + String name = e.getName(); + if (name.endsWith(".class")) { + this.nextEntry = e; + break; + } + } + } + + public boolean hasNext() { + return nextEntry != null; + } + + public ClassFile next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + ClassFile cf; + try { + cf = ClassFile.read(jarfile.getInputStream(nextEntry)); + } catch (IOException | ConstantPoolException ex) { + throw new ClassFileError(ex); + } + JarEntry entry = nextEntry; + nextEntry = null; + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + String name = e.getName(); + if (name.endsWith(".class")) { + nextEntry = e; + break; + } + } + return cf; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + } + } +}