package main.coding_170430.jvm.loader;
import main.coding_170430.jvm.clz.AccessFlag;
import main.coding_170430.jvm.clz.ClassFile;
import main.coding_170430.jvm.clz.ClassIndex;
import main.coding_170430.jvm.constant.*;
import main.coding_170430.jvm.field.Field;
import main.coding_170430.jvm.method.Method;
import java.io.UnsupportedEncodingException;
/**
* Created by peter on 2017/4/21.
*/
public class ClassFileParse {
public ClassFile parse(byte[] codes) {
ClassFile clzFile = new ClassFile();
ByteCodeIterator iterator = new ByteCodeIterator(codes);
String magicNumber = iterator.nextU4ToHexString();
if (!"cafebabe".equals(magicNumber)) {
return null;
}
clzFile.setMinorVersion(iterator.nextU2ToInt());
clzFile.setMajorVersion(iterator.nextU2ToInt());
ConstantPool pool = parseConstantPool(iterator);
clzFile.setConstantPool(pool);
AccessFlag flag = parseAccessFlag(iterator);
clzFile.setAccessFlag(flag);
parseInterfaces(iterator);
parseFields(clzFile, iterator);
parseMethods(clzFile, iterator);
return clzFile;
}
public AccessFlag parseAccessFlag(ByteCodeIterator iterator) {
AccessFlag flag = new AccessFlag(iterator.nextU2ToInt());
return flag;
}
public ClassIndex parseClassIndex(ByteCodeIterator iterator) {
int thisClassIndex = iterator.nextU2ToInt();
int superClassIndex = iterator.nextU2ToInt();
ClassIndex clzIndex = new ClassIndex();
clzIndex.setThisClassIndex(thisClassIndex);
clzIndex.setSuperClassIndex(superClassIndex);
return clzIndex;
}
public ConstantPool parseConstantPool(ByteCodeIterator iterator) {
int constantPoolCount = iterator.nextU2ToInt();
ConstantPool pool = new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
for (int i = 1; i <= constantPoolCount - 1; i++) {
int tag = iterator.nextU1ToInt();
if (tag == 7) {
//Class Info
int utf8Index = iterator.nextU2ToInt();
ClassInfo classInfo = new ClassInfo(pool);
classInfo.setUtf8Index(utf8Index);
pool.addConstantInfo(classInfo);
} else if (tag == 1) {
//UTF-8 String
int len = iterator.nextU2ToInt();
byte[] data = iterator.getBytes(len);
String value = null;
try {
value = new String(data, "UTF-8");
} catch (UnsupportedEncodingException 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(iterator.nextU2ToInt());
pool.addConstantInfo(info);
} else if (tag == 9) {
FieldRefInfo field = new FieldRefInfo(pool);
field.setClassInfoIndex(iterator.nextU2ToInt());
field.setNameAndTypeIndex(iterator.nextU2ToInt());
pool.addConstantInfo(field);
} else if (tag == 10) {
//MethodRef
MethodRefInfo method = new MethodRefInfo(pool);
method.setClassInfoIndex(iterator.nextU2ToInt());
method.setNameAndTypeIndex(iterator.nextU2ToInt());
pool.addConstantInfo(method);
} else if (tag == 12) {
//Name and Type Info
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
nameAndTypeInfo.setIndexA(iterator.nextU2ToInt());
nameAndTypeInfo.setIndexB(iterator.nextU2ToInt());
pool.addConstantInfo(nameAndTypeInfo);
} else {
throw new RuntimeException("the constant pool tag " + tag + " has not implemented");
}
}
System.out.println("Finished reading Constant pool");
return pool;
}
public void parseInterfaces(ByteCodeIterator iterator) {
int interfaxrCount = iterator.nextU2ToInt();
System.out.println("interfaceCount:" + interfaxrCount);
//如果实现了接口这里需要实现
}
public void parseFields(ClassFile clzFile, ByteCodeIterator iterator) {
int fieldCount = iterator.nextU2ToInt();
for (int i = 1; i <= fieldCount; i++) {
Field f = Field.parse(clzFile.getConstantPool(), iterator);
clzFile.addField(f);
}
}
public void parseMethods(ClassFile clzfFile, ByteCodeIterator iterator) {
int methodCount = iterator.nextU2ToInt();
for (int i = 0; i <= methodCount; i++) {
Method m = Method.parse(clzfFile, iterator);
clzfFile.addMethod(m);
}
}
}