forked from openrs2/openrs2
parent
e4fe120bf7
commit
0b3f24fed2
@ -1,323 +0,0 @@ |
|||||||
package dev.openrs2.asm; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
import java.util.stream.Stream; |
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList; |
|
||||||
import com.google.common.collect.ImmutableMap; |
|
||||||
import org.objectweb.asm.Opcodes; |
|
||||||
import org.objectweb.asm.tree.AbstractInsnNode; |
|
||||||
import org.objectweb.asm.tree.InsnList; |
|
||||||
import org.objectweb.asm.tree.MethodNode; |
|
||||||
import org.objectweb.asm.util.Printer; |
|
||||||
|
|
||||||
public final class InsnMatcher { |
|
||||||
private static final int PRIVATE_USE_AREA = 0xE000; |
|
||||||
private static final ImmutableMap<String, int[]> OPCODE_GROUPS = ImmutableMap.<String, int[]>builder() |
|
||||||
.put("InsnNode", new int[] { |
|
||||||
Opcodes.NOP, |
|
||||||
Opcodes.ACONST_NULL, |
|
||||||
Opcodes.ICONST_M1, |
|
||||||
Opcodes.ICONST_0, |
|
||||||
Opcodes.ICONST_1, |
|
||||||
Opcodes.ICONST_2, |
|
||||||
Opcodes.ICONST_3, |
|
||||||
Opcodes.ICONST_4, |
|
||||||
Opcodes.ICONST_5, |
|
||||||
Opcodes.LCONST_0, |
|
||||||
Opcodes.LCONST_1, |
|
||||||
Opcodes.FCONST_0, |
|
||||||
Opcodes.FCONST_1, |
|
||||||
Opcodes.FCONST_2, |
|
||||||
Opcodes.DCONST_0, |
|
||||||
Opcodes.DCONST_1, |
|
||||||
Opcodes.IALOAD, |
|
||||||
Opcodes.LALOAD, |
|
||||||
Opcodes.FALOAD, |
|
||||||
Opcodes.DALOAD, |
|
||||||
Opcodes.AALOAD, |
|
||||||
Opcodes.BALOAD, |
|
||||||
Opcodes.CALOAD, |
|
||||||
Opcodes.SALOAD, |
|
||||||
Opcodes.IASTORE, |
|
||||||
Opcodes.LASTORE, |
|
||||||
Opcodes.FASTORE, |
|
||||||
Opcodes.DASTORE, |
|
||||||
Opcodes.AASTORE, |
|
||||||
Opcodes.BASTORE, |
|
||||||
Opcodes.CASTORE, |
|
||||||
Opcodes.SASTORE, |
|
||||||
Opcodes.POP, |
|
||||||
Opcodes.POP2, |
|
||||||
Opcodes.DUP, |
|
||||||
Opcodes.DUP_X1, |
|
||||||
Opcodes.DUP_X2, |
|
||||||
Opcodes.DUP2, |
|
||||||
Opcodes.DUP2_X1, |
|
||||||
Opcodes.DUP2_X2, |
|
||||||
Opcodes.SWAP, |
|
||||||
Opcodes.IADD, |
|
||||||
Opcodes.LADD, |
|
||||||
Opcodes.FADD, |
|
||||||
Opcodes.DADD, |
|
||||||
Opcodes.ISUB, |
|
||||||
Opcodes.LSUB, |
|
||||||
Opcodes.FSUB, |
|
||||||
Opcodes.DSUB, |
|
||||||
Opcodes.IMUL, |
|
||||||
Opcodes.LMUL, |
|
||||||
Opcodes.FMUL, |
|
||||||
Opcodes.DMUL, |
|
||||||
Opcodes.IDIV, |
|
||||||
Opcodes.LDIV, |
|
||||||
Opcodes.FDIV, |
|
||||||
Opcodes.DDIV, |
|
||||||
Opcodes.IREM, |
|
||||||
Opcodes.LREM, |
|
||||||
Opcodes.FREM, |
|
||||||
Opcodes.DREM, |
|
||||||
Opcodes.INEG, |
|
||||||
Opcodes.LNEG, |
|
||||||
Opcodes.FNEG, |
|
||||||
Opcodes.DNEG, |
|
||||||
Opcodes.ISHL, |
|
||||||
Opcodes.LSHL, |
|
||||||
Opcodes.ISHR, |
|
||||||
Opcodes.LSHR, |
|
||||||
Opcodes.IUSHR, |
|
||||||
Opcodes.LUSHR, |
|
||||||
Opcodes.IAND, |
|
||||||
Opcodes.LAND, |
|
||||||
Opcodes.IOR, |
|
||||||
Opcodes.LOR, |
|
||||||
Opcodes.IXOR, |
|
||||||
Opcodes.LXOR, |
|
||||||
Opcodes.I2L, |
|
||||||
Opcodes.I2F, |
|
||||||
Opcodes.I2D, |
|
||||||
Opcodes.L2I, |
|
||||||
Opcodes.L2F, |
|
||||||
Opcodes.L2D, |
|
||||||
Opcodes.F2I, |
|
||||||
Opcodes.F2L, |
|
||||||
Opcodes.F2D, |
|
||||||
Opcodes.D2I, |
|
||||||
Opcodes.D2L, |
|
||||||
Opcodes.D2F, |
|
||||||
Opcodes.I2B, |
|
||||||
Opcodes.I2C, |
|
||||||
Opcodes.I2S, |
|
||||||
Opcodes.LCMP, |
|
||||||
Opcodes.FCMPL, |
|
||||||
Opcodes.FCMPG, |
|
||||||
Opcodes.DCMPL, |
|
||||||
Opcodes.DCMPG, |
|
||||||
Opcodes.IRETURN, |
|
||||||
Opcodes.LRETURN, |
|
||||||
Opcodes.FRETURN, |
|
||||||
Opcodes.DRETURN, |
|
||||||
Opcodes.ARETURN, |
|
||||||
Opcodes.RETURN, |
|
||||||
Opcodes.ARRAYLENGTH, |
|
||||||
Opcodes.ATHROW, |
|
||||||
Opcodes.MONITORENTER, |
|
||||||
Opcodes.MONITOREXIT |
|
||||||
}) |
|
||||||
.put("IntInsnNode", new int[] { |
|
||||||
Opcodes.BIPUSH, |
|
||||||
Opcodes.SIPUSH, |
|
||||||
Opcodes.NEWARRAY |
|
||||||
}) |
|
||||||
.put("VarInsnNode", new int[] { |
|
||||||
Opcodes.ILOAD, |
|
||||||
Opcodes.LLOAD, |
|
||||||
Opcodes.FLOAD, |
|
||||||
Opcodes.DLOAD, |
|
||||||
Opcodes.ALOAD, |
|
||||||
Opcodes.ISTORE, |
|
||||||
Opcodes.LSTORE, |
|
||||||
Opcodes.FSTORE, |
|
||||||
Opcodes.DSTORE, |
|
||||||
Opcodes.ASTORE, |
|
||||||
Opcodes.RET |
|
||||||
}) |
|
||||||
.put("TypeInsnNode", new int[] { |
|
||||||
Opcodes.NEW, |
|
||||||
Opcodes.ANEWARRAY, |
|
||||||
Opcodes.CHECKCAST, |
|
||||||
Opcodes.INSTANCEOF |
|
||||||
}) |
|
||||||
.put("FieldInsnNode", new int[] { |
|
||||||
Opcodes.GETSTATIC, |
|
||||||
Opcodes.PUTSTATIC, |
|
||||||
Opcodes.GETFIELD, |
|
||||||
Opcodes.PUTFIELD |
|
||||||
}) |
|
||||||
.put("MethodInsnNode", new int[] { |
|
||||||
Opcodes.INVOKEVIRTUAL, |
|
||||||
Opcodes.INVOKESPECIAL, |
|
||||||
Opcodes.INVOKESTATIC, |
|
||||||
Opcodes.INVOKEINTERFACE |
|
||||||
}) |
|
||||||
.put("InvokeDynamicInsnNode", new int[] { |
|
||||||
Opcodes.INVOKEDYNAMIC |
|
||||||
}) |
|
||||||
.put("JumpInsnNode", new int[] { |
|
||||||
Opcodes.IFEQ, |
|
||||||
Opcodes.IFNE, |
|
||||||
Opcodes.IFLT, |
|
||||||
Opcodes.IFGE, |
|
||||||
Opcodes.IFGT, |
|
||||||
Opcodes.IFLE, |
|
||||||
Opcodes.IF_ICMPEQ, |
|
||||||
Opcodes.IF_ICMPNE, |
|
||||||
Opcodes.IF_ICMPLT, |
|
||||||
Opcodes.IF_ICMPGE, |
|
||||||
Opcodes.IF_ICMPGT, |
|
||||||
Opcodes.IF_ICMPLE, |
|
||||||
Opcodes.IF_ACMPEQ, |
|
||||||
Opcodes.IF_ACMPNE, |
|
||||||
Opcodes.GOTO, |
|
||||||
Opcodes.JSR, |
|
||||||
Opcodes.IFNULL, |
|
||||||
Opcodes.IFNONNULL |
|
||||||
}) |
|
||||||
.put("LdcInsnNode", new int[] { |
|
||||||
Opcodes.LDC |
|
||||||
}) |
|
||||||
.put("IincInsnNode", new int[] { |
|
||||||
Opcodes.IINC |
|
||||||
}) |
|
||||||
.put("TableSwitchInsnNode", new int[] { |
|
||||||
Opcodes.TABLESWITCH |
|
||||||
}) |
|
||||||
.put("LookupSwitchInsnNode", new int[] { |
|
||||||
Opcodes.LOOKUPSWITCH |
|
||||||
}) |
|
||||||
.put("MultiANewArrayInsnNode", new int[] { |
|
||||||
Opcodes.MULTIANEWARRAY |
|
||||||
}) |
|
||||||
.put("ICONST", new int[] { |
|
||||||
Opcodes.ICONST_M1, |
|
||||||
Opcodes.ICONST_0, |
|
||||||
Opcodes.ICONST_1, |
|
||||||
Opcodes.ICONST_2, |
|
||||||
Opcodes.ICONST_3, |
|
||||||
Opcodes.ICONST_4, |
|
||||||
Opcodes.ICONST_5 |
|
||||||
}) |
|
||||||
.put("FCONST", new int[] { |
|
||||||
Opcodes.FCONST_0, |
|
||||||
Opcodes.FCONST_1, |
|
||||||
Opcodes.FCONST_2 |
|
||||||
}) |
|
||||||
.put("DCONST", new int[] { |
|
||||||
Opcodes.DCONST_0, |
|
||||||
Opcodes.DCONST_1 |
|
||||||
}) |
|
||||||
.build(); |
|
||||||
|
|
||||||
private static char opcodeToCodepoint(int opcode) { |
|
||||||
return (char) (PRIVATE_USE_AREA + opcode); |
|
||||||
} |
|
||||||
|
|
||||||
private static List<AbstractInsnNode> createRealInsnList(InsnList list) { |
|
||||||
List<AbstractInsnNode> realInsns = new ArrayList<>(); |
|
||||||
for (var insn : list) { |
|
||||||
if (insn.getOpcode() != -1) { |
|
||||||
realInsns.add(insn); |
|
||||||
} |
|
||||||
} |
|
||||||
return realInsns; |
|
||||||
} |
|
||||||
|
|
||||||
private static String createCodepointSeq(List<AbstractInsnNode> insns) { |
|
||||||
var codepoints = new char[insns.size()]; |
|
||||||
for (var i = 0; i < codepoints.length; i++) { |
|
||||||
codepoints[i] = opcodeToCodepoint(insns.get(i).getOpcode()); |
|
||||||
} |
|
||||||
return new String(codepoints); |
|
||||||
} |
|
||||||
|
|
||||||
public static InsnMatcher compile(String expr) { |
|
||||||
var pattern = new StringBuilder(); |
|
||||||
var opcode = new StringBuilder(); |
|
||||||
|
|
||||||
for (var i = 0; i < expr.length(); i++) { |
|
||||||
var c = expr.charAt(i); |
|
||||||
if (Character.isLetterOrDigit(c) || c == '_') { |
|
||||||
opcode.append(c); |
|
||||||
} else { |
|
||||||
if (opcode.length() > 0) { |
|
||||||
appendOpcodeRegex(pattern, opcode.toString()); |
|
||||||
opcode.delete(0, opcode.length()); |
|
||||||
} |
|
||||||
|
|
||||||
if (!Character.isWhitespace(c)) { |
|
||||||
pattern.append(c); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (opcode.length() > 0) { |
|
||||||
appendOpcodeRegex(pattern, opcode.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
return new InsnMatcher(Pattern.compile(pattern.toString())); |
|
||||||
} |
|
||||||
|
|
||||||
private static void appendOpcodeRegex(StringBuilder pattern, String opcode) { |
|
||||||
for (var i = 0; i < Printer.OPCODES.length; i++) { |
|
||||||
if (opcode.equals(Printer.OPCODES[i])) { |
|
||||||
pattern.append(opcodeToCodepoint(i)); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var group = OPCODE_GROUPS.get(opcode); |
|
||||||
if (group != null) { |
|
||||||
pattern.append('('); |
|
||||||
for (var i = 0; i < group.length; i++) { |
|
||||||
pattern.append(opcodeToCodepoint(group[i])); |
|
||||||
if (i != group.length - 1) { |
|
||||||
pattern.append('|'); |
|
||||||
} |
|
||||||
} |
|
||||||
pattern.append(')'); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (opcode.equals("AbstractInsnNode")) { |
|
||||||
pattern.append('.'); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
throw new IllegalArgumentException(opcode + " is not a valid opcode or opcode group"); |
|
||||||
} |
|
||||||
|
|
||||||
private final Pattern pattern; |
|
||||||
|
|
||||||
private InsnMatcher(Pattern pattern) { |
|
||||||
this.pattern = pattern; |
|
||||||
} |
|
||||||
|
|
||||||
public Stream<ImmutableList<AbstractInsnNode>> match(MethodNode method) { |
|
||||||
return match(method.instructions); |
|
||||||
} |
|
||||||
|
|
||||||
public Stream<ImmutableList<AbstractInsnNode>> match(InsnList list) { |
|
||||||
Stream.Builder<ImmutableList<AbstractInsnNode>> matches = Stream.builder(); |
|
||||||
|
|
||||||
var insns = createRealInsnList(list); |
|
||||||
var matcher = pattern.matcher(createCodepointSeq(insns)); |
|
||||||
while (matcher.find()) { |
|
||||||
var start = matcher.start(); |
|
||||||
var end = matcher.end(); |
|
||||||
matches.add(ImmutableList.copyOf(insns.subList(start, end))); |
|
||||||
} |
|
||||||
|
|
||||||
return matches.build(); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,286 @@ |
|||||||
|
package dev.openrs2.asm |
||||||
|
|
||||||
|
import org.objectweb.asm.Opcodes |
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode |
||||||
|
import org.objectweb.asm.tree.InsnList |
||||||
|
import org.objectweb.asm.tree.MethodNode |
||||||
|
import org.objectweb.asm.util.Printer |
||||||
|
import java.util.stream.Stream |
||||||
|
import kotlin.streams.asStream |
||||||
|
|
||||||
|
class InsnMatcher private constructor(private val regex: Regex) { |
||||||
|
// TODO(gpe): use Sequence<T> when the rest of the deobfuscator is ported to Kotlin |
||||||
|
fun match(method: MethodNode): Stream<List<AbstractInsnNode>> { |
||||||
|
return match(method.instructions) |
||||||
|
} |
||||||
|
|
||||||
|
fun match(list: InsnList): Stream<List<AbstractInsnNode>> { |
||||||
|
val insns = list.filter { it.opcode != -1 }.toList() |
||||||
|
val codepoints = insns.map { opcodeToCodepoint(it.opcode) }.toCharArray() |
||||||
|
return regex.findAll(String(codepoints)).map { |
||||||
|
insns.subList(it.range.first, it.range.last + 1) |
||||||
|
}.asStream() |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
private const val PRIVATE_USE_AREA = 0xE000 |
||||||
|
private val OPCODE_GROUPS = mapOf( |
||||||
|
"InsnNode" to intArrayOf( |
||||||
|
Opcodes.NOP, |
||||||
|
Opcodes.ACONST_NULL, |
||||||
|
Opcodes.ICONST_M1, |
||||||
|
Opcodes.ICONST_0, |
||||||
|
Opcodes.ICONST_1, |
||||||
|
Opcodes.ICONST_2, |
||||||
|
Opcodes.ICONST_3, |
||||||
|
Opcodes.ICONST_4, |
||||||
|
Opcodes.ICONST_5, |
||||||
|
Opcodes.LCONST_0, |
||||||
|
Opcodes.LCONST_1, |
||||||
|
Opcodes.FCONST_0, |
||||||
|
Opcodes.FCONST_1, |
||||||
|
Opcodes.FCONST_2, |
||||||
|
Opcodes.DCONST_0, |
||||||
|
Opcodes.DCONST_1, |
||||||
|
Opcodes.IALOAD, |
||||||
|
Opcodes.LALOAD, |
||||||
|
Opcodes.FALOAD, |
||||||
|
Opcodes.DALOAD, |
||||||
|
Opcodes.AALOAD, |
||||||
|
Opcodes.BALOAD, |
||||||
|
Opcodes.CALOAD, |
||||||
|
Opcodes.SALOAD, |
||||||
|
Opcodes.IASTORE, |
||||||
|
Opcodes.LASTORE, |
||||||
|
Opcodes.FASTORE, |
||||||
|
Opcodes.DASTORE, |
||||||
|
Opcodes.AASTORE, |
||||||
|
Opcodes.BASTORE, |
||||||
|
Opcodes.CASTORE, |
||||||
|
Opcodes.SASTORE, |
||||||
|
Opcodes.POP, |
||||||
|
Opcodes.POP2, |
||||||
|
Opcodes.DUP, |
||||||
|
Opcodes.DUP_X1, |
||||||
|
Opcodes.DUP_X2, |
||||||
|
Opcodes.DUP2, |
||||||
|
Opcodes.DUP2_X1, |
||||||
|
Opcodes.DUP2_X2, |
||||||
|
Opcodes.SWAP, |
||||||
|
Opcodes.IADD, |
||||||
|
Opcodes.LADD, |
||||||
|
Opcodes.FADD, |
||||||
|
Opcodes.DADD, |
||||||
|
Opcodes.ISUB, |
||||||
|
Opcodes.LSUB, |
||||||
|
Opcodes.FSUB, |
||||||
|
Opcodes.DSUB, |
||||||
|
Opcodes.IMUL, |
||||||
|
Opcodes.LMUL, |
||||||
|
Opcodes.FMUL, |
||||||
|
Opcodes.DMUL, |
||||||
|
Opcodes.IDIV, |
||||||
|
Opcodes.LDIV, |
||||||
|
Opcodes.FDIV, |
||||||
|
Opcodes.DDIV, |
||||||
|
Opcodes.IREM, |
||||||
|
Opcodes.LREM, |
||||||
|
Opcodes.FREM, |
||||||
|
Opcodes.DREM, |
||||||
|
Opcodes.INEG, |
||||||
|
Opcodes.LNEG, |
||||||
|
Opcodes.FNEG, |
||||||
|
Opcodes.DNEG, |
||||||
|
Opcodes.ISHL, |
||||||
|
Opcodes.LSHL, |
||||||
|
Opcodes.ISHR, |
||||||
|
Opcodes.LSHR, |
||||||
|
Opcodes.IUSHR, |
||||||
|
Opcodes.LUSHR, |
||||||
|
Opcodes.IAND, |
||||||
|
Opcodes.LAND, |
||||||
|
Opcodes.IOR, |
||||||
|
Opcodes.LOR, |
||||||
|
Opcodes.IXOR, |
||||||
|
Opcodes.LXOR, |
||||||
|
Opcodes.I2L, |
||||||
|
Opcodes.I2F, |
||||||
|
Opcodes.I2D, |
||||||
|
Opcodes.L2I, |
||||||
|
Opcodes.L2F, |
||||||
|
Opcodes.L2D, |
||||||
|
Opcodes.F2I, |
||||||
|
Opcodes.F2L, |
||||||
|
Opcodes.F2D, |
||||||
|
Opcodes.D2I, |
||||||
|
Opcodes.D2L, |
||||||
|
Opcodes.D2F, |
||||||
|
Opcodes.I2B, |
||||||
|
Opcodes.I2C, |
||||||
|
Opcodes.I2S, |
||||||
|
Opcodes.LCMP, |
||||||
|
Opcodes.FCMPL, |
||||||
|
Opcodes.FCMPG, |
||||||
|
Opcodes.DCMPL, |
||||||
|
Opcodes.DCMPG, |
||||||
|
Opcodes.IRETURN, |
||||||
|
Opcodes.LRETURN, |
||||||
|
Opcodes.FRETURN, |
||||||
|
Opcodes.DRETURN, |
||||||
|
Opcodes.ARETURN, |
||||||
|
Opcodes.RETURN, |
||||||
|
Opcodes.ARRAYLENGTH, |
||||||
|
Opcodes.ATHROW, |
||||||
|
Opcodes.MONITORENTER, |
||||||
|
Opcodes.MONITOREXIT |
||||||
|
), |
||||||
|
"IntInsnNode" to intArrayOf( |
||||||
|
Opcodes.BIPUSH, |
||||||
|
Opcodes.SIPUSH, |
||||||
|
Opcodes.NEWARRAY |
||||||
|
), |
||||||
|
"VarInsnNode" to intArrayOf( |
||||||
|
Opcodes.ILOAD, |
||||||
|
Opcodes.LLOAD, |
||||||
|
Opcodes.FLOAD, |
||||||
|
Opcodes.DLOAD, |
||||||
|
Opcodes.ALOAD, |
||||||
|
Opcodes.ISTORE, |
||||||
|
Opcodes.LSTORE, |
||||||
|
Opcodes.FSTORE, |
||||||
|
Opcodes.DSTORE, |
||||||
|
Opcodes.ASTORE, |
||||||
|
Opcodes.RET |
||||||
|
), |
||||||
|
"TypeInsnNode" to intArrayOf( |
||||||
|
Opcodes.NEW, |
||||||
|
Opcodes.ANEWARRAY, |
||||||
|
Opcodes.CHECKCAST, |
||||||
|
Opcodes.INSTANCEOF |
||||||
|
), |
||||||
|
"FieldInsnNode" to intArrayOf( |
||||||
|
Opcodes.GETSTATIC, |
||||||
|
Opcodes.PUTSTATIC, |
||||||
|
Opcodes.GETFIELD, |
||||||
|
Opcodes.PUTFIELD |
||||||
|
), |
||||||
|
"MethodInsnNode" to intArrayOf( |
||||||
|
Opcodes.INVOKEVIRTUAL, |
||||||
|
Opcodes.INVOKESPECIAL, |
||||||
|
Opcodes.INVOKESTATIC, |
||||||
|
Opcodes.INVOKEINTERFACE |
||||||
|
), |
||||||
|
"InvokeDynamicInsnNode" to intArrayOf( |
||||||
|
Opcodes.INVOKEDYNAMIC |
||||||
|
), |
||||||
|
"JumpInsnNode" to intArrayOf( |
||||||
|
Opcodes.IFEQ, |
||||||
|
Opcodes.IFNE, |
||||||
|
Opcodes.IFLT, |
||||||
|
Opcodes.IFGE, |
||||||
|
Opcodes.IFGT, |
||||||
|
Opcodes.IFLE, |
||||||
|
Opcodes.IF_ICMPEQ, |
||||||
|
Opcodes.IF_ICMPNE, |
||||||
|
Opcodes.IF_ICMPLT, |
||||||
|
Opcodes.IF_ICMPGE, |
||||||
|
Opcodes.IF_ICMPGT, |
||||||
|
Opcodes.IF_ICMPLE, |
||||||
|
Opcodes.IF_ACMPEQ, |
||||||
|
Opcodes.IF_ACMPNE, |
||||||
|
Opcodes.GOTO, |
||||||
|
Opcodes.JSR, |
||||||
|
Opcodes.IFNULL, |
||||||
|
Opcodes.IFNONNULL |
||||||
|
), |
||||||
|
"LdcInsnNode" to intArrayOf( |
||||||
|
Opcodes.LDC |
||||||
|
), |
||||||
|
"IincInsnNode" to intArrayOf( |
||||||
|
Opcodes.IINC |
||||||
|
), |
||||||
|
"TableSwitchInsnNode" to intArrayOf( |
||||||
|
Opcodes.TABLESWITCH |
||||||
|
), |
||||||
|
"LookupSwitchInsnNode" to intArrayOf( |
||||||
|
Opcodes.LOOKUPSWITCH |
||||||
|
), |
||||||
|
"MultiANewArrayInsnNode" to intArrayOf( |
||||||
|
Opcodes.MULTIANEWARRAY |
||||||
|
), |
||||||
|
"ICONST" to intArrayOf( |
||||||
|
Opcodes.ICONST_M1, |
||||||
|
Opcodes.ICONST_0, |
||||||
|
Opcodes.ICONST_1, |
||||||
|
Opcodes.ICONST_2, |
||||||
|
Opcodes.ICONST_3, |
||||||
|
Opcodes.ICONST_4, |
||||||
|
Opcodes.ICONST_5 |
||||||
|
), |
||||||
|
"FCONST" to intArrayOf( |
||||||
|
Opcodes.FCONST_0, |
||||||
|
Opcodes.FCONST_1, |
||||||
|
Opcodes.FCONST_2 |
||||||
|
), |
||||||
|
"DCONST" to intArrayOf( |
||||||
|
Opcodes.DCONST_0, |
||||||
|
Opcodes.DCONST_1 |
||||||
|
) |
||||||
|
) |
||||||
|
|
||||||
|
private fun opcodeToCodepoint(opcode: Int): Char { |
||||||
|
return (PRIVATE_USE_AREA + opcode).toChar() |
||||||
|
} |
||||||
|
|
||||||
|
private fun appendOpcodeRegex(pattern: StringBuilder, opcode: String) { |
||||||
|
val i = Printer.OPCODES.indexOf(opcode) |
||||||
|
if (i != -1) { |
||||||
|
pattern.append(opcodeToCodepoint(i)) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
val group = OPCODE_GROUPS[opcode] |
||||||
|
if (group != null) { |
||||||
|
pattern.append('(') |
||||||
|
group.map { opcodeToCodepoint(it) }.joinTo(pattern, "|") |
||||||
|
pattern.append(')') |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (opcode == "AbstractInsnNode") { |
||||||
|
pattern.append('.') |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
throw IllegalArgumentException("$opcode is not a valid opcode or opcode group") |
||||||
|
} |
||||||
|
|
||||||
|
@JvmStatic |
||||||
|
fun compile(regex: String): InsnMatcher { |
||||||
|
val pattern = StringBuilder() |
||||||
|
val opcode = StringBuilder() |
||||||
|
|
||||||
|
for (c in regex) { |
||||||
|
if (c.isLetterOrDigit() || c == '_') { |
||||||
|
opcode.append(c) |
||||||
|
} else { |
||||||
|
if (opcode.isNotEmpty()) { |
||||||
|
appendOpcodeRegex(pattern, opcode.toString()) |
||||||
|
opcode.delete(0, opcode.length) |
||||||
|
} |
||||||
|
|
||||||
|
if (!c.isWhitespace()) { |
||||||
|
pattern.append(c) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (opcode.isNotEmpty()) { |
||||||
|
appendOpcodeRegex(pattern, opcode.toString()) |
||||||
|
opcode.delete(0, opcode.length) |
||||||
|
} |
||||||
|
|
||||||
|
return InsnMatcher(Regex(pattern.toString())) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue