make/tools/classanalyzer/src/com/sun/classanalyzer/ClassPaths.java

Print this page




   2  * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 package com.sun.classanalyzer;
  25 

  26 import java.io.BufferedInputStream;
  27 import java.io.File;
  28 import java.io.FileInputStream;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.util.ArrayList;
  32 import java.util.Enumeration;
  33 import java.util.HashSet;
  34 import java.util.List;
  35 import java.util.Set;
  36 import java.util.jar.JarEntry;
  37 import java.util.jar.JarFile;
  38 
  39 /**





  40  *
  41  * @author mchung
  42  */
  43 public class ClassPath {
  44 
  45     public class FileInfo {


  46 
  47         File file;
  48         JarFile jarfile;
  49         int classCount;
  50         long filesize;
  51 
  52         FileInfo(File f) throws IOException {
  53             this.file = f;
  54             this.classCount = 0;
  55             if (file.getName().endsWith(".jar")) {
  56                 this.filesize = file.length();
  57                 jarfile = new JarFile(f);


  58             }




  59         }

























  60 
  61         File getFile() {
  62             return file;
  63         }
  64 
  65         JarFile getJarFile() {
  66             return jarfile;






  67         }





  68 
  69         String getName() throws IOException {
  70             return file.getCanonicalPath();
  71         }



  72     }
  73     private List<FileInfo> fileList = new ArrayList<FileInfo>();
  74     private static ClassPath instance = new ClassPath();
  75 
  76     static List<FileInfo> getFileInfos() {
  77         return instance.fileList;


  78     }
  79 
  80     static ClassPath setJDKHome(String jdkhome) throws IOException {





































  81         List<File> files = new ArrayList<File>();
  82         File jre = new File(jdkhome, "jre");
  83         File lib = new File(jdkhome, "lib");

  84         if (jre.exists() && jre.isDirectory()) {
  85             listFiles(new File(jre, "lib"), ".jar", files);
  86             listFiles(lib, ".jar", files);
  87         } else if (lib.exists() && lib.isDirectory()) {
  88             // either a JRE or a jdk build image
  89             listFiles(lib, ".jar", files);
  90 
  91             File classes = new File(jdkhome, "classes");
  92             if (classes.exists() && classes.isDirectory()) {
  93                 // jdk build outputdir
  94                 instance.add(classes);
  95             }

  96         } else {
  97             throw new RuntimeException("\"" + jdkhome + "\" not a JDK home");
  98         }

  99 
 100         for (File f : files) {
 101             instance.add(f);







 102         }
 103         return instance;
 104     }


 105 
 106     static ClassPath setClassPath(String path) throws IOException {
 107         if (path.endsWith(".class")) {
 108             // one class file
 109             File f = new File(path);
 110             if (!f.exists()) {
 111                 throw new RuntimeException("Classfile \"" + f + "\" doesn't exist");




 112             }





 113 
 114             instance.add(f);
 115         } else {
 116             List<File> jarFiles = new ArrayList<File>();
 117             String[] locs = path.split(File.pathSeparator);
 118             for (String p : locs) {
 119                 File f = new File(p);
 120                 if (!f.exists()) {
 121                     throw new RuntimeException("\"" + f + "\" doesn't exist");
 122                 }
 123 
 124                 if (f.isDirectory()) {
 125                     instance.add(f);  // add the directory to look up .class files
 126                     listFiles(f, ".jar", jarFiles);
 127                 } else if (p.endsWith(".jar")) {
 128                     // jar files
 129                     jarFiles.add(f);
 130                 } else {
 131                     throw new RuntimeException("Invalid file \"" + f);
 132                 }









 133             }
 134             // add jarFiles if any
 135             for (File f : jarFiles) {
 136                 instance.add(f);
 137             }



 138         }
 139 
 140         return instance;

 141     }
 142 
 143     private void add(File f) throws IOException {
 144         fileList.add(new FileInfo(f));


 145     }

 146 
 147     public static InputStream open(String pathname) throws IOException {
 148         for (FileInfo fi : instance.fileList) {
 149             if (fi.getName().endsWith(".jar")) {
 150                 String path = pathname.replace(File.separatorChar, '/');
 151                 JarEntry e = fi.jarfile.getJarEntry(path);
 152                 if (e != null) {
 153                     return fi.jarfile.getInputStream(e);
 154                 }
 155             } else if (fi.getFile().isDirectory()) {
 156                 File f = new File(fi.getFile(), pathname);
 157                 if (f.exists()) {
 158                     return new FileInputStream(f);
 159                 }
 160             } else if (fi.file.isFile()) {
 161                 if (fi.getName().endsWith(File.separator + pathname)) {
 162                     return new FileInputStream(fi.file);
 163                 }





 164             }




 165         }
 166         return null;
 167     }
 168 
 169     static ClassFileParser parserForClass(String classname) throws IOException {
 170         String pathname = classname.replace('.', File.separatorChar) + ".class";
 171 
 172         ClassFileParser cfparser = null;
 173         for (FileInfo fi : instance.fileList) {
 174             if (fi.getName().endsWith(".class")) {
 175                 if (fi.getName().endsWith(File.separator + pathname)) {
 176                     cfparser = ClassFileParser.newParser(fi.getFile(), true);
 177                     break;







 178                 }
 179             } else if (fi.getName().endsWith(".jar")) {
 180                 JarEntry e = fi.jarfile.getJarEntry(classname.replace('.', '/') + ".class");
 181                 if (e != null) {
 182                     cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true);
 183                     break;


 184                 }
 185             } else if (fi.getFile().isDirectory()) {
 186                 File f = new File(fi.getFile(), pathname);
 187                 if (f.exists()) {
 188                     cfparser = ClassFileParser.newParser(f, true);
 189                     break;
 190                 }







 191             }
 192         }
 193         return cfparser;








 194     }

 195 
 196     public static void parseAllClassFiles() throws IOException {
 197         instance.parseFiles();


 198     }

 199 
 200     private void parseFiles() throws IOException {
 201         Set<Klass> classes = new HashSet<Klass>();
 202 
 203         int count = 0;
 204         for (FileInfo fi : fileList) {
 205             // filter out public generated classes (i.e. not public API)
 206             // javax.management.remote.rmi._RMIConnectionImpl_Tie
 207             // javax.management.remote.rmi._RMIServerImpl_Tie
 208             if (fi.getName().endsWith(".class")) {
 209                 parseClass(fi);
 210             } else if (fi.getName().endsWith(".jar")) {
 211                 Enumeration<JarEntry> entries = fi.jarfile.entries();
 212                 while (entries.hasMoreElements()) {
 213                     JarEntry e = entries.nextElement();
 214                     if (e.getName().endsWith(".class")) {
 215                         ClassFileParser cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true);
 216                         cfparser.parseDependency(false);
 217                         fi.classCount++;
 218                     } else if (!e.isDirectory() && ResourceFile.isResource(e.getName())) {
 219                         ResourceFile.addResource(e.getName(), fi.jarfile.getInputStream(e));
 220                     }





 221                 }
 222             } else if (fi.getFile().isDirectory()) {
 223                 List<File> files = new ArrayList<File>();
 224                 listFiles(fi.getFile(), "", files);
 225                 for (File f : files) {
 226                     if (f.getName().endsWith(".class")) {
 227                         parseClass(fi, f);
 228                     } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) {
 229                         String pathname = f.getCanonicalPath();
 230                         String dir = fi.getName();
 231                         if (!pathname.startsWith(dir)) {

 232                             throw new RuntimeException("Incorrect pathname " + pathname);
 233                         }
 234                         String name = pathname.substring(dir.length() + 1, pathname.length());
 235                         BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
 236                         try {
 237                             ResourceFile.addResource(name, in);
 238                         } finally {
 239                             in.close();
 240                         }





 241                     }

 242                 }








































 243             } else {
 244                 // should not reach here
 245                 throw new RuntimeException("Unexpected class path: " + fi.getFile());
 246             }
 247         }








 248     }

 249 
 250     private void parseClass(FileInfo fi) throws IOException {
 251         parseClass(fi, fi.getFile());






 252     }


 253 
 254     private void parseClass(FileInfo fi, File f) throws IOException {
 255         ClassFileParser cfparser = ClassFileParser.newParser(f, true);
 256         cfparser.parseDependency(false);
 257         fi.classCount++;
 258         // need to update the filesize for this directory
 259         fi.filesize += fi.getFile().length();


 260 










 261     }

 262 
 263     public static void listFiles(File path, String suffix, List<File> result) {
 264         if (path.isDirectory()) {
 265             File[] children = path.listFiles();
 266             for (File c : children) {
 267                 listFiles(c, suffix, result);


 268             }

 269 






 270         } else {
 271             if (suffix.isEmpty() || path.getName().endsWith(suffix)) {
 272                 result.add(path);
 273             }
 274         }






 275     }



 276 }


   2  * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.

  22  */
  23 package com.sun.classanalyzer;
  24 
  25 import com.sun.classanalyzer.ClassPaths.*;
  26 import java.io.BufferedInputStream;
  27 import java.io.File;
  28 import java.io.FileInputStream;
  29 import java.io.IOException;
  30 import java.io.InputStream;
  31 import java.util.*;




  32 import java.util.jar.JarEntry;
  33 import java.util.jar.JarFile;
  34 
  35 /**
  36  * Legacy class path.  Each entry can be a directory containing
  37  * classes and resources, or a jar file.  It supports classpath
  38  * wildcard "*" that lists all jar files in the given directory
  39  * and also recursive wildcard "**" that lists all jar files
  40  * recursively in the given directory and its subdirectories.
  41  *
  42  * @author Mandy Chung
  43  */
  44 public class ClassPaths {
  45 
  46     protected final List<ClassPath> entries = new LinkedList<ClassPath>();
  47     private final Set<Klass> classes = new LinkedHashSet<Klass>();
  48     private final Set<ResourceFile> resources = new LinkedHashSet<ResourceFile>();
  49 
  50     private ClassPaths() {
  51     }


  52 
  53     public ClassPaths(String... paths) throws IOException {
  54         for (String p : paths) {
  55             String cp = p;
  56             int index = p.indexOf("*");
  57             String wildcard = "";
  58             if (index >= 0) {
  59                 cp = p.substring(0, index);
  60                 wildcard = p.substring(index, p.length());
  61             }
  62 
  63             File f = new File(cp);
  64             if (!f.exists()) {
  65                 throw new RuntimeException("\"" + f + "\" doesn't exist");
  66             }
  67             if (wildcard.isEmpty()) {
  68                 if (f.isDirectory()) {
  69                     entries.add(new DirClassPath(f));
  70                 } else if (cp.endsWith(".jar")) {
  71                     entries.add(new JarFileClassPath(f));
  72                 } else {
  73                     entries.add(new ClassPath(f));
  74                 }
  75             } else {
  76                 if (wildcard.equals("*")) {
  77                     // add jar files in the specified directory
  78                     String[] ls = Files.list(f);
  79                     for (String s : ls) {
  80                         File sf = new File(f, s);
  81                         if (s.endsWith(".jar")) {
  82                             entries.add(new JarFileClassPath(f));
  83                         }
  84                     }
  85                 } else if (wildcard.equals("**")) {
  86                     // add all jar files in all directories under f
  87                     addJarFileEntries(f);
  88                 }
  89             }
  90         }
  91     }
  92 
  93     public List<ClassPath> entries() {
  94         return Collections.unmodifiableList(entries);
  95     }
  96 
  97     /**
  98      * Returns the modules containing the classes and resources being
  99      * processed.
 100      */
 101     public Set<Module> getModules() {
 102         Set<Module> modules = new LinkedHashSet<Module>();
 103         for (Klass k : classes) {
 104             modules.add(k.getModule().group());
 105         }
 106         for (ResourceFile r : resources) {
 107             modules.add(r.getModule().group());
 108         }
 109         return modules;
 110     }
 111 
 112     public void parse() throws IOException {
 113         parse(null, true, false);
 114     }
 115 
 116     public void parse(boolean deps, boolean apiOnly) throws IOException {
 117         parse(null, deps, apiOnly);
 118     }


 119 
 120     public void parse(Filter filter, boolean deps, boolean apiOnly) throws IOException {
 121         ClassResourceVisitor crv = new ClassResourceVisitor(classes, resources, deps, apiOnly);
 122         ClassPathVisitor cpvisitor = new ClassPathVisitor(crv, filter);
 123         visit(cpvisitor, filter, null);
 124     }
 125 
 126     public void printStats() {
 127         System.out.format("%d classes %d resource files processed%n",
 128                 classes.size(), resources.size());
 129     }
 130 
 131     protected void addJarFileEntries(File f) throws IOException {
 132         List<File> ls;
 133         if (f.isDirectory()) {
 134             ls = Files.walkTree(f, new Files.Filter<File>() {
 135                 @Override
 136                 public boolean accept(File f) throws IOException {
 137                     return f.isDirectory() || f.getName().endsWith(".jar");
 138                 }
 139             });
 140         } else {
 141             ls = Collections.singletonList(f);
 142         }
 143         for (File jf : ls) {
 144             entries.add(new JarFileClassPath(jf));
 145         }
 146     }
 147     // FIXME - used by open() method
 148     static ClassPaths instance = null;
 149 
 150     static ClassPaths newInstance(String cpaths) throws IOException {
 151         String[] paths = cpaths.split(File.pathSeparator);
 152         instance = new ClassPaths(paths);
 153         return instance;
 154     }
 155 
 156     static ClassPaths newJDKClassPaths(String jdkhome) throws IOException {
 157         instance = new JDKClassPaths(jdkhome);
 158         return instance;
 159     }
 160 
 161     static class JDKClassPaths extends ClassPaths {
 162         JDKClassPaths(String jdkhome) throws IOException {
 163             super();
 164             List<File> files = new ArrayList<File>();
 165             File jre = new File(jdkhome, "jre");
 166             File lib = new File(jdkhome, "lib");
 167 
 168             if (jre.exists() && jre.isDirectory()) {
 169                 addJarFiles(new File(jre, "lib"));
 170                 addJarFiles(lib);
 171             } else if (lib.exists() && lib.isDirectory()) {
 172                 // either a JRE or a jdk build image


 173                 File classes = new File(jdkhome, "classes");
 174                 if (classes.exists() && classes.isDirectory()) {
 175                     // jdk build outputdir
 176                     this.entries.add(new DirClassPath(classes));
 177                 }
 178                 addJarFiles(lib);
 179             } else {
 180                 throw new RuntimeException("\"" + jdkhome + "\" not a JDK home");
 181             }
 182         }
 183 
 184         // Filter the jigsaw module library, if any
 185         final void addJarFiles(File dir) throws IOException {
 186             String[] ls = dir.list();
 187             for (String fn : ls) {
 188                 File f = new File(dir, fn);
 189                 if (f.isDirectory() && !fn.equals("modules")) {
 190                     addJarFileEntries(f);
 191                 } else if (f.isFile() && fn.endsWith(".jar")) {
 192                     addJarFileEntries(f);
 193                 }

 194             }
 195         }
 196     }
 197 
 198     /**
 199      * Visits all entries in the class path.
 200      */
 201     public <R, P> List<R> visit(final ClassPath.Visitor<R, P> visitor,
 202             final Filter filter, P p)
 203             throws IOException {
 204         List<R> result = new ArrayList<R>();
 205         for (ClassPath cp : entries) {
 206             if (filter != null && !filter.accept(cp.file)) {
 207                 continue;
 208             }
 209             R r = cp.accept(visitor, p);
 210             result.add(r);
 211         }
 212         return result;
 213     }
 214 
 215     public static interface FileVisitor {
 216         public void visitClass(File f, String cn) throws IOException;
 217         public void visitClass(JarFile jf, JarEntry e) throws IOException;
 218         public void visitResource(File f, String rn) throws IOException;
 219         public void visitResource(JarFile jf, JarEntry e) throws IOException;



 220     }
 221 
 222     public static interface Filter {
 223         // any file, jar file, directory
 224         public boolean accept(File f) throws IOException;
 225         public boolean accept(JarFile jf, JarEntry e) throws IOException;




 226     }
 227 
 228     public static class ClassPath {
 229 
 230         private final File file;
 231         private final String name;
 232 
 233         ClassPath(File f) throws IOException {
 234             this.file = f;
 235             this.name = file.getCanonicalPath();
 236         }
 237 
 238         File getFile() {
 239             return file;
 240         }
 241 
 242         String getName() {
 243             return name;
 244         }
 245 
 246         <R, P> R accept(Visitor<R, P> visitor, P p) throws IOException {
 247             return visitor.visitFile(file, this, p);
 248         }
 249 
 250         public interface Visitor<R, P> {
 251             public R visitFile(File f, ClassPath cp, P p) throws IOException;
 252             public R visitDir(File dir, ClassPath cp, P p) throws IOException;
 253             public R visitJarFile(JarFile jf, ClassPath cp, P p) throws IOException;
 254         }
 255     }
 256 
 257     static class JarFileClassPath extends ClassPath {
 258         JarFile jarfile;
 259         JarFileClassPath(File f) throws IOException {
 260             super(f);
 261             this.jarfile = new JarFile(f);


 262         }
 263 
 264         @Override
 265         <R, P> R accept(Visitor<R, P> visitor, P p) throws IOException {
 266             return visitor.visitJarFile(jarfile, this, p);
 267         }



 268     }
 269 
 270     class DirClassPath extends ClassPath {
 271 
 272         DirClassPath(File f) throws IOException {
 273             super(f);
 274         }
 275 
 276         @Override
 277         <R, P> R accept(final Visitor<R, P> visitor, P p) throws IOException {
 278             return visitor.visitDir(getFile(), this, p);
 279         }

 280     }
 281 
 282     static class ClassResourceVisitor implements FileVisitor {

 283 
 284         private final Set<Klass> classes;
 285         private final Set<ResourceFile> resources;
 286         private final boolean parseDeps;
 287         private final boolean apiOnly;
 288 
 289         ClassResourceVisitor(Set<Klass> classes,
 290                 Set<ResourceFile> resources,
 291                 boolean parseDeps,
 292                 boolean apiOnly) {
 293             this.classes = classes;
 294             this.resources = resources;
 295             this.apiOnly = apiOnly;
 296             this.parseDeps = parseDeps;
 297         }
 298 
 299         @Override
 300         public void visitClass(File f, String cn) throws IOException {
 301             ClassFileParser cfparser = ClassFileParser.newParser(f, true);
 302             classes.add(cfparser.this_klass);
 303             if (parseDeps) {
 304                 cfparser.parseDependency(apiOnly);
 305             }





 306         }
 307 
 308         @Override
 309         public void visitClass(JarFile jf, JarEntry e) throws IOException {
 310             ClassFileParser cfparser = ClassFileParser.newParser(jf.getInputStream(e), e.getSize(), true);
 311             classes.add(cfparser.this_klass);
 312             if (parseDeps) {
 313                 cfparser.parseDependency(apiOnly);
 314             }
 315         }
 316 
 317         @Override
 318         public void visitResource(File f, String rn) throws IOException {
 319             BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
 320             try {
 321                 ResourceFile res = ResourceFile.addResource(rn, in);
 322                 resources.add(res);
 323             } finally {
 324                 in.close();
 325             }
 326         }
 327 
 328         @Override
 329         public void visitResource(JarFile jf, JarEntry e) throws IOException {
 330             ResourceFile res = ResourceFile.addResource(e.getName(), jf.getInputStream(e));
 331             resources.add(res);
 332         }
 333     }
 334 
 335     static class ClassPathVisitor implements ClassPath.Visitor<Void, Void> {

 336 
 337         private final FileVisitor visitor;
 338         private final Filter filter;
 339 
 340         ClassPathVisitor(FileVisitor fv, Filter filter) {
 341             this.visitor = fv;
 342             this.filter = filter;











 343         }
 344 
 345         @Override
 346         public Void visitFile(File f, ClassPath cp, Void v) throws IOException {
 347             if (filter != null && !filter.accept(f)) {
 348                 return null;
 349             }
 350 
 351             String name = f.getName();





 352             String pathname = f.getCanonicalPath();
 353             String root = cp.getName();
 354             if (!name.equals(root) && !pathname.equals(root)) {
 355                 if (!pathname.startsWith(root)) {
 356                     throw new RuntimeException("Incorrect pathname " + pathname);
 357                 }
 358 
 359                 name = pathname.substring(root.length() + 1, pathname.length());




 360             }
 361 
 362             if (name.endsWith(".class")) {
 363                 visitor.visitClass(f, name);
 364             } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) {
 365                 visitor.visitResource(f, name);
 366             }
 367             return null;
 368         }
 369 
 370         @Override
 371         public Void visitDir(final File dir, final ClassPath cp, Void v) throws IOException {
 372             List<File> ls = Files.walkTree(dir, null);
 373             for (File f : ls) {
 374                 visitFile(f, (ClassPath) cp, null);
 375             }
 376             return null;
 377         }
 378 
 379         @Override
 380         public Void visitJarFile(JarFile jf, ClassPath cp, Void v) throws IOException {
 381             if (filter != null && !filter.accept(cp.getFile())) {
 382                 return null;
 383             }
 384 
 385             Enumeration<JarEntry> entries = jf.entries();
 386             while (entries.hasMoreElements()) {
 387                 JarEntry e = entries.nextElement();
 388                 String name = e.getName();
 389                 if (filter != null && !filter.accept(jf, e)) {
 390                     continue;
 391                 }
 392                 if (name.endsWith(".class")) {
 393                     visitor.visitClass(jf, e);
 394                 } else if (!e.isDirectory() && ResourceFile.isResource(name)) {
 395                     visitor.visitResource(jf, e);
 396                 }
 397             }
 398             return null;
 399         }
 400     };
 401 
 402     public static InputStream open(String pathname) throws IOException {
 403         ClassPath.Visitor<InputStream, String> fv = new ClassPath.Visitor<InputStream, String>() {
 404 
 405             @Override
 406             public InputStream visitFile(File f, ClassPath cp, String pathname) throws IOException {
 407                 if (cp.getName().endsWith(File.separator + pathname)) {
 408                     return new FileInputStream(f);
 409                 } else {
 410                     return null;

 411                 }
 412             }
 413 
 414             @Override
 415             public InputStream visitDir(File dir, ClassPath cp, String pathname) throws IOException {
 416                 File f = new File(cp.getFile(), pathname);
 417                 if (f.exists()) {
 418                     return new FileInputStream(f);
 419                 } else {
 420                     return null;
 421                 }
 422             }
 423 
 424             @Override
 425             public InputStream visitJarFile(JarFile jf, ClassPath cp, String pathname) throws IOException {
 426                 String p = pathname.replace(File.separatorChar, '/');
 427                 JarEntry e = jf.getJarEntry(p);
 428                 if (e != null) {
 429                     return jf.getInputStream(e);
 430                 } else {
 431                     return null;
 432                 }
 433             }
 434         };
 435 
 436         for (ClassPath cp : instance.entries) {
 437             InputStream in = cp.accept(fv, pathname);
 438             if (in != null) {
 439                 return in;
 440             }
 441         }
 442         return null;
 443     }
 444 
 445     public ClassFileParser parserForClass(String classname) throws IOException {
 446         String pathname = classname.replace('.', File.separatorChar) + ".class";
 447         ClassPath.Visitor<ClassFileParser, String> fv = new ClassPath.Visitor<ClassFileParser, String>() {
 448 
 449             @Override
 450             public ClassFileParser visitFile(File f, ClassPath cp, String pathname) throws IOException {
 451                 if (cp.getName().endsWith(File.separator + pathname)) {
 452                     return ClassFileParser.newParser(f, true);
 453                 } else {
 454                     return null;
 455                 }
 456             }
 457 
 458             @Override
 459             public ClassFileParser visitDir(File dir, ClassPath cp, String pathname) throws IOException {
 460                 File f = new File(cp.getFile(), pathname);
 461                 if (f.exists()) {
 462                     return ClassFileParser.newParser(f, true);
 463                 } else {
 464                     return null;
 465                 }
 466             }
 467 
 468             @Override
 469             public ClassFileParser visitJarFile(JarFile jf, ClassPath cp, String pathname) throws IOException {
 470                 String p = pathname.replace(File.separatorChar, '/');
 471                 JarEntry e = jf.getJarEntry(p);
 472                 if (e != null) {
 473                     return ClassFileParser.newParser(jf.getInputStream(e), e.getSize(), true);
 474                 } else {
 475                     return null;

 476                 }
 477             }
 478         };
 479 
 480         for (ClassPath cp : entries) {
 481             ClassFileParser cfparser = cp.accept(fv, pathname);
 482             if (cfparser != null) {
 483                 return cfparser;
 484             }
 485         }
 486         return null;
 487     }
 488 }