Skip to content

Commit 46a3f2c

Browse files
committed
properly obf interface methods (probably)
1 parent 3f096ff commit 46a3f2c

File tree

1 file changed

+81
-37
lines changed

1 file changed

+81
-37
lines changed

src/main/java/com/cleanroommc/groovyscript/sandbox/mapper/GroovyDeobfMapper.java

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap;
66
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
77
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
8-
import org.apache.commons.lang3.tuple.Pair;
8+
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
99
import org.codehaus.groovy.ast.ClassHelper;
1010
import org.codehaus.groovy.ast.ClassNode;
1111
import org.codehaus.groovy.ast.Parameter;
@@ -15,11 +15,8 @@
1515
import java.io.BufferedReader;
1616
import java.io.InputStream;
1717
import java.io.InputStreamReader;
18-
import java.util.ArrayList;
19-
import java.util.Arrays;
20-
import java.util.List;
21-
import java.util.Map;
22-
import java.util.stream.Collectors;
18+
import java.util.*;
19+
import java.util.function.Function;
2320

2421
public class GroovyDeobfMapper {
2522

@@ -113,23 +110,60 @@ public static Map<String, String> getDeobfFields(Class<?> clazz) {
113110

114111
public static String getObfuscatedMethodName(ClassNode receiver, String method, Parameter[] args) {
115112
ClassNode objClass = ClassHelper.OBJECT_TYPE;
116-
Map<String, MethodInfo> obfNames;
117-
String obfName = null;
113+
Set<String> searched = new ObjectOpenHashSet<>();
114+
String obfName;
118115

119116
do {
120-
obfNames = OBF_METHOD_NAMES.get(receiver.getName());
121-
if (obfNames != null) {
122-
MethodInfo methodInfo = obfNames.get(method);
123-
if (methodInfo != null) {
124-
obfName = methodInfo.findMethod(args);
125-
}
117+
obfName = getObfMethodInClass(receiver, method, args);
118+
if (obfName == null) {
119+
searched.add(receiver.getName());
120+
obfName = forAllInterfaces(receiver, searched, i -> getObfMethodInClass(i, method, args));
126121
}
127122
receiver = receiver.getSuperClass();
128123
} while (obfName == null && receiver != null && receiver != objClass);
129124

130125
return obfName;
131126
}
132127

128+
private static <T> T forAllInterfaces(ClassNode clz, Set<String> searched, Function<ClassNode, T> consumer) {
129+
ClassNode[] interfaces = clz.getInterfaces();
130+
if (interfaces == null || interfaces.length == 0) return null;
131+
List<ClassNode> queue = new ArrayList<>();
132+
Collections.addAll(queue, interfaces);
133+
while (!queue.isEmpty()) {
134+
ClassNode current = queue.remove(0);
135+
T t = consumer.apply(current);
136+
if (t != null) return t;
137+
ClassNode superClass = current.getSuperClass();
138+
if (superClass != null && !searched.contains(superClass.getName())) {
139+
queue.add(superClass); // idk if interfaces can have super classes or if its counted as interfaces everytime
140+
searched.add(superClass.getName());
141+
}
142+
interfaces = current.getInterfaces();
143+
if (interfaces != null) {
144+
for (ClassNode i : interfaces) {
145+
if (!searched.contains(i.getName())) {
146+
queue.add(i);
147+
searched.add(i.getName());
148+
}
149+
}
150+
}
151+
}
152+
return null;
153+
}
154+
155+
@Nullable
156+
private static String getObfMethodInClass(ClassNode clz, String method, Parameter[] args) {
157+
Map<String, MethodInfo> obfNames = OBF_METHOD_NAMES.get(clz.getName());
158+
if (obfNames != null) {
159+
MethodInfo methodInfo = obfNames.get(method);
160+
if (methodInfo != null) {
161+
return methodInfo.findMethod(args);
162+
}
163+
}
164+
return null;
165+
}
166+
133167
public static String getObfuscatedFieldName(Class<?> receiver, String field) {
134168
Class<Object> objClass = Object.class;
135169
Map<String, String> obfNames;
@@ -149,8 +183,8 @@ public static String getObfuscatedFieldName(Class<?> receiver, String field) {
149183
private static class MethodInfo {
150184

151185
private final String deobfName;
152-
//private Object2ObjectOpenCustomHashMap<Object[], String> obfNames;
153-
private List<Pair<String[], String>> obfNames;
186+
private List<String> obfNames;
187+
private List<String[]> obfArgs;
154188
private final String defObfName;
155189
private final String defArgs;
156190

@@ -163,35 +197,45 @@ private MethodInfo(String deobfName, String defObfName, String defArgs) {
163197
public void registerOverloadedMethod(String obfName, String args) {
164198
if (obfName.equals(defObfName)) return;
165199
if (obfNames == null) {
166-
//obfNames = new Object2ObjectOpenCustomHashMap<>(PARAM_HASH_STRATEGY);
167-
//obfNames.put(makeClassArray(defArgs), defObfName);
168200
obfNames = new ArrayList<>();
169-
obfNames.add(Pair.of(makeClassArray(defArgs), defObfName));
201+
obfArgs = new ArrayList<>();
202+
obfNames.add(defObfName);
203+
obfArgs.add(makeClassArray(defArgs));
170204
}
171-
obfNames.add(Pair.of(makeClassArray(args), obfName));
205+
obfNames.add(obfName);
206+
obfArgs.add(makeClassArray(args));
172207
}
173208

209+
@Nullable
174210
public String findMethod(Parameter[] args) {
175211
if (this.obfNames == null) {
176212
return this.defObfName;
177213
}
178-
List<String> results = this.obfNames.stream()
179-
.filter(pair -> pair.getKey().length == args.length)
180-
.filter(pair -> {
181-
for (int i = 0; i < args.length; i++) {
182-
String origParam = pair.getKey()[i];
183-
if (!matches(origParam, args[i])) {
184-
return false;
185-
}
186-
}
187-
return true;
188-
})
189-
.map(Pair::getValue)
190-
.collect(Collectors.toList());
191-
if (results.isEmpty()) return null;
192-
if (results.size() == 1) return results.get(0);
193-
GroovyLog.get().errorMC("Multiple methods match the name {} and params {}", this.deobfName, Arrays.toString(args));
194-
return results.get(0);
214+
String result = null;
215+
for (int i = 0; i < this.obfNames.size(); i++) {
216+
String obfName = this.obfNames.get(i);
217+
String[] obfArgs = this.obfArgs.get(i);
218+
if (matches(obfArgs, args)) {
219+
if (result == null) {
220+
result = obfName;
221+
} else {
222+
GroovyLog.get().errorMC("Multiple methods match the name {} and params {}", this.deobfName, Arrays.toString(args));
223+
return result;
224+
}
225+
}
226+
}
227+
return result;
228+
}
229+
230+
public static boolean matches(String[] original, Parameter[] parameters) {
231+
if (original.length != parameters.length) return false;
232+
for (int j = 0; j < parameters.length; j++) {
233+
String origParam = original[j];
234+
if (!matches(origParam, parameters[j])) {
235+
return false;
236+
}
237+
}
238+
return true;
195239
}
196240

197241
public static boolean matches(String original, Parameter param) {

0 commit comments

Comments
 (0)