📄 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 + -