diff --git a/jode/jode/bytecode/AttributeInfo.java b/jode/jode/bytecode/AttributeInfo.java new file mode 100644 index 0000000..ecaab77 --- /dev/null +++ b/jode/jode/bytecode/AttributeInfo.java @@ -0,0 +1,84 @@ +/* jode.bytecode.AttributeInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.bytecode; +import jode.TabbedPrintWriter; +import java.io.*; +import java.lang.reflect.Modifier; + +public class AttributeInfo { + ClassInfo classinfo; + + String name; + byte[] data; + + public AttributeInfo() { + } + + public void read(ConstantPool constantPool, + DataInputStream input, int howMuch) throws IOException { + String attrName = constantPool.getUTF8(input.readUnsignedShort()); + int length = input.readInt(); + if ((howMuch & ClassInfo.ALL_ATTRIBUTES) != 0) { + name = attrName; + data = new byte[length]; + input.read(data); + } else + input.skip(length); + } + + public String getName() { + return name; + } + + public byte[] getContents() { + return data; + } + + static final char hex[] = { '0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f' }; + + public void dumpSource(TabbedPrintWriter writer) throws IOException{ + if (data != null) { + writer.println("/* Attribute "+name+" ["+data.length+"]"); + writer.tab(); + StringBuffer sb = new StringBuffer(); + for (int i=0; i< data.length; i++) { + byte b = data[i]; + int h = (b<0)?b+256:b; + writer.print(" " + hex[h/16] + hex[h%16]); + if (b >=32 && b < 127) { + sb.append((char)b); + } else { + sb.append("."); + } + if (i % 16 == 15) { + writer.println(" "+sb.toString()); + sb.setLength(0); + } + } + if ((data.length % 16) != 0) { + for (int i=data.length % 16; i<16; i++) + writer.print(" "); + writer.println(" "+sb.toString()); + } + writer.untab(); + writer.println("*/"); + } + } +} diff --git a/jode/jode/bytecode/BinaryInfo.java b/jode/jode/bytecode/BinaryInfo.java new file mode 100644 index 0000000..62f18b4 --- /dev/null +++ b/jode/jode/bytecode/BinaryInfo.java @@ -0,0 +1,69 @@ +/* jode.bytecode.BinaryInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ + +package jode.bytecode; +import java.io.*; + +/** + * + * @author Jochen Hoenicke + */ +public class BinaryInfo { + public static final int HIERARCHY = 0x01; + public static final int FIELDS = 0x02; + public static final int METHODS = 0x04; + public static final int CONSTANTS = 0x08; + public static final int ALL_ATTRIBUTES = 0x10; + public static final int FULLINFO = 0xff; + + private int status = 0; + + private AttributeInfo[] attributes; + + public AttributeInfo findAttribute(String name) { + for (int i=0; i< attributes.length; i++) + if (attributes[i].getName().equals(name)) + return attributes[i]; + return null; + } + + protected void skipAttributes(DataInputStream input) throws IOException { + int count = input.readUnsignedShort(); + for (int i=0; i< count; i++) { + input.readUnsignedShort(); // the name index + int length = input.readInt(); + input.skip(length); + } + } + + protected void readAttributes(ConstantPool constantPool, + DataInputStream input, + int howMuch) throws IOException { + if ((howMuch & ALL_ATTRIBUTES) != 0) { + int count = input.readUnsignedShort(); + attributes = new AttributeInfo[count]; + for (int i=0; i< count; i++) { + attributes[i] = new AttributeInfo(); + attributes[i].read(constantPool, input, howMuch); + } + } else + skipAttributes(input); + } +} + diff --git a/jode/jode/bytecode/ClassInfo.java b/jode/jode/bytecode/ClassInfo.java new file mode 100644 index 0000000..3a539df --- /dev/null +++ b/jode/jode/bytecode/ClassInfo.java @@ -0,0 +1,277 @@ +/* jode.bytecode.ClassInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.bytecode; +import jode.SearchPath; +import jode.MethodType; +import java.io.*; +import java.util.Hashtable; + +/** + * This class does represent a class similar to java.lang.Class. You + * can get the super class and the interfaces. + * + * The main difference to java.lang.Class is, that the objects are builded + * from a stream containing the .class file, and that it uses the + * jode.Type to represent types instead of Class itself. + * + * @author Jochen Hoenicke + */ +public class ClassInfo extends BinaryInfo { + private String name; + + private static SearchPath classpath; + private static Hashtable classes = new Hashtable(); // XXX - weak map + + private int status = 0; + + private ConstantPool constantPool; + private int modifiers = -1; + private ClassInfo superclass; + private ClassInfo[] interfaces; + private FieldInfo[] fields; + private MethodInfo[] methods; + private AttributeInfo[] attributes; + + public final static ClassInfo javaLangObject = + ClassInfo.forName("java.lang.Object"); + + public static void setClassPath(SearchPath path) { + classpath = path; + } + + + public static ClassInfo forName(String name) { + if (name == null) + return null; + name = name.replace('/', '.'); + ClassInfo clazz = (ClassInfo) classes.get(name); + if (clazz == null) { + clazz = new ClassInfo(name); + classes.put(name, clazz); + } + return clazz; + } + + public ClassInfo(String name) { + this.name = name; + } + + private void readHeader(DataInputStream input, int howMuch) + throws IOException { + if (input.readInt() != 0xcafebabe) + throw new ClassFormatException("Wrong magic"); + if (input.readUnsignedShort() > 3) + throw new ClassFormatException("Wrong minor"); + if (input.readUnsignedShort() != 45) + throw new ClassFormatException("Wrong major"); + } + + private ConstantPool readConstants(DataInputStream input, int howMuch) + throws IOException { + ConstantPool cpool = new ConstantPool(); + cpool.read(input); + return cpool; + } + + private void readNameAndSuper(ConstantPool cpool, + DataInputStream input, int howMuch) + throws IOException { + modifiers = input.readUnsignedShort(); + String name = cpool.getClassName(input.readUnsignedShort()); + if (!this.name.equals(name)) + new ClassFormatException("Class has wrong name: "+name); + superclass = ClassInfo.forName + (cpool.getClassName(input.readUnsignedShort())); + } + + private void readInterfaces(ConstantPool cpool, + DataInputStream input, int howMuch) + throws IOException { + int count = input.readUnsignedShort(); + interfaces = new ClassInfo[count]; + for (int i=0; i< count; i++) { + interfaces[i] = ClassInfo.forName + (cpool.getClassName(input.readUnsignedShort())); + } + } + + private void readFields(ConstantPool cpool, + DataInputStream input, int howMuch) + throws IOException { + if ((howMuch & FIELDS) != 0) { + int count = input.readUnsignedShort(); + fields = new FieldInfo[count]; + for (int i=0; i< count; i++) { + fields[i] = new FieldInfo(); + fields[i].read(cpool, input, howMuch); + } + } else { + int count = input.readUnsignedShort(); + fields = new FieldInfo[count]; + for (int i=0; i< count; i++) { + input.readUnsignedShort(); // modifier + input.readUnsignedShort(); // name + input.readUnsignedShort(); // type + skipAttributes(input); + } + } + } + + private void readMethods(ConstantPool cpool, + DataInputStream input, int howMuch) + throws IOException { + if ((howMuch & METHODS) != 0) { + int count = input.readUnsignedShort(); + methods = new MethodInfo[count]; + for (int i=0; i< count; i++) { + methods[i] = new MethodInfo(); + methods[i].read(cpool, input, howMuch); + } + } else { + int count = input.readUnsignedShort(); + fields = new FieldInfo[count]; + for (int i=0; i< count; i++) { + input.readUnsignedShort(); // modifier + input.readUnsignedShort(); // name + input.readUnsignedShort(); // type + skipAttributes(input); + } + } + } + + public void loadInfo(int howMuch) { + try { + DataInputStream input = + new DataInputStream(classpath.getFile(name.replace('.', '/') + + ".class")); + readHeader(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; + + } catch (IOException ex) { + String message = ex.getLocalizedMessage(); + if ((howMuch & ~(METHODS|HIERARCHY)) == 0) + System.err.println("Can't read class " + name + + ", types may be incorrect. (" + + ex.getClass().getName() + + (message != null ? ": " + message : "") + + ")"); + else + System.err.println("Can't read class " + name + "(" + + ex.getClass().getName() + + (message != null ? ": " + message : "") + + ")"); + + if (name.equals("java.lang.Object")) + superclass = null; + else + superclass = ClassInfo.forName("java.lang.Object"); + interfaces = new ClassInfo[0]; + status = FULLINFO; + } + } + + public ClassInfo getSuperclass() { + if ((status & HIERARCHY) == 0) + loadInfo(HIERARCHY); + return superclass; + } + + public ClassInfo[] getInterfaces() { + if ((status & HIERARCHY) == 0) + loadInfo(HIERARCHY); + return interfaces; + } + + public int getModifiers() { + if ((status & HIERARCHY) == 0) + loadInfo(HIERARCHY); + return modifiers; + } + + public boolean isInterface() { + return java.lang.reflect.Modifier.isInterface(getModifiers()); + } + + public String toString() { + return name; + } + + public String getName() { + return name; + } + + public boolean superClassOf(ClassInfo son) { + while (son != this && son != null) { + son = son.getSuperclass(); + } + return son == this; + } + + public boolean implementedBy(ClassInfo clazz) { + while (clazz != this && clazz != null) { + ClassInfo[] ifaces = clazz.getInterfaces(); + for (int i=0; i< ifaces.length; i++) { + if (implementedBy(ifaces[i])) + return true; + } + clazz = clazz.getSuperclass(); + } + return clazz == this; + } + + public ConstantPool getConstantPool() { + if ((status & CONSTANTS) == 0) + 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; + } +} diff --git a/jode/jode/bytecode/CodeInfo.java b/jode/jode/bytecode/CodeInfo.java new file mode 100644 index 0000000..8f022ef --- /dev/null +++ b/jode/jode/bytecode/CodeInfo.java @@ -0,0 +1,62 @@ +/* jode.bytecode.CodeInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.bytecode; +import java.io.*; +import java.lang.reflect.Modifier; + +public class CodeInfo extends BinaryInfo { + + int maxStack, maxLocals; + byte[] code; + int[] exceptionTable; + + public int getMaxStack() { + return maxStack; + } + + public int getMaxLocals() { + return maxLocals; + } + + public byte[] getCode() { + return code; + } + + public int[] getExceptionHandlers() { + return exceptionTable; + } + + public void read(ConstantPool constantPool, + DataInputStream input) throws IOException { + maxStack = input.readUnsignedShort(); + maxLocals = input.readUnsignedShort(); + int codeLength = input.readInt(); + code = new byte[codeLength]; + input.read(code); + int count = 4*input.readUnsignedShort(); + exceptionTable = new int[count]; + for (int i = 0; i< count; i+=4) { + exceptionTable[i+0] = input.readUnsignedShort(); + exceptionTable[i+1] = input.readUnsignedShort(); + exceptionTable[i+2] = input.readUnsignedShort(); + exceptionTable[i+3] = input.readUnsignedShort(); + } + readAttributes(constantPool, input, FULLINFO); + } +} diff --git a/jode/jode/bytecode/FieldInfo.java b/jode/jode/bytecode/FieldInfo.java new file mode 100644 index 0000000..3489800 --- /dev/null +++ b/jode/jode/bytecode/FieldInfo.java @@ -0,0 +1,54 @@ +/* jode.bytecode.FieldInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.bytecode; +import jode.Type; +import java.io.*; +import java.lang.reflect.Modifier; + +public class FieldInfo extends BinaryInfo { + int modifier; + String name; + Type type; + + public String getName() { + return name; + } + + public Type getType() { + return type; + } + + public int getModifiers() { + return modifier; + } + + public void read(ConstantPool constantPool, + DataInputStream input, int howMuch) throws IOException { + modifier = input.readUnsignedShort(); + name = constantPool.getUTF8(input.readUnsignedShort()); + type = Type.tType(constantPool.getUTF8(input.readUnsignedShort())); + + readAttributes(constantPool, input, howMuch); + } + + public String toString() { + return "Field "+Modifier.toString(modifier)+" "+ + type.toString()+" "+name; + } +} diff --git a/jode/jode/bytecode/MethodInfo.java b/jode/jode/bytecode/MethodInfo.java new file mode 100644 index 0000000..4eaa5af --- /dev/null +++ b/jode/jode/bytecode/MethodInfo.java @@ -0,0 +1,55 @@ +/* jode.bytecode.MethodInfo Copyright (C) 1997-1998 Jochen Hoenicke. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id$ + */ +package jode.bytecode; +import jode.MethodType; +import java.io.*; +import java.lang.reflect.Modifier; + +public class MethodInfo extends BinaryInfo { + + int modifier; + String name; + MethodType type; + + public String getName() { + return name; + } + + public MethodType getType() { + return type; + } + + public int getModifiers() { + return modifier; + } + + public void read(ConstantPool constantPool, + DataInputStream input, int howMuch) throws IOException { + modifier = input.readUnsignedShort(); + name = constantPool.getUTF8(input.readUnsignedShort()); + type = new MethodType(Modifier.isStatic(modifier), + constantPool.getUTF8(input.readUnsignedShort())); + readAttributes(constantPool, input, howMuch); + } + + public String toString() { + return "Method "+Modifier.toString(modifier)+" "+ + type.toString()+" "+name; + } +}