summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2015-03-08 20:48:30 -0400
committerGravatar jeff2015-03-08 20:48:30 -0400
commit4ceb8d490058e48df666bf7227ce020e60928be5 (patch)
treebdfb432cd1d61dc4914b8591468193dcd7e7421c /src
parentlots of small tweaks and improvements (diff)
downloadenigma-fork-4ceb8d490058e48df666bf7227ce020e60928be5.tar.gz
enigma-fork-4ceb8d490058e48df666bf7227ce020e60928be5.tar.xz
enigma-fork-4ceb8d490058e48df666bf7227ce020e60928be5.zip
more tweaks, improvements, and bug fixes
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/ConvertMain.java22
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java25
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java25
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java60
-rw-r--r--src/cuchaz/enigma/gui/MatchingGui.java79
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentMapping.java5
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java11
-rw-r--r--src/cuchaz/enigma/mapping/FieldMapping.java26
-rw-r--r--src/cuchaz/enigma/mapping/MethodMapping.java16
-rw-r--r--src/cuchaz/enigma/mapping/Signature.java5
-rw-r--r--src/cuchaz/enigma/mapping/Type.java13
11 files changed, 233 insertions, 54 deletions
diff --git a/src/cuchaz/enigma/ConvertMain.java b/src/cuchaz/enigma/ConvertMain.java
index cad49f5..975cdcc 100644
--- a/src/cuchaz/enigma/ConvertMain.java
+++ b/src/cuchaz/enigma/ConvertMain.java
@@ -2,6 +2,7 @@ package cuchaz.enigma;
2 2
3import java.io.File; 3import java.io.File;
4import java.io.FileReader; 4import java.io.FileReader;
5import java.io.FileWriter;
5import java.io.IOException; 6import java.io.IOException;
6import java.util.jar.JarFile; 7import java.util.jar.JarFile;
7 8
@@ -14,6 +15,7 @@ import cuchaz.enigma.gui.MatchingGui.SaveListener;
14import cuchaz.enigma.mapping.MappingParseException; 15import cuchaz.enigma.mapping.MappingParseException;
15import cuchaz.enigma.mapping.Mappings; 16import cuchaz.enigma.mapping.Mappings;
16import cuchaz.enigma.mapping.MappingsReader; 17import cuchaz.enigma.mapping.MappingsReader;
18import cuchaz.enigma.mapping.MappingsWriter;
17 19
18 20
19public class ConvertMain { 21public class ConvertMain {
@@ -32,7 +34,7 @@ public class ConvertMain {
32 34
33 //computeMatches(matchingFile, sourceJar, destJar, mappings); 35 //computeMatches(matchingFile, sourceJar, destJar, mappings);
34 editMatches(matchingFile, sourceJar, destJar, mappings); 36 editMatches(matchingFile, sourceJar, destJar, mappings);
35 //convertMappings(outMappingsFile, mappings, matchingFile); 37 //convertMappings(outMappingsFile, sourceJar, destJar, mappings, matchingFile);
36 38
37 /* TODO 39 /* TODO
38 // write out the converted mappings 40 // write out the converted mappings
@@ -56,7 +58,7 @@ public class ConvertMain {
56 Matches matches = MatchesReader.read(matchingFile); 58 Matches matches = MatchesReader.read(matchingFile);
57 System.out.println("Indexing source jar..."); 59 System.out.println("Indexing source jar...");
58 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar); 60 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar);
59 sourceDeobfuscator.setMappings(mappings); 61 sourceDeobfuscator.setMappings(mappings, false);
60 System.out.println("Indexing dest jar..."); 62 System.out.println("Indexing dest jar...");
61 Deobfuscator destDeobfuscator = new Deobfuscator(destJar); 63 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
62 System.out.println("Starting GUI..."); 64 System.out.println("Starting GUI...");
@@ -72,9 +74,21 @@ public class ConvertMain {
72 }); 74 });
73 } 75 }
74 76
75 private static void convertMappings(File outMappingsFile, Mappings mappings, File matchingFile) 77 private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File matchingFile)
76 throws IOException { 78 throws IOException {
79 System.out.println("Reading matches...");
77 Matches matches = MatchesReader.read(matchingFile); 80 Matches matches = MatchesReader.read(matchingFile);
78 MappingsConverter.convertMappings(mappings, matches.getUniqueMatches()); 81 System.out.println("Indexing source jar...");
82 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar);
83 sourceDeobfuscator.setMappings(mappings);
84 System.out.println("Indexing dest jar...");
85 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
86
87 Mappings newMappings = MappingsConverter.newMappings(matches, mappings, sourceDeobfuscator, destDeobfuscator);
88
89 try (FileWriter out = new FileWriter(outMappingsFile)) {
90 new MappingsWriter().write(out, newMappings);
91 }
92 System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath());
79 } 93 }
80} 94}
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index e5d0e3d..9b0d3db 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -116,6 +116,10 @@ public class Deobfuscator {
116 } 116 }
117 117
118 public void setMappings(Mappings val) { 118 public void setMappings(Mappings val) {
119 setMappings(val, true);
120 }
121
122 public void setMappings(Mappings val, boolean warnAboutDrops) {
119 if (val == null) { 123 if (val == null) {
120 val = new Mappings(); 124 val = new Mappings();
121 } 125 }
@@ -123,7 +127,10 @@ public class Deobfuscator {
123 // drop mappings that don't match the jar 127 // drop mappings that don't match the jar
124 RelatedMethodChecker relatedMethodChecker = new RelatedMethodChecker(m_jarIndex); 128 RelatedMethodChecker relatedMethodChecker = new RelatedMethodChecker(m_jarIndex);
125 for (ClassMapping classMapping : Lists.newArrayList(val.classes())) { 129 for (ClassMapping classMapping : Lists.newArrayList(val.classes())) {
126 if (!checkClassMapping(relatedMethodChecker, classMapping)) { 130 if (!checkClassMapping(relatedMethodChecker, classMapping, warnAboutDrops)) {
131 if (warnAboutDrops) {
132 System.err.println("WARNING: unable to find class " + classMapping.getObfFullName() + ". dropping mapping");
133 }
127 val.removeClassMapping(classMapping); 134 val.removeClassMapping(classMapping);
128 } 135 }
129 } 136 }
@@ -138,7 +145,7 @@ public class Deobfuscator {
138 m_translatorCache.clear(); 145 m_translatorCache.clear();
139 } 146 }
140 147
141 private boolean checkClassMapping(RelatedMethodChecker relatedMethodChecker, ClassMapping classMapping) { 148 private boolean checkClassMapping(RelatedMethodChecker relatedMethodChecker, ClassMapping classMapping, boolean warnAboutDrops) {
142 149
143 // check the class 150 // check the class
144 ClassEntry classEntry = EntryFactory.getObfClassEntry(m_jarIndex, classMapping); 151 ClassEntry classEntry = EntryFactory.getObfClassEntry(m_jarIndex, classMapping);
@@ -150,7 +157,9 @@ public class Deobfuscator {
150 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { 157 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
151 FieldEntry fieldEntry = new FieldEntry(classEntry, fieldMapping.getObfName(), fieldMapping.getObfType()); 158 FieldEntry fieldEntry = new FieldEntry(classEntry, fieldMapping.getObfName(), fieldMapping.getObfType());
152 if (!m_jarIndex.containsObfField(fieldEntry)) { 159 if (!m_jarIndex.containsObfField(fieldEntry)) {
153 System.err.println("WARNING: unable to find field " + fieldEntry + ". dropping mapping."); 160 if (warnAboutDrops) {
161 System.err.println("WARNING: unable to find field " + fieldEntry + ". dropping mapping.");
162 }
154 classMapping.removeFieldMapping(fieldMapping); 163 classMapping.removeFieldMapping(fieldMapping);
155 } 164 }
156 } 165 }
@@ -159,7 +168,9 @@ public class Deobfuscator {
159 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { 168 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
160 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); 169 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping);
161 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) { 170 if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) {
162 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping."); 171 if (warnAboutDrops) {
172 System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping.");
173 }
163 classMapping.removeMethodMapping(methodMapping); 174 classMapping.removeMethodMapping(methodMapping);
164 } 175 }
165 176
@@ -168,8 +179,10 @@ public class Deobfuscator {
168 179
169 // check inner classes 180 // check inner classes
170 for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) { 181 for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) {
171 if (!checkClassMapping(relatedMethodChecker, innerClassMapping)) { 182 if (!checkClassMapping(relatedMethodChecker, innerClassMapping, warnAboutDrops)) {
172 System.err.println("WARNING: unable to find inner class " + EntryFactory.getObfClassEntry(m_jarIndex, classMapping) + ". dropping mapping."); 183 if (warnAboutDrops) {
184 System.err.println("WARNING: unable to find inner class " + EntryFactory.getObfClassEntry(m_jarIndex, classMapping) + ". dropping mapping.");
185 }
173 classMapping.removeInnerClassMapping(innerClassMapping); 186 classMapping.removeInnerClassMapping(innerClassMapping);
174 } 187 }
175 } 188 }
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index d07e0a4..35667b0 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -16,6 +16,7 @@ import java.security.NoSuchAlgorithmException;
16import java.util.Enumeration; 16import java.util.Enumeration;
17import java.util.List; 17import java.util.List;
18import java.util.Map; 18import java.util.Map;
19import java.util.Set;
19 20
20import javassist.CannotCompileException; 21import javassist.CannotCompileException;
21import javassist.CtBehavior; 22import javassist.CtBehavior;
@@ -38,6 +39,7 @@ import com.google.common.collect.HashMultiset;
38import com.google.common.collect.Lists; 39import com.google.common.collect.Lists;
39import com.google.common.collect.Maps; 40import com.google.common.collect.Maps;
40import com.google.common.collect.Multiset; 41import com.google.common.collect.Multiset;
42import com.google.common.collect.Sets;
41 43
42import cuchaz.enigma.Constants; 44import cuchaz.enigma.Constants;
43import cuchaz.enigma.Util; 45import cuchaz.enigma.Util;
@@ -67,6 +69,7 @@ public class ClassIdentity {
67 private String m_staticInitializer; 69 private String m_staticInitializer;
68 private String m_extends; 70 private String m_extends;
69 private Multiset<String> m_implements; 71 private Multiset<String> m_implements;
72 private Set<String> m_stringLiterals;
70 private Multiset<String> m_implementations; 73 private Multiset<String> m_implementations;
71 private Multiset<String> m_references; 74 private Multiset<String> m_references;
72 private String m_outer; 75 private String m_outer;
@@ -140,6 +143,14 @@ public class ClassIdentity {
140 m_implements.add(scrubClassName(Descriptor.toJvmName(interfaceName))); 143 m_implements.add(scrubClassName(Descriptor.toJvmName(interfaceName)));
141 } 144 }
142 145
146 m_stringLiterals = Sets.newHashSet();
147 ConstPool constants = c.getClassFile().getConstPool();
148 for (int i=1; i<constants.getSize(); i++) {
149 if (constants.getTag(i) == ConstPool.CONST_String) {
150 m_stringLiterals.add(constants.getStringInfo(i));
151 }
152 }
153
143 // stuff from the jar index 154 // stuff from the jar index
144 155
145 m_implementations = HashMultiset.create(); 156 m_implementations = HashMultiset.create();
@@ -410,13 +421,15 @@ public class ClassIdentity {
410 public int getMatchScore(ClassIdentity other) { 421 public int getMatchScore(ClassIdentity other) {
411 return 2*getNumMatches(m_extends, other.m_extends) 422 return 2*getNumMatches(m_extends, other.m_extends)
412 + 2*getNumMatches(m_outer, other.m_outer) 423 + 2*getNumMatches(m_outer, other.m_outer)
424 + 2*getNumMatches(m_implements, other.m_implements)
425 + getNumMatches(m_stringLiterals, other.m_stringLiterals)
413 + getNumMatches(m_fields, other.m_fields) 426 + getNumMatches(m_fields, other.m_fields)
414 + getNumMatches(m_methods, other.m_methods) 427 + getNumMatches(m_methods, other.m_methods)
415 + getNumMatches(m_constructors, other.m_constructors); 428 + getNumMatches(m_constructors, other.m_constructors);
416 } 429 }
417 430
418 public int getMaxMatchScore() { 431 public int getMaxMatchScore() {
419 return 2 + 2 + m_fields.size() + m_methods.size() + m_constructors.size(); 432 return 2 + 2 + 2*m_implements.size() + m_stringLiterals.size() + m_fields.size() + m_methods.size() + m_constructors.size();
420 } 433 }
421 434
422 public boolean matches(CtClass c) { 435 public boolean matches(CtClass c) {
@@ -426,6 +439,16 @@ public class ClassIdentity {
426 && m_constructors.size() == c.getDeclaredConstructors().length; 439 && m_constructors.size() == c.getDeclaredConstructors().length;
427 } 440 }
428 441
442 private int getNumMatches(Set<String> a, Set<String> b) {
443 int numMatches = 0;
444 for (String val : a) {
445 if (b.contains(val)) {
446 numMatches++;
447 }
448 }
449 return numMatches;
450 }
451
429 private int getNumMatches(Multiset<String> a, Multiset<String> b) { 452 private int getNumMatches(Multiset<String> a, Multiset<String> b) {
430 int numMatches = 0; 453 int numMatches = 0;
431 for (String val : a) { 454 for (String val : a) {
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
index f38723f..5883878 100644
--- a/src/cuchaz/enigma/convert/MappingsConverter.java
+++ b/src/cuchaz/enigma/convert/MappingsConverter.java
@@ -30,7 +30,10 @@ import cuchaz.enigma.analysis.JarIndex;
30import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 30import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
31import cuchaz.enigma.mapping.ClassEntry; 31import cuchaz.enigma.mapping.ClassEntry;
32import cuchaz.enigma.mapping.ClassMapping; 32import cuchaz.enigma.mapping.ClassMapping;
33import cuchaz.enigma.mapping.ClassNameReplacer;
34import cuchaz.enigma.mapping.FieldMapping;
33import cuchaz.enigma.mapping.Mappings; 35import cuchaz.enigma.mapping.Mappings;
36import cuchaz.enigma.mapping.MethodMapping;
34 37
35public class MappingsConverter { 38public class MappingsConverter {
36 39
@@ -129,15 +132,20 @@ public class MappingsConverter {
129 for (Entry<ClassEntry,ClassEntry> match : matchesByDestChainSize.get(chainSize)) { 132 for (Entry<ClassEntry,ClassEntry> match : matchesByDestChainSize.get(chainSize)) {
130 133
131 // get class info 134 // get class info
132 ClassEntry sourceClassEntry = match.getKey(); 135 ClassEntry obfSourceClassEntry = match.getKey();
133 ClassEntry deobfClassEntry = sourceDeobfuscator.deobfuscateEntry(sourceClassEntry); 136 ClassEntry obfDestClassEntry = match.getValue();
134 ClassEntry destClassEntry = match.getValue(); 137 List<ClassEntry> destClassChain = destDeobfuscator.getJarIndex().getObfClassChain(obfDestClassEntry);
135 List<ClassEntry> destClassChain = destDeobfuscator.getJarIndex().getObfClassChain(destClassEntry); 138
139 ClassMapping sourceMapping = sourceDeobfuscator.getMappings().getClassByObf(obfSourceClassEntry);
140 if (sourceMapping == null) {
141 // if this class was never deobfuscated, don't try to match it
142 continue;
143 }
136 144
137 // find out where to make the dest class mapping 145 // find out where to make the dest class mapping
138 if (destClassChain.size() == 1) { 146 if (destClassChain.size() == 1) {
139 // not an inner class, add directly to mappings 147 // not an inner class, add directly to mappings
140 newMappings.addClassMapping(new ClassMapping(destClassEntry.getName(), deobfClassEntry.getName())); 148 newMappings.addClassMapping(migrateClassMapping(obfDestClassEntry, sourceMapping, matches, false));
141 } else { 149 } else {
142 // inner class, find the outer class mapping 150 // inner class, find the outer class mapping
143 ClassMapping destMapping = null; 151 ClassMapping destMapping = null;
@@ -157,14 +165,52 @@ public class MappingsConverter {
157 } 165 }
158 } 166 }
159 } 167 }
160 String deobfName = deobfClassEntry.isInnerClass() ? deobfClassEntry.getInnerClassName() : deobfClassEntry.getSimpleName(); 168 destMapping.addInnerClassMapping(migrateClassMapping(obfDestClassEntry, sourceMapping, matches, true));
161 destMapping.addInnerClassMapping(new ClassMapping(destClassEntry.getName(), deobfName));
162 } 169 }
163 } 170 }
164 } 171 }
165 return newMappings; 172 return newMappings;
166 } 173 }
167 174
175 private static ClassMapping migrateClassMapping(ClassEntry newObfClass, ClassMapping mapping, final Matches matches, boolean useSimpleName) {
176
177 ClassNameReplacer replacer = new ClassNameReplacer() {
178 @Override
179 public String replace(String className) {
180 ClassEntry newClassEntry = matches.getUniqueMatches().get(new ClassEntry(className));
181 if (newClassEntry != null) {
182 return newClassEntry.getName();
183 }
184 return null;
185 }
186 };
187
188 ClassMapping newMapping;
189 String deobfName = mapping.getDeobfName();
190 if (deobfName != null) {
191 if (useSimpleName) {
192 deobfName = new ClassEntry(deobfName).getSimpleName();
193 }
194 newMapping = new ClassMapping(newObfClass.getName(), deobfName);
195 } else {
196 newMapping = new ClassMapping(newObfClass.getName());
197 }
198
199 // copy fields
200 for (FieldMapping fieldMapping : mapping.fields()) {
201 // TODO: map field obf names too...
202 newMapping.addFieldMapping(new FieldMapping(fieldMapping, replacer));
203 }
204
205 // copy methods
206 for (MethodMapping methodMapping : mapping.methods()) {
207 // TODO: map method obf names too...
208 newMapping.addMethodMapping(new MethodMapping(methodMapping, replacer));
209 }
210
211 return newMapping;
212 }
213
168 public static void convertMappings(Mappings mappings, BiMap<ClassEntry,ClassEntry> changes) { 214 public static void convertMappings(Mappings mappings, BiMap<ClassEntry,ClassEntry> changes) {
169 215
170 // sort the changes so classes are renamed in the correct order 216 // sort the changes so classes are renamed in the correct order
diff --git a/src/cuchaz/enigma/gui/MatchingGui.java b/src/cuchaz/enigma/gui/MatchingGui.java
index 1e618d0..85842c1 100644
--- a/src/cuchaz/enigma/gui/MatchingGui.java
+++ b/src/cuchaz/enigma/gui/MatchingGui.java
@@ -6,10 +6,8 @@ import java.awt.Dimension;
6import java.awt.FlowLayout; 6import java.awt.FlowLayout;
7import java.awt.event.ActionEvent; 7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener; 8import java.awt.event.ActionListener;
9import java.util.ArrayList;
10import java.util.Arrays; 9import java.util.Arrays;
11import java.util.Collection; 10import java.util.Collection;
12import java.util.Collections;
13import java.util.List; 11import java.util.List;
14import java.util.Map; 12import java.util.Map;
15 13
@@ -29,9 +27,7 @@ import javax.swing.WindowConstants;
29 27
30import com.beust.jcommander.internal.Lists; 28import com.beust.jcommander.internal.Lists;
31import com.beust.jcommander.internal.Maps; 29import com.beust.jcommander.internal.Maps;
32import com.google.common.collect.ArrayListMultimap;
33import com.google.common.collect.BiMap; 30import com.google.common.collect.BiMap;
34import com.google.common.collect.Multimap;
35import com.strobel.decompiler.languages.java.ast.CompilationUnit; 31import com.strobel.decompiler.languages.java.ast.CompilationUnit;
36 32
37import cuchaz.enigma.Constants; 33import cuchaz.enigma.Constants;
@@ -272,7 +268,7 @@ public class MatchingGui {
272 m_sourceDeobfuscator.getMappings(), 268 m_sourceDeobfuscator.getMappings(),
273 m_sourceDeobfuscator, 269 m_sourceDeobfuscator,
274 m_destDeobfuscator 270 m_destDeobfuscator
275 )); 271 ), false);
276 } 272 }
277 273
278 protected void setSourceType(SourceType val) { 274 protected void setSourceType(SourceType val) {
@@ -307,7 +303,18 @@ public class MatchingGui {
307 } 303 }
308 304
309 protected void setSourceClass(ClassEntry classEntry) { 305 protected void setSourceClass(ClassEntry classEntry) {
310 setSourceClass(classEntry, null); 306
307 Runnable onGetDestClasses = null;
308 if (m_advanceCheck.isSelected()) {
309 onGetDestClasses = new Runnable() {
310 @Override
311 public void run() {
312 pickBestDestClass();
313 }
314 };
315 }
316
317 setSourceClass(classEntry, onGetDestClasses);
311 } 318 }
312 319
313 protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) { 320 protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) {
@@ -596,36 +603,40 @@ public class MatchingGui {
596 setSourceClass(sourceClass, new Runnable() { 603 setSourceClass(sourceClass, new Runnable() {
597 @Override 604 @Override
598 public void run() { 605 public void run() {
599 606 pickBestDestClass();
600 // then, pick the best dest class
601 ClassEntry firstClass = null;
602 ScoredClassEntry bestDestClass = null;
603 for (ClassSelectorPackageNode packageNode : m_destClasses.packageNodes()) {
604 for (ClassSelectorClassNode classNode : m_destClasses.classNodes(packageNode)) {
605 if (firstClass == null) {
606 firstClass = classNode.getClassEntry();
607 }
608 if (classNode.getClassEntry() instanceof ScoredClassEntry) {
609 ScoredClassEntry scoredClass = (ScoredClassEntry)classNode.getClassEntry();
610 if (bestDestClass == null || bestDestClass.getScore() < scoredClass.getScore()) {
611 bestDestClass = scoredClass;
612 }
613 }
614 }
615 }
616
617 // pick the entry to show
618 ClassEntry destClass = null;
619 if (bestDestClass != null) {
620 destClass = bestDestClass;
621 } else if (firstClass != null) {
622 destClass = firstClass;
623 }
624
625 setDestClass(destClass);
626 m_destClasses.setSelectionClass(destClass);
627 } 607 }
628 }); 608 });
629 m_sourceClasses.setSelectionClass(sourceClass); 609 m_sourceClasses.setSelectionClass(sourceClass);
630 } 610 }
611
612 private void pickBestDestClass() {
613
614 // then, pick the best dest class
615 ClassEntry firstClass = null;
616 ScoredClassEntry bestDestClass = null;
617 for (ClassSelectorPackageNode packageNode : m_destClasses.packageNodes()) {
618 for (ClassSelectorClassNode classNode : m_destClasses.classNodes(packageNode)) {
619 if (firstClass == null) {
620 firstClass = classNode.getClassEntry();
621 }
622 if (classNode.getClassEntry() instanceof ScoredClassEntry) {
623 ScoredClassEntry scoredClass = (ScoredClassEntry)classNode.getClassEntry();
624 if (bestDestClass == null || bestDestClass.getScore() < scoredClass.getScore()) {
625 bestDestClass = scoredClass;
626 }
627 }
628 }
629 }
630
631 // pick the entry to show
632 ClassEntry destClass = null;
633 if (bestDestClass != null) {
634 destClass = bestDestClass;
635 } else if (firstClass != null) {
636 destClass = firstClass;
637 }
638
639 setDestClass(destClass);
640 m_destClasses.setSelectionClass(destClass);
641 }
631} 642}
diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java
index f4d8e77..9f366a0 100644
--- a/src/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -25,6 +25,11 @@ public class ArgumentMapping implements Serializable, Comparable<ArgumentMapping
25 m_name = NameValidator.validateArgumentName(name); 25 m_name = NameValidator.validateArgumentName(name);
26 } 26 }
27 27
28 public ArgumentMapping(ArgumentMapping other) {
29 m_index = other.m_index;
30 m_name = other.m_name;
31 }
32
28 public int getIndex() { 33 public int getIndex() {
29 return m_index; 34 return m_index;
30 } 35 }
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index 3610e33..43605e5 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -393,6 +393,17 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
393 } 393 }
394 } 394 }
395 395
396 // rename field types
397 for (FieldMapping fieldMapping : new ArrayList<FieldMapping>(m_fieldsByObf.values())) {
398 String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
399 if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) {
400 boolean wasRemoved = m_fieldsByObf.remove(oldFieldKey) != null;
401 assert (wasRemoved);
402 boolean wasAdded = m_fieldsByObf.put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null;
403 assert (wasAdded);
404 }
405 }
406
396 // rename method signatures 407 // rename method signatures
397 for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) { 408 for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) {
398 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); 409 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
index 14b20dd..55b0a19 100644
--- a/src/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -26,6 +26,12 @@ public class FieldMapping implements Serializable, Comparable<FieldMapping> {
26 m_obfType = obfType; 26 m_obfType = obfType;
27 } 27 }
28 28
29 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) {
30 m_obfName = other.m_obfName;
31 m_deobfName = other.m_deobfName;
32 m_obfType = new Type(other.m_obfType, obfClassNameReplacer);
33 }
34
29 public String getObfName() { 35 public String getObfName() {
30 return m_obfName; 36 return m_obfName;
31 } 37 }
@@ -46,4 +52,24 @@ public class FieldMapping implements Serializable, Comparable<FieldMapping> {
46 public int compareTo(FieldMapping other) { 52 public int compareTo(FieldMapping other) {
47 return (m_obfName + m_obfType).compareTo(other.m_obfName + other.m_obfType); 53 return (m_obfName + m_obfType).compareTo(other.m_obfName + other.m_obfType);
48 } 54 }
55
56 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
57
58 // rename obf classes in the type
59 Type newType = new Type(m_obfType, new ClassNameReplacer() {
60 @Override
61 public String replace(String className) {
62 if (className.equals(oldObfClassName)) {
63 return newObfClassName;
64 }
65 return null;
66 }
67 });
68
69 if (!newType.equals(m_obfType)) {
70 m_obfType = newType;
71 return true;
72 }
73 return false;
74 }
49} 75}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index 1704428..bf8a94f 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -12,7 +12,9 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14import java.util.Map; 14import java.util.Map;
15import java.util.TreeMap; 15import java.util.Map.Entry;
16
17import com.google.common.collect.Maps;
16 18
17public class MethodMapping implements Serializable, Comparable<MethodMapping> { 19public class MethodMapping implements Serializable, Comparable<MethodMapping> {
18 20
@@ -37,9 +39,19 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping> {
37 m_obfName = obfName; 39 m_obfName = obfName;
38 m_deobfName = NameValidator.validateMethodName(deobfName); 40 m_deobfName = NameValidator.validateMethodName(deobfName);
39 m_obfSignature = obfSignature; 41 m_obfSignature = obfSignature;
40 m_arguments = new TreeMap<Integer,ArgumentMapping>(); 42 m_arguments = Maps.newTreeMap();
41 } 43 }
42 44
45 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) {
46 m_obfName = other.m_obfName;
47 m_deobfName = other.m_deobfName;
48 m_obfSignature = new Signature(other.m_obfSignature, obfClassNameReplacer);
49 m_arguments = Maps.newTreeMap();
50 for (Entry<Integer,ArgumentMapping> entry : other.m_arguments.entrySet()) {
51 m_arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue()));
52 }
53 }
54
43 public String getObfName() { 55 public String getObfName() {
44 return m_obfName; 56 return m_obfName;
45 } 57 }
diff --git a/src/cuchaz/enigma/mapping/Signature.java b/src/cuchaz/enigma/mapping/Signature.java
index 273a77b..ea83e40 100644
--- a/src/cuchaz/enigma/mapping/Signature.java
+++ b/src/cuchaz/enigma/mapping/Signature.java
@@ -39,6 +39,11 @@ public class Signature implements Serializable {
39 } 39 }
40 } 40 }
41 41
42 public Signature(Signature other) {
43 m_argumentTypes = Lists.newArrayList(other.m_argumentTypes);
44 m_returnType = new Type(other.m_returnType);
45 }
46
42 public Signature(Signature other, ClassNameReplacer replacer) { 47 public Signature(Signature other, ClassNameReplacer replacer) {
43 m_argumentTypes = Lists.newArrayList(other.m_argumentTypes); 48 m_argumentTypes = Lists.newArrayList(other.m_argumentTypes);
44 for (int i=0; i<m_argumentTypes.size(); i++) { 49 for (int i=0; i<m_argumentTypes.size(); i++) {
diff --git a/src/cuchaz/enigma/mapping/Type.java b/src/cuchaz/enigma/mapping/Type.java
index d8c073e..72118b0 100644
--- a/src/cuchaz/enigma/mapping/Type.java
+++ b/src/cuchaz/enigma/mapping/Type.java
@@ -68,6 +68,11 @@ public class Type implements Serializable {
68 if (c == 'L') { 68 if (c == 'L') {
69 return readClass(in); 69 return readClass(in);
70 } 70 }
71
72 // then check for templates
73 if (c == 'T') {
74 return readClass(in);
75 }
71 76
72 // then check for arrays 77 // then check for arrays
73 int dim = countArrayDimension(in); 78 int dim = countArrayDimension(in);
@@ -85,6 +90,10 @@ public class Type implements Serializable {
85 m_name = name; 90 m_name = name;
86 } 91 }
87 92
93 public Type(Type other) {
94 m_name = other.m_name;
95 }
96
88 public Type(ClassEntry classEntry) { 97 public Type(ClassEntry classEntry) {
89 m_name = "L" + classEntry.getClassName() + ";"; 98 m_name = "L" + classEntry.getClassName() + ";";
90 } 99 }
@@ -128,6 +137,10 @@ public class Type implements Serializable {
128 return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';'; 137 return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';';
129 } 138 }
130 139
140 public boolean isTemplate() {
141 return m_name.charAt(0) == 'T' && m_name.charAt(m_name.length() - 1) == ';';
142 }
143
131 public ClassEntry getClassEntry() { 144 public ClassEntry getClassEntry() {
132 if (isClass()) { 145 if (isClass()) {
133 String name = m_name.substring(1, m_name.length() - 1); 146 String name = m_name.substring(1, m_name.length() - 1);