001: /*
002: * Copyright 2004 Brian S O'Neill
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.cojen.classfile;
018:
019: import java.io.BufferedInputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileNotFoundException;
023: import java.io.InputStream;
024: import java.io.IOException;
025: import java.io.PrintWriter;
026: import java.util.ArrayList;
027: import java.util.Arrays;
028: import java.util.Comparator;
029: import java.util.Date;
030: import java.util.HashMap;
031: import java.util.List;
032: import java.util.Map;
033:
034: import org.cojen.classfile.attribute.CodeAttr;
035: import org.cojen.classfile.attribute.SignatureAttr;
036:
037: /**
038: * Disassembles a class file, sending the results to standard out. The class
039: * can be specified by name or by a file name. If the class is specified by
040: * name, it must be available in the classpath.
041: * <p>
042: * Two output formats are supported: assembly and builder. The assembly format
043: * is the default, and it produces a pseudo Java source file, where the method
044: * bodies contain JVM assembly code.
045: * <p>
046: * The builder format produces a valid Java file, which uses the Cojen
047: * classfile API. When compiled and run, it rebuilds the original class and
048: * inner classes. This format makes it easier to understand how to use the
049: * classfile API to generate new classes.
050: *
051: * @author Brian S O'Neill
052: */
053: public class DisassemblyTool {
054: /**
055: * Disassembles a class file, sending the results to standard out.
056: *
057: * <pre>
058: * DisassemblyTool [-f <format style>] <file or class name>
059: * </pre>
060: *
061: * The format style may be "assembly" (the default) or "builder".
062: */
063: public static void main(String[] args) throws Exception {
064: if (args.length == 0) {
065: System.out
066: .println("DisassemblyTool [-f <format style>] <file or class name>");
067: System.out.println();
068: System.out
069: .println("The format style may be \"assembly\" (the default) or \"builder\"");
070: return;
071: }
072:
073: String style;
074: String name;
075:
076: if ("-f".equals(args[0])) {
077: style = args[1];
078: name = args[2];
079: } else {
080: style = "assembly";
081: name = args[0];
082: }
083:
084: ClassFileDataLoader loader;
085: InputStream in;
086:
087: try {
088: final File file = new File(name);
089: in = new FileInputStream(file);
090: loader = new ClassFileDataLoader() {
091: public InputStream getClassData(String name)
092: throws IOException {
093: name = name.substring(name.lastIndexOf('.') + 1);
094: File f = new File(file.getParentFile(), name
095: + ".class");
096:
097: if (f.exists()) {
098: return new FileInputStream(f);
099: }
100:
101: return null;
102: }
103: };
104: } catch (FileNotFoundException e) {
105: if (name.endsWith(".class")) {
106: System.err.println(e);
107: return;
108: }
109:
110: loader = new ResourceClassFileDataLoader();
111: in = loader.getClassData(name);
112:
113: if (in == null) {
114: System.err.println(e);
115: return;
116: }
117: }
118:
119: in = new BufferedInputStream(in);
120: ClassFile cf = ClassFile.readFrom(in, loader, null);
121:
122: PrintWriter out = new PrintWriter(System.out);
123:
124: Printer p;
125: if (style == null || style.equals("assembly")) {
126: p = new AssemblyStylePrinter();
127: } else if (style.equals("builder")) {
128: p = new BuilderStylePrinter();
129: } else {
130: System.err.println("Unknown format style: " + style);
131: return;
132: }
133:
134: p.disassemble(cf, out);
135:
136: out.flush();
137: }
138:
139: public static interface Printer {
140: void disassemble(ClassFile cf, PrintWriter out);
141: }
142: }
|