src/share/classes/com/sun/tools/javap/JavapTask.java

Tue, 12 Feb 2013 13:36:56 +0000

author
vromero
date
Tue, 12 Feb 2013 13:36:56 +0000
changeset 1561
073696f59241
parent 1442
fcf89720ae71
child 1578
040f02711b73
permissions
-rw-r--r--

8006334: javap, JavapTask constructor breaks with null pointer exception if parameter options is null
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javap;
    28 import java.io.EOFException;
    29 import java.io.FileNotFoundException;
    30 import java.io.FilterInputStream;
    31 import java.io.InputStream;
    32 import java.io.IOException;
    33 import java.io.OutputStream;
    34 import java.io.PrintWriter;
    35 import java.io.Reader;
    36 import java.io.StringWriter;
    37 import java.io.Writer;
    38 import java.net.URI;
    39 import java.security.DigestInputStream;
    40 import java.security.MessageDigest;
    41 import java.security.NoSuchAlgorithmException;
    42 import java.text.MessageFormat;
    43 import java.util.ArrayList;
    44 import java.util.Arrays;
    45 import java.util.EnumSet;
    46 import java.util.HashMap;
    47 import java.util.Iterator;
    48 import java.util.List;
    49 import java.util.Locale;
    50 import java.util.Map;
    51 import java.util.MissingResourceException;
    52 import java.util.ResourceBundle;
    54 import javax.lang.model.element.Modifier;
    55 import javax.lang.model.element.NestingKind;
    56 import javax.tools.Diagnostic;
    57 import javax.tools.DiagnosticListener;
    58 import javax.tools.JavaFileManager;
    59 import javax.tools.JavaFileObject;
    60 import javax.tools.StandardJavaFileManager;
    61 import javax.tools.StandardLocation;
    63 import com.sun.tools.classfile.*;
    64 import java.net.URISyntaxException;
    65 import java.net.URL;
    66 import java.net.URLConnection;
    68 /**
    69  *  "Main" class for javap, normally accessed from the command line
    70  *  via Main, or from JSR199 via DisassemblerTool.
    71  *
    72  *  <p><b>This is NOT part of any supported API.
    73  *  If you write code that depends on this, you do so at your own risk.
    74  *  This code and its internal interfaces are subject to change or
    75  *  deletion without notice.</b>
    76  */
    77 public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
    78     public class BadArgs extends Exception {
    79         static final long serialVersionUID = 8765093759964640721L;
    80         BadArgs(String key, Object... args) {
    81             super(JavapTask.this.getMessage(key, args));
    82             this.key = key;
    83             this.args = args;
    84         }
    86         BadArgs showUsage(boolean b) {
    87             showUsage = b;
    88             return this;
    89         }
    91         final String key;
    92         final Object[] args;
    93         boolean showUsage;
    94     }
    96     static abstract class Option {
    97         Option(boolean hasArg, String... aliases) {
    98             this.hasArg = hasArg;
    99             this.aliases = aliases;
   100         }
   102         boolean matches(String opt) {
   103             for (String a: aliases) {
   104                 if (a.equals(opt))
   105                     return true;
   106             }
   107             return false;
   108         }
   110         boolean ignoreRest() {
   111             return false;
   112         }
   114         abstract void process(JavapTask task, String opt, String arg) throws BadArgs;
   116         final boolean hasArg;
   117         final String[] aliases;
   118     }
   120     static final Option[] recognizedOptions = {
   122         new Option(false, "-help", "--help", "-?") {
   123             void process(JavapTask task, String opt, String arg) {
   124                 task.options.help = true;
   125             }
   126         },
   128         new Option(false, "-version") {
   129             void process(JavapTask task, String opt, String arg) {
   130                 task.options.version = true;
   131             }
   132         },
   134         new Option(false, "-fullversion") {
   135             void process(JavapTask task, String opt, String arg) {
   136                 task.options.fullVersion = true;
   137             }
   138         },
   140         new Option(false, "-v", "-verbose", "-all") {
   141             void process(JavapTask task, String opt, String arg) {
   142                 task.options.verbose = true;
   143                 task.options.showFlags = true;
   144                 task.options.showAllAttrs = true;
   145             }
   146         },
   148         new Option(false, "-l") {
   149             void process(JavapTask task, String opt, String arg) {
   150                 task.options.showLineAndLocalVariableTables = true;
   151             }
   152         },
   154         new Option(false, "-public") {
   155             void process(JavapTask task, String opt, String arg) {
   156                 task.options.accessOptions.add(opt);
   157                 task.options.showAccess = AccessFlags.ACC_PUBLIC;
   158             }
   159         },
   161         new Option(false, "-protected") {
   162             void process(JavapTask task, String opt, String arg) {
   163                 task.options.accessOptions.add(opt);
   164                 task.options.showAccess = AccessFlags.ACC_PROTECTED;
   165             }
   166         },
   168         new Option(false, "-package") {
   169             void process(JavapTask task, String opt, String arg) {
   170                 task.options.accessOptions.add(opt);
   171                 task.options.showAccess = 0;
   172             }
   173         },
   175         new Option(false, "-p", "-private") {
   176             void process(JavapTask task, String opt, String arg) {
   177                 if (!task.options.accessOptions.contains("-p") &&
   178                         !task.options.accessOptions.contains("-private")) {
   179                     task.options.accessOptions.add(opt);
   180                 }
   181                 task.options.showAccess = AccessFlags.ACC_PRIVATE;
   182             }
   183         },
   185         new Option(false, "-c") {
   186             void process(JavapTask task, String opt, String arg) {
   187                 task.options.showDisassembled = true;
   188             }
   189         },
   191         new Option(false, "-s") {
   192             void process(JavapTask task, String opt, String arg) {
   193                 task.options.showInternalSignatures = true;
   194             }
   195         },
   197 //        new Option(false, "-all") {
   198 //            void process(JavapTask task, String opt, String arg) {
   199 //                task.options.showAllAttrs = true;
   200 //            }
   201 //        },
   203         new Option(false, "-h") {
   204             void process(JavapTask task, String opt, String arg) throws BadArgs {
   205                 throw task.new BadArgs("err.h.not.supported");
   206             }
   207         },
   209         new Option(false, "-verify", "-verify-verbose") {
   210             void process(JavapTask task, String opt, String arg) throws BadArgs {
   211                 throw task.new BadArgs("err.verify.not.supported");
   212             }
   213         },
   215         new Option(false, "-sysinfo") {
   216             void process(JavapTask task, String opt, String arg) {
   217                 task.options.sysInfo = true;
   218             }
   219         },
   221         new Option(false, "-Xold") {
   222             void process(JavapTask task, String opt, String arg) throws BadArgs {
   223                 task.log.println(task.getMessage("warn.Xold.not.supported"));
   224             }
   225         },
   227         new Option(false, "-Xnew") {
   228             void process(JavapTask task, String opt, String arg) throws BadArgs {
   229                 // ignore: this _is_ the new version
   230             }
   231         },
   233         new Option(false, "-XDcompat") {
   234             void process(JavapTask task, String opt, String arg) {
   235                 task.options.compat = true;
   236             }
   237         },
   239         new Option(false, "-XDdetails") {
   240             void process(JavapTask task, String opt, String arg) {
   241                 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   242             }
   244         },
   246         new Option(false, "-XDdetails:") {
   247             @Override
   248             boolean matches(String opt) {
   249                 int sep = opt.indexOf(":");
   250                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   251             }
   253             void process(JavapTask task, String opt, String arg) throws BadArgs {
   254                 int sep = opt.indexOf(":");
   255                 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
   256                     if (!handleArg(task, v))
   257                         throw task.new BadArgs("err.invalid.arg.for.option", v);
   258                 }
   259             }
   261             boolean handleArg(JavapTask task, String arg) {
   262                 if (arg.length() == 0)
   263                     return true;
   265                 if (arg.equals("all")) {
   266                     task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
   267                     return true;
   268                 }
   270                 boolean on = true;
   271                 if (arg.startsWith("-")) {
   272                     on = false;
   273                     arg = arg.substring(1);
   274                 }
   276                 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
   277                     if (arg.equalsIgnoreCase(k.option)) {
   278                         if (on)
   279                             task.options.details.add(k);
   280                         else
   281                             task.options.details.remove(k);
   282                         return true;
   283                     }
   284                 }
   285                 return false;
   286             }
   287         },
   289         new Option(false, "-constants") {
   290             void process(JavapTask task, String opt, String arg) {
   291                 task.options.showConstants = true;
   292             }
   293         },
   295         new Option(false, "-XDinner") {
   296             void process(JavapTask task, String opt, String arg) {
   297                 task.options.showInnerClasses = true;
   298             }
   299         },
   301         new Option(false, "-XDindent:") {
   302             @Override
   303             boolean matches(String opt) {
   304                 int sep = opt.indexOf(":");
   305                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   306             }
   308             void process(JavapTask task, String opt, String arg) throws BadArgs {
   309                 int sep = opt.indexOf(":");
   310                 try {
   311                     task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
   312                 } catch (NumberFormatException e) {
   313                 }
   314             }
   315         },
   317         new Option(false, "-XDtab:") {
   318             @Override
   319             boolean matches(String opt) {
   320                 int sep = opt.indexOf(":");
   321                 return sep != -1 && super.matches(opt.substring(0, sep + 1));
   322             }
   324             void process(JavapTask task, String opt, String arg) throws BadArgs {
   325                 int sep = opt.indexOf(":");
   326                 try {
   327                     task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
   328                 } catch (NumberFormatException e) {
   329                 }
   330             }
   331         }
   333     };
   335     public JavapTask() {
   336         context = new Context();
   337         context.put(Messages.class, this);
   338         options = Options.instance(context);
   339         attributeFactory = new Attribute.Factory();
   340     }
   342     public JavapTask(Writer out,
   343             JavaFileManager fileManager,
   344             DiagnosticListener<? super JavaFileObject> diagnosticListener) {
   345         this();
   346         this.log = getPrintWriterForWriter(out);
   347         this.fileManager = fileManager;
   348         this.diagnosticListener = diagnosticListener;
   349     }
   351     public JavapTask(Writer out,
   352             JavaFileManager fileManager,
   353             DiagnosticListener<? super JavaFileObject> diagnosticListener,
   354             Iterable<String> options,
   355             Iterable<String> classes) {
   356         this(out, fileManager, diagnosticListener);
   358         this.classes = new ArrayList<String>();
   359         for (String classname: classes) {
   360             classname.getClass(); // null-check
   361             this.classes.add(classname);
   362         }
   364         try {
   365             if (options != null)
   366                 handleOptions(options, false);
   367         } catch (BadArgs e) {
   368             throw new IllegalArgumentException(e.getMessage());
   369         }
   370     }
   372     public void setLocale(Locale locale) {
   373         if (locale == null)
   374             locale = Locale.getDefault();
   375         task_locale = locale;
   376     }
   378     public void setLog(Writer log) {
   379         this.log = getPrintWriterForWriter(log);
   380     }
   382     public void setLog(OutputStream s) {
   383         setLog(getPrintWriterForStream(s));
   384     }
   386     private static PrintWriter getPrintWriterForStream(OutputStream s) {
   387         return new PrintWriter(s == null ? System.err : s, true);
   388     }
   390     private static PrintWriter getPrintWriterForWriter(Writer w) {
   391         if (w == null)
   392             return getPrintWriterForStream(null);
   393         else if (w instanceof PrintWriter)
   394             return (PrintWriter) w;
   395         else
   396             return new PrintWriter(w, true);
   397     }
   399     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
   400         diagnosticListener = dl;
   401     }
   403     public void setDiagnosticListener(OutputStream s) {
   404         setDiagnosticListener(getDiagnosticListenerForStream(s));
   405     }
   407     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
   408         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
   409     }
   411     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
   412         final PrintWriter pw = getPrintWriterForWriter(w);
   413         return new DiagnosticListener<JavaFileObject> () {
   414             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   415                 switch (diagnostic.getKind()) {
   416                     case ERROR:
   417                         pw.print(getMessage("err.prefix"));
   418                         break;
   419                     case WARNING:
   420                         pw.print(getMessage("warn.prefix"));
   421                         break;
   422                     case NOTE:
   423                         pw.print(getMessage("note.prefix"));
   424                         break;
   425                 }
   426                 pw.print(" ");
   427                 pw.println(diagnostic.getMessage(null));
   428             }
   429         };
   430     }
   432     /** Result codes.
   433      */
   434     static final int
   435         EXIT_OK = 0,        // Compilation completed with no errors.
   436         EXIT_ERROR = 1,     // Completed but reported errors.
   437         EXIT_CMDERR = 2,    // Bad command-line arguments
   438         EXIT_SYSERR = 3,    // System error or resource exhaustion.
   439         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
   441     int run(String[] args) {
   442         try {
   443             handleOptions(args);
   445             // the following gives consistent behavior with javac
   446             if (classes == null || classes.size() == 0) {
   447                 if (options.help || options.version || options.fullVersion)
   448                     return EXIT_OK;
   449                 else
   450                     return EXIT_CMDERR;
   451             }
   453             try {
   454                 boolean ok = run();
   455                 return ok ? EXIT_OK : EXIT_ERROR;
   456             } finally {
   457                 if (defaultFileManager != null) {
   458                     try {
   459                         defaultFileManager.close();
   460                         defaultFileManager = null;
   461                     } catch (IOException e) {
   462                         throw new InternalError(e);
   463                     }
   464                 }
   465             }
   466         } catch (BadArgs e) {
   467             reportError(e.key, e.args);
   468             if (e.showUsage) {
   469                 log.println(getMessage("main.usage.summary", progname));
   470             }
   471             return EXIT_CMDERR;
   472         } catch (InternalError e) {
   473             Object[] e_args;
   474             if (e.getCause() == null)
   475                 e_args = e.args;
   476             else {
   477                 e_args = new Object[e.args.length + 1];
   478                 e_args[0] = e.getCause();
   479                 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
   480             }
   481             reportError("err.internal.error", e_args);
   482             return EXIT_ABNORMAL;
   483         } finally {
   484             log.flush();
   485         }
   486     }
   488     public void handleOptions(String[] args) throws BadArgs {
   489         handleOptions(Arrays.asList(args), true);
   490     }
   492     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
   493         if (log == null) {
   494             log = getPrintWriterForStream(System.out);
   495             if (diagnosticListener == null)
   496               diagnosticListener = getDiagnosticListenerForStream(System.err);
   497         } else {
   498             if (diagnosticListener == null)
   499               diagnosticListener = getDiagnosticListenerForWriter(log);
   500         }
   503         if (fileManager == null)
   504             fileManager = getDefaultFileManager(diagnosticListener, log);
   506         Iterator<String> iter = args.iterator();
   507         boolean noArgs = !iter.hasNext();
   509         while (iter.hasNext()) {
   510             String arg = iter.next();
   511             if (arg.startsWith("-"))
   512                 handleOption(arg, iter);
   513             else if (allowClasses) {
   514                 if (classes == null)
   515                     classes = new ArrayList<String>();
   516                 classes.add(arg);
   517                 while (iter.hasNext())
   518                     classes.add(iter.next());
   519             } else
   520                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
   521         }
   523         if (!options.compat && options.accessOptions.size() > 1) {
   524             StringBuilder sb = new StringBuilder();
   525             for (String opt: options.accessOptions) {
   526                 if (sb.length() > 0)
   527                     sb.append(" ");
   528                 sb.append(opt);
   529             }
   530             throw new BadArgs("err.incompatible.options", sb);
   531         }
   533         if ((classes == null || classes.size() == 0) &&
   534                 !(noArgs || options.help || options.version || options.fullVersion)) {
   535             throw new BadArgs("err.no.classes.specified");
   536         }
   538         if (noArgs || options.help)
   539             showHelp();
   541         if (options.version || options.fullVersion)
   542             showVersion(options.fullVersion);
   543     }
   545     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
   546         for (Option o: recognizedOptions) {
   547             if (o.matches(name)) {
   548                 if (o.hasArg) {
   549                     if (rest.hasNext())
   550                         o.process(this, name, rest.next());
   551                     else
   552                         throw new BadArgs("err.missing.arg", name).showUsage(true);
   553                 } else
   554                     o.process(this, name, null);
   556                 if (o.ignoreRest()) {
   557                     while (rest.hasNext())
   558                         rest.next();
   559                 }
   560                 return;
   561             }
   562         }
   564         if (fileManager.handleOption(name, rest))
   565             return;
   567         throw new BadArgs("err.unknown.option", name).showUsage(true);
   568     }
   570     public Boolean call() {
   571         return run();
   572     }
   574     public boolean run() {
   575         if (classes == null || classes.size() == 0)
   576             return false;
   578         context.put(PrintWriter.class, log);
   579         ClassWriter classWriter = ClassWriter.instance(context);
   580         SourceWriter sourceWriter = SourceWriter.instance(context);
   581         sourceWriter.setFileManager(fileManager);
   583         attributeFactory.setCompat(options.compat);
   585         boolean ok = true;
   587         for (String className: classes) {
   588             JavaFileObject fo;
   589             try {
   590                 writeClass(classWriter, className);
   591             } catch (ConstantPoolException e) {
   592                 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
   593                 ok = false;
   594             } catch (EOFException e) {
   595                 reportError("err.end.of.file", className);
   596                 ok = false;
   597             } catch (FileNotFoundException e) {
   598                 reportError("err.file.not.found", e.getLocalizedMessage());
   599                 ok = false;
   600             } catch (IOException e) {
   601                 //e.printStackTrace();
   602                 Object msg = e.getLocalizedMessage();
   603                 if (msg == null)
   604                     msg = e;
   605                 reportError("err.ioerror", className, msg);
   606                 ok = false;
   607             } catch (Throwable t) {
   608                 StringWriter sw = new StringWriter();
   609                 PrintWriter pw = new PrintWriter(sw);
   610                 t.printStackTrace(pw);
   611                 pw.close();
   612                 reportError("err.crash", t.toString(), sw.toString());
   613                 ok = false;
   614             }
   615         }
   617         return ok;
   618     }
   620     protected boolean writeClass(ClassWriter classWriter, String className)
   621             throws IOException, ConstantPoolException {
   622         JavaFileObject fo = open(className);
   623         if (fo == null) {
   624             reportError("err.class.not.found", className);
   625             return false;
   626         }
   628         ClassFileInfo cfInfo = read(fo);
   629         if (!className.endsWith(".class")) {
   630             String cfName = cfInfo.cf.getName();
   631             if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
   632                 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
   633         }
   634         write(cfInfo);
   636         if (options.showInnerClasses) {
   637             ClassFile cf = cfInfo.cf;
   638             Attribute a = cf.getAttribute(Attribute.InnerClasses);
   639             if (a instanceof InnerClasses_attribute) {
   640                 InnerClasses_attribute inners = (InnerClasses_attribute) a;
   641                 try {
   642                     boolean ok = true;
   643                     for (int i = 0; i < inners.classes.length; i++) {
   644                         int outerIndex = inners.classes[i].outer_class_info_index;
   645                         ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
   646                         String outerClassName = outerClassInfo.getName();
   647                         if (outerClassName.equals(cf.getName())) {
   648                             int innerIndex = inners.classes[i].inner_class_info_index;
   649                             ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
   650                             String innerClassName = innerClassInfo.getName();
   651                             classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
   652                             classWriter.println();
   653                             ok = ok & writeClass(classWriter, innerClassName);
   654                         }
   655                     }
   656                     return ok;
   657                 } catch (ConstantPoolException e) {
   658                     reportError("err.bad.innerclasses.attribute", className);
   659                     return false;
   660                 }
   661             } else if (a != null) {
   662                 reportError("err.bad.innerclasses.attribute", className);
   663                 return false;
   664             }
   665         }
   667         return true;
   668     }
   670     protected JavaFileObject open(String className) throws IOException {
   671         // for compatibility, first see if it is a class name
   672         JavaFileObject fo = getClassFileObject(className);
   673         if (fo != null)
   674             return fo;
   676         // see if it is an inner class, by replacing dots to $, starting from the right
   677         String cn = className;
   678         int lastDot;
   679         while ((lastDot = cn.lastIndexOf(".")) != -1) {
   680             cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
   681             fo = getClassFileObject(cn);
   682             if (fo != null)
   683                 return fo;
   684         }
   686         if (!className.endsWith(".class"))
   687             return null;
   689         if (fileManager instanceof StandardJavaFileManager) {
   690             StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
   691             fo = sfm.getJavaFileObjects(className).iterator().next();
   692             if (fo != null && fo.getLastModified() != 0) {
   693                 return fo;
   694             }
   695         }
   697         // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
   698         // to suit javap's needs
   699         if (className.matches("^[A-Za-z]+:.*")) {
   700             try {
   701                 final URI uri = new URI(className);
   702                 final URL url = uri.toURL();
   703                 final URLConnection conn = url.openConnection();
   704                 return new JavaFileObject() {
   705                     public Kind getKind() {
   706                         return JavaFileObject.Kind.CLASS;
   707                     }
   709                     public boolean isNameCompatible(String simpleName, Kind kind) {
   710                         throw new UnsupportedOperationException();
   711                     }
   713                     public NestingKind getNestingKind() {
   714                         throw new UnsupportedOperationException();
   715                     }
   717                     public Modifier getAccessLevel() {
   718                         throw new UnsupportedOperationException();
   719                     }
   721                     public URI toUri() {
   722                         return uri;
   723                     }
   725                     public String getName() {
   726                         return url.toString();
   727                     }
   729                     public InputStream openInputStream() throws IOException {
   730                         return conn.getInputStream();
   731                     }
   733                     public OutputStream openOutputStream() throws IOException {
   734                         throw new UnsupportedOperationException();
   735                     }
   737                     public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
   738                         throw new UnsupportedOperationException();
   739                     }
   741                     public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
   742                         throw new UnsupportedOperationException();
   743                     }
   745                     public Writer openWriter() throws IOException {
   746                         throw new UnsupportedOperationException();
   747                     }
   749                     public long getLastModified() {
   750                         return conn.getLastModified();
   751                     }
   753                     public boolean delete() {
   754                         throw new UnsupportedOperationException();
   755                     }
   757                 };
   758             } catch (URISyntaxException ignore) {
   759             } catch (IOException ignore) {
   760             }
   761         }
   763         return null;
   764     }
   766     public static class ClassFileInfo {
   767         ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
   768             this.fo = fo;
   769             this.cf = cf;
   770             this.digest = digest;
   771             this.size = size;
   772         }
   773         public final JavaFileObject fo;
   774         public final ClassFile cf;
   775         public final byte[] digest;
   776         public final int size;
   777     }
   779     public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
   780         InputStream in = fo.openInputStream();
   781         try {
   782             SizeInputStream sizeIn = null;
   783             MessageDigest md  = null;
   784             if (options.sysInfo || options.verbose) {
   785                 try {
   786                     md = MessageDigest.getInstance("MD5");
   787                 } catch (NoSuchAlgorithmException ignore) {
   788                 }
   789                 in = new DigestInputStream(in, md);
   790                 in = sizeIn = new SizeInputStream(in);
   791             }
   793             ClassFile cf = ClassFile.read(in, attributeFactory);
   794             byte[] digest = (md == null) ? null : md.digest();
   795             int size = (sizeIn == null) ? -1 : sizeIn.size();
   796             return new ClassFileInfo(fo, cf, digest, size);
   797         } finally {
   798             in.close();
   799         }
   800     }
   802     public void write(ClassFileInfo info) {
   803         ClassWriter classWriter = ClassWriter.instance(context);
   804         if (options.sysInfo || options.verbose) {
   805             classWriter.setFile(info.fo.toUri());
   806             classWriter.setLastModified(info.fo.getLastModified());
   807             classWriter.setDigest("MD5", info.digest);
   808             classWriter.setFileSize(info.size);
   809         }
   811         classWriter.write(info.cf);
   812     }
   814     protected void setClassFile(ClassFile classFile) {
   815         ClassWriter classWriter = ClassWriter.instance(context);
   816         classWriter.setClassFile(classFile);
   817     }
   819     protected void setMethod(Method enclosingMethod) {
   820         ClassWriter classWriter = ClassWriter.instance(context);
   821         classWriter.setMethod(enclosingMethod);
   822     }
   824     protected void write(Attribute value) {
   825         AttributeWriter attrWriter = AttributeWriter.instance(context);
   826         ClassWriter classWriter = ClassWriter.instance(context);
   827         ClassFile cf = classWriter.getClassFile();
   828         attrWriter.write(cf, value, cf.constant_pool);
   829     }
   831     protected void write(Attributes attrs) {
   832         AttributeWriter attrWriter = AttributeWriter.instance(context);
   833         ClassWriter classWriter = ClassWriter.instance(context);
   834         ClassFile cf = classWriter.getClassFile();
   835         attrWriter.write(cf, attrs, cf.constant_pool);
   836     }
   838     protected void write(ConstantPool constant_pool) {
   839         ConstantWriter constantWriter = ConstantWriter.instance(context);
   840         constantWriter.writeConstantPool(constant_pool);
   841     }
   843     protected void write(ConstantPool constant_pool, int value) {
   844         ConstantWriter constantWriter = ConstantWriter.instance(context);
   845         constantWriter.write(value);
   846     }
   848     protected void write(ConstantPool.CPInfo value) {
   849         ConstantWriter constantWriter = ConstantWriter.instance(context);
   850         constantWriter.println(value);
   851     }
   853     protected void write(Field value) {
   854         ClassWriter classWriter = ClassWriter.instance(context);
   855         classWriter.writeField(value);
   856     }
   858     protected void write(Method value) {
   859         ClassWriter classWriter = ClassWriter.instance(context);
   860         classWriter.writeMethod(value);
   861     }
   863     private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
   864         if (defaultFileManager == null)
   865             defaultFileManager = JavapFileManager.create(dl, log);
   866         return defaultFileManager;
   867     }
   869     private JavaFileObject getClassFileObject(String className) throws IOException {
   870         JavaFileObject fo;
   871         fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   872         if (fo == null)
   873             fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
   874         return fo;
   875     }
   877     private void showHelp() {
   878         log.println(getMessage("main.usage", progname));
   879         for (Option o: recognizedOptions) {
   880             String name = o.aliases[0].substring(1); // there must always be at least one name
   881             if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
   882                 continue;
   883             log.println(getMessage("main.opt." + name));
   884         }
   885         String[] fmOptions = { "-classpath", "-bootclasspath" };
   886         for (String o: fmOptions) {
   887             if (fileManager.isSupportedOption(o) == -1)
   888                 continue;
   889             String name = o.substring(1);
   890             log.println(getMessage("main.opt." + name));
   891         }
   893     }
   895     private void showVersion(boolean full) {
   896         log.println(version(full ? "full" : "release"));
   897     }
   899     private static final String versionRBName = "com.sun.tools.javap.resources.version";
   900     private static ResourceBundle versionRB;
   902     private String version(String key) {
   903         // key=version:  mm.nn.oo[-milestone]
   904         // key=full:     mm.mm.oo[-milestone]-build
   905         if (versionRB == null) {
   906             try {
   907                 versionRB = ResourceBundle.getBundle(versionRBName);
   908             } catch (MissingResourceException e) {
   909                 return getMessage("version.resource.missing", System.getProperty("java.version"));
   910             }
   911         }
   912         try {
   913             return versionRB.getString(key);
   914         }
   915         catch (MissingResourceException e) {
   916             return getMessage("version.unknown", System.getProperty("java.version"));
   917         }
   918     }
   920     private void reportError(String key, Object... args) {
   921         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
   922     }
   924     private void reportNote(String key, Object... args) {
   925         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
   926     }
   928     private void reportWarning(String key, Object... args) {
   929         diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
   930     }
   932     private Diagnostic<JavaFileObject> createDiagnostic(
   933             final Diagnostic.Kind kind, final String key, final Object... args) {
   934         return new Diagnostic<JavaFileObject>() {
   935             public Kind getKind() {
   936                 return kind;
   937             }
   939             public JavaFileObject getSource() {
   940                 return null;
   941             }
   943             public long getPosition() {
   944                 return Diagnostic.NOPOS;
   945             }
   947             public long getStartPosition() {
   948                 return Diagnostic.NOPOS;
   949             }
   951             public long getEndPosition() {
   952                 return Diagnostic.NOPOS;
   953             }
   955             public long getLineNumber() {
   956                 return Diagnostic.NOPOS;
   957             }
   959             public long getColumnNumber() {
   960                 return Diagnostic.NOPOS;
   961             }
   963             public String getCode() {
   964                 return key;
   965             }
   967             public String getMessage(Locale locale) {
   968                 return JavapTask.this.getMessage(locale, key, args);
   969             }
   971             @Override
   972             public String toString() {
   973                 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
   974             }
   976         };
   978     }
   980     public String getMessage(String key, Object... args) {
   981         return getMessage(task_locale, key, args);
   982     }
   984     public String getMessage(Locale locale, String key, Object... args) {
   985         if (bundles == null) {
   986             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
   987             // and for efficiency, keep a hard reference to the bundle for the task
   988             // locale
   989             bundles = new HashMap<Locale, ResourceBundle>();
   990         }
   992         if (locale == null)
   993             locale = Locale.getDefault();
   995         ResourceBundle b = bundles.get(locale);
   996         if (b == null) {
   997             try {
   998                 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
   999                 bundles.put(locale, b);
  1000             } catch (MissingResourceException e) {
  1001                 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
  1005         try {
  1006             return MessageFormat.format(b.getString(key), args);
  1007         } catch (MissingResourceException e) {
  1008             throw new InternalError(e, key);
  1012     protected Context context;
  1013     JavaFileManager fileManager;
  1014     JavaFileManager defaultFileManager;
  1015     PrintWriter log;
  1016     DiagnosticListener<? super JavaFileObject> diagnosticListener;
  1017     List<String> classes;
  1018     Options options;
  1019     //ResourceBundle bundle;
  1020     Locale task_locale;
  1021     Map<Locale, ResourceBundle> bundles;
  1022     protected Attribute.Factory attributeFactory;
  1024     private static final String progname = "javap";
  1026     private static class SizeInputStream extends FilterInputStream {
  1027         SizeInputStream(InputStream in) {
  1028             super(in);
  1031         int size() {
  1032             return size;
  1035         @Override
  1036         public int read(byte[] buf, int offset, int length) throws IOException {
  1037             int n = super.read(buf, offset, length);
  1038             if (n > 0)
  1039                 size += n;
  1040             return n;
  1043         @Override
  1044         public int read() throws IOException {
  1045             int b = super.read();
  1046             size += 1;
  1047             return b;
  1050         private int size;

mercurial