diff --git a/.gitignore b/.gitignore
index d5be5e446a..c99c2fa7a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-/target/
-nbactions.xml
-nb-configuration.xml
+/target/
+nbactions.xml
+nb-configuration.xml
+/nbproject/
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index efe9011dc3..0000000000
--- a/.project
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
- deob
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.jdt.core.javanature
- org.eclipse.m2e.core.maven2Nature
-
-
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index f4217b01dd..0000000000
--- a/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,12 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.7
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.source=1.7
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
deleted file mode 100644
index 14b697b7bb..0000000000
--- a/.settings/org.eclipse.m2e.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-activeProfiles=
-eclipse.preferences.version=1
-resolveWorkspaceProjects=true
-version=1
diff --git a/pom.xml b/pom.xml
index 295625ff7f..e9fd898944 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,8 +51,6 @@
net.runelite.rs
api
1.0-SNAPSHOT
- test
- jar
diff --git a/src/main/java/net/runelite/deob/ClassFile.java b/src/main/java/net/runelite/deob/ClassFile.java
index cdfa6fb1ca..29ae344a3d 100644
--- a/src/main/java/net/runelite/deob/ClassFile.java
+++ b/src/main/java/net/runelite/deob/ClassFile.java
@@ -185,6 +185,11 @@ public class ClassFile
return fields.findField(name);
}
+ public Field findField(NameAndType nat)
+ {
+ return fields.findField(nat);
+ }
+
public Class getPoolClass()
{
return name;
diff --git a/src/main/java/net/runelite/deob/Interfaces.java b/src/main/java/net/runelite/deob/Interfaces.java
index 42503916dd..0d63d27d25 100644
--- a/src/main/java/net/runelite/deob/Interfaces.java
+++ b/src/main/java/net/runelite/deob/Interfaces.java
@@ -30,6 +30,12 @@ public class Interfaces
classFile = c;
}
+ public void addInterface(Class clazz)
+ {
+ if (!interfaces.contains(clazz))
+ interfaces.add(clazz);
+ }
+
public List getInterfaces()
{
return interfaces;
diff --git a/src/main/java/net/runelite/deob/attributes/Annotations.java b/src/main/java/net/runelite/deob/attributes/Annotations.java
index c95e70fa63..55cc079146 100644
--- a/src/main/java/net/runelite/deob/attributes/Annotations.java
+++ b/src/main/java/net/runelite/deob/attributes/Annotations.java
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.runelite.deob.attributes.annotation.Annotation;
+import net.runelite.deob.signature.Type;
public class Annotations extends Attribute
{
@@ -26,6 +27,14 @@ public class Annotations extends Attribute
annotations.add(annotation);
}
+ public Annotation find(Type type)
+ {
+ for (Annotation a : annotations)
+ if (a.getType().equals(type))
+ return a;
+ return null;
+ }
+
@Override
public void loadAttribute(DataInputStream is) throws IOException
{
diff --git a/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java b/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java
index dcd6b51859..4e3e95536e 100644
--- a/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java
+++ b/src/main/java/net/runelite/deob/attributes/annotation/Annotation.java
@@ -40,6 +40,11 @@ public class Annotation
return elements;
}
+ public Element getElement()
+ {
+ return elements.get(0);
+ }
+
public void addElement(Element element)
{
elements.add(element);
diff --git a/src/main/java/net/runelite/deob/attributes/annotation/Element.java b/src/main/java/net/runelite/deob/attributes/annotation/Element.java
index c644994534..150bcb7515 100644
--- a/src/main/java/net/runelite/deob/attributes/annotation/Element.java
+++ b/src/main/java/net/runelite/deob/attributes/annotation/Element.java
@@ -43,6 +43,11 @@ public class Element
this.value = value;
}
+ public String getString()
+ {
+ return (String) value.getObject();
+ }
+
public void load(DataInputStream is) throws IOException
{
ConstantPool pool = annotation.getAnnotations().getAttributes().getClassFile().getPool();
diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java b/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java
index 6ff7a50d28..c88844e5b5 100644
--- a/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java
+++ b/src/main/java/net/runelite/deob/attributes/code/instructions/GetField.java
@@ -30,6 +30,13 @@ public class GetField extends Instruction implements GetFieldInstruction
super(instructions, type, pc);
}
+ public GetField(Instructions instructions, Field field)
+ {
+ super(instructions, InstructionType.GETFIELD, -1);
+
+ this.field = field;
+ }
+
@Override
public String toString()
{
diff --git a/src/main/java/net/runelite/deob/attributes/code/instructions/Return.java b/src/main/java/net/runelite/deob/attributes/code/instructions/Return.java
index b2620d001b..1c929146e3 100644
--- a/src/main/java/net/runelite/deob/attributes/code/instructions/Return.java
+++ b/src/main/java/net/runelite/deob/attributes/code/instructions/Return.java
@@ -9,14 +9,18 @@ import net.runelite.deob.execution.InstructionContext;
import net.runelite.deob.execution.Stack;
import net.runelite.deob.execution.StackContext;
-import java.io.IOException;
public class Return extends Instruction implements ReturnInstruction
{
- public Return(Instructions instructions, InstructionType type, int pc) throws IOException
+ public Return(Instructions instructions, InstructionType type, int pc)
{
super(instructions, type, pc);
}
+
+ public Return(Instructions instructions)
+ {
+ super(instructions, InstructionType.RETURN, -1);
+ }
@Override
public void execute(Frame frame)
diff --git a/src/main/java/net/runelite/deob/injection/Inject.java b/src/main/java/net/runelite/deob/injection/Inject.java
new file mode 100644
index 0000000000..c21d76420c
--- /dev/null
+++ b/src/main/java/net/runelite/deob/injection/Inject.java
@@ -0,0 +1,240 @@
+package net.runelite.deob.injection;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import net.runelite.deob.ClassFile;
+import net.runelite.deob.ClassGroup;
+import net.runelite.deob.Field;
+import net.runelite.deob.Interfaces;
+import net.runelite.deob.Method;
+import net.runelite.deob.attributes.Annotations;
+import net.runelite.deob.attributes.Attributes;
+import net.runelite.deob.attributes.Code;
+import net.runelite.deob.attributes.annotation.Annotation;
+import net.runelite.deob.attributes.code.Instruction;
+import net.runelite.deob.attributes.code.Instructions;
+import net.runelite.deob.attributes.code.instructions.ALoad;
+import net.runelite.deob.attributes.code.instructions.GetField;
+import net.runelite.deob.attributes.code.instructions.GetStatic;
+import net.runelite.deob.attributes.code.instructions.IMul;
+import net.runelite.deob.attributes.code.instructions.LDC2_W;
+import net.runelite.deob.attributes.code.instructions.LDC_W;
+import net.runelite.deob.attributes.code.instructions.LMul;
+import net.runelite.deob.attributes.code.instructions.Return;
+import net.runelite.deob.signature.Type;
+import net.runelite.deob.pool.Class;
+import net.runelite.deob.pool.NameAndType;
+import net.runelite.deob.signature.Signature;
+import net.runelite.mapping.Import;
+
+public class Inject
+{
+ private static final Type OBFUSCATED_NAME = new Type("Lnet/runelite/mapping/ObfuscatedName;");
+ private static final Type EXPORT = new Type("Lnet/runelite/mapping/Export;");
+ private static final Type IMPLEMENTS = new Type("Lnet/runelite/mapping/Implements;");
+ private static final Type OBFUSCATED_GETTER = new Type("Lnet/runelite/mapping/ObfuscatedGetter;");
+
+ private static java.lang.Class> clientClass;
+
+ static
+ {
+ try
+ {
+ clientClass = java.lang.Class.forName("net.runelite.rs.api.Client");
+ }
+ catch (ClassNotFoundException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ // deobfuscated contains exports etc to apply to vanilla
+ private final ClassGroup deobfuscated, vanilla;
+
+ public Inject(ClassGroup deobfuscated, ClassGroup vanilla)
+ {
+ this.deobfuscated = deobfuscated;
+ this.vanilla = vanilla;
+ }
+
+ private Type toObType(Type t)
+ {
+ String className = t.getType();
+ ClassFile cf = deobfuscated.findClass(className);
+
+ Annotations an = cf.getAttributes().getAnnotations();
+ String obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
+ return new Type(obfuscatedName, t.getArrayDims());
+ }
+
+ private Signature toObSignature(Signature s)
+ {
+ Signature sig = new Signature();
+ sig.setTypeOfReturnValue(toObType(s.getReturnValue()));
+ for (Type t : s.getArguments())
+ sig.addArg(toObType(t));
+ return sig;
+ }
+
+ public void run()
+ {
+ for (ClassFile cf : deobfuscated.getClasses())
+ {
+ Annotations an = cf.getAttributes().getAnnotations();
+ String obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
+
+ ClassFile other = vanilla.findClass(obfuscatedName);
+ assert other != null;
+
+ java.lang.Class implementingClass = injectInterface(cf, other);
+ if (implementingClass == null)
+ continue;
+
+ for (Field f : cf.getFields().getFields())
+ {
+ an = f.getAttributes().getAnnotations();
+
+ if (an.find(EXPORT) == null)
+ continue; // not an exported field
+
+ String exportedName = an.find(EXPORT).getElement().toString();
+ obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
+
+ Annotation getterAnnotation = an.find(OBFUSCATED_GETTER);
+ Number getter = null;
+ if (getterAnnotation != null)
+ getter = (Number) getterAnnotation.getElement().getValue().getObject();
+
+ // the ob jar is the same as the vanilla so this field must exist in this class.
+
+ Field otherf = other.findField(new NameAndType(obfuscatedName, toObType(f.getType())));
+ assert otherf != null;
+
+ assert f.isStatic() == otherf.isStatic();
+
+ //
+
+ ClassFile targetClass = f.isStatic() ? vanilla.findClass("client") : other; // target class for getter
+ java.lang.Class targetApiClass = f.isStatic() ? clientClass : implementingClass; // target api class for getter
+
+ java.lang.reflect.Method apiMethod = findImportMethodOnApi(targetApiClass, exportedName);
+
+ injectGetter(targetClass, apiMethod, otherf, getter);
+ }
+
+ for (Method m : cf.getMethods().getMethods())
+ {
+ an = m.getAttributes().getAnnotations();
+
+ if (an.find(EXPORT) == null)
+ continue; // not an exported method
+
+ String exportedName = an.find(EXPORT).getElement().toString();
+ obfuscatedName = an.find(OBFUSCATED_NAME).getElement().toString();
+
+ // XXX static methods don't have to be in the same class, so we should have @ObfuscatedClass or something
+
+ Method otherm = other.findMethod(new NameAndType(obfuscatedName, toObSignature(m.getDescriptor())));
+ assert otherm != null;
+ }
+ }
+ }
+
+ private java.lang.Class injectInterface(ClassFile cf, ClassFile other)
+ {
+ Annotations an = cf.getAttributes().getAnnotations();
+ if (an == null)
+ return null;
+
+ Annotation a = an.find(IMPLEMENTS);
+ if (a == null)
+ return null;
+
+ String ifaceName = a.getElement().toString();
+ Class clazz = new Class(ifaceName);
+
+ Interfaces interfaces = other.getInterfaces();
+ interfaces.addInterface(clazz);
+
+ try
+ {
+ return java.lang.Class.forName(ifaceName);
+ }
+ catch (ClassNotFoundException ex)
+ {
+ ex.addSuppressed(ex);
+ return null;
+ }
+ }
+
+ private java.lang.reflect.Method findImportMethodOnApi(java.lang.Class> clazz, String name)
+ {
+ for (java.lang.reflect.Method method : clazz.getMethods())
+ {
+ Import i = method.getAnnotation(Import.class);
+
+ if (i == null || !name.equals(i.value()))
+ continue;
+
+ return method;
+ }
+
+ return null;
+ }
+
+ private void injectGetter(ClassFile clazz, java.lang.reflect.Method method, Field field, Number getter)
+ {
+ // clazz = class file we're injecting the method into.
+ // method = api method (java reflect) that we're overriding
+ // field = field we're getting. might not be in this class if static.
+ // getter = encryption getter
+
+ assert clazz.findMethod(method.getName()) == null;
+ assert field.isStatic() || field.getFields().getClassFile() == clazz;
+
+ Signature sig = new Signature();
+ sig.setTypeOfReturnValue(field.getType());
+ Method getterMethod = new Method(clazz.getMethods(), method.getName(), sig);
+
+ Attributes methodAttributes = getterMethod.getAttributes();
+
+ // create code attribute
+ Code code = new Code(methodAttributes);
+ methodAttributes.addAttribute(code);
+
+ Instructions instructions = code.getInstructions();
+ List ins = new ArrayList<>();
+
+ if (field.isStatic())
+ {
+ ins.add(new GetStatic(instructions, field.getPoolField()));
+ }
+ else
+ {
+ ins.add(new ALoad(instructions, 0));
+ ins.add(new GetField(instructions, field.getPoolField()));
+ }
+
+ if (getter != null)
+ {
+ assert getter instanceof Integer || getter instanceof Long;
+
+ if (getter instanceof Integer)
+ {
+ ins.add(new LDC_W(instructions, (int) getter));
+ ins.add(new IMul(instructions));
+ }
+ else
+ {
+ ins.add(new LDC2_W(instructions, (long) getter));
+ ins.add(new LMul(instructions));
+ }
+ }
+
+ ins.add(new Return(instructions));
+
+ clazz.getMethods().addMethod(getterMethod);
+ }
+}
diff --git a/src/main/java/net/runelite/deob/signature/Signature.java b/src/main/java/net/runelite/deob/signature/Signature.java
index 8b9ce7fec5..60ed0abeec 100644
--- a/src/main/java/net/runelite/deob/signature/Signature.java
+++ b/src/main/java/net/runelite/deob/signature/Signature.java
@@ -14,6 +14,10 @@ public class Signature
private List arguments = new ArrayList<>();
private Type rv;
+ public Signature()
+ {
+ }
+
public Signature(String str)
{
Matcher m = paramRetPattern.matcher(str);
@@ -90,6 +94,11 @@ public class Signature
arguments.set(i, type);
}
+ public void addArg(Type type)
+ {
+ arguments.add(type);
+ }
+
public Type getReturnValue()
{
return rv;
@@ -99,4 +108,9 @@ public class Signature
{
rv = type;
}
+
+ public List getArguments()
+ {
+ return arguments;
+ }
}