package cutils.classDumper;
import java.io.*;
public class ClassFile {
int magic;
short majorVersion;
short minorVersion;
ConstantPoolInfo constantPool[];
short accessFlags;
ConstantPoolInfo thisClass;
ConstantPoolInfo superClass;
ConstantPoolInfo interfaces[];
FieldInfo fields[];
MethodInfo methods[];
AttributeInfo attributes[];
boolean isValidClass = false;
public static final int ACC_PUBLIC = 0x1;
public static final int ACC_PRIVATE = 0x2;
public static final int ACC_PROTECTED = 0x4;
public static final int ACC_STATIC = 0x8;
public static final int ACC_FINAL = 0x10;
public static final int ACC_SYNCHRONIZED = 0x20;
public static final int ACC_THREADSAFE = 0x40;
public static final int ACC_TRANSIENT = 0x80;
public static final int ACC_NATIVE = 0x100;
public static final int ACC_INTERFACE = 0x200;
public static final int ACC_ABSTRACT = 0x400;
public boolean debug = false;
public boolean dumpConstants = false;
public boolean read(InputStream in)
throws IOException {
DataInputStream di = new DataInputStream(in);
int count;
magic = di.readInt();
if (magic != (int) 0xCAFEBABE) {
return (false);
}
majorVersion = di.readShort();
minorVersion = di.readShort();
count = di.readShort();
constantPool = new ConstantPoolInfo[count];
if (debug)
System.out.println("read(): Read writeHeader...");
constantPool[0] = new ConstantPoolInfo();
for (int i = 1; i < constantPool.length; i++) {
constantPool[i] = new ConstantPoolInfo();
if (!constantPool[i].read(di)) {
return (false);
}
if ((constantPool[i].type == ConstantPoolInfo.LONG) ||
(constantPool[i].type == ConstantPoolInfo.DOUBLE))
i++;
}
for (int i = 1; i < constantPool.length; i++) {
if (constantPool[i] == null)
continue;
if (constantPool[i].index1 > 0)
constantPool[i].arg1 = constantPool[constantPool[i].index1];
if (constantPool[i].index2 > 0)
constantPool[i].arg2 = constantPool[constantPool[i].index2];
}
if (dumpConstants) {
for (int i = 1; i < constantPool.length; i++) {
System.out.println("C" + i + " - " + constantPool[i]);
}
}
accessFlags = di.readShort();
thisClass = constantPool[di.readShort()];
superClass = constantPool[di.readShort()];
if (debug)
System.out.println("read(): Read class info...");
count = di.readShort();
if (count != 0) {
if (debug)
System.out.println("Class implements " + count + " interfaces.");
interfaces = new ConstantPoolInfo[count];
for (int i = 0; i < count; i++) {
int iindex = di.readShort();
if ((iindex < 1) || (iindex > constantPool.length - 1))
return (false);
interfaces[i] = constantPool[iindex];
if (debug)
System.out.println("I" + i + ": " + interfaces[i]);
}
}
if (debug)
System.out.println("read(): Read interface info...");
count = di.readShort();
if (debug)
System.out.println("This class has " + count + " fields.");
if (count != 0) {
fields = new FieldInfo[count];
for (int i = 0; i < count; i++) {
fields[i] = new FieldInfo();
if (!fields[i].read(di, constantPool)) {
return (false);
}
if (debug)
System.out.println("F" + i + ": " +
fields[i].toString(constantPool));
}
}
if (debug)
System.out.println("read(): Read field info...");
count = di.readShort();
if (count != 0) {
methods = new MethodInfo[count];
for (int i = 0; i < count; i++) {
methods[i] = new MethodInfo();
if (!methods[i].read(di, constantPool)) {
return (false);
}
if (debug)
System.out.println("M" + i + ": " + methods[i].toString());
}
}
if (debug)
System.out.println("read(): Read method info...");
count = di.readShort();
if (count != 0) {
attributes = new AttributeInfo[count];
for (int i = 0; i < count; i++) {
attributes[i] = new AttributeInfo();
if (!attributes[i].read(di, constantPool)) {
return (false);
}
}
}
if (debug) {
System.out.println("read(): Read attribute info...");
System.out.println("done.");
}
isValidClass = true;
return (true);
}
public void write(OutputStream out)
throws IOException, Exception {
DataOutputStream dos = new DataOutputStream(out);
if (!isValidClass) {
throw new Exception("ClassFile::write() - Invalid Class");
}
dos.writeInt(magic);
dos.writeShort(majorVersion);
dos.writeShort(minorVersion);
dos.writeShort(constantPool.length);
for (int i = 1; i < constantPool.length; i++) {
if (constantPool[i] != null)
constantPool[i].write(dos, constantPool);
}
dos.writeShort(accessFlags);
dos.writeShort(ConstantPoolInfo.indexOf(thisClass, constantPool));
dos.writeShort(ConstantPoolInfo.indexOf(superClass, constantPool));
if (interfaces == null)
dos.writeShort(0);
else {
dos.writeShort(interfaces.length);
for (int i = 0; i < interfaces.length; i++)
dos.writeShort(
ConstantPoolInfo.indexOf(
interfaces[i], constantPool));
}
if (fields == null) {
dos.writeShort(0);
} else {
dos.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
fields[i].write(dos, constantPool);
}
}
if (methods == null) {
dos.writeShort(0);
} else {
dos.writeShort(methods.length);
for (int i = 0; i < methods.length; i++) {
methods[i].write(dos, constantPool);
}
}
if (attributes == null) {
dos.writeShort(0);
} else {
dos.writeShort(attributes.length);
for (int i = 0; i < attributes.length; i++) {
attributes[i].write(dos, constantPool);
}
}
}
public static String accessString(short flags) {
StringBuffer x = new StringBuffer();
if ((flags & ACC_PUBLIC) != 0) {
x.append("public ");
}
if ((flags & ACC_PRIVATE) != 0) {
x.append("private ");
}
if ((flags & ACC_PROTECTED) != 0) {
x.append("protected ");
}
if ((flags & ACC_STATIC) != 0) {
x.append("static ");
}
if ((flags & ACC_FINAL) != 0) {
x.append("final ");
}
if ((flags & ACC_SYNCHRONIZED) != 0) {
x.append("synchronized ");
}
if ((flags & ACC_THREADSAFE) != 0) {
x.append("threadsafe ");
}
if ((flags & ACC_TRANSIENT) != 0) {
x.append("transient ");
}
if ((flags & ACC_NATIVE) != 0) {
x.append("native ");
}
if ((flags & ACC_INTERFACE) != 0) {
x.append("interface ");
}
if ((flags & ACC_ABSTRACT) != 0) {
x.append("abstract ");
}
return (x.toString());
}
public static String typeString(String typeString, String varName) {
int isArray = 0;
int ndx = 0;
StringBuffer x = new StringBuffer();
while (typeString.charAt(ndx) == '[') {
isArray++;
ndx++;
}
switch (typeString.charAt(ndx)) {
case 'B':
x.append("byte ");
break;
case 'C':
x.append("char ");
break;
case 'D':
x.append("double ");
break;
case 'F':
x.append("float ");
break;
case 'I':
x.append("int ");
break;
case 'J':
x.append("long ");
break;
case 'L':
for (int i = ndx + 1; i < typeString.indexOf(';'); i++) {
if (typeString.charAt(i) != '/')
x.append(typeString.charAt(i));
else
x.append('.');
}
x.append(" ");
break;
case 'V':
x.append("void ");
break;
case 'S':
x.append("short ");
break;
case 'Z':
x.append("boolean ");
break;
}
x.append(varName);
while (isArray > 0) {
x.append("[]");
isArray--;
}
return (x.toString());
}
public static String nextSig(String sig) {
int ndx = 0;
String x;
while (sig.charAt(ndx) == '[')
ndx++;
if (sig.charAt(ndx) == 'L') {
while (sig.charAt(ndx) != ';')
ndx++;
}
ndx++;
x = (sig.substring(ndx));
return (x);
}
private String printClassName(String s) {
StringBuffer x;
if (s.charAt(0) == '[') {
return (typeString(s, ""));
}
x = new StringBuffer();
for (int j = 0; j < s.length(); j++) {
if (s.charAt(j) == '/')
x.append('.');
else
x.append(s.charAt(j));
}
return (x.toString());
}
public String getClassName() {
return printClassName(thisClass.arg1.strValue);
}
public String toString() {
return ("Class File (Version " + majorVersion + "." + minorVersion +
") for class " + thisClass.arg1);
}
public void display(PrintStream ps)
throws Exception {
int i;
String myClassName;
String mySuperClassName;
String packageName = null;
if (!isValidClass) {
ps.println("Not a valid class");
}
myClassName = printClassName(thisClass.arg1.strValue);
mySuperClassName = printClassName(superClass.arg1.strValue);
if (myClassName.indexOf('.') > 0) {
packageName =
myClassName.substring(0, myClassName.lastIndexOf('.'));
myClassName = myClassName.substring(myClassName.lastIndexOf('.') + 1);
ps.println("package " + packageName + "\n");
}
for (i = 1; i < constantPool.length; i++) {
if (constantPool[i] == null)
continue;
if ((constantPool[i] == thisClass) ||
(constantPool[i] == superClass))
continue;
if (constantPool[i].type == ConstantPoolInfo.CLASS) {
String s = constantPool[i].arg1.strValue;
if (s.charAt(0) == '[')
continue;
s = printClassName(constantPool[i].arg1.strValue);
if ((packageName != null) && (s.startsWith(packageName)))
continue;
ps.println("import " + printClassName(s) + ";");
}
}
ps.println();
ps.println("/*");
DataInputStream dis;
ConstantPoolInfo cpi;
if (attributes != null) {
ps.println(" * This class has " + attributes.length +
" optional class attributes.");
ps.println(" * These attributes are: ");
for (i = 0; i < attributes.length; i++) {
String attrName = attributes[i].name.strValue;
dis = new DataInputStream(new ByteArrayInputStream(attributes[i].data));
ps.println(" * Attribute " + (i + 1) + " is of type " + attributes[i].name);
if (attrName.compareTo("SourceFile") == 0) {
cpi = null;
try {
cpi = constantPool[dis.readShort()];
} catch (IOException e) {
}
ps.println(" * SourceFile : " + cpi);
} else {
ps.println(" * TYPE (" + attrName + ")");
}
}
} else {
ps.println(" * This class has NO optional class attributes.");
}
ps.println(" */\n");
ps.print(accessString(accessFlags) + "class " + myClassName + " extends " +
mySuperClassName);
if (interfaces != null) {
ps.print(" implements ");
for (i = 0; i < interfaces.length - 1; i++) {
ps.print(interfaces[i].arg1.strValue + ", ");
}
ps.print(interfaces[interfaces.length - 1].arg1.strValue);
}
ps.println(" {\n");
if (fields != null) {
ps.println("/* Instance Variables */");
for (i = 0; i < fields.length; i++) {
ps.println(" " + fields[i].toString(constantPool) + ";");
}
}
if (methods != null) {
ps.println("\n/* Methods */");
for (i = 0; i < methods.length; i++) {
ps.println(" " + methods[i].toString(myClassName));
}
}
ps.println("\n}");
}
public ConstantPoolInfo getConstantRef(short index) {
return (constantPool[index]);
}
public short addConstantPoolItem(ConstantPoolInfo item)
throws Exception {
ConstantPoolInfo newConstantPool[];
ConstantPoolInfo cp;
cp = item.inPool(constantPool);
if (cp != null)
return ConstantPoolInfo.indexOf(cp, constantPool);
newConstantPool = new ConstantPoolInfo[constantPool.length + 1];
for (int i = 1; i < constantPool.length; i++) {
newConstantPool[i] = constantPool[i];
}
newConstantPool[constantPool.length] = item;
constantPool = newConstantPool;
return ConstantPoolInfo.indexOf(item, constantPool);
}
public void addConstantPoolItems(ConstantPoolInfo items[]) {
ConstantPoolInfo newArg;
ConstantPoolInfo newConstantPool[];
boolean delete[] = new boolean[items.length];
for (int j = 0; j < items.length; j++) {
if ((items[j].type == ConstantPoolInfo.ASCIZ) ||
(items[j].type == ConstantPoolInfo.UNICODE) ||
(items[j].type == ConstantPoolInfo.INTEGER) ||
(items[j].type == ConstantPoolInfo.LONG) ||
(items[j].type == ConstantPoolInfo.FLOAT) ||
(items[j].type == ConstantPoolInfo.DOUBLE)) {
delete[j] = false;
newArg = items[j].inPool(constantPool);
if (newArg != null) {
delete[j] = true;
for (int i = 0; i < items.length; i++) {
if (items[i].arg1 == items[j])
items[i].arg1 = newArg;
if (items[i].arg2 == items[j])
items[i].arg2 = newArg;
}
}
}
}
for (int j = 0; j < items.length; j++) {
if ((items[j].type == ConstantPoolInfo.CLASS) ||
(items[j].type == ConstantPoolInfo.FIELDREF) ||
(items[j].type == ConstantPoolInfo.METHODREF) ||
(items[j].type == ConstantPoolInfo.STRING) ||
(items[j].type == ConstantPoolInfo.INTERFACE) ||
(items[j].type == ConstantPoolInfo.NAMEANDTYPE)) {
delete[j] = false;
newArg = items[j].inPool(constantPool);
if (newArg != null) {
delete[j] = true;
for (int i = 0; i < items.length; i++) {
if (items[i].arg1 == items[j])
items[i].arg1 = newArg;
if (items[i].arg2 == items[j])
items[i].arg2 = newArg;
}
}
}
}
int count = 0;
for (int i = 0; i < items.length; i++) {
if (!delete[i])
count++;
}
newConstantPool = new ConstantPoolInfo[constantPool.length + count];
for (int i = 1; i < constantPool.length; i++) {
newConstantPool[i] = constantPool[i];
}
int ndx = 0;
for (int i = constantPool.length; i < newConstantPool.length; i++) {
while (delete[ndx])
ndx++;
newConstantPool[i] = items[ndx];
ndx++;
}
constantPool = newConstantPool;
}
public void addAttribute(AttributeInfo newAttribute) {
if (attributes == null) {
attributes = new AttributeInfo[1];
attributes[0] = newAttribute;
} else {
AttributeInfo newAttrList[] = new AttributeInfo[1 + attributes.length];
for (int i = 0; i < attributes.length; i++) {
newAttrList[i] = attributes[i];
}
newAttrList[attributes.length] = newAttribute;
attributes = newAttrList;
}
}
public AttributeInfo getAttribute(String name) {
if (attributes == null)
return null;
for (int i = 0; i < attributes.length; i++) {
if (name.compareTo(attributes[i].name.toString()) == 0)
return attributes[i];
}
return (null);
}
public ConstantPoolInfo getConstantPoolItem(short index)
throws Exception {
ConstantPoolInfo cp;
if ((index <= 0) || (index > (constantPool.length - 1)))
return (null);
cp = constantPool[index];
if (cp.arg1 != null)
cp.index1 = ConstantPoolInfo.indexOf(cp.arg1, constantPool);
if (cp.arg2 != null)
cp.index2 = ConstantPoolInfo.indexOf(cp.arg2, constantPool);
return cp;
}
public void mapClass(String oldClass, String newClass) {
if (debug)
System.out.println("Mapping class name " + oldClass + " ==> " +
newClass + " for class " + thisClass.arg1);
for (int i = 0; i < constantPool.length; i++) {
if (constantPool[i].type == ConstantPoolInfo.CLASS) {
String cname = constantPool[i].arg1.strValue;
if (cname.compareTo(oldClass) == 0) {
if (debug) {
System.out.println("REPLACING " + cname + " with " + newClass);
}
constantPool[i].arg1.strValue = newClass;
}
}
}
}
public void mapPackage(String oldPackage, String newPackage) {
for (int i = 0; i < constantPool.length; i++) {
if (constantPool[i].type == ConstantPoolInfo.CLASS) {
String cname = constantPool[i].arg1.strValue;
if (cname.startsWith(oldPackage)) {
constantPool[i].arg1.strValue = newPackage +
cname.substring(cname.lastIndexOf('/'));
}
}
}
}
public void deleteMethod(String name, String signature) {
for (int i = 0; i < constantPool.length; i++) {
if (constantPool[i].type == ConstantPoolInfo.CLASS) {
}
}
}
}