--- old/langtools/src/jdk.compiler/share/classes/com/sun/tools/javap/JavapTask.java 2015-05-26 21:42:35.775833065 -0700 +++ /dev/null 2015-04-26 22:05:36.465433038 -0700 @@ -1,1068 +0,0 @@ -/* - * Copyright (c) 2007, 2014, 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.javap; - -import java.io.EOFException; -import java.io.FileNotFoundException; -import java.io.FilterInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.NoSuchFileException; -import java.security.DigestInputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.Objects; -import java.util.ResourceBundle; - -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; - -import com.sun.tools.classfile.*; -import com.sun.tools.javac.util.DefinedBy; -import com.sun.tools.javac.util.DefinedBy.Api; - -/** - * "Main" class for javap, normally accessed from the command line - * via Main, or from JSR199 via DisassemblerTool. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages { - public class BadArgs extends Exception { - static final long serialVersionUID = 8765093759964640721L; - BadArgs(String key, Object... args) { - super(JavapTask.this.getMessage(key, args)); - this.key = key; - this.args = args; - } - - BadArgs showUsage(boolean b) { - showUsage = b; - return this; - } - - final String key; - final Object[] args; - boolean showUsage; - } - - static abstract class Option { - Option(boolean hasArg, String... aliases) { - this.hasArg = hasArg; - this.aliases = aliases; - } - - boolean matches(String opt) { - for (String a: aliases) { - if (a.equals(opt)) - return true; - } - return false; - } - - boolean ignoreRest() { - return false; - } - - abstract void process(JavapTask task, String opt, String arg) throws BadArgs; - - final boolean hasArg; - final String[] aliases; - } - - static final Option[] recognizedOptions = { - - new Option(false, "-help", "--help", "-?") { - void process(JavapTask task, String opt, String arg) { - task.options.help = true; - } - }, - - new Option(false, "-version") { - void process(JavapTask task, String opt, String arg) { - task.options.version = true; - } - }, - - new Option(false, "-fullversion") { - void process(JavapTask task, String opt, String arg) { - task.options.fullVersion = true; - } - }, - - new Option(false, "-v", "-verbose", "-all") { - void process(JavapTask task, String opt, String arg) { - task.options.verbose = true; - task.options.showDescriptors = true; - task.options.showFlags = true; - task.options.showAllAttrs = true; - } - }, - - new Option(false, "-l") { - void process(JavapTask task, String opt, String arg) { - task.options.showLineAndLocalVariableTables = true; - } - }, - - new Option(false, "-public") { - void process(JavapTask task, String opt, String arg) { - task.options.accessOptions.add(opt); - task.options.showAccess = AccessFlags.ACC_PUBLIC; - } - }, - - new Option(false, "-protected") { - void process(JavapTask task, String opt, String arg) { - task.options.accessOptions.add(opt); - task.options.showAccess = AccessFlags.ACC_PROTECTED; - } - }, - - new Option(false, "-package") { - void process(JavapTask task, String opt, String arg) { - task.options.accessOptions.add(opt); - task.options.showAccess = 0; - } - }, - - new Option(false, "-p", "-private") { - void process(JavapTask task, String opt, String arg) { - if (!task.options.accessOptions.contains("-p") && - !task.options.accessOptions.contains("-private")) { - task.options.accessOptions.add(opt); - } - task.options.showAccess = AccessFlags.ACC_PRIVATE; - } - }, - - new Option(false, "-c") { - void process(JavapTask task, String opt, String arg) { - task.options.showDisassembled = true; - } - }, - - new Option(false, "-s") { - void process(JavapTask task, String opt, String arg) { - task.options.showDescriptors = true; - } - }, - - new Option(false, "-sysinfo") { - void process(JavapTask task, String opt, String arg) { - task.options.sysInfo = true; - } - }, - - new Option(false, "-XDdetails") { - void process(JavapTask task, String opt, String arg) { - task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); - } - - }, - - new Option(false, "-XDdetails:") { - @Override - boolean matches(String opt) { - int sep = opt.indexOf(":"); - return sep != -1 && super.matches(opt.substring(0, sep + 1)); - } - - void process(JavapTask task, String opt, String arg) throws BadArgs { - int sep = opt.indexOf(":"); - for (String v: opt.substring(sep + 1).split("[,: ]+")) { - if (!handleArg(task, v)) - throw task.new BadArgs("err.invalid.arg.for.option", v); - } - } - - boolean handleArg(JavapTask task, String arg) { - if (arg.length() == 0) - return true; - - if (arg.equals("all")) { - task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); - return true; - } - - boolean on = true; - if (arg.startsWith("-")) { - on = false; - arg = arg.substring(1); - } - - for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) { - if (arg.equalsIgnoreCase(k.option)) { - if (on) - task.options.details.add(k); - else - task.options.details.remove(k); - return true; - } - } - return false; - } - }, - - new Option(false, "-constants") { - void process(JavapTask task, String opt, String arg) { - task.options.showConstants = true; - } - }, - - new Option(false, "-XDinner") { - void process(JavapTask task, String opt, String arg) { - task.options.showInnerClasses = true; - } - }, - - new Option(false, "-XDindent:") { - @Override - boolean matches(String opt) { - int sep = opt.indexOf(":"); - return sep != -1 && super.matches(opt.substring(0, sep + 1)); - } - - void process(JavapTask task, String opt, String arg) throws BadArgs { - int sep = opt.indexOf(":"); - try { - int i = Integer.valueOf(opt.substring(sep + 1)); - if (i > 0) // silently ignore invalid values - task.options.indentWidth = i; - } catch (NumberFormatException e) { - } - } - }, - - new Option(false, "-XDtab:") { - @Override - boolean matches(String opt) { - int sep = opt.indexOf(":"); - return sep != -1 && super.matches(opt.substring(0, sep + 1)); - } - - void process(JavapTask task, String opt, String arg) throws BadArgs { - int sep = opt.indexOf(":"); - try { - int i = Integer.valueOf(opt.substring(sep + 1)); - if (i > 0) // silently ignore invalid values - task.options.tabColumn = i; - } catch (NumberFormatException e) { - } - } - } - - }; - - public JavapTask() { - context = new Context(); - context.put(Messages.class, this); - options = Options.instance(context); - attributeFactory = new Attribute.Factory(); - } - - public JavapTask(Writer out, - JavaFileManager fileManager, - DiagnosticListener diagnosticListener) { - this(); - this.log = getPrintWriterForWriter(out); - this.fileManager = fileManager; - this.diagnosticListener = diagnosticListener; - } - - public JavapTask(Writer out, - JavaFileManager fileManager, - DiagnosticListener diagnosticListener, - Iterable options, - Iterable classes) { - this(out, fileManager, diagnosticListener); - - this.classes = new ArrayList<>(); - for (String classname: classes) { - Objects.requireNonNull(classname); - this.classes.add(classname); - } - - try { - if (options != null) - handleOptions(options, false); - } catch (BadArgs e) { - throw new IllegalArgumentException(e.getMessage()); - } - } - - public void setLocale(Locale locale) { - if (locale == null) - locale = Locale.getDefault(); - task_locale = locale; - } - - public void setLog(Writer log) { - this.log = getPrintWriterForWriter(log); - } - - public void setLog(OutputStream s) { - setLog(getPrintWriterForStream(s)); - } - - private static PrintWriter getPrintWriterForStream(OutputStream s) { - return new PrintWriter(s == null ? System.err : s, true); - } - - private static PrintWriter getPrintWriterForWriter(Writer w) { - if (w == null) - return getPrintWriterForStream(null); - else if (w instanceof PrintWriter) - return (PrintWriter) w; - else - return new PrintWriter(w, true); - } - - public void setDiagnosticListener(DiagnosticListener dl) { - diagnosticListener = dl; - } - - public void setDiagnosticListener(OutputStream s) { - setDiagnosticListener(getDiagnosticListenerForStream(s)); - } - - private DiagnosticListener getDiagnosticListenerForStream(OutputStream s) { - return getDiagnosticListenerForWriter(getPrintWriterForStream(s)); - } - - private DiagnosticListener getDiagnosticListenerForWriter(Writer w) { - final PrintWriter pw = getPrintWriterForWriter(w); - return new DiagnosticListener () { - @DefinedBy(Api.COMPILER) - public void report(Diagnostic diagnostic) { - switch (diagnostic.getKind()) { - case ERROR: - pw.print(getMessage("err.prefix")); - break; - case WARNING: - pw.print(getMessage("warn.prefix")); - break; - case NOTE: - pw.print(getMessage("note.prefix")); - break; - } - pw.print(" "); - pw.println(diagnostic.getMessage(null)); - } - }; - } - - /** Result codes. - */ - static final int - EXIT_OK = 0, // Compilation completed with no errors. - EXIT_ERROR = 1, // Completed but reported errors. - EXIT_CMDERR = 2, // Bad command-line arguments - EXIT_SYSERR = 3, // System error or resource exhaustion. - EXIT_ABNORMAL = 4; // Compiler terminated abnormally - - int run(String[] args) { - try { - try { - handleOptions(args); - - // the following gives consistent behavior with javac - if (classes == null || classes.size() == 0) { - if (options.help || options.version || options.fullVersion) - return EXIT_OK; - else - return EXIT_CMDERR; - } - - return run(); - } finally { - if (defaultFileManager != null) { - try { - defaultFileManager.close(); - defaultFileManager = null; - } catch (IOException e) { - throw new InternalError(e); - } - } - } - } catch (BadArgs e) { - reportError(e.key, e.args); - if (e.showUsage) { - printLines(getMessage("main.usage.summary", progname)); - } - return EXIT_CMDERR; - } catch (InternalError e) { - Object[] e_args; - if (e.getCause() == null) - e_args = e.args; - else { - e_args = new Object[e.args.length + 1]; - e_args[0] = e.getCause(); - System.arraycopy(e.args, 0, e_args, 1, e.args.length); - } - reportError("err.internal.error", e_args); - return EXIT_ABNORMAL; - } finally { - log.flush(); - } - } - - public void handleOptions(String[] args) throws BadArgs { - handleOptions(Arrays.asList(args), true); - } - - private void handleOptions(Iterable args, boolean allowClasses) throws BadArgs { - if (log == null) { - log = getPrintWriterForStream(System.out); - if (diagnosticListener == null) - diagnosticListener = getDiagnosticListenerForStream(System.err); - } else { - if (diagnosticListener == null) - diagnosticListener = getDiagnosticListenerForWriter(log); - } - - - if (fileManager == null) - fileManager = getDefaultFileManager(diagnosticListener, log); - - Iterator iter = args.iterator(); - boolean noArgs = !iter.hasNext(); - - while (iter.hasNext()) { - String arg = iter.next(); - if (arg.startsWith("-")) - handleOption(arg, iter); - else if (allowClasses) { - if (classes == null) - classes = new ArrayList<>(); - classes.add(arg); - while (iter.hasNext()) - classes.add(iter.next()); - } else - throw new BadArgs("err.unknown.option", arg).showUsage(true); - } - - if (options.accessOptions.size() > 1) { - StringBuilder sb = new StringBuilder(); - for (String opt: options.accessOptions) { - if (sb.length() > 0) - sb.append(" "); - sb.append(opt); - } - throw new BadArgs("err.incompatible.options", sb); - } - - if ((classes == null || classes.size() == 0) && - !(noArgs || options.help || options.version || options.fullVersion)) { - throw new BadArgs("err.no.classes.specified"); - } - - if (noArgs || options.help) - showHelp(); - - if (options.version || options.fullVersion) - showVersion(options.fullVersion); - } - - private void handleOption(String name, Iterator rest) throws BadArgs { - for (Option o: recognizedOptions) { - if (o.matches(name)) { - if (o.hasArg) { - if (rest.hasNext()) - o.process(this, name, rest.next()); - else - throw new BadArgs("err.missing.arg", name).showUsage(true); - } else - o.process(this, name, null); - - if (o.ignoreRest()) { - while (rest.hasNext()) - rest.next(); - } - return; - } - } - - try { - if (fileManager.handleOption(name, rest)) - return; - } catch (IllegalArgumentException e) { - throw new BadArgs("err.invalid.use.of.option", name).showUsage(true); - } - - throw new BadArgs("err.unknown.option", name).showUsage(true); - } - - public Boolean call() { - return run() == 0; - } - - public int run() { - if (classes == null || classes.isEmpty()) { - return EXIT_ERROR; - } - - context.put(PrintWriter.class, log); - ClassWriter classWriter = ClassWriter.instance(context); - SourceWriter sourceWriter = SourceWriter.instance(context); - sourceWriter.setFileManager(fileManager); - - int result = EXIT_OK; - - for (String className: classes) { - try { - result = writeClass(classWriter, className); - } catch (ConstantPoolException e) { - reportError("err.bad.constant.pool", className, e.getLocalizedMessage()); - result = EXIT_ERROR; - } catch (EOFException e) { - reportError("err.end.of.file", className); - result = EXIT_ERROR; - } catch (FileNotFoundException | NoSuchFileException e) { - reportError("err.file.not.found", e.getLocalizedMessage()); - result = EXIT_ERROR; - } catch (IOException e) { - //e.printStackTrace(); - Object msg = e.getLocalizedMessage(); - if (msg == null) { - msg = e; - } - reportError("err.ioerror", className, msg); - result = EXIT_ERROR; - } catch (OutOfMemoryError e) { - reportError("err.nomem"); - result = EXIT_ERROR; - } catch (Throwable t) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - pw.close(); - reportError("err.crash", t.toString(), sw.toString()); - result = EXIT_ABNORMAL; - } - } - - return result; - } - - protected int writeClass(ClassWriter classWriter, String className) - throws IOException, ConstantPoolException { - JavaFileObject fo = open(className); - if (fo == null) { - reportError("err.class.not.found", className); - return EXIT_ERROR; - } - - ClassFileInfo cfInfo = read(fo); - if (!className.endsWith(".class")) { - String cfName = cfInfo.cf.getName(); - if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", "."))) { - reportWarning("warn.unexpected.class", className, cfName.replace('/', '.')); - } - } - write(cfInfo); - - if (options.showInnerClasses) { - ClassFile cf = cfInfo.cf; - Attribute a = cf.getAttribute(Attribute.InnerClasses); - if (a instanceof InnerClasses_attribute) { - InnerClasses_attribute inners = (InnerClasses_attribute) a; - try { - int result = EXIT_OK; - for (int i = 0; i < inners.classes.length; i++) { - int outerIndex = inners.classes[i].outer_class_info_index; - ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex); - String outerClassName = outerClassInfo.getName(); - if (outerClassName.equals(cf.getName())) { - int innerIndex = inners.classes[i].inner_class_info_index; - ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex); - String innerClassName = innerClassInfo.getName(); - classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", ".")); - classWriter.println(); - result = writeClass(classWriter, innerClassName); - if (result != EXIT_OK) return result; - } - } - return result; - } catch (ConstantPoolException e) { - reportError("err.bad.innerclasses.attribute", className); - return EXIT_ERROR; - } - } else if (a != null) { - reportError("err.bad.innerclasses.attribute", className); - return EXIT_ERROR; - } - } - - return EXIT_OK; - } - - protected JavaFileObject open(String className) throws IOException { - // for compatibility, first see if it is a class name - JavaFileObject fo = getClassFileObject(className); - if (fo != null) - return fo; - - // see if it is an inner class, by replacing dots to $, starting from the right - String cn = className; - int lastDot; - while ((lastDot = cn.lastIndexOf(".")) != -1) { - cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1); - fo = getClassFileObject(cn); - if (fo != null) - return fo; - } - - if (!className.endsWith(".class")) - return null; - - if (fileManager instanceof StandardJavaFileManager) { - StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; - try { - fo = sfm.getJavaFileObjects(className).iterator().next(); - if (fo != null && fo.getLastModified() != 0) { - return fo; - } - } catch (IllegalArgumentException ignore) { - } - } - - // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject - // to suit javap's needs - if (className.matches("^[A-Za-z]+:.*")) { - try { - final URI uri = new URI(className); - final URL url = uri.toURL(); - final URLConnection conn = url.openConnection(); - conn.setUseCaches(false); - return new JavaFileObject() { - @DefinedBy(Api.COMPILER) - public Kind getKind() { - return JavaFileObject.Kind.CLASS; - } - - @DefinedBy(Api.COMPILER) - public boolean isNameCompatible(String simpleName, Kind kind) { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public NestingKind getNestingKind() { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public Modifier getAccessLevel() { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public URI toUri() { - return uri; - } - - @DefinedBy(Api.COMPILER) - public String getName() { - return uri.toString(); - } - - @DefinedBy(Api.COMPILER) - public InputStream openInputStream() throws IOException { - return conn.getInputStream(); - } - - @DefinedBy(Api.COMPILER) - public OutputStream openOutputStream() throws IOException { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public Reader openReader(boolean ignoreEncodingErrors) throws IOException { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public Writer openWriter() throws IOException { - throw new UnsupportedOperationException(); - } - - @DefinedBy(Api.COMPILER) - public long getLastModified() { - return conn.getLastModified(); - } - - @DefinedBy(Api.COMPILER) - public boolean delete() { - throw new UnsupportedOperationException(); - } - - }; - } catch (URISyntaxException | IOException ignore) { - } - } - - return null; - } - - public static class ClassFileInfo { - ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) { - this.fo = fo; - this.cf = cf; - this.digest = digest; - this.size = size; - } - public final JavaFileObject fo; - public final ClassFile cf; - public final byte[] digest; - public final int size; - } - - public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException { - InputStream in = fo.openInputStream(); - try { - SizeInputStream sizeIn = null; - MessageDigest md = null; - if (options.sysInfo || options.verbose) { - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException ignore) { - } - in = new DigestInputStream(in, md); - in = sizeIn = new SizeInputStream(in); - } - - ClassFile cf = ClassFile.read(in, attributeFactory); - byte[] digest = (md == null) ? null : md.digest(); - int size = (sizeIn == null) ? -1 : sizeIn.size(); - return new ClassFileInfo(fo, cf, digest, size); - } finally { - in.close(); - } - } - - public void write(ClassFileInfo info) { - ClassWriter classWriter = ClassWriter.instance(context); - if (options.sysInfo || options.verbose) { - classWriter.setFile(info.fo.toUri()); - classWriter.setLastModified(info.fo.getLastModified()); - classWriter.setDigest("MD5", info.digest); - classWriter.setFileSize(info.size); - } - - classWriter.write(info.cf); - } - - protected void setClassFile(ClassFile classFile) { - ClassWriter classWriter = ClassWriter.instance(context); - classWriter.setClassFile(classFile); - } - - protected void setMethod(Method enclosingMethod) { - ClassWriter classWriter = ClassWriter.instance(context); - classWriter.setMethod(enclosingMethod); - } - - protected void write(Attribute value) { - AttributeWriter attrWriter = AttributeWriter.instance(context); - ClassWriter classWriter = ClassWriter.instance(context); - ClassFile cf = classWriter.getClassFile(); - attrWriter.write(cf, value, cf.constant_pool); - } - - protected void write(Attributes attrs) { - AttributeWriter attrWriter = AttributeWriter.instance(context); - ClassWriter classWriter = ClassWriter.instance(context); - ClassFile cf = classWriter.getClassFile(); - attrWriter.write(cf, attrs, cf.constant_pool); - } - - protected void write(ConstantPool constant_pool) { - ConstantWriter constantWriter = ConstantWriter.instance(context); - constantWriter.writeConstantPool(constant_pool); - } - - protected void write(ConstantPool constant_pool, int value) { - ConstantWriter constantWriter = ConstantWriter.instance(context); - constantWriter.write(value); - } - - protected void write(ConstantPool.CPInfo value) { - ConstantWriter constantWriter = ConstantWriter.instance(context); - constantWriter.println(value); - } - - protected void write(Field value) { - ClassWriter classWriter = ClassWriter.instance(context); - classWriter.writeField(value); - } - - protected void write(Method value) { - ClassWriter classWriter = ClassWriter.instance(context); - classWriter.writeMethod(value); - } - - private JavaFileManager getDefaultFileManager(final DiagnosticListener dl, PrintWriter log) { - if (defaultFileManager == null) - defaultFileManager = JavapFileManager.create(dl, log); - return defaultFileManager; - } - - private JavaFileObject getClassFileObject(String className) throws IOException { - try { - JavaFileObject fo; - fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); - if (fo == null) - fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); - return fo; - } catch (IllegalArgumentException e) { - return null; - } - } - - private void showHelp() { - printLines(getMessage("main.usage", progname)); - for (Option o: recognizedOptions) { - String name = o.aliases[0].substring(1); // there must always be at least one name - if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify")) - continue; - printLines(getMessage("main.opt." + name)); - } - String[] fmOptions = { "-classpath", "-cp", "-bootclasspath" }; - for (String o: fmOptions) { - if (fileManager.isSupportedOption(o) == -1) - continue; - String name = o.substring(1); - printLines(getMessage("main.opt." + name)); - } - - } - - private void showVersion(boolean full) { - printLines(version(full ? "full" : "release")); - } - - private void printLines(String msg) { - log.println(msg.replace("\n", nl)); - } - - private static final String nl = System.getProperty("line.separator"); - - private static final String versionRBName = "com.sun.tools.javap.resources.version"; - private static ResourceBundle versionRB; - - private String version(String key) { - // key=version: mm.nn.oo[-milestone] - // key=full: mm.mm.oo[-milestone]-build - if (versionRB == null) { - try { - versionRB = ResourceBundle.getBundle(versionRBName); - } catch (MissingResourceException e) { - return getMessage("version.resource.missing", System.getProperty("java.version")); - } - } - try { - return versionRB.getString(key); - } - catch (MissingResourceException e) { - return getMessage("version.unknown", System.getProperty("java.version")); - } - } - - private void reportError(String key, Object... args) { - diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args)); - } - - private void reportNote(String key, Object... args) { - diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args)); - } - - private void reportWarning(String key, Object... args) { - diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args)); - } - - private Diagnostic createDiagnostic( - final Diagnostic.Kind kind, final String key, final Object... args) { - return new Diagnostic() { - @DefinedBy(Api.COMPILER) - public Kind getKind() { - return kind; - } - - @DefinedBy(Api.COMPILER) - public JavaFileObject getSource() { - return null; - } - - @DefinedBy(Api.COMPILER) - public long getPosition() { - return Diagnostic.NOPOS; - } - - @DefinedBy(Api.COMPILER) - public long getStartPosition() { - return Diagnostic.NOPOS; - } - - @DefinedBy(Api.COMPILER) - public long getEndPosition() { - return Diagnostic.NOPOS; - } - - @DefinedBy(Api.COMPILER) - public long getLineNumber() { - return Diagnostic.NOPOS; - } - - @DefinedBy(Api.COMPILER) - public long getColumnNumber() { - return Diagnostic.NOPOS; - } - - @DefinedBy(Api.COMPILER) - public String getCode() { - return key; - } - - @DefinedBy(Api.COMPILER) - public String getMessage(Locale locale) { - return JavapTask.this.getMessage(locale, key, args); - } - - @Override - public String toString() { - return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]"; - } - - }; - - } - - public String getMessage(String key, Object... args) { - return getMessage(task_locale, key, args); - } - - public String getMessage(Locale locale, String key, Object... args) { - if (bundles == null) { - // could make this a HashMap> - // and for efficiency, keep a hard reference to the bundle for the task - // locale - bundles = new HashMap<>(); - } - - if (locale == null) - locale = Locale.getDefault(); - - ResourceBundle b = bundles.get(locale); - if (b == null) { - try { - b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale); - bundles.put(locale, b); - } catch (MissingResourceException e) { - throw new InternalError("Cannot find javap resource bundle for locale " + locale); - } - } - - try { - return MessageFormat.format(b.getString(key), args); - } catch (MissingResourceException e) { - throw new InternalError(e, key); - } - } - - protected Context context; - JavaFileManager fileManager; - JavaFileManager defaultFileManager; - PrintWriter log; - DiagnosticListener diagnosticListener; - List classes; - Options options; - //ResourceBundle bundle; - Locale task_locale; - Map bundles; - protected Attribute.Factory attributeFactory; - - private static final String progname = "javap"; - - private static class SizeInputStream extends FilterInputStream { - SizeInputStream(InputStream in) { - super(in); - } - - int size() { - return size; - } - - @Override - public int read(byte[] buf, int offset, int length) throws IOException { - int n = super.read(buf, offset, length); - if (n > 0) - size += n; - return n; - } - - @Override - public int read() throws IOException { - int b = super.read(); - size += 1; - return b; - } - - private int size; - } -} --- /dev/null 2015-04-26 22:05:36.465433038 -0700 +++ new/langtools/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java 2015-05-26 21:42:35.599833063 -0700 @@ -0,0 +1,1068 @@ +/* + * Copyright (c) 2007, 2014, 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.javap; + +import java.io.EOFException; +import java.io.FileNotFoundException; +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.io.Writer; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.NoSuchFileException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.Objects; +import java.util.ResourceBundle; + +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.tools.classfile.*; +import com.sun.tools.javac.util.DefinedBy; +import com.sun.tools.javac.util.DefinedBy.Api; + +/** + * "Main" class for javap, normally accessed from the command line + * via Main, or from JSR199 via DisassemblerTool. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages { + public class BadArgs extends Exception { + static final long serialVersionUID = 8765093759964640721L; + BadArgs(String key, Object... args) { + super(JavapTask.this.getMessage(key, args)); + this.key = key; + this.args = args; + } + + BadArgs showUsage(boolean b) { + showUsage = b; + return this; + } + + final String key; + final Object[] args; + boolean showUsage; + } + + static abstract class Option { + Option(boolean hasArg, String... aliases) { + this.hasArg = hasArg; + this.aliases = aliases; + } + + boolean matches(String opt) { + for (String a: aliases) { + if (a.equals(opt)) + return true; + } + return false; + } + + boolean ignoreRest() { + return false; + } + + abstract void process(JavapTask task, String opt, String arg) throws BadArgs; + + final boolean hasArg; + final String[] aliases; + } + + static final Option[] recognizedOptions = { + + new Option(false, "-help", "--help", "-?") { + void process(JavapTask task, String opt, String arg) { + task.options.help = true; + } + }, + + new Option(false, "-version") { + void process(JavapTask task, String opt, String arg) { + task.options.version = true; + } + }, + + new Option(false, "-fullversion") { + void process(JavapTask task, String opt, String arg) { + task.options.fullVersion = true; + } + }, + + new Option(false, "-v", "-verbose", "-all") { + void process(JavapTask task, String opt, String arg) { + task.options.verbose = true; + task.options.showDescriptors = true; + task.options.showFlags = true; + task.options.showAllAttrs = true; + } + }, + + new Option(false, "-l") { + void process(JavapTask task, String opt, String arg) { + task.options.showLineAndLocalVariableTables = true; + } + }, + + new Option(false, "-public") { + void process(JavapTask task, String opt, String arg) { + task.options.accessOptions.add(opt); + task.options.showAccess = AccessFlags.ACC_PUBLIC; + } + }, + + new Option(false, "-protected") { + void process(JavapTask task, String opt, String arg) { + task.options.accessOptions.add(opt); + task.options.showAccess = AccessFlags.ACC_PROTECTED; + } + }, + + new Option(false, "-package") { + void process(JavapTask task, String opt, String arg) { + task.options.accessOptions.add(opt); + task.options.showAccess = 0; + } + }, + + new Option(false, "-p", "-private") { + void process(JavapTask task, String opt, String arg) { + if (!task.options.accessOptions.contains("-p") && + !task.options.accessOptions.contains("-private")) { + task.options.accessOptions.add(opt); + } + task.options.showAccess = AccessFlags.ACC_PRIVATE; + } + }, + + new Option(false, "-c") { + void process(JavapTask task, String opt, String arg) { + task.options.showDisassembled = true; + } + }, + + new Option(false, "-s") { + void process(JavapTask task, String opt, String arg) { + task.options.showDescriptors = true; + } + }, + + new Option(false, "-sysinfo") { + void process(JavapTask task, String opt, String arg) { + task.options.sysInfo = true; + } + }, + + new Option(false, "-XDdetails") { + void process(JavapTask task, String opt, String arg) { + task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); + } + + }, + + new Option(false, "-XDdetails:") { + @Override + boolean matches(String opt) { + int sep = opt.indexOf(":"); + return sep != -1 && super.matches(opt.substring(0, sep + 1)); + } + + void process(JavapTask task, String opt, String arg) throws BadArgs { + int sep = opt.indexOf(":"); + for (String v: opt.substring(sep + 1).split("[,: ]+")) { + if (!handleArg(task, v)) + throw task.new BadArgs("err.invalid.arg.for.option", v); + } + } + + boolean handleArg(JavapTask task, String arg) { + if (arg.length() == 0) + return true; + + if (arg.equals("all")) { + task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class); + return true; + } + + boolean on = true; + if (arg.startsWith("-")) { + on = false; + arg = arg.substring(1); + } + + for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) { + if (arg.equalsIgnoreCase(k.option)) { + if (on) + task.options.details.add(k); + else + task.options.details.remove(k); + return true; + } + } + return false; + } + }, + + new Option(false, "-constants") { + void process(JavapTask task, String opt, String arg) { + task.options.showConstants = true; + } + }, + + new Option(false, "-XDinner") { + void process(JavapTask task, String opt, String arg) { + task.options.showInnerClasses = true; + } + }, + + new Option(false, "-XDindent:") { + @Override + boolean matches(String opt) { + int sep = opt.indexOf(":"); + return sep != -1 && super.matches(opt.substring(0, sep + 1)); + } + + void process(JavapTask task, String opt, String arg) throws BadArgs { + int sep = opt.indexOf(":"); + try { + int i = Integer.valueOf(opt.substring(sep + 1)); + if (i > 0) // silently ignore invalid values + task.options.indentWidth = i; + } catch (NumberFormatException e) { + } + } + }, + + new Option(false, "-XDtab:") { + @Override + boolean matches(String opt) { + int sep = opt.indexOf(":"); + return sep != -1 && super.matches(opt.substring(0, sep + 1)); + } + + void process(JavapTask task, String opt, String arg) throws BadArgs { + int sep = opt.indexOf(":"); + try { + int i = Integer.valueOf(opt.substring(sep + 1)); + if (i > 0) // silently ignore invalid values + task.options.tabColumn = i; + } catch (NumberFormatException e) { + } + } + } + + }; + + public JavapTask() { + context = new Context(); + context.put(Messages.class, this); + options = Options.instance(context); + attributeFactory = new Attribute.Factory(); + } + + public JavapTask(Writer out, + JavaFileManager fileManager, + DiagnosticListener diagnosticListener) { + this(); + this.log = getPrintWriterForWriter(out); + this.fileManager = fileManager; + this.diagnosticListener = diagnosticListener; + } + + public JavapTask(Writer out, + JavaFileManager fileManager, + DiagnosticListener diagnosticListener, + Iterable options, + Iterable classes) { + this(out, fileManager, diagnosticListener); + + this.classes = new ArrayList<>(); + for (String classname: classes) { + Objects.requireNonNull(classname); + this.classes.add(classname); + } + + try { + if (options != null) + handleOptions(options, false); + } catch (BadArgs e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + + public void setLocale(Locale locale) { + if (locale == null) + locale = Locale.getDefault(); + task_locale = locale; + } + + public void setLog(Writer log) { + this.log = getPrintWriterForWriter(log); + } + + public void setLog(OutputStream s) { + setLog(getPrintWriterForStream(s)); + } + + private static PrintWriter getPrintWriterForStream(OutputStream s) { + return new PrintWriter(s == null ? System.err : s, true); + } + + private static PrintWriter getPrintWriterForWriter(Writer w) { + if (w == null) + return getPrintWriterForStream(null); + else if (w instanceof PrintWriter) + return (PrintWriter) w; + else + return new PrintWriter(w, true); + } + + public void setDiagnosticListener(DiagnosticListener dl) { + diagnosticListener = dl; + } + + public void setDiagnosticListener(OutputStream s) { + setDiagnosticListener(getDiagnosticListenerForStream(s)); + } + + private DiagnosticListener getDiagnosticListenerForStream(OutputStream s) { + return getDiagnosticListenerForWriter(getPrintWriterForStream(s)); + } + + private DiagnosticListener getDiagnosticListenerForWriter(Writer w) { + final PrintWriter pw = getPrintWriterForWriter(w); + return new DiagnosticListener () { + @DefinedBy(Api.COMPILER) + public void report(Diagnostic diagnostic) { + switch (diagnostic.getKind()) { + case ERROR: + pw.print(getMessage("err.prefix")); + break; + case WARNING: + pw.print(getMessage("warn.prefix")); + break; + case NOTE: + pw.print(getMessage("note.prefix")); + break; + } + pw.print(" "); + pw.println(diagnostic.getMessage(null)); + } + }; + } + + /** Result codes. + */ + static final int + EXIT_OK = 0, // Compilation completed with no errors. + EXIT_ERROR = 1, // Completed but reported errors. + EXIT_CMDERR = 2, // Bad command-line arguments + EXIT_SYSERR = 3, // System error or resource exhaustion. + EXIT_ABNORMAL = 4; // Compiler terminated abnormally + + int run(String[] args) { + try { + try { + handleOptions(args); + + // the following gives consistent behavior with javac + if (classes == null || classes.size() == 0) { + if (options.help || options.version || options.fullVersion) + return EXIT_OK; + else + return EXIT_CMDERR; + } + + return run(); + } finally { + if (defaultFileManager != null) { + try { + defaultFileManager.close(); + defaultFileManager = null; + } catch (IOException e) { + throw new InternalError(e); + } + } + } + } catch (BadArgs e) { + reportError(e.key, e.args); + if (e.showUsage) { + printLines(getMessage("main.usage.summary", progname)); + } + return EXIT_CMDERR; + } catch (InternalError e) { + Object[] e_args; + if (e.getCause() == null) + e_args = e.args; + else { + e_args = new Object[e.args.length + 1]; + e_args[0] = e.getCause(); + System.arraycopy(e.args, 0, e_args, 1, e.args.length); + } + reportError("err.internal.error", e_args); + return EXIT_ABNORMAL; + } finally { + log.flush(); + } + } + + public void handleOptions(String[] args) throws BadArgs { + handleOptions(Arrays.asList(args), true); + } + + private void handleOptions(Iterable args, boolean allowClasses) throws BadArgs { + if (log == null) { + log = getPrintWriterForStream(System.out); + if (diagnosticListener == null) + diagnosticListener = getDiagnosticListenerForStream(System.err); + } else { + if (diagnosticListener == null) + diagnosticListener = getDiagnosticListenerForWriter(log); + } + + + if (fileManager == null) + fileManager = getDefaultFileManager(diagnosticListener, log); + + Iterator iter = args.iterator(); + boolean noArgs = !iter.hasNext(); + + while (iter.hasNext()) { + String arg = iter.next(); + if (arg.startsWith("-")) + handleOption(arg, iter); + else if (allowClasses) { + if (classes == null) + classes = new ArrayList<>(); + classes.add(arg); + while (iter.hasNext()) + classes.add(iter.next()); + } else + throw new BadArgs("err.unknown.option", arg).showUsage(true); + } + + if (options.accessOptions.size() > 1) { + StringBuilder sb = new StringBuilder(); + for (String opt: options.accessOptions) { + if (sb.length() > 0) + sb.append(" "); + sb.append(opt); + } + throw new BadArgs("err.incompatible.options", sb); + } + + if ((classes == null || classes.size() == 0) && + !(noArgs || options.help || options.version || options.fullVersion)) { + throw new BadArgs("err.no.classes.specified"); + } + + if (noArgs || options.help) + showHelp(); + + if (options.version || options.fullVersion) + showVersion(options.fullVersion); + } + + private void handleOption(String name, Iterator rest) throws BadArgs { + for (Option o: recognizedOptions) { + if (o.matches(name)) { + if (o.hasArg) { + if (rest.hasNext()) + o.process(this, name, rest.next()); + else + throw new BadArgs("err.missing.arg", name).showUsage(true); + } else + o.process(this, name, null); + + if (o.ignoreRest()) { + while (rest.hasNext()) + rest.next(); + } + return; + } + } + + try { + if (fileManager.handleOption(name, rest)) + return; + } catch (IllegalArgumentException e) { + throw new BadArgs("err.invalid.use.of.option", name).showUsage(true); + } + + throw new BadArgs("err.unknown.option", name).showUsage(true); + } + + public Boolean call() { + return run() == 0; + } + + public int run() { + if (classes == null || classes.isEmpty()) { + return EXIT_ERROR; + } + + context.put(PrintWriter.class, log); + ClassWriter classWriter = ClassWriter.instance(context); + SourceWriter sourceWriter = SourceWriter.instance(context); + sourceWriter.setFileManager(fileManager); + + int result = EXIT_OK; + + for (String className: classes) { + try { + result = writeClass(classWriter, className); + } catch (ConstantPoolException e) { + reportError("err.bad.constant.pool", className, e.getLocalizedMessage()); + result = EXIT_ERROR; + } catch (EOFException e) { + reportError("err.end.of.file", className); + result = EXIT_ERROR; + } catch (FileNotFoundException | NoSuchFileException e) { + reportError("err.file.not.found", e.getLocalizedMessage()); + result = EXIT_ERROR; + } catch (IOException e) { + //e.printStackTrace(); + Object msg = e.getLocalizedMessage(); + if (msg == null) { + msg = e; + } + reportError("err.ioerror", className, msg); + result = EXIT_ERROR; + } catch (OutOfMemoryError e) { + reportError("err.nomem"); + result = EXIT_ERROR; + } catch (Throwable t) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + t.printStackTrace(pw); + pw.close(); + reportError("err.crash", t.toString(), sw.toString()); + result = EXIT_ABNORMAL; + } + } + + return result; + } + + protected int writeClass(ClassWriter classWriter, String className) + throws IOException, ConstantPoolException { + JavaFileObject fo = open(className); + if (fo == null) { + reportError("err.class.not.found", className); + return EXIT_ERROR; + } + + ClassFileInfo cfInfo = read(fo); + if (!className.endsWith(".class")) { + String cfName = cfInfo.cf.getName(); + if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", "."))) { + reportWarning("warn.unexpected.class", className, cfName.replace('/', '.')); + } + } + write(cfInfo); + + if (options.showInnerClasses) { + ClassFile cf = cfInfo.cf; + Attribute a = cf.getAttribute(Attribute.InnerClasses); + if (a instanceof InnerClasses_attribute) { + InnerClasses_attribute inners = (InnerClasses_attribute) a; + try { + int result = EXIT_OK; + for (int i = 0; i < inners.classes.length; i++) { + int outerIndex = inners.classes[i].outer_class_info_index; + ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex); + String outerClassName = outerClassInfo.getName(); + if (outerClassName.equals(cf.getName())) { + int innerIndex = inners.classes[i].inner_class_info_index; + ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex); + String innerClassName = innerClassInfo.getName(); + classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", ".")); + classWriter.println(); + result = writeClass(classWriter, innerClassName); + if (result != EXIT_OK) return result; + } + } + return result; + } catch (ConstantPoolException e) { + reportError("err.bad.innerclasses.attribute", className); + return EXIT_ERROR; + } + } else if (a != null) { + reportError("err.bad.innerclasses.attribute", className); + return EXIT_ERROR; + } + } + + return EXIT_OK; + } + + protected JavaFileObject open(String className) throws IOException { + // for compatibility, first see if it is a class name + JavaFileObject fo = getClassFileObject(className); + if (fo != null) + return fo; + + // see if it is an inner class, by replacing dots to $, starting from the right + String cn = className; + int lastDot; + while ((lastDot = cn.lastIndexOf(".")) != -1) { + cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1); + fo = getClassFileObject(cn); + if (fo != null) + return fo; + } + + if (!className.endsWith(".class")) + return null; + + if (fileManager instanceof StandardJavaFileManager) { + StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager; + try { + fo = sfm.getJavaFileObjects(className).iterator().next(); + if (fo != null && fo.getLastModified() != 0) { + return fo; + } + } catch (IllegalArgumentException ignore) { + } + } + + // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject + // to suit javap's needs + if (className.matches("^[A-Za-z]+:.*")) { + try { + final URI uri = new URI(className); + final URL url = uri.toURL(); + final URLConnection conn = url.openConnection(); + conn.setUseCaches(false); + return new JavaFileObject() { + @DefinedBy(Api.COMPILER) + public Kind getKind() { + return JavaFileObject.Kind.CLASS; + } + + @DefinedBy(Api.COMPILER) + public boolean isNameCompatible(String simpleName, Kind kind) { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public NestingKind getNestingKind() { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public Modifier getAccessLevel() { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public URI toUri() { + return uri; + } + + @DefinedBy(Api.COMPILER) + public String getName() { + return uri.toString(); + } + + @DefinedBy(Api.COMPILER) + public InputStream openInputStream() throws IOException { + return conn.getInputStream(); + } + + @DefinedBy(Api.COMPILER) + public OutputStream openOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public Writer openWriter() throws IOException { + throw new UnsupportedOperationException(); + } + + @DefinedBy(Api.COMPILER) + public long getLastModified() { + return conn.getLastModified(); + } + + @DefinedBy(Api.COMPILER) + public boolean delete() { + throw new UnsupportedOperationException(); + } + + }; + } catch (URISyntaxException | IOException ignore) { + } + } + + return null; + } + + public static class ClassFileInfo { + ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) { + this.fo = fo; + this.cf = cf; + this.digest = digest; + this.size = size; + } + public final JavaFileObject fo; + public final ClassFile cf; + public final byte[] digest; + public final int size; + } + + public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException { + InputStream in = fo.openInputStream(); + try { + SizeInputStream sizeIn = null; + MessageDigest md = null; + if (options.sysInfo || options.verbose) { + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException ignore) { + } + in = new DigestInputStream(in, md); + in = sizeIn = new SizeInputStream(in); + } + + ClassFile cf = ClassFile.read(in, attributeFactory); + byte[] digest = (md == null) ? null : md.digest(); + int size = (sizeIn == null) ? -1 : sizeIn.size(); + return new ClassFileInfo(fo, cf, digest, size); + } finally { + in.close(); + } + } + + public void write(ClassFileInfo info) { + ClassWriter classWriter = ClassWriter.instance(context); + if (options.sysInfo || options.verbose) { + classWriter.setFile(info.fo.toUri()); + classWriter.setLastModified(info.fo.getLastModified()); + classWriter.setDigest("MD5", info.digest); + classWriter.setFileSize(info.size); + } + + classWriter.write(info.cf); + } + + protected void setClassFile(ClassFile classFile) { + ClassWriter classWriter = ClassWriter.instance(context); + classWriter.setClassFile(classFile); + } + + protected void setMethod(Method enclosingMethod) { + ClassWriter classWriter = ClassWriter.instance(context); + classWriter.setMethod(enclosingMethod); + } + + protected void write(Attribute value) { + AttributeWriter attrWriter = AttributeWriter.instance(context); + ClassWriter classWriter = ClassWriter.instance(context); + ClassFile cf = classWriter.getClassFile(); + attrWriter.write(cf, value, cf.constant_pool); + } + + protected void write(Attributes attrs) { + AttributeWriter attrWriter = AttributeWriter.instance(context); + ClassWriter classWriter = ClassWriter.instance(context); + ClassFile cf = classWriter.getClassFile(); + attrWriter.write(cf, attrs, cf.constant_pool); + } + + protected void write(ConstantPool constant_pool) { + ConstantWriter constantWriter = ConstantWriter.instance(context); + constantWriter.writeConstantPool(constant_pool); + } + + protected void write(ConstantPool constant_pool, int value) { + ConstantWriter constantWriter = ConstantWriter.instance(context); + constantWriter.write(value); + } + + protected void write(ConstantPool.CPInfo value) { + ConstantWriter constantWriter = ConstantWriter.instance(context); + constantWriter.println(value); + } + + protected void write(Field value) { + ClassWriter classWriter = ClassWriter.instance(context); + classWriter.writeField(value); + } + + protected void write(Method value) { + ClassWriter classWriter = ClassWriter.instance(context); + classWriter.writeMethod(value); + } + + private JavaFileManager getDefaultFileManager(final DiagnosticListener dl, PrintWriter log) { + if (defaultFileManager == null) + defaultFileManager = JavapFileManager.create(dl, log); + return defaultFileManager; + } + + private JavaFileObject getClassFileObject(String className) throws IOException { + try { + JavaFileObject fo; + fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS); + if (fo == null) + fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS); + return fo; + } catch (IllegalArgumentException e) { + return null; + } + } + + private void showHelp() { + printLines(getMessage("main.usage", progname)); + for (Option o: recognizedOptions) { + String name = o.aliases[0].substring(1); // there must always be at least one name + if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify")) + continue; + printLines(getMessage("main.opt." + name)); + } + String[] fmOptions = { "-classpath", "-cp", "-bootclasspath" }; + for (String o: fmOptions) { + if (fileManager.isSupportedOption(o) == -1) + continue; + String name = o.substring(1); + printLines(getMessage("main.opt." + name)); + } + + } + + private void showVersion(boolean full) { + printLines(version(full ? "full" : "release")); + } + + private void printLines(String msg) { + log.println(msg.replace("\n", nl)); + } + + private static final String nl = System.getProperty("line.separator"); + + private static final String versionRBName = "com.sun.tools.javap.resources.version"; + private static ResourceBundle versionRB; + + private String version(String key) { + // key=version: mm.nn.oo[-milestone] + // key=full: mm.mm.oo[-milestone]-build + if (versionRB == null) { + try { + versionRB = ResourceBundle.getBundle(versionRBName); + } catch (MissingResourceException e) { + return getMessage("version.resource.missing", System.getProperty("java.version")); + } + } + try { + return versionRB.getString(key); + } + catch (MissingResourceException e) { + return getMessage("version.unknown", System.getProperty("java.version")); + } + } + + private void reportError(String key, Object... args) { + diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args)); + } + + private void reportNote(String key, Object... args) { + diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args)); + } + + private void reportWarning(String key, Object... args) { + diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args)); + } + + private Diagnostic createDiagnostic( + final Diagnostic.Kind kind, final String key, final Object... args) { + return new Diagnostic() { + @DefinedBy(Api.COMPILER) + public Kind getKind() { + return kind; + } + + @DefinedBy(Api.COMPILER) + public JavaFileObject getSource() { + return null; + } + + @DefinedBy(Api.COMPILER) + public long getPosition() { + return Diagnostic.NOPOS; + } + + @DefinedBy(Api.COMPILER) + public long getStartPosition() { + return Diagnostic.NOPOS; + } + + @DefinedBy(Api.COMPILER) + public long getEndPosition() { + return Diagnostic.NOPOS; + } + + @DefinedBy(Api.COMPILER) + public long getLineNumber() { + return Diagnostic.NOPOS; + } + + @DefinedBy(Api.COMPILER) + public long getColumnNumber() { + return Diagnostic.NOPOS; + } + + @DefinedBy(Api.COMPILER) + public String getCode() { + return key; + } + + @DefinedBy(Api.COMPILER) + public String getMessage(Locale locale) { + return JavapTask.this.getMessage(locale, key, args); + } + + @Override + public String toString() { + return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]"; + } + + }; + + } + + public String getMessage(String key, Object... args) { + return getMessage(task_locale, key, args); + } + + public String getMessage(Locale locale, String key, Object... args) { + if (bundles == null) { + // could make this a HashMap> + // and for efficiency, keep a hard reference to the bundle for the task + // locale + bundles = new HashMap<>(); + } + + if (locale == null) + locale = Locale.getDefault(); + + ResourceBundle b = bundles.get(locale); + if (b == null) { + try { + b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale); + bundles.put(locale, b); + } catch (MissingResourceException e) { + throw new InternalError("Cannot find javap resource bundle for locale " + locale); + } + } + + try { + return MessageFormat.format(b.getString(key), args); + } catch (MissingResourceException e) { + throw new InternalError(e, key); + } + } + + protected Context context; + JavaFileManager fileManager; + JavaFileManager defaultFileManager; + PrintWriter log; + DiagnosticListener diagnosticListener; + List classes; + Options options; + //ResourceBundle bundle; + Locale task_locale; + Map bundles; + protected Attribute.Factory attributeFactory; + + private static final String progname = "javap"; + + private static class SizeInputStream extends FilterInputStream { + SizeInputStream(InputStream in) { + super(in); + } + + int size() { + return size; + } + + @Override + public int read(byte[] buf, int offset, int length) throws IOException { + int n = super.read(buf, offset, length); + if (n > 0) + size += n; + return n; + } + + @Override + public int read() throws IOException { + int b = super.read(); + size += 1; + return b; + } + + private int size; + } +}