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.ClassInfo; import com.coderising.jvm.constant.ConstantInfo; import com.coderising.jvm.constant.ConstantPool; import com.coderising.jvm.constant.FieldRefInfo; import com.coderising.jvm.constant.MethodRefInfo; import com.coderising.jvm.constant.NameAndTypeInfo; import com.coderising.jvm.constant.NullConstantInfo; import com.coderising.jvm.constant.StringInfo; import com.coderising.jvm.constant.UTF8Info; public class ClassFileParser { public ClassFile parse(byte[] codes) { ByteCodeIterator iter = new ByteCodeIterator(codes); ClassFile clzFile = new ClassFile(); String magicNum = iter.getBytesAsHexString(4); if(!"cafebabe".equals(magicNum)){ throw new RuntimeException("Magic Number validation failure, this may not be a java class file."); } int minVer = iter.nextU2AsInt(); int majVer = iter.nextU2AsInt(); System.out.println("magicNum="+magicNum+",minVer="+minVer+",majVer="+majVer); clzFile.setMajorVersion(majVer); clzFile.setMinorVersion(minVer); ConstantPool pool = parseConstantPool(iter); clzFile.setConstPool(pool); AccessFlag accFlag = parseAccessFlag(iter); clzFile.setAccessFlag(accFlag); ClassIndex clsIdx = parseClassIndex(iter); clzFile.setClassIndex(clsIdx); return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { AccessFlag af = new AccessFlag(iter.nextU2AsInt()); return af; } private ClassIndex parseClassIndex(ByteCodeIterator iter) { ClassIndex ci = new ClassIndex(); ci.setThisClassIndex(iter.nextU2AsInt()); ci.setSuperClassIndex(iter.nextU2AsInt()); return ci; } private ConstantPool parseConstantPool(ByteCodeIterator iter) { ConstantPool cp = new ConstantPool(); cp.addConstantInfo(new NullConstantInfo()); int cpLen = iter.nextU2AsInt(); for(int i=0;i<cpLen-1;i++){ int typeFlag = iter.nextU1AsInt(); switch(typeFlag){ case ConstantInfo.CLASS_INFO: //class info ClassInfo cf = new ClassInfo(cp); cf.setUtf8Index(iter.nextU2AsInt()); cp.addConstantInfo(cf); break; case ConstantInfo.UTF8_INFO: //UTF8 info UTF8Info ui = new UTF8Info(cp); ui.setLength(iter.nextU2AsInt()); ui.setValue(iter.getBytesAsString(ui.getLength())); cp.addConstantInfo(ui); break; case ConstantInfo.STRING_INFO: StringInfo ci = new StringInfo(cp); ci.setIndex(iter.nextU2AsInt()); cp.addConstantInfo(ci); break; case ConstantInfo.FIELD_INFO: FieldRefInfo fri = new FieldRefInfo(cp); fri.setClassInfoIndex(iter.nextU2AsInt()); fri.setNameAndTypeIndex(iter.nextU2AsInt()); cp.addConstantInfo(fri); break; case ConstantInfo.METHOD_INFO: MethodRefInfo mri = new MethodRefInfo(cp); mri.setClassInfoIndex(iter.nextU2AsInt()); mri.setNameAndTypeIndex(iter.nextU2AsInt()); cp.addConstantInfo(mri); break; case ConstantInfo.NAME_AND_TYPE_INFO: NameAndTypeInfo nti = new NameAndTypeInfo(cp); nti.setIndex1(iter.nextU2AsInt()); nti.setIndex2(iter.nextU2AsInt()); cp.addConstantInfo(nti); break; default : throw new RuntimeException("Parse exception:"+typeFlag); } } return cp; } }