Search in sources :

Example 6 with Annotations

use of net.runelite.asm.attributes.Annotations in project runelite by runelite.

the class AnnotationTest method testAnnotation.

@Test
public void testAnnotation() throws IOException {
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("net/runelite/asm/annotations/TestClass.class");
    Assert.assertNotNull(in);
    ClassGroup group = new ClassGroup();
    ClassFile cf = ClassUtil.loadClass(in);
    group.addClass(cf);
    byte[] out = JarUtil.writeClass(group, cf);
    // parse it again
    cf = ClassUtil.loadClass(new ByteArrayInputStream(out));
    Method method = cf.getMethods().get(1);
    Assert.assertEquals("method1", method.getName());
    Annotations annotations = method.getAnnotations();
    Assert.assertNotNull(annotations);
    Optional<Annotation> annotation = annotations.getAnnotations().stream().filter(a -> a.getType().equals(new Type("Lnet/runelite/asm/annotations/MyAnnotation;"))).findFirst();
    Assert.assertTrue(annotation.isPresent());
    Annotation an = annotation.get();
    List<Element> elements = an.getElements();
    Assert.assertEquals(1, elements.size());
    Element element = elements.get(0);
    Assert.assertEquals("value", element.getName());
    Assert.assertEquals("method1", element.getValue());
}
Also used : Annotations(net.runelite.asm.attributes.Annotations) IOException(java.io.IOException) Test(org.junit.Test) Type(net.runelite.asm.Type) ClassGroup(net.runelite.asm.ClassGroup) JarUtil(net.runelite.deob.util.JarUtil) List(java.util.List) ClassFile(net.runelite.asm.ClassFile) Annotation(net.runelite.asm.attributes.annotation.Annotation) ByteArrayInputStream(java.io.ByteArrayInputStream) Method(net.runelite.asm.Method) ClassUtil(net.runelite.asm.ClassUtil) Element(net.runelite.asm.attributes.annotation.Element) Optional(java.util.Optional) Assert(org.junit.Assert) InputStream(java.io.InputStream) ClassFile(net.runelite.asm.ClassFile) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) Element(net.runelite.asm.attributes.annotation.Element) Method(net.runelite.asm.Method) Annotation(net.runelite.asm.attributes.annotation.Annotation) Type(net.runelite.asm.Type) Annotations(net.runelite.asm.attributes.Annotations) ByteArrayInputStream(java.io.ByteArrayInputStream) ClassGroup(net.runelite.asm.ClassGroup) Test(org.junit.Test)

Example 7 with Annotations

use of net.runelite.asm.attributes.Annotations in project runelite by runelite.

the class Inject method run.

