import java.io.File; import classfile.*; import classfile.ClassFile.*; import classfile.util.StringUtil; import classfile.view.*; import java.io.PrintWriter; import java.io.Writer; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.Enumeration; /** * Sample application. *

* The user can specify any view after the -o flag. This view * must exist as either "classfile.view." + theview + "View" or * theview + "View". The classfile.view package is * searched first, then the default package. *

* For example, type *

 * java DJava -o Jasmin HelloWorld.class
* to use the JasminView module. Note the capital 'J'. Or type *
 * java DJava -o mypackage.subpack.Numbered Assign4.class
* to use mypackage.subpack.NumberedView. * *

* Copyright © 1997 Shawn Silverman * * @author Shawn Silverman - * shawn@pobox.com */ public class DJava implements ClassFileConstants { private static PrintWriter pw = new PrintWriter(System.out); private static boolean onlyAttributes; private static boolean onlyFields; private static boolean onlyConstantPool; private static boolean loadFromClassPath; // As soon as I figure out a good way to do this, I'll do it // Done! private static boolean noLNT; private static boolean noLVT; public static void main(String args[]) throws IOException, ClassFileFormatException { if (args.length == 0) { printUsage(); return; } String classname = null; String outputView = "DJava"; boolean flagsDone = false; // Look for only the first classname for (int i = 0; i < args.length && classname == null; i++) { String arg = args[i]; if (arg.charAt(0) == '-') { if (flagsDone || arg.length() == 1) { printUsage(); return; } // Parse the flags int index = 1; while (index < arg.length()) { switch (arg.charAt(index++)) { case 'a': onlyAttributes = true; break; case 'c': onlyConstantPool = true; break; case 'f': onlyFields = true; break; case 'h': printDetailedUsage(); return; case 'l': loadFromClassPath = true; break; case 'n': // Make sure no more chars after if (index < arg.length()) { printUsage(); return; } if (++i >= args.length) { printUsage(); return; } arg = args[i]; if (arg.equals("lnt")) noLNT = true; else if (arg.equals("lvt")) noLVT = true; // Break out of the while loop index = arg.length(); break; case 'o': // Make sure no more chars after if (index < arg.length()) { printUsage(); return; } if (++i >= args.length) { printUsage(); return; } outputView = args[i]; // Break out of the while loop index = outputView.length(); break; default: printUsage(); return; } } } else { flagsDone = true; classname = arg; } } if (classname == null) { printUsage(); return; } ClassFile cf; // Make the new classfile try { String mode = null; if (onlyAttributes || onlyConstantPool) mode = "lite"; if (loadFromClassPath) cf = new ClassFile(classname, mode); else cf = new ClassFile(new File(classname), mode); } catch (FileNotFoundException fnfe) { System.err.println("DJava: Class not found: " + classname); return; } // Use the correct view, and print usage if incorrect // First search classfile.view package, then default package Class view; try { view = Class.forName("classfile.view." + outputView + "View"); } catch (ClassNotFoundException cnfe) { try { view = Class.forName(outputView + "View"); } catch (ClassNotFoundException cnfe2) { System.err.println("DJava: View not found: " + outputView + " (Check capitalization)"); return; } } // Make a new instance of this view and set it Class[] paramTypes = {Writer.class}; Constructor constr; try { constr = view.getConstructor(paramTypes); Object[] initargs = {pw}; cf.setView((ClassFileView)constr.newInstance(initargs)); } catch (Exception e) { System.err.println(e); return; } /*if (output.equals("djava")) cf.setView(new DJavaView(pw)); else if (output.equals("jasmin")) cf.setView(new JasminView(pw)); else if (output.equals("grinder")) cf.setView(new GrinderView(pw)); else if (output.equals("krad")) cf.setView(new KRadView(pw)); else cf.setView(new DJavaView(pw)); */ if (onlyFields) showOnlyFields(cf); else if (onlyAttributes) showOnlyAttributes(cf); else if (onlyConstantPool) showOnlyConstantPool(cf); else { if (noLVT) cf.getView().disableLocalVariableTableAttribute(true); if (noLNT) cf.getView().disableLineNumberTableAttribute(true); cf.show(); } pw.flush(); } private static void showOnlyFields(ClassFile cf) { pw.println(">> " + cf.getAtThisClass() + " <<"); pw.println(); pw.println("Fields:"); pw.println(); Enumeration items; items = cf.getFields().elements(); while (items.hasMoreElements()) { ((Field)items.nextElement()).show(); } pw.println(); // Don't display the method body cf.getView().disableCodeAttribute(true); items = cf.getMethods().elements(); while (items.hasMoreElements()) { ((Method)items.nextElement()).show(); } } private static void showOnlyConstantPool(ClassFile cf) { pw.println(">> " + cf.getAtThisClass() + " <<"); pw.println(); pw.println("Constant pool:"); pw.println(); Enumeration cpEntries = cf.getConstantPool().elements(); // The 0th one doesn't count if (cpEntries.hasMoreElements()) cpEntries.nextElement(); int i = 1; while (cpEntries.hasMoreElements()) { Constant cpEntry = (Constant)cpEntries.nextElement(); pw.print(StringUtil.rightAlign(String.valueOf(i++), 5) + ": "); cpEntry.show(); // Advance i again if this takes up two constant entries switch (cpEntry.getTag()) { case CONSTANT_Long: case CONSTANT_Double: i++; cpEntries.nextElement(); } } } private static void showOnlyAttributes(ClassFile cf) { pw.println(">> " + cf.getAtThisClass() + " <<"); pw.println(); pw.println("Attributes:"); Enumeration atts; showAttributes(cf.getAttributes().elements(), 4); pw.println(); pw.println("Field attributes:"); Enumeration fields = cf.getFields().elements(); while (fields.hasMoreElements()) { Field field = (Field)fields.nextElement(); pw.println(" " + field.getAtNameIndex()); showAttributes(field.getAttributes().elements(), 8); } pw.println(); pw.println("Method attributes:"); Enumeration methods = cf.getMethods().elements(); while (methods.hasMoreElements()) { Method method = (Method)methods.nextElement(); pw.print(" " + method.getAtNameIndex()); pw.println("{ " + method.getAtSigIndex() + " }"); showAttributes(method.getAttributes().elements(), 8); } } private static void showAttributes(Enumeration atts, int indentLength) { if (!atts.hasMoreElements()) return; // Make an indent string if there are elements StringBuffer sb = new StringBuffer(); for (int i = 0; i < indentLength; i++) sb.append(' '); String strIndent = sb.toString(); while (atts.hasMoreElements()) { Attribute att = (Attribute)atts.nextElement(); pw.println(strIndent + "-" + att.getAtNameIndex() + "-"); if (att instanceof CodeAttribute) { Enumeration codeAttAtts = att.getSubAttributes().elements(); showAttributes(codeAttAtts, indentLength + 4); } } } private static void printUsage() { System.out.println("Usage: DJava [-acfhl] [[-n ]...] [-o ] classfile"); System.out.println(" DJava -h for more detailed help."); } private static void printDetailedUsage() { System.out.println("------------------- DJava -------------------"); System.out.println(" Copyright (c) 1996-Present Shawn Silverman"); System.out.println(" email: shawn@pobox.com"); System.out.println("---------------------------------------------"); System.out.println("Usage: DJava [options] classfile"); System.out.println(" -a Show only attributes"); System.out.println(" This option does not load the attributes into memory"); System.out.println(" -c Dump the constant pool"); System.out.println(" -f List of field and method names"); System.out.println(" -h This help listing"); System.out.println(" -l Load classfile from CLASSPATH"); System.out.println(" -n Omit one of:"); System.out.println(" * lnt - line number table"); System.out.println(" * lvt - local variable table"); System.out.println(" -o Output in a specific format,"); System.out.println(" where can be one of:"); System.out.println(" * Jasmin * Grinder"); System.out.println(" * Hex"); System.out.println(" * DJava - this is the default"); System.out.println(" * KRad - untamed for the animal in you"); System.out.println(" * Builder - outputs to a compilable .java file"); System.out.println(" for simple reassembly"); System.out.println(" * your own View"); System.out.println(" class \"java.lang.Object\" format if \'-l\' option is specified"); System.out.println(" For inner classes, use \'$\'"); } }