package com.coding2017.jvm.loader;
import com.coding2017.jvm.clz.AccessFlag;
import com.coding2017.jvm.clz.ClassFile;
import com.coding2017.jvm.clz.ClassIndex;
import com.coding2017.jvm.constant.*;
import com.coding2017.jvm.field.Field;
import com.coding2017.jvm.method.Method;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ClassFile classFile = new ClassFile();
ByteCodeIterator iterator = new ByteCodeIterator(codes);
boolean check = checkMagicNumber(iterator);
if (!check) {
System.out.println("不是标准class文件, magic number不正确");
return null;
}
// 版本号
classFile.setMinorVersion(iterator.nextU2ToInt());
classFile.setMajorVersion(iterator.nextU2ToInt());
// 常量池
classFile.setConstPool(parseConstantPool(iterator));
// 访问标志
classFile.setAccessFlag(parseAccessFlag(iterator));
// this class and super class
classFile.setClassIndex(parseClassInfex(iterator));
parseInterfaces(iterator);
parseFields(classFile, iterator);
parseMethods(classFile, iterator);
return classFile;
}
private void parseMethods(ClassFile clzFile, ByteCodeIterator iterator) {
int methodCount = iterator.nextU2ToInt();
for (int i = 0; i < methodCount; i++) {
clzFile.getMethods().add(Method.parse(clzFile, iterator));
}
}
private void parseFields(ClassFile clzFile, ByteCodeIterator iterator) {
int fieldCount = iterator.nextU2ToInt();
for (int i = 0; i < fieldCount; i++) {
clzFile.getFields().add(Field.parse(clzFile.getConstantPool(), iterator));
}
}
private boolean checkMagicNumber(ByteCodeIterator iterator) {
String magicNumber = iterator.nextU4ToString();
return "cafebabe".equals(magicNumber);
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt());
return accessFlag;
}
private ClassIndex parseClassInfex(ByteCodeIterator iter) {
ClassIndex classIndex = new ClassIndex();
classIndex.setThisClassIndex(iter.nextU2ToInt());
classIndex.setSuperClassIndex(iter.nextU2ToInt());
return classIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
ConstantPool constantPool = new ConstantPool();
int constantCount = iter.nextU2ToInt();
constantPool.addConstantInfo(new NullConstantInfo());
for (int i = 1; i < constantCount; i++) {
constantPool.addConstantInfo(parseConstantInfo(constantPool, iter));
}
return constantPool;
}
private ConstantInfo parseConstantInfo(ConstantPool constantPool, ByteCodeIterator iterator) {
int tag = iterator.nextU1ToInt();
if (tag == ConstantInfo.UTF8_INFO) {
UTF8Info utf8Info = new UTF8Info(constantPool);
utf8Info.setLength(iterator.nextU2ToInt());
utf8Info.setValue(new String(iterator.nextByteN(utf8Info.getLength())));
return utf8Info;
} else if (tag == ConstantInfo.CLASS_INFO) {
ClassInfo classInfo = new ClassInfo(constantPool);
classInfo.setUtf8Index(iterator.nextU2ToInt());
return classInfo;
} else if (tag == ConstantInfo.STRING_INFO) {
StringInfo stringInfo = new StringInfo(constantPool);
stringInfo.setIndex(iterator.nextU2ToInt());
return stringInfo;
} else if (tag == ConstantInfo.FIELD_INFO) {
FieldRefInfo fieldRefInfo = new FieldRefInfo(constantPool);
fieldRefInfo.setClassInfoIndex(iterator.nextU2ToInt());
fieldRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt());
return fieldRefInfo;
} else if (tag == ConstantInfo.METHOD_INFO) {
MethodRefInfo methodRefInfo = new MethodRefInfo(constantPool);
methodRefInfo.setClassInfoIndex(iterator.nextU2ToInt());
methodRefInfo.setNameAndTypeIndex(iterator.nextU2ToInt());
return methodRefInfo;
} else if (tag == ConstantInfo.NAME_AND_TYPE_INFO) {
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(constantPool);
nameAndTypeInfo.setIndex1(iterator.nextU2ToInt());
nameAndTypeInfo.setIndex2(iterator.nextU2ToInt());
return nameAndTypeInfo;
} else {
throw new RuntimeException("not support tag " + tag);
}
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextU2ToInt();
System.out.println("interfaceCount:" + interfaceCount);
if (interfaceCount != 0) {
throw new RuntimeException("not parse interface");
}
// TODO : 如果实现了interface, 这里需要解析
}
}