package com.coderising.jvm.loader; import java.io.UnsupportedEncodingException; 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.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; import com.coderising.jvm.field.Field; import com.coderising.jvm.method.Method; public class ClassFileParser { public ClassFile parse(byte[] codes) { ClassFile clzFile = new ClassFile(); ByteCodeIterator iter = new ByteCodeIterator(codes); String magicNumber = iter.nextU4ToHexString(); if ("cafebabe".equals(magicNumber) == false) { throw new RuntimeException("invalide class file!" + magicNumber); } int minorVersion = iter.nextU2ToInt(); System.out.println("minorVersion is " + minorVersion); clzFile.setMinorVersion(minorVersion); int majorVersion = iter.nextU2ToInt(); System.out.println("majorVersion is " + majorVersion); clzFile.setMajorVersion(majorVersion); ConstantPool pool = parseConstantPool(iter); clzFile.setConstPool(pool); AccessFlag accessFlag = parseAccessFlag(iter); clzFile.setAccessFlag(accessFlag); ClassIndex classIndex = parseClassIndex(iter); clzFile.setClassIndex(classIndex); parseInterfaces(iter); parseFields(clzFile, iter); parseMethods(clzFile, iter); return clzFile; } private AccessFlag parseAccessFlag(ByteCodeIterator iter) { return AccessFlag.parseAccessFlag(iter); } private ClassIndex parseClassIndex(ByteCodeIterator iter) { int thisClassIndex = iter.nextU2ToInt(); int superClassIndex = iter.nextU2ToInt(); ClassIndex classIndex = new ClassIndex(); classIndex.setThisClassIndex(thisClassIndex); classIndex.setSuperClassIndex(superClassIndex); return classIndex; } private ConstantPool parseConstantPool(ByteCodeIterator iter) { int constantsNum = iter.nextU2ToInt(); System.out.println("constantsNum is " + constantsNum); ConstantPool pool = new ConstantPool(); pool.addConstantInfo(new NullConstantInfo()); for (int i = 1; i < constantsNum; i++) { int tag = iter.nextU1ToInt(); if (tag == 7) { // Class info ClassInfo classInfo = new ClassInfo(pool); int utf8Index = iter.nextU2ToInt(); classInfo.setUtf8Index(utf8Index); } else if (tag == 1) { // utf8-info UTF8Info utf8Info = new UTF8Info(pool); int length = iter.nextU2ToInt(); //System.out.println("length is " + length); utf8Info.setLength(length); byte[] bytes = iter.nextNbytesToHexString(length); String value = ""; try { value = new String(bytes, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //System.out.println("value is " + value); utf8Info.setValue(value); } else if (tag == 8) { // StringInfo StringInfo stringInfo = new StringInfo(pool); int stringIndex = iter.nextU2ToInt(); stringInfo.setIndex(stringIndex); } else if (tag == 9) { // FieldRefInfo FieldRefInfo fieldRefInfo = new FieldRefInfo(pool); int classIndex = iter.nextU2ToInt(); fieldRefInfo.setClassInfoIndex(classIndex); int nameAndTypeIndex = iter.nextU2ToInt(); fieldRefInfo.setNameAndTypeIndex(nameAndTypeIndex); } else if (tag == 10) { // MethodRefInfo MethodRefInfo methodRefInfo = new MethodRefInfo(pool); int classIndex = iter.nextU2ToInt(); methodRefInfo.setClassInfoIndex(classIndex); int nameAndTypeIndex = iter.nextU2ToInt(); methodRefInfo.setNameAndTypeIndex(nameAndTypeIndex); } else if (tag == 12) { // NameAndTypeInfo NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool); int index1 = iter.nextU2ToInt(); nameAndTypeInfo.setIndex1(index1); int index2 = iter.nextU2ToInt(); nameAndTypeInfo.setIndex2(index2); } } return pool; } private void parseFields(ClassFile clzFile, ByteCodeIterator iter) { int fieldNum = iter.nextU2ToInt(); ConstantPool pool = clzFile.getConstantPool(); for (int i = 0; i < fieldNum; i++) { Field field = Field.parse(pool,iter); clzFile.addField(field); } } private void parseInterfaces(ByteCodeIterator iter) { int interfaceNum = iter.nextU2ToInt(); if (0 != interfaceNum) { throw new RuntimeException("interface parser not finsihed yet, pls check!"); } } private void parseMethods(ClassFile clzFile, ByteCodeIterator iter) { int methodNum = iter.nextU2ToInt(); for (int i = 0; i < methodNum; i++) { Method method = Method.parse(clzFile,iter); clzFile.addMethod(method); } } }