Wed, 17 Nov 2010 15:07:43 -0800
7000973: isBogus needs to be called on the to-be-returned entry, not on the current entry
Reviewed-by: jjg
Contributed-by: jan.lahoda@oracle.com
1 /*
2 * Copyright (c) 2007, 2009, 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 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 handleOptions(options, false);
366 } catch (BadArgs e) {
367 throw new IllegalArgumentException(e.getMessage());
368 }
369 }
371 public void setLocale(Locale locale) {
372 if (locale == null)
373 locale = Locale.getDefault();
374 task_locale = locale;
375 }
377 public void setLog(PrintWriter log) {
378 this.log = log;
379 }
381 public void setLog(OutputStream s) {
382 setLog(getPrintWriterForStream(s));
383 }
385 private static PrintWriter getPrintWriterForStream(OutputStream s) {
386 return new PrintWriter(s, true);
387 }
389 private static PrintWriter getPrintWriterForWriter(Writer w) {
390 if (w == null)
391 return getPrintWriterForStream(null);
392 else if (w instanceof PrintWriter)
393 return (PrintWriter) w;
394 else
395 return new PrintWriter(w, true);
396 }
398 public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
399 diagnosticListener = dl;
400 }
402 public void setDiagnosticListener(OutputStream s) {
403 setDiagnosticListener(getDiagnosticListenerForStream(s));
404 }
406 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
407 return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
408 }
410 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
411 final PrintWriter pw = getPrintWriterForWriter(w);
412 return new DiagnosticListener<JavaFileObject> () {
413 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
414 switch (diagnostic.getKind()) {
415 case ERROR:
416 pw.print(getMessage("err.prefix"));
417 break;
418 case WARNING:
419 pw.print(getMessage("warn.prefix"));
420 break;
421 case NOTE:
422 pw.print(getMessage("note.prefix"));
423 break;
424 }
425 pw.print(" ");
426 pw.println(diagnostic.getMessage(null));
427 }
428 };
429 }
431 /** Result codes.
432 */
433 static final int
434 EXIT_OK = 0, // Compilation completed with no errors.
435 EXIT_ERROR = 1, // Completed but reported errors.
436 EXIT_CMDERR = 2, // Bad command-line arguments
437 EXIT_SYSERR = 3, // System error or resource exhaustion.
438 EXIT_ABNORMAL = 4; // Compiler terminated abnormally
440 int run(String[] args) {
441 try {
442 handleOptions(args);
444 // the following gives consistent behavior with javac
445 if (classes == null || classes.size() == 0) {
446 if (options.help || options.version || options.fullVersion)
447 return EXIT_OK;
448 else
449 return EXIT_CMDERR;
450 }
452 try {
453 boolean ok = run();
454 return ok ? EXIT_OK : EXIT_ERROR;
455 } finally {
456 if (defaultFileManager != null) {
457 try {
458 defaultFileManager.close();
459 defaultFileManager = null;
460 } catch (IOException e) {
461 throw new InternalError(e);
462 }
463 }
464 }
465 } catch (BadArgs e) {
466 reportError(e.key, e.args);
467 if (e.showUsage) {
468 log.println(getMessage("main.usage.summary", progname));
469 }
470 return EXIT_CMDERR;
471 } catch (InternalError e) {
472 Object[] e_args;
473 if (e.getCause() == null)
474 e_args = e.args;
475 else {
476 e_args = new Object[e.args.length + 1];
477 e_args[0] = e.getCause();
478 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
479 }
480 reportError("err.internal.error", e_args);
481 return EXIT_ABNORMAL;
482 } finally {
483 log.flush();
484 }
485 }
487 public void handleOptions(String[] args) throws BadArgs {
488 handleOptions(Arrays.asList(args), true);
489 }
491 private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
492 if (log == null) {
493 log = getPrintWriterForStream(System.out);
494 if (diagnosticListener == null)
495 diagnosticListener = getDiagnosticListenerForStream(System.err);
496 } else {
497 if (diagnosticListener == null)
498 diagnosticListener = getDiagnosticListenerForWriter(log);
499 }
502 if (fileManager == null)
503 fileManager = getDefaultFileManager(diagnosticListener, log);
505 Iterator<String> iter = args.iterator();
506 boolean noArgs = !iter.hasNext();
508 while (iter.hasNext()) {
509 String arg = iter.next();
510 if (arg.startsWith("-"))
511 handleOption(arg, iter);
512 else if (allowClasses) {
513 if (classes == null)
514 classes = new ArrayList<String>();
515 classes.add(arg);
516 while (iter.hasNext())
517 classes.add(iter.next());
518 } else
519 throw new BadArgs("err.unknown.option", arg).showUsage(true);
520 }
522 if (!options.compat && options.accessOptions.size() > 1) {
523 StringBuilder sb = new StringBuilder();
524 for (String opt: options.accessOptions) {
525 if (sb.length() > 0)
526 sb.append(" ");
527 sb.append(opt);
528 }
529 throw new BadArgs("err.incompatible.options", sb);
530 }
532 if ((classes == null || classes.size() == 0) &&
533 !(noArgs || options.help || options.version || options.fullVersion)) {
534 throw new BadArgs("err.no.classes.specified");
535 }
537 if (noArgs || options.help)
538 showHelp();
540 if (options.version || options.fullVersion)
541 showVersion(options.fullVersion);
542 }
544 private void handleOption(String name, Iterator<String> rest) throws BadArgs {
545 for (Option o: recognizedOptions) {
546 if (o.matches(name)) {
547 if (o.hasArg) {
548 if (rest.hasNext())
549 o.process(this, name, rest.next());
550 else
551 throw new BadArgs("err.missing.arg", name).showUsage(true);
552 } else
553 o.process(this, name, null);
555 if (o.ignoreRest()) {
556 while (rest.hasNext())
557 rest.next();
558 }
559 return;
560 }
561 }
563 if (fileManager.handleOption(name, rest))
564 return;
566 throw new BadArgs("err.unknown.option", name).showUsage(true);
567 }
569 public Boolean call() {
570 return run();
571 }
573 public boolean run() {
574 if (classes == null || classes.size() == 0)
575 return false;
577 context.put(PrintWriter.class, log);
578 ClassWriter classWriter = ClassWriter.instance(context);
579 SourceWriter sourceWriter = SourceWriter.instance(context);
580 sourceWriter.setFileManager(fileManager);
582 attributeFactory.setCompat(options.compat);
584 boolean ok = true;
586 for (String className: classes) {
587 JavaFileObject fo;
588 try {
589 writeClass(classWriter, className);
590 } catch (ConstantPoolException e) {
591 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
592 ok = false;
593 } catch (EOFException e) {
594 reportError("err.end.of.file", className);
595 ok = false;
596 } catch (FileNotFoundException e) {
597 reportError("err.file.not.found", e.getLocalizedMessage());
598 ok = false;
599 } catch (IOException e) {
600 //e.printStackTrace();
601 Object msg = e.getLocalizedMessage();
602 if (msg == null)
603 msg = e;
604 reportError("err.ioerror", className, msg);
605 ok = false;
606 } catch (Throwable t) {
607 StringWriter sw = new StringWriter();
608 PrintWriter pw = new PrintWriter(sw);
609 t.printStackTrace(pw);
610 pw.close();
611 reportError("err.crash", t.toString(), sw.toString());
612 ok = false;
613 }
614 }
616 return ok;
617 }
619 protected boolean writeClass(ClassWriter classWriter, String className)
620 throws IOException, ConstantPoolException {
621 JavaFileObject fo = open(className);
622 if (fo == null) {
623 reportError("err.class.not.found", className);
624 return false;
625 }
627 ClassFileInfo cfInfo = read(fo);
628 if (!className.endsWith(".class")) {
629 String cfName = cfInfo.cf.getName();
630 if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
631 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
632 }
633 write(cfInfo);
635 if (options.showInnerClasses) {
636 ClassFile cf = cfInfo.cf;
637 Attribute a = cf.getAttribute(Attribute.InnerClasses);
638 if (a instanceof InnerClasses_attribute) {
639 InnerClasses_attribute inners = (InnerClasses_attribute) a;
640 try {
641 boolean ok = true;
642 for (int i = 0; i < inners.classes.length; i++) {
643 int outerIndex = inners.classes[i].outer_class_info_index;
644 ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
645 String outerClassName = outerClassInfo.getName();
646 if (outerClassName.equals(cf.getName())) {
647 int innerIndex = inners.classes[i].inner_class_info_index;
648 ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
649 String innerClassName = innerClassInfo.getName();
650 classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
651 classWriter.println();
652 ok = ok & writeClass(classWriter, innerClassName);
653 }
654 }
655 return ok;
656 } catch (ConstantPoolException e) {
657 reportError("err.bad.innerclasses.attribute", className);
658 return false;
659 }
660 } else if (a != null) {
661 reportError("err.bad.innerclasses.attribute", className);
662 return false;
663 }
664 }
666 return true;
667 }
669 protected JavaFileObject open(String className) throws IOException {
670 // for compatibility, first see if it is a class name
671 JavaFileObject fo = getClassFileObject(className);
672 if (fo != null)
673 return fo;
675 // see if it is an inner class, by replacing dots to $, starting from the right
676 String cn = className;
677 int lastDot;
678 while ((lastDot = cn.lastIndexOf(".")) != -1) {
679 cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
680 fo = getClassFileObject(cn);
681 if (fo != null)
682 return fo;
683 }
685 if (!className.endsWith(".class"))
686 return null;
688 if (fileManager instanceof StandardJavaFileManager) {
689 StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
690 fo = sfm.getJavaFileObjects(className).iterator().next();
691 if (fo != null && fo.getLastModified() != 0) {
692 return fo;
693 }
694 }
696 // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
697 // to suit javap's needs
698 if (className.matches("^[A-Za-z]+:.*")) {
699 try {
700 final URI uri = new URI(className);
701 final URL url = uri.toURL();
702 final URLConnection conn = url.openConnection();
703 return new JavaFileObject() {
704 public Kind getKind() {
705 return JavaFileObject.Kind.CLASS;
706 }
708 public boolean isNameCompatible(String simpleName, Kind kind) {
709 throw new UnsupportedOperationException();
710 }
712 public NestingKind getNestingKind() {
713 throw new UnsupportedOperationException();
714 }
716 public Modifier getAccessLevel() {
717 throw new UnsupportedOperationException();
718 }
720 public URI toUri() {
721 return uri;
722 }
724 public String getName() {
725 return url.toString();
726 }
728 public InputStream openInputStream() throws IOException {
729 return conn.getInputStream();
730 }
732 public OutputStream openOutputStream() throws IOException {
733 throw new UnsupportedOperationException();
734 }
736 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
737 throw new UnsupportedOperationException();
738 }
740 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
741 throw new UnsupportedOperationException();
742 }
744 public Writer openWriter() throws IOException {
745 throw new UnsupportedOperationException();
746 }
748 public long getLastModified() {
749 return conn.getLastModified();
750 }
752 public boolean delete() {
753 throw new UnsupportedOperationException();
754 }
756 };
757 } catch (URISyntaxException ignore) {
758 } catch (IOException ignore) {
759 }
760 }
762 return null;
763 }
765 public static class ClassFileInfo {
766 ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
767 this.fo = fo;
768 this.cf = cf;
769 this.digest = digest;
770 this.size = size;
771 }
772 public final JavaFileObject fo;
773 public final ClassFile cf;
774 public final byte[] digest;
775 public final int size;
776 }
778 public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
779 InputStream in = fo.openInputStream();
780 try {
781 SizeInputStream sizeIn = null;
782 MessageDigest md = null;
783 if (options.sysInfo || options.verbose) {
784 try {
785 md = MessageDigest.getInstance("MD5");
786 } catch (NoSuchAlgorithmException ignore) {
787 }
788 in = new DigestInputStream(in, md);
789 in = sizeIn = new SizeInputStream(in);
790 }
792 ClassFile cf = ClassFile.read(in, attributeFactory);
793 byte[] digest = (md == null) ? null : md.digest();
794 int size = (sizeIn == null) ? -1 : sizeIn.size();
795 return new ClassFileInfo(fo, cf, digest, size);
796 } finally {
797 in.close();
798 }
799 }
801 public void write(ClassFileInfo info) {
802 ClassWriter classWriter = ClassWriter.instance(context);
803 if (options.sysInfo || options.verbose) {
804 classWriter.setFile(info.fo.toUri());
805 classWriter.setLastModified(info.fo.getLastModified());
806 classWriter.setDigest("MD5", info.digest);
807 classWriter.setFileSize(info.size);
808 }
810 classWriter.write(info.cf);
811 }
813 protected void setClassFile(ClassFile classFile) {
814 ClassWriter classWriter = ClassWriter.instance(context);
815 classWriter.setClassFile(classFile);
816 }
818 protected void setMethod(Method enclosingMethod) {
819 ClassWriter classWriter = ClassWriter.instance(context);
820 classWriter.setMethod(enclosingMethod);
821 }
823 protected void write(Attribute value) {
824 AttributeWriter attrWriter = AttributeWriter.instance(context);
825 ClassWriter classWriter = ClassWriter.instance(context);
826 ClassFile cf = classWriter.getClassFile();
827 attrWriter.write(cf, value, cf.constant_pool);
828 }
830 protected void write(Attributes attrs) {
831 AttributeWriter attrWriter = AttributeWriter.instance(context);
832 ClassWriter classWriter = ClassWriter.instance(context);
833 ClassFile cf = classWriter.getClassFile();
834 attrWriter.write(cf, attrs, cf.constant_pool);
835 }
837 protected void write(ConstantPool constant_pool) {
838 ConstantWriter constantWriter = ConstantWriter.instance(context);
839 constantWriter.writeConstantPool(constant_pool);
840 }
842 protected void write(ConstantPool constant_pool, int value) {
843 ConstantWriter constantWriter = ConstantWriter.instance(context);
844 constantWriter.write(value);
845 }
847 protected void write(ConstantPool.CPInfo value) {
848 ConstantWriter constantWriter = ConstantWriter.instance(context);
849 constantWriter.println(value);
850 }
852 protected void write(Field value) {
853 ClassWriter classWriter = ClassWriter.instance(context);
854 classWriter.writeField(value);
855 }
857 protected void write(Method value) {
858 ClassWriter classWriter = ClassWriter.instance(context);
859 classWriter.writeMethod(value);
860 }
862 private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
863 if (defaultFileManager == null)
864 defaultFileManager = JavapFileManager.create(dl, log);
865 return defaultFileManager;
866 }
868 private JavaFileObject getClassFileObject(String className) throws IOException {
869 JavaFileObject fo;
870 fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
871 if (fo == null)
872 fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
873 return fo;
874 }
876 private void showHelp() {
877 log.println(getMessage("main.usage", progname));
878 for (Option o: recognizedOptions) {
879 String name = o.aliases[0].substring(1); // there must always be at least one name
880 if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
881 continue;
882 log.println(getMessage("main.opt." + name));
883 }
884 String[] fmOptions = { "-classpath", "-bootclasspath" };
885 for (String o: fmOptions) {
886 if (fileManager.isSupportedOption(o) == -1)
887 continue;
888 String name = o.substring(1);
889 log.println(getMessage("main.opt." + name));
890 }
892 }
894 private void showVersion(boolean full) {
895 log.println(version(full ? "full" : "release"));
896 }
898 private static final String versionRBName = "com.sun.tools.javap.resources.version";
899 private static ResourceBundle versionRB;
901 private String version(String key) {
902 // key=version: mm.nn.oo[-milestone]
903 // key=full: mm.mm.oo[-milestone]-build
904 if (versionRB == null) {
905 try {
906 versionRB = ResourceBundle.getBundle(versionRBName);
907 } catch (MissingResourceException e) {
908 return getMessage("version.resource.missing", System.getProperty("java.version"));
909 }
910 }
911 try {
912 return versionRB.getString(key);
913 }
914 catch (MissingResourceException e) {
915 return getMessage("version.unknown", System.getProperty("java.version"));
916 }
917 }
919 private void reportError(String key, Object... args) {
920 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
921 }
923 private void reportNote(String key, Object... args) {
924 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
925 }
927 private void reportWarning(String key, Object... args) {
928 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
929 }
931 private Diagnostic<JavaFileObject> createDiagnostic(
932 final Diagnostic.Kind kind, final String key, final Object... args) {
933 return new Diagnostic<JavaFileObject>() {
934 public Kind getKind() {
935 return kind;
936 }
938 public JavaFileObject getSource() {
939 return null;
940 }
942 public long getPosition() {
943 return Diagnostic.NOPOS;
944 }
946 public long getStartPosition() {
947 return Diagnostic.NOPOS;
948 }
950 public long getEndPosition() {
951 return Diagnostic.NOPOS;
952 }
954 public long getLineNumber() {
955 return Diagnostic.NOPOS;
956 }
958 public long getColumnNumber() {
959 return Diagnostic.NOPOS;
960 }
962 public String getCode() {
963 return key;
964 }
966 public String getMessage(Locale locale) {
967 return JavapTask.this.getMessage(locale, key, args);
968 }
970 @Override
971 public String toString() {
972 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
973 }
975 };
977 }
979 public String getMessage(String key, Object... args) {
980 return getMessage(task_locale, key, args);
981 }
983 public String getMessage(Locale locale, String key, Object... args) {
984 if (bundles == null) {
985 // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
986 // and for efficiency, keep a hard reference to the bundle for the task
987 // locale
988 bundles = new HashMap<Locale, ResourceBundle>();
989 }
991 if (locale == null)
992 locale = Locale.getDefault();
994 ResourceBundle b = bundles.get(locale);
995 if (b == null) {
996 try {
997 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
998 bundles.put(locale, b);
999 } catch (MissingResourceException e) {
1000 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
1001 }
1002 }
1004 try {
1005 return MessageFormat.format(b.getString(key), args);
1006 } catch (MissingResourceException e) {
1007 throw new InternalError(e, key);
1008 }
1009 }
1011 protected Context context;
1012 JavaFileManager fileManager;
1013 JavaFileManager defaultFileManager;
1014 PrintWriter log;
1015 DiagnosticListener<? super JavaFileObject> diagnosticListener;
1016 List<String> classes;
1017 Options options;
1018 //ResourceBundle bundle;
1019 Locale task_locale;
1020 Map<Locale, ResourceBundle> bundles;
1021 protected Attribute.Factory attributeFactory;
1023 private static final String progname = "javap";
1025 private static class SizeInputStream extends FilterInputStream {
1026 SizeInputStream(InputStream in) {
1027 super(in);
1028 }
1030 int size() {
1031 return size;
1032 }
1034 @Override
1035 public int read(byte[] buf, int offset, int length) throws IOException {
1036 int n = super.read(buf, offset, length);
1037 if (n > 0)
1038 size += n;
1039 return n;
1040 }
1042 @Override
1043 public int read() throws IOException {
1044 int b = super.read();
1045 size += 1;
1046 return b;
1047 }
1049 private int size;
1050 }
1051 }