/** Parses an {@code InnerClasses} attribute. */ private Attribute innerClasses( DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length < 2) { return throwSeverelyTruncated(); } ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int count = bytes.getUnsignedShort(offset); // number_of_classes if (observer != null) { observer.parsed(bytes, offset, 2, "number_of_classes: " + Hex.u2(count)); } offset += 2; length -= 2; if (length != (count * 8)) { throwBadLength((count * 8) + 2); } InnerClassList list = new InnerClassList(count); for (int i = 0; i < count; i++) { int innerClassIdx = bytes.getUnsignedShort(offset); int outerClassIdx = bytes.getUnsignedShort(offset + 2); int nameIdx = bytes.getUnsignedShort(offset + 4); int accessFlags = bytes.getUnsignedShort(offset + 6); CstType innerClass = (CstType) pool.get(innerClassIdx); CstType outerClass = (CstType) pool.get0Ok(outerClassIdx); CstString name = (CstString) pool.get0Ok(nameIdx); list.set(i, innerClass, outerClass, name, accessFlags); if (observer != null) { observer.parsed( bytes, offset, 2, "inner_class: " + DirectClassFile.stringOrNone(innerClass)); observer.parsed( bytes, offset + 2, 2, " outer_class: " + DirectClassFile.stringOrNone(outerClass)); observer.parsed(bytes, offset + 4, 2, " name: " + DirectClassFile.stringOrNone(name)); observer.parsed( bytes, offset + 6, 2, " access_flags: " + AccessFlags.innerClassString(accessFlags)); } offset += 8; } list.setImmutable(); return new AttInnerClasses(list); }
/** Parses an {@code EnclosingMethod} attribute. */ private Attribute enclosingMethod( DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length != 4) { throwBadLength(4); } ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int idx = bytes.getUnsignedShort(offset); CstType type = (CstType) pool.get(idx); idx = bytes.getUnsignedShort(offset + 2); CstNat method = (CstNat) pool.get0Ok(idx); Attribute result = new AttEnclosingMethod(type, method); if (observer != null) { observer.parsed(bytes, offset, 2, "class: " + type); observer.parsed(bytes, offset + 2, 2, "method: " + DirectClassFile.stringOrNone(method)); } return result; }
/** Parses a {@code Code} attribute. */ private Attribute code(DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length < 12) { return throwSeverelyTruncated(); } ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals int codeLength = bytes.getInt(offset + 4); // u4 code_length int origOffset = offset; if (observer != null) { observer.parsed(bytes, offset, 2, "max_stack: " + Hex.u2(maxStack)); observer.parsed(bytes, offset + 2, 2, "max_locals: " + Hex.u2(maxLocals)); observer.parsed(bytes, offset + 4, 4, "code_length: " + Hex.u4(codeLength)); } offset += 8; length -= 8; if (length < (codeLength + 4)) { return throwTruncated(); } int codeOffset = offset; offset += codeLength; length -= codeLength; BytecodeArray code = new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength), pool); if (observer != null) { code.forEach(new CodeObserver(code.getBytes(), observer)); } // u2 exception_table_length int exceptionTableLength = bytes.getUnsignedShort(offset); ByteCatchList catches = (exceptionTableLength == 0) ? ByteCatchList.EMPTY : new ByteCatchList(exceptionTableLength); if (observer != null) { observer.parsed(bytes, offset, 2, "exception_table_length: " + Hex.u2(exceptionTableLength)); } offset += 2; length -= 2; if (length < (exceptionTableLength * 8 + 2)) { return throwTruncated(); } for (int i = 0; i < exceptionTableLength; i++) { if (observer != null) { observer.changeIndent(1); } int startPc = bytes.getUnsignedShort(offset); int endPc = bytes.getUnsignedShort(offset + 2); int handlerPc = bytes.getUnsignedShort(offset + 4); int catchTypeIdx = bytes.getUnsignedShort(offset + 6); CstType catchType = (CstType) pool.get0Ok(catchTypeIdx); catches.set(i, startPc, endPc, handlerPc, catchType); if (observer != null) { observer.parsed( bytes, offset, 8, Hex.u2(startPc) + ".." + Hex.u2(endPc) + " -> " + Hex.u2(handlerPc) + " " + ((catchType == null) ? "<any>" : catchType.toHuman())); } offset += 8; length -= 8; if (observer != null) { observer.changeIndent(-1); } } catches.setImmutable(); AttributeListParser parser = new AttributeListParser(cf, CTX_CODE, offset, this); parser.setObserver(observer); StdAttributeList attributes = parser.getList(); attributes.setImmutable(); int attributeByteCount = parser.getEndOffset() - offset; if (attributeByteCount != length) { return throwBadLength(attributeByteCount + (offset - origOffset)); } return new AttCode(maxStack, maxLocals, code, catches, attributes); }