diff --git a/pom.xml b/pom.xml index ce2f133839..7b2820c28d 100644 --- a/pom.xml +++ b/pom.xml @@ -184,6 +184,11 @@ Sam Yoon + + + Hippo + hippah at protonmail.com + diff --git a/src/main/java/org/apache/bcel/classfile/Attribute.java b/src/main/java/org/apache/bcel/classfile/Attribute.java index 185360e60d..0b7b6bd8b8 100644 --- a/src/main/java/org/apache/bcel/classfile/Attribute.java +++ b/src/main/java/org/apache/bcel/classfile/Attribute.java @@ -93,6 +93,7 @@ protected static void println(final String msg) { } } + /** * Class method reads one attribute from the input data stream. This method * must not be accessible from the outside. It is called by the Field and @@ -110,6 +111,28 @@ protected static void println(final String msg) { */ public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException + { + return readAttribute(file, constant_pool, false); + } + + /** + * Class method reads one attribute from the input data stream. This method + * must not be accessible from the outside. It is called by the Field and + * Method constructor methods. + * + * @see Field + * @see Method + * + * @param file Input stream + * @param constant_pool Array of constants + * @param isOak If the the class file is oak + * @return Attribute + * @throws IOException + * @throws ClassFormatException + * @since 6.0 + */ + public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool, final boolean isOak) + throws IOException, ClassFormatException { byte tag = Const.ATTR_UNKNOWN; // Unknown attribute // Get class name from constant pool via `name_index' indirection @@ -145,7 +168,7 @@ public static Attribute readAttribute(final DataInput file, final ConstantPool c case Const.ATTR_SOURCE_FILE: return new SourceFile(name_index, length, file, constant_pool); case Const.ATTR_CODE: - return new Code(name_index, length, file, constant_pool); + return new Code(name_index, length, file, constant_pool, isOak); case Const.ATTR_EXCEPTIONS: return new ExceptionTable(name_index, length, file, constant_pool); case Const.ATTR_LINE_NUMBER_TABLE: diff --git a/src/main/java/org/apache/bcel/classfile/ClassParser.java b/src/main/java/org/apache/bcel/classfile/ClassParser.java index a592bfed06..79a3b29174 100644 --- a/src/main/java/org/apache/bcel/classfile/ClassParser.java +++ b/src/main/java/org/apache/bcel/classfile/ClassParser.java @@ -58,6 +58,7 @@ public final class ClassParser { private Attribute[] attributes; // attributes defined in the class private final boolean isZip; // Loaded from zip file private static final int BUFSIZE = 8192; + private boolean isOak; // Is oak class file /** @@ -290,7 +291,7 @@ private void readMethods() throws IOException, ClassFormatException { final int methods_count = dataInputStream.readUnsignedShort(); methods = new Method[methods_count]; for (int i = 0; i < methods_count; i++) { - methods[i] = new Method(dataInputStream, constantPool); + methods[i] = new Method(dataInputStream, constantPool, isOak); } } @@ -303,5 +304,6 @@ private void readMethods() throws IOException, ClassFormatException { private void readVersion() throws IOException, ClassFormatException { minor = dataInputStream.readUnsignedShort(); major = dataInputStream.readUnsignedShort(); + isOak = major < Const.MAJOR_1_1 || (major == Const.MAJOR_1_1 && minor < 3); } } diff --git a/src/main/java/org/apache/bcel/classfile/Code.java b/src/main/java/org/apache/bcel/classfile/Code.java index cedc53527e..6a1e06b8a2 100644 --- a/src/main/java/org/apache/bcel/classfile/Code.java +++ b/src/main/java/org/apache/bcel/classfile/Code.java @@ -48,6 +48,7 @@ public final class Code extends Attribute { private byte[] code; // Actual byte code private CodeException[] exceptionTable; // Table of handled exceptions private Attribute[] attributes; // or LocalVariable + private boolean isOak; // If the class file follows oak format /** @@ -60,6 +61,7 @@ public Code(final Code c) { } + /** * @param name_index Index pointing to the name Code * @param length Content length in bytes @@ -68,10 +70,23 @@ public Code(final Code c) { */ Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool) throws IOException { + this(name_index, length, file, constant_pool, false); + } + + /** + * @param name_index Index pointing to the name Code + * @param length Content length in bytes + * @param file Input stream + * @param constant_pool Array of constants + * @param isOak If the class file is oak + */ + Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool, final boolean isOak) + throws IOException { // Initialize with some default values which will be overwritten later - this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, - (CodeException[]) null, (Attribute[]) null, constant_pool); - final int code_length = file.readInt(); + this(name_index, length, isOak ? file.readUnsignedByte() : file.readUnsignedShort(), isOak ? file.readUnsignedByte() : file.readUnsignedShort(), + (byte[]) null, (CodeException[]) null, (Attribute[]) null, constant_pool); + this.isOak = isOak; + final int code_length = isOak ? file.readUnsignedShort() : file.readInt(); code = new byte[code_length]; // Read byte code file.readFully(code); /* Read exception table that contains all regions where an exception @@ -109,13 +124,30 @@ public Code(final Code c) { * @param constant_pool Array of constants */ public Code(final int name_index, final int length, final int maxStack, final int maxLocals, final byte[] code, - final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool) { + final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool) { + this(name_index, length, maxStack, maxLocals, code, exceptionTable, attributes, constant_pool, false); + } + + /** + * @param name_index Index pointing to the name Code + * @param length Content length in bytes + * @param maxStack Maximum size of stack + * @param maxLocals Number of local variables + * @param code Actual byte code + * @param exceptionTable of handled exceptions + * @param attributes Attributes of code: LineNumber or LocalVariable + * @param constant_pool Array of constants + * @param isOak If the class file follows the oak format + */ + public Code(final int name_index, final int length, final int maxStack, final int maxLocals, final byte[] code, + final CodeException[] exceptionTable, final Attribute[] attributes, final ConstantPool constant_pool, final boolean isOak) { super(Const.ATTR_CODE, name_index, length, constant_pool); this.maxStack = maxStack; this.maxLocals = maxLocals; this.code = code != null ? code : ArrayUtils.EMPTY_BYTE_ARRAY; this.exceptionTable = exceptionTable != null ? exceptionTable : CodeException.EMPTY_CODE_EXCEPTION_ARRAY; this.attributes = attributes != null ? attributes : EMPTY_ATTRIBUTE_ARRAY; + this.isOak = isOak; super.setLength(calculateLength()); // Adjust length } @@ -142,9 +174,15 @@ public void accept( final Visitor v ) { @Override public void dump( final DataOutputStream file ) throws IOException { super.dump(file); - file.writeShort(maxStack); - file.writeShort(maxLocals); - file.writeInt(code.length); + if (isOak) { + file.writeByte(maxStack); + file.writeByte(maxLocals); + file.writeShort(code.length); + } else { + file.writeShort(maxStack); + file.writeShort(maxLocals); + file.writeInt(code.length); + } file.write(code, 0, code.length); file.writeShort(exceptionTable.length); for (final CodeException exception : exceptionTable) { @@ -230,7 +268,19 @@ public int getMaxStack() { * and excluding all its attributes */ private int getInternalLength() { - return 2 /*maxStack*/+ 2 /*maxLocals*/+ 4 /*code length*/ + final int maxStack; + final int maxLocals; + final int codeLength; + if (isOak) { + maxStack = 1; + maxLocals = 1; + codeLength = 2; + } else { + maxStack = 2; + maxLocals = 2; + codeLength = 4; + } + return maxStack + maxLocals + codeLength + code.length /*byte-code*/ + 2 /*exception-table length*/ + 8 * (exceptionTable == null ? 0 : exceptionTable.length) /* exception table */ diff --git a/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java index 6b70942185..8ed8e82d67 100644 --- a/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java +++ b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java @@ -100,12 +100,23 @@ protected FieldOrMethod(final DataInputStream file, final ConstantPool constant_ * @throws ClassFormatException */ protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException { + this(file, constant_pool, false); + } + + /** + * Construct object from file stream. + * @param file Input stream + * @param isOak If the class file is oak + * @throws IOException + * @throws ClassFormatException + */ + protected FieldOrMethod(final DataInput file, final ConstantPool constant_pool, final boolean isOak) throws IOException, ClassFormatException { this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constant_pool); final int attributes_count = file.readUnsignedShort(); attributes = new Attribute[attributes_count]; for (int i = 0; i < attributes_count; i++) { - attributes[i] = Attribute.readAttribute(file, constant_pool); + attributes[i] = Attribute.readAttribute(file, constant_pool, isOak); } this.attributes_count = attributes_count; // init deprecated field } diff --git a/src/main/java/org/apache/bcel/classfile/Method.java b/src/main/java/org/apache/bcel/classfile/Method.java index a414de7a49..ebbe539753 100644 --- a/src/main/java/org/apache/bcel/classfile/Method.java +++ b/src/main/java/org/apache/bcel/classfile/Method.java @@ -84,7 +84,19 @@ public Method(final Method c) { */ Method(final DataInput file, final ConstantPool constant_pool) throws IOException, ClassFormatException { - super(file, constant_pool); + this(file, constant_pool, false); + } + + /** + * Construct object from file stream. + * @param file Input stream + * @param isOak If the class file is oak + * @throws IOException + * @throws ClassFormatException + */ + Method(final DataInput file, final ConstantPool constant_pool, final boolean isOak) throws IOException, + ClassFormatException { + super(file, constant_pool, isOak); }