package com.github.miniyk2012.coding2017.coderising.jvm.loader; import com.github.miniyk2012.coding2017.coderising.jvm.clz.AccessFlag; import com.github.miniyk2012.coding2017.coderising.jvm.clz.ClassFile; import com.github.miniyk2012.coding2017.coderising.jvm.clz.ClassIndex; import com.github.miniyk2012.coding2017.coderising.jvm.constant.*; import com.github.miniyk2012.coding2017.coderising.jvm.field.Field; import com.github.miniyk2012.coding2017.coderising.jvm.method.Method; public class ClassFileParser { public ClassFile parse(byte[] codes) { ClassFile clzFile = new ClassFile(); ByteCodeIterator byteCodeIterator = new ByteCodeIterator(codes); // byteCodeIterator.skip(4); // skip magic number String magicNumber = byteCodeIterator.nextU4ToHexString(); if (!"cafebabe".equals(magicNumber)) { return null; } int minorVersion = byteCodeIterator.nextU2toInt(); int majorVersion = byteCodeIterator.nextU2toInt(); ConstantPool constantPool = parseConstantPool(byteCodeIterator); AccessFlag accessFlag = parseAccessFlag(byteCodeIterator); ClassIndex classIndex = parseClassInfex(byteCodeIterator); clzFile.setMinorVersion(minorVersion); clzFile.setMajorVersion(majorVersion); clzFile.setConstPool(constantPool); clzFile.setAccessFlag(accessFlag); clzFile.setClassIndex(classIndex); parseInterfaces(byteCodeIterator); parseFileds(clzFile, byteCodeIterator); parseMethods(clzFile, byteCodeIterator); return clzFile; } protected AccessFlag parseAccessFlag(ByteCodeIterator iter) { int access_flags = iter.nextU2toInt(); AccessFlag accessFlag = new AccessFlag(access_flags); return accessFlag; } protected ClassIndex parseClassInfex(ByteCodeIterator iter) { ClassIndex classIndex = new ClassIndex(); int thisClassIndex = iter.nextU2toInt(); int superClassIndex = iter.nextU2toInt(); classIndex.setThisClassIndex(thisClassIndex); classIndex.setSuperClassIndex(superClassIndex); return classIndex; } protected ConstantPool parseConstantPool(ByteCodeIterator iter) { ConstantPool constantPool = new ConstantPool(); int constant_pool_count = iter.nextU2toInt(); ConstantInfo constantInfo; constantPool.addConstantInfo(new NullConstantInfo()); for (int i=1; i<constant_pool_count; i++) { int tag = iter.nextU1toInt(); constantInfo = getConstantInfo(iter, tag, constantPool); constantPool.addConstantInfo(constantInfo); } return constantPool; } private void parseInterfaces(ByteCodeIterator iter) { int interfaceCount = iter.nextU2toInt(); // System.out.println("interfaceCount:" + interfaceCount); for (int i=0; i<interfaceCount; i++) { // TODO : 如果实现了interface, 这里需要解析 iter.skip(2); } } private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { int fieldCount = iter.nextU2toInt(); for (int i =0; i<fieldCount; 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=0; i<methodCount; i++) { Method m = Method.parse(clzFile, iter); clzFile.addMethod(m); } } protected ConstantInfo getConstantInfo(ByteCodeIterator iter, int tag, ConstantPool pool) { switch (tag) { case ConstantInfo.UTF8_INFO: { UTF8Info utf8Info = new UTF8Info(pool); int length = iter.nextU2toInt(); String value = iter.readUtf8(length); utf8Info.setLength(length); utf8Info.setValue(value); return utf8Info; } case ConstantInfo.FLOAT_INFO: { throw new RuntimeException(String.format("FLOAT_INFO常量池类型[%d]还未实现", tag)); } case ConstantInfo.CLASS_INFO: { ClassInfo classInfo = new ClassInfo(pool); int utf8Index = iter.nextU2toInt(); classInfo.setUtf8Index(utf8Index); return classInfo; } case ConstantInfo.FIELD_INFO: { FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); int classInfoIndex = iter.nextU2toInt(); fieldRefInfo.setClassInfoIndex(classInfoIndex); int nameAndTypeIndex = iter.nextU2toInt(); fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); return fieldRefInfo; } case ConstantInfo.METHOD_INFO: { MethodRefInfo methodRefInfo = new MethodRefInfo(pool); int classInfoIndex = iter.nextU2toInt(); int nameAndTypeIndex = iter.nextU2toInt(); methodRefInfo.setClassInfoIndex(classInfoIndex); methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); return methodRefInfo; } case ConstantInfo.NAME_AND_TYPE_INFO: { NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); int index1 = iter.nextU2toInt(); int index2 = iter.nextU2toInt(); nameAndTypeInfo.setIndex1(index1); nameAndTypeInfo.setIndex2(index2); return nameAndTypeInfo; } case ConstantInfo.STRING_INFO: { StringInfo stringInfo = new StringInfo(pool); int index = iter.nextU2toInt(); stringInfo.setIndex(index); return stringInfo; } default: { throw new RuntimeException(String.format("该常量池类型[%d]还未实现", tag)); } } } }