/** Parses a {@code LineNumberTable} attribute. */ private Attribute lineNumberTable( DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length < 2) { return throwSeverelyTruncated(); } ByteArray bytes = cf.getBytes(); int count = bytes.getUnsignedShort(offset); // line_number_table_length if (observer != null) { observer.parsed(bytes, offset, 2, "line_number_table_length: " + Hex.u2(count)); } offset += 2; length -= 2; if (length != (count * 4)) { throwBadLength((count * 4) + 2); } LineNumberList list = new LineNumberList(count); for (int i = 0; i < count; i++) { int startPc = bytes.getUnsignedShort(offset); int lineNumber = bytes.getUnsignedShort(offset + 2); list.set(i, startPc, lineNumber); if (observer != null) { observer.parsed(bytes, offset, 4, Hex.u2(startPc) + " " + lineNumber); } offset += 4; } list.setImmutable(); return new AttLineNumberTable(list); }
/** 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); }
/** * Parse the table part of either a {@code LocalVariableTable} or a {@code * LocalVariableTypeTable}. * * @param bytes {@code non-null;} bytes to parse, which should <i>only</i> contain the table data * (no header) * @param pool {@code non-null;} constant pool to use * @param count {@code >= 0;} the number of entries * @param typeTable {@code true} iff this is for a type table * @return {@code non-null;} the constructed list */ private LocalVariableList parseLocalVariables( ByteArray bytes, ConstantPool pool, ParseObserver observer, int count, boolean typeTable) { if (bytes.size() != (count * 10)) { // "+ 2" is for the count. throwBadLength((count * 10) + 2); } ByteArray.MyDataInputStream in = bytes.makeDataInputStream(); LocalVariableList list = new LocalVariableList(count); try { for (int i = 0; i < count; i++) { int startPc = in.readUnsignedShort(); int length = in.readUnsignedShort(); int nameIdx = in.readUnsignedShort(); int typeIdx = in.readUnsignedShort(); int index = in.readUnsignedShort(); CstString name = (CstString) pool.get(nameIdx); CstString type = (CstString) pool.get(typeIdx); CstString descriptor = null; CstString signature = null; if (typeTable) { signature = type; } else { descriptor = type; } list.set(i, startPc, length, name, descriptor, signature, index); if (observer != null) { observer.parsed( bytes, i * 10, 10, Hex.u2(startPc) + ".." + Hex.u2(startPc + length) + " " + Hex.u2(index) + " " + name.toHuman() + " " + type.toHuman()); } } } catch (IOException ex) { throw new RuntimeException("shouldn't happen", ex); } list.setImmutable(); return 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 SourceFile} attribute. */ private Attribute sourceFile(DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length != 2) { throwBadLength(2); } ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int idx = bytes.getUnsignedShort(offset); CstString cst = (CstString) pool.get(idx); Attribute result = new AttSourceFile(cst); if (observer != null) { observer.parsed(bytes, offset, 2, "source: " + cst); } return result; }
/** Parses a {@code LocalVariableTypeTable} attribute. */ private Attribute localVariableTypeTable( DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length < 2) { return throwSeverelyTruncated(); } ByteArray bytes = cf.getBytes(); int count = bytes.getUnsignedShort(offset); if (observer != null) { observer.parsed(bytes, offset, 2, "local_variable_type_table_length: " + Hex.u2(count)); } LocalVariableList list = parseLocalVariables( bytes.slice(offset + 2, offset + length), cf.getConstantPool(), observer, count, true); return new AttLocalVariableTypeTable(list); }
/** Parses a {@code ConstantValue} attribute. */ private Attribute constantValue( DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length != 2) { return throwBadLength(2); } ByteArray bytes = cf.getBytes(); ConstantPool pool = cf.getConstantPool(); int idx = bytes.getUnsignedShort(offset); TypedConstant cst = (TypedConstant) pool.get(idx); Attribute result = new AttConstantValue(cst); if (observer != null) { observer.parsed(bytes, offset, 2, "value: " + cst); } return result; }
/** Parses an {@code Exceptions} attribute. */ private Attribute exceptions(DirectClassFile cf, int offset, int length, ParseObserver observer) { if (length < 2) { return throwSeverelyTruncated(); } ByteArray bytes = cf.getBytes(); int count = bytes.getUnsignedShort(offset); // number_of_exceptions if (observer != null) { observer.parsed(bytes, offset, 2, "number_of_exceptions: " + Hex.u2(count)); } offset += 2; length -= 2; if (length != (count * 2)) { throwBadLength((count * 2) + 2); } TypeList list = cf.makeTypeList(offset, count); return new AttExceptions(list); }
/** 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); }