diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/cuchaz/enigma/ConvertMain.java | 135 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 28 | ||||
| -rw-r--r-- | src/cuchaz/enigma/convert/FieldMatches.java | 69 | ||||
| -rw-r--r-- | src/cuchaz/enigma/convert/MatchesReader.java | 40 | ||||
| -rw-r--r-- | src/cuchaz/enigma/convert/MatchesWriter.java | 38 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/ClassMatchingGui.java | 3 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/CodeReader.java | 56 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/FieldMatchingGui.java | 212 | ||||
| -rw-r--r-- | src/cuchaz/enigma/mapping/EntryFactory.java | 16 |
9 files changed, 525 insertions, 72 deletions
diff --git a/src/cuchaz/enigma/ConvertMain.java b/src/cuchaz/enigma/ConvertMain.java index 624eb40..a5a00e8 100644 --- a/src/cuchaz/enigma/ConvertMain.java +++ b/src/cuchaz/enigma/ConvertMain.java | |||
| @@ -4,8 +4,12 @@ import java.io.File; | |||
| 4 | import java.io.FileReader; | 4 | import java.io.FileReader; |
| 5 | import java.io.FileWriter; | 5 | import java.io.FileWriter; |
| 6 | import java.io.IOException; | 6 | import java.io.IOException; |
| 7 | import java.util.Set; | ||
| 7 | import java.util.jar.JarFile; | 8 | import java.util.jar.JarFile; |
| 8 | 9 | ||
| 10 | import com.google.common.collect.BiMap; | ||
| 11 | import com.google.common.collect.Sets; | ||
| 12 | |||
| 9 | import cuchaz.enigma.convert.ClassMatches; | 13 | import cuchaz.enigma.convert.ClassMatches; |
| 10 | import cuchaz.enigma.convert.FieldMatches; | 14 | import cuchaz.enigma.convert.FieldMatches; |
| 11 | import cuchaz.enigma.convert.MappingsConverter; | 15 | import cuchaz.enigma.convert.MappingsConverter; |
| @@ -13,11 +17,18 @@ import cuchaz.enigma.convert.MatchesReader; | |||
| 13 | import cuchaz.enigma.convert.MatchesWriter; | 17 | import cuchaz.enigma.convert.MatchesWriter; |
| 14 | import cuchaz.enigma.gui.ClassMatchingGui; | 18 | import cuchaz.enigma.gui.ClassMatchingGui; |
| 15 | import cuchaz.enigma.gui.FieldMatchingGui; | 19 | import cuchaz.enigma.gui.FieldMatchingGui; |
| 20 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 21 | import cuchaz.enigma.mapping.ClassMapping; | ||
| 22 | import cuchaz.enigma.mapping.ClassNameReplacer; | ||
| 23 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 24 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 25 | import cuchaz.enigma.mapping.FieldMapping; | ||
| 16 | import cuchaz.enigma.mapping.MappingParseException; | 26 | import cuchaz.enigma.mapping.MappingParseException; |
| 17 | import cuchaz.enigma.mapping.Mappings; | 27 | import cuchaz.enigma.mapping.Mappings; |
| 18 | import cuchaz.enigma.mapping.MappingsChecker; | 28 | import cuchaz.enigma.mapping.MappingsChecker; |
| 19 | import cuchaz.enigma.mapping.MappingsReader; | 29 | import cuchaz.enigma.mapping.MappingsReader; |
| 20 | import cuchaz.enigma.mapping.MappingsWriter; | 30 | import cuchaz.enigma.mapping.MappingsWriter; |
| 31 | import cuchaz.enigma.mapping.Type; | ||
| 21 | 32 | ||
| 22 | 33 | ||
| 23 | public class ConvertMain { | 34 | public class ConvertMain { |
| @@ -32,13 +43,14 @@ public class ConvertMain { | |||
| 32 | File inMappingsFile = new File("../Enigma Mappings/1.8.mappings"); | 43 | File inMappingsFile = new File("../Enigma Mappings/1.8.mappings"); |
| 33 | File outMappingsFile = new File("../Enigma Mappings/1.8.3.mappings"); | 44 | File outMappingsFile = new File("../Enigma Mappings/1.8.3.mappings"); |
| 34 | Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); | 45 | Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); |
| 35 | File classMatchingFile = new File(inMappingsFile.getName() + ".class.matching"); | 46 | File classMatchesFile = new File(inMappingsFile.getName() + ".class.matches"); |
| 36 | File fieldMatchingFile = new File(inMappingsFile.getName() + ".field.matching"); | 47 | File fieldMatchesFile = new File(inMappingsFile.getName() + ".field.matches"); |
| 37 | 48 | ||
| 38 | //computeMatches(classMatchingFile, sourceJar, destJar, mappings); | 49 | //computeClassMatches(classMatchingFile, sourceJar, destJar, mappings); |
| 39 | //editClasssMatches(classMatchingFile, sourceJar, destJar, mappings); | 50 | //editClasssMatches(classMatchingFile, sourceJar, destJar, mappings); |
| 40 | //convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchingFile); | 51 | //convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchingFile); |
| 41 | editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchingFile, fieldMatchingFile); | 52 | //computeFieldMatches(fieldMatchesFile, destJar, outMappingsFile, classMatchesFile); |
| 53 | editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile); | ||
| 42 | 54 | ||
| 43 | /* TODO | 55 | /* TODO |
| 44 | // write out the converted mappings | 56 | // write out the converted mappings |
| @@ -49,17 +61,17 @@ public class ConvertMain { | |||
| 49 | */ | 61 | */ |
| 50 | } | 62 | } |
| 51 | 63 | ||
| 52 | private static void computeMatches(File classMatchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings) | 64 | private static void computeClassMatches(File classMatchesFile, JarFile sourceJar, JarFile destJar, Mappings mappings) |
| 53 | throws IOException { | 65 | throws IOException { |
| 54 | ClassMatches classMatches = MappingsConverter.computeMatches(sourceJar, destJar, mappings); | 66 | ClassMatches classMatches = MappingsConverter.computeMatches(sourceJar, destJar, mappings); |
| 55 | MatchesWriter.writeClasses(classMatches, classMatchingFile); | 67 | MatchesWriter.writeClasses(classMatches, classMatchesFile); |
| 56 | System.out.println("Wrote:\n\t" + classMatchingFile.getAbsolutePath()); | 68 | System.out.println("Wrote:\n\t" + classMatchesFile.getAbsolutePath()); |
| 57 | } | 69 | } |
| 58 | 70 | ||
| 59 | private static void editClasssMatches(final File classMatchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings) | 71 | private static void editClasssMatches(final File classMatchesFile, JarFile sourceJar, JarFile destJar, Mappings mappings) |
| 60 | throws IOException { | 72 | throws IOException { |
| 61 | System.out.println("Reading matches..."); | 73 | System.out.println("Reading class matches..."); |
| 62 | ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile); | 74 | ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); |
| 63 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); | 75 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); |
| 64 | deobfuscators.source.setMappings(mappings); | 76 | deobfuscators.source.setMappings(mappings); |
| 65 | System.out.println("Starting GUI..."); | 77 | System.out.println("Starting GUI..."); |
| @@ -67,7 +79,7 @@ public class ConvertMain { | |||
| 67 | @Override | 79 | @Override |
| 68 | public void save(ClassMatches matches) { | 80 | public void save(ClassMatches matches) { |
| 69 | try { | 81 | try { |
| 70 | MatchesWriter.writeClasses(matches, classMatchingFile); | 82 | MatchesWriter.writeClasses(matches, classMatchesFile); |
| 71 | } catch (IOException ex) { | 83 | } catch (IOException ex) { |
| 72 | throw new Error(ex); | 84 | throw new Error(ex); |
| 73 | } | 85 | } |
| @@ -75,10 +87,10 @@ public class ConvertMain { | |||
| 75 | }); | 87 | }); |
| 76 | } | 88 | } |
| 77 | 89 | ||
| 78 | private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchingFile) | 90 | private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchesFile) |
| 79 | throws IOException { | 91 | throws IOException { |
| 80 | System.out.println("Reading matches..."); | 92 | System.out.println("Reading class matches..."); |
| 81 | ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile); | 93 | ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); |
| 82 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); | 94 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); |
| 83 | deobfuscators.source.setMappings(mappings); | 95 | deobfuscators.source.setMappings(mappings); |
| 84 | 96 | ||
| @@ -90,19 +102,90 @@ public class ConvertMain { | |||
| 90 | System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath()); | 102 | System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath()); |
| 91 | } | 103 | } |
| 92 | 104 | ||
| 93 | private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchingFile, final File fieldMatchingFile) | 105 | private static void computeFieldMatches(File fieldMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile) |
| 94 | throws IOException, MappingParseException { | 106 | throws IOException, MappingParseException { |
| 95 | 107 | ||
| 96 | System.out.println("Reading matches..."); | 108 | System.out.println("Reading class matches..."); |
| 97 | ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile); | 109 | ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); |
| 98 | FieldMatches fieldMatches; | 110 | System.out.println("Reading mappings..."); |
| 99 | if (fieldMatchingFile.exists() /* TEMP */ && false) { | 111 | Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile)); |
| 100 | // TODO | 112 | System.out.println("Indexing dest jar..."); |
| 101 | //fieldMatches = MatchesReader.readFields(fieldMatchingFile); | 113 | Deobfuscator destDeobfuscator = new Deobfuscator(destJar); |
| 102 | } else { | 114 | |
| 103 | fieldMatches = new FieldMatches(); | 115 | System.out.println("Writing field matches..."); |
| 116 | |||
| 117 | // get the matched and unmatched field mappings | ||
| 118 | FieldMatches fieldMatches = new FieldMatches(); | ||
| 119 | |||
| 120 | // unmatched source fields are easy | ||
| 121 | MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex()); | ||
| 122 | checker.dropBrokenMappings(destMappings); | ||
| 123 | for (FieldEntry destObfField : checker.getDroppedFieldMappings().keySet()) { | ||
| 124 | FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); | ||
| 125 | fieldMatches.addUnmatchedSourceField(srcObfField); | ||
| 126 | } | ||
| 127 | |||
| 128 | // get matched fields (anything that's left after the checks/drops is matched( | ||
| 129 | for (ClassMapping classMapping : destMappings.classes()) { | ||
| 130 | collectMatchedFields(fieldMatches, classMapping, classMatches); | ||
| 131 | } | ||
| 132 | |||
| 133 | // get unmatched dest fields | ||
| 134 | Set<FieldEntry> unmatchedDestFields = Sets.newHashSet(); | ||
| 135 | for (FieldEntry destFieldEntry : destDeobfuscator.getJarIndex().getObfFieldEntries()) { | ||
| 136 | if (!fieldMatches.isDestMatched(destFieldEntry)) { | ||
| 137 | unmatchedDestFields.add(destFieldEntry); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | fieldMatches.addUnmatchedDestFields(unmatchedDestFields); | ||
| 141 | |||
| 142 | MatchesWriter.writeFields(fieldMatches, fieldMatchesFile); | ||
| 143 | System.out.println("Wrote:\n\t" + fieldMatchesFile.getAbsolutePath()); | ||
| 144 | } | ||
| 145 | |||
| 146 | private static void collectMatchedFields(FieldMatches fieldMatches, ClassMapping destClassMapping, ClassMatches classMatches) { | ||
| 147 | |||
| 148 | // get the fields for this class | ||
| 149 | for (FieldMapping destFieldMapping : destClassMapping.fields()) { | ||
| 150 | FieldEntry destObfField = EntryFactory.getObfFieldEntry(destClassMapping, destFieldMapping); | ||
| 151 | FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); | ||
| 152 | fieldMatches.addMatch(srcObfField, destObfField); | ||
| 104 | } | 153 | } |
| 105 | 154 | ||
| 155 | // recurse | ||
| 156 | for (ClassMapping destInnerClassMapping : destClassMapping.innerClasses()) { | ||
| 157 | collectMatchedFields(fieldMatches, destInnerClassMapping, classMatches); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | private static FieldEntry translate(FieldEntry in, BiMap<ClassEntry,ClassEntry> map) { | ||
| 162 | return new FieldEntry( | ||
| 163 | map.get(in.getClassEntry()), | ||
| 164 | in.getName(), | ||
| 165 | translate(in.getType(), map) | ||
| 166 | ); | ||
| 167 | } | ||
| 168 | |||
| 169 | private static Type translate(Type type, final BiMap<ClassEntry,ClassEntry> map) { | ||
| 170 | return new Type(type, new ClassNameReplacer() { | ||
| 171 | @Override | ||
| 172 | public String replace(String inClassName) { | ||
| 173 | ClassEntry outClassEntry = map.get(new ClassEntry(inClassName)); | ||
| 174 | if (outClassEntry == null) { | ||
| 175 | return null; | ||
| 176 | } | ||
| 177 | return outClassEntry.getName(); | ||
| 178 | } | ||
| 179 | }); | ||
| 180 | } | ||
| 181 | |||
| 182 | private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File fieldMatchesFile) | ||
| 183 | throws IOException, MappingParseException { | ||
| 184 | |||
| 185 | System.out.println("Reading matches..."); | ||
| 186 | ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); | ||
| 187 | FieldMatches fieldMatches = MatchesReader.readFields(fieldMatchesFile); | ||
| 188 | |||
| 106 | // prep deobfuscators | 189 | // prep deobfuscators |
| 107 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); | 190 | Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); |
| 108 | deobfuscators.source.setMappings(sourceMappings); | 191 | deobfuscators.source.setMappings(sourceMappings); |
| @@ -111,16 +194,14 @@ public class ConvertMain { | |||
| 111 | checker.dropBrokenMappings(destMappings); | 194 | checker.dropBrokenMappings(destMappings); |
| 112 | deobfuscators.dest.setMappings(destMappings); | 195 | deobfuscators.dest.setMappings(destMappings); |
| 113 | 196 | ||
| 114 | new FieldMatchingGui(classMatches, fieldMatches, checker.getDroppedFieldMappings(), deobfuscators.source, deobfuscators.dest).setSaveListener(new FieldMatchingGui.SaveListener() { | 197 | new FieldMatchingGui(classMatches, fieldMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new FieldMatchingGui.SaveListener() { |
| 115 | @Override | 198 | @Override |
| 116 | public void save(FieldMatches matches) { | 199 | public void save(FieldMatches matches) { |
| 117 | /* TODO | ||
| 118 | try { | 200 | try { |
| 119 | MatchesWriter.writeFields(matches, fieldMatchingFile); | 201 | MatchesWriter.writeFields(matches, fieldMatchesFile); |
| 120 | } catch (IOException ex) { | 202 | } catch (IOException ex) { |
| 121 | throw new Error(ex); | 203 | throw new Error(ex); |
| 122 | } | 204 | } |
| 123 | */ | ||
| 124 | } | 205 | } |
| 125 | }); | 206 | }); |
| 126 | } | 207 | } |
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index e0a8bf5..7ebbd97 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -60,6 +60,8 @@ public class JarIndex { | |||
| 60 | private TranslationIndex m_translationIndex; | 60 | private TranslationIndex m_translationIndex; |
| 61 | private Multimap<String,String> m_interfaces; | 61 | private Multimap<String,String> m_interfaces; |
| 62 | private Map<Entry,Access> m_access; | 62 | private Map<Entry,Access> m_access; |
| 63 | private Multimap<ClassEntry,FieldEntry> m_fields; | ||
| 64 | private Multimap<ClassEntry,BehaviorEntry> m_behaviors; | ||
| 63 | private Multimap<String,MethodEntry> m_methodImplementations; | 65 | private Multimap<String,MethodEntry> m_methodImplementations; |
| 64 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; | 66 | private Multimap<BehaviorEntry,EntryReference<BehaviorEntry,BehaviorEntry>> m_behaviorReferences; |
| 65 | private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences; | 67 | private Multimap<FieldEntry,EntryReference<FieldEntry,BehaviorEntry>> m_fieldReferences; |
| @@ -73,6 +75,8 @@ public class JarIndex { | |||
| 73 | m_translationIndex = new TranslationIndex(); | 75 | m_translationIndex = new TranslationIndex(); |
| 74 | m_interfaces = HashMultimap.create(); | 76 | m_interfaces = HashMultimap.create(); |
| 75 | m_access = Maps.newHashMap(); | 77 | m_access = Maps.newHashMap(); |
| 78 | m_fields = HashMultimap.create(); | ||
| 79 | m_behaviors = HashMultimap.create(); | ||
| 76 | m_methodImplementations = HashMultimap.create(); | 80 | m_methodImplementations = HashMultimap.create(); |
| 77 | m_behaviorReferences = HashMultimap.create(); | 81 | m_behaviorReferences = HashMultimap.create(); |
| 78 | m_fieldReferences = HashMultimap.create(); | 82 | m_fieldReferences = HashMultimap.create(); |
| @@ -97,10 +101,14 @@ public class JarIndex { | |||
| 97 | for (CtClass c : JarClassIterator.classes(jar)) { | 101 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 98 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); | 102 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); |
| 99 | for (CtField field : c.getDeclaredFields()) { | 103 | for (CtField field : c.getDeclaredFields()) { |
| 100 | m_access.put(EntryFactory.getFieldEntry(field), Access.get(field)); | 104 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 105 | m_access.put(fieldEntry, Access.get(field)); | ||
| 106 | m_fields.put(fieldEntry.getClassEntry(), fieldEntry); | ||
| 101 | } | 107 | } |
| 102 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 108 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 103 | m_access.put(EntryFactory.getBehaviorEntry(behavior), Access.get(behavior)); | 109 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 110 | m_access.put(behaviorEntry, Access.get(behavior)); | ||
| 111 | m_behaviors.put(behaviorEntry.getClassEntry(), behaviorEntry); | ||
| 104 | } | 112 | } |
| 105 | } | 113 | } |
| 106 | 114 | ||
| @@ -520,6 +528,22 @@ public class JarIndex { | |||
| 520 | return m_obfClassEntries; | 528 | return m_obfClassEntries; |
| 521 | } | 529 | } |
| 522 | 530 | ||
| 531 | public Collection<FieldEntry> getObfFieldEntries() { | ||
| 532 | return m_fields.values(); | ||
| 533 | } | ||
| 534 | |||
| 535 | public Collection<FieldEntry> getObfFieldEntries(ClassEntry classEntry) { | ||
| 536 | return m_fields.get(classEntry); | ||
| 537 | } | ||
| 538 | |||
| 539 | public Collection<BehaviorEntry> getObfBehaviorEntries() { | ||
| 540 | return m_behaviors.values(); | ||
| 541 | } | ||
| 542 | |||
| 543 | public Collection<BehaviorEntry> getObfBehaviorEntries(ClassEntry classEntry) { | ||
| 544 | return m_behaviors.get(classEntry); | ||
| 545 | } | ||
| 546 | |||
| 523 | public TranslationIndex getTranslationIndex() { | 547 | public TranslationIndex getTranslationIndex() { |
| 524 | return m_translationIndex; | 548 | return m_translationIndex; |
| 525 | } | 549 | } |
diff --git a/src/cuchaz/enigma/convert/FieldMatches.java b/src/cuchaz/enigma/convert/FieldMatches.java index f78a8f5..6335974 100644 --- a/src/cuchaz/enigma/convert/FieldMatches.java +++ b/src/cuchaz/enigma/convert/FieldMatches.java | |||
| @@ -5,7 +5,8 @@ import java.util.Set; | |||
| 5 | 5 | ||
| 6 | import com.google.common.collect.BiMap; | 6 | import com.google.common.collect.BiMap; |
| 7 | import com.google.common.collect.HashBiMap; | 7 | import com.google.common.collect.HashBiMap; |
| 8 | import com.google.common.collect.Sets; | 8 | import com.google.common.collect.HashMultimap; |
| 9 | import com.google.common.collect.Multimap; | ||
| 9 | 10 | ||
| 10 | import cuchaz.enigma.mapping.ClassEntry; | 11 | import cuchaz.enigma.mapping.ClassEntry; |
| 11 | import cuchaz.enigma.mapping.FieldEntry; | 12 | import cuchaz.enigma.mapping.FieldEntry; |
| @@ -14,22 +15,70 @@ import cuchaz.enigma.mapping.FieldEntry; | |||
| 14 | public class FieldMatches { | 15 | public class FieldMatches { |
| 15 | 16 | ||
| 16 | private BiMap<FieldEntry,FieldEntry> m_matches; | 17 | private BiMap<FieldEntry,FieldEntry> m_matches; |
| 17 | private Set<FieldEntry> m_unmatchedSourceFields; | 18 | private Multimap<ClassEntry,FieldEntry> m_unmatchedSourceFields; |
| 19 | private Multimap<ClassEntry,FieldEntry> m_unmatchedDestFields; | ||
| 18 | 20 | ||
| 19 | public FieldMatches() { | 21 | public FieldMatches() { |
| 20 | m_matches = HashBiMap.create(); | 22 | m_matches = HashBiMap.create(); |
| 21 | m_unmatchedSourceFields = Sets.newHashSet(); | 23 | m_unmatchedSourceFields = HashMultimap.create(); |
| 24 | m_unmatchedDestFields = HashMultimap.create(); | ||
| 22 | } | 25 | } |
| 23 | 26 | ||
| 24 | public void addUnmatchedSourceFields(Set<FieldEntry> fieldEntries) { | 27 | public void addMatch(FieldEntry srcField, FieldEntry destField) { |
| 25 | m_unmatchedSourceFields.addAll(fieldEntries); | 28 | m_matches.put(srcField, destField); |
| 26 | } | 29 | } |
| 27 | 30 | ||
| 28 | public Collection<ClassEntry> getSourceClassesWithUnmatchedFields() { | 31 | public void addUnmatchedSourceField(FieldEntry fieldEntry) { |
| 29 | Set<ClassEntry> classEntries = Sets.newHashSet(); | 32 | m_unmatchedSourceFields.put(fieldEntry.getClassEntry(), fieldEntry); |
| 30 | for (FieldEntry fieldEntry : m_unmatchedSourceFields) { | 33 | } |
| 31 | classEntries.add(fieldEntry.getClassEntry()); | 34 | |
| 35 | public void addUnmatchedSourceFields(Iterable<FieldEntry> fieldEntries) { | ||
| 36 | for (FieldEntry fieldEntry : fieldEntries) { | ||
| 37 | addUnmatchedSourceField(fieldEntry); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | public void addUnmatchedDestField(FieldEntry fieldEntry) { | ||
| 42 | m_unmatchedDestFields.put(fieldEntry.getClassEntry(), fieldEntry); | ||
| 43 | } | ||
| 44 | |||
| 45 | public void addUnmatchedDestFields(Iterable<FieldEntry> fieldEntries) { | ||
| 46 | for (FieldEntry fieldEntry : fieldEntries) { | ||
| 47 | addUnmatchedDestField(fieldEntry); | ||
| 32 | } | 48 | } |
| 33 | return classEntries; | 49 | } |
| 50 | |||
| 51 | public Set<ClassEntry> getSourceClassesWithUnmatchedFields() { | ||
| 52 | return m_unmatchedSourceFields.keySet(); | ||
| 53 | } | ||
| 54 | |||
| 55 | public Collection<FieldEntry> getUnmatchedSourceFields() { | ||
| 56 | return m_unmatchedSourceFields.values(); | ||
| 57 | } | ||
| 58 | |||
| 59 | public Collection<FieldEntry> getUnmatchedSourceFields(ClassEntry sourceClass) { | ||
| 60 | return m_unmatchedSourceFields.get(sourceClass); | ||
| 61 | } | ||
| 62 | |||
| 63 | public Collection<FieldEntry> getUnmatchedDestFields() { | ||
| 64 | return m_unmatchedDestFields.values(); | ||
| 65 | } | ||
| 66 | |||
| 67 | public Collection<FieldEntry> getUnmatchedDestFields(ClassEntry sourceClass) { | ||
| 68 | return m_unmatchedDestFields.get(sourceClass); | ||
| 69 | } | ||
| 70 | |||
| 71 | public BiMap<FieldEntry,FieldEntry> matches() { | ||
| 72 | return m_matches; | ||
| 73 | } | ||
| 74 | |||
| 75 | public boolean isDestMatched(FieldEntry destFieldEntry) { | ||
| 76 | return m_matches.containsValue(destFieldEntry); | ||
| 77 | } | ||
| 78 | |||
| 79 | public void makeMatch(FieldEntry sourceField, FieldEntry destField) { | ||
| 80 | m_unmatchedSourceFields.remove(sourceField.getClassEntry(), sourceField); | ||
| 81 | m_unmatchedDestFields.remove(destField.getClassEntry(), destField); | ||
| 82 | m_matches.put(sourceField, destField); | ||
| 34 | } | 83 | } |
| 35 | } | 84 | } |
diff --git a/src/cuchaz/enigma/convert/MatchesReader.java b/src/cuchaz/enigma/convert/MatchesReader.java index b43535c..1dd042d 100644 --- a/src/cuchaz/enigma/convert/MatchesReader.java +++ b/src/cuchaz/enigma/convert/MatchesReader.java | |||
| @@ -10,6 +10,8 @@ import java.util.List; | |||
| 10 | import com.beust.jcommander.internal.Lists; | 10 | import com.beust.jcommander.internal.Lists; |
| 11 | 11 | ||
| 12 | import cuchaz.enigma.mapping.ClassEntry; | 12 | import cuchaz.enigma.mapping.ClassEntry; |
| 13 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 14 | import cuchaz.enigma.mapping.Type; | ||
| 13 | 15 | ||
| 14 | 16 | ||
| 15 | public class MatchesReader { | 17 | public class MatchesReader { |
| @@ -42,4 +44,42 @@ public class MatchesReader { | |||
| 42 | } | 44 | } |
| 43 | return entries; | 45 | return entries; |
| 44 | } | 46 | } |
| 47 | |||
| 48 | public static FieldMatches readFields(File file) | ||
| 49 | throws IOException { | ||
| 50 | try (BufferedReader in = new BufferedReader(new FileReader(file))) { | ||
| 51 | FieldMatches matches = new FieldMatches(); | ||
| 52 | String line = null; | ||
| 53 | while ((line = in.readLine()) != null) { | ||
| 54 | readFieldMatch(matches, line); | ||
| 55 | } | ||
| 56 | return matches; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | private static void readFieldMatch(FieldMatches matches, String line) { | ||
| 61 | String[] parts = line.split(":", 2); | ||
| 62 | FieldEntry source = readField(parts[0]); | ||
| 63 | FieldEntry dest = readField(parts[1]); | ||
| 64 | if (source != null && dest != null) { | ||
| 65 | matches.addMatch(source, dest); | ||
| 66 | } else if (source != null) { | ||
| 67 | matches.addUnmatchedSourceField(source); | ||
| 68 | } else if (dest != null) { | ||
| 69 | matches.addUnmatchedDestField(dest); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | private static FieldEntry readField(String in) { | ||
| 74 | if (in.length() <= 0) { | ||
| 75 | return null; | ||
| 76 | } | ||
| 77 | String[] parts = in.split(" "); | ||
| 78 | assert(parts.length == 3); | ||
| 79 | return new FieldEntry( | ||
| 80 | new ClassEntry(parts[0]), | ||
| 81 | parts[1], | ||
| 82 | new Type(parts[2]) | ||
| 83 | ); | ||
| 84 | } | ||
| 45 | } | 85 | } |
diff --git a/src/cuchaz/enigma/convert/MatchesWriter.java b/src/cuchaz/enigma/convert/MatchesWriter.java index 6658e2a..6e371bc 100644 --- a/src/cuchaz/enigma/convert/MatchesWriter.java +++ b/src/cuchaz/enigma/convert/MatchesWriter.java | |||
| @@ -3,8 +3,10 @@ package cuchaz.enigma.convert; | |||
| 3 | import java.io.File; | 3 | import java.io.File; |
| 4 | import java.io.FileWriter; | 4 | import java.io.FileWriter; |
| 5 | import java.io.IOException; | 5 | import java.io.IOException; |
| 6 | import java.util.Map; | ||
| 6 | 7 | ||
| 7 | import cuchaz.enigma.mapping.ClassEntry; | 8 | import cuchaz.enigma.mapping.ClassEntry; |
| 9 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 8 | 10 | ||
| 9 | 11 | ||
| 10 | public class MatchesWriter { | 12 | public class MatchesWriter { |
| @@ -38,4 +40,40 @@ public class MatchesWriter { | |||
| 38 | out.write(entry.toString()); | 40 | out.write(entry.toString()); |
| 39 | } | 41 | } |
| 40 | } | 42 | } |
| 43 | |||
| 44 | public static void writeFields(FieldMatches fieldMatches, File file) | ||
| 45 | throws IOException { | ||
| 46 | try (FileWriter out = new FileWriter(file)) { | ||
| 47 | for (Map.Entry<FieldEntry,FieldEntry> match : fieldMatches.matches().entrySet()) { | ||
| 48 | writeFieldMatch(out, match.getKey(), match.getValue()); | ||
| 49 | } | ||
| 50 | for (FieldEntry fieldEntry : fieldMatches.getUnmatchedSourceFields()) { | ||
| 51 | writeFieldMatch(out, fieldEntry, null); | ||
| 52 | } | ||
| 53 | for (FieldEntry fieldEntry : fieldMatches.getUnmatchedDestFields()) { | ||
| 54 | writeFieldMatch(out, null, fieldEntry); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | private static void writeFieldMatch(FileWriter out, FieldEntry source, FieldEntry dest) | ||
| 60 | throws IOException { | ||
| 61 | if (source != null) { | ||
| 62 | writeField(out, source); | ||
| 63 | } | ||
| 64 | out.write(":"); | ||
| 65 | if (dest != null) { | ||
| 66 | writeField(out, dest); | ||
| 67 | } | ||
| 68 | out.write("\n"); | ||
| 69 | } | ||
| 70 | |||
| 71 | private static void writeField(FileWriter out, FieldEntry fieldEntry) | ||
| 72 | throws IOException { | ||
| 73 | out.write(fieldEntry.getClassName()); | ||
| 74 | out.write(" "); | ||
| 75 | out.write(fieldEntry.getName()); | ||
| 76 | out.write(" "); | ||
| 77 | out.write(fieldEntry.getType().toString()); | ||
| 78 | } | ||
| 41 | } | 79 | } |
diff --git a/src/cuchaz/enigma/gui/ClassMatchingGui.java b/src/cuchaz/enigma/gui/ClassMatchingGui.java index b674451..6943c3e 100644 --- a/src/cuchaz/enigma/gui/ClassMatchingGui.java +++ b/src/cuchaz/enigma/gui/ClassMatchingGui.java | |||
| @@ -201,13 +201,10 @@ public class ClassMatchingGui { | |||
| 201 | 201 | ||
| 202 | m_sourceClassLabel = new JLabel(); | 202 | m_sourceClassLabel = new JLabel(); |
| 203 | m_sourceClassLabel.setHorizontalAlignment(SwingConstants.RIGHT); | 203 | m_sourceClassLabel.setHorizontalAlignment(SwingConstants.RIGHT); |
| 204 | m_sourceClassLabel.setPreferredSize(new Dimension(300, 24)); | ||
| 205 | m_destClassLabel = new JLabel(); | 204 | m_destClassLabel = new JLabel(); |
| 206 | m_destClassLabel.setHorizontalAlignment(SwingConstants.LEFT); | 205 | m_destClassLabel.setHorizontalAlignment(SwingConstants.LEFT); |
| 207 | m_destClassLabel.setPreferredSize(new Dimension(300, 24)); | ||
| 208 | 206 | ||
| 209 | m_matchButton = new JButton(); | 207 | m_matchButton = new JButton(); |
| 210 | m_matchButton.setPreferredSize(new Dimension(140, 24)); | ||
| 211 | 208 | ||
| 212 | m_advanceCheck = new JCheckBox("Advance to next likely match"); | 209 | m_advanceCheck = new JCheckBox("Advance to next likely match"); |
| 213 | m_advanceCheck.addActionListener(new ActionListener() { | 210 | m_advanceCheck.addActionListener(new ActionListener() { |
diff --git a/src/cuchaz/enigma/gui/CodeReader.java b/src/cuchaz/enigma/gui/CodeReader.java index 05feb59..aa7e2db 100644 --- a/src/cuchaz/enigma/gui/CodeReader.java +++ b/src/cuchaz/enigma/gui/CodeReader.java | |||
| @@ -7,12 +7,15 @@ import java.awt.event.ActionListener; | |||
| 7 | import javax.swing.JEditorPane; | 7 | import javax.swing.JEditorPane; |
| 8 | import javax.swing.SwingUtilities; | 8 | import javax.swing.SwingUtilities; |
| 9 | import javax.swing.Timer; | 9 | import javax.swing.Timer; |
| 10 | import javax.swing.event.CaretEvent; | ||
| 11 | import javax.swing.event.CaretListener; | ||
| 10 | import javax.swing.text.BadLocationException; | 12 | import javax.swing.text.BadLocationException; |
| 11 | import javax.swing.text.Highlighter.HighlightPainter; | 13 | import javax.swing.text.Highlighter.HighlightPainter; |
| 12 | 14 | ||
| 13 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | 15 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; |
| 14 | 16 | ||
| 15 | import cuchaz.enigma.Deobfuscator; | 17 | import cuchaz.enigma.Deobfuscator; |
| 18 | import cuchaz.enigma.analysis.EntryReference; | ||
| 16 | import cuchaz.enigma.analysis.SourceIndex; | 19 | import cuchaz.enigma.analysis.SourceIndex; |
| 17 | import cuchaz.enigma.analysis.Token; | 20 | import cuchaz.enigma.analysis.Token; |
| 18 | import cuchaz.enigma.mapping.ClassEntry; | 21 | import cuchaz.enigma.mapping.ClassEntry; |
| @@ -26,8 +29,13 @@ public class CodeReader extends JEditorPane { | |||
| 26 | 29 | ||
| 27 | private static final Object m_lock = new Object(); | 30 | private static final Object m_lock = new Object(); |
| 28 | 31 | ||
| 29 | private SelectionHighlightPainter m_highlightPainter; | 32 | public static interface SelectionListener { |
| 33 | void onSelect(EntryReference<Entry,Entry> reference); | ||
| 34 | } | ||
| 35 | |||
| 36 | private SelectionHighlightPainter m_selectionHighlightPainter; | ||
| 30 | private SourceIndex m_sourceIndex; | 37 | private SourceIndex m_sourceIndex; |
| 38 | private SelectionListener m_selectionListener; | ||
| 31 | 39 | ||
| 32 | public CodeReader() { | 40 | public CodeReader() { |
| 33 | 41 | ||
| @@ -38,8 +46,28 @@ public class CodeReader extends JEditorPane { | |||
| 38 | DefaultSyntaxKit kit = (DefaultSyntaxKit)getEditorKit(); | 46 | DefaultSyntaxKit kit = (DefaultSyntaxKit)getEditorKit(); |
| 39 | kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker"); | 47 | kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker"); |
| 40 | 48 | ||
| 41 | m_highlightPainter = new SelectionHighlightPainter(); | 49 | // hook events |
| 50 | addCaretListener(new CaretListener() { | ||
| 51 | @Override | ||
| 52 | public void caretUpdate(CaretEvent event) { | ||
| 53 | if (m_selectionListener != null && m_sourceIndex != null) { | ||
| 54 | Token token = m_sourceIndex.getReferenceToken(event.getDot()); | ||
| 55 | if (token != null) { | ||
| 56 | m_selectionListener.onSelect(m_sourceIndex.getDeobfReference(token)); | ||
| 57 | } else { | ||
| 58 | m_selectionListener.onSelect(null); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | } | ||
| 62 | }); | ||
| 63 | |||
| 64 | m_selectionHighlightPainter = new SelectionHighlightPainter(); | ||
| 42 | m_sourceIndex = null; | 65 | m_sourceIndex = null; |
| 66 | m_selectionListener = null; | ||
| 67 | } | ||
| 68 | |||
| 69 | public void setSelectionListener(SelectionListener val) { | ||
| 70 | m_selectionListener = val; | ||
| 43 | } | 71 | } |
| 44 | 72 | ||
| 45 | public void setCode(String code) { | 73 | public void setCode(String code) { |
| @@ -49,6 +77,10 @@ public class CodeReader extends JEditorPane { | |||
| 49 | } | 77 | } |
| 50 | } | 78 | } |
| 51 | 79 | ||
| 80 | public SourceIndex getSourceIndex() { | ||
| 81 | return m_sourceIndex; | ||
| 82 | } | ||
| 83 | |||
| 52 | public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) { | 84 | public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) { |
| 53 | decompileClass(classEntry, deobfuscator, null); | 85 | decompileClass(classEntry, deobfuscator, null); |
| 54 | } | 86 | } |
| @@ -110,7 +142,7 @@ public class CodeReader extends JEditorPane { | |||
| 110 | } | 142 | } |
| 111 | 143 | ||
| 112 | public void navigateToToken(final Token token) { | 144 | public void navigateToToken(final Token token) { |
| 113 | navigateToToken(this, token, m_highlightPainter); | 145 | navigateToToken(this, token, m_selectionHighlightPainter); |
| 114 | } | 146 | } |
| 115 | 147 | ||
| 116 | // HACKHACK: someday we can update the main GUI to use this code reader | 148 | // HACKHACK: someday we can update the main GUI to use this code reader |
| @@ -161,4 +193,22 @@ public class CodeReader extends JEditorPane { | |||
| 161 | }); | 193 | }); |
| 162 | timer.start(); | 194 | timer.start(); |
| 163 | } | 195 | } |
| 196 | |||
| 197 | public void setHighlightedTokens(Iterable<Token> tokens, HighlightPainter painter) { | ||
| 198 | for (Token token : tokens) { | ||
| 199 | setHighlightedToken(token, painter); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | public void setHighlightedToken(Token token, HighlightPainter painter) { | ||
| 204 | try { | ||
| 205 | getHighlighter().addHighlight(token.start, token.end, painter); | ||
| 206 | } catch (BadLocationException ex) { | ||
| 207 | throw new IllegalArgumentException(ex); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | public void clearHighlights() { | ||
| 212 | getHighlighter().removeAllHighlights(); | ||
| 213 | } | ||
| 164 | } | 214 | } |
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/FieldMatchingGui.java index de9ba14..ef374c8 100644 --- a/src/cuchaz/enigma/gui/FieldMatchingGui.java +++ b/src/cuchaz/enigma/gui/FieldMatchingGui.java | |||
| @@ -4,24 +4,34 @@ import java.awt.BorderLayout; | |||
| 4 | import java.awt.Container; | 4 | import java.awt.Container; |
| 5 | import java.awt.Dimension; | 5 | import java.awt.Dimension; |
| 6 | import java.awt.FlowLayout; | 6 | import java.awt.FlowLayout; |
| 7 | import java.util.Map; | 7 | import java.awt.event.ActionEvent; |
| 8 | import java.awt.event.ActionListener; | ||
| 9 | import java.util.Collection; | ||
| 10 | import java.util.Set; | ||
| 8 | 11 | ||
| 9 | import javax.swing.BoxLayout; | 12 | import javax.swing.BoxLayout; |
| 13 | import javax.swing.JButton; | ||
| 10 | import javax.swing.JFrame; | 14 | import javax.swing.JFrame; |
| 11 | import javax.swing.JLabel; | 15 | import javax.swing.JLabel; |
| 12 | import javax.swing.JPanel; | 16 | import javax.swing.JPanel; |
| 13 | import javax.swing.JScrollPane; | 17 | import javax.swing.JScrollPane; |
| 14 | import javax.swing.JSplitPane; | 18 | import javax.swing.JSplitPane; |
| 15 | import javax.swing.WindowConstants; | 19 | import javax.swing.WindowConstants; |
| 20 | import javax.swing.text.Highlighter.HighlightPainter; | ||
| 21 | |||
| 22 | import com.google.common.collect.Sets; | ||
| 16 | 23 | ||
| 17 | import cuchaz.enigma.Constants; | 24 | import cuchaz.enigma.Constants; |
| 18 | import cuchaz.enigma.Deobfuscator; | 25 | import cuchaz.enigma.Deobfuscator; |
| 26 | import cuchaz.enigma.analysis.EntryReference; | ||
| 27 | import cuchaz.enigma.analysis.SourceIndex; | ||
| 28 | import cuchaz.enigma.analysis.Token; | ||
| 19 | import cuchaz.enigma.convert.ClassMatches; | 29 | import cuchaz.enigma.convert.ClassMatches; |
| 20 | import cuchaz.enigma.convert.FieldMatches; | 30 | import cuchaz.enigma.convert.FieldMatches; |
| 21 | import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; | 31 | import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; |
| 22 | import cuchaz.enigma.mapping.ClassEntry; | 32 | import cuchaz.enigma.mapping.ClassEntry; |
| 33 | import cuchaz.enigma.mapping.Entry; | ||
| 23 | import cuchaz.enigma.mapping.FieldEntry; | 34 | import cuchaz.enigma.mapping.FieldEntry; |
| 24 | import cuchaz.enigma.mapping.FieldMapping; | ||
| 25 | import de.sciss.syntaxpane.DefaultSyntaxKit; | 35 | import de.sciss.syntaxpane.DefaultSyntaxKit; |
| 26 | 36 | ||
| 27 | 37 | ||
| @@ -36,19 +46,28 @@ public class FieldMatchingGui { | |||
| 36 | private ClassSelector m_sourceClasses; | 46 | private ClassSelector m_sourceClasses; |
| 37 | private CodeReader m_sourceReader; | 47 | private CodeReader m_sourceReader; |
| 38 | private CodeReader m_destReader; | 48 | private CodeReader m_destReader; |
| 49 | private JButton m_matchButton; | ||
| 50 | private JLabel m_sourceLabel; | ||
| 51 | private JLabel m_destLabel; | ||
| 52 | private HighlightPainter m_unmatchedHighlightPainter; | ||
| 53 | private HighlightPainter m_matchedHighlightPainter; | ||
| 39 | 54 | ||
| 40 | private ClassMatches m_classMatches; | 55 | private ClassMatches m_classMatches; |
| 41 | private FieldMatches m_fieldMatches; | 56 | private FieldMatches m_fieldMatches; |
| 42 | private Map<FieldEntry,FieldMapping> m_droppedFieldMappings; | ||
| 43 | private Deobfuscator m_sourceDeobfuscator; | 57 | private Deobfuscator m_sourceDeobfuscator; |
| 44 | private Deobfuscator m_destDeobfuscator; | 58 | private Deobfuscator m_destDeobfuscator; |
| 45 | private SaveListener m_saveListener; | 59 | private SaveListener m_saveListener; |
| 60 | private ClassEntry m_obfSourceClass; | ||
| 61 | private ClassEntry m_obfDestClass; | ||
| 62 | private FieldEntry m_obfSourceField; | ||
| 63 | private FieldEntry m_obfDestField; | ||
| 64 | private Set<FieldEntry> m_obfUnmatchedSourceFields; | ||
| 65 | private Set<FieldEntry> m_obfUnmatchedDestFields; | ||
| 46 | 66 | ||
| 47 | public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Map<FieldEntry,FieldMapping> droppedFieldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { | 67 | public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { |
| 48 | 68 | ||
| 49 | m_classMatches = classMatches; | 69 | m_classMatches = classMatches; |
| 50 | m_fieldMatches = fieldMatches; | 70 | m_fieldMatches = fieldMatches; |
| 51 | m_droppedFieldMappings = droppedFieldMappings; | ||
| 52 | m_sourceDeobfuscator = sourceDeobfuscator; | 71 | m_sourceDeobfuscator = sourceDeobfuscator; |
| 53 | m_destDeobfuscator = destDeobfuscator; | 72 | m_destDeobfuscator = destDeobfuscator; |
| 54 | 73 | ||
| @@ -74,31 +93,57 @@ public class FieldMatchingGui { | |||
| 74 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); | 93 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); |
| 75 | classesPanel.add(sourceScroller); | 94 | classesPanel.add(sourceScroller); |
| 76 | 95 | ||
| 77 | // init fields side | ||
| 78 | JPanel fieldsPanel = new JPanel(); | ||
| 79 | fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.PAGE_AXIS)); | ||
| 80 | fieldsPanel.setPreferredSize(new Dimension(200, 0)); | ||
| 81 | pane.add(fieldsPanel, BorderLayout.WEST); | ||
| 82 | fieldsPanel.add(new JLabel("Destination Fields")); | ||
| 83 | |||
| 84 | // init readers | 96 | // init readers |
| 85 | DefaultSyntaxKit.initKit(); | 97 | DefaultSyntaxKit.initKit(); |
| 86 | m_sourceReader = new CodeReader(); | 98 | m_sourceReader = new CodeReader(); |
| 99 | m_sourceReader.setSelectionListener(new CodeReader.SelectionListener() { | ||
| 100 | @Override | ||
| 101 | public void onSelect(EntryReference<Entry,Entry> reference) { | ||
| 102 | if (reference != null) { | ||
| 103 | onSelectSource(reference.entry); | ||
| 104 | } else { | ||
| 105 | onSelectSource(null); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | }); | ||
| 87 | m_destReader = new CodeReader(); | 109 | m_destReader = new CodeReader(); |
| 110 | m_destReader.setSelectionListener(new CodeReader.SelectionListener() { | ||
| 111 | @Override | ||
| 112 | public void onSelect(EntryReference<Entry,Entry> reference) { | ||
| 113 | if (reference != null) { | ||
| 114 | onSelectDest(reference.entry); | ||
| 115 | } else { | ||
| 116 | onSelectDest(null); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | }); | ||
| 88 | 120 | ||
| 89 | // init all the splits | 121 | // init all the splits |
| 90 | JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, new JScrollPane(m_sourceReader)); | 122 | JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_sourceReader), new JScrollPane(m_destReader)); |
| 123 | splitRight.setResizeWeight(0.5); // resize 50:50 | ||
| 124 | JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight); | ||
| 91 | splitLeft.setResizeWeight(0); // let the right side take all the slack | 125 | splitLeft.setResizeWeight(0); // let the right side take all the slack |
| 92 | JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_destReader), fieldsPanel); | 126 | pane.add(splitLeft, BorderLayout.CENTER); |
| 93 | splitRight.setResizeWeight(1); // let the left side take all the slack | 127 | splitLeft.resetToPreferredSizes(); |
| 94 | JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight); | ||
| 95 | splitCenter.setResizeWeight(0.5); // resize 50:50 | ||
| 96 | pane.add(splitCenter, BorderLayout.CENTER); | ||
| 97 | splitCenter.resetToPreferredSizes(); | ||
| 98 | 128 | ||
| 99 | // init bottom panel | 129 | // init bottom panel |
| 100 | JPanel bottomPanel = new JPanel(); | 130 | JPanel bottomPanel = new JPanel(); |
| 101 | bottomPanel.setLayout(new FlowLayout()); | 131 | bottomPanel.setLayout(new FlowLayout()); |
| 132 | pane.add(bottomPanel, BorderLayout.SOUTH); | ||
| 133 | |||
| 134 | m_matchButton = new JButton("Match"); | ||
| 135 | m_matchButton.addActionListener(new ActionListener() { | ||
| 136 | @Override | ||
| 137 | public void actionPerformed(ActionEvent event) { | ||
| 138 | match(); | ||
| 139 | } | ||
| 140 | }); | ||
| 141 | |||
| 142 | m_sourceLabel = new JLabel(); | ||
| 143 | bottomPanel.add(m_sourceLabel); | ||
| 144 | bottomPanel.add(m_matchButton); | ||
| 145 | m_destLabel = new JLabel(); | ||
| 146 | bottomPanel.add(m_destLabel); | ||
| 102 | 147 | ||
| 103 | // show the frame | 148 | // show the frame |
| 104 | pane.doLayout(); | 149 | pane.doLayout(); |
| @@ -106,26 +151,139 @@ public class FieldMatchingGui { | |||
| 106 | m_frame.setMinimumSize(new Dimension(640, 480)); | 151 | m_frame.setMinimumSize(new Dimension(640, 480)); |
| 107 | m_frame.setVisible(true); | 152 | m_frame.setVisible(true); |
| 108 | m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); | 153 | m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); |
| 154 | |||
| 155 | m_unmatchedHighlightPainter = new ObfuscatedHighlightPainter(); | ||
| 156 | m_matchedHighlightPainter = new DeobfuscatedHighlightPainter(); | ||
| 109 | 157 | ||
| 110 | // init state | 158 | // init state |
| 111 | m_saveListener = null; | 159 | m_saveListener = null; |
| 112 | m_fieldMatches.addUnmatchedSourceFields(droppedFieldMappings.keySet()); | 160 | m_obfSourceClass = null; |
| 113 | m_sourceClasses.setClasses(m_fieldMatches.getSourceClassesWithUnmatchedFields()); | 161 | m_obfDestClass = null; |
| 162 | m_obfSourceField = null; | ||
| 163 | m_obfDestField = null; | ||
| 164 | m_obfUnmatchedSourceFields = null; | ||
| 165 | m_obfUnmatchedDestFields = null; | ||
| 166 | updateSourceClasses(); | ||
| 167 | updateMatchButton(); | ||
| 114 | } | 168 | } |
| 115 | 169 | ||
| 116 | public void setSaveListener(SaveListener val) { | 170 | public void setSaveListener(SaveListener val) { |
| 117 | m_saveListener = val; | 171 | m_saveListener = val; |
| 118 | } | 172 | } |
| 119 | 173 | ||
| 174 | private void updateSourceClasses() { | ||
| 175 | m_sourceClasses.setClasses(m_fieldMatches.getSourceClassesWithUnmatchedFields()); | ||
| 176 | m_sourceClasses.expandAll(); | ||
| 177 | } | ||
| 178 | |||
| 120 | protected void setSourceClass(ClassEntry obfSourceClass) { | 179 | protected void setSourceClass(ClassEntry obfSourceClass) { |
| 121 | 180 | ||
| 122 | // get the matched dest class | 181 | m_obfSourceClass = obfSourceClass; |
| 123 | final ClassEntry obfDestClass = m_classMatches.getUniqueMatches().get(obfSourceClass); | 182 | m_obfDestClass = m_classMatches.getUniqueMatches().get(obfSourceClass); |
| 124 | if (obfDestClass == null) { | 183 | if (m_obfDestClass == null) { |
| 125 | throw new Error("No matching dest class for source class: " + obfSourceClass); | 184 | throw new Error("No matching dest class for source class: " + m_obfSourceClass); |
| 126 | } | 185 | } |
| 186 | |||
| 187 | updateUnmatchedFields(); | ||
| 188 | m_sourceReader.decompileClass(m_obfSourceClass, m_sourceDeobfuscator, new Runnable() { | ||
| 189 | @Override | ||
| 190 | public void run() { | ||
| 191 | updateSourceHighlights(); | ||
| 192 | } | ||
| 193 | }); | ||
| 194 | m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, new Runnable() { | ||
| 195 | @Override | ||
| 196 | public void run() { | ||
| 197 | updateDestHighlights(); | ||
| 198 | } | ||
| 199 | }); | ||
| 200 | } | ||
| 201 | |||
| 202 | private void updateUnmatchedFields() { | ||
| 203 | m_obfUnmatchedSourceFields = Sets.newHashSet(m_fieldMatches.getUnmatchedSourceFields(m_obfSourceClass)); | ||
| 204 | m_obfUnmatchedDestFields = Sets.newHashSet(); | ||
| 205 | for (FieldEntry destFieldEntry : m_destDeobfuscator.getJarIndex().getObfFieldEntries(m_obfDestClass)) { | ||
| 206 | if (!m_fieldMatches.isDestMatched(destFieldEntry)) { | ||
| 207 | m_obfUnmatchedDestFields.add(destFieldEntry); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | protected void updateSourceHighlights() { | ||
| 213 | highlightFields(m_sourceReader, m_sourceDeobfuscator, m_obfUnmatchedSourceFields, m_fieldMatches.matches().keySet()); | ||
| 214 | } | ||
| 215 | |||
| 216 | protected void updateDestHighlights() { | ||
| 217 | highlightFields(m_destReader, m_destDeobfuscator, m_obfUnmatchedDestFields, m_fieldMatches.matches().values()); | ||
| 218 | } | ||
| 219 | |||
| 220 | private void highlightFields(CodeReader reader, Deobfuscator deobfuscator, Collection<FieldEntry> obfFieldEntries, Collection<FieldEntry> obfMatchedFieldEntries) { | ||
| 221 | reader.clearHighlights(); | ||
| 222 | SourceIndex index = reader.getSourceIndex(); | ||
| 223 | for (FieldEntry obfFieldEntry : obfFieldEntries) { | ||
| 224 | FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry); | ||
| 225 | Token token = index.getDeclarationToken(deobfFieldEntry); | ||
| 226 | if (token == null) { | ||
| 227 | System.err.println("WARNING: Can't find declaration token for " + deobfFieldEntry); | ||
| 228 | } else { | ||
| 229 | reader.setHighlightedToken( | ||
| 230 | token, | ||
| 231 | obfMatchedFieldEntries.contains(obfFieldEntry) ? m_matchedHighlightPainter : m_unmatchedHighlightPainter | ||
| 232 | ); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | } | ||
| 236 | |||
| 237 | protected void onSelectSource(Entry entry) { | ||
| 238 | m_sourceLabel.setText(""); | ||
| 239 | m_obfSourceField = null; | ||
| 240 | if (entry != null && entry instanceof FieldEntry) { | ||
| 241 | FieldEntry fieldEntry = (FieldEntry)entry; | ||
| 242 | FieldEntry obfFieldEntry = m_sourceDeobfuscator.obfuscateEntry(fieldEntry); | ||
| 243 | if (m_obfUnmatchedSourceFields.contains(obfFieldEntry)) { | ||
| 244 | m_obfSourceField = obfFieldEntry; | ||
| 245 | m_sourceLabel.setText(fieldEntry.getName() + " " + fieldEntry.getType().toString()); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | updateMatchButton(); | ||
| 249 | } | ||
| 127 | 250 | ||
| 128 | m_sourceReader.decompileClass(obfSourceClass, m_sourceDeobfuscator); | 251 | protected void onSelectDest(Entry entry) { |
| 129 | m_destReader.decompileClass(obfDestClass, m_destDeobfuscator); | 252 | m_destLabel.setText(""); |
| 253 | m_obfDestField = null; | ||
| 254 | if (entry != null && entry instanceof FieldEntry) { | ||
| 255 | FieldEntry fieldEntry = (FieldEntry)entry; | ||
| 256 | FieldEntry obfFieldEntry = m_destDeobfuscator.obfuscateEntry(fieldEntry); | ||
| 257 | if (m_obfUnmatchedDestFields.contains(obfFieldEntry)) { | ||
| 258 | m_obfDestField = obfFieldEntry; | ||
| 259 | m_destLabel.setText(fieldEntry.getName() + " " + fieldEntry.getType().toString()); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | updateMatchButton(); | ||
| 263 | } | ||
| 264 | |||
| 265 | private void updateMatchButton() { | ||
| 266 | m_matchButton.setEnabled(m_obfSourceField != null && m_obfDestField != null); | ||
| 267 | } | ||
| 268 | |||
| 269 | protected void match() { | ||
| 270 | |||
| 271 | // update the field matches | ||
| 272 | m_fieldMatches.makeMatch(m_obfSourceField, m_obfDestField); | ||
| 273 | save(); | ||
| 274 | |||
| 275 | // update the ui | ||
| 276 | onSelectSource(null); | ||
| 277 | onSelectDest(null); | ||
| 278 | updateUnmatchedFields(); | ||
| 279 | updateSourceHighlights(); | ||
| 280 | updateDestHighlights(); | ||
| 281 | updateSourceClasses(); | ||
| 282 | } | ||
| 283 | |||
| 284 | private void save() { | ||
| 285 | if (m_saveListener != null) { | ||
| 286 | m_saveListener.save(m_fieldMatches); | ||
| 287 | } | ||
| 130 | } | 288 | } |
| 131 | } | 289 | } |
diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java index f4d62c8..333bb09 100644 --- a/src/cuchaz/enigma/mapping/EntryFactory.java +++ b/src/cuchaz/enigma/mapping/EntryFactory.java | |||
| @@ -26,6 +26,10 @@ public class EntryFactory { | |||
| 26 | return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry)); | 26 | return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry)); |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | private static ClassEntry getObfClassEntry(ClassMapping classMapping) { | ||
| 30 | return new ClassEntry(classMapping.getObfFullName()); | ||
| 31 | } | ||
| 32 | |||
| 29 | public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { | 33 | public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { |
| 30 | return new ClassEntry(classMapping.getDeobfName()); | 34 | return new ClassEntry(classMapping.getDeobfName()); |
| 31 | } | 35 | } |
| @@ -50,6 +54,14 @@ public class EntryFactory { | |||
| 50 | ); | 54 | ); |
| 51 | } | 55 | } |
| 52 | 56 | ||
| 57 | public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) { | ||
| 58 | return new FieldEntry( | ||
| 59 | getObfClassEntry(classMapping), | ||
| 60 | fieldMapping.getObfName(), | ||
| 61 | fieldMapping.getObfType() | ||
| 62 | ); | ||
| 63 | } | ||
| 64 | |||
| 53 | public static MethodEntry getMethodEntry(CtMethod method) { | 65 | public static MethodEntry getMethodEntry(CtMethod method) { |
| 54 | return new MethodEntry( | 66 | return new MethodEntry( |
| 55 | getClassEntry(method.getDeclaringClass()), | 67 | getClassEntry(method.getDeclaringClass()), |
| @@ -148,4 +160,8 @@ public class EntryFactory { | |||
| 148 | public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { | 160 | public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { |
| 149 | return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); | 161 | return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); |
| 150 | } | 162 | } |
| 163 | |||
| 164 | public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) { | ||
| 165 | return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping); | ||
| 166 | } | ||
| 151 | } | 167 | } |