package org.xukai.jvm.loader;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.xukai.jvm.clz.AccessFlag;
import org.xukai.jvm.clz.ClassFile;
import org.xukai.jvm.clz.ClassIndex;
import org.xukai.jvm.constant.ClassInfo;
import org.xukai.jvm.constant.ConstantPool;
import org.xukai.jvm.constant.FieldRefInfo;
import org.xukai.jvm.constant.MethodRefInfo;
import org.xukai.jvm.constant.NameAndTypeInfo;
import org.xukai.jvm.constant.NullConstantInfo;
import org.xukai.jvm.constant.StringInfo;
import org.xukai.jvm.constant.UTF8Info;
import org.xukai.jvm.field.Field;
import org.xukai.jvm.method.Method;
import java.util.ArrayList;
import java.util.List;
public class ClassFileParser {
public ClassFile parse(byte[] codes) {
ByteCodeIterator iter = new ByteCodeIterator(codes, 0);
String magic = iter.nextToString(4);
Preconditions.checkArgument(magic.equals("cafebabe"),"无法解析此class文件");
ClassFile classFile = new ClassFile();
int minorVersion = iter.nextToInt(2);
classFile.setMinorVersion(minorVersion);
int majorVersion = iter.nextToInt(2);
classFile.setMajorVersion(majorVersion);
ConstantPool pool = parseConstantPool(iter);
AccessFlag accessFlag = parseAccessFlag(iter);
ClassIndex classIndex = parseClassInfex(iter);
parseInterfaces(iter);
classFile.setConstPool(pool);
classFile.setAccessFlag(accessFlag);
classFile.setClassIndex(classIndex);
parseFields(pool, iter, classFile);
parseMethod(pool, iter, classFile);
return classFile;
}
private List<Field> parseFields(ConstantPool pool, ByteCodeIterator iter, ClassFile classFile) {
int fieldsCount = iter.nextToInt(2);
ArrayList<Field> fields = new ArrayList<>(fieldsCount);
for (int i = 0; i < fieldsCount; i++) {
int flages = iter.nextToInt(2);
int nameIndex = iter.nextToInt(2);
int descriptorIndex = iter.nextToInt(2);
int attributeCount = iter.nextToInt(2);
if (attributeCount > 0) {
System.out.println("jeixi");
}
Field field = new Field(flages, nameIndex, descriptorIndex, pool);
classFile.addField(field);
}
return fields;
}
private void parseMethod(ConstantPool pool, ByteCodeIterator iter, ClassFile classFile) {
int methodsCount = iter.nextToInt(2);
for (int i = 0; i < methodsCount; i++) {
Method.parse(classFile,iter);
}
}
private AccessFlag parseAccessFlag(ByteCodeIterator iter) {
return new AccessFlag(iter.nextToInt(2));
}
private ClassIndex parseClassInfex(ByteCodeIterator iter) {
ClassIndex classIndex = new ClassIndex();
classIndex.setThisClassIndex(iter.nextToInt(2));
classIndex.setSuperClassIndex(iter.nextToInt(2));
return classIndex;
}
private ConstantPool parseConstantPool(ByteCodeIterator iter) {
int constantCount = iter.nextToInt(2);
System.out.println(constantCount);
Preconditions.checkArgument(constantCount > 0, "无法解析此class文件");
ConstantPool pool = new ConstantPool();
pool.addConstantInfo(new NullConstantInfo());
for (int i = 0; i < constantCount - 1; i++) {
int tag = iter.nextToInt(1);
switch (tag) {
case 1:
UTF8Info info = new UTF8Info(pool);
int length = iter.nextToInt(2);
String value = iter.nextToUTF(length);
Preconditions.checkNotNull(value);
info.setLength(length);
info.setValue(value);
pool.addConstantInfo(info);
break;
case 4:
throw new RuntimeException();
case 7:
ClassInfo classInfo = new ClassInfo(pool);
int ut8Index = iter.nextToInt(2);
Preconditions.checkArgument(-1 != ut8Index);
classInfo.setUtf8Index(ut8Index);
pool.addConstantInfo(classInfo);
break;
case 8:
StringInfo stringInfo = new StringInfo(pool);
int index = iter.nextToInt(2);
Preconditions.checkArgument(-1 != index);
stringInfo.setIndex(index);
pool.addConstantInfo(stringInfo);
break;
case 9:
FieldRefInfo fieldRefInfo = new FieldRefInfo(pool);
int classIndex = iter.nextToInt(2);
int nameAndType = iter.nextToInt(2);
Preconditions.checkArgument(-1 != classIndex);
Preconditions.checkArgument(-1 != nameAndType);
fieldRefInfo.setClassInfoIndex(classIndex);
fieldRefInfo.setNameAndTypeIndex(nameAndType);
pool.addConstantInfo(fieldRefInfo);
break;
case 10:
MethodRefInfo methodRefInfo = new MethodRefInfo(pool);
int classIndex2 = iter.nextToInt(2);
int nameAndType2 = iter.nextToInt(2);
Preconditions.checkArgument(-1 != classIndex2);
Preconditions.checkArgument(-1 != nameAndType2);
methodRefInfo.setClassInfoIndex(classIndex2);
methodRefInfo.setNameAndTypeIndex(nameAndType2);
pool.addConstantInfo(methodRefInfo);
break;
case 12:
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
int nameIndex = iter.nextToInt(2);
int descriptorIndex = iter.nextToInt(2);
Preconditions.checkArgument(-1 != nameIndex);
Preconditions.checkArgument(-1 != descriptorIndex);
nameAndTypeInfo.setIndex1(nameIndex);
nameAndTypeInfo.setIndex2(descriptorIndex);
pool.addConstantInfo(nameAndTypeInfo);
break;
default:
throw new RuntimeException();
}
}
return pool;
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextToInt(2);
System.out.println("interfaceCount:" + interfaceCount);
// TODO : 如果实现了interface, 这里需要解析
}
}