|
|
@@ -56,323 +56,486 @@ package org.aspectj.apache.bcel.util; |
|
|
|
|
|
|
|
import java.util.*; |
|
|
|
import java.util.zip.*; |
|
|
|
|
|
|
|
import java.io.*; |
|
|
|
import java.net.URI; |
|
|
|
import java.nio.file.DirectoryStream; |
|
|
|
import java.nio.file.FileSystems; |
|
|
|
import java.nio.file.Files; |
|
|
|
import java.nio.file.NoSuchFileException; |
|
|
|
import java.nio.file.Path; |
|
|
|
import java.nio.file.attribute.BasicFileAttributeView; |
|
|
|
import java.nio.file.attribute.BasicFileAttributes; |
|
|
|
|
|
|
|
/** |
|
|
|
* Responsible for loading (class) files from the CLASSPATH. Inspired by |
|
|
|
* sun.tools.ClassPath. |
|
|
|
* |
|
|
|
* @version $Id: ClassPath.java,v 1.5 2009/09/09 19:56:20 aclement Exp $ |
|
|
|
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> |
|
|
|
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> |
|
|
|
*/ |
|
|
|
public class ClassPath implements Serializable { |
|
|
|
private static ClassPath SYSTEM_CLASS_PATH = null; |
|
|
|
|
|
|
|
private PathEntry[] paths; |
|
|
|
private String class_path; |
|
|
|
|
|
|
|
public static ClassPath getSystemClassPath() { |
|
|
|
if (SYSTEM_CLASS_PATH == null) { |
|
|
|
SYSTEM_CLASS_PATH = new ClassPath(); |
|
|
|
} |
|
|
|
return SYSTEM_CLASS_PATH; |
|
|
|
} |
|
|
|
/** |
|
|
|
* Search for classes in given path. |
|
|
|
*/ |
|
|
|
public ClassPath(String class_path) { |
|
|
|
this.class_path = class_path; |
|
|
|
|
|
|
|
ArrayList<PathEntry> vec = new ArrayList<PathEntry>(); |
|
|
|
|
|
|
|
for(StringTokenizer tok=new StringTokenizer(class_path, |
|
|
|
System.getProperty("path.separator")); |
|
|
|
tok.hasMoreTokens();) |
|
|
|
{ |
|
|
|
String path = tok.nextToken(); |
|
|
|
|
|
|
|
if(!path.equals("")) { |
|
|
|
File file = new File(path); |
|
|
|
|
|
|
|
try { |
|
|
|
if(file.exists()) { |
|
|
|
if(file.isDirectory()) |
|
|
|
vec.add(new Dir(path)); |
|
|
|
else |
|
|
|
vec.add(new Zip(new ZipFile(file))); |
|
|
|
} |
|
|
|
} catch(IOException e) { |
|
|
|
System.err.println("CLASSPATH component " + file + ": " + e); |
|
|
|
private static ClassPath SYSTEM_CLASS_PATH = null; |
|
|
|
|
|
|
|
private PathEntry[] paths; |
|
|
|
private String class_path; |
|
|
|
|
|
|
|
public static ClassPath getSystemClassPath() { |
|
|
|
if (SYSTEM_CLASS_PATH == null) { |
|
|
|
SYSTEM_CLASS_PATH = new ClassPath(); |
|
|
|
} |
|
|
|
return SYSTEM_CLASS_PATH; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
paths = new PathEntry[vec.size()]; |
|
|
|
vec.toArray(paths); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Search for classes in CLASSPATH. |
|
|
|
* @deprecated Use SYSTEM_CLASS_PATH constant |
|
|
|
*/ |
|
|
|
public ClassPath() { |
|
|
|
this(getClassPath()); |
|
|
|
} |
|
|
|
|
|
|
|
/** @return used class path string |
|
|
|
*/ |
|
|
|
public String toString() { |
|
|
|
return class_path; |
|
|
|
} |
|
|
|
|
|
|
|
public int hashCode() { |
|
|
|
return class_path.hashCode(); |
|
|
|
} |
|
|
|
|
|
|
|
public boolean equals(Object o) { |
|
|
|
if(o instanceof ClassPath) { |
|
|
|
return class_path.equals(((ClassPath)o).class_path); |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private static final void getPathComponents(String path, ArrayList<String> list) { |
|
|
|
if(path != null) { |
|
|
|
StringTokenizer tok = new StringTokenizer(path, File.pathSeparator); |
|
|
|
|
|
|
|
while(tok.hasMoreTokens()) { |
|
|
|
String name = tok.nextToken(); |
|
|
|
File file = new File(name); |
|
|
|
|
|
|
|
if(file.exists()) |
|
|
|
list.add(name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** Checks for class path components in the following properties: |
|
|
|
* "java.class.path", "sun.boot.class.path", "java.ext.dirs" |
|
|
|
* |
|
|
|
* @return class path as used by default by BCEL |
|
|
|
*/ |
|
|
|
public static final String getClassPath() { |
|
|
|
String class_path = System.getProperty("java.class.path"); |
|
|
|
String boot_path = System.getProperty("sun.boot.class.path"); |
|
|
|
String ext_path = System.getProperty("java.ext.dirs"); |
|
|
|
|
|
|
|
ArrayList<String> list = new ArrayList<String>(); |
|
|
|
|
|
|
|
getPathComponents(class_path, list); |
|
|
|
getPathComponents(boot_path, list); |
|
|
|
|
|
|
|
ArrayList<String> dirs = new ArrayList<String>(); |
|
|
|
getPathComponents(ext_path, dirs); |
|
|
|
|
|
|
|
for(Iterator<String> e = dirs.iterator(); e.hasNext(); ) { |
|
|
|
File ext_dir = new File(e.next()); |
|
|
|
String[] extensions = ext_dir.list(new FilenameFilter() { |
|
|
|
public boolean accept(File dir, String name) { |
|
|
|
name = name.toLowerCase(); |
|
|
|
return name.endsWith(".zip") || name.endsWith(".jar"); |
|
|
|
|
|
|
|
/** |
|
|
|
* Search for classes in given path. |
|
|
|
*/ |
|
|
|
public ClassPath(String class_path) { |
|
|
|
this.class_path = class_path; |
|
|
|
|
|
|
|
ArrayList<PathEntry> vec = new ArrayList<PathEntry>(); |
|
|
|
|
|
|
|
for (StringTokenizer tok = new StringTokenizer(class_path, System.getProperty("path.separator")); tok |
|
|
|
.hasMoreTokens();) { |
|
|
|
String path = tok.nextToken(); |
|
|
|
|
|
|
|
if (!path.equals("")) { |
|
|
|
File file = new File(path); |
|
|
|
|
|
|
|
try { |
|
|
|
if (file.exists()) { |
|
|
|
if (file.isDirectory()) |
|
|
|
vec.add(new Dir(path)); |
|
|
|
else if (file.getName().endsWith(".jimage")) { |
|
|
|
vec.add(new JImage(file)); |
|
|
|
} else { |
|
|
|
vec.add(new Zip(new ZipFile(file))); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (IOException e) { |
|
|
|
System.err.println("CLASSPATH component " + file + ": " + e); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
paths = new PathEntry[vec.size()]; |
|
|
|
vec.toArray(paths); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
if(extensions != null) |
|
|
|
for(int i=0; i < extensions.length; i++) |
|
|
|
list.add(ext_path + File.separatorChar + extensions[i]); |
|
|
|
} |
|
|
|
|
|
|
|
StringBuffer buf = new StringBuffer(); |
|
|
|
|
|
|
|
for(Iterator<String> e = list.iterator(); e.hasNext(); ) { |
|
|
|
buf.append(e.next()); |
|
|
|
|
|
|
|
if(e.hasNext()) |
|
|
|
buf.append(File.pathSeparatorChar); |
|
|
|
} |
|
|
|
|
|
|
|
return buf.toString().intern(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name fully qualified class name, e.g. java.lang.String |
|
|
|
* @return input stream for class |
|
|
|
*/ |
|
|
|
public InputStream getInputStream(String name) throws IOException { |
|
|
|
return getInputStream(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Return stream for class or resource on CLASSPATH. |
|
|
|
* |
|
|
|
* @param name fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix file name ends with suff, e.g. .java |
|
|
|
* @return input stream for file on class path |
|
|
|
*/ |
|
|
|
public InputStream getInputStream(String name, String suffix) throws IOException { |
|
|
|
InputStream is = null; |
|
|
|
|
|
|
|
try { |
|
|
|
is = getClass().getClassLoader().getResourceAsStream(name + suffix); |
|
|
|
} catch(Exception e) { } |
|
|
|
|
|
|
|
if(is != null) |
|
|
|
return is; |
|
|
|
|
|
|
|
return getClassFile(name, suffix).getInputStream(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix file name ends with suff, e.g. .java |
|
|
|
* @return class file for the java class |
|
|
|
*/ |
|
|
|
public ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
for(int i=0; i < paths.length; i++) { |
|
|
|
ClassFile cf; |
|
|
|
|
|
|
|
if((cf = paths[i].getClassFile(name, suffix)) != null) |
|
|
|
return cf; |
|
|
|
} |
|
|
|
|
|
|
|
throw new IOException("Couldn't find: " + name + suffix); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name fully qualified class name, e.g. java.lang.String |
|
|
|
* @return input stream for class |
|
|
|
*/ |
|
|
|
public ClassFile getClassFile(String name) throws IOException { |
|
|
|
return getClassFile(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix file name ends with suffix, e.g. .java |
|
|
|
* @return byte array for file on class path |
|
|
|
*/ |
|
|
|
public byte[] getBytes(String name, String suffix) throws IOException { |
|
|
|
InputStream is = getInputStream(name, suffix); |
|
|
|
|
|
|
|
if(is == null) |
|
|
|
throw new IOException("Couldn't find: " + name + suffix); |
|
|
|
|
|
|
|
DataInputStream dis = new DataInputStream(is); |
|
|
|
byte[] bytes = new byte[is.available()]; |
|
|
|
dis.readFully(bytes); |
|
|
|
dis.close(); is.close(); |
|
|
|
|
|
|
|
return bytes; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return byte array for class |
|
|
|
*/ |
|
|
|
public byte[] getBytes(String name) throws IOException { |
|
|
|
return getBytes(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name name of file to search for, e.g. java/lang/String.java |
|
|
|
* @return full (canonical) path for file |
|
|
|
*/ |
|
|
|
public String getPath(String name) throws IOException { |
|
|
|
int index = name.lastIndexOf('.'); |
|
|
|
String suffix = ""; |
|
|
|
|
|
|
|
if(index > 0) { |
|
|
|
suffix = name.substring(index); |
|
|
|
name = name.substring(0, index); |
|
|
|
} |
|
|
|
|
|
|
|
return getPath(name, suffix); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name name of file to search for, e.g. java/lang/String |
|
|
|
* @param suffix file name suffix, e.g. .java |
|
|
|
* @return full (canonical) path for file, if it exists |
|
|
|
*/ |
|
|
|
public String getPath(String name, String suffix) throws IOException { |
|
|
|
return getClassFile(name, suffix).getPath(); |
|
|
|
} |
|
|
|
|
|
|
|
private static abstract class PathEntry implements Serializable { |
|
|
|
abstract ClassFile getClassFile(String name, String suffix) throws IOException; |
|
|
|
} |
|
|
|
|
|
|
|
/** Contains information about file/ZIP entry of the Java class. |
|
|
|
*/ |
|
|
|
public interface ClassFile { |
|
|
|
/** @return input stream for class file. |
|
|
|
*/ |
|
|
|
public abstract InputStream getInputStream() throws IOException; |
|
|
|
|
|
|
|
/** @return canonical path to class file. |
|
|
|
*/ |
|
|
|
public abstract String getPath(); |
|
|
|
|
|
|
|
/** @return base path of found class, i.e. class is contained relative |
|
|
|
* to that path, which may either denote a directory, or zip file |
|
|
|
*/ |
|
|
|
public abstract String getBase(); |
|
|
|
|
|
|
|
/** @return modification time of class file. |
|
|
|
*/ |
|
|
|
public abstract long getTime(); |
|
|
|
|
|
|
|
/** @return size of class file. |
|
|
|
*/ |
|
|
|
public abstract long getSize(); |
|
|
|
} |
|
|
|
|
|
|
|
private static class Dir extends PathEntry { |
|
|
|
private String dir; |
|
|
|
|
|
|
|
Dir(String d) { dir = d; } |
|
|
|
|
|
|
|
ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
final File file = new File(dir + File.separatorChar + |
|
|
|
name.replace('.', File.separatorChar) + suffix); |
|
|
|
|
|
|
|
return file.exists()? new ClassFile() { |
|
|
|
public InputStream getInputStream() throws IOException { return new FileInputStream(file); } |
|
|
|
|
|
|
|
public String getPath() { try { |
|
|
|
return file.getCanonicalPath(); |
|
|
|
} catch(IOException e) { return null; } |
|
|
|
|
|
|
|
/** |
|
|
|
* Search for classes in CLASSPATH. |
|
|
|
* |
|
|
|
* @deprecated Use SYSTEM_CLASS_PATH constant |
|
|
|
*/ |
|
|
|
public ClassPath() { |
|
|
|
this(getClassPath()); |
|
|
|
} |
|
|
|
public long getTime() { return file.lastModified(); } |
|
|
|
public long getSize() { return file.length(); } |
|
|
|
public String getBase() { return dir; } |
|
|
|
|
|
|
|
} : null; |
|
|
|
} |
|
|
|
/** |
|
|
|
* @return used class path string |
|
|
|
*/ |
|
|
|
public String toString() { |
|
|
|
return class_path; |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { return dir; } |
|
|
|
} |
|
|
|
public int hashCode() { |
|
|
|
return class_path.hashCode(); |
|
|
|
} |
|
|
|
|
|
|
|
private static class Zip extends PathEntry { |
|
|
|
private ZipFile zip; |
|
|
|
public boolean equals(Object o) { |
|
|
|
if (o instanceof ClassPath) { |
|
|
|
return class_path.equals(((ClassPath) o).class_path); |
|
|
|
} |
|
|
|
|
|
|
|
Zip(ZipFile z) { zip = z; } |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix); |
|
|
|
private static final void getPathComponents(String path, ArrayList<String> list) { |
|
|
|
if (path != null) { |
|
|
|
StringTokenizer tok = new StringTokenizer(path, File.pathSeparator); |
|
|
|
|
|
|
|
return (entry != null)? new ClassFile() { |
|
|
|
public InputStream getInputStream() throws IOException { return zip.getInputStream(entry); } |
|
|
|
public String getPath() { return entry.toString(); } |
|
|
|
public long getTime() { return entry.getTime(); } |
|
|
|
public long getSize() { return entry.getSize(); } |
|
|
|
public String getBase() { |
|
|
|
return zip.getName(); |
|
|
|
while (tok.hasMoreTokens()) { |
|
|
|
String name = tok.nextToken(); |
|
|
|
File file = new File(name); |
|
|
|
|
|
|
|
if (file.exists()) |
|
|
|
list.add(name); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} : null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Checks for class path components in the following properties: |
|
|
|
* "java.class.path", "sun.boot.class.path", "java.ext.dirs" |
|
|
|
* |
|
|
|
* @return class path as used by default by BCEL |
|
|
|
*/ |
|
|
|
public static final String getClassPath() { |
|
|
|
String class_path = System.getProperty("java.class.path"); |
|
|
|
String boot_path = System.getProperty("sun.boot.class.path"); |
|
|
|
String ext_path = System.getProperty("java.ext.dirs"); |
|
|
|
|
|
|
|
ArrayList<String> list = new ArrayList<String>(); |
|
|
|
|
|
|
|
getPathComponents(class_path, list); |
|
|
|
getPathComponents(boot_path, list); |
|
|
|
|
|
|
|
ArrayList<String> dirs = new ArrayList<String>(); |
|
|
|
getPathComponents(ext_path, dirs); |
|
|
|
|
|
|
|
for (Iterator<String> e = dirs.iterator(); e.hasNext();) { |
|
|
|
File ext_dir = new File(e.next()); |
|
|
|
String[] extensions = ext_dir.list(new FilenameFilter() { |
|
|
|
public boolean accept(File dir, String name) { |
|
|
|
name = name.toLowerCase(); |
|
|
|
return name.endsWith(".zip") || name.endsWith(".jar"); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
if (extensions != null) |
|
|
|
for (int i = 0; i < extensions.length; i++) |
|
|
|
list.add(ext_path + File.separatorChar + extensions[i]); |
|
|
|
} |
|
|
|
|
|
|
|
StringBuffer buf = new StringBuffer(); |
|
|
|
|
|
|
|
for (Iterator<String> e = list.iterator(); e.hasNext();) { |
|
|
|
buf.append(e.next()); |
|
|
|
|
|
|
|
if (e.hasNext()) |
|
|
|
buf.append(File.pathSeparatorChar); |
|
|
|
} |
|
|
|
|
|
|
|
return buf.toString().intern(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* fully qualified class name, e.g. java.lang.String |
|
|
|
* @return input stream for class |
|
|
|
*/ |
|
|
|
public InputStream getInputStream(String name) throws IOException { |
|
|
|
return getInputStream(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Return stream for class or resource on CLASSPATH. |
|
|
|
* |
|
|
|
* @param name |
|
|
|
* fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix |
|
|
|
* file name ends with suff, e.g. .java |
|
|
|
* @return input stream for file on class path |
|
|
|
*/ |
|
|
|
public InputStream getInputStream(String name, String suffix) throws IOException { |
|
|
|
InputStream is = null; |
|
|
|
|
|
|
|
try { |
|
|
|
is = getClass().getClassLoader().getResourceAsStream(name + suffix); |
|
|
|
} catch (Exception e) { |
|
|
|
} |
|
|
|
|
|
|
|
if (is != null) |
|
|
|
return is; |
|
|
|
|
|
|
|
return getClassFile(name, suffix).getInputStream(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix |
|
|
|
* file name ends with suff, e.g. .java |
|
|
|
* @return class file for the java class |
|
|
|
*/ |
|
|
|
public ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
for (int i = 0; i < paths.length; i++) { |
|
|
|
ClassFile cf; |
|
|
|
|
|
|
|
if ((cf = paths[i].getClassFile(name, suffix)) != null) |
|
|
|
return cf; |
|
|
|
} |
|
|
|
|
|
|
|
throw new IOException("Couldn't find: " + name + suffix); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* fully qualified class name, e.g. java.lang.String |
|
|
|
* @return input stream for class |
|
|
|
*/ |
|
|
|
public ClassFile getClassFile(String name) throws IOException { |
|
|
|
return getClassFile(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* fully qualified file name, e.g. java/lang/String |
|
|
|
* @param suffix |
|
|
|
* file name ends with suffix, e.g. .java |
|
|
|
* @return byte array for file on class path |
|
|
|
*/ |
|
|
|
public byte[] getBytes(String name, String suffix) throws IOException { |
|
|
|
InputStream is = getInputStream(name, suffix); |
|
|
|
|
|
|
|
if (is == null) |
|
|
|
throw new IOException("Couldn't find: " + name + suffix); |
|
|
|
|
|
|
|
DataInputStream dis = new DataInputStream(is); |
|
|
|
byte[] bytes = new byte[is.available()]; |
|
|
|
dis.readFully(bytes); |
|
|
|
dis.close(); |
|
|
|
is.close(); |
|
|
|
|
|
|
|
return bytes; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @return byte array for class |
|
|
|
*/ |
|
|
|
public byte[] getBytes(String name) throws IOException { |
|
|
|
return getBytes(name, ".class"); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* name of file to search for, e.g. java/lang/String.java |
|
|
|
* @return full (canonical) path for file |
|
|
|
*/ |
|
|
|
public String getPath(String name) throws IOException { |
|
|
|
int index = name.lastIndexOf('.'); |
|
|
|
String suffix = ""; |
|
|
|
|
|
|
|
if (index > 0) { |
|
|
|
suffix = name.substring(index); |
|
|
|
name = name.substring(0, index); |
|
|
|
} |
|
|
|
|
|
|
|
return getPath(name, suffix); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @param name |
|
|
|
* name of file to search for, e.g. java/lang/String |
|
|
|
* @param suffix |
|
|
|
* file name suffix, e.g. .java |
|
|
|
* @return full (canonical) path for file, if it exists |
|
|
|
*/ |
|
|
|
public String getPath(String name, String suffix) throws IOException { |
|
|
|
return getClassFile(name, suffix).getPath(); |
|
|
|
} |
|
|
|
|
|
|
|
private static abstract class PathEntry implements Serializable { |
|
|
|
abstract ClassFile getClassFile(String name, String suffix) throws IOException; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Contains information about file/ZIP entry of the Java class. |
|
|
|
*/ |
|
|
|
public interface ClassFile { |
|
|
|
/** |
|
|
|
* @return input stream for class file. |
|
|
|
*/ |
|
|
|
public abstract InputStream getInputStream() throws IOException; |
|
|
|
|
|
|
|
/** |
|
|
|
* @return canonical path to class file. |
|
|
|
*/ |
|
|
|
public abstract String getPath(); |
|
|
|
|
|
|
|
/** |
|
|
|
* @return base path of found class, i.e. class is contained relative to |
|
|
|
* that path, which may either denote a directory, or zip file |
|
|
|
*/ |
|
|
|
public abstract String getBase(); |
|
|
|
|
|
|
|
/** |
|
|
|
* @return modification time of class file. |
|
|
|
*/ |
|
|
|
public abstract long getTime(); |
|
|
|
|
|
|
|
/** |
|
|
|
* @return size of class file. |
|
|
|
*/ |
|
|
|
public abstract long getSize(); |
|
|
|
} |
|
|
|
|
|
|
|
private static class Dir extends PathEntry { |
|
|
|
private String dir; |
|
|
|
|
|
|
|
Dir(String d) { |
|
|
|
dir = d; |
|
|
|
} |
|
|
|
|
|
|
|
ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
final File file = new File(dir + File.separatorChar + name.replace('.', File.separatorChar) + suffix); |
|
|
|
|
|
|
|
return file.exists() ? new ClassFile() { |
|
|
|
public InputStream getInputStream() throws IOException { |
|
|
|
return new FileInputStream(file); |
|
|
|
} |
|
|
|
|
|
|
|
public String getPath() { |
|
|
|
try { |
|
|
|
return file.getCanonicalPath(); |
|
|
|
} catch (IOException e) { |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
public long getTime() { |
|
|
|
return file.lastModified(); |
|
|
|
} |
|
|
|
|
|
|
|
public long getSize() { |
|
|
|
return file.length(); |
|
|
|
} |
|
|
|
|
|
|
|
public String getBase() { |
|
|
|
return dir; |
|
|
|
} |
|
|
|
|
|
|
|
} : null; |
|
|
|
} |
|
|
|
|
|
|
|
public String toString() { |
|
|
|
return dir; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static class JImage extends PathEntry { |
|
|
|
private java.nio.file.FileSystem fs; |
|
|
|
|
|
|
|
private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$ |
|
|
|
|
|
|
|
private static String MODULES_PATH = "modules"; //$NON-NLS-1$ |
|
|
|
private static String JAVA_BASE_PATH = "java.base"; //$NON-NLS-1$ |
|
|
|
|
|
|
|
|
|
|
|
JImage(File jimage) { |
|
|
|
// TODO bizarre that you use getFileSystem with just the jrt:/ and not the path !! What happens |
|
|
|
// if there are two? |
|
|
|
fs = FileSystems.getFileSystem(JRT_URI);//.create(jimage.getAbsolutePath())); |
|
|
|
} |
|
|
|
|
|
|
|
private static class ByteBasedClassFile implements ClassFile { |
|
|
|
|
|
|
|
private byte[] bytes; |
|
|
|
private ByteArrayInputStream bais; |
|
|
|
private String path; |
|
|
|
private String base; |
|
|
|
private long time; |
|
|
|
private long size; |
|
|
|
|
|
|
|
public ByteBasedClassFile(byte[] bytes, String path, String base, long time, long size) { |
|
|
|
this.bytes = bytes; |
|
|
|
this.path = path; |
|
|
|
this.base = base; |
|
|
|
this.time = time; |
|
|
|
this.size = size; |
|
|
|
} |
|
|
|
|
|
|
|
public InputStream getInputStream() throws IOException { |
|
|
|
// TODO too costly to keep these in inflated form in memory? |
|
|
|
this.bais = new ByteArrayInputStream(bytes); |
|
|
|
return this.bais; |
|
|
|
} |
|
|
|
|
|
|
|
public String getPath() { |
|
|
|
return this.path; |
|
|
|
} |
|
|
|
|
|
|
|
public String getBase() { |
|
|
|
return this.base; |
|
|
|
} |
|
|
|
|
|
|
|
public long getTime() { |
|
|
|
return this.time; |
|
|
|
} |
|
|
|
|
|
|
|
public long getSize() { |
|
|
|
return this.size; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
// Class files are in here under names like this: |
|
|
|
// /modules/java.base/java/lang/Object.class (jdk9 b74) |
|
|
|
// so within a modules top level qualifier and then the java.base module |
|
|
|
String fileName = name + suffix; |
|
|
|
try { |
|
|
|
Path p = fs.getPath(MODULES_PATH,JAVA_BASE_PATH,fileName); |
|
|
|
byte[] bs = Files.readAllBytes(p); |
|
|
|
BasicFileAttributeView bfav = Files.getFileAttributeView(p, BasicFileAttributeView.class); |
|
|
|
BasicFileAttributes bfas = bfav.readAttributes(); |
|
|
|
long time = bfas.lastModifiedTime().toMillis(); |
|
|
|
long size = bfas.size(); |
|
|
|
return new ByteBasedClassFile(bs, "jimage",fileName,time,size); |
|
|
|
} catch (NoSuchFileException nsfe) { |
|
|
|
// try other modules! |
|
|
|
Iterable<java.nio.file.Path> roots = fs.getRootDirectories(); |
|
|
|
roots = fs.getRootDirectories(); |
|
|
|
for (java.nio.file.Path path : roots) { |
|
|
|
DirectoryStream<java.nio.file.Path> stream = Files.newDirectoryStream(path); |
|
|
|
try { |
|
|
|
for (java.nio.file.Path module: stream) { |
|
|
|
// module will be something like /packages or /modules |
|
|
|
for (java.nio.file.Path submodule: Files.newDirectoryStream(module)) { |
|
|
|
// submodule will be /modules/java.base or somesuch |
|
|
|
try { |
|
|
|
Path p = fs.getPath(submodule.toString(), fileName); |
|
|
|
byte[] bs = Files.readAllBytes(p); |
|
|
|
BasicFileAttributeView bfav = Files.getFileAttributeView(p, BasicFileAttributeView.class); |
|
|
|
BasicFileAttributes bfas = bfav.readAttributes(); |
|
|
|
long time = bfas.lastModifiedTime().toMillis(); |
|
|
|
long size = bfas.size(); |
|
|
|
return new ByteBasedClassFile(bs, "jimage", fileName,time,size); |
|
|
|
} catch (NoSuchFileException nsfe2) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} finally { |
|
|
|
stream.close(); |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static class Zip extends PathEntry { |
|
|
|
private ZipFile zip; |
|
|
|
|
|
|
|
Zip(ZipFile z) { |
|
|
|
zip = z; |
|
|
|
} |
|
|
|
|
|
|
|
ClassFile getClassFile(String name, String suffix) throws IOException { |
|
|
|
final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix); |
|
|
|
|
|
|
|
return (entry != null) ? new ClassFile() { |
|
|
|
public InputStream getInputStream() throws IOException { |
|
|
|
return zip.getInputStream(entry); |
|
|
|
} |
|
|
|
|
|
|
|
public String getPath() { |
|
|
|
return entry.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
public long getTime() { |
|
|
|
return entry.getTime(); |
|
|
|
} |
|
|
|
|
|
|
|
public long getSize() { |
|
|
|
return entry.getSize(); |
|
|
|
} |
|
|
|
|
|
|
|
public String getBase() { |
|
|
|
return zip.getName(); |
|
|
|
} |
|
|
|
} : null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |