package com.pan.jvm.loader;
import com.pan.jvm.clz.AccessFlag;
import com.pan.jvm.clz.ClassFile;
import com.pan.jvm.clz.ClassIndex;
import com.pan.jvm.constant.*;
import com.pan.jvm.field.Field;
import com.pan.jvm.method.Method;
import java.io.UnsupportedEncodingException;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ByteCodeIterator iterator = new ByteCodeIterator(codes);
String magicNumber = iterator.nextU4ToHexString();
if (!"cafebabe".equals(magicNumber)) {// 验证是否为Java的.class文件
return null;
}
ClassFile classFile = new ClassFile();
classFile.setMinorVersion(iterator.nextU2ToInt());
classFile.setMajorVersion(iterator.nextU2ToInt());
ConstantPool constantPool = parseConstantPool(iterator);
classFile.setConstPool(constantPool);
AccessFlag flag = parseAccessFlag(iterator);
classFile.setAccessFlag(flag);
// this clz 和 supper clz
ClassIndex clzIndex = parseClassIndex(iterator);
classFile.setClassIndex(clzIndex);
// interface
parseInterfaces(iterator);
// field
parseFields(classFile, iterator);
// method
parseMethods(classFile, iterator);
return classFile;
}
private void parseMethods(ClassFile classFile, ByteCodeIterator iterator) {
int methodsCount = iterator.nextU2ToInt();
System.out.println("Methods Count: " + methodsCount);
for (int i = 1; i <= methodsCount; i++) {
Method method = Method.parse(classFile, iterator);
classFile.addMethod(method);
}
}
private void parseFields(ClassFile clzFile, ByteCodeIterator iterator) {
int fieldsCount = iterator.nextU2ToInt();
System.out.println("Field count:" + fieldsCount);
for (int i = 1; i <= fieldsCount; i++) {// 从第一个开始,因为不包含本身
Field field = Field.parse(clzFile.getConstantPool(), iterator);
clzFile.addField(field);
}
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
AccessFlag accessFlag = new AccessFlag(iter.nextU2ToInt());
return accessFlag;
}
private ClassIndex parseClassIndex(ByteCodeIterator iter) {
int thisClassIndex = iter.nextU2ToInt();
int supperClassIndex = iter.nextU2ToInt();
ClassIndex classIndex = new ClassIndex();
classIndex.setThisClassIndex(thisClassIndex);
classIndex.setSuperClassIndex(supperClassIndex);
return classIndex;
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextU2ToInt();
System.out.println("interfaceCount:" + interfaceCount);
// TODO : 如果实现了interface, 这里需要解析
}
/**
* 解析常量池
*
* @param iter
* @return
*/
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
int constPoolCount = iter.nextU2ToInt();
System.out.println("Constant Pool Count :" + constPoolCount);
ConstantPool pool = new ConstantPool();
// 因为常量池中的信息是从 1 开始的,但是数组或者List 下标是从0开始,所以设置第一个为空的常量
pool.addConstantInfo(new NullConstantInfo());
for (int i = 1; i <= constPoolCount - 1; i++) {
// 获取标识符信息
int tag = iter.nextU1toInt();
switch (tag) {
case ConstantInfo.CLASS_INFO: //CONSTANT_Class
int utf8Index = iter.nextU2ToInt();
ClassInfo classInfo = new ClassInfo(pool);
classInfo.setUtf8Index(utf8Index);
pool.addConstantInfo(classInfo);
break;
case ConstantInfo.FIELD_INFO: // CONSTANT_Fieldref
FieldRefInfo fieldRefInfo = new FieldRefInfo(pool);
fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt());
fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(fieldRefInfo);
break;
case ConstantInfo.METHOD_INFO: // CONSTANT_Methodref
MethodRefInfo methodRefInfo = new MethodRefInfo(pool);
methodRefInfo.setClassInfoIndex(iter.nextU2ToInt());
methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(methodRefInfo);
break;
case ConstantInfo.STRING_INFO:
StringInfo info = new StringInfo(pool);
info.setIndex(iter.nextU2ToInt());
pool.addConstantInfo(info);
break;
case ConstantInfo.NAME_AND_TYPE_INFO: // CONSTANT_NameAndType
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
nameAndTypeInfo.setIndex1(iter.nextU2ToInt());
nameAndTypeInfo.setIndex2(iter.nextU2ToInt());
pool.addConstantInfo(nameAndTypeInfo);
break;
case ConstantInfo.UTF8_INFO: // CONSTANT_Utf8
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 utf8Str = new UTF8Info(pool);
utf8Str.setLength(length);
utf8Str.setValue(value);
pool.addConstantInfo(utf8Str);
break;
default:
throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet.");
}
}
System.out.println("Finished reading Constant pool ");
return pool;
}
}