diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt index a7ff6e0258..c7b2b7ebb0 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt @@ -16,6 +16,7 @@ import dev.openrs2.deob.transform.ClassLiteralTransformer import dev.openrs2.deob.transform.CounterTransformer import dev.openrs2.deob.transform.DummyArgTransformer import dev.openrs2.deob.transform.DummyLocalTransformer +import dev.openrs2.deob.transform.EmptyClassTransformer import dev.openrs2.deob.transform.ExceptionTracingTransformer import dev.openrs2.deob.transform.FieldOrderTransformer import dev.openrs2.deob.transform.FinalTransformer @@ -168,6 +169,7 @@ class Deobfuscator(private val input: Path, private val output: Path) { ClassLiteralTransformer(), InvokeSpecialTransformer(), StaticScramblingTransformer(), + EmptyClassTransformer(), VisibilityTransformer(), OverrideTransformer() ) diff --git a/deob/src/main/java/dev/openrs2/deob/transform/EmptyClassTransformer.kt b/deob/src/main/java/dev/openrs2/deob/transform/EmptyClassTransformer.kt new file mode 100644 index 0000000000..8ca24cf2d6 --- /dev/null +++ b/deob/src/main/java/dev/openrs2/deob/transform/EmptyClassTransformer.kt @@ -0,0 +1,95 @@ +package dev.openrs2.deob.transform + +import com.github.michaelbull.logging.InlineLogger +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library +import dev.openrs2.asm.transform.Transformer +import org.objectweb.asm.Opcodes +import org.objectweb.asm.Type +import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.FieldNode +import org.objectweb.asm.tree.LdcInsnNode +import org.objectweb.asm.tree.MethodNode +import org.objectweb.asm.tree.TypeInsnNode + +class EmptyClassTransformer : Transformer() { + private val emptyClasses = mutableSetOf() + private val referencedClasses = mutableSetOf() + + override fun preTransform(classPath: ClassPath) { + emptyClasses.clear() + referencedClasses.clear() + } + + override fun transformClass(classPath: ClassPath, library: Library, clazz: ClassNode): Boolean { + if (clazz.access and Opcodes.ACC_INTERFACE == 0 && clazz.fields.isEmpty() && clazz.methods.isEmpty()) { + emptyClasses.add(clazz.name) + } + + if (clazz.superName != null) { + referencedClasses.add(clazz.superName) + } + + return false + } + + private fun addTypeReference(type: Type) { + when (type.sort) { + Type.OBJECT -> referencedClasses.add(type.internalName) + Type.ARRAY -> addTypeReference(type.elementType) + Type.METHOD -> { + type.argumentTypes.forEach(::addTypeReference) + addTypeReference(type.returnType) + } + } + } + + override fun transformField(classPath: ClassPath, library: Library, clazz: ClassNode, field: FieldNode): Boolean { + addTypeReference(Type.getType(field.desc)) + return false + } + + override fun preTransformMethod( + classPath: ClassPath, + library: Library, + clazz: ClassNode, + method: MethodNode + ): Boolean { + addTypeReference(Type.getType(method.desc)) + return false + } + + override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { + for (insn in method.instructions) { + when (insn) { + is LdcInsnNode -> { + val cst = insn.cst + if (cst is Type) { + addTypeReference(cst) + } + } + is TypeInsnNode -> referencedClasses.add(insn.desc) + } + } + + return false + } + + override fun postTransform(classPath: ClassPath) { + var removed = 0 + + for (name in emptyClasses.subtract(referencedClasses)) { + for (library in classPath.libraries) { + if (library.remove(name) != null) { + removed++ + } + } + } + + logger.info { "Removed $removed unused classes" } + } + + companion object { + private val logger = InlineLogger() + } +}