📄 classreader.java
字号:
} else if (checkClassFile && majorVersion == Target.MAX().majorVersion &&
minorVersion > Target.MAX().minorVersion) {
printCCF("found.later.version", Integer.toString(minorVersion));
}
indexPool();
readClass(c);
}
/**
* Is this the name of a zip file?
*/
boolean isZip(String name) {
return new File(name).isFile();
}
/**
* An archive consists of a zipfile and a list of zip entries in
* that file.
*/
static class Archive {
ZipFile zdir;
List entries;
Archive(ZipFile zdir, List entries) {
super();
this.zdir = zdir;
this.entries = entries;
}
}
/**
* A directory of zip files already opened.
*/
Hashtable archives = Hashtable.make();
/**
* Open a new zip file directory.
*/
Archive openArchive(String dirname) throws IOException {
Archive archive = (ClassReader.Archive) archives.get(dirname);
if (archive == null) {
ZipFile zdir = new ZipFile(dirname);
ListBuffer entries = new ListBuffer();
for (java.util.Enumeration e = zdir.entries(); e.hasMoreElements();) {
entries.append((ZipEntry) e.nextElement());
}
archive = new Archive(zdir, entries.toList());
archives.put(dirname, archive);
}
return archive;
}
/**
* Close the ClassReader, releasing resources.
*/
public void close() {
for (List dirnames = archives.keys(); dirnames.nonEmpty();
dirnames = dirnames.tail) {
Archive a = (ClassReader.Archive) archives.remove(dirnames.head);
try {
a.zdir.close();
} catch (IOException e) {
}
}
}
/**
* Define a new class given its name and owner.
*/
public ClassSymbol defineClass(Name name, Symbol owner) {
ClassSymbol c = new ClassSymbol(0, name, owner);
c.completer = this;
return c;
}
/**
* Create a new toplevel or member class symbol with given name
* and owner and enter in `classes' unless already there.
*/
public ClassSymbol enterClass(Name name, TypeSymbol owner) {
Name flatname = TypeSymbol.formFlatName(name, owner);
ClassSymbol c = (ClassSymbol) classes.get(flatname);
if (c == null) {
c = defineClass(name, owner);
classes.put(flatname, c);
} else if ((c.name != name || c.owner != owner) && owner.kind == TYP) {
c.name = name;
c.owner = owner;
c.fullname = ClassSymbol.formFullName(name, owner);
}
return c;
}
/**
* Create a new member or toplevel class symbol with given flat name
* and enter in `classes' unless already there.
*/
public ClassSymbol enterClass(Name flatname) {
ClassSymbol c = (ClassSymbol) classes.get(flatname);
if (c == null) {
Name packageName = Convert.packagePart(flatname);
if (packageName == names.empty)
packageName = names.emptyPackage;
c = defineClass(Convert.shortName(flatname), enterPackage(packageName));
classes.put(flatname, c);
}
return c;
}
/**
* Completion for classes to be loaded. Before a class is loaded
* we make sure its enclosing class (if any) is loaded.
*/
public void complete(Symbol sym) throws CompletionFailure {
if (sym.kind == TYP) {
ClassSymbol c = (ClassSymbol) sym;
c.members_field = new Scope.ErrorScope(c);
c.owner.complete();
fillIn(c);
} else if (sym.kind == PCK) {
PackageSymbol p = (PackageSymbol) sym;
fillIn(p);
}
}
/**
* We can only read a single class file at a time; this
* flag keeps track of when we are currently reading a class
* file.
*/
private boolean filling = false;
/**
* Fill in definition of class `c' from corresponding class or
* source file.
*/
private void fillIn(ClassSymbol c) {
if (completionFailureName == c.fullname) {
throw new CompletionFailure(c, "user-selected completion failure by class name");
}
currentOwner = c;
FileEntry classfile = c.classfile;
if (classfile != null) {
try {
assert ! filling;
InputStream s = classfile.open();
currentClassFileName = classfile.getPath();
if (verbose) {
printVerbose("loading", currentClassFileName);
}
if (classfile.getName().endsWith(".class")) {
filling = true;
int size = (int) classfile.length();
if (buf.length < size)
buf = new byte[size];
int n = 0;
while (n < size)
n = n + s.read(buf, n, size - n);
s.close();
bp = 0;
readClassFile(c);
} else {
sourceCompleter.complete(c, currentClassFileName, s);
}
return;
} catch (IOException ex) {
throw badClassFile("unable.to.access.file", ex.getMessage());
}
finally { filling = false;
} } else {
String fn = externalizeFileName(c.flatname);
throw newCompletionFailure(c,
Log.getLocalizedString("dot.class.not.found", fn));
}
}
/**
* Static factory for CompletionFailure objects.
* In practice, only one can be used at a time, so we share one
* to reduce the expense of allocating new exception objects.
*/
private CompletionFailure newCompletionFailure(ClassSymbol c, String localized) {
CompletionFailure result = cachedCompletionFailure;
result.sym = c;
result.errmsg = localized;
return result;
}
private CompletionFailure cachedCompletionFailure =
new CompletionFailure(null, null);
/**
* Load a toplevel class with given fully qualified name
* The class is entered into `classes' only if load was successful.
*/
public ClassSymbol loadClass(Name flatname) throws CompletionFailure {
boolean absent = classes.get(flatname) == null;
ClassSymbol c = enterClass(flatname);
if (c.members_field == null && c.completer != null) {
try {
c.complete();
} catch (CompletionFailure ex) {
if (absent)
classes.remove(flatname);
throw ex;
}
}
return c;
}
/**
* Check to see if a package exists, given its fully qualified name.
*/
public boolean packageExists(Name fullname) {
return enterPackage(fullname).exists();
}
/**
* Make a package, given its fully qualified name.
*/
public PackageSymbol enterPackage(Name fullname) {
PackageSymbol p = (PackageSymbol) packages.get(fullname);
if (p == null) {
assert fullname.length() != 0 :
"rootPackage missing!";
p = new PackageSymbol(Convert.shortName(fullname),
enterPackage(Convert.packagePart(fullname)));
p.completer = this;
packages.put(fullname, p);
}
return p;
}
/**
* Make a package, given its unqualified name and enclosing package.
*/
public PackageSymbol enterPackage(Name name, PackageSymbol owner) {
return enterPackage(TypeSymbol.formFullName(name, owner));
}
/**
* Include class corresponding to given class file in package,
* unless (1) we already have one the same kind (.class or .java), or
* (2) we have one of the other kind, and the given class file
* is older.
*/
private void includeClassFile(PackageSymbol p, FileEntry file) {
if ((p.flags_field & EXISTS) == 0)
for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
q.flags_field |= EXISTS;
String filename = file.getName();
int seen;
int extlen;
if (filename.endsWith(".class")) {
seen = CLASS_SEEN;
extlen = 6;
} else {
seen = SOURCE_SEEN;
extlen = 5;
}
Name classname =
names.fromString(filename.substring(0, filename.length() - extlen));
ClassSymbol c = (ClassSymbol) p.members_field.lookup(classname).sym;
if (c == null) {
c = enterClass(classname, p);
c.classfile = file;
if (c.owner == p)
p.members_field.enter(c);
} else if (c.classfile != null && (c.flags_field & seen) == 0) {
if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) {
long fdate = file.lastModified();
long cdate = c.classfile.lastModified();
if (fdate >= 0 && cdate >= 0 && fdate > cdate) {
c.classfile = file;
}
}
}
c.flags_field |= seen;
}
/**
* Insert all files in subdirectory `name' of `pathname'
* which end in one of the extensions in `extensions' into package.
*/
private void list(String pathname, String name, String[] extensions,
PackageSymbol p) {
try {
if (isZip(pathname)) {
Archive archive = openArchive(pathname);
if (name.length() != 0) {
name = name.replace('\\', '/');
if (!name.endsWith("/"))
name = name + "/";
}
int namelen = name.length();
for (List l = archive.entries; l.nonEmpty(); l = l.tail) {
ZipEntry entry = (ZipEntry) l.head;
String ename = entry.getName();
if (ename.startsWith(name)) {
if (endsWith(ename, extensions)) {
String suffix = ename.substring(namelen);
if (suffix.length() > 0 && suffix.indexOf('/') < 0) {
includeClassFile(p,
new FileEntry.Zipped(suffix,
archive.zdir, entry));
}
} else
extraZipFileActions(p, ename, name, pathname);
}
}
} else {
File f = name.length() != 0 ? new File(pathname, name) :
new File(pathname);
String[] names = f.list();
if (names != null && caseMapCheck(f, name)) {
for (int i = 0; i < names.length; i++) {
String fname = names[i];
if (isValidFile(fname, extensions)) {
includeClassFile(p,
new FileEntry.Regular(fname, new File(f, fname)));
} else
extraFileActions(p, fname, f);
}
}
}
} catch (IOException ex) {
}
}
private boolean endsWith(String s, String[] extensions) {
for (int i = 0; i < extensions.length; i++)
if (s.endsWith(extensions[i]))
return true;
return false;
}
private boolean isValidFile(String s, String[] extensions) {
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
if (s.endsWith(extension) && isJavaIdentifier(
s.substring(0, s.length() - extension.length())))
return true;
}
return false;
}
private boolean isJavaIdentifier(String s) {
if (s.length() < 1)
return false;
if (!Character.isJavaIdentifierStart(s.charAt(0)))
return false;
for (int j = 1; j < s.length(); j++)
if (!Character.isJavaIdentifierPart(s.charAt(j)))
return false;
return true;
}
static final boolean fileSystemIsCaseSensitive = File.separatorChar == '/';
/**
* Hack to make Windows case sensitive. Test whether given path
* ends in a string of characters with the same case as given name.
* Ignore file separators in both path and name.
*/
private boolean caseMapCheck(File f, String name) throws IOException {
if (fileSystemIsCaseSensitive)
return true;
String path = f.getCanonicalPath();
char[] pcs = path.toCharArray();
char[] ncs = name.toCharArray();
int i = pcs.length - 1;
int j = ncs.length - 1;
while (i >= 0 && j >= 0) {
while (i >= 0 && pcs[i] == File.separatorChar)
i--;
while (j >= 0 && ncs[j] == File.separatorChar)
j--;
if (i >= 0 && j >= 0) {
if (pcs[i] != ncs[j])
return false;
i--;
j--;
}
}
return j < 0;
}
/**
* These are used to support javadoc
*/
protected void extraZipFileActions(PackageSymbol pack, String zipEntryName,
String classPathName, String zipName) {
}
protected void extraFileActions(PackageSymbol pack, String fileName,
File fileDir) {
}
/**
* Insert all files in subdirectory `name' somewhere on
* class path `path' which end in one of the extensions in `extensions'
* into package.
*/
private void listAll(String path, String name, String[] extensions,
PackageSymbol p) {
int i = 0;
int plen = path.length();
while (i < plen) {
int end = path.indexOf(pathSep, i);
String pathname = path.substring(i, end);
list(pathname, name, extensions, p);
i = end + 1;
}
}
static final String[] classOnly = {".class"};
static final String[] javaOnly = {".java"};
static final String[] classOrJava = {".class", ".java"};
/**
* Load directory of package into members scope.
*/
private void fillIn(PackageSymbol p) {
if (p.members_field == null)
p.members_field = new Scope(p);
Name packageName = p.fullname;
if (packageName == names.emptyPackage)
packageName = names.empty;
String dirname = externalizeFileName(packageName);
listAll(bootClassPath, dirname, classOnly, p);
if (sourceCompleter != null && sourceClassPath == null) {
listAll(classPath, dirname, classOrJava, p);
} else {
listAll(classPath, dirname, classOnly, p);
if (sourceCompleter != null) {
listAll(sourceClassPath, dirname, javaOnly, p);
}
}
}
/**
* Output for "-verbose" option.
* @param key The key to look up the correct internationalized string.
* @param arg An argument for substitution into the output string.
*/
private void printVerbose(String key, String arg) {
Log.printLines(log.noticeWriter,
Log.getLocalizedString("verbose." + key, arg));
}
/**
* Output for "-checkclassfile" option.
* @param key The key to look up the correct internationalized string.
* @param arg An argument for substitution into the output string.
*/
private void printCCF(String key, String arg) {
Log.printLines(log.noticeWriter,
Log.getLocalizedString("verbose." + key, arg));
}
public interface SourceCompleter {
void complete(ClassSymbol sym, String filename,
InputStream f) throws CompletionFailure;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -