package coderising.jvm.loader;
import java.io.UnsupportedEncodingException;
import coderising.jvm.clz.AccessFlag;
import coderising.jvm.clz.ClassFile;
import coderising.jvm.clz.ClassIndex;
import coderising.jvm.constant.ClassInfo;
import coderising.jvm.constant.ConstantPool;
import coderising.jvm.constant.FieldRefInfo;
import coderising.jvm.constant.MethodRefInfo;
import coderising.jvm.constant.NameAndTypeInfo;
import coderising.jvm.constant.NullConstantInfo;
import coderising.jvm.constant.StringInfo;
import coderising.jvm.constant.UTF8Info;
import coderising.jvm.field.Field;
import 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(!magicNumber.equals("cafebabe")){
return null;
}
clzFile.setMinorVersion(iter.nextU2ToInt());
clzFile.setMajorVersion(iter.nextU2ToInt());
ConstantPool pool = parseConstantPool(iter);
clzFile.setConstPool(pool);
AccessFlag flag = parseAccessFlag(iter);
clzFile.setAccessFlag(flag);
ClassIndex clzindex = parseClassInfex(iter);
clzFile.setClassIndex(clzindex);
parseInterfaces(iter);
parseFileds(clzFile, iter);
parseMethods(clzFile, iter);
return clzFile;
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
return new AccessFlag(iter.nextU2ToInt());
}
private ClassIndex parseClassInfex(ByteCodeIterator iter) {
ClassIndex clzIndex = new ClassIndex();
clzIndex.setThisClassIndex(iter.nextU2ToInt());
clzIndex.setSuperClassIndex(iter.nextU2ToInt());
return clzIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
ConstantPool pool = new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
int poolSize = iter.nextU2ToInt();
for(int i =1;i<poolSize;i++){
int tag = iter.nextU1ToInt();
switch (tag){
case 1:
int len = iter.nextU2ToInt();
byte[] data = iter.getBytes(len);
String value = null;
try {
value = new String(data, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
UTF8Info utf8Str = new UTF8Info(pool);
utf8Str.setLength(len);
utf8Str.setValue(value);
pool.addConstantInfo(utf8Str);
break;
case 4:
break;
case 7:
int utf8Index = iter.nextU2ToInt();
ClassInfo clzInfo = new ClassInfo(pool);
clzInfo.setUtf8Index(utf8Index);
pool.addConstantInfo(clzInfo);
break;
case 8:
StringInfo stringInfo = new StringInfo(pool);
stringInfo.setIndex(iter.nextU2ToInt());
pool.addConstantInfo(stringInfo);
break;
case 9:
FieldRefInfo fieldRef = new FieldRefInfo(pool);
fieldRef.setClassInfoIndex(iter.nextU2ToInt());
fieldRef.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(fieldRef);
break;
case 10:
MethodRefInfo methodRef = new MethodRefInfo(pool);
methodRef.setClassInfoIndex(iter.nextU2ToInt());
methodRef.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(methodRef);
break;
case 12:
NameAndTypeInfo nati = new NameAndTypeInfo(pool);
nati.setIndex1(iter.nextU2ToInt());
nati.setIndex2(iter.nextU2ToInt());
pool.addConstantInfo(nati);
break;
default:
throw new RuntimeException("noFoundConstantIndex:"+tag);
}
}
System.out.println("Finished reading Constant pool ");
return pool;
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextU2ToInt();
System.out.println("interfaceCount:" + interfaceCount);
// TODO : 如果实现了interface, 这里需要解析
}
private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) {
int fieldCount = iter.nextU2ToInt();
for (int i = 1; i <= fieldCount; i++) {
Field f = Field.parse(clzFile.getConstantPool(), iter);
clzFile.addField(f);
}
}
private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) {
int methodCount = iter.nextU2ToInt();
for (int i = 1; i <= methodCount; i++) {
Method m = Method.parse(clzFile, iter);
clzFile.addMethod(m);
}
}
}