public void run() throws InjectionException {
    Map<ClassFile, java.lang.Class> implemented = new HashMap<>();
    // check below works
    for (ClassFile cf : deobfuscated.getClasses()) {
        Annotations an = cf.getAnnotations();
        if (an == null || an.size() == 0) {
            continue;
        }
        String obfuscatedName = DeobAnnotations.getObfuscatedName(an);
        if (obfuscatedName == null) {
            obfuscatedName = cf.getName();
        }
        ClassFile other = vanilla.findClass(obfuscatedName);
        assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName;
        java.lang.Class implementingClass = injectInterface(cf, other);
        // it can not implement an interface but still have exported static fields, which are
        // moved to client
        implemented.put(cf, implementingClass);
    }
    // requires interfaces to be injected
    mixinInjector.inject();
    construct.inject(implemented);
    for (ClassFile cf : deobfuscated.getClasses()) {
        java.lang.Class implementingClass = implemented.get(cf);
        Annotations an = cf.getAnnotations();
        if (an == null || an.size() == 0) {
            continue;
        }
        String obfuscatedName = DeobAnnotations.getObfuscatedName(an);
        if (obfuscatedName == null) {
            obfuscatedName = cf.getName();
        }
        ClassFile other = vanilla.findClass(obfuscatedName);
        assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName;
        for (Field f : cf.getFields()) {
            an = f.getAnnotations();
            if (an == null || an.find(DeobAnnotations.EXPORT) == null) {
                // not an exported field
                continue;
            }
            Annotation exportAnnotation = an.find(DeobAnnotations.EXPORT);
            String exportedName = exportAnnotation.getElement().getString();
            obfuscatedName = DeobAnnotations.getObfuscatedName(an);
            Annotation getterAnnotation = an.find(DeobAnnotations.OBFUSCATED_GETTER);
            Number getter = null;
            if (getterAnnotation != null) {
                getter = (Number) getterAnnotation.getElement().getValue();
            }
            // the ob jar is the same as the vanilla so this field must exist in this class.
            Type obType = getFieldType(f);
            Field otherf = other.findField(obfuscatedName, obType);
            assert otherf != null;
            assert f.isStatic() == otherf.isStatic();
            // target class for getter
            ClassFile targetClass = f.isStatic() ? vanilla.findClass("client") : other;
            // target api class for getter
            java.lang.Class targetApiClass = f.isStatic() ? CLIENT_CLASS : implementingClass;
            if (targetApiClass == null) {
                assert !f.isStatic();
                // non static field exported on non exported interface
                logger.debug("Non static exported field {} on non exported interface", exportedName);
                continue;
            }
            java.lang.reflect.Method apiMethod = findImportMethodOnApi(targetApiClass, exportedName, true);
            if (apiMethod != null) {
                Number setter = null;
                if (getter != null) {
                    // inverse getter to get the setter
                    setter = DMath.modInverse(getter);
                }
                setters.injectSetter(targetClass, targetApiClass, otherf, exportedName, setter);
            }
            apiMethod = findImportMethodOnApi(targetApiClass, exportedName, false);
            if (apiMethod == null) {
                logger.debug("Unable to find import method on api class {} with imported name {}, not injecting getter", targetApiClass, exportedName);
                continue;
            }
            // check that otherf is converable to apiMethod's
            // return type
            Type fieldType = otherf.getType();
            Type returnType = classToType(apiMethod.getReturnType());
            if (!validateTypeIsConvertibleTo(fieldType, returnType)) {
                throw new InjectionException("Type " + fieldType + " is not convertable to " + returnType + " for getter " + apiMethod);
            }
            getters.injectGetter(targetClass, apiMethod, otherf, getter);
        }
        for (Method m : cf.getMethods()) {
            hookMethod.process(m);
            invokes.process(m, other, implementingClass);
        }
    }
    logger.info("Injected {} getters, {} settters, {} invokers", getters.getInjectedGetters(), setters.getInjectedSetters(), invokes.getInjectedInvokers());
    drawAfterWidgets.inject();
    scriptVM.inject();
}
Also used : ClassFile(net.runelite.asm.ClassFile) HashMap(java.util.HashMap) Method(net.runelite.asm.Method) Annotation(net.runelite.asm.attributes.annotation.Annotation) Field(net.runelite.asm.Field) Type(net.runelite.asm.Type) Annotations(net.runelite.asm.attributes.Annotations) DeobAnnotations(net.runelite.deob.DeobAnnotations) Class(net.runelite.asm.pool.Class)

Example 8 with Annotations

use of net.runelite.asm.attributes.Annotations in project runelite by runelite.

the class Inject method injectInterface.

