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