diff --git a/src/main/java/net/runelite/deob/attributes/Annotations.java b/src/main/java/net/runelite/deob/attributes/Annotations.java new file mode 100644 index 0000000000..897d1648de --- /dev/null +++ b/src/main/java/net/runelite/deob/attributes/Annotations.java @@ -0,0 +1,41 @@ +package net.runelite.deob.attributes; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import net.runelite.deob.attributes.annotation.Annotation; + +public class Annotations extends Attribute +{ + private final List annotations = new ArrayList<>(); + + public Annotations(Attributes attributes) + { + super(attributes, AttributeType.RUNTIMEVISIBLEANNOTATIONS); + } + + @Override + public void loadAttribute(DataInputStream is) throws IOException + { + int num_annotations = is.readUnsignedShort(); + for (int i = 0; i < num_annotations; ++i) + { + Annotation a = new Annotation(this); + a.load(is); + annotations.add(a); + } + } + + @Override + public void writeAttr(DataOutputStream out) throws IOException + { + out.writeShort(annotations.size()); + for (Annotation a : annotations) + { + a.write(out); + } + } + +} diff --git a/src/main/java/net/runelite/deob/attributes/AttributeType.java b/src/main/java/net/runelite/deob/attributes/AttributeType.java index c7fbbf3793..e9307bcc95 100644 --- a/src/main/java/net/runelite/deob/attributes/AttributeType.java +++ b/src/main/java/net/runelite/deob/attributes/AttributeType.java @@ -5,6 +5,7 @@ public enum AttributeType CONSTANT_VALUE("ConstantValue", ConstantValue.class), CODE("Code", Code.class), EXCEPTIONS("Exceptions", Exceptions.class), + RUNTIMEVISIBLEANNOTATIONS("RuntimeVisibleAnnotations", Annotations.class), UNKNOWN(null, Unknown.class); private String name; diff --git a/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java b/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java new file mode 100644 index 0000000000..45dddb2414 --- /dev/null +++ b/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java @@ -0,0 +1,55 @@ +package net.runelite.deob.attributes.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import net.runelite.deob.ConstantPool; +import net.runelite.deob.attributes.Annotations; +import net.runelite.deob.signature.Type; + +public class Annotation +{ + private final Annotations annotations; + private Type type; + private List elements = new ArrayList<>(); + + public Annotation(Annotations annotations) + { + this.annotations = annotations; + } + + public Annotations getAnnotations() + { + return annotations; + } + + public void load(DataInputStream is) throws IOException + { + ConstantPool pool = annotations.getAttributes().getClassFile().getPool(); + + int typeIndex = is.readUnsignedShort(); + type = new Type(pool.getUTF8(typeIndex)); + + int pairs = is.readUnsignedShort(); + for (int i = 0; i < pairs; ++i) + { + Element e = new Element(this); + e.load(is); + elements.add(e); + } + } + + public void write(DataOutputStream out) throws IOException + { + ConstantPool pool = annotations.getAttributes().getClassFile().getPool(); + + out.writeShort(pool.makeUTF8(type.toString())); + out.writeShort(elements.size()); + for (Element e : elements) + { + e.write(out); + } + } +} diff --git a/src/main/java/net/runelite/deob/attributes/annotation/Element.java b/src/main/java/net/runelite/deob/attributes/annotation/Element.java new file mode 100644 index 0000000000..8bd1c8db4f --- /dev/null +++ b/src/main/java/net/runelite/deob/attributes/annotation/Element.java @@ -0,0 +1,45 @@ +package net.runelite.deob.attributes.annotation; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import net.runelite.deob.ConstantPool; +import net.runelite.deob.signature.Type; + +public class Element +{ + private final Annotation annotation; + private Type type; + private String value; + + public Element(Annotation annotation) + { + this.annotation = annotation; + } + + public void load(DataInputStream is) throws IOException + { + ConstantPool pool = annotation.getAnnotations().getAttributes().getClassFile().getPool(); + + int typeIndex = is.readShort(); + type = new Type(pool.getUTF8(typeIndex)); + + byte type = is.readByte(); + + if (type != 's') + throw new RuntimeException("can't parse non string annotation element"); + + int index = is.readShort(); // pool index to String + + value = pool.getUTF8(index); + } + + public void write(DataOutputStream out) throws IOException + { + ConstantPool pool = annotation.getAnnotations().getAttributes().getClassFile().getPool(); + + out.writeShort(pool.makeUTF8(type.toString())); + out.write('s'); + out.writeShort(pool.makeUTF8(value)); + } +} diff --git a/src/test/java/net/runelite/deob/annotations/AnnotationTest.java b/src/test/java/net/runelite/deob/annotations/AnnotationTest.java new file mode 100644 index 0000000000..09c078973f --- /dev/null +++ b/src/test/java/net/runelite/deob/annotations/AnnotationTest.java @@ -0,0 +1,35 @@ +package net.runelite.deob.annotations; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import net.runelite.deob.ClassFile; +import net.runelite.deob.ClassGroup; +import org.junit.Assert; +import org.junit.Test; + +public class AnnotationTest +{ + @Test + public void testAnnotation() throws Exception + { + InputStream in = this.getClass().getClassLoader().getResourceAsStream("net/runelite/deob/annotations/TestClass.class"); + Assert.assertNotNull(in); + + ClassGroup group = new ClassGroup(); + + ClassFile cf = new ClassFile(group, new DataInputStream(in)); + group.addClass(cf); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bout); + cf.write(out); // write it out + + // parse it again + cf = new ClassFile(group, new DataInputStream(new ByteArrayInputStream(bout.toByteArray()))); + + System.out.println(cf); + } +} diff --git a/src/test/java/net/runelite/deob/annotations/MyAnnotation.java b/src/test/java/net/runelite/deob/annotations/MyAnnotation.java new file mode 100644 index 0000000000..a2e61a650a --- /dev/null +++ b/src/test/java/net/runelite/deob/annotations/MyAnnotation.java @@ -0,0 +1,10 @@ +package net.runelite.deob.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface MyAnnotation +{ + String value(); +} diff --git a/src/test/java/net/runelite/deob/annotations/TestClass.java b/src/test/java/net/runelite/deob/annotations/TestClass.java new file mode 100644 index 0000000000..38115c9456 --- /dev/null +++ b/src/test/java/net/runelite/deob/annotations/TestClass.java @@ -0,0 +1,10 @@ +package net.runelite.deob.annotations; + +public class TestClass +{ + @MyAnnotation("field1") + public int field1; + + @MyAnnotation("method1") + public void method1() { } +}