/* * Copyright 2004-2010 Brian S O'Neill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cojen.classfile; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.cojen.classfile.attribute.CodeAttr; import org.cojen.classfile.attribute.SignatureAttr; /** * Disassembles a class file, sending the results to standard out. The class * can be specified by name or by a file name. If the class is specified by * name, it must be available in the classpath. * <p> * Two output formats are supported: assembly and builder. The assembly format * is the default, and it produces a pseudo Java source file, where the method * bodies contain JVM assembly code. * <p> * The builder format produces a valid Java file, which uses the Cojen * classfile API. When compiled and run, it rebuilds the original class and * inner classes. This format makes it easier to understand how to use the * classfile API to generate new classes. * * @author Brian S O'Neill */ public class DisassemblyTool { /** * Disassembles a class file, sending the results to standard out. * * <pre> * DisassemblyTool [-f <format style>] <file or class name> * </pre> * * The format style may be "assembly" (the default) or "builder". */ public static void main(String[] args) throws Exception { if (args.length == 0) { System.out.println("DisassemblyTool [-f <format style>] <file or class name>"); System.out.println(); System.out.println("The format style may be \"assembly\" (the default) or \"builder\""); return; } String style; String name; if ("-f".equals(args[0])) { style = args[1]; name = args[2]; } else { style = "assembly"; name = args[0]; } ClassFileDataLoader loader; InputStream in; try { final File file = new File(name); in = new FileInputStream(file); loader = new ClassFileDataLoader() { public InputStream getClassData(String name) throws IOException { name = name.substring(name.lastIndexOf('.') + 1); File f = new File(file.getParentFile(), name + ".class"); if (f.exists()) { return new FileInputStream(f); } return null; } }; } catch (FileNotFoundException e) { if (name.endsWith(".class")) { System.err.println(e); return; } loader = new ResourceClassFileDataLoader(); in = loader.getClassData(name); if (in == null) { System.err.println(e); return; } } in = new BufferedInputStream(in); ClassFile cf = ClassFile.readFrom(in, loader, null); PrintWriter out = new PrintWriter(System.out); Printer p; if (style == null || style.equals("assembly")) { p = new AssemblyStylePrinter(); } else if (style.equals("builder")) { p = new BuilderStylePrinter(); } else { System.err.println("Unknown format style: " + style); return; } p.disassemble(cf, out); out.flush(); } public static interface Printer { void disassemble(ClassFile cf, PrintWriter out); } }