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.ConstantInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.field.Field; import com.coderising.jvm.method.Method; import com.coderising.jvm.parser.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ClassFileParser { private static final Map<Integer, ConstantInfoParser> constantPoolParserMap = new HashMap<Integer, ConstantInfoParser>(); static { constantPoolParserMap.put(ConstantInfo.UTF8_INFO, new UTF8InfoParser()); // constantPoolParserMap.put(ConstantInfo.INTEGER_INFO, new IntegerInfoParser()); // constantPoolParserMap.put(ConstantInfo.FLOAT_INFO, new FloatInfoParser()); // constantPoolParserMap.put(ConstantInfo.LONG_INFO, new LongInfoParser()); // constantPoolParserMap.put(ConstantInfo.DOUBLE_INFO, new DoubleInfoParser()); constantPoolParserMap.put(ConstantInfo.CLASS_INFO, new ClassInfoParser()); constantPoolParserMap.put(ConstantInfo.STRING_INFO, new StringInfoParser()); constantPoolParserMap.put(ConstantInfo.FIELDREF_INFO, new FieldRefInfoParser()); constantPoolParserMap.put(ConstantInfo.METHODREF_INFO, new MethodRefInfoParser()); // constantPoolParserMap.put(ConstantInfo.INTERFACE_METHODREF_INFO, new InterfaceMethodrefInfoParser()); constantPoolParserMap.put(ConstantInfo.NAMEANDTYPE_INFO, new NameAndTypeInfoParser()); // constantPoolParserMap.put(ConstantInfo.METHODHANDLE_INFO, new MethodHandleInfoParser()); // constantPoolParserMap.put(ConstantInfo.METHODTYPE_INFO, new MethodTypeInfoParser()); // constantPoolParserMap.put(ConstantInfo.INVOKEDYNAMIC_INFO, new InvokeDynamicInfoParser()); } public ClassFile parse(byte[] codes) { ByteCodeIterator iterator = new ByteCodeIterator(codes); String magicNum = iterator.nextU4ToHexString(); if (!"cafebabe".equals(magicNum)){ return null; } ClassFile clzFile = new ClassFile(); clzFile.setMinorVersion(iterator.nextU2ToInt()); clzFile.setMajorVersion(iterator.nextU2ToInt()); clzFile.setConstPool(parseConstantPool(iterator)); clzFile.setAccessFlag(parseAccessFlag(iterator)); clzFile.setClassIndex(parseClassInfex(iterator)); parseInterfaces(iterator); parseFileds(clzFile, iterator); parseMethods(clzFile, iterator); return clzFile; } 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) { int constantPoolCount = iter.nextU2ToInt(); ConstantPool constantPool = new ConstantPool(); constantPool.addConstantInfo(new NullConstantInfo()); for (int i = 1; i < constantPoolCount; i++) { int tag = iter.nextU1toInt(); ConstantInfoParser parser = constantPoolParserMap.get(tag); if (parser == null){ throw new RuntimeException("the constant pool tag " + tag + " has not been implemented yet."); } constantPool.addConstantInfo(parser.parser(constantPool, iter)); } return constantPool; } private void parseInterfaces(ByteCodeIterator iter) { int interfaceCount = iter.nextU2ToInt(); System.out.println("interfaceCount:" + interfaceCount); // throw new RuntimeException("interfaceParse has not been implemented"); // TODO : 如果实现了interface, 这里需要解析 } private void parseFileds(ClassFile clzFile, ByteCodeIterator iter) { int fieldCount = iter.nextU2ToInt(); for (int i = 0; i < fieldCount; i++) { clzFile.addField(Field.parse(clzFile.getConstantPool(), iter)); } } private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { int methodCount = iter.nextU2ToInt(); for (int i = 0; i < methodCount; i++) { clzFile.addMethod(Method.parse(clzFile, iter)); } } }