summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Runemoro2020-07-06 06:34:10 -0400
committerGravatar GitHub2020-07-06 12:34:10 +0200
commitf0885819aeeb2edbfcfc0b23566cccb571166a02 (patch)
treed650aa68641fdfd9cc5f5ed0093229d1840506d8
parentFix "Mark as Deobfuscated" menu entry not working... this time without breaki... (diff)
downloadenigma-f0885819aeeb2edbfcfc0b23566cccb571166a02.tar.gz
enigma-f0885819aeeb2edbfcfc0b23566cccb571166a02.tar.xz
enigma-f0885819aeeb2edbfcfc0b23566cccb571166a02.zip
Make class loading more flexible (#277)
-rw-r--r--enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java3
-rw-r--r--enigma-cli/src/main/java/cuchaz/enigma/command/Command.java3
-rw-r--r--enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java16
-rw-r--r--enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java3
-rw-r--r--enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java3
-rw-r--r--enigma/src/main/java/cuchaz/enigma/ClassProvider.java10
-rw-r--r--enigma/src/main/java/cuchaz/enigma/Enigma.java19
-rw-r--r--enigma/src/main/java/cuchaz/enigma/EnigmaProject.java40
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java3
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/ClassCache.java126
-rw-r--r--enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java24
-rw-r--r--enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java15
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java17
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java36
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java17
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java27
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java31
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java64
-rw-r--r--enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java85
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java2
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java20
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java23
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java33
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java38
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java140
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java38
-rw-r--r--enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java20
-rw-r--r--enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java20
-rw-r--r--enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java10
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestDeobfed.java27
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java5
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java13
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java10
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java13
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java9
-rw-r--r--enigma/src/test/java/cuchaz/enigma/TokenChecker.java9
-rw-r--r--enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java3
37 files changed, 440 insertions, 535 deletions
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java
index e4deef8b..75ef225a 100644
--- a/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java
+++ b/enigma-cli/src/main/java/cuchaz/enigma/command/CheckMappingsCommand.java
@@ -4,6 +4,7 @@ import cuchaz.enigma.Enigma;
4import cuchaz.enigma.EnigmaProject; 4import cuchaz.enigma.EnigmaProject;
5import cuchaz.enigma.ProgressListener; 5import cuchaz.enigma.ProgressListener;
6import cuchaz.enigma.analysis.index.JarIndex; 6import cuchaz.enigma.analysis.index.JarIndex;
7import cuchaz.enigma.classprovider.ClasspathClassProvider;
7import cuchaz.enigma.translation.mapping.EntryMapping; 8import cuchaz.enigma.translation.mapping.EntryMapping;
8import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 9import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
9import cuchaz.enigma.translation.mapping.serde.MappingFormat; 10import cuchaz.enigma.translation.mapping.serde.MappingFormat;
@@ -39,7 +40,7 @@ public class CheckMappingsCommand extends Command {
39 40
40 System.out.println("Reading JAR..."); 41 System.out.println("Reading JAR...");
41 42
42 EnigmaProject project = enigma.openJar(fileJarIn, ProgressListener.none()); 43 EnigmaProject project = enigma.openJar(fileJarIn, new ClasspathClassProvider(), ProgressListener.none());
43 44
44 System.out.println("Reading mappings..."); 45 System.out.println("Reading mappings...");
45 46
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java b/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java
index 0640e3e7..0d71f028 100644
--- a/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java
+++ b/enigma-cli/src/main/java/cuchaz/enigma/command/Command.java
@@ -3,6 +3,7 @@ package cuchaz.enigma.command;
3import cuchaz.enigma.Enigma; 3import cuchaz.enigma.Enigma;
4import cuchaz.enigma.EnigmaProject; 4import cuchaz.enigma.EnigmaProject;
5import cuchaz.enigma.ProgressListener; 5import cuchaz.enigma.ProgressListener;
6import cuchaz.enigma.classprovider.ClasspathClassProvider;
6import cuchaz.enigma.translation.mapping.EntryMapping; 7import cuchaz.enigma.translation.mapping.EntryMapping;
7import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 8import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
8import cuchaz.enigma.translation.mapping.serde.MappingFormat; 9import cuchaz.enigma.translation.mapping.serde.MappingFormat;
@@ -34,7 +35,7 @@ public abstract class Command {
34 Enigma enigma = Enigma.create(); 35 Enigma enigma = Enigma.create();
35 36
36 System.out.println("Reading jar..."); 37 System.out.println("Reading jar...");
37 EnigmaProject project = enigma.openJar(fileJarIn, progress); 38 EnigmaProject project = enigma.openJar(fileJarIn, new ClasspathClassProvider(), progress);
38 39
39 if (fileMappings != null) { 40 if (fileMappings != null) {
40 System.out.println("Reading mappings..."); 41 System.out.println("Reading mappings...");
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java
index 292de192..94f70100 100644
--- a/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java
+++ b/enigma-cli/src/main/java/cuchaz/enigma/command/MapSpecializedMethodsCommand.java
@@ -1,14 +1,15 @@
1package cuchaz.enigma.command; 1package cuchaz.enigma.command;
2 2
3import cuchaz.enigma.ProgressListener; 3import cuchaz.enigma.ProgressListener;
4import cuchaz.enigma.analysis.ClassCache;
5import cuchaz.enigma.analysis.index.BridgeMethodIndex; 4import cuchaz.enigma.analysis.index.BridgeMethodIndex;
6import cuchaz.enigma.analysis.index.JarIndex; 5import cuchaz.enigma.analysis.index.JarIndex;
7import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat; 6import cuchaz.enigma.classprovider.CachingClassProvider;
8import cuchaz.enigma.translation.mapping.serde.MappingParseException; 7import cuchaz.enigma.classprovider.JarClassProvider;
9import cuchaz.enigma.translation.MappingTranslator; 8import cuchaz.enigma.translation.MappingTranslator;
10import cuchaz.enigma.translation.Translator; 9import cuchaz.enigma.translation.Translator;
11import cuchaz.enigma.translation.mapping.*; 10import cuchaz.enigma.translation.mapping.EntryMapping;
11import cuchaz.enigma.translation.mapping.serde.MappingFileNameFormat;
12import cuchaz.enigma.translation.mapping.serde.MappingParseException;
12import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters; 13import cuchaz.enigma.translation.mapping.serde.MappingSaveParameters;
13import cuchaz.enigma.translation.mapping.tree.EntryTree; 14import cuchaz.enigma.translation.mapping.tree.EntryTree;
14import cuchaz.enigma.translation.mapping.tree.EntryTreeNode; 15import cuchaz.enigma.translation.mapping.tree.EntryTreeNode;
@@ -45,8 +46,11 @@ public class MapSpecializedMethodsCommand extends Command {
45 MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF); 46 MappingSaveParameters saveParameters = new MappingSaveParameters(MappingFileNameFormat.BY_DEOBF);
46 EntryTree<EntryMapping> source = MappingCommandsUtil.read(sourceFormat, sourcePath, saveParameters); 47 EntryTree<EntryMapping> source = MappingCommandsUtil.read(sourceFormat, sourcePath, saveParameters);
47 EntryTree<EntryMapping> result = new HashEntryTree<>(); 48 EntryTree<EntryMapping> result = new HashEntryTree<>();
48 ClassCache classCache = ClassCache.of(jar); 49
49 JarIndex jarIndex = classCache.index(ProgressListener.none()); 50 JarClassProvider jcp = new JarClassProvider(jar);
51 JarIndex jarIndex = JarIndex.empty();
52 jarIndex.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none());
53
50 BridgeMethodIndex bridgeMethodIndex = jarIndex.getBridgeMethodIndex(); 54 BridgeMethodIndex bridgeMethodIndex = jarIndex.getBridgeMethodIndex();
51 Translator translator = new MappingTranslator(source, jarIndex.getEntryResolver()); 55 Translator translator = new MappingTranslator(source, jarIndex.getEntryResolver());
52 56
diff --git a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java
index 924302f3..41f08342 100644
--- a/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java
+++ b/enigma-server/src/main/java/cuchaz/enigma/network/DedicatedEnigmaServer.java
@@ -2,6 +2,7 @@ package cuchaz.enigma.network;
2 2
3import com.google.common.io.MoreFiles; 3import com.google.common.io.MoreFiles;
4import cuchaz.enigma.*; 4import cuchaz.enigma.*;
5import cuchaz.enigma.classprovider.ClasspathClassProvider;
5import cuchaz.enigma.translation.mapping.serde.MappingParseException; 6import cuchaz.enigma.translation.mapping.serde.MappingParseException;
6import cuchaz.enigma.translation.mapping.EntryRemapper; 7import cuchaz.enigma.translation.mapping.EntryRemapper;
7import cuchaz.enigma.translation.mapping.serde.MappingFormat; 8import cuchaz.enigma.translation.mapping.serde.MappingFormat;
@@ -108,7 +109,7 @@ public class DedicatedEnigmaServer extends EnigmaServer {
108 EnigmaProfile profile = EnigmaProfile.read(profileFile); 109 EnigmaProfile profile = EnigmaProfile.read(profileFile);
109 Enigma enigma = Enigma.builder().setProfile(profile).build(); 110 Enigma enigma = Enigma.builder().setProfile(profile).build();
110 System.out.println("Indexing Jar..."); 111 System.out.println("Indexing Jar...");
111 EnigmaProject project = enigma.openJar(jar, ProgressListener.none()); 112 EnigmaProject project = enigma.openJar(jar, new ClasspathClassProvider(), ProgressListener.none());
112 113
113 MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY; 114 MappingFormat mappingFormat = MappingFormat.ENIGMA_DIRECTORY;
114 EntryRemapper mappings; 115 EntryRemapper mappings;
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
index 66a21b00..2dc1d77a 100644
--- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -34,6 +34,7 @@ import cuchaz.enigma.EnigmaProfile;
34import cuchaz.enigma.EnigmaProject; 34import cuchaz.enigma.EnigmaProject;
35import cuchaz.enigma.analysis.*; 35import cuchaz.enigma.analysis.*;
36import cuchaz.enigma.api.service.ObfuscationTestService; 36import cuchaz.enigma.api.service.ObfuscationTestService;
37import cuchaz.enigma.classprovider.ClasspathClassProvider;
37import cuchaz.enigma.classhandle.ClassHandle; 38import cuchaz.enigma.classhandle.ClassHandle;
38import cuchaz.enigma.classhandle.ClassHandleProvider; 39import cuchaz.enigma.classhandle.ClassHandleProvider;
39import cuchaz.enigma.gui.config.Config; 40import cuchaz.enigma.gui.config.Config;
@@ -95,7 +96,7 @@ public class GuiController implements ClientPacketHandler {
95 this.gui.onStartOpenJar(); 96 this.gui.onStartOpenJar();
96 97
97 return ProgressDialog.runOffThread(gui.getFrame(), progress -> { 98 return ProgressDialog.runOffThread(gui.getFrame(), progress -> {
98 project = enigma.openJar(jarPath, progress); 99 project = enigma.openJar(jarPath, new ClasspathClassProvider(), progress);
99 indexTreeBuilder = new IndexTreeBuilder(project.getJarIndex()); 100 indexTreeBuilder = new IndexTreeBuilder(project.getJarIndex());
100 chp = new ClassHandleProvider(project, Config.getInstance().decompiler.service); 101 chp = new ClassHandleProvider(project, Config.getInstance().decompiler.service);
101 gui.onFinishOpenJar(jarPath.getFileName().toString()); 102 gui.onFinishOpenJar(jarPath.getFileName().toString());
diff --git a/enigma/src/main/java/cuchaz/enigma/ClassProvider.java b/enigma/src/main/java/cuchaz/enigma/ClassProvider.java
deleted file mode 100644
index 2b913792..00000000
--- a/enigma/src/main/java/cuchaz/enigma/ClassProvider.java
+++ /dev/null
@@ -1,10 +0,0 @@
1package cuchaz.enigma;
2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable;
6
7public interface ClassProvider {
8 @Nullable
9 ClassNode getClassNode(String name);
10}
diff --git a/enigma/src/main/java/cuchaz/enigma/Enigma.java b/enigma/src/main/java/cuchaz/enigma/Enigma.java
index 73c9a090..2e9be34f 100644
--- a/enigma/src/main/java/cuchaz/enigma/Enigma.java
+++ b/enigma/src/main/java/cuchaz/enigma/Enigma.java
@@ -13,7 +13,6 @@ package cuchaz.enigma;
13 13
14import com.google.common.base.Preconditions; 14import com.google.common.base.Preconditions;
15import com.google.common.collect.ImmutableListMultimap; 15import com.google.common.collect.ImmutableListMultimap;
16import cuchaz.enigma.analysis.ClassCache;
17import cuchaz.enigma.analysis.index.JarIndex; 16import cuchaz.enigma.analysis.index.JarIndex;
18import cuchaz.enigma.api.EnigmaPlugin; 17import cuchaz.enigma.api.EnigmaPlugin;
19import cuchaz.enigma.api.EnigmaPluginContext; 18import cuchaz.enigma.api.EnigmaPluginContext;
@@ -21,6 +20,10 @@ import cuchaz.enigma.api.service.EnigmaService;
21import cuchaz.enigma.api.service.EnigmaServiceFactory; 20import cuchaz.enigma.api.service.EnigmaServiceFactory;
22import cuchaz.enigma.api.service.EnigmaServiceType; 21import cuchaz.enigma.api.service.EnigmaServiceType;
23import cuchaz.enigma.api.service.JarIndexerService; 22import cuchaz.enigma.api.service.JarIndexerService;
23import cuchaz.enigma.classprovider.CachingClassProvider;
24import cuchaz.enigma.classprovider.ClassProvider;
25import cuchaz.enigma.classprovider.CombiningClassProvider;
26import cuchaz.enigma.classprovider.JarClassProvider;
24import cuchaz.enigma.utils.Utils; 27import cuchaz.enigma.utils.Utils;
25import org.objectweb.asm.Opcodes; 28import org.objectweb.asm.Opcodes;
26 29
@@ -28,6 +31,7 @@ import java.io.IOException;
28import java.nio.file.Path; 31import java.nio.file.Path;
29import java.util.List; 32import java.util.List;
30import java.util.ServiceLoader; 33import java.util.ServiceLoader;
34import java.util.Set;
31 35
32public class Enigma { 36public class Enigma {
33 public static final String NAME = "Enigma"; 37 public static final String NAME = "Enigma";
@@ -51,13 +55,16 @@ public class Enigma {
51 return new Builder(); 55 return new Builder();
52 } 56 }
53 57
54 public EnigmaProject openJar(Path path, ProgressListener progress) throws IOException { 58 public EnigmaProject openJar(Path path, ClassProvider libraryClassProvider, ProgressListener progress) throws IOException {
55 ClassCache classCache = ClassCache.of(path); 59 JarClassProvider jarClassProvider = new JarClassProvider(path);
56 JarIndex jarIndex = classCache.index(progress); 60 ClassProvider classProvider = new CachingClassProvider(new CombiningClassProvider(jarClassProvider, libraryClassProvider));
61 Set<String> scope = jarClassProvider.getClassNames();
57 62
58 services.get(JarIndexerService.TYPE).forEach(indexer -> indexer.acceptJar(classCache, jarIndex)); 63 JarIndex index = JarIndex.empty();
64 index.indexJar(scope, classProvider, progress);
65 services.get(JarIndexerService.TYPE).forEach(indexer -> indexer.acceptJar(scope, classProvider, index));
59 66
60 return new EnigmaProject(this, classCache, jarIndex, Utils.zipSha1(path)); 67 return new EnigmaProject(this, classProvider, index, Utils.zipSha1(path));
61 } 68 }
62 69
63 public EnigmaProfile getProfile() { 70 public EnigmaProfile getProfile() {
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
index 43ea14ed..3999572f 100644
--- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
+++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java
@@ -2,16 +2,20 @@ package cuchaz.enigma;
2 2
3import com.google.common.base.Functions; 3import com.google.common.base.Functions;
4import com.google.common.base.Preconditions; 4import com.google.common.base.Preconditions;
5import cuchaz.enigma.analysis.ClassCache;
6import cuchaz.enigma.analysis.EntryReference; 5import cuchaz.enigma.analysis.EntryReference;
7import cuchaz.enigma.analysis.index.JarIndex; 6import cuchaz.enigma.analysis.index.JarIndex;
8import cuchaz.enigma.api.service.NameProposalService; 7import cuchaz.enigma.api.service.NameProposalService;
9import cuchaz.enigma.bytecode.translators.SourceFixVisitor; 8import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
10import cuchaz.enigma.bytecode.translators.TranslationClassVisitor; 9import cuchaz.enigma.bytecode.translators.TranslationClassVisitor;
11import cuchaz.enigma.source.*; 10import cuchaz.enigma.classprovider.ClassProvider;
11import cuchaz.enigma.source.Decompiler;
12import cuchaz.enigma.source.DecompilerService;
13import cuchaz.enigma.source.SourceSettings;
12import cuchaz.enigma.translation.ProposingTranslator; 14import cuchaz.enigma.translation.ProposingTranslator;
13import cuchaz.enigma.translation.Translator; 15import cuchaz.enigma.translation.Translator;
14import cuchaz.enigma.translation.mapping.*; 16import cuchaz.enigma.translation.mapping.EntryMapping;
17import cuchaz.enigma.translation.mapping.EntryRemapper;
18import cuchaz.enigma.translation.mapping.MappingsChecker;
15import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; 19import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree;
16import cuchaz.enigma.translation.mapping.tree.EntryTree; 20import cuchaz.enigma.translation.mapping.tree.EntryTree;
17import cuchaz.enigma.translation.representation.entry.ClassEntry; 21import cuchaz.enigma.translation.representation.entry.ClassEntry;
@@ -19,11 +23,11 @@ import cuchaz.enigma.translation.representation.entry.Entry;
19import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; 23import cuchaz.enigma.translation.representation.entry.LocalVariableEntry;
20import cuchaz.enigma.translation.representation.entry.MethodEntry; 24import cuchaz.enigma.translation.representation.entry.MethodEntry;
21import cuchaz.enigma.utils.I18n; 25import cuchaz.enigma.utils.I18n;
22
23import org.objectweb.asm.ClassWriter; 26import org.objectweb.asm.ClassWriter;
24import org.objectweb.asm.tree.ClassNode; 27import org.objectweb.asm.tree.ClassNode;
25 28
26import java.io.*; 29import java.io.BufferedWriter;
30import java.io.IOException;
27import java.nio.file.Files; 31import java.nio.file.Files;
28import java.nio.file.Path; 32import java.nio.file.Path;
29import java.util.Collection; 33import java.util.Collection;
@@ -37,16 +41,16 @@ import java.util.stream.Collectors;
37public class EnigmaProject { 41public class EnigmaProject {
38 private final Enigma enigma; 42 private final Enigma enigma;
39 43
40 private final ClassCache classCache; 44 private final ClassProvider classProvider;
41 private final JarIndex jarIndex; 45 private final JarIndex jarIndex;
42 private final byte[] jarChecksum; 46 private final byte[] jarChecksum;
43 47
44 private EntryRemapper mapper; 48 private EntryRemapper mapper;
45 49
46 public EnigmaProject(Enigma enigma, ClassCache classCache, JarIndex jarIndex, byte[] jarChecksum) { 50 public EnigmaProject(Enigma enigma, ClassProvider classProvider, JarIndex jarIndex, byte[] jarChecksum) {
47 Preconditions.checkArgument(jarChecksum.length == 20); 51 Preconditions.checkArgument(jarChecksum.length == 20);
48 this.enigma = enigma; 52 this.enigma = enigma;
49 this.classCache = classCache; 53 this.classProvider = classProvider;
50 this.jarIndex = jarIndex; 54 this.jarIndex = jarIndex;
51 this.jarChecksum = jarChecksum; 55 this.jarChecksum = jarChecksum;
52 56
@@ -65,8 +69,8 @@ public class EnigmaProject {
65 return enigma; 69 return enigma;
66 } 70 }
67 71
68 public ClassCache getClassCache() { 72 public ClassProvider getClassProvider() {
69 return classCache; 73 return classProvider;
70 } 74 }
71 75
72 public JarIndex getJarIndex() { 76 public JarIndex getJarIndex() {
@@ -103,20 +107,6 @@ public class EnigmaProject {
103 return droppedMappings.keySet(); 107 return droppedMappings.keySet();
104 } 108 }
105 109
106 public Decompiler createDecompiler(DecompilerService decompilerService) {
107 return decompilerService.create(name -> {
108 ClassNode node = this.getClassCache().getClassNode(name);
109
110 if (node == null) {
111 return null;
112 }
113
114 ClassNode fixedNode = new ClassNode();
115 node.accept(new SourceFixVisitor(Enigma.ASM_VERSION, fixedNode, getJarIndex()));
116 return fixedNode;
117 }, new SourceSettings(true, true));
118 }
119
120 public boolean isRenamable(Entry<?> obfEntry) { 110 public boolean isRenamable(Entry<?> obfEntry) {
121 if (obfEntry instanceof MethodEntry) { 111 if (obfEntry instanceof MethodEntry) {
122 // HACKHACK: Object methods are not obfuscated identifiers 112 // HACKHACK: Object methods are not obfuscated identifiers
@@ -171,7 +161,7 @@ public class EnigmaProject {
171 ClassEntry translatedEntry = deobfuscator.translate(entry); 161 ClassEntry translatedEntry = deobfuscator.translate(entry);
172 progress.step(count.getAndIncrement(), translatedEntry.toString()); 162 progress.step(count.getAndIncrement(), translatedEntry.toString());
173 163
174 ClassNode node = classCache.getClassNode(entry.getFullName()); 164 ClassNode node = classProvider.get(entry.getFullName());
175 if (node != null) { 165 if (node != null) {
176 ClassNode translatedNode = new ClassNode(); 166 ClassNode translatedNode = new ClassNode();
177 node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, new SourceFixVisitor(Enigma.ASM_VERSION, translatedNode, jarIndex))); 167 node.accept(new TranslationClassVisitor(deobfuscator, Enigma.ASM_VERSION, new SourceFixVisitor(Enigma.ASM_VERSION, translatedNode, jarIndex)));
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
index 4685b390..989464de 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/BuiltinPlugin.java
@@ -12,7 +12,6 @@ import cuchaz.enigma.translation.representation.entry.ClassEntry;
12import cuchaz.enigma.translation.representation.entry.Entry; 12import cuchaz.enigma.translation.representation.entry.Entry;
13import cuchaz.enigma.translation.representation.entry.FieldEntry; 13import cuchaz.enigma.translation.representation.entry.FieldEntry;
14import cuchaz.enigma.utils.Pair; 14import cuchaz.enigma.utils.Pair;
15import org.objectweb.asm.ClassReader;
16import org.objectweb.asm.ClassVisitor; 15import org.objectweb.asm.ClassVisitor;
17import org.objectweb.asm.FieldVisitor; 16import org.objectweb.asm.FieldVisitor;
18import org.objectweb.asm.MethodVisitor; 17import org.objectweb.asm.MethodVisitor;
@@ -51,7 +50,7 @@ public final class BuiltinPlugin implements EnigmaPlugin {
51 final Map<Entry<?>, String> names = new HashMap<>(); 50 final Map<Entry<?>, String> names = new HashMap<>();
52 final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names); 51 final EnumFieldNameFindingVisitor visitor = new EnumFieldNameFindingVisitor(names);
53 52
54 ctx.registerService("enigma:enum_initializer_indexer", JarIndexerService.TYPE, ctx1 -> (classCache, jarIndex) -> classCache.visit(() -> visitor, ClassReader.SKIP_FRAMES)); 53 ctx.registerService("enigma:enum_initializer_indexer", JarIndexerService.TYPE, ctx1 -> JarIndexerService.fromVisitor(visitor));
55 ctx.registerService("enigma:enum_name_proposer", NameProposalService.TYPE, ctx1 -> (obfEntry, remapper) -> Optional.ofNullable(names.get(obfEntry))); 54 ctx.registerService("enigma:enum_name_proposer", NameProposalService.TYPE, ctx1 -> (obfEntry, remapper) -> Optional.ofNullable(names.get(obfEntry)));
56 } 55 }
57 56
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/ClassCache.java b/enigma/src/main/java/cuchaz/enigma/analysis/ClassCache.java
deleted file mode 100644
index a3d24e32..00000000
--- a/enigma/src/main/java/cuchaz/enigma/analysis/ClassCache.java
+++ /dev/null
@@ -1,126 +0,0 @@
1package cuchaz.enigma.analysis;
2
3import com.google.common.cache.Cache;
4import com.google.common.cache.CacheBuilder;
5import com.google.common.collect.ImmutableSet;
6import cuchaz.enigma.ClassProvider;
7import cuchaz.enigma.Enigma;
8import cuchaz.enigma.ProgressListener;
9import cuchaz.enigma.analysis.index.JarIndex;
10import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
11import org.objectweb.asm.ClassReader;
12import org.objectweb.asm.ClassVisitor;
13import org.objectweb.asm.tree.ClassNode;
14
15import javax.annotation.Nullable;
16import java.io.IOException;
17import java.nio.file.FileSystem;
18import java.nio.file.FileSystems;
19import java.nio.file.Files;
20import java.nio.file.Path;
21import java.util.concurrent.ExecutionException;
22import java.util.concurrent.TimeUnit;
23import java.util.function.Supplier;
24
25public final class ClassCache implements AutoCloseable, ClassProvider {
26 private final FileSystem fileSystem;
27 private final ImmutableSet<String> classNames;
28
29 private final Cache<String, ClassNode> nodeCache = CacheBuilder.newBuilder()
30 .maximumSize(128)
31 .expireAfterAccess(1, TimeUnit.MINUTES)
32 .build();
33
34 private ClassCache(FileSystem fileSystem, ImmutableSet<String> classNames) {
35 this.fileSystem = fileSystem;
36 this.classNames = classNames;
37 }
38
39 public static ClassCache of(Path jarPath) throws IOException {
40 FileSystem fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null);
41 ImmutableSet<String> classNames = collectClassNames(fileSystem);
42
43 return new ClassCache(fileSystem, classNames);
44 }
45
46 private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException {
47 ImmutableSet.Builder<String> classNames = ImmutableSet.builder();
48 for (Path root : fileSystem.getRootDirectories()) {
49 Files.walk(root).map(Path::toString)
50 .forEach(path -> {
51 if (path.endsWith(".class")) {
52 String name = path.substring(1, path.length() - ".class".length());
53 classNames.add(name);
54 }
55 });
56 }
57
58 return classNames.build();
59 }
60
61 @Nullable
62 @Override
63 public ClassNode getClassNode(String name) {
64 if (!classNames.contains(name)) {
65 return null;
66 }
67
68 try {
69 return nodeCache.get(name, () -> parseNode(name));
70 } catch (ExecutionException e) {
71 throw new RuntimeException(e);
72 }
73 }
74
75 private ClassNode parseNode(String name) throws IOException {
76 ClassReader reader = getReader(name);
77
78 ClassNode node = new ClassNode();
79
80 LocalVariableFixVisitor visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, node);
81 reader.accept(visitor, 0);
82
83 return node;
84 }
85
86 private ClassReader getReader(String name) throws IOException {
87 Path path = fileSystem.getPath(name + ".class");
88 byte[] bytes = Files.readAllBytes(path);
89 return new ClassReader(bytes);
90 }
91
92 public int getClassCount() {
93 return classNames.size();
94 }
95
96 public void visit(Supplier<ClassVisitor> visitorSupplier, int readFlags) {
97 for (String className : classNames) {
98 ClassVisitor visitor = visitorSupplier.get();
99
100 ClassNode cached = nodeCache.getIfPresent(className);
101 if (cached != null) {
102 cached.accept(visitor);
103 continue;
104 }
105
106 try {
107 ClassReader reader = getReader(className);
108 reader.accept(visitor, readFlags);
109 } catch (IOException e) {
110 System.out.println("Failed to visit class " + className);
111 e.printStackTrace();
112 }
113 }
114 }
115
116 @Override
117 public void close() throws IOException {
118 this.fileSystem.close();
119 }
120
121 public JarIndex index(ProgressListener progress) {
122 JarIndex index = JarIndex.empty();
123 index.indexJar(this, progress);
124 return index;
125 }
126}
diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
index de3f5f57..b5ad91a8 100644
--- a/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
+++ b/enigma/src/main/java/cuchaz/enigma/analysis/index/JarIndex.java
@@ -15,20 +15,21 @@ import com.google.common.collect.HashMultimap;
15import com.google.common.collect.Multimap; 15import com.google.common.collect.Multimap;
16import cuchaz.enigma.Enigma; 16import cuchaz.enigma.Enigma;
17import cuchaz.enigma.ProgressListener; 17import cuchaz.enigma.ProgressListener;
18import cuchaz.enigma.analysis.ClassCache;
19import cuchaz.enigma.analysis.ReferenceTargetType; 18import cuchaz.enigma.analysis.ReferenceTargetType;
19import cuchaz.enigma.classprovider.ClassProvider;
20import cuchaz.enigma.translation.mapping.EntryResolver; 20import cuchaz.enigma.translation.mapping.EntryResolver;
21import cuchaz.enigma.translation.mapping.IndexEntryResolver; 21import cuchaz.enigma.translation.mapping.IndexEntryResolver;
22import cuchaz.enigma.translation.representation.Lambda; 22import cuchaz.enigma.translation.representation.Lambda;
23import cuchaz.enigma.translation.representation.entry.*; 23import cuchaz.enigma.translation.representation.entry.*;
24import cuchaz.enigma.utils.I18n; 24import cuchaz.enigma.utils.I18n;
25 25
26import org.objectweb.asm.ClassReader;
27
28import java.util.Arrays; 26import java.util.Arrays;
29import java.util.Collection; 27import java.util.Collection;
28import java.util.HashSet;
29import java.util.Set;
30 30
31public class JarIndex implements JarIndexer { 31public class JarIndex implements JarIndexer {
32 private final Set<String> indexedClasses = new HashSet<>();
32 private final EntryIndex entryIndex; 33 private final EntryIndex entryIndex;
33 private final InheritanceIndex inheritanceIndex; 34 private final InheritanceIndex inheritanceIndex;
34 private final ReferenceIndex referenceIndex; 35 private final ReferenceIndex referenceIndex;
@@ -59,14 +60,21 @@ public class JarIndex implements JarIndexer {
59 return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex); 60 return new JarIndex(entryIndex, inheritanceIndex, referenceIndex, bridgeMethodIndex, packageVisibilityIndex);
60 } 61 }
61 62
62 public void indexJar(ClassCache classCache, ProgressListener progress) { 63 public void indexJar(Set<String> classNames, ClassProvider classProvider, ProgressListener progress) {
64 indexedClasses.addAll(classNames);
63 progress.init(4, I18n.translate("progress.jar.indexing")); 65 progress.init(4, I18n.translate("progress.jar.indexing"));
64 66
65 progress.step(1, I18n.translate("progress.jar.indexing.entries")); 67 progress.step(1, I18n.translate("progress.jar.indexing.entries"));
66 classCache.visit(() -> new IndexClassVisitor(this, Enigma.ASM_VERSION), ClassReader.SKIP_CODE); 68
69 for (String className : classNames) {
70 classProvider.get(className).accept(new IndexClassVisitor(this, Enigma.ASM_VERSION));
71 }
67 72
68 progress.step(2, I18n.translate("progress.jar.indexing.references")); 73 progress.step(2, I18n.translate("progress.jar.indexing.references"));
69 classCache.visit(() -> new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Enigma.ASM_VERSION), 0); 74
75 for (String className : classNames) {
76 classProvider.get(className).accept(new IndexReferenceVisitor(this, entryIndex, inheritanceIndex, Enigma.ASM_VERSION));
77 }
70 78
71 progress.step(3, I18n.translate("progress.jar.indexing.methods")); 79 progress.step(3, I18n.translate("progress.jar.indexing.methods"));
72 bridgeMethodIndex.findBridgeMethods(); 80 bridgeMethodIndex.findBridgeMethods();
@@ -167,4 +175,8 @@ public class JarIndex implements JarIndexer {
167 public EntryResolver getEntryResolver() { 175 public EntryResolver getEntryResolver() {
168 return entryResolver; 176 return entryResolver;
169 } 177 }
178
179 public boolean isIndexed(String internalName) {
180 return indexedClasses.contains(internalName);
181 }
170} 182}
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
index 0cda1998..5417531c 100644
--- a/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/api/service/JarIndexerService.java
@@ -1,10 +1,21 @@
1package cuchaz.enigma.api.service; 1package cuchaz.enigma.api.service;
2 2
3import cuchaz.enigma.analysis.ClassCache;
4import cuchaz.enigma.analysis.index.JarIndex; 3import cuchaz.enigma.analysis.index.JarIndex;
4import cuchaz.enigma.classprovider.ClassProvider;
5import org.objectweb.asm.ClassVisitor;
6
7import java.util.Set;
5 8
6public interface JarIndexerService extends EnigmaService { 9public interface JarIndexerService extends EnigmaService {
7 EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer"); 10 EnigmaServiceType<JarIndexerService> TYPE = EnigmaServiceType.create("jar_indexer");
8 11
9 void acceptJar(ClassCache classCache, JarIndex jarIndex); 12 void acceptJar(Set<String> scope, ClassProvider classProvider, JarIndex jarIndex);
13
14 static JarIndexerService fromVisitor(ClassVisitor visitor) {
15 return (scope, classProvider, jarIndex) -> {
16 for (String className : scope) {
17 classProvider.get(className).accept(visitor);
18 }
19 };
20 }
10} 21}
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
index f9e4eff8..bc38e61b 100644
--- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
+++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java
@@ -11,11 +11,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
11 11
12import javax.annotation.Nullable; 12import javax.annotation.Nullable;
13 13
14import org.objectweb.asm.tree.ClassNode; 14import cuchaz.enigma.classprovider.CachingClassProvider;
15import cuchaz.enigma.classprovider.ObfuscationFixClassProvider;
15 16
16import cuchaz.enigma.Enigma;
17import cuchaz.enigma.EnigmaProject; 17import cuchaz.enigma.EnigmaProject;
18import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
19import cuchaz.enigma.events.ClassHandleListener; 18import cuchaz.enigma.events.ClassHandleListener;
20import cuchaz.enigma.events.ClassHandleListener.InvalidationType; 19import cuchaz.enigma.events.ClassHandleListener.InvalidationType;
21import cuchaz.enigma.source.*; 20import cuchaz.enigma.source.*;
@@ -89,17 +88,7 @@ public final class ClassHandleProvider {
89 } 88 }
90 89
91 private Decompiler createDecompiler() { 90 private Decompiler createDecompiler() {
92 return ds.create(name -> { 91 return ds.create(new CachingClassProvider(new ObfuscationFixClassProvider(project.getClassProvider(), project.getJarIndex())), new SourceSettings(true, true));
93 ClassNode node = project.getClassCache().getClassNode(name);
94
95 if (node == null) {
96 return null;
97 }
98
99 ClassNode fixedNode = new ClassNode();
100 node.accept(new SourceFixVisitor(Enigma.ASM_VERSION, fixedNode, project.getJarIndex()));
101 return fixedNode;
102 }, new SourceSettings(true, true));
103 } 92 }
104 93
105 /** 94 /**
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
new file mode 100644
index 00000000..47f5eb86
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CachingClassProvider.java
@@ -0,0 +1,36 @@
1package cuchaz.enigma.classprovider;
2
3import com.google.common.cache.Cache;
4import com.google.common.cache.CacheBuilder;
5import org.objectweb.asm.tree.ClassNode;
6
7import javax.annotation.Nullable;
8import java.util.Optional;
9import java.util.concurrent.ExecutionException;
10import java.util.concurrent.TimeUnit;
11
12/**
13 * Wraps a ClassProvider to provide caching and synchronization.
14 */
15public class CachingClassProvider implements ClassProvider {
16 private final ClassProvider classProvider;
17 private final Cache<String, Optional<ClassNode>> cache = CacheBuilder.newBuilder()
18 .maximumSize(128)
19 .expireAfterAccess(1, TimeUnit.MINUTES)
20 .concurrencyLevel(1)
21 .build();
22
23 public CachingClassProvider(ClassProvider classProvider) {
24 this.classProvider = classProvider;
25 }
26
27 @Override
28 @Nullable
29 public ClassNode get(String name) {
30 try {
31 return cache.get(name, () -> Optional.ofNullable(classProvider.get(name))).orElse(null);
32 } catch (ExecutionException e) {
33 throw new RuntimeException(e);
34 }
35 }
36}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
new file mode 100644
index 00000000..6e4a665a
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClassProvider.java
@@ -0,0 +1,17 @@
1package cuchaz.enigma.classprovider;
2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable;
6
7public interface ClassProvider {
8 /**
9 * Gets the {@linkplain ClassNode} for a class. The class provider may return a cached result,
10 * so it's important to not mutate it.
11 *
12 * @param name the internal name of the class
13 * @return the {@linkplain ClassNode} for that class, or {@code null} if it was not found
14 */
15 @Nullable
16 ClassNode get(String name);
17}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
new file mode 100644
index 00000000..e9472fa9
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ClasspathClassProvider.java
@@ -0,0 +1,27 @@
1package cuchaz.enigma.classprovider;
2
3import org.objectweb.asm.ClassReader;
4import org.objectweb.asm.tree.ClassNode;
5
6import javax.annotation.Nullable;
7import java.io.IOException;
8import java.io.InputStream;
9
10/**
11 * Provides classes by loading them from the classpath.
12 */
13public class ClasspathClassProvider implements ClassProvider {
14 @Nullable @Override public ClassNode get(String name) {
15 try (InputStream in = ClasspathClassProvider.class.getResourceAsStream("/" + name + ".class")) {
16 if (in == null) {
17 return null;
18 }
19
20 ClassNode node = new ClassNode();
21 new ClassReader(in).accept(node, 0);
22 return node;
23 } catch (IOException e) {
24 return null;
25 }
26 }
27}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
new file mode 100644
index 00000000..865464cf
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/CombiningClassProvider.java
@@ -0,0 +1,31 @@
1package cuchaz.enigma.classprovider;
2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable;
6
7/**
8 * Combines a list of {@link ClassProvider}s into one, calling each one in a row
9 * until one can provide the class.
10 */
11public class CombiningClassProvider implements ClassProvider {
12 private final ClassProvider[] classProviders;
13
14 public CombiningClassProvider(ClassProvider... classProviders) {
15 this.classProviders = classProviders;
16 }
17
18 @Override
19 @Nullable
20 public ClassNode get(String name) {
21 for (ClassProvider cp : classProviders) {
22 ClassNode node = cp.get(name);
23
24 if (node != null) {
25 return node;
26 }
27 }
28
29 return null;
30 }
31}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
new file mode 100644
index 00000000..c614b0a8
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/JarClassProvider.java
@@ -0,0 +1,64 @@
1package cuchaz.enigma.classprovider;
2
3import com.google.common.collect.ImmutableSet;
4import cuchaz.enigma.utils.AsmUtil;
5import org.objectweb.asm.tree.ClassNode;
6
7import javax.annotation.Nullable;
8import java.io.IOException;
9import java.nio.file.FileSystem;
10import java.nio.file.FileSystems;
11import java.nio.file.Files;
12import java.nio.file.Path;
13import java.util.Set;
14
15/**
16 * Provides classes by loading them from a JAR file.
17 */
18public class JarClassProvider implements AutoCloseable, ClassProvider {
19 private final FileSystem fileSystem;
20 private final Set<String> classNames;
21
22 public JarClassProvider(Path jarPath) throws IOException {
23 this.fileSystem = FileSystems.newFileSystem(jarPath, (ClassLoader) null);
24 this.classNames = collectClassNames(fileSystem);
25 }
26
27 private static ImmutableSet<String> collectClassNames(FileSystem fileSystem) throws IOException {
28 ImmutableSet.Builder<String> classNames = ImmutableSet.builder();
29 for (Path root : fileSystem.getRootDirectories()) {
30 Files.walk(root).map(Path::toString)
31 .forEach(path -> {
32 if (path.endsWith(".class")) {
33 String name = path.substring(1, path.length() - ".class".length());
34 classNames.add(name);
35 }
36 });
37 }
38
39 return classNames.build();
40 }
41
42 public Set<String> getClassNames() {
43 return classNames;
44 }
45
46 @Nullable
47 @Override
48 public ClassNode get(String name) {
49 if (!classNames.contains(name)) {
50 return null;
51 }
52
53 try {
54 return AsmUtil.bytesToNode(Files.readAllBytes(fileSystem.getPath(name + ".class")));
55 } catch (IOException e) {
56 throw new RuntimeException(e);
57 }
58 }
59
60 @Override
61 public void close() throws Exception {
62 fileSystem.close();
63 }
64}
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
new file mode 100644
index 00000000..db9e2d04
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/classprovider/ObfuscationFixClassProvider.java
@@ -0,0 +1,85 @@
1package cuchaz.enigma.classprovider;
2
3import cuchaz.enigma.Enigma;
4import cuchaz.enigma.analysis.index.JarIndex;
5import cuchaz.enigma.bytecode.translators.LocalVariableFixVisitor;
6import cuchaz.enigma.bytecode.translators.SourceFixVisitor;
7import cuchaz.enigma.classprovider.ClassProvider;
8import org.objectweb.asm.ClassVisitor;
9import org.objectweb.asm.Opcodes;
10import org.objectweb.asm.tree.AbstractInsnNode;
11import org.objectweb.asm.tree.ClassNode;
12import org.objectweb.asm.tree.MethodInsnNode;
13import org.objectweb.asm.tree.MethodNode;
14
15import javax.annotation.Nullable;
16
17/**
18 * Wraps a ClassProvider to apply fixes to the following problems introduced by the obfuscator,
19 * so that the classes can be decompiled correctly:
20 * <ul>
21 * <li>Bridge methods missing the "bridge" or "synthetic" access modifier
22 * <li>.getClass() calls added by Proguard (Proguard adds these to preserve semantics when Proguard removes
23 * a field access which may have caused a {@code NullPointerException}).
24 * <li>LVT names that don't match parameter table name
25 * <li>LVT names that are invalid or duplicate
26 * <li>Enum constructor parameters that are incorrectly named or missing the "synthetic" access modifier
27 * <li>"this" parameter which is incorrectly named
28 * </ul>
29 * <p>
30 * These fixes are only applied to classes that were indexed by the JarIndex provided, and not library classes.
31 */
32public class ObfuscationFixClassProvider implements ClassProvider {
33 private final ClassProvider classProvider;
34 private final JarIndex jarIndex;
35
36 public ObfuscationFixClassProvider(ClassProvider classProvider, JarIndex jarIndex) {
37 this.classProvider = classProvider;
38 this.jarIndex = jarIndex;
39 }
40
41 @Override
42 @Nullable
43 public ClassNode get(String name) {
44 ClassNode node = classProvider.get(name);
45
46 if (!jarIndex.isIndexed(name)) {
47 return node;
48 }
49
50 ClassNode fixedNode = new ClassNode();
51 ClassVisitor visitor = fixedNode;
52 visitor = new LocalVariableFixVisitor(Enigma.ASM_VERSION, visitor);
53 visitor = new SourceFixVisitor(Enigma.ASM_VERSION, visitor, jarIndex);
54 node.accept(visitor);
55 removeRedundantClassCalls(fixedNode);
56
57 return fixedNode;
58 }
59
60 private void removeRedundantClassCalls(ClassNode node) {
61 // Removes .getClass() calls added by Proguard:
62 // DUP
63 // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
64 // POP
65 for (MethodNode methodNode : node.methods) {
66 AbstractInsnNode insnNode = methodNode.instructions.getFirst();
67 while (insnNode != null) {
68 if (insnNode instanceof MethodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
69 MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
70 if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
71 AbstractInsnNode previous = methodInsnNode.getPrevious();
72 AbstractInsnNode next = methodInsnNode.getNext();
73 if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
74 insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction
75 methodNode.instructions.remove(previous);
76 methodNode.instructions.remove(methodInsnNode);
77 methodNode.instructions.remove(next);
78 }
79 }
80 }
81 insnNode = insnNode.getNext();
82 }
83 }
84 }
85}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
index 377ccbc1..638498f7 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/DecompilerService.java
@@ -1,6 +1,6 @@
1package cuchaz.enigma.source; 1package cuchaz.enigma.source;
2 2
3import cuchaz.enigma.ClassProvider; 3import cuchaz.enigma.classprovider.ClassProvider;
4import cuchaz.enigma.api.service.EnigmaService; 4import cuchaz.enigma.api.service.EnigmaService;
5import cuchaz.enigma.api.service.EnigmaServiceType; 5import cuchaz.enigma.api.service.EnigmaServiceType;
6 6
diff --git a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
index 9e37f168..941a699f 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/cfr/CfrDecompiler.java
@@ -1,10 +1,10 @@
1package cuchaz.enigma.source.cfr; 1package cuchaz.enigma.source.cfr;
2 2
3import com.google.common.io.ByteStreams; 3import cuchaz.enigma.classprovider.ClassProvider;
4import cuchaz.enigma.ClassProvider;
5import cuchaz.enigma.source.Decompiler; 4import cuchaz.enigma.source.Decompiler;
6import cuchaz.enigma.source.Source; 5import cuchaz.enigma.source.Source;
7import cuchaz.enigma.source.SourceSettings; 6import cuchaz.enigma.source.SourceSettings;
7import cuchaz.enigma.utils.AsmUtil;
8import org.benf.cfr.reader.apiunreleased.ClassFileSource2; 8import org.benf.cfr.reader.apiunreleased.ClassFileSource2;
9import org.benf.cfr.reader.apiunreleased.JarContent; 9import org.benf.cfr.reader.apiunreleased.JarContent;
10import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair; 10import org.benf.cfr.reader.bytecode.analysis.parse.utils.Pair;
@@ -19,16 +19,12 @@ import org.benf.cfr.reader.util.CannotLoadClassException;
19import org.benf.cfr.reader.util.collections.ListFactory; 19import org.benf.cfr.reader.util.collections.ListFactory;
20import org.benf.cfr.reader.util.getopt.Options; 20import org.benf.cfr.reader.util.getopt.Options;
21import org.benf.cfr.reader.util.getopt.OptionsImpl; 21import org.benf.cfr.reader.util.getopt.OptionsImpl;
22import org.objectweb.asm.ClassWriter;
23import org.objectweb.asm.tree.ClassNode; 22import org.objectweb.asm.tree.ClassNode;
24 23
25import java.io.IOException;
26import java.io.InputStream;
27import java.util.Collection; 24import java.util.Collection;
28import java.util.HashMap; 25import java.util.HashMap;
29import java.util.Map; 26import java.util.Map;
30 27
31
32public class CfrDecompiler implements Decompiler { 28public class CfrDecompiler implements Decompiler {
33 private final DCCommonState state; 29 private final DCCommonState state;
34 30
@@ -58,21 +54,13 @@ public class CfrDecompiler implements Decompiler {
58 54
59 @Override 55 @Override
60 public Pair<byte[], String> getClassFileContent(String path) { 56 public Pair<byte[], String> getClassFileContent(String path) {
61 ClassNode node = classProvider.getClassNode(path.substring(0, path.lastIndexOf('.'))); 57 ClassNode node = classProvider.get(path.substring(0, path.lastIndexOf('.')));
62 58
63 if (node == null) { 59 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; 60 return null;
71 } 61 }
72 62
73 ClassWriter cw = new ClassWriter(0); 63 return new Pair<>(AsmUtil.nodeToBytes(node), path);
74 node.accept(cw);
75 return new Pair<>(cw.toByteArray(), path);
76 } 64 }
77 }); 65 });
78 } 66 }
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
index 3cbd680c..9dc1e0a8 100644
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
+++ b/enigma/src/main/java/cuchaz/enigma/source/procyon/ProcyonDecompiler.java
@@ -11,14 +11,13 @@ import com.strobel.decompiler.languages.java.JavaFormattingOptions;
11import com.strobel.decompiler.languages.java.ast.AstBuilder; 11import com.strobel.decompiler.languages.java.ast.AstBuilder;
12import com.strobel.decompiler.languages.java.ast.CompilationUnit; 12import com.strobel.decompiler.languages.java.ast.CompilationUnit;
13import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; 13import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
14import cuchaz.enigma.ClassProvider; 14import cuchaz.enigma.classprovider.ClassProvider;
15import cuchaz.enigma.source.Source; 15import cuchaz.enigma.source.Source;
16import cuchaz.enigma.source.Decompiler; 16import cuchaz.enigma.source.Decompiler;
17import cuchaz.enigma.source.SourceSettings; 17import cuchaz.enigma.source.SourceSettings;
18import cuchaz.enigma.source.procyon.transformers.*; 18import cuchaz.enigma.source.procyon.transformers.*;
19import cuchaz.enigma.source.procyon.typeloader.CompiledSourceTypeLoader; 19import cuchaz.enigma.utils.AsmUtil;
20import cuchaz.enigma.source.procyon.typeloader.NoRetryMetadataSystem; 20import org.objectweb.asm.tree.ClassNode;
21import cuchaz.enigma.source.procyon.typeloader.SynchronizedTypeLoader;
22 21
23public class ProcyonDecompiler implements Decompiler { 22public class ProcyonDecompiler implements Decompiler {
24 private final SourceSettings settings; 23 private final SourceSettings settings;
@@ -26,9 +25,21 @@ public class ProcyonDecompiler implements Decompiler {
26 private final MetadataSystem metadataSystem; 25 private final MetadataSystem metadataSystem;
27 26
28 public ProcyonDecompiler(ClassProvider classProvider, SourceSettings settings) { 27 public ProcyonDecompiler(ClassProvider classProvider, SourceSettings settings) {
29 ITypeLoader typeLoader = new SynchronizedTypeLoader(new CompiledSourceTypeLoader(classProvider)); 28 ITypeLoader typeLoader = (name, buffer) -> {
29 ClassNode node = classProvider.get(name);
30 30
31 metadataSystem = new NoRetryMetadataSystem(typeLoader); 31 if (node == null) {
32 return false;
33 }
34
35 byte[] data = AsmUtil.nodeToBytes(node);
36 buffer.reset(data.length);
37 System.arraycopy(data, 0, buffer.array(), buffer.position(), data.length);
38 buffer.position(0);
39 return true;
40 };
41
42 metadataSystem = new MetadataSystem(typeLoader);
32 metadataSystem.setEagerMethodLoadingEnabled(true); 43 metadataSystem.setEagerMethodLoadingEnabled(true);
33 44
34 decompilerSettings = DecompilerSettings.javaDefaults(); 45 decompilerSettings = DecompilerSettings.javaDefaults();
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java
deleted file mode 100644
index e702956e..00000000
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingClasspathTypeLoader.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package cuchaz.enigma.source.procyon.typeloader;
2
3import com.strobel.assembler.metadata.Buffer;
4import com.strobel.assembler.metadata.ClasspathTypeLoader;
5import com.strobel.assembler.metadata.ITypeLoader;
6
7/**
8 * Caching version of {@link ClasspathTypeLoader}
9 */
10public class CachingClasspathTypeLoader extends CachingTypeLoader {
11 private static ITypeLoader extraClassPathLoader = null;
12
13 public static void setExtraClassPathLoader(ITypeLoader loader){
14 extraClassPathLoader = loader;
15 }
16
17 private final ITypeLoader classpathLoader = new ClasspathTypeLoader();
18
19 @Override
20 protected byte[] doLoad(String className) {
21 Buffer parentBuf = new Buffer();
22 if (classpathLoader.tryLoadType(className, parentBuf)) {
23 return parentBuf.array();
24 }
25 if (extraClassPathLoader != null){
26 parentBuf.reset();
27 if (extraClassPathLoader.tryLoadType(className, parentBuf)){
28 return parentBuf.array();
29 }
30 }
31 return EMPTY_ARRAY;//need to return *something* as null means no store
32 }
33}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java
deleted file mode 100644
index 5be5ddd9..00000000
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CachingTypeLoader.java
+++ /dev/null
@@ -1,38 +0,0 @@
1package cuchaz.enigma.source.procyon.typeloader;
2
3import com.google.common.collect.Maps;
4import com.strobel.assembler.metadata.Buffer;
5import com.strobel.assembler.metadata.ITypeLoader;
6
7import java.util.Map;
8
9/**
10 * Common cache functions
11 */
12public abstract class CachingTypeLoader implements ITypeLoader {
13 protected static final byte[] EMPTY_ARRAY = {};
14
15 private final Map<String, byte[]> cache = Maps.newHashMap();
16
17 protected abstract byte[] doLoad(String className);
18
19 @Override
20 public boolean tryLoadType(String className, Buffer out) {
21
22 // check the cache
23 byte[] data = this.cache.computeIfAbsent(className, this::doLoad);
24
25 if (data == EMPTY_ARRAY) {
26 return false;
27 }
28
29 out.reset(data.length);
30 System.arraycopy(data, 0, out.array(), out.position(), data.length);
31 out.position(0);
32 return true;
33 }
34
35 public void clearCache() {
36 this.cache.clear();
37 }
38}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java
deleted file mode 100644
index e703d3b3..00000000
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/CompiledSourceTypeLoader.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11
12package cuchaz.enigma.source.procyon.typeloader;
13
14import com.google.common.collect.Lists;
15import com.strobel.assembler.metadata.Buffer;
16import com.strobel.assembler.metadata.ITypeLoader;
17import cuchaz.enigma.ClassProvider;
18import cuchaz.enigma.translation.representation.entry.ClassEntry;
19import org.objectweb.asm.ClassVisitor;
20import org.objectweb.asm.ClassWriter;
21import org.objectweb.asm.Opcodes;
22import org.objectweb.asm.tree.AbstractInsnNode;
23import org.objectweb.asm.tree.ClassNode;
24import org.objectweb.asm.tree.MethodInsnNode;
25import org.objectweb.asm.tree.MethodNode;
26
27import java.util.Collection;
28import java.util.LinkedList;
29import java.util.List;
30import java.util.function.Function;
31
32public class CompiledSourceTypeLoader extends CachingTypeLoader {
33 //Store one instance as the classpath shouldn't change during load
34 private static final ITypeLoader CLASSPATH_TYPE_LOADER = new CachingClasspathTypeLoader();
35
36 private final ClassProvider compiledSource;
37 private final LinkedList<Function<ClassVisitor, ClassVisitor>> visitors = new LinkedList<>();
38
39 public CompiledSourceTypeLoader(ClassProvider compiledSource) {
40 this.compiledSource = compiledSource;
41 }
42
43 public void addVisitor(Function<ClassVisitor, ClassVisitor> visitor) {
44 this.visitors.addFirst(visitor);
45 }
46
47 @Override
48 protected byte[] doLoad(String className) {
49 byte[] data = loadType(className);
50 if (data == null) {
51 return loadClasspath(className);
52 }
53
54 return data;
55 }
56
57 private byte[] loadClasspath(String name) {
58 Buffer parentBuf = new Buffer();
59 if (CLASSPATH_TYPE_LOADER.tryLoadType(name, parentBuf)) {
60 return parentBuf.array();
61 }
62 return EMPTY_ARRAY;
63 }
64
65 private byte[] loadType(String className) {
66 ClassEntry entry = new ClassEntry(className);
67
68 // find the class in the jar
69 ClassNode node = findClassNode(entry);
70 if (node == null) {
71 // couldn't find it
72 return null;
73 }
74
75 removeRedundantClassCalls(node);
76
77 ClassWriter writer = new ClassWriter(0);
78
79 ClassVisitor visitor = writer;
80 for (Function<ClassVisitor, ClassVisitor> visitorFunction : this.visitors) {
81 visitor = visitorFunction.apply(visitor);
82 }
83
84 node.accept(visitor);
85
86 // we have a transformed class!
87 return writer.toByteArray();
88 }
89
90 private void removeRedundantClassCalls(ClassNode node) {
91 // remove <obj>.getClass() calls that are seemingly injected
92 // DUP
93 // INVOKEVIRTUAL java/lang/Object.getClass ()Ljava/lang/Class;
94 // POP
95 for (MethodNode methodNode : node.methods) {
96 AbstractInsnNode insnNode = methodNode.instructions.getFirst();
97 while (insnNode != null) {
98 if (insnNode instanceof MethodInsnNode && insnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
99 MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
100 if (methodInsnNode.name.equals("getClass") && methodInsnNode.owner.equals("java/lang/Object") && methodInsnNode.desc.equals("()Ljava/lang/Class;")) {
101 AbstractInsnNode previous = methodInsnNode.getPrevious();
102 AbstractInsnNode next = methodInsnNode.getNext();
103 if (previous.getOpcode() == Opcodes.DUP && next.getOpcode() == Opcodes.POP) {
104 insnNode = previous.getPrevious();//reset the iterator so it gets the new next instruction
105 methodNode.instructions.remove(previous);
106 methodNode.instructions.remove(methodInsnNode);
107 methodNode.instructions.remove(next);
108 }
109 }
110 }
111 insnNode = insnNode.getNext();
112 }
113 }
114 }
115
116 private ClassNode findClassNode(ClassEntry entry) {
117 // try to find the class in the jar
118 for (String className : getClassNamesToTry(entry)) {
119 ClassNode node = compiledSource.getClassNode(className);
120 if (node != null) {
121 return node;
122 }
123 }
124
125 // didn't find it ;_;
126 return null;
127 }
128
129 private Collection<String> getClassNamesToTry(ClassEntry entry) {
130 List<String> classNamesToTry = Lists.newArrayList();
131 classNamesToTry.add(entry.getFullName());
132
133 ClassEntry outerClass = entry.getOuterClass();
134 if (outerClass != null) {
135 classNamesToTry.addAll(getClassNamesToTry(outerClass));
136 }
137
138 return classNamesToTry;
139 }
140}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java
deleted file mode 100644
index c4732b04..00000000
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/NoRetryMetadataSystem.java
+++ /dev/null
@@ -1,38 +0,0 @@
1package cuchaz.enigma.source.procyon.typeloader;
2
3import com.strobel.assembler.metadata.ITypeLoader;
4import com.strobel.assembler.metadata.MetadataSystem;
5import com.strobel.assembler.metadata.TypeDefinition;
6import com.strobel.assembler.metadata.TypeReference;
7
8import java.util.Collections;
9import java.util.Set;
10import java.util.concurrent.ConcurrentHashMap;
11
12public final class NoRetryMetadataSystem extends MetadataSystem {
13 private final Set<String> failedTypes = Collections.newSetFromMap(new ConcurrentHashMap<>());
14
15 public NoRetryMetadataSystem(final ITypeLoader typeLoader) {
16 super(typeLoader);
17 }
18
19 @Override
20 protected synchronized TypeDefinition resolveType(final String descriptor, final boolean mightBePrimitive) {
21 if (failedTypes.contains(descriptor)) {
22 return null;
23 }
24
25 final TypeDefinition result = super.resolveType(descriptor, mightBePrimitive);
26
27 if (result == null) {
28 failedTypes.add(descriptor);
29 }
30
31 return result;
32 }
33
34 @Override
35 public synchronized TypeDefinition resolve(final TypeReference type) {
36 return super.resolve(type);
37 }
38}
diff --git a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java b/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java
deleted file mode 100644
index 86c6ecc6..00000000
--- a/enigma/src/main/java/cuchaz/enigma/source/procyon/typeloader/SynchronizedTypeLoader.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package cuchaz.enigma.source.procyon.typeloader;
2
3import com.strobel.assembler.metadata.Buffer;
4import com.strobel.assembler.metadata.ITypeLoader;
5
6/**
7 * Typeloader with synchronized tryLoadType method
8 */
9public class SynchronizedTypeLoader implements ITypeLoader {
10 private final ITypeLoader delegate;
11
12 public SynchronizedTypeLoader(ITypeLoader delegate) {
13 this.delegate = delegate;
14 }
15
16 @Override
17 public synchronized boolean tryLoadType(String internalName, Buffer buffer) {
18 return delegate.tryLoadType(internalName, buffer);
19 }
20}
diff --git a/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java
new file mode 100644
index 00000000..7d34b020
--- /dev/null
+++ b/enigma/src/main/java/cuchaz/enigma/utils/AsmUtil.java
@@ -0,0 +1,20 @@
1package cuchaz.enigma.utils;
2
3import org.objectweb.asm.ClassReader;
4import org.objectweb.asm.ClassWriter;
5import org.objectweb.asm.tree.ClassNode;
6
7public class AsmUtil {
8 public static byte[] nodeToBytes(ClassNode node) {
9 ClassWriter w = new ClassWriter(0);
10 node.accept(w);
11 return w.toByteArray();
12 }
13
14 public static ClassNode bytesToNode(byte[] bytes) {
15 ClassReader r = new ClassReader(bytes);
16 ClassNode node = new ClassNode();
17 r.accept(node, 0);
18 return node;
19 }
20}
diff --git a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
index 1dc9748b..12515358 100644
--- a/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
+++ b/enigma/src/test/java/cuchaz/enigma/PackageVisibilityIndexTest.java
@@ -11,12 +11,13 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.ClassCache;
15import cuchaz.enigma.analysis.index.JarIndex; 14import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.analysis.index.PackageVisibilityIndex; 15import cuchaz.enigma.analysis.index.PackageVisibilityIndex;
16import cuchaz.enigma.classprovider.JarClassProvider;
17import cuchaz.enigma.translation.representation.entry.ClassEntry; 17import cuchaz.enigma.translation.representation.entry.ClassEntry;
18import org.junit.Test; 18import org.junit.Test;
19 19
20import java.nio.file.Path;
20import java.nio.file.Paths; 21import java.nio.file.Paths;
21 22
22import static cuchaz.enigma.TestEntryFactory.newClass; 23import static cuchaz.enigma.TestEntryFactory.newClass;
@@ -25,7 +26,7 @@ import static org.hamcrest.Matchers.contains;
25import static org.hamcrest.Matchers.containsInAnyOrder; 26import static org.hamcrest.Matchers.containsInAnyOrder;
26 27
27public class PackageVisibilityIndexTest { 28public class PackageVisibilityIndexTest {
28 29 public static final Path JAR = Paths.get("build/test-obf/packageAccess.jar");
29 private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep"); 30 private static final ClassEntry KEEP = newClass("cuchaz/enigma/inputs/Keep");
30 private static final ClassEntry BASE = newClass("a"); 31 private static final ClassEntry BASE = newClass("a");
31 private static final ClassEntry SAME_PACKAGE_CHILD = newClass("b"); 32 private static final ClassEntry SAME_PACKAGE_CHILD = newClass("b");
@@ -35,8 +36,9 @@ public class PackageVisibilityIndexTest {
35 private final JarIndex jarIndex; 36 private final JarIndex jarIndex;
36 37
37 public PackageVisibilityIndexTest() throws Exception { 38 public PackageVisibilityIndexTest() throws Exception {
38 ClassCache classCache = ClassCache.of(Paths.get("build/test-obf/packageAccess.jar")); 39 JarClassProvider jcp = new JarClassProvider(JAR);
39 jarIndex = classCache.index(ProgressListener.none()); 40 jarIndex = JarIndex.empty();
41 jarIndex.indexJar(jcp.getClassNames(), jcp, ProgressListener.none());
40 } 42 }
41 43
42 @Test 44 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
index 494d959e..6daa2931 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfed.java
@@ -11,8 +11,7 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.ClassCache; 14import cuchaz.enigma.classprovider.ClasspathClassProvider;
15import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.source.Decompiler; 15import cuchaz.enigma.source.Decompiler;
17import cuchaz.enigma.source.Decompilers; 16import cuchaz.enigma.source.Decompilers;
18import cuchaz.enigma.source.SourceSettings; 17import cuchaz.enigma.source.SourceSettings;
@@ -28,27 +27,24 @@ import static org.hamcrest.MatcherAssert.assertThat;
28import static org.hamcrest.Matchers.containsInAnyOrder; 27import static org.hamcrest.Matchers.containsInAnyOrder;
29 28
30public class TestDeobfed { 29public class TestDeobfed {
31 private static Enigma enigma; 30 public static final Path OBF = Paths.get("build/test-obf/translation.jar");
32 private static ClassCache classCache; 31 public static final Path DEOBF = Paths.get("build/test-deobf/translation.jar");
33 private static JarIndex index; 32 private static EnigmaProject deobfProject;
34 33
35 @BeforeClass 34 @BeforeClass
36 public static void beforeClass() throws Exception { 35 public static void beforeClass() throws Exception {
37 enigma = Enigma.create(); 36 Enigma enigma = Enigma.create();
38 37
39 Path obf = Paths.get("build/test-obf/translation.jar"); 38 Files.createDirectories(DEOBF.getParent());
40 Path deobf = Paths.get("build/test-deobf/translation.jar"); 39 EnigmaProject obfProject = enigma.openJar(OBF, new ClasspathClassProvider(), ProgressListener.none());
41 Files.createDirectories(deobf.getParent()); 40 obfProject.exportRemappedJar(ProgressListener.none()).write(DEOBF, ProgressListener.none());
42 EnigmaProject project = enigma.openJar(obf, ProgressListener.none());
43 project.exportRemappedJar(ProgressListener.none()).write(deobf, ProgressListener.none());
44 41
45 classCache = ClassCache.of(deobf); 42 deobfProject = enigma.openJar(DEOBF, new ClasspathClassProvider(), ProgressListener.none());
46 index = classCache.index(ProgressListener.none());
47 } 43 }
48 44
49 @Test 45 @Test
50 public void obfEntries() { 46 public void obfEntries() {
51 assertThat(index.getEntryIndex().getClasses(), containsInAnyOrder( 47 assertThat(deobfProject.getJarIndex().getEntryIndex().getClasses(), containsInAnyOrder(
52 newClass("cuchaz/enigma/inputs/Keep"), 48 newClass("cuchaz/enigma/inputs/Keep"),
53 newClass("a"), 49 newClass("a"),
54 newClass("b"), 50 newClass("b"),
@@ -77,8 +73,7 @@ public class TestDeobfed {
77 73
78 @Test 74 @Test
79 public void decompile() { 75 public void decompile() {
80 EnigmaProject project = new EnigmaProject(enigma, classCache, index, new byte[20]); 76 Decompiler decompiler = Decompilers.PROCYON.create(deobfProject.getClassProvider(), new SourceSettings(false, false));
81 Decompiler decompiler = Decompilers.PROCYON.create(project.getClassCache(), new SourceSettings(false, false));
82 77
83 decompiler.getSource("a"); 78 decompiler.getSource("a");
84 decompiler.getSource("b"); 79 decompiler.getSource("b");
diff --git a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
index 6619d26e..ae42235e 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestDeobfuscator.java
@@ -11,6 +11,7 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.classprovider.ClasspathClassProvider;
14import cuchaz.enigma.source.Decompiler; 15import cuchaz.enigma.source.Decompiler;
15import cuchaz.enigma.source.Decompilers; 16import cuchaz.enigma.source.Decompilers;
16import cuchaz.enigma.source.SourceSettings; 17import cuchaz.enigma.source.SourceSettings;
@@ -22,7 +23,7 @@ import java.nio.file.Paths;
22public class TestDeobfuscator { 23public class TestDeobfuscator {
23 private EnigmaProject openProject() throws IOException { 24 private EnigmaProject openProject() throws IOException {
24 Enigma enigma = Enigma.create(); 25 Enigma enigma = Enigma.create();
25 return enigma.openJar(Paths.get("build/test-obf/loneClass.jar"), ProgressListener.none()); 26 return enigma.openJar(Paths.get("build/test-obf/loneClass.jar"), new ClasspathClassProvider(), ProgressListener.none());
26 } 27 }
27 28
28 @Test 29 @Test
@@ -34,7 +35,7 @@ public class TestDeobfuscator {
34 @Test 35 @Test
35 public void decompileClass() throws Exception { 36 public void decompileClass() throws Exception {
36 EnigmaProject project = openProject(); 37 EnigmaProject project = openProject();
37 Decompiler decompiler = Decompilers.PROCYON.create(project.getClassCache(), new SourceSettings(false, false)); 38 Decompiler decompiler = Decompilers.PROCYON.create(project.getClassProvider(), new SourceSettings(false, false));
38 39
39 decompiler.getSource("a").asString(); 40 decompiler.getSource("a").asString();
40 } 41 }
diff --git a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
index 85c72f81..6b609941 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestInnerClasses.java
@@ -11,14 +11,16 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.ClassCache;
15import cuchaz.enigma.analysis.index.JarIndex; 14import cuchaz.enigma.analysis.index.JarIndex;
15import cuchaz.enigma.classprovider.CachingClassProvider;
16import cuchaz.enigma.classprovider.JarClassProvider;
16import cuchaz.enigma.source.Decompiler; 17import cuchaz.enigma.source.Decompiler;
17import cuchaz.enigma.source.Decompilers; 18import cuchaz.enigma.source.Decompilers;
18import cuchaz.enigma.source.SourceSettings; 19import cuchaz.enigma.source.SourceSettings;
19import cuchaz.enigma.translation.representation.entry.ClassEntry; 20import cuchaz.enigma.translation.representation.entry.ClassEntry;
20import org.junit.Test; 21import org.junit.Test;
21 22
23import java.nio.file.Path;
22import java.nio.file.Paths; 24import java.nio.file.Paths;
23 25
24import static cuchaz.enigma.TestEntryFactory.newClass; 26import static cuchaz.enigma.TestEntryFactory.newClass;
@@ -35,13 +37,16 @@ public class TestInnerClasses {
35 private static final ClassEntry ClassTreeLevel1 = newClass("f$a"); 37 private static final ClassEntry ClassTreeLevel1 = newClass("f$a");
36 private static final ClassEntry ClassTreeLevel2 = newClass("f$a$a"); 38 private static final ClassEntry ClassTreeLevel2 = newClass("f$a$a");
37 private static final ClassEntry ClassTreeLevel3 = newClass("f$a$a$a"); 39 private static final ClassEntry ClassTreeLevel3 = newClass("f$a$a$a");
40 public static final Path JAR = Paths.get("build/test-obf/innerClasses.jar");
38 private final JarIndex index; 41 private final JarIndex index;
39 private final Decompiler decompiler; 42 private final Decompiler decompiler;
40 43
41 public TestInnerClasses() throws Exception { 44 public TestInnerClasses() throws Exception {
42 ClassCache classCache = ClassCache.of(Paths.get("build/test-obf/innerClasses.jar")); 45 JarClassProvider jcp = new JarClassProvider(JAR);
43 index = classCache.index(ProgressListener.none()); 46 CachingClassProvider classProvider = new CachingClassProvider(jcp);
44 decompiler = Decompilers.PROCYON.create(classCache, new SourceSettings(false, false)); 47 index = JarIndex.empty();
48 index.indexJar(jcp.getClassNames(), classProvider, ProgressListener.none());
49 decompiler = Decompilers.PROCYON.create(classProvider, new SourceSettings(false, false));
45 } 50 }
46 51
47 @Test 52 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
index 48975c82..0790193d 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexConstructorReferences.java
@@ -11,14 +11,16 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.ClassCache;
15import cuchaz.enigma.analysis.EntryReference; 14import cuchaz.enigma.analysis.EntryReference;
16import cuchaz.enigma.analysis.index.JarIndex; 15import cuchaz.enigma.analysis.index.JarIndex;
16import cuchaz.enigma.classprovider.CachingClassProvider;
17import cuchaz.enigma.classprovider.JarClassProvider;
17import cuchaz.enigma.translation.representation.entry.ClassEntry; 18import cuchaz.enigma.translation.representation.entry.ClassEntry;
18import cuchaz.enigma.translation.representation.entry.MethodDefEntry; 19import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
19import cuchaz.enigma.translation.representation.entry.MethodEntry; 20import cuchaz.enigma.translation.representation.entry.MethodEntry;
20import org.junit.Test; 21import org.junit.Test;
21 22
23import java.nio.file.Path;
22import java.nio.file.Paths; 24import java.nio.file.Paths;
23import java.util.Collection; 25import java.util.Collection;
24 26
@@ -28,6 +30,7 @@ import static org.hamcrest.Matchers.*;
28 30
29public class TestJarIndexConstructorReferences { 31public class TestJarIndexConstructorReferences {
30 32
33 public static final Path JAR = Paths.get("build/test-obf/constructors.jar");
31 private JarIndex index; 34 private JarIndex index;
32 35
33 private ClassEntry baseClass = newClass("a"); 36 private ClassEntry baseClass = newClass("a");
@@ -37,8 +40,9 @@ public class TestJarIndexConstructorReferences {
37 private ClassEntry callerClass = newClass("b"); 40 private ClassEntry callerClass = newClass("b");
38 41
39 public TestJarIndexConstructorReferences() throws Exception { 42 public TestJarIndexConstructorReferences() throws Exception {
40 ClassCache classCache = ClassCache.of(Paths.get("build/test-obf/constructors.jar")); 43 JarClassProvider jcp = new JarClassProvider(JAR);
41 index = classCache.index(ProgressListener.none()); 44 index = JarIndex.empty();
45 index.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none());
42 } 46 }
43 47
44 @Test 48 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
index 76e379c3..a9045f9c 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexInheritanceTree.java
@@ -11,11 +11,12 @@
11 11
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import cuchaz.enigma.analysis.ClassCache;
15import cuchaz.enigma.analysis.EntryReference; 14import cuchaz.enigma.analysis.EntryReference;
16import cuchaz.enigma.analysis.index.EntryIndex; 15import cuchaz.enigma.analysis.index.EntryIndex;
17import cuchaz.enigma.analysis.index.InheritanceIndex; 16import cuchaz.enigma.analysis.index.InheritanceIndex;
18import cuchaz.enigma.analysis.index.JarIndex; 17import cuchaz.enigma.analysis.index.JarIndex;
18import cuchaz.enigma.classprovider.CachingClassProvider;
19import cuchaz.enigma.classprovider.JarClassProvider;
19import cuchaz.enigma.translation.mapping.EntryResolver; 20import cuchaz.enigma.translation.mapping.EntryResolver;
20import cuchaz.enigma.translation.mapping.IndexEntryResolver; 21import cuchaz.enigma.translation.mapping.IndexEntryResolver;
21import cuchaz.enigma.translation.representation.AccessFlags; 22import cuchaz.enigma.translation.representation.AccessFlags;
@@ -26,6 +27,7 @@ import cuchaz.enigma.translation.representation.entry.MethodEntry;
26import org.junit.Test; 27import org.junit.Test;
27import org.objectweb.asm.Opcodes; 28import org.objectweb.asm.Opcodes;
28 29
30import java.nio.file.Path;
29import java.nio.file.Paths; 31import java.nio.file.Paths;
30import java.util.Collection; 32import java.util.Collection;
31 33
@@ -35,6 +37,7 @@ import static org.hamcrest.Matchers.*;
35 37
36public class TestJarIndexInheritanceTree { 38public class TestJarIndexInheritanceTree {
37 39
40 public static final Path JAR = Paths.get("build/test-obf/inheritanceTree.jar");
38 private JarIndex index; 41 private JarIndex index;
39 42
40 private ClassEntry baseClass = newClass("a"); 43 private ClassEntry baseClass = newClass("a");
@@ -44,10 +47,10 @@ public class TestJarIndexInheritanceTree {
44 private FieldEntry nameField = newField(baseClass, "a", "Ljava/lang/String;"); 47 private FieldEntry nameField = newField(baseClass, "a", "Ljava/lang/String;");
45 private FieldEntry numThingsField = newField(subClassB, "a", "I"); 48 private FieldEntry numThingsField = newField(subClassB, "a", "I");
46 49
47 public TestJarIndexInheritanceTree() 50 public TestJarIndexInheritanceTree() throws Exception {
48 throws Exception { 51 JarClassProvider jcp = new JarClassProvider(JAR);
49 ClassCache classCache = ClassCache.of(Paths.get("build/test-obf/inheritanceTree.jar")); 52 index = JarIndex.empty();
50 index = classCache.index(ProgressListener.none()); 53 index.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none());
51 } 54 }
52 55
53 @Test 56 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
index 103c366b..6e3755ca 100644
--- a/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
+++ b/enigma/src/test/java/cuchaz/enigma/TestJarIndexLoneClass.java
@@ -15,6 +15,8 @@ import cuchaz.enigma.analysis.*;
15import cuchaz.enigma.analysis.index.EntryIndex; 15import cuchaz.enigma.analysis.index.EntryIndex;
16import cuchaz.enigma.analysis.index.InheritanceIndex; 16import cuchaz.enigma.analysis.index.InheritanceIndex;
17import cuchaz.enigma.analysis.index.JarIndex; 17import cuchaz.enigma.analysis.index.JarIndex;
18import cuchaz.enigma.classprovider.CachingClassProvider;
19import cuchaz.enigma.classprovider.JarClassProvider;
18import cuchaz.enigma.translation.VoidTranslator; 20import cuchaz.enigma.translation.VoidTranslator;
19import cuchaz.enigma.translation.representation.AccessFlags; 21import cuchaz.enigma.translation.representation.AccessFlags;
20import cuchaz.enigma.translation.representation.entry.ClassEntry; 22import cuchaz.enigma.translation.representation.entry.ClassEntry;
@@ -23,6 +25,7 @@ import cuchaz.enigma.translation.representation.entry.MethodDefEntry;
23import cuchaz.enigma.translation.representation.entry.MethodEntry; 25import cuchaz.enigma.translation.representation.entry.MethodEntry;
24import org.junit.Test; 26import org.junit.Test;
25 27
28import java.nio.file.Path;
26import java.nio.file.Paths; 29import java.nio.file.Paths;
27import java.util.Collection; 30import java.util.Collection;
28import java.util.List; 31import java.util.List;
@@ -33,11 +36,13 @@ import static org.hamcrest.Matchers.*;
33 36
34public class TestJarIndexLoneClass { 37public class TestJarIndexLoneClass {
35 38
39 public static final Path JAR = Paths.get("build/test-obf/loneClass.jar");
36 private JarIndex index; 40 private JarIndex index;
37 41
38 public TestJarIndexLoneClass() throws Exception { 42 public TestJarIndexLoneClass() throws Exception {
39 ClassCache classCache = ClassCache.of(Paths.get("build/test-obf/loneClass.jar")); 43 JarClassProvider jcp = new JarClassProvider(JAR);
40 index = classCache.index(ProgressListener.none()); 44 index = JarIndex.empty();
45 index.indexJar(jcp.getClassNames(), new CachingClassProvider(jcp), ProgressListener.none());
41 } 46 }
42 47
43 @Test 48 @Test
diff --git a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
index 96fc6dab..feef272e 100644
--- a/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
+++ b/enigma/src/test/java/cuchaz/enigma/TokenChecker.java
@@ -12,11 +12,10 @@
12package cuchaz.enigma; 12package cuchaz.enigma;
13 13
14import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15import cuchaz.enigma.analysis.ClassCache;
16import cuchaz.enigma.analysis.EntryReference; 15import cuchaz.enigma.analysis.EntryReference;
17import cuchaz.enigma.source.SourceIndex; 16import cuchaz.enigma.classprovider.CachingClassProvider;
17import cuchaz.enigma.classprovider.JarClassProvider;
18import cuchaz.enigma.source.*; 18import cuchaz.enigma.source.*;
19import cuchaz.enigma.source.Token;
20import cuchaz.enigma.translation.representation.entry.Entry; 19import cuchaz.enigma.translation.representation.entry.Entry;
21 20
22import java.io.IOException; 21import java.io.IOException;
@@ -28,8 +27,8 @@ public class TokenChecker {
28 private final Decompiler decompiler; 27 private final Decompiler decompiler;
29 28
30 protected TokenChecker(Path path) throws IOException { 29 protected TokenChecker(Path path) throws IOException {
31 ClassCache classCache = ClassCache.of(path); 30 CachingClassProvider classProvider = new CachingClassProvider(new JarClassProvider(path));
32 decompiler = Decompilers.PROCYON.create(classCache, new SourceSettings(false, false)); 31 decompiler = Decompilers.PROCYON.create(classProvider, new SourceSettings(false, false));
33 } 32 }
34 33
35 protected String getDeclarationToken(Entry<?> entry) { 34 protected String getDeclarationToken(Entry<?> entry) {
diff --git a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
index 65941e54..60c70b73 100644
--- a/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
+++ b/enigma/src/test/java/cuchaz/enigma/translation/mapping/TestTinyV2InnerClasses.java
@@ -14,6 +14,7 @@ package cuchaz.enigma.translation.mapping;
14import cuchaz.enigma.Enigma; 14import cuchaz.enigma.Enigma;
15import cuchaz.enigma.EnigmaProject; 15import cuchaz.enigma.EnigmaProject;
16import cuchaz.enigma.ProgressListener; 16import cuchaz.enigma.ProgressListener;
17import cuchaz.enigma.classprovider.ClasspathClassProvider;
17import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader; 18import cuchaz.enigma.translation.mapping.serde.enigma.EnigmaMappingsReader;
18 19
19import java.nio.file.Path; 20import java.nio.file.Path;
@@ -30,7 +31,7 @@ public final class TestTinyV2InnerClasses {
30 31
31// @Test 32// @Test
32 public void testMappings() throws Exception { 33 public void testMappings() throws Exception {
33 EnigmaProject project = Enigma.create().openJar(jar, ProgressListener.none()); 34 EnigmaProject project = Enigma.create().openJar(jar, new ClasspathClassProvider(), ProgressListener.none());
34 project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters())); 35 project.setMappings(EnigmaMappingsReader.DIRECTORY.read(mappings, ProgressListener.none(), project.getEnigma().getProfile().getMappingSaveParameters()));
35 36
36 } 37 }