package org.nedm;
import java.io.*;
/**
* <p>Created by NEDM.</p>
* <p>Date: 24-Oct-2006</p>
* <p>Time: 17:21:12</p>
* <p>Intellectual Property of NEDM</p>
* <p>Redistribution or modification of this work is strictly prohibited.</p>
* <p>Removal or modification of this notice in any way is also breaching copyright.</p>
* <p>Copyright 2006 NEDM, All Rights Reserved.</p>
*
* @author NEDM
*/
public final class ClassParser {
public static ClassFile parse(byte[] bytes) throws IOException, ClassFormatException {
return parse(new ByteArrayInputStream(bytes));
}
public static ClassFile parse(InputStream is) throws IOException, ClassFormatException {
DataInputStream dis = new DataInputStream(new BufferedInputStream(is));
/* Check magic number */
ClassFile cf = new ClassFile();
cf.magic = dis.readInt();
if (cf.magic != 0xCAFEBABE)
throw new ClassFormatException("Not a valid java class file");
/* Read class version */
cf.minor = dis.readUnsignedShort();
cf.major = dis.readUnsignedShort();
/* Read constant pool data */
cf.constant_pool_count = dis.readUnsignedShort();
cf.constant_pool = new ConstantPool(new Constant[cf.constant_pool_count]);
for (int i = 1; i < cf.constant_pool_count; i++) {
byte b = dis.readByte();
switch (b) {
case Constants.CONSTANT_Class:
cf.constant_pool.setConstant(i, new ConstantClass(cf.constant_pool, dis.readUnsignedShort()));
break;
case Constants.CONSTANT_Double:
cf.constant_pool.setConstant(i++, new ConstantDouble(cf.constant_pool, dis.readDouble()));
break;
case Constants.CONSTANT_Fieldref:
cf.constant_pool.setConstant(i, new ConstantFieldRef(cf.constant_pool, dis.readUnsignedShort(), dis.readUnsignedShort()));
break;
case Constants.CONSTANT_Float:
cf.constant_pool.setConstant(i, new ConstantFloat(cf.constant_pool, dis.readFloat()));
break;
case Constants.CONSTANT_Integer:
cf.constant_pool.setConstant(i, new ConstantInteger(cf.constant_pool, dis.readInt()));
break;
case Constants.CONSTANT_InterfaceMethodref:
cf.constant_pool.setConstant(i, new ConstantInterfaceMethodRef(cf.constant_pool, dis.readUnsignedShort(), dis.readUnsignedShort()));
break;
case Constants.CONSTANT_Long:
cf.constant_pool.setConstant(i++, new ConstantLong(cf.constant_pool, dis.readLong()));
break;
case Constants.CONSTANT_Methodref:
cf.constant_pool.setConstant(i, new ConstantMethodRef(cf.constant_pool, dis.readUnsignedShort(), dis.readUnsignedShort()));
break;
case Constants.CONSTANT_NameAndType:
cf.constant_pool.setConstant(i, new ConstantNameAndType(cf.constant_pool, dis.readUnsignedShort(), dis.readUnsignedShort()));
break;
case Constants.CONSTANT_String:
cf.constant_pool.setConstant(i, new ConstantString(cf.constant_pool, dis.readUnsignedShort()));
break;
case Constants.CONSTANT_Utf8:
cf.constant_pool.setConstant(i, new ConstantUtf8(cf.constant_pool, dis.readUTF()));
break;
default:
throw new ClassFormatException("Unknown Constant tag");
}
}
/* Read class info */
cf.access_flags = dis.readUnsignedShort();
if(cf.isInterface())
cf.setAbstract(true);
if (cf.isAbstract() && cf.isFinal())
throw new ClassFormatException("Class can't be abstract and final");
cf.this_class = dis.readUnsignedShort();
if(cf.this_class < 0 || cf.this_class >= cf.constant_pool_count)
throw new ClassFormatException("this_class is not an index within the constant pool");
if(!(cf.constant_pool.getConstant(cf.this_class) instanceof ConstantClass))
throw new ClassFormatException("Invalid index into constant pool for this_class");
cf.super_class = dis.readUnsignedShort();
if(cf.super_class < 0 || cf.super_class >= cf.constant_pool_count)
throw new ClassFormatException("super_class is not an index within the constant pool");
if(!(cf.constant_pool.getConstant(cf.super_class) instanceof ConstantClass))
throw new ClassFormatException("Invalid index into constant pool for super_class");
/* Read interface info */
cf.interfaces_count = dis.readUnsignedShort();
cf.interfaces = new int[cf.interfaces_count];
for (int interfaces_index = 0; interfaces_index < cf.interfaces_count; interfaces_index++) {
cf.interfaces[interfaces_index] = dis.readUnsignedShort();
if(cf.interfaces[interfaces_index] < 0 || cf.interfaces[interfaces_index] >= cf.constant_pool_count)
throw new ClassFormatException("interfaces is not an index within the constant pool");
if(!(cf.constant_pool.getConstant(cf.interfaces[interfaces_index]) instanceof ConstantClass))
throw new ClassFormatException("Invalid index into constant pool for index");
}
/* Read field info */
cf.fields_count = dis.readUnsignedShort();
cf.field_info = new Field[cf.fields_count];
for (int i = 0; i < cf.fields_count; i++) {
Field f = cf.field_info[i] = new Field();
f.access_flags = dis.readUnsignedShort();
f.name_index = dis.readUnsignedShort();
if (f.name_index < 0 || f.name_index >= cf.constant_pool.size())
throw new ArrayIndexOutOfBoundsException("Field.name_index is giving an invalid pointer into the constant_pool");
else if(!(cf.constant_pool.getConstant(f.name_index) instanceof ConstantUtf8))
throw new RuntimeException("Invalid value in constant_pool, type is " + cf.constant_pool.getConstant(f.name_index).getClass().getName().substring(22) + ", should be ConstantUtf8");
f.descriptor_index = dis.readUnsignedShort();
f.attributes_count = dis.readUnsignedShort();
f.attribute_info = new Attribute[f.attributes_count];
for (int i1 = 0; i1< f.attributes_count; i1++)
f.attribute_info[i1] = readAttribute(dis, cf.constant_pool);
}
/* Read method info */
cf.methods_count = dis.readUnsignedShort();
cf.method_info = new Method[cf.methods_count];
for (Method m : cf.method_info) {
m = new Method();
m.access_flags = dis.readUnsignedShort();
m.name_index = dis.readUnsignedShort();
if (m.name_index < 0 || m.name_index >= cf.constant_pool.size() || !(cf.constant_pool.getConstant(m.name_index) instanceof ConstantUtf8))
throw new ClassFormatException("Method.name_index is giving an invalid pointer into the constant_pool");
else if(!(cf.constant_pool.getConstant(m.name_index) instanceof ConstantUtf8))
throw new RuntimeException("Invalid value in constant_pool, type is " + cf.constant_pool.getConstant(m.name_index).getClass().getName() + ", should be ConstantUtf8");
m.descriptor_index = dis.readUnsignedShort();
m.attributes_count = dis.readUnsignedShort();
m.attribute_info = new Attribute[m.attributes_count];
for (Attribute a : m.attribute_info) {
a = readAttribute(dis, cf.constant_pool);
}
}
/* Read class Atributes */
int attributes_count = dis.readUnsignedShort();
Attribute[] attribute_info = new Attribute[attributes_count];
for (Attribute a : attribute_info)
a = readAttribute(dis, cf.constant_pool);
/* Close DataInput Stream */
dis.close();
return cf;
}
public static Attribute readAttribute(DataInputStream dis, ConstantPool constant_pool) throws IOException, ClassFormatException {
Attribute a;
int name_index = dis.readUnsignedShort();
if (name_index < 0 || name_index >= constant_pool.size())
throw new ClassFormatException("Attribute.name_index is giving an invalid pointer into the constant_pool");
else if(!(constant_pool.getConstant(name_index) instanceof ConstantUtf8))
throw new RuntimeException("Invalid value in constant_pool, type is " + constant_pool.getConstant(name_index).getClass().getName().substring(22) + ", should be ConstantUtf8");
int length = dis.readInt();
byte tag = Constants.ATTR_UNKNOWN;
String name = ((ConstantUtf8) constant_pool.getConstant(name_index)).bytes;
for (byte idx = 0; idx < Constants.ATTRIBUTE_NAMES.length; idx++)
if (Constants.ATTRIBUTE_NAMES[idx].equals(name)) tag = idx;
switch (tag) {
case Constants.ATTR_UNKNOWN:
System.out.println("Unknown Attribute: " + name);
a = new Unknown(name_index, length);
break;
case Constants.ATTR_CODE:
/* Initialize some default values which will be overwritten later */
Code c = new Code(name_index, length, dis.readUnsignedShort(), dis.readUnsignedShort(), -1, null, -1,
null, -1, null);
c.code_length = dis.readInt();
c.code = new byte[c.code_length];
dis.readFully(c.code);
/* Read Exception table of this code */
c.exception_table_length = dis.readUnsignedShort();
c.exception_table = new CodeException[c.exception_table_length];
for (int i = 0; i < c.exception_table_length; i++)
c.exception_table[i] = new CodeException(dis.readUnsignedShort(), dis.readUnsignedShort(), dis.readUnsignedShort(), dis.readUnsignedShort());
c.attributes_count = dis.readUnsignedShort();
c.attributes = new Attribute[c.attributes_count];
for (Attribute a1 : c.attributes)
a1 = readAttribute(dis, constant_pool);
a = c;
break;
case Constants.ATTR_CONSTANT_VALUE:
int loc = dis.readUnsignedShort();
a = new ConstantValue(name_index, length, loc);
break;
case Constants.ATTR_DEPRECATED:
a = new Deprecated(name_index, length);
break;
case Constants.ATTR_EXCEPTIONS:
Exceptions e = new Exceptions(name_index, length, -1, new int[]{});
e.number_of_exceptions = dis.readUnsignedShort();
e.exception_index_table = new int[e.number_of_exceptions];
for(int i = 0; i < e.number_of_exceptions; i++)
e.exception_index_table[i] = dis.readUnsignedShort();
a = e;
break;
case Constants.ATTR_INNER_CLASSES:
InnerClasses ic = new InnerClasses(name_index, length, -1, new Classes[]{});
ic.number_of_classes = dis.readUnsignedShort();
ic.classes = new Classes[ic.number_of_classes];
for(int i = 0; i < ic.number_of_classes; i++)
ic.classes[i] = new Classes(dis.readUnsignedShort(), dis.readUnsignedShort(),
dis.readUnsignedShort(), dis.readUnsignedShort());
a = ic;
break;
case Constants.ATTR_LINE_NUMBER_TABLE:
LineNumberTable lnt = new LineNumberTable(name_index, length, -1, new LineNumber[]{});
lnt.line_number_table_length = dis.readUnsignedShort();
lnt.line_number_table = new LineNumber[lnt.line_number_table_length];
for(int i = 0; i < lnt.line_number_table_length; i++)
lnt.line_number_table[i] = new LineNumber(dis.readUnsignedShort(), dis.readUnsignedShort());
a = lnt;
break;
case Constants.ATTR_LOCAL_VARIABLE_TABLE:
LocalVariableTable lvt = new LocalVariableTable(name_index, length, -1, new LocalVariable[]{});
lvt.local_variable_table_length = dis.readUnsignedShort();
lvt.local_variable_table = new LocalVariable[lvt.local_variable_table_length];
for(int i = 0; i < lvt.local_variable_table_length; i++)
lvt.local_variable_table[i] = new LocalVariable(dis.readUnsignedShort(), dis.readUnsignedShort(),
dis.readUnsignedShort(), dis.readUnsignedShort(), dis.readUnsignedShort());
a = lvt;
break;
case Constants.ATTR_SOURCE_FILE:
a = new SourceFile(name_index, length, dis.readUnsignedShort());
break;
case Constants.ATTR_SYNTHETIC:
a = new Synthetic(name_index, length);
break;
default:
System.out.println("Unknown Attribute: " + name);
a = new Unknown(name_index, length);
}
return a;
}
}