private java.lang.Class injectInterface(ClassFile cf, ClassFile other) {
    Annotations an = cf.getAnnotations();
    if (an == null) {
        return null;
    }
    Annotation a = an.find(DeobAnnotations.IMPLEMENTS);
    if (a == null) {
        return null;
    }
    String ifaceName = API_PACKAGE_BASE + a.getElement().getString();
    java.lang.Class<?> apiClass;
    try {
        apiClass = java.lang.Class.forName(ifaceName);
    } catch (ClassNotFoundException ex) {
        logger.trace("Class {} implements nonexistent interface {}, skipping interface injection", cf.getName(), ifaceName);
        return null;
    }
    // to internal name
    String ifaceNameInternal = ifaceName.replace('.', '/');
    Class clazz = new Class(ifaceNameInternal);
    Interfaces interfaces = other.getInterfaces();
    interfaces.addInterface(clazz);
    return apiClass;
}
Also used : Interfaces(net.runelite.asm.Interfaces) Annotations(net.runelite.asm.attributes.Annotations) DeobAnnotations(net.runelite.deob.DeobAnnotations) Class(net.runelite.asm.pool.Class) Annotation(net.runelite.asm.attributes.annotation.Annotation)

Example 9 with Annotations

use of net.runelite.asm.attributes.Annotations in project runelite by runelite.

the class InjectInvoker method process.

/**
 * Inject an invoker for a method
 *
 * @param m Method in the deobfuscated client to inject an invoker for
 * @param other Class in the vanilla client of the same class m is a
 * member of
 * @param implementingClass Java class for the API interface the class
 * will implement
 */
public void process(Method m, ClassFile other, java.lang.Class<?> implementingClass) {
    Annotations an = m.getAnnotations();
    if (an == null || an.find(EXPORT) == null) {
        // not an exported method
        return;
    }
    String exportedName = DeobAnnotations.getExportedName(an);
    String obfuscatedName = DeobAnnotations.getObfuscatedName(an);
    if (obfuscatedName == null) {
        obfuscatedName = m.getName();
    }
    String garbage = DeobAnnotations.getObfuscatedValue(m);
    Method otherm = other.findMethod(obfuscatedName, inject.getMethodSignature(m));
    assert otherm != null;
    assert m.isStatic() == otherm.isStatic();
    ClassGroup vanilla = inject.getVanilla();
    ClassFile targetClass = m.isStatic() ? vanilla.findClass("client") : other;
    // Place into implementing class, unless the method is static
    java.lang.Class<?> targetClassJava = m.isStatic() ? Inject.CLIENT_CLASS : implementingClass;
    if (targetClassJava == null) {
        assert !m.isStatic();
        // non static exported method on non exported interface, weird.
        logger.debug("Non static exported method {} on non exported interface", exportedName);
        return;
    }
    // api method to invoke 'otherm'
    java.lang.reflect.Method apiMethod = inject.findImportMethodOnApi(targetClassJava, exportedName, null);
    if (apiMethod == null) {
        logger.debug("Unable to find api method on {} with imported name {}, not injecting invoker", targetClassJava, exportedName);
        return;
    }
    injectInvoker(targetClass, apiMethod, m, otherm, garbage);
    ++injectedInvokers;
}
Also used : Annotations(net.runelite.asm.attributes.Annotations) DeobAnnotations(net.runelite.deob.DeobAnnotations) ClassFile(net.runelite.asm.ClassFile) ClassGroup(net.runelite.asm.ClassGroup) Method(net.runelite.asm.Method)

Aggregations

Annotations (net.runelite.asm.attributes.Annotations)9 ClassFile (net.runelite.asm.ClassFile)6 Method (net.runelite.asm.Method)6 Annotation (net.runelite.asm.attributes.annotation.Annotation)6 DeobAnnotations (net.runelite.deob.DeobAnnotations)5 ClassGroup (net.runelite.asm.ClassGroup)3 Field (net.runelite.asm.Field)2 Type (net.runelite.asm.Type)2 Element (net.runelite.asm.attributes.annotation.Element)2 Class (net.runelite.asm.pool.Class)2 Signature (net.runelite.asm.signature.Signature)2 Test (org.junit.Test)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Optional (java.util.Optional)1 ClassUtil (net.runelite.asm.ClassUtil)1 Interfaces (net.runelite.asm.Interfaces)1