package com.coderising.jvm.loader;
import java.io.UnsupportedEncodingException;
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;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ClassFile clzFile = new ClassFile();
ByteCodeIterator iter = new ByteCodeIterator(codes);
String magicNumber = iter.nextU4toHexString();
if (!"cafebabe".equals(magicNumber)) {
return null;
}
clzFile.setMinorVersion(iter.nextU2toInt());
clzFile.setMajorVersion(iter.nextU2toInt());
ConstantPool pool = parseConstantPool(iter);
clzFile.setConstPool(pool);
clzFile.setAccessFlag(parseAccessFlag(iter));
clzFile.setClassIndex(parseClassIndex(iter));
parseInterfaces(iter);//如果实现接口,需要进一步解析
parseFields(clzFile, iter);
parseMethods(clzFile, iter);
return clzFile;
}
private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) {
int methodCount = iter.nextU2toInt();
System.out.println("methodCount:" + methodCount);
for (int i = 0; i < methodCount; i++) {
System.out.println("method :" + (i+1));
Method m = Method.parse(clzFile, iter);
clzFile.addMethod(m);
}
}
private void parseFields(ClassFile clzFile, ByteCodeIterator iter) {
int fieldCount = iter.nextU2toInt();
System.out.println("fieldCount:" + fieldCount);
for (int i = 0; i < fieldCount; i++) {
Field f = Field.parse(clzFile.getConstantPool(), iter);
clzFile.addField(f);
}
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
//int flagValue = iter.nextU2toInt();
return new AccessFlag(iter.nextU2toInt());
}
private ClassIndex parseClassIndex(ByteCodeIterator iter) {
ClassIndex classIndex = new ClassIndex();
classIndex.setThisClassIndex(iter.nextU2toInt());
classIndex.setSuperClassIndex(iter.nextU2toInt());
return classIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
int constantPoolIndexCount = iter.nextU2toInt();
System.out.println("Constant Pool Index Count:" + constantPoolIndexCount);
ConstantPool pool = new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
for (int i = 1; i <= constantPoolIndexCount - 1; i++) {
int tag = iter.nextU1toInt();
if (tag == 7) {//Class Info
int nameIndex = iter.nextU2toInt();
ClassInfo clzInfo = new ClassInfo(pool);
clzInfo.setUtf8Index(nameIndex);
pool.addConstantInfo(clzInfo);
} else if (tag == 1) {//Utf8 Info
int length = iter.nextU2toInt();
byte[] data = iter.getBytes(length);
String value = null;
try {
value = new String(data, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
UTF8Info utf8Info = new UTF8Info(pool);
utf8Info.setLength(length);
utf8Info.setValue(value);
pool.addConstantInfo(utf8Info);
} else if (tag == 8) {// String Info
int strIndex = iter.nextU2toInt();
StringInfo stringInfo = new StringInfo(pool);
stringInfo.setIndex(strIndex);
pool.addConstantInfo(stringInfo);
} else if (tag == 9) {// Fieldref Info
FieldRefInfo fieldRefInfo = new FieldRefInfo(pool);
fieldRefInfo.setClassInfoIndex(iter.nextU2toInt());
fieldRefInfo.setNameAndTypeIndex(iter.nextU2toInt());
pool.addConstantInfo(fieldRefInfo);
} else if (tag == 10) {// Methodref Info
int classIndex = iter.nextU2toInt();
int nameAndTypeIndex = iter.nextU2toInt();
MethodRefInfo methodRefInfo = new MethodRefInfo(pool);
methodRefInfo.setClassInfoIndex(classIndex);
methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex);
pool.addConstantInfo(methodRefInfo);
} else if (tag == 12) { //NameAndType Info
int nameIndex = iter.nextU2toInt();
int descriptorIndex = iter.nextU2toInt();
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
nameAndTypeInfo.setIndex1(nameIndex);
nameAndTypeInfo.setIndex2(descriptorIndex);
pool.addConstantInfo(nameAndTypeInfo);
}
else {
throw new RuntimeException("The constant pool has not realized at tag=" + tag);
}
}
return pool;
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextU2toInt();
System.out.println("interfaceCount:" + interfaceCount);
// TODO : 如果实现了interface, 这里需要解析
}
}