package com.coderising.jvm.loader;
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.ConstantInfo;
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;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ByteCodeIterator iter = new ByteCodeIterator(codes);
ClassFile clzFile = new ClassFile();
String magicNum = iter.getBytesAsHexString(4);
if(!"cafebabe".equals(magicNum)){
throw new RuntimeException("Magic Number validation failure, this may not be a java class file.");
}
int minVer = iter.nextU2AsInt();
int majVer = iter.nextU2AsInt();
System.out.println("magicNum="+magicNum+",minVer="+minVer+",majVer="+majVer);
clzFile.setMajorVersion(majVer);
clzFile.setMinorVersion(minVer);
ConstantPool pool = parseConstantPool(iter);
clzFile.setConstPool(pool);
AccessFlag accFlag = parseAccessFlag(iter);
clzFile.setAccessFlag(accFlag);
ClassIndex clsIdx = parseClassIndex(iter);
clzFile.setClassIndex(clsIdx);
parseInterfaces(iter,pool,clzFile);
parseFields(iter, pool, clzFile);
parseMethods(iter, pool, clzFile);
return clzFile;
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
AccessFlag af = new AccessFlag(iter.nextU2AsInt());
return af;
}
private ClassIndex parseClassIndex(ByteCodeIterator iter) {
ClassIndex ci = new ClassIndex();
ci.setThisClassIndex(iter.nextU2AsInt());
ci.setSuperClassIndex(iter.nextU2AsInt());
return ci;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
ConstantPool cp = new ConstantPool();
cp.addConstantInfo(new NullConstantInfo());
int cpLen = iter.nextU2AsInt();
for(int i=0;i<cpLen-1;i++){
int typeFlag = iter.nextU1AsInt();
switch(typeFlag){
case ConstantInfo.CLASS_INFO: //class info
ClassInfo cf = new ClassInfo(cp);
cf.setUtf8Index(iter.nextU2AsInt());
cp.addConstantInfo(cf);
break;
case ConstantInfo.UTF8_INFO: //UTF8 info
UTF8Info ui = new UTF8Info(cp);
ui.setLength(iter.nextU2AsInt());
ui.setValue(iter.getBytesAsString(ui.getLength()));
cp.addConstantInfo(ui);
break;
case ConstantInfo.STRING_INFO:
StringInfo ci = new StringInfo(cp);
ci.setIndex(iter.nextU2AsInt());
cp.addConstantInfo(ci);
break;
case ConstantInfo.FIELD_INFO:
FieldRefInfo fri = new FieldRefInfo(cp);
fri.setClassInfoIndex(iter.nextU2AsInt());
fri.setNameAndTypeIndex(iter.nextU2AsInt());
cp.addConstantInfo(fri);
break;
case ConstantInfo.METHOD_INFO:
MethodRefInfo mri = new MethodRefInfo(cp);
mri.setClassInfoIndex(iter.nextU2AsInt());
mri.setNameAndTypeIndex(iter.nextU2AsInt());
cp.addConstantInfo(mri);
break;
case ConstantInfo.NAME_AND_TYPE_INFO:
NameAndTypeInfo nti = new NameAndTypeInfo(cp);
nti.setIndex1(iter.nextU2AsInt());
nti.setIndex2(iter.nextU2AsInt());
cp.addConstantInfo(nti);
break;
default : throw new RuntimeException("Parse exception:"+typeFlag);
}
}
return cp;
}
private void parseInterfaces(ByteCodeIterator iter, ConstantPool pool, ClassFile clz){
int interfaceCount = iter.nextU2AsInt();
System.out.println("Total number of interface="+interfaceCount);
for(int i=0;i<interfaceCount;i++){
System.out.println("Parse Interface="+iter.nextU2AsInt());
}
}
private void parseFields(ByteCodeIterator iter, ConstantPool pool, ClassFile clz){
int fieldCount = iter.nextU2AsInt();
System.out.println("Total number of fields="+fieldCount);
for(int i=0;i<fieldCount;i++){
Field field = Field.parse(pool, iter);
clz.addField(field);
}
}
private void parseMethods(ByteCodeIterator iter, ConstantPool pool, ClassFile clz){
int methodCount = iter.nextU2AsInt();
System.out.println("Total number of methods="+methodCount);
for(int i=0;i<methodCount;i++){
Method method = Method.parse(clz,pool, iter);
clz.addMethod(method);
}
}
}