package com.coderising.jvm.loader;
import com.coderising.jvm.attr.CodeAttr;
import com.coderising.jvm.attr.LineNumberTable;
import com.coderising.jvm.attr.LocalVariableTable;
import com.coderising.jvm.clz.AccessFlag;
import com.coderising.jvm.clz.ClassFile;
import com.coderising.jvm.clz.ClassIndex;
import com.coderising.jvm.constant.ClassInfo;
import com.coderising.jvm.constant.ConstantPool;
import com.coderising.jvm.constant.FieldRefInfo;
import com.coderising.jvm.constant.MethodRefInfo;
import com.coderising.jvm.constant.NameAndTypeInfo;
import com.coderising.jvm.constant.NullConstantInfo;
import com.coderising.jvm.constant.StringInfo;
import com.coderising.jvm.constant.UTF8Info;
import com.coderising.jvm.field.Field;
import com.coderising.jvm.method.Method;
import com.coderising.jvm.util.Util;
import com.sun.org.apache.bcel.internal.classfile.LineNumber;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ByteCodeIterator iter=new ByteCodeIterator(codes);
String magicNumber=iter.nextU4ToHexString();
if (!magicNumber.equals("cafebabe")) {
return null;
}
ClassFile classFile=new ClassFile();
classFile.setMinorVersion(iter.nextU2ToInt());
classFile.setMajorVersion(iter.nextU2ToInt());
ConstantPool pool=parseConstantPool(iter);
classFile.setConstPool(pool);
classFile.setAccessFlag(parseAccessFlag(iter));
classFile.setClassIndex(parseClassInfex(iter));
parseInterfaces(iter);
int fieldCount=iter.nextU2ToInt();
for (int i = 0; i <fieldCount ; i++) {
classFile.addField(parseField(iter,pool));
}
int methodCount=iter.nextU2ToInt();
for (int i = 0; i < methodCount; i++) {
classFile.addMethod(parseMethod(iter, classFile));
}
return classFile;
}
private Method parseMethod(ByteCodeIterator iter,ClassFile clzFile) {
int accessFlag=iter.nextU2ToInt();
int nameIndex=iter.nextU2ToInt();
int descriptorIndex=iter.nextU2ToInt();
Method method= new Method(clzFile, accessFlag, nameIndex, descriptorIndex);
int attrCount=iter.nextU2ToInt();
int attrNameIndex=iter.nextU2ToInt();
int attrLen=iter.nextU4ToInt();
int maxStack=iter.nextU2ToInt();
int maxLocals=iter.nextU2ToInt();
int codeLen=iter.nextU4ToInt();
byte[] codes=iter.getByte(codeLen);
String code=Util.byteToHexString(codes);
CodeAttr codeAttr=new CodeAttr(attrNameIndex, attrLen, maxStack, maxLocals, codeLen, code);
int exceptionLength=iter.nextU2ToInt();
int count=iter.nextU2ToInt();
for (int i = 0; i < count; i++) {
int attrNameIndex1=iter.nextU2ToInt();
UTF8Info utf8Info=(UTF8Info) clzFile.getConstantPool().getConstantInfo(attrNameIndex1);
String attrName=utf8Info.getValue();
if (attrName.equals("LineNumberTable")) {
int attrLen1=iter.nextU4ToInt();
LineNumberTable lnTable=new LineNumberTable(attrNameIndex1, attrLen1);
lnTable.parse(iter);
}
else if (attrName.equals("LocalVariableTable")) {
int attrLen1=iter.nextU4ToInt();
LocalVariableTable lvTable=new LocalVariableTable(attrNameIndex1, attrLen1);
lvTable.parse(iter);
}
else {
throw new RuntimeException();
}
}
method.setCodeAttr(codeAttr);
return method;
}
private Field parseField(ByteCodeIterator iter,ConstantPool pool) {
int accessFlag=iter.nextU2ToInt();
int nameIndex=iter.nextU2ToInt();
int descriptorIndex=iter.nextU2ToInt();
Field field=new Field(accessFlag, nameIndex, descriptorIndex, pool);
iter.nextU2ToInt();
return field;
}
private void parseInterfaces(ByteCodeIterator iter) {
// TODO Auto-generated method stub
int interfaceCount = iter.nextU2ToInt();
System.out.println("interfaceCount:" + interfaceCount);
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
return new AccessFlag(iter.nextU2ToInt());
}
private ClassIndex parseClassInfex(ByteCodeIterator iter) {
ClassIndex classIndex=new ClassIndex();
classIndex.setThisClassIndex(iter.nextU2ToInt());
classIndex.setSuperClassIndex(iter.nextU2ToInt());
return classIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
int constPoolCount=iter.nextU2ToInt();
ConstantPool pool=new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
for (int i = 1; i <= constPoolCount-1; i++) {
int tag=iter.next();
if (tag==1) {
//UTF8Info
UTF8Info utf8Info=new UTF8Info(pool);
int length=iter.nextU2ToInt();
utf8Info.setLength(length);
String value=Util.byteToString(iter.getByte(length));
utf8Info.setValue(value);
pool.addConstantInfo(utf8Info);
}
else if (tag==7) {
//ClassInfo
ClassInfo classInfo=new ClassInfo(pool);
int utf8Index=iter.nextU2ToInt();
classInfo.setUtf8Index(utf8Index);
pool.addConstantInfo(classInfo);
}
else if (tag==8) {
//StringInfo
StringInfo stringInfo=new StringInfo(pool);
int index=iter.nextU2ToInt();
stringInfo.setIndex(index);
pool.addConstantInfo(stringInfo);
}
else if (tag==9) {
//FieldRefInfo
FieldRefInfo fieldRefInfo=new FieldRefInfo(pool);
int classInfoIndex=iter.nextU2ToInt();
int nameAndTypeIndex=iter.nextU2ToInt();
fieldRefInfo.setClassInfoIndex(classInfoIndex);
fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex);
pool.addConstantInfo(fieldRefInfo);
}
else if (tag==10) {
//MethodRefInfo
MethodRefInfo methodRefInfo=new MethodRefInfo(pool);
int classInfoIndex=iter.nextU2ToInt();
int nameAndTypeIndex=iter.nextU2ToInt();
methodRefInfo.setClassInfoIndex(classInfoIndex);
methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex);
pool.addConstantInfo(methodRefInfo);
}
else if (tag==12) {
//NameAndTypeInfo
NameAndTypeInfo nameAndTypeInfo=new NameAndTypeInfo(pool);
int index1=iter.nextU2ToInt();
int index2=iter.nextU2ToInt();
nameAndTypeInfo.setIndex1(index1);
nameAndTypeInfo.setIndex2(index2);
pool.addConstantInfo(nameAndTypeInfo);
}
else {
new RuntimeException("缺少tag为"+tag+"的常量");
}
}
return pool;
}
}