package com.github.orajavac.coding2017.jvm.loader;
import com.github.orajavac.coding2017.jvm.clz.AccessFlag;
import com.github.orajavac.coding2017.jvm.clz.ClassFile;
import com.github.orajavac.coding2017.jvm.clz.ClassIndex;
import com.github.orajavac.coding2017.jvm.constant.ClassInfo;
import com.github.orajavac.coding2017.jvm.constant.ConstantPool;
import com.github.orajavac.coding2017.jvm.constant.FieldRefInfo;
import com.github.orajavac.coding2017.jvm.constant.MethodRefInfo;
import com.github.orajavac.coding2017.jvm.constant.NameAndTypeInfo;
import com.github.orajavac.coding2017.jvm.constant.NullConstantInfo;
import com.github.orajavac.coding2017.jvm.constant.StringInfo;
import com.github.orajavac.coding2017.jvm.constant.UTF8Info;
import com.github.orajavac.coding2017.jvm.field.Field;
import com.github.orajavac.coding2017.jvm.method.Method;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ClassFile clzFile = new ClassFile();
ByteCodeIterator iter = new ByteCodeIterator(codes);
String magicNumber = iter.nextU4ToHexString();
System.out.println("magicNumber="+magicNumber);
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) {
AccessFlag flag = new AccessFlag(iter.nextU2ToInt());
return flag;
}
private ClassIndex parseClassInfex(ByteCodeIterator iter) {
int thisClassIndex = iter.nextU2ToInt();
int superClassIndex = iter.nextU2ToInt();
ClassIndex clzIndex = new ClassIndex();
clzIndex.setThisClassIndex(thisClassIndex);
clzIndex.setSuperClassIndex(superClassIndex);
return clzIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
int constPoolCount = iter.nextU2ToInt();
System.out.println("Constant Pool Count :"+constPoolCount);
ConstantPool pool = new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
for (int i=1;i<constPoolCount-1;i++){
int tag = iter.nextU1ToInt();
if (tag == 7){ //class info
int uft8Index = iter.nextU2ToInt();
ClassInfo clzInfo = new ClassInfo(pool);
clzInfo.setUtf8Index(uft8Index);
pool.addConstantInfo(clzInfo);
}else if (tag == 1){ //utf-8 string
int len = iter.nextU2ToInt();
byte[] data = iter.getBytes(len);
String value = null;
try{
value = new String(data,"UTF-8");
}catch(Exception e){
e.printStackTrace();
}
UTF8Info utf8info = new UTF8Info(pool);
utf8info.setLength(len);
utf8info.setValue(value);
pool.addConstantInfo(utf8info);
}else if (tag == 8){
StringInfo info = new StringInfo(pool);
info.setIndex(iter.nextU2ToInt());
pool.addConstantInfo(info);
}else if (tag == 9){
FieldRefInfo field = new FieldRefInfo(pool);
field.setClassInfoIndex(iter.nextU2ToInt());
field.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(field);
}else if (tag == 10){
MethodRefInfo method = new MethodRefInfo(pool);
method.setClassInfoIndex(iter.nextU2ToInt());
method.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(method);
}else if (tag == 12){
NameAndTypeInfo nameType = new NameAndTypeInfo(pool);
nameType.setIndex1(iter.nextU2ToInt());
nameType.setIndex2(iter.nextU2ToInt());
pool.addConstantInfo(nameType);
}else{
throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet.");
}
}
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 filedCount = iter.nextU2ToInt();
System.out.println("Field count:" + filedCount);
for (int i=1;i<=filedCount;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);
}
}
}