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.exception.AddAnotherParserException;
import com.coderising.jvm.exception.NotAClassFileException;
import com.coderising.jvm.field.Field;
import com.coderising.jvm.method.Method;
import com.coderising.jvm.util.Util;
public class ClassFileParser {
public ClassFile parse(byte[] codes) throws NotAClassFileException {
ByteCodeIterator iterator = new ByteCodeIterator(codes);
if(!validator(iterator)){
throw new NotAClassFileException();
}
ClassFile clazzFile = new ClassFile();
clazzFile.setMinorVersion(iterator.nextU2ToInt());
clazzFile.setMajorVersion(iterator.nextU2ToInt());
clazzFile.setConstPool(parseConstantPool(iterator,clazzFile));
clazzFile.setAccessFlag(parseAccessFlag(iterator));
clazzFile.setClassIndex(parseClassInfex(iterator));
parseInterfaces(iterator);
//解析属性
int fieldCount = iterator.nextU2ToInt();
for (int i = 0; i < fieldCount; i++) {
clazzFile.addField(Field.parse(clazzFile.getConstantPool(), iterator));
}
//解析方法
int methodCount = iterator.nextU2ToInt();
for (int i = 0; i < methodCount; i++) {
clazzFile.addMethod(Method.parse(clazzFile.getConstantPool(), iterator));;
}
return clazzFile;
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter){
return new AccessFlag(iter.nextU2ToInt());
}
private ClassIndex parseClassInfex(ByteCodeIterator iter){
ClassIndex classIndex = new ClassIndex();
classIndex.setThisClassIndex(iter.nextU2ToInt());
classIndex.setSuperClassIndex(iter.nextU2ToInt());
return classIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter,ClassFile clazzFile){
ConstantPool pool = new ConstantPool(clazzFile);
pool.addConstantInfo(new NullConstantInfo());
try {
int poolSize = iter.nextU2ToInt();
for (int i = 1; i < poolSize; i++) {
int tag = iter.nextInt();
switch (tag) {
case ConstantInfo.UTF8_INFO:
UTF8Info UTF8Info = new UTF8Info(pool);
int len = iter.nextU2ToInt();
String value = iter.nextStr(len);
UTF8Info.setLength(len);
UTF8Info.setValue(value);
pool.addConstantInfo(UTF8Info);
break;
case ConstantInfo.FLOAT_INFO:
//TODO
break;
case ConstantInfo.CLASS_INFO:
ClassInfo classInfo = new ClassInfo(pool);
classInfo.setUtf8Index(iter.nextU2ToInt());
pool.addConstantInfo(classInfo);
break;
case ConstantInfo.STRING_INFO:
StringInfo stringInfo = new StringInfo(pool);
stringInfo.setIndex(iter.nextU2ToInt());
pool.addConstantInfo(stringInfo);
break;
case ConstantInfo.FIELD_INFO:
FieldRefInfo fieldRefInfo = new FieldRefInfo(pool);
fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt());
fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(fieldRefInfo);
break;
case ConstantInfo.METHOD_INFO:
MethodRefInfo methodRefInfo = new MethodRefInfo(pool);
methodRefInfo.setClassInfoIndex(iter.nextU2ToInt());
methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(methodRefInfo);
break;
case ConstantInfo.NAME_AND_TYPE_INFO:
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
nameAndTypeInfo.setIndex1(iter.nextU2ToInt());
nameAndTypeInfo.setIndex2(iter.nextU2ToInt());
pool.addConstantInfo(nameAndTypeInfo);
break;
default:
throw new AddAnotherParserException();
}
}
} catch (AddAnotherParserException e) {
e.printStackTrace();
}
return pool;
}
private void parseInterfaces(ByteCodeIterator iter){
@SuppressWarnings("unused")
int interfaceCount = iter.nextU2ToInt();
//System.out.println("接口数量为:"+interfaceCount);
// TODO
}
/**
* 校验是否为class文件
* @param iterator
* @return
*/
private boolean validator(ByteCodeIterator iterator){
if(iterator.hasNext(4)){
byte[] magicByte = iterator.next(4);
String magicNumber = Util.byteToHexString(magicByte);
if("cafebabe".equals(magicNumber)){
return true;
}
}
return false;
}
}