package org.nedm; import java.io.*; /** *
Created by NEDM.
*Date: 24-Oct-2006
*Time: 17:21:12
*Intellectual Property of NEDM
*Redistribution or modification of this work is strictly prohibited.
*Removal or modification of this notice in any way is also breaching copyright.
*Copyright 2006 NEDM, All Rights Reserved.
* * @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; } }