attribute handling.

setXXX methods
write methods


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@619 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 7a326a40c1
commit 4ba3551e10
  1. 456
      jode/jode/bytecode/ClassInfo.java

@ -18,8 +18,8 @@
*/ */
package jode.bytecode; package jode.bytecode;
import jode.Decompiler;
import jode.type.Type; import jode.type.Type;
import jode.type.MethodType;
import java.io.*; import java.io.*;
import java.util.*; import java.util.*;
///#ifdef JDK12 ///#ifdef JDK12
@ -53,12 +53,13 @@ public class ClassInfo extends BinaryInfo {
private int status = 0; private int status = 0;
private ConstantPool constantPool;
private int modifiers = -1; private int modifiers = -1;
private ClassInfo superclass; private ClassInfo superclass;
private ClassInfo[] interfaces; private ClassInfo[] interfaces;
private FieldInfo[] fields; private FieldInfo[] fields;
private MethodInfo[] methods; private MethodInfo[] methods;
private InnerClassInfo[] innerClasses;
private String sourceFile;
public final static ClassInfo javaLangObject = forName("java.lang.Object"); public final static ClassInfo javaLangObject = forName("java.lang.Object");
@ -86,7 +87,7 @@ public class ClassInfo extends BinaryInfo {
ci.fields = null; ci.fields = null;
ci.interfaces = null; ci.interfaces = null;
ci.methods = null; ci.methods = null;
ci.attributes = null; ci.unknownAttributes = null;
} }
} }
@ -194,7 +195,7 @@ public class ClassInfo extends BinaryInfo {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
fields = new FieldInfo[count]; fields = new FieldInfo[count];
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
fields[i] = new FieldInfo(); fields[i] = new FieldInfo(this);
fields[i].read(cpool, input, howMuch); fields[i].read(cpool, input, howMuch);
} }
} else { } else {
@ -215,7 +216,7 @@ public class ClassInfo extends BinaryInfo {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
methods = new MethodInfo[count]; methods = new MethodInfo[count];
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
methods[i] = new MethodInfo(); methods[i] = new MethodInfo(this);
methods[i].read(cpool, input, howMuch); methods[i].read(cpool, input, howMuch);
} }
} else { } else {
@ -229,69 +230,256 @@ public class ClassInfo extends BinaryInfo {
} }
} }
public void loadInfoReflection(Class clazz, int howMuch) { protected void readAttribute(String name, int length,
try { ConstantPool cp,
modifiers = clazz.getModifiers(); DataInputStream input,
if ((howMuch & HIERARCHY) != 0) { int howMuch) throws IOException {
if (clazz.getSuperclass() == null) if (name.equals("SourceFile")) {
superclass = null; if (length != 2)
else throw new ClassFormatException("SourceFile attribute"
superclass = ClassInfo.forName + " has wrong length");
(clazz.getSuperclass().getName()); sourceFile = cp.getUTF8(input.readUnsignedShort());
Class[] ifaces = clazz.getInterfaces(); } else if (name.equals("InnerClasses")) {
interfaces = new ClassInfo[ifaces.length]; int count = input.readUnsignedShort();
for (int i=0; i<ifaces.length; i++) innerClasses = new InnerClassInfo[count];
interfaces[i] = ClassInfo.forName(ifaces[i].getName()); for (int i=0; i< count; i++) {
status |= HIERARCHY; int innerIndex = input.readUnsignedShort();
int outerIndex = input.readUnsignedShort();
int nameIndex = input.readUnsignedShort();
String inner = cp.getClassName(innerIndex);
String outer =
outerIndex != 0 ? cp.getClassName(outerIndex) : null;
String innername =
nameIndex != 0 ? cp.getUTF8(nameIndex) : null;
int access = input.readUnsignedShort();
innerClasses[i] = new InnerClassInfo
(inner, outer, innername, access);
} }
if ((howMuch & FIELDS) != 0) { if (length != 2 + 8 * count)
Field[] fs; throw new ClassFormatException
try { ("InnerClasses attribute has wrong length");
fs = clazz.getDeclaredFields(); } else
} catch (SecurityException ex) { super.readAttribute(name, length, cp, input, howMuch);
fs = clazz.getFields(); }
jode.Decompiler.err.println
("Could only get public fields of class " public void read(DataInputStream input, int howMuch) throws IOException {
+ name + "."); /* header */
} if (input.readInt() != 0xcafebabe)
fields = new FieldInfo[fs.length]; throw new ClassFormatException("Wrong magic");
for (int i = fs.length; --i >= 0; ) { if (input.readUnsignedShort() > 3)
Type type = Type.tType(fs[i].getType()); throw new ClassFormatException("Wrong minor");
fields[i] = new FieldInfo if (input.readUnsignedShort() != 45)
(fs[i].getName(), type, fs[i].getModifiers()); throw new ClassFormatException("Wrong major");
}
/* constant pool */
ConstantPool cpool = new ConstantPool();
cpool.read(input);
/* always read modifiers, name, super, ifaces */
{
status |= HIERARCHY;
modifiers = input.readUnsignedShort();
String className = cpool.getClassName(input.readUnsignedShort());
if (!name.equals(className))
throw new ClassFormatException("wrong name " + className);
String superName = cpool.getClassName(input.readUnsignedShort());
superclass = superName != null ? ClassInfo.forName(superName) : null;
int count = input.readUnsignedShort();
interfaces = new ClassInfo[count];
for (int i=0; i< count; i++) {
interfaces[i] = ClassInfo.forName
(cpool.getClassName(input.readUnsignedShort()));
} }
if ((howMuch & METHODS) != 0) { }
Method[] ms;
try { /* fields */
ms = clazz.getDeclaredMethods(); if ((howMuch & FIELDS) != 0) {
} catch (SecurityException ex) { int count = input.readUnsignedShort();
ms = clazz.getMethods(); fields = new FieldInfo[count];
jode.Decompiler.err.println for (int i=0; i< count; i++) {
("Could only get public methods of class " fields[i] = new FieldInfo(this);
+ name + "."); fields[i].read(cpool, input, howMuch);
} }
methods = new MethodInfo[ms.length]; } else {
for (int i = ms.length; --i >= 0; ) { byte[] skipBuf = new byte[6];
MethodType type = Type.tMethod int count = input.readUnsignedShort();
(ms[i].getParameterTypes(), ms[i].getReturnType()); for (int i=0; i< count; i++) {
methods[i] = new MethodInfo input.readFully(skipBuf); // modifier, name, type
(ms[i].getName(), type, ms[i].getModifiers()); skipAttributes(input);
} }
}
/* methods */
if ((howMuch & METHODS) != 0) {
int count = input.readUnsignedShort();
methods = new MethodInfo[count];
for (int i=0; i< count; i++) {
methods[i] = new MethodInfo(this);
methods[i].read(cpool, input, howMuch);
}
} else {
byte[] skipBuf = new byte[6];
int count = input.readUnsignedShort();
for (int i=0; i< count; i++) {
input.readFully(skipBuf); // modifier, name, type
skipAttributes(input);
}
}
/* attributes */
readAttributes(cpool, input, howMuch);
}
public void reserveSmallConstants(GrowableConstantPool gcp) {
for (int i=0; i < fields.length; i++)
fields[i].reserveSmallConstants(gcp);
for (int i=0; i < methods.length; i++)
methods[i].reserveSmallConstants(gcp);
}
public void prepareWriting(GrowableConstantPool gcp) {
gcp.putClassName(name);
gcp.putClassName(superclass.getName());
for (int i=0; i < interfaces.length; i++)
gcp.putClassName(interfaces[i].getName());
for (int i=0; i < fields.length; i++)
fields[i].prepareWriting(gcp);
for (int i=0; i < methods.length; i++)
methods[i].prepareWriting(gcp);
if (sourceFile != null) {
gcp.putUTF8("SourceFile");
gcp.putUTF8(sourceFile);
}
if (innerClasses != null) {
gcp.putUTF8("InnerClasses");
int count = innerClasses.length;
for (int i=0; i< count; i++) {
gcp.putClassName(innerClasses[i].inner);
if (innerClasses[i].outer != null)
gcp.putClassName(innerClasses[i].outer);
if (innerClasses[i].name != null)
gcp.putUTF8(innerClasses[i].name);
} }
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY)) != 0) { }
jode.Decompiler.err.println prepareAttributes(gcp);
("Can't find class " + name }
+ " in classpath, and couldn't load everything"
+ " from reflection."); protected int getKnownAttributeCount() {
status |= howMuch; int count = 0;
if (sourceFile != null)
count++;
if (innerClasses != null)
count++;
return count;
}
public void writeKnownAttributes(GrowableConstantPool gcp,
DataOutputStream output)
throws IOException {
if (sourceFile != null) {
output.writeShort(gcp.putUTF8("SourceFile"));
output.writeInt(2);
output.writeShort(gcp.putUTF8(sourceFile));
}
if (innerClasses != null) {
output.writeShort(gcp.putUTF8("InnerClasses"));
int count = innerClasses.length;
output.writeInt(2 + count * 8);
output.writeShort(count);
for (int i=0; i< count; i++) {
output.writeShort(gcp.putClassName(innerClasses[i].inner));
output.writeShort(innerClasses[i].outer != null ?
gcp.putClassName(innerClasses[i].outer) : 0);
output.writeShort(innerClasses[i].name != null ?
gcp.putUTF8(innerClasses[i].name) : 0);
output.writeShort(innerClasses[i].modifiers);
} }
}
}
public void write(DataOutputStream out) throws IOException {
GrowableConstantPool gcp = new GrowableConstantPool();
reserveSmallConstants(gcp);
prepareWriting(gcp);
out.writeInt(0xcafebabe);
out.writeShort(3);
out.writeShort(45);
gcp.write(out);
out.writeShort(modifiers);
out.writeShort(gcp.putClassName(name));
out.writeShort(gcp.putClassName(superclass.getName()));
out.writeShort(interfaces.length);
for (int i=0; i < interfaces.length; i++)
out.writeShort(gcp.putClassName(interfaces[i].getName()));
out.writeShort(fields.length);
for (int i=0; i < fields.length; i++)
fields[i].write(gcp, out);
} catch (SecurityException ex) { out.writeShort(methods.length);
jode.Decompiler.err.println for (int i=0; i < methods.length; i++)
(ex+" while collecting info about class " + name + "."); methods[i].write(gcp, out);
jode.Decompiler.err.println("Bad things may happen?");
writeAttributes(gcp, out);
}
public void loadInfoReflection(Class clazz, int howMuch)
throws SecurityException {
if ((howMuch & HIERARCHY) != 0) {
modifiers = clazz.getModifiers();
if (clazz.getSuperclass() == null)
superclass = null;
else
superclass = ClassInfo.forName
(clazz.getSuperclass().getName());
Class[] ifaces = clazz.getInterfaces();
interfaces = new ClassInfo[ifaces.length];
for (int i=0; i<ifaces.length; i++)
interfaces[i] = ClassInfo.forName(ifaces[i].getName());
status |= HIERARCHY;
}
if ((howMuch & FIELDS) != 0 && fields == null) {
Field[] fs;
try {
fs = clazz.getDeclaredFields();
} catch (SecurityException ex) {
fs = clazz.getFields();
Decompiler.err.println
("Could only get public fields of class "
+ name + ".");
}
fields = new FieldInfo[fs.length];
for (int i = fs.length; --i >= 0; ) {
String type = Type.getSignature(fs[i].getType());
fields[i] = new FieldInfo
(this, fs[i].getName(), type, fs[i].getModifiers());
}
}
if ((howMuch & METHODS) != 0 && methods == null) {
Method[] ms;
try {
ms = clazz.getDeclaredMethods();
} catch (SecurityException ex) {
ms = clazz.getMethods();
Decompiler.err.println
("Could only get public methods of class "
+ name + ".");
}
methods = new MethodInfo[ms.length];
for (int i = ms.length; --i >= 0; ) {
String type = Type.getSignature
(ms[i].getParameterTypes(), ms[i].getReturnType());
methods[i] = new MethodInfo
(this, ms[i].getName(), type, ms[i].getModifiers());
}
} }
status |= howMuch;
} }
public void loadInfo(int howMuch) { public void loadInfo(int howMuch) {
@ -299,22 +487,17 @@ public class ClassInfo extends BinaryInfo {
DataInputStream input = DataInputStream input =
new DataInputStream(classpath.getFile(name.replace('.', '/') new DataInputStream(classpath.getFile(name.replace('.', '/')
+ ".class")); + ".class"));
readHeader(input, howMuch); read(input, howMuch);
ConstantPool cpool = readConstants(input, howMuch);
if ((howMuch & CONSTANTS) != 0)
this.constantPool = cpool;
readNameAndSuper(cpool, input, howMuch);
readInterfaces(cpool, input, howMuch);
if ((howMuch & HIERARCHY) != 0)
status |= HIERARCHY;
readFields(cpool, input, howMuch);
readMethods(cpool, input, howMuch);
readAttributes(cpool, input, howMuch);
status |= howMuch; status |= howMuch;
} catch (IOException ex) { } catch (IOException ex) {
String message = ex.getMessage();
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY)) != 0) {
Decompiler.err.println
("Can't read class " + name + ".");
ex.printStackTrace(Decompiler.err);
throw new NoClassDefFoundError(name);
}
// Try getting the info through the reflection interface // Try getting the info through the reflection interface
// instead. // instead.
Class clazz = null; Class clazz = null;
@ -323,33 +506,40 @@ public class ClassInfo extends BinaryInfo {
} catch (ClassNotFoundException ex2) { } catch (ClassNotFoundException ex2) {
} catch (NoClassDefFoundError ex2) { } catch (NoClassDefFoundError ex2) {
} }
if (clazz != null) try {
loadInfoReflection(clazz, howMuch); loadInfoReflection(clazz, howMuch);
else { return;
// Nothing helped, ``guess'' the hierarchie } catch (SecurityException ex2) {
String message = ex.getMessage(); Decompiler.err.println
if ((howMuch & ~(METHODS|HIERARCHY)) == 0) { (ex2+" while collecting info about class " + name + ".");
jode.Decompiler.err.println }
("Can't read class " + name + ", types may be incorrect. ("
+ ex.getClass().getName()
+ (message != null ? ": " + message : "") + ")");
} else
jode.Decompiler.err.println
("Can't read class " + name
+ " (" + ex.getClass().getName()
+ (message != null ? ": " + message : "") + ")");
// Give a warning and ``guess'' the hierarchie, methods etc.
Decompiler.err.println
("Can't read class " + name + ", types may be incorrect. ("
+ ex.getClass().getName()
+ (message != null ? ": " + message : "") + ")");
if ((howMuch & HIERARCHY) != 0) {
modifiers = Modifier.PUBLIC;
if (name.equals("java.lang.Object")) if (name.equals("java.lang.Object"))
superclass = null; superclass = null;
else else
superclass = ClassInfo.forName("java.lang.Object"); superclass = ClassInfo.forName("java.lang.Object");
interfaces = new ClassInfo[0]; interfaces = new ClassInfo[0];
modifiers = Modifier.PUBLIC;
status = FULLINFO;
} }
if ((howMuch & METHODS) != 0)
methods = new MethodInfo[0];
if ((howMuch & FIELDS) != 0)
fields = new FieldInfo[0];
status |= howMuch;
} }
} }
public String getName() {
return name;
}
public ClassInfo getSuperclass() { public ClassInfo getSuperclass() {
if ((status & HIERARCHY) == 0) if ((status & HIERARCHY) == 0)
loadInfo(HIERARCHY); loadInfo(HIERARCHY);
@ -372,12 +562,60 @@ public class ClassInfo extends BinaryInfo {
return Modifier.isInterface(getModifiers()); return Modifier.isInterface(getModifiers());
} }
public String toString() { public FieldInfo findField(String name, String typeSig) {
return name; if ((status & FIELDS) == 0)
loadInfo(FIELDS);
for (int i=0; i< methods.length; i++)
if (fields[i].getName().equals(name)
&& fields[i].getType().equals(typeSig))
return fields[i];
return null;
} }
public String getName() { public MethodInfo findMethod(String name, String typeSig) {
return name; if ((status & METHODS) == 0)
loadInfo(METHODS);
for (int i=0; i< methods.length; i++)
if (methods[i].getName().equals(name)
&& methods[i].getType().equals(typeSig))
return methods[i];
return null;
}
public MethodInfo[] getMethods() {
if ((status & METHODS) == 0)
loadInfo(METHODS);
return methods;
}
public FieldInfo[] getFields() {
if ((status & FIELDS) == 0)
loadInfo(FIELDS);
return fields;
}
public void setName(String newName) {
name = newName;
}
public void setSuperclass(ClassInfo newSuper) {
superclass = newSuper;
}
public void setInterfaces(ClassInfo[] newIfaces) {
interfaces = newIfaces;
}
public void setModifiers(int newModifiers) {
modifiers = newModifiers;
}
public void setMethods(MethodInfo[] mi) {
methods = mi;
}
public void setFields(FieldInfo[] fi) {
fields = fi;
} }
public boolean superClassOf(ClassInfo son) { public boolean superClassOf(ClassInfo son) {
@ -399,31 +637,7 @@ public class ClassInfo extends BinaryInfo {
return clazz == this; return clazz == this;
} }
public ConstantPool getConstantPool() { public String toString() {
if ((status & CONSTANTS) == 0) return name;
loadInfo(CONSTANTS);
return constantPool;
}
public MethodInfo findMethod(String name, MethodType type) {
if ((status & METHODS) == 0)
loadInfo(METHODS);
for (int i=0; i< methods.length; i++)
if (methods[i].getName().equals(name)
&& methods[i].getType().equals(type))
return methods[i];
return null;
}
public MethodInfo[] getMethods() {
if ((status & METHODS) == 0)
loadInfo(METHODS);
return methods;
}
public FieldInfo[] getFields() {
if ((status & FIELDS) == 0)
loadInfo(FIELDS);
return fields;
} }
} }

Loading…
Cancel
Save