Mon, 25 Mar 2013 16:55:14 -0700
8010521: jdk8 l10n resource file translation update 2
Reviewed-by: naoto, yhuang
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.showDescriptors = true;
144 task.options.showFlags = true;
145 task.options.showAllAttrs = true;
146 }
147 },
149 new Option(false, "-l") {
150 void process(JavapTask task, String opt, String arg) {
151 task.options.showLineAndLocalVariableTables = true;
152 }
153 },
155 new Option(false, "-public") {
156 void process(JavapTask task, String opt, String arg) {
157 task.options.accessOptions.add(opt);
158 task.options.showAccess = AccessFlags.ACC_PUBLIC;
159 }
160 },
162 new Option(false, "-protected") {
163 void process(JavapTask task, String opt, String arg) {
164 task.options.accessOptions.add(opt);
165 task.options.showAccess = AccessFlags.ACC_PROTECTED;
166 }
167 },
169 new Option(false, "-package") {
170 void process(JavapTask task, String opt, String arg) {
171 task.options.accessOptions.add(opt);
172 task.options.showAccess = 0;
173 }
174 },
176 new Option(false, "-p", "-private") {
177 void process(JavapTask task, String opt, String arg) {
178 if (!task.options.accessOptions.contains("-p") &&
179 !task.options.accessOptions.contains("-private")) {
180 task.options.accessOptions.add(opt);
181 }
182 task.options.showAccess = AccessFlags.ACC_PRIVATE;
183 }
184 },
186 new Option(false, "-c") {
187 void process(JavapTask task, String opt, String arg) {
188 task.options.showDisassembled = true;
189 }
190 },
192 new Option(false, "-s") {
193 void process(JavapTask task, String opt, String arg) {
194 task.options.showDescriptors = true;
195 }
196 },
198 // new Option(false, "-all") {
199 // void process(JavapTask task, String opt, String arg) {
200 // task.options.showAllAttrs = true;
201 // }
202 // },
204 new Option(false, "-h") {
205 void process(JavapTask task, String opt, String arg) throws BadArgs {
206 throw task.new BadArgs("err.h.not.supported");
207 }
208 },
210 new Option(false, "-verify", "-verify-verbose") {
211 void process(JavapTask task, String opt, String arg) throws BadArgs {
212 throw task.new BadArgs("err.verify.not.supported");
213 }
214 },
216 new Option(false, "-sysinfo") {
217 void process(JavapTask task, String opt, String arg) {
218 task.options.sysInfo = true;
219 }
220 },
222 new Option(false, "-Xold") {
223 void process(JavapTask task, String opt, String arg) throws BadArgs {
224 task.log.println(task.getMessage("warn.Xold.not.supported"));
225 }
226 },
228 new Option(false, "-Xnew") {
229 void process(JavapTask task, String opt, String arg) throws BadArgs {
230 // ignore: this _is_ the new version
231 }
232 },
234 new Option(false, "-XDcompat") {
235 void process(JavapTask task, String opt, String arg) {
236 task.options.compat = true;
237 }
238 },
240 new Option(false, "-XDdetails") {
241 void process(JavapTask task, String opt, String arg) {
242 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
243 }
245 },
247 new Option(false, "-XDdetails:") {
248 @Override
249 boolean matches(String opt) {
250 int sep = opt.indexOf(":");
251 return sep != -1 && super.matches(opt.substring(0, sep + 1));
252 }
254 void process(JavapTask task, String opt, String arg) throws BadArgs {
255 int sep = opt.indexOf(":");
256 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
257 if (!handleArg(task, v))
258 throw task.new BadArgs("err.invalid.arg.for.option", v);
259 }
260 }
262 boolean handleArg(JavapTask task, String arg) {
263 if (arg.length() == 0)
264 return true;
266 if (arg.equals("all")) {
267 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
268 return true;
269 }
271 boolean on = true;
272 if (arg.startsWith("-")) {
273 on = false;
274 arg = arg.substring(1);
275 }
277 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
278 if (arg.equalsIgnoreCase(k.option)) {
279 if (on)
280 task.options.details.add(k);
281 else
282 task.options.details.remove(k);
283 return true;
284 }
285 }
286 return false;
287 }
288 },
290 new Option(false, "-constants") {
291 void process(JavapTask task, String opt, String arg) {
292 task.options.showConstants = true;
293 }
294 },
296 new Option(false, "-XDinner") {
297 void process(JavapTask task, String opt, String arg) {
298 task.options.showInnerClasses = true;
299 }
300 },
302 new Option(false, "-XDindent:") {
303 @Override
304 boolean matches(String opt) {
305 int sep = opt.indexOf(":");
306 return sep != -1 && super.matches(opt.substring(0, sep + 1));
307 }
309 void process(JavapTask task, String opt, String arg) throws BadArgs {
310 int sep = opt.indexOf(":");
311 try {
312 task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
313 } catch (NumberFormatException e) {
314 }
315 }
316 },
318 new Option(false, "-XDtab:") {
319 @Override
320 boolean matches(String opt) {
321 int sep = opt.indexOf(":");
322 return sep != -1 && super.matches(opt.substring(0, sep + 1));
323 }
325 void process(JavapTask task, String opt, String arg) throws BadArgs {
326 int sep = opt.indexOf(":");
327 try {
328 task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
329 } catch (NumberFormatException e) {
330 }
331 }
332 }
334 };
336 public JavapTask() {
337 context = new Context();
338 context.put(Messages.class, this);
339 options = Options.instance(context);
340 attributeFactory = new Attribute.Factory();
341 }
343 public JavapTask(Writer out,
344 JavaFileManager fileManager,
345 DiagnosticListener<? super JavaFileObject> diagnosticListener) {
346 this();
347 this.log = getPrintWriterForWriter(out);
348 this.fileManager = fileManager;
349 this.diagnosticListener = diagnosticListener;
350 }
352 public JavapTask(Writer out,
353 JavaFileManager fileManager,
354 DiagnosticListener<? super JavaFileObject> diagnosticListener,
355 Iterable<String> options,
356 Iterable<String> classes) {
357 this(out, fileManager, diagnosticListener);
359 this.classes = new ArrayList<String>();
360 for (String classname: classes) {
361 classname.getClass(); // null-check
362 this.classes.add(classname);
363 }
365 try {
366 if (options != null)
367 handleOptions(options, false);
368 } catch (BadArgs e) {
369 throw new IllegalArgumentException(e.getMessage());
370 }
371 }
373 public void setLocale(Locale locale) {
374 if (locale == null)
375 locale = Locale.getDefault();
376 task_locale = locale;
377 }
379 public void setLog(Writer log) {
380 this.log = getPrintWriterForWriter(log);
381 }
383 public void setLog(OutputStream s) {
384 setLog(getPrintWriterForStream(s));
385 }
387 private static PrintWriter getPrintWriterForStream(OutputStream s) {
388 return new PrintWriter(s == null ? System.err : s, true);
389 }
391 private static PrintWriter getPrintWriterForWriter(Writer w) {
392 if (w == null)
393 return getPrintWriterForStream(null);
394 else if (w instanceof PrintWriter)
395 return (PrintWriter) w;
396 else
397 return new PrintWriter(w, true);
398 }
400 public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
401 diagnosticListener = dl;
402 }
404 public void setDiagnosticListener(OutputStream s) {
405 setDiagnosticListener(getDiagnosticListenerForStream(s));
406 }
408 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
409 return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
410 }
412 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
413 final PrintWriter pw = getPrintWriterForWriter(w);
414 return new DiagnosticListener<JavaFileObject> () {
415 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
416 switch (diagnostic.getKind()) {
417 case ERROR:
418 pw.print(getMessage("err.prefix"));
419 break;
420 case WARNING:
421 pw.print(getMessage("warn.prefix"));
422 break;
423 case NOTE:
424 pw.print(getMessage("note.prefix"));
425 break;
426 }
427 pw.print(" ");
428 pw.println(diagnostic.getMessage(null));
429 }
430 };
431 }
433 /** Result codes.
434 */
435 static final int
436 EXIT_OK = 0, // Compilation completed with no errors.
437 EXIT_ERROR = 1, // Completed but reported errors.
438 EXIT_CMDERR = 2, // Bad command-line arguments
439 EXIT_SYSERR = 3, // System error or resource exhaustion.
440 EXIT_ABNORMAL = 4; // Compiler terminated abnormally
442 int run(String[] args) {
443 try {
444 handleOptions(args);
446 // the following gives consistent behavior with javac
447 if (classes == null || classes.size() == 0) {
448 if (options.help || options.version || options.fullVersion)
449 return EXIT_OK;
450 else
451 return EXIT_CMDERR;
452 }
454 try {
455 boolean ok = run();
456 return ok ? EXIT_OK : EXIT_ERROR;
457 } finally {
458 if (defaultFileManager != null) {
459 try {
460 defaultFileManager.close();
461 defaultFileManager = null;
462 } catch (IOException e) {
463 throw new InternalError(e);
464 }
465 }
466 }
467 } catch (BadArgs e) {
468 reportError(e.key, e.args);
469 if (e.showUsage) {
470 log.println(getMessage("main.usage.summary", progname));
471 }
472 return EXIT_CMDERR;
473 } catch (InternalError e) {
474 Object[] e_args;
475 if (e.getCause() == null)
476 e_args = e.args;
477 else {
478 e_args = new Object[e.args.length + 1];
479 e_args[0] = e.getCause();
480 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
481 }
482 reportError("err.internal.error", e_args);
483 return EXIT_ABNORMAL;
484 } finally {
485 log.flush();
486 }
487 }
489 public void handleOptions(String[] args) throws BadArgs {
490 handleOptions(Arrays.asList(args), true);
491 }
493 private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
494 if (log == null) {
495 log = getPrintWriterForStream(System.out);
496 if (diagnosticListener == null)
497 diagnosticListener = getDiagnosticListenerForStream(System.err);
498 } else {
499 if (diagnosticListener == null)
500 diagnosticListener = getDiagnosticListenerForWriter(log);
501 }
504 if (fileManager == null)
505 fileManager = getDefaultFileManager(diagnosticListener, log);
507 Iterator<String> iter = args.iterator();
508 boolean noArgs = !iter.hasNext();
510 while (iter.hasNext()) {
511 String arg = iter.next();
512 if (arg.startsWith("-"))
513 handleOption(arg, iter);
514 else if (allowClasses) {
515 if (classes == null)
516 classes = new ArrayList<String>();
517 classes.add(arg);
518 while (iter.hasNext())
519 classes.add(iter.next());
520 } else
521 throw new BadArgs("err.unknown.option", arg).showUsage(true);
522 }
524 if (!options.compat && options.accessOptions.size() > 1) {
525 StringBuilder sb = new StringBuilder();
526 for (String opt: options.accessOptions) {
527 if (sb.length() > 0)
528 sb.append(" ");
529 sb.append(opt);
530 }
531 throw new BadArgs("err.incompatible.options", sb);
532 }
534 if ((classes == null || classes.size() == 0) &&
535 !(noArgs || options.help || options.version || options.fullVersion)) {
536 throw new BadArgs("err.no.classes.specified");
537 }
539 if (noArgs || options.help)
540 showHelp();
542 if (options.version || options.fullVersion)
543 showVersion(options.fullVersion);
544 }
546 private void handleOption(String name, Iterator<String> rest) throws BadArgs {
547 for (Option o: recognizedOptions) {
548 if (o.matches(name)) {
549 if (o.hasArg) {
550 if (rest.hasNext())
551 o.process(this, name, rest.next());
552 else
553 throw new BadArgs("err.missing.arg", name).showUsage(true);
554 } else
555 o.process(this, name, null);
557 if (o.ignoreRest()) {
558 while (rest.hasNext())
559 rest.next();
560 }
561 return;
562 }
563 }
565 if (fileManager.handleOption(name, rest))
566 return;
568 throw new BadArgs("err.unknown.option", name).showUsage(true);
569 }
571 public Boolean call() {
572 return run();
573 }
575 public boolean run() {
576 if (classes == null || classes.size() == 0)
577 return false;
579 context.put(PrintWriter.class, log);
580 ClassWriter classWriter = ClassWriter.instance(context);
581 SourceWriter sourceWriter = SourceWriter.instance(context);
582 sourceWriter.setFileManager(fileManager);
584 attributeFactory.setCompat(options.compat);
586 boolean ok = true;
588 for (String className: classes) {
589 JavaFileObject fo;
590 try {
591 writeClass(classWriter, className);
592 } catch (ConstantPoolException e) {
593 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
594 ok = false;
595 } catch (EOFException e) {
596 reportError("err.end.of.file", className);
597 ok = false;
598 } catch (FileNotFoundException e) {
599 reportError("err.file.not.found", e.getLocalizedMessage());
600 ok = false;
601 } catch (IOException e) {
602 //e.printStackTrace();
603 Object msg = e.getLocalizedMessage();
604 if (msg == null)
605 msg = e;
606 reportError("err.ioerror", className, msg);
607 ok = false;
608 } catch (Throwable t) {
609 StringWriter sw = new StringWriter();
610 PrintWriter pw = new PrintWriter(sw);
611 t.printStackTrace(pw);
612 pw.close();
613 reportError("err.crash", t.toString(), sw.toString());
614 ok = false;
615 }
616 }
618 return ok;
619 }
621 protected boolean writeClass(ClassWriter classWriter, String className)
622 throws IOException, ConstantPoolException {
623 JavaFileObject fo = open(className);
624 if (fo == null) {
625 reportError("err.class.not.found", className);
626 return false;
627 }
629 ClassFileInfo cfInfo = read(fo);
630 if (!className.endsWith(".class")) {
631 String cfName = cfInfo.cf.getName();
632 if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
633 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
634 }
635 write(cfInfo);
637 if (options.showInnerClasses) {
638 ClassFile cf = cfInfo.cf;
639 Attribute a = cf.getAttribute(Attribute.InnerClasses);
640 if (a instanceof InnerClasses_attribute) {
641 InnerClasses_attribute inners = (InnerClasses_attribute) a;
642 try {
643 boolean ok = true;
644 for (int i = 0; i < inners.classes.length; i++) {
645 int outerIndex = inners.classes[i].outer_class_info_index;
646 ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
647 String outerClassName = outerClassInfo.getName();
648 if (outerClassName.equals(cf.getName())) {
649 int innerIndex = inners.classes[i].inner_class_info_index;
650 ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
651 String innerClassName = innerClassInfo.getName();
652 classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
653 classWriter.println();
654 ok = ok & writeClass(classWriter, innerClassName);
655 }
656 }
657 return ok;
658 } catch (ConstantPoolException e) {
659 reportError("err.bad.innerclasses.attribute", className);
660 return false;
661 }
662 } else if (a != null) {
663 reportError("err.bad.innerclasses.attribute", className);
664 return false;
665 }
666 }
668 return true;
669 }
671 protected JavaFileObject open(String className) throws IOException {
672 // for compatibility, first see if it is a class name
673 JavaFileObject fo = getClassFileObject(className);
674 if (fo != null)
675 return fo;
677 // see if it is an inner class, by replacing dots to $, starting from the right
678 String cn = className;
679 int lastDot;
680 while ((lastDot = cn.lastIndexOf(".")) != -1) {
681 cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
682 fo = getClassFileObject(cn);
683 if (fo != null)
684 return fo;
685 }
687 if (!className.endsWith(".class"))
688 return null;
690 if (fileManager instanceof StandardJavaFileManager) {
691 StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
692 fo = sfm.getJavaFileObjects(className).iterator().next();
693 if (fo != null && fo.getLastModified() != 0) {
694 return fo;
695 }
696 }
698 // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
699 // to suit javap's needs
700 if (className.matches("^[A-Za-z]+:.*")) {
701 try {
702 final URI uri = new URI(className);
703 final URL url = uri.toURL();
704 final URLConnection conn = url.openConnection();
705 return new JavaFileObject() {
706 public Kind getKind() {
707 return JavaFileObject.Kind.CLASS;
708 }
710 public boolean isNameCompatible(String simpleName, Kind kind) {
711 throw new UnsupportedOperationException();
712 }
714 public NestingKind getNestingKind() {
715 throw new UnsupportedOperationException();
716 }
718 public Modifier getAccessLevel() {
719 throw new UnsupportedOperationException();
720 }
722 public URI toUri() {
723 return uri;
724 }
726 public String getName() {
727 return url.toString();
728 }
730 public InputStream openInputStream() throws IOException {
731 return conn.getInputStream();
732 }
734 public OutputStream openOutputStream() throws IOException {
735 throw new UnsupportedOperationException();
736 }
738 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
739 throw new UnsupportedOperationException();
740 }
742 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
743 throw new UnsupportedOperationException();
744 }
746 public Writer openWriter() throws IOException {
747 throw new UnsupportedOperationException();
748 }
750 public long getLastModified() {
751 return conn.getLastModified();
752 }
754 public boolean delete() {
755 throw new UnsupportedOperationException();
756 }
758 };
759 } catch (URISyntaxException ignore) {
760 } catch (IOException ignore) {
761 }
762 }
764 return null;
765 }
767 public static class ClassFileInfo {
768 ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
769 this.fo = fo;
770 this.cf = cf;
771 this.digest = digest;
772 this.size = size;
773 }
774 public final JavaFileObject fo;
775 public final ClassFile cf;
776 public final byte[] digest;
777 public final int size;
778 }
780 public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
781 InputStream in = fo.openInputStream();
782 try {
783 SizeInputStream sizeIn = null;
784 MessageDigest md = null;
785 if (options.sysInfo || options.verbose) {
786 try {
787 md = MessageDigest.getInstance("MD5");
788 } catch (NoSuchAlgorithmException ignore) {
789 }
790 in = new DigestInputStream(in, md);
791 in = sizeIn = new SizeInputStream(in);
792 }
794 ClassFile cf = ClassFile.read(in, attributeFactory);
795 byte[] digest = (md == null) ? null : md.digest();
796 int size = (sizeIn == null) ? -1 : sizeIn.size();
797 return new ClassFileInfo(fo, cf, digest, size);
798 } finally {
799 in.close();
800 }
801 }
803 public void write(ClassFileInfo info) {
804 ClassWriter classWriter = ClassWriter.instance(context);
805 if (options.sysInfo || options.verbose) {
806 classWriter.setFile(info.fo.toUri());
807 classWriter.setLastModified(info.fo.getLastModified());
808 classWriter.setDigest("MD5", info.digest);
809 classWriter.setFileSize(info.size);
810 }
812 classWriter.write(info.cf);
813 }
815 protected void setClassFile(ClassFile classFile) {
816 ClassWriter classWriter = ClassWriter.instance(context);
817 classWriter.setClassFile(classFile);
818 }
820 protected void setMethod(Method enclosingMethod) {
821 ClassWriter classWriter = ClassWriter.instance(context);
822 classWriter.setMethod(enclosingMethod);
823 }
825 protected void write(Attribute value) {
826 AttributeWriter attrWriter = AttributeWriter.instance(context);
827 ClassWriter classWriter = ClassWriter.instance(context);
828 ClassFile cf = classWriter.getClassFile();
829 attrWriter.write(cf, value, cf.constant_pool);
830 }
832 protected void write(Attributes attrs) {
833 AttributeWriter attrWriter = AttributeWriter.instance(context);
834 ClassWriter classWriter = ClassWriter.instance(context);
835 ClassFile cf = classWriter.getClassFile();
836 attrWriter.write(cf, attrs, cf.constant_pool);
837 }
839 protected void write(ConstantPool constant_pool) {
840 ConstantWriter constantWriter = ConstantWriter.instance(context);
841 constantWriter.writeConstantPool(constant_pool);
842 }
844 protected void write(ConstantPool constant_pool, int value) {
845 ConstantWriter constantWriter = ConstantWriter.instance(context);
846 constantWriter.write(value);
847 }
849 protected void write(ConstantPool.CPInfo value) {
850 ConstantWriter constantWriter = ConstantWriter.instance(context);
851 constantWriter.println(value);
852 }
854 protected void write(Field value) {
855 ClassWriter classWriter = ClassWriter.instance(context);
856 classWriter.writeField(value);
857 }
859 protected void write(Method value) {
860 ClassWriter classWriter = ClassWriter.instance(context);
861 classWriter.writeMethod(value);
862 }
864 private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
865 if (defaultFileManager == null)
866 defaultFileManager = JavapFileManager.create(dl, log);
867 return defaultFileManager;
868 }
870 private JavaFileObject getClassFileObject(String className) throws IOException {
871 JavaFileObject fo;
872 fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
873 if (fo == null)
874 fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
875 return fo;
876 }
878 private void showHelp() {
879 log.println(getMessage("main.usage", progname));
880 for (Option o: recognizedOptions) {
881 String name = o.aliases[0].substring(1); // there must always be at least one name
882 if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
883 continue;
884 log.println(getMessage("main.opt." + name));
885 }
886 String[] fmOptions = { "-classpath", "-bootclasspath" };
887 for (String o: fmOptions) {
888 if (fileManager.isSupportedOption(o) == -1)
889 continue;
890 String name = o.substring(1);
891 log.println(getMessage("main.opt." + name));
892 }
894 }
896 private void showVersion(boolean full) {
897 log.println(version(full ? "full" : "release"));
898 }
900 private static final String versionRBName = "com.sun.tools.javap.resources.version";
901 private static ResourceBundle versionRB;
903 private String version(String key) {
904 // key=version: mm.nn.oo[-milestone]
905 // key=full: mm.mm.oo[-milestone]-build
906 if (versionRB == null) {
907 try {
908 versionRB = ResourceBundle.getBundle(versionRBName);
909 } catch (MissingResourceException e) {
910 return getMessage("version.resource.missing", System.getProperty("java.version"));
911 }
912 }
913 try {
914 return versionRB.getString(key);
915 }
916 catch (MissingResourceException e) {
917 return getMessage("version.unknown", System.getProperty("java.version"));
918 }
919 }
921 private void reportError(String key, Object... args) {
922 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
923 }
925 private void reportNote(String key, Object... args) {
926 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
927 }
929 private void reportWarning(String key, Object... args) {
930 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
931 }
933 private Diagnostic<JavaFileObject> createDiagnostic(
934 final Diagnostic.Kind kind, final String key, final Object... args) {
935 return new Diagnostic<JavaFileObject>() {
936 public Kind getKind() {
937 return kind;
938 }
940 public JavaFileObject getSource() {
941 return null;
942 }
944 public long getPosition() {
945 return Diagnostic.NOPOS;
946 }
948 public long getStartPosition() {
949 return Diagnostic.NOPOS;
950 }
952 public long getEndPosition() {
953 return Diagnostic.NOPOS;
954 }
956 public long getLineNumber() {
957 return Diagnostic.NOPOS;
958 }
960 public long getColumnNumber() {
961 return Diagnostic.NOPOS;
962 }
964 public String getCode() {
965 return key;
966 }
968 public String getMessage(Locale locale) {
969 return JavapTask.this.getMessage(locale, key, args);
970 }
972 @Override
973 public String toString() {
974 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
975 }
977 };
979 }
981 public String getMessage(String key, Object... args) {
982 return getMessage(task_locale, key, args);
983 }
985 public String getMessage(Locale locale, String key, Object... args) {
986 if (bundles == null) {
987 // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
988 // and for efficiency, keep a hard reference to the bundle for the task
989 // locale
990 bundles = new HashMap<Locale, ResourceBundle>();
991 }
993 if (locale == null)
994 locale = Locale.getDefault();
996 ResourceBundle b = bundles.get(locale);
997 if (b == null) {
998 try {
999 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
1000 bundles.put(locale, b);
1001 } catch (MissingResourceException e) {
1002 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
1003 }
1004 }
1006 try {
1007 return MessageFormat.format(b.getString(key), args);
1008 } catch (MissingResourceException e) {
1009 throw new InternalError(e, key);
1010 }
1011 }
1013 protected Context context;
1014 JavaFileManager fileManager;
1015 JavaFileManager defaultFileManager;
1016 PrintWriter log;
1017 DiagnosticListener<? super JavaFileObject> diagnosticListener;
1018 List<String> classes;
1019 Options options;
1020 //ResourceBundle bundle;
1021 Locale task_locale;
1022 Map<Locale, ResourceBundle> bundles;
1023 protected Attribute.Factory attributeFactory;
1025 private static final String progname = "javap";
1027 private static class SizeInputStream extends FilterInputStream {
1028 SizeInputStream(InputStream in) {
1029 super(in);
1030 }
1032 int size() {
1033 return size;
1034 }
1036 @Override
1037 public int read(byte[] buf, int offset, int length) throws IOException {
1038 int n = super.read(buf, offset, length);
1039 if (n > 0)
1040 size += n;
1041 return n;
1042 }
1044 @Override
1045 public int read() throws IOException {
1046 int b = super.read();
1047 size += 1;
1048 return b;
1049 }
1051 private int size;
1052 }
1053 }