summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/source/cfr
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/source/cfr')
-rw-r--r--src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java108
-rw-r--r--src/main/java/cuchaz/enigma/source/cfr/CfrSource.java38
-rw-r--r--src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java433
3 files changed, 0 insertions, 579 deletions
diff --git a/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
deleted file mode 100644
index 9e37f16..0000000
--- a/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
+++ /dev/null
@@ -1,108 +0,0 @@
1package cuchaz.enigma.source.cfr;
2
3import com.google.common.io.ByteStreams;
4import cuchaz.enigma.ClassProvider;
5import cuchaz.enigma.source.Decompiler;
6import cuchaz.enigma.source.Source;
7import cuchaz.enigma.source.SourceSettings;
8import org.benf.cfr.reader.apiunreleased.ClassFileSource2;
9import org.benf.cfr.reader.apiunreleased.JarContent;
10import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
11import org.benf.cfr.reader.entities.ClassFile;
12import org.benf.cfr.reader.mapping.MappingFactory;
13import org.benf.cfr.reader.mapping.ObfuscationMapping;
14import org.benf.cfr.reader.relationship.MemberNameResolver;
15import org.benf.cfr.reader.state.DCCommonState;
16import org.benf.cfr.reader.state.TypeUsageCollectingDumper;
17import org.benf.cfr.reader.util.AnalysisType;
18import org.benf.cfr.reader.util.CannotLoadClassException;
19import org.benf.cfr.reader.util.collections.ListFactory;
20import org.benf.cfr.reader.util.getopt.Options;
21import org.benf.cfr.reader.util.getopt.OptionsImpl;
22import org.objectweb.asm.ClassWriter;
23import org.objectweb.asm.tree.ClassNode;
24
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.Collection;
28import java.util.HashMap;
29import java.util.Map;
30
31
32public class CfrDecompiler implements Decompiler {
33 private final DCCommonState state;
34
35 public CfrDecompiler(ClassProvider classProvider, SourceSettings sourceSettings) {
36 Map<String, String> options = new HashMap<>();
37
38 state = new DCCommonState(OptionsImpl.getFactory().create(options), new ClassFileSource2() {
39 @Override
40 public JarContent addJarContent(String s, AnalysisType analysisType) {
41 return null;
42 }
43
44 @Override
45 public void informAnalysisRelativePathDetail(String usePath, String classFilePath) {
46
47 }
48
49 @Override
50 public Collection<String> addJar(String jarPath) {
51 return null;
52 }
53
54 @Override
55 public String getPossiblyRenamedPath(String path) {
56 return path;
57 }
58
59 @Override
60 public Pair<byte[], String> getClassFileContent(String path) {
61 ClassNode node = classProvider.getClassNode(path.substring(0, path.lastIndexOf('.')));
62
63 if (node == null) {
64 try (InputStream classResource = CfrDecompiler.class.getClassLoader().getResourceAsStream(path)) {
65 if (classResource != null) {
66 return new Pair<>(ByteStreams.toByteArray(classResource), path);
67 }
68 } catch (IOException ignored) {}
69
70 return null;
71 }
72
73 ClassWriter cw = new ClassWriter(0);
74 node.accept(cw);
75 return new Pair<>(cw.toByteArray(), path);
76 }
77 });
78 }
79
80 @Override
81 public Source getSource(String className) {
82 DCCommonState state = this.state;
83 Options options = state.getOptions();
84
85 ObfuscationMapping mapping = MappingFactory.get(options, state);
86 state = new DCCommonState(state, mapping);
87 ClassFile tree = state.getClassFileMaybePath(className);
88
89 state.configureWith(tree);
90
91 // To make sure we're analysing the cached version
92 try {
93 tree = state.getClassFile(tree.getClassType());
94 } catch (CannotLoadClassException ignored) {}
95
96 if (options.getOption(OptionsImpl.DECOMPILE_INNER_CLASSES)) {
97 tree.loadInnerClasses(state);
98 }
99
100 if (options.getOption(OptionsImpl.RENAME_DUP_MEMBERS)) {
101 MemberNameResolver.resolveNames(state, ListFactory.newList(state.getClassCache().getLoadedTypes()));
102 }
103
104 TypeUsageCollectingDumper typeUsageCollector = new TypeUsageCollectingDumper(options, tree);
105 tree.analyseTop(state, typeUsageCollector);
106 return new CfrSource(tree, state, typeUsageCollector.getRealTypeUsageInformation());
107 }
108}
diff --git a/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java b/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java
deleted file mode 100644
index d4f2da6..0000000
--- a/src/main/java/cuchaz/enigma/source/cfr/CfrSource.java
+++ /dev/null
@@ -1,38 +0,0 @@
1package cuchaz.enigma.source.cfr;
2
3import cuchaz.enigma.source.Source;
4import cuchaz.enigma.source.SourceIndex;
5import cuchaz.enigma.translation.mapping.EntryRemapper;
6import org.benf.cfr.reader.entities.ClassFile;
7import org.benf.cfr.reader.state.DCCommonState;
8import org.benf.cfr.reader.state.TypeUsageInformation;
9
10public class CfrSource implements Source {
11 private final ClassFile tree;
12 private final SourceIndex index;
13 private final String string;
14
15 public CfrSource(ClassFile tree, DCCommonState state, TypeUsageInformation typeUsages) {
16 this.tree = tree;
17
18 EnigmaDumper dumper = new EnigmaDumper(typeUsages);
19 tree.dump(state.getObfuscationMapping().wrap(dumper));
20 index = dumper.getIndex();
21 string = dumper.getString();
22 }
23
24 @Override
25 public String asString() {
26 return string;
27 }
28
29 @Override
30 public Source addJavadocs(EntryRemapper remapper) {
31 return this; // TODO
32 }
33
34 @Override
35 public SourceIndex index() {
36 return index;
37 }
38}
diff --git a/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java b/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java
deleted file mode 100644
index 09e0a9b..0000000
--- a/src/main/java/cuchaz/enigma/source/cfr/EnigmaDumper.java
+++ /dev/null
@@ -1,433 +0,0 @@
1package cuchaz.enigma.source.cfr;
2
3import cuchaz.enigma.analysis.Token;
4import cuchaz.enigma.source.SourceIndex;
5import cuchaz.enigma.translation.representation.MethodDescriptor;
6import cuchaz.enigma.translation.representation.TypeDescriptor;
7import cuchaz.enigma.translation.representation.entry.*;
8import org.benf.cfr.reader.bytecode.analysis.types.*;
9import org.benf.cfr.reader.bytecode.analysis.variables.NamedVariable;
10import org.benf.cfr.reader.entities.Field;
11import org.benf.cfr.reader.entities.Method;
12import org.benf.cfr.reader.mapping.NullMapping;
13import org.benf.cfr.reader.mapping.ObfuscationMapping;
14import org.benf.cfr.reader.state.TypeUsageInformation;
15import org.benf.cfr.reader.util.collections.SetFactory;
16import org.benf.cfr.reader.util.output.DelegatingDumper;
17import org.benf.cfr.reader.util.output.Dumpable;
18import org.benf.cfr.reader.util.output.Dumper;
19import org.benf.cfr.reader.util.output.TypeContext;
20
21import java.util.Set;
22import java.util.stream.Collectors;
23
24public class EnigmaDumper implements Dumper {
25 private int outputCount = 0;
26 private int indent;
27 private boolean atStart = true;
28 private boolean pendingCR = false;
29 private final StringBuilder sb = new StringBuilder();
30 private final TypeUsageInformation typeUsageInformation;
31 private final Set<JavaTypeInstance> emitted = SetFactory.newSet();
32 private final SourceIndex index = new SourceIndex();
33 private int position;
34
35
36 public EnigmaDumper(TypeUsageInformation typeUsageInformation) {
37 this.typeUsageInformation = typeUsageInformation;
38 }
39
40 private void append(String s) {
41 sb.append(s);
42 position += s.length();
43 }
44
45 private String getDesc(JavaTypeInstance type) {
46 if (!type.isUsableType() && type != RawJavaType.VOID) {
47 throw new IllegalArgumentException(type.toString());
48 }
49
50 if (type instanceof JavaGenericBaseInstance) {
51 return getDesc(type.getDeGenerifiedType());
52 }
53
54 if (type instanceof JavaRefTypeInstance) {
55 return "L" + type.getRawName().replace('.', '/') + ";";
56 }
57
58 if (type instanceof JavaArrayTypeInstance) {
59 return "[" + getDesc(((JavaArrayTypeInstance) type).removeAnArrayIndirection());
60 }
61
62 if (type instanceof RawJavaType) {
63 switch ((RawJavaType) type) {
64 case BOOLEAN:
65 return "Z";
66 case BYTE:
67 return "B";
68 case CHAR:
69 return "C";
70 case SHORT:
71 return "S";
72 case INT:
73 return "I";
74 case LONG:
75 return "J";
76 case FLOAT:
77 return "F";
78 case DOUBLE:
79 return "D";
80 case VOID:
81 return "V";
82 default:
83 throw new AssertionError();
84 }
85 }
86
87 throw new AssertionError();
88 }
89
90 private MethodEntry getMethodEntry(MethodPrototype method) {
91 if (method == null || method.getClassType() == null) {
92 return null;
93 }
94
95 MethodDescriptor desc = new MethodDescriptor(
96 method.getArgs().stream().map(type -> new TypeDescriptor(getDesc(type))).collect(Collectors.toList()),
97 new TypeDescriptor(method.getName().equals("<init>") || method.getName().equals("<clinit>") ? "V" : getDesc(method.getReturnType()))
98 );
99
100 return new MethodEntry(getClassEntry(method.getClassType()), method.getName(), desc);
101 }
102
103 private LocalVariableEntry getParameterEntry(MethodPrototype method, int parameterIndex, String name) {
104 int variableIndex = method.isInstanceMethod() ? 1 : 0;
105 for (int i = 0; i < parameterIndex; i++) {
106 variableIndex += method.getArgs().get(i).getStackType().getComputationCategory();
107 }
108
109 return new LocalVariableEntry(getMethodEntry(method), variableIndex, name, true, null);
110 }
111
112 private FieldEntry getFieldEntry(JavaTypeInstance owner, String name, JavaTypeInstance type) {
113 return new FieldEntry(getClassEntry(owner), name, new TypeDescriptor(getDesc(type)));
114 }
115
116 private ClassEntry getClassEntry(JavaTypeInstance type) {
117 return new ClassEntry(type.getRawName().replace('.', '/'));
118 }
119
120 @Override
121 public Dumper beginBlockComment(boolean inline) {
122 print("/*").newln();
123 return this;
124 }
125
126 @Override
127 public Dumper endBlockComment() {
128 print(" */").newln();
129 return this;
130 }
131
132 @Override
133 public Dumper label(String s, boolean inline) {
134 processPendingCR();
135 append(s);
136 append(":");
137 return this;
138 }
139
140 @Override
141 public Dumper comment(String s) {
142 append("// ");
143 append(s);
144 append("\n");
145 return this;
146 }
147
148 @Override
149 public void enqueuePendingCarriageReturn() {
150 pendingCR = true;
151 }
152
153 @Override
154 public Dumper removePendingCarriageReturn() {
155 pendingCR = false;
156 return this;
157 }
158
159 private void processPendingCR() {
160 if (pendingCR) {
161 append("\n");
162 atStart = true;
163 pendingCR = false;
164 }
165 }
166
167 @Override
168 public Dumper identifier(String s, Object ref, boolean defines) {
169 return print(s);
170 }
171
172 @Override
173 public Dumper methodName(String name, MethodPrototype method, boolean special, boolean defines) {
174 doIndent();
175 Token token = new Token(position, position + name.length(), name);
176 Entry<?> entry = getMethodEntry(method);
177
178 if (entry != null) {
179 if (defines) {
180 index.addDeclaration(token, entry);
181 } else {
182 index.addReference(token, entry, null);
183 }
184 }
185
186 return identifier(name, null, defines);
187 }
188
189 @Override
190 public Dumper parameterName(String name, MethodPrototype method, int index, boolean defines) {
191 doIndent();
192 Token token = new Token(position, position + name.length(), name);
193 Entry<?> entry = getParameterEntry(method, index, name);
194
195 if (entry != null) {
196 if (defines) {
197 this.index.addDeclaration(token, entry);
198 } else {
199 this.index.addReference(token, entry, null);
200 }
201 }
202
203 return identifier(name, null, defines);
204 }
205
206 @Override
207 public Dumper variableName(String name, NamedVariable variable, boolean defines) {
208 return identifier(name, null, defines);
209 }
210
211 @Override
212 public Dumper packageName(JavaRefTypeInstance t) {
213 String s = t.getPackageName();
214
215 if (!s.isEmpty()) {
216 keyword("package ").print(s).endCodeln().newln();
217 }
218
219 return this;
220 }
221
222 @Override
223 public Dumper fieldName(String name, Field field, JavaTypeInstance owner, boolean hiddenDeclaration, boolean defines) {
224 doIndent();
225 Token token = new Token(position, position + name.length(), name);
226 Entry<?> entry = field == null ? null : getFieldEntry(owner, name, field.getJavaTypeInstance());
227
228 if (entry != null) {
229 if (defines) {
230 index.addDeclaration(token, entry);
231 } else {
232 index.addReference(token, entry, null);
233 }
234 }
235
236 identifier(name, null, defines);
237 return this;
238 }
239
240 @Override
241 public Dumper print(String s) {
242 processPendingCR();
243 doIndent();
244 append(s);
245 atStart = s.endsWith("\n");
246 outputCount++;
247 return this;
248 }
249
250 @Override
251 public Dumper print(char c) {
252 return print(String.valueOf(c));
253 }
254
255 @Override
256 public Dumper newln() {
257 append("\n");
258 atStart = true;
259 outputCount++;
260 return this;
261 }
262
263 @Override
264 public Dumper endCodeln() {
265 append(";\n");
266 atStart = true;
267 outputCount++;
268 return this;
269 }
270
271 @Override
272 public Dumper keyword(String s) {
273 print(s);
274 return this;
275 }
276
277 @Override
278 public Dumper operator(String s) {
279 print(s);
280 return this;
281 }
282
283 @Override
284 public Dumper separator(String s) {
285 print(s);
286 return this;
287 }
288
289 @Override
290 public Dumper literal(String s, Object o) {
291 print(s);
292 return this;
293 }
294
295 private void doIndent() {
296 if (!atStart) return;
297 String indents = " ";
298
299 for (int x = 0; x < indent; ++x) {
300 append(indents);
301 }
302
303 atStart = false;
304 }
305
306 @Override
307 public void indent(int diff) {
308 indent += diff;
309 }
310
311 @Override
312 public Dumper dump(Dumpable d) {
313 if (d == null) {
314 keyword("null");
315 return this;
316 }
317
318 d.dump(this);
319 return this;
320 }
321
322 @Override
323 public TypeUsageInformation getTypeUsageInformation() {
324 return typeUsageInformation;
325 }
326
327 @Override
328 public ObfuscationMapping getObfuscationMapping() {
329 return NullMapping.INSTANCE;
330 }
331
332 @Override
333 public String toString() {
334 return sb.toString();
335 }
336
337 @Override
338 public void addSummaryError(Method method, String s) {}
339
340 @Override
341 public void close() {
342 }
343
344 @Override
345 public boolean canEmitClass(JavaTypeInstance type) {
346 return emitted.add(type);
347 }
348
349 @Override
350 public int getOutputCount() {
351 return outputCount;
352 }
353
354 @Override
355 public Dumper dump(JavaTypeInstance type) {
356 return dump(type, TypeContext.None, false);
357 }
358
359 @Override
360 public Dumper dump(JavaTypeInstance type, boolean defines) {
361 return dump(type, TypeContext.None, false);
362 }
363
364 @Override
365 public Dumper dump(JavaTypeInstance type, TypeContext context) {
366 return dump(type, context, false);
367 }
368
369 private Dumper dump(JavaTypeInstance type, TypeContext context, boolean defines) {
370 doIndent();
371 if (type instanceof JavaRefTypeInstance) {
372 int start = position;
373 type.dumpInto(this, typeUsageInformation, TypeContext.None);
374 int end = position;
375 Token token = new Token(start, end, sb.toString().substring(start, end));
376
377 if (defines) {
378 index.addDeclaration(token, getClassEntry(type));
379 } else {
380 index.addReference(token, getClassEntry(type), null);
381 }
382
383 return this;
384 }
385
386 type.dumpInto(this, typeUsageInformation, context);
387 return this;
388 }
389
390 @Override
391 public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) {
392 return new WithTypeUsageInformationDumper(this, innerclassTypeUsageInformation);
393 }
394
395 public SourceIndex getIndex() {
396 index.setSource(getString());
397 return index;
398 }
399
400 public String getString() {
401 return sb.toString();
402 }
403
404 public static class WithTypeUsageInformationDumper extends DelegatingDumper {
405 private final TypeUsageInformation typeUsageInformation;
406
407 WithTypeUsageInformationDumper(Dumper delegate, TypeUsageInformation typeUsageInformation) {
408 super(delegate);
409 this.typeUsageInformation = typeUsageInformation;
410 }
411
412 @Override
413 public TypeUsageInformation getTypeUsageInformation() {
414 return typeUsageInformation;
415 }
416
417 @Override
418 public Dumper dump(JavaTypeInstance javaTypeInstance) {
419 return dump(javaTypeInstance, TypeContext.None);
420 }
421
422 @Override
423 public Dumper dump(JavaTypeInstance javaTypeInstance, TypeContext typeContext) {
424 javaTypeInstance.dumpInto(this, typeUsageInformation, typeContext);
425 return this;
426 }
427
428 @Override
429 public Dumper withTypeUsageInformation(TypeUsageInformation innerclassTypeUsageInformation) {
430 return new WithTypeUsageInformationDumper(delegate, innerclassTypeUsageInformation);
431 }
432 }
433}