package org.tinylcy; import org.tinylcy.accessflags.AccessFlags; import org.tinylcy.accessflags.ClassAccessFlags; import org.tinylcy.attributeinfo.BasicAttributeInfo; import org.tinylcy.basictype.U1; import org.tinylcy.basictype.U2; import org.tinylcy.basictype.U4; import org.tinylcy.constantpool.*; import java.io.InputStream; import java.util.ArrayList; /** * Created by chenyangli. */ public class ClassReader { public static void analyze(InputStream inputStream) { ClassFile classFile = read(inputStream); ConstantPool constantPool = new ConstantPool(classFile.constantPoolCount.getValue()); constantPool.setCpInfo(classFile.cpInfo); System.out.println("magic = " + classFile.magic.getHexValue()); System.out.println("minorVersion = " + classFile.minorVersion.getValue()); System.out.println("majorVersion = " + classFile.majorVersion.getValue()); System.out.println("constantPoolCount = " + classFile.constantPoolCount.getValue()); for (int i = 0; i < classFile.cpInfo.length; i++) { System.out.println("cpInfo[" + (i + 1) + "] = " + classFile.cpInfo[i]); } System.out.println("accessFlags = " + classFile.accessFlags.getHexValue() + ", " + AccessFlags.getFormattedAccessFlags(new ClassAccessFlags(), classFile.accessFlags.getValue())); System.out.println("thisClass = " + classFile.thisClass.getValue() + ", this class name = " + getConstantClassInfoValue(constantPool, classFile.thisClass.getValue())); System.out.println("superClass = " + classFile.superClass.getValue() + ", super class name = " + getConstantClassInfoValue(constantPool, classFile.superClass.getValue())); System.out.println("interfacesCount = " + classFile.interfacesCount.getValue()); for (int i = 0; i < classFile.interfacesCount.getValue(); i++) { System.out.println("interfaces[" + i + "] = " + classFile.interfaces[i].getValue() + ", interface name = " + getConstantClassInfoValue(constantPool, classFile.interfaces[i].getValue())); } System.out.println("fieldsCount = " + classFile.fieldsCount.getValue()); for (int i = 0; i < classFile.fieldsCount.getValue(); i++) { System.out.println("fields[" + i + "] = " + classFile.fields[i]); } System.out.println("methodsCount = " + classFile.methodsCount.getValue()); for (int i = 0; i < classFile.methodsCount.getValue(); i++) { System.out.println("methods[" + i + "] = " + classFile.methods[i]); } System.out.println("attributesCount = " + classFile.attributesCount.getValue()); for (int i = 0; i < classFile.attributesCount.getValue(); i++) { System.out.println("attributes[" + i + "] = " + classFile.attributes[i]); } } public static ClassFile read(InputStream inputStream) { ClassFile classFile = new ClassFile(); classFile.magic = U4.read(inputStream); classFile.minorVersion = U2.read(inputStream); classFile.majorVersion = U2.read(inputStream); classFile.constantPoolCount = U2.read(inputStream); ConstantPool constantPool = readConstantPool(inputStream, (short) (classFile.constantPoolCount.getValue() - 1)); classFile.cpInfo = constantPool.getCpInfo(); classFile.accessFlags = U2.read(inputStream); classFile.thisClass = U2.read(inputStream); classFile.superClass = U2.read(inputStream); classFile.interfacesCount = U2.read(inputStream); classFile.interfaces = new U2[classFile.interfacesCount.getValue()]; readInterfaces(inputStream, classFile, classFile.interfacesCount.getValue()); classFile.fieldsCount = U2.read(inputStream); readFieldsInfo(constantPool, inputStream, classFile, classFile.fieldsCount.getValue()); classFile.methodsCount = U2.read(inputStream); readMethodsInfo(constantPool, inputStream, classFile, classFile.methodsCount.getValue()); classFile.attributesCount = U2.read(inputStream); readClassAttributesInfo(constantPool, inputStream, classFile, classFile.attributesCount.getValue()); return classFile; } public static ConstantPool readConstantPool(InputStream inputStream, short constantPoolCount) { ConstantPool constantPool = new ConstantPool(constantPoolCount); ArrayList<ConstantPoolInfo> infoList = new ArrayList<ConstantPoolInfo>(); for (short i = 0; i < constantPoolCount; i++) { U1 tag = U1.read(inputStream); if (tag.getValue() == ConstantPoolInfo.CONSTANT_LONG_INFO || tag.getValue() == ConstantPoolInfo.CONSTANT_DOUBLE_INFO) { i++; infoList.add(null); } ConstantPoolInfo info = newConstantPoolInfo(tag, inputStream); infoList.add(info); } constantPool.setCpInfo(infoList.toArray(new ConstantPoolInfo[0])); return constantPool; } private static ConstantPoolInfo newConstantPoolInfo(U1 tag, InputStream inputStream) { int tagValue = tag.getValue(); ConstantPoolInfo constantPoolInfo = null; switch (tagValue) { case ConstantPoolInfo.CONSTANT_UTF8_INFO: constantPoolInfo = new ConstantUtf8Info(ConstantPoolInfo.CONSTANT_UTF8_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_INTEGER_INFO: constantPoolInfo = new ConstantIntegerInfo(ConstantPoolInfo.CONSTANT_INTEGER_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_FLOAT_INFO: constantPoolInfo = new ConstantFloatInfo(ConstantPoolInfo.CONSTANT_FLOAT_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_LONG_INFO: constantPoolInfo = new ConstantLongInfo(ConstantPoolInfo.CONSTANT_LONG_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_DOUBLE_INFO: constantPoolInfo = new ConstantDoubleInfo(ConstantPoolInfo.CONSTANT_DOUBLE_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_CLASS_INFO: constantPoolInfo = new ConstantClassInfo(ConstantPoolInfo.CONSTANT_CLASS_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_STRING_INFO: constantPoolInfo = new ConstantClassInfo(ConstantPoolInfo.CONSTANT_STRING_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_FIELDREF_INFO: constantPoolInfo = new ConstantFieldRefInfo(ConstantPoolInfo.CONSTANT_FIELDREF_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_METHODREF_INFO: constantPoolInfo = new ConstantMethodRefInfo(ConstantPoolInfo.CONSTANT_METHODREF_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_INTERFACEMETHODREF_INFO: constantPoolInfo = new ConstantInterfaceMethodRefInfo(ConstantPoolInfo.CONSTANT_INTERFACEMETHODREF_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_NAMEANDTYPE_INFO: constantPoolInfo = new ConstantNameAndTypeInfo(ConstantPoolInfo.CONSTANT_NAMEANDTYPE_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_METHODHANDLE_INFO: constantPoolInfo = new ConstantMethodHandleInfo(ConstantPoolInfo.CONSTANT_METHODHANDLE_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_METHODTYPE_INFO: constantPoolInfo = new ConstantMethodTypeInfo(ConstantPoolInfo.CONSTANT_METHODTYPE_INFO); constantPoolInfo.read(inputStream); break; case ConstantPoolInfo.CONSTANT_INVOKEDYNAMIC_INFO: constantPoolInfo = new ConstantInvokeDynamicInfo(ConstantPoolInfo.CONSTANT_INVOKEDYNAMIC_INFO); constantPoolInfo.read(inputStream); break; } return constantPoolInfo; } public static void readInterfaces(InputStream inputStream, ClassFile classFile, short interfacesCount) { for (int i = 0; i < interfacesCount; i++) { classFile.interfaces[i] = U2.read(inputStream); } } public static void readFieldsInfo(ConstantPool constantPool, InputStream inputStream, ClassFile classFile, short fieldsCount) { ArrayList<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>(); for (int i = 0; i < fieldsCount; i++) { FieldInfo fieldInfo = new FieldInfo(constantPool); fieldInfo.read(inputStream); fieldInfoList.add(fieldInfo); } classFile.fields = fieldInfoList.toArray(new FieldInfo[0]); } public static void readMethodsInfo(ConstantPool constantPool, InputStream inputStream, ClassFile classFile, short methodsCount) { classFile.methods = new MethodInfo[methodsCount]; for (int i = 0; i < methodsCount; i++) { MethodInfo methodInfo = new MethodInfo(constantPool); methodInfo.read(inputStream); classFile.methods[i] = methodInfo; } } public static void readClassAttributesInfo(ConstantPool constantPool, InputStream inputStream, ClassFile classFile, short classAttributesCount) { classFile.attributes = new BasicAttributeInfo[classAttributesCount]; for (int i = 0; i < classAttributesCount; i++) { short attributeNameIndex = U2.read(inputStream).getValue(); BasicAttributeInfo attributeInfo = BasicAttributeInfo.newAttributeInfo(constantPool, attributeNameIndex); attributeInfo.read(inputStream); classFile.attributes[i] = attributeInfo; } } private static String getConstantClassInfoValue(ConstantPool constantPool, short constantClassInfoIndex) { ConstantClassInfo constantClassInfo = (ConstantClassInfo) constantPool.getCpInfo()[constantClassInfoIndex - 1]; short index = constantClassInfo.getIndex(); ConstantUtf8Info constantUtf8Info = ((ConstantUtf8Info) (constantPool.getCpInfo()[index - 1])); return constantUtf8Info.getValue(); } }