summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proguard.conf2
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java8
-rw-r--r--src/cuchaz/enigma/TranslatingTypeLoader.java2
-rw-r--r--src/cuchaz/enigma/analysis/EntryReference.java2
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java2
-rw-r--r--src/cuchaz/enigma/bytecode/ClassRenamer.java2
-rw-r--r--src/cuchaz/enigma/bytecode/ClassTranslator.java17
-rw-r--r--src/cuchaz/enigma/bytecode/InnerClassWriter.java4
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java2
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java2
-rw-r--r--src/cuchaz/enigma/gui/CodeReader.java2
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java2
-rw-r--r--src/cuchaz/enigma/mapping/ClassEntry.java31
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java79
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java28
-rw-r--r--src/cuchaz/enigma/mapping/MappingsRenamer.java128
-rw-r--r--src/cuchaz/enigma/mapping/Translator.java73
-rw-r--r--test/cuchaz/enigma/TestDeobfed.java54
-rw-r--r--test/cuchaz/enigma/TestInnerClasses.java38
-rw-r--r--test/cuchaz/enigma/TestSourceIndex.java2
-rw-r--r--test/cuchaz/enigma/TestTranslator.java29
-rw-r--r--test/cuchaz/enigma/inputs/translation/F_ObjectMethods.java (renamed from test/cuchaz/enigma/inputs/translation/G_ObjectMethods.java)2
-rw-r--r--test/cuchaz/enigma/inputs/translation/G_OuterClass.java (renamed from test/cuchaz/enigma/inputs/translation/H_OuterClass.java)10
-rw-r--r--test/cuchaz/enigma/inputs/translation/H_NamelessClass.java28
-rw-r--r--test/cuchaz/enigma/inputs/translation/I_Generics.java25
-rw-r--r--test/cuchaz/enigma/inputs/translation/M_NamelessClass.java28
-rw-r--r--test/cuchaz/enigma/resources/translation.mappings13
27 files changed, 333 insertions, 282 deletions
diff --git a/proguard.conf b/proguard.conf
index e1f04aee..0d3d60e9 100644
--- a/proguard.conf
+++ b/proguard.conf
@@ -4,4 +4,6 @@
4-allowaccessmodification 4-allowaccessmodification
5-dontoptimize 5-dontoptimize
6-dontshrink 6-dontshrink
7-keepparameternames
8-keepattributes
7-keep class cuchaz.enigma.inputs.Keep \ No newline at end of file 9-keep class cuchaz.enigma.inputs.Keep \ No newline at end of file
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index f5012bde..5a23ce5b 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -438,7 +438,13 @@ public class Deobfuscator {
438 public boolean hasDeobfuscatedName(Entry obfEntry) { 438 public boolean hasDeobfuscatedName(Entry obfEntry) {
439 Translator translator = getTranslator(TranslationDirection.Deobfuscating); 439 Translator translator = getTranslator(TranslationDirection.Deobfuscating);
440 if (obfEntry instanceof ClassEntry) { 440 if (obfEntry instanceof ClassEntry) {
441 return translator.translate((ClassEntry)obfEntry) != null; 441 ClassEntry obfClass = (ClassEntry)obfEntry;
442 ClassEntry translated = translator.translateEntry(obfClass);
443 if (obfClass.isInnerClass()) {
444 return !obfClass.getInnermostClassName().equals(translated.getInnermostClassName());
445 } else {
446 return !obfClass.equals(translated);
447 }
442 } else if (obfEntry instanceof FieldEntry) { 448 } else if (obfEntry instanceof FieldEntry) {
443 return translator.translate((FieldEntry)obfEntry) != null; 449 return translator.translate((FieldEntry)obfEntry) != null;
444 } else if (obfEntry instanceof MethodEntry) { 450 } else if (obfEntry instanceof MethodEntry) {
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index 7b57cfa7..ecd7d642 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -205,7 +205,7 @@ public class TranslatingTypeLoader implements ITypeLoader {
205 } 205 }
206 if (obfClassEntry.isInnerClass()) { 206 if (obfClassEntry.isInnerClass()) {
207 // try just the inner class name 207 // try just the inner class name
208 classNamesToTry.add(obfClassEntry.getInnerClassName()); 208 classNamesToTry.add(obfClassEntry.getInnermostClassName());
209 } 209 }
210 return classNamesToTry; 210 return classNamesToTry;
211 } 211 }
diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java
index bb611df5..d0a5c6af 100644
--- a/src/cuchaz/enigma/analysis/EntryReference.java
+++ b/src/cuchaz/enigma/analysis/EntryReference.java
@@ -74,7 +74,7 @@ public class EntryReference<E extends Entry,C extends Entry> {
74 ClassEntry classEntry = (ClassEntry)getNameableEntry(); 74 ClassEntry classEntry = (ClassEntry)getNameableEntry();
75 if (classEntry.isInnerClass()) { 75 if (classEntry.isInnerClass()) {
76 // make sure we only rename the inner class name 76 // make sure we only rename the inner class name
77 return classEntry.getInnerClassName(); 77 return classEntry.getInnermostClassName();
78 } 78 }
79 } 79 }
80 80
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 7ebbd974..a4a3abb8 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -312,7 +312,7 @@ public class JarIndex {
312 312
313 // does this class already have an outer class? 313 // does this class already have an outer class?
314 if (classEntry.isInnerClass()) { 314 if (classEntry.isInnerClass()) {
315 return classEntry.getOuterClassEntry(); 315 return classEntry.getOutermostClassEntry();
316 } 316 }
317 InnerClassesAttribute innerClassesAttribute = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag); 317 InnerClassesAttribute innerClassesAttribute = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag);
318 if (innerClassesAttribute != null) { 318 if (innerClassesAttribute != null) {
diff --git a/src/cuchaz/enigma/bytecode/ClassRenamer.java b/src/cuchaz/enigma/bytecode/ClassRenamer.java
index a5fea926..e9cdea3c 100644
--- a/src/cuchaz/enigma/bytecode/ClassRenamer.java
+++ b/src/cuchaz/enigma/bytecode/ClassRenamer.java
@@ -43,7 +43,7 @@ public class ClassRenamer {
43 for (int i = 0; i < attr.tableLength(); i++) { 43 for (int i = 0; i < attr.tableLength(); i++) {
44 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i))); 44 ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i)));
45 if (attr.innerNameIndex(i) != 0) { 45 if (attr.innerNameIndex(i) != 0) {
46 attr.setInnerNameIndex(i, constants.addUtf8Info(classEntry.getInnerClassName())); 46 attr.setInnerNameIndex(i, constants.addUtf8Info(classEntry.getInnermostClassName()));
47 } 47 }
48 48
49 /* DEBUG 49 /* DEBUG
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java
index 4167731a..94ab2c4b 100644
--- a/src/cuchaz/enigma/bytecode/ClassTranslator.java
+++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java
@@ -26,7 +26,6 @@ import cuchaz.enigma.mapping.BehaviorEntry;
26import cuchaz.enigma.mapping.ClassEntry; 26import cuchaz.enigma.mapping.ClassEntry;
27import cuchaz.enigma.mapping.EntryFactory; 27import cuchaz.enigma.mapping.EntryFactory;
28import cuchaz.enigma.mapping.FieldEntry; 28import cuchaz.enigma.mapping.FieldEntry;
29import cuchaz.enigma.mapping.MethodEntry;
30import cuchaz.enigma.mapping.Signature; 29import cuchaz.enigma.mapping.Signature;
31import cuchaz.enigma.mapping.Translator; 30import cuchaz.enigma.mapping.Translator;
32import cuchaz.enigma.mapping.Type; 31import cuchaz.enigma.mapping.Type;
@@ -101,26 +100,30 @@ public class ClassTranslator {
101 } 100 }
102 101
103 // translate the type 102 // translate the type
104 Type translatedType = m_translator.translateType(new Type(field.getFieldInfo().getDescriptor())); 103 Type translatedType = m_translator.translateType(entry.getType());
105 field.getFieldInfo().setDescriptor(translatedType.toString()); 104 field.getFieldInfo().setDescriptor(translatedType.toString());
106 } 105 }
107 106
108 // translate all the methods and constructors 107 // translate all the methods and constructors
109 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 108 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
109
110 BehaviorEntry entry = EntryFactory.getBehaviorEntry(behavior);
111
110 if (behavior instanceof CtMethod) { 112 if (behavior instanceof CtMethod) {
111 CtMethod method = (CtMethod)behavior; 113 CtMethod method = (CtMethod)behavior;
112 114
113 // translate the name 115 // translate the name
114 MethodEntry entry = EntryFactory.getMethodEntry(method);
115 String translatedName = m_translator.translate(entry); 116 String translatedName = m_translator.translate(entry);
116 if (translatedName != null) { 117 if (translatedName != null) {
117 method.setName(translatedName); 118 method.setName(translatedName);
118 } 119 }
119 } 120 }
120 121
121 // translate the type 122 if (entry.getSignature() != null) {
122 Signature translatedSignature = m_translator.translateSignature(new Signature(behavior.getMethodInfo().getDescriptor())); 123 // translate the type
123 behavior.getMethodInfo().setDescriptor(translatedSignature.toString()); 124 Signature translatedSignature = m_translator.translateSignature(entry.getSignature());
125 behavior.getMethodInfo().setDescriptor(translatedSignature.toString());
126 }
124 } 127 }
125 128
126 // translate all the class names referenced in the code 129 // translate all the class names referenced in the code
@@ -137,7 +140,7 @@ public class ClassTranslator {
137 // translate the source file attribute too 140 // translate the source file attribute too
138 ClassEntry deobfClassEntry = map.get(classEntry); 141 ClassEntry deobfClassEntry = map.get(classEntry);
139 if (deobfClassEntry != null) { 142 if (deobfClassEntry != null) {
140 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOuterClassName()) + ".java"; 143 String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassName()) + ".java";
141 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); 144 c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile));
142 } 145 }
143 } 146 }
diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
index dd21a780..976028d2 100644
--- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java
+++ b/src/cuchaz/enigma/bytecode/InnerClassWriter.java
@@ -93,7 +93,7 @@ public class InnerClassWriter {
93 93
94 // get the new inner class name 94 // get the new inner class name
95 ClassEntry obfInnerClassEntry = obfClassEntry.buildClassEntry(obfClassChain); 95 ClassEntry obfInnerClassEntry = obfClassEntry.buildClassEntry(obfClassChain);
96 ClassEntry obfOuterClassEntry = obfInnerClassEntry.getOuterClassEntry(); 96 ClassEntry obfOuterClassEntry = obfInnerClassEntry.getOutermostClassEntry();
97 97
98 // here's what the JVM spec says about the InnerClasses attribute 98 // here's what the JVM spec says about the InnerClasses attribute
99 // append(inner, parent, 0 if anonymous else simple name, flags); 99 // append(inner, parent, 0 if anonymous else simple name, flags);
@@ -105,7 +105,7 @@ public class InnerClassWriter {
105 int innerClassNameIndex = 0; 105 int innerClassNameIndex = 0;
106 int accessFlags = 0; 106 int accessFlags = 0;
107 if (!m_index.isAnonymousClass(obfClassEntry)) { 107 if (!m_index.isAnonymousClass(obfClassEntry)) {
108 innerClassNameIndex = constPool.addUtf8Info(obfInnerClassEntry.getInnerClassName()); 108 innerClassNameIndex = constPool.addUtf8Info(obfInnerClassEntry.getInnermostClassName());
109 } 109 }
110 110
111 attr.append(innerClassIndex, parentClassIndex, innerClassNameIndex, accessFlags); 111 attr.append(innerClassIndex, parentClassIndex, innerClassNameIndex, accessFlags);
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index 35667b05..d76cd63e 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -180,7 +180,7 @@ public class ClassIdentity {
180 } 180 }
181 } 181 }
182 182
183 m_outer = EntryFactory.getClassEntry(c).getOuterClassName(); 183 m_outer = EntryFactory.getClassEntry(c).getOutermostClassName();
184 } 184 }
185 185
186 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) { 186 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) {
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
index ddd3a53c..2afa1208 100644
--- a/src/cuchaz/enigma/convert/MappingsConverter.java
+++ b/src/cuchaz/enigma/convert/MappingsConverter.java
@@ -169,7 +169,7 @@ public class MappingsConverter {
169 newMappings.addClassMapping(destMapping); 169 newMappings.addClassMapping(destMapping);
170 } 170 }
171 } else { 171 } else {
172 destMapping = destMapping.getInnerClassByObf(destChainClassEntry.getInnerClassName()); 172 destMapping = destMapping.getInnerClassByObfSimple(destChainClassEntry.getInnermostClassName());
173 if (destMapping == null) { 173 if (destMapping == null) {
174 destMapping = new ClassMapping(destChainClassEntry.getName()); 174 destMapping = new ClassMapping(destChainClassEntry.getName());
175 destMapping.addInnerClassMapping(destMapping); 175 destMapping.addInnerClassMapping(destMapping);
diff --git a/src/cuchaz/enigma/gui/CodeReader.java b/src/cuchaz/enigma/gui/CodeReader.java
index 743ef2e4..fb8e0825 100644
--- a/src/cuchaz/enigma/gui/CodeReader.java
+++ b/src/cuchaz/enigma/gui/CodeReader.java
@@ -106,7 +106,7 @@ public class CodeReader extends JEditorPane {
106 // get the outermost class 106 // get the outermost class
107 ClassEntry outermostClassEntry = classEntry; 107 ClassEntry outermostClassEntry = classEntry;
108 while (outermostClassEntry.isInnerClass()) { 108 while (outermostClassEntry.isInnerClass()) {
109 outermostClassEntry = outermostClassEntry.getOuterClassEntry(); 109 outermostClassEntry = outermostClassEntry.getOutermostClassEntry();
110 } 110 }
111 111
112 // decompile it 112 // decompile it
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 9fa633eb..552ee47c 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -257,7 +257,7 @@ public class GuiController {
257 257
258 // get the reference target class 258 // get the reference target class
259 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference); 259 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
260 ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry(); 260 ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOutermostClassEntry();
261 if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) { 261 if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) {
262 throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!"); 262 throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!");
263 } 263 }
diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java
index 69e66bc0..5f3b5e23 100644
--- a/src/cuchaz/enigma/mapping/ClassEntry.java
+++ b/src/cuchaz/enigma/mapping/ClassEntry.java
@@ -13,6 +13,8 @@ package cuchaz.enigma.mapping;
13import java.io.Serializable; 13import java.io.Serializable;
14import java.util.List; 14import java.util.List;
15 15
16import com.beust.jcommander.internal.Lists;
17
16public class ClassEntry implements Entry, Serializable { 18public class ClassEntry implements Entry, Serializable {
17 19
18 private static final long serialVersionUID = 4235460580973955811L; 20 private static final long serialVersionUID = 4235460580973955811L;
@@ -29,7 +31,7 @@ public class ClassEntry implements Entry, Serializable {
29 31
30 m_name = className; 32 m_name = className;
31 33
32 if (isInnerClass() && getInnerClassName().indexOf('/') >= 0) { 34 if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) {
33 throw new IllegalArgumentException("Inner class must not have a package: " + className); 35 throw new IllegalArgumentException("Inner class must not have a package: " + className);
34 } 36 }
35 } 37 }
@@ -84,22 +86,39 @@ public class ClassEntry implements Entry, Serializable {
84 return m_name.lastIndexOf('$') >= 0; 86 return m_name.lastIndexOf('$') >= 0;
85 } 87 }
86 88
87 public String getOuterClassName() { 89 public List<String> getClassChainNames() {
90 return Lists.newArrayList(m_name.split("\\$"));
91 }
92
93 public List<ClassEntry> getClassChain() {
94 List<ClassEntry> entries = Lists.newArrayList();
95 StringBuilder buf = new StringBuilder();
96 for (String name : getClassChainNames()) {
97 if (buf.length() > 0) {
98 buf.append("$");
99 }
100 buf.append(name);
101 entries.add(new ClassEntry(buf.toString()));
102 }
103 return entries;
104 }
105
106 public String getOutermostClassName() {
88 if (isInnerClass()) { 107 if (isInnerClass()) {
89 return m_name.substring(0, m_name.lastIndexOf('$')); 108 return m_name.substring(0, m_name.lastIndexOf('$'));
90 } 109 }
91 return m_name; 110 return m_name;
92 } 111 }
93 112
94 public String getInnerClassName() { 113 public String getInnermostClassName() {
95 if (!isInnerClass()) { 114 if (!isInnerClass()) {
96 throw new Error("This is not an inner class!"); 115 throw new Error("This is not an inner class!");
97 } 116 }
98 return m_name.substring(m_name.lastIndexOf('$') + 1); 117 return m_name.substring(m_name.lastIndexOf('$') + 1);
99 } 118 }
100 119
101 public ClassEntry getOuterClassEntry() { 120 public ClassEntry getOutermostClassEntry() {
102 return new ClassEntry(getOuterClassName()); 121 return new ClassEntry(getOutermostClassName());
103 } 122 }
104 123
105 public boolean isInDefaultPackage() { 124 public boolean isInDefaultPackage() {
@@ -130,7 +149,7 @@ public class ClassEntry implements Entry, Serializable {
130 buf.append(chainEntry.getName()); 149 buf.append(chainEntry.getName());
131 } else { 150 } else {
132 buf.append("$"); 151 buf.append("$");
133 buf.append(chainEntry.isInnerClass() ? chainEntry.getInnerClassName() : chainEntry.getSimpleName()); 152 buf.append(chainEntry.isInnerClass() ? chainEntry.getInnermostClassName() : chainEntry.getSimpleName());
134 } 153 }
135 154
136 if (chainEntry == this) { 155 if (chainEntry == this) {
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index 38cd3d6d..6e7fd17b 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -23,22 +23,23 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
23 private String m_obfFullName; 23 private String m_obfFullName;
24 private String m_obfSimpleName; 24 private String m_obfSimpleName;
25 private String m_deobfName; 25 private String m_deobfName;
26 private Map<String,ClassMapping> m_innerClassesByObf; 26 private Map<String,ClassMapping> m_innerClassesByObfSimple;
27 private Map<String,ClassMapping> m_innerClassesByDeobf; 27 private Map<String,ClassMapping> m_innerClassesByDeobf;
28 private Map<String,FieldMapping> m_fieldsByObf; 28 private Map<String,FieldMapping> m_fieldsByObf;
29 private Map<String,FieldMapping> m_fieldsByDeobf; 29 private Map<String,FieldMapping> m_fieldsByDeobf;
30 private Map<String,MethodMapping> m_methodsByObf; 30 private Map<String,MethodMapping> m_methodsByObf;
31 private Map<String,MethodMapping> m_methodsByDeobf; 31 private Map<String,MethodMapping> m_methodsByDeobf;
32 32
33 public ClassMapping(String obfName) { 33 public ClassMapping(String obfFullName) {
34 this(obfName, null); 34 this(obfFullName, null);
35 } 35 }
36 36
37 public ClassMapping(String obfName, String deobfName) { 37 public ClassMapping(String obfFullName, String deobfName) {
38 m_obfFullName = obfName; 38 m_obfFullName = obfFullName;
39 m_obfSimpleName = new ClassEntry(obfName).getSimpleName(); 39 ClassEntry classEntry = new ClassEntry(obfFullName);
40 m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName();
40 m_deobfName = NameValidator.validateClassName(deobfName, false); 41 m_deobfName = NameValidator.validateClassName(deobfName, false);
41 m_innerClassesByObf = Maps.newHashMap(); 42 m_innerClassesByObfSimple = Maps.newHashMap();
42 m_innerClassesByDeobf = Maps.newHashMap(); 43 m_innerClassesByDeobf = Maps.newHashMap();
43 m_fieldsByObf = Maps.newHashMap(); 44 m_fieldsByObf = Maps.newHashMap();
44 m_fieldsByDeobf = Maps.newHashMap(); 45 m_fieldsByDeobf = Maps.newHashMap();
@@ -65,12 +66,12 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
65 //// INNER CLASSES //////// 66 //// INNER CLASSES ////////
66 67
67 public Iterable<ClassMapping> innerClasses() { 68 public Iterable<ClassMapping> innerClasses() {
68 assert (m_innerClassesByObf.size() >= m_innerClassesByDeobf.size()); 69 assert (m_innerClassesByObfSimple.size() >= m_innerClassesByDeobf.size());
69 return m_innerClassesByObf.values(); 70 return m_innerClassesByObfSimple.values();
70 } 71 }
71 72
72 public void addInnerClassMapping(ClassMapping classMapping) { 73 public void addInnerClassMapping(ClassMapping classMapping) {
73 boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfSimpleName(), classMapping) == null; 74 boolean obfWasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null;
74 assert (obfWasAdded); 75 assert (obfWasAdded);
75 if (classMapping.getDeobfName() != null) { 76 if (classMapping.getDeobfName() != null) {
76 assert (isSimpleClassName(classMapping.getDeobfName())); 77 assert (isSimpleClassName(classMapping.getDeobfName()));
@@ -80,7 +81,7 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
80 } 81 }
81 82
82 public void removeInnerClassMapping(ClassMapping classMapping) { 83 public void removeInnerClassMapping(ClassMapping classMapping) {
83 boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfSimpleName()) != null; 84 boolean obfWasRemoved = m_innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null;
84 assert (obfWasRemoved); 85 assert (obfWasRemoved);
85 if (classMapping.getDeobfName() != null) { 86 if (classMapping.getDeobfName() != null) {
86 boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; 87 boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
@@ -88,20 +89,19 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
88 } 89 }
89 } 90 }
90 91
91 public ClassMapping getOrCreateInnerClass(String obfName) { 92 public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) {
92 assert (isSimpleClassName(obfName)); 93 ClassMapping classMapping = m_innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName());
93 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
94 if (classMapping == null) { 94 if (classMapping == null) {
95 classMapping = new ClassMapping(obfName); 95 classMapping = new ClassMapping(obfInnerClass.getName());
96 boolean wasAdded = m_innerClassesByObf.put(obfName, classMapping) == null; 96 boolean wasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null;
97 assert (wasAdded); 97 assert (wasAdded);
98 } 98 }
99 return classMapping; 99 return classMapping;
100 } 100 }
101 101
102 public ClassMapping getInnerClassByObf(String obfName) { 102 public ClassMapping getInnerClassByObfSimple(String obfSimpleName) {
103 assert (isSimpleClassName(obfName)); 103 assert (isSimpleClassName(obfSimpleName));
104 return m_innerClassesByObf.get(obfName); 104 return m_innerClassesByObfSimple.get(obfSimpleName);
105 } 105 }
106 106
107 public ClassMapping getInnerClassByDeobf(String deobfName) { 107 public ClassMapping getInnerClassByDeobf(String deobfName) {
@@ -109,35 +109,25 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
109 return m_innerClassesByDeobf.get(deobfName); 109 return m_innerClassesByDeobf.get(deobfName);
110 } 110 }
111 111
112 public ClassMapping getInnerClassByDeobfThenObf(String name) { 112 public ClassMapping getInnerClassByDeobfThenObfSimple(String name) {
113 ClassMapping classMapping = getInnerClassByDeobf(name); 113 ClassMapping classMapping = getInnerClassByDeobf(name);
114 if (classMapping == null) { 114 if (classMapping == null) {
115 classMapping = getInnerClassByObf(name); 115 classMapping = getInnerClassByObfSimple(name);
116 } 116 }
117 return classMapping; 117 return classMapping;
118 } 118 }
119 119
120 public String getObfInnerClassSimpleName(String deobfName) { 120 public String getDeobfInnerClassName(String obfSimpleName) {
121 assert (isSimpleClassName(deobfName)); 121 assert (isSimpleClassName(obfSimpleName));
122 ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName); 122 ClassMapping classMapping = m_innerClassesByObfSimple.get(obfSimpleName);
123 if (classMapping != null) {
124 return classMapping.getObfSimpleName();
125 }
126 return null;
127 }
128
129 public String getDeobfInnerClassName(String obfName) {
130 assert (isSimpleClassName(obfName));
131 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
132 if (classMapping != null) { 123 if (classMapping != null) {
133 return classMapping.getDeobfName(); 124 return classMapping.getDeobfName();
134 } 125 }
135 return null; 126 return null;
136 } 127 }
137 128
138 public void setInnerClassName(String obfName, String deobfName) { 129 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) {
139 assert (isSimpleClassName(obfName)); 130 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass);
140 ClassMapping classMapping = getOrCreateInnerClass(obfName);
141 if (classMapping.getDeobfName() != null) { 131 if (classMapping.getDeobfName() != null) {
142 boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; 132 boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
143 assert (wasRemoved); 133 assert (wasRemoved);
@@ -150,6 +140,15 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
150 } 140 }
151 } 141 }
152 142
143 public boolean hasInnerClassByObfSimple(String obfSimpleName) {
144 return m_innerClassesByObfSimple.containsKey(obfSimpleName);
145 }
146
147 public boolean hasInnerClassByDeobf(String deobfName) {
148 return m_innerClassesByDeobf.containsKey(deobfName);
149 }
150
151
153 //// FIELDS //////// 152 //// FIELDS ////////
154 153
155 public Iterable<FieldMapping> fields() { 154 public Iterable<FieldMapping> fields() {
@@ -382,7 +381,7 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
382 buf.append("\n"); 381 buf.append("\n");
383 } 382 }
384 buf.append("Inner Classes:\n"); 383 buf.append("Inner Classes:\n");
385 for (ClassMapping classMapping : m_innerClassesByObf.values()) { 384 for (ClassMapping classMapping : m_innerClassesByObfSimple.values()) {
386 buf.append("\t"); 385 buf.append("\t");
387 buf.append(classMapping.getObfSimpleName()); 386 buf.append(classMapping.getObfSimpleName());
388 buf.append(" <-> "); 387 buf.append(" <-> ");
@@ -404,11 +403,11 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
404 public boolean renameObfClass(String oldObfClassName, String newObfClassName) { 403 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
405 404
406 // rename inner classes 405 // rename inner classes
407 for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObf.values())) { 406 for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObfSimple.values())) {
408 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { 407 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
409 boolean wasRemoved = m_innerClassesByObf.remove(oldObfClassName) != null; 408 boolean wasRemoved = m_innerClassesByObfSimple.remove(oldObfClassName) != null;
410 assert (wasRemoved); 409 assert (wasRemoved);
411 boolean wasAdded = m_innerClassesByObf.put(newObfClassName, innerClassMapping) == null; 410 boolean wasAdded = m_innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null;
412 assert (wasAdded); 411 assert (wasAdded);
413 } 412 }
414 } 413 }
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index a85bcbf6..659d23ac 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -13,9 +13,11 @@ package cuchaz.enigma.mapping;
13import java.io.Serializable; 13import java.io.Serializable;
14import java.util.ArrayList; 14import java.util.ArrayList;
15import java.util.Collection; 15import java.util.Collection;
16import java.util.List;
16import java.util.Map; 17import java.util.Map;
17import java.util.Set; 18import java.util.Set;
18 19
20import com.beust.jcommander.internal.Lists;
19import com.google.common.collect.Maps; 21import com.google.common.collect.Maps;
20import com.google.common.collect.Sets; 22import com.google.common.collect.Sets;
21 23
@@ -89,6 +91,18 @@ public class Mappings implements Serializable {
89 return m_classesByDeobf.get(deobfName); 91 return m_classesByDeobf.get(deobfName);
90 } 92 }
91 93
94 public void setClassDeobfName(ClassMapping classMapping, String deobfName) {
95 if (classMapping.getDeobfName() != null) {
96 boolean wasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
97 assert (wasRemoved);
98 }
99 classMapping.setDeobfName(deobfName);
100 if (deobfName != null) {
101 boolean wasAdded = m_classesByDeobf.put(deobfName, classMapping) == null;
102 assert (wasAdded);
103 }
104 }
105
92 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) { 106 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) {
93 switch (direction) { 107 switch (direction) {
94 case Deobfuscating: 108 case Deobfuscating:
@@ -185,4 +199,18 @@ public class Mappings implements Serializable {
185 } 199 }
186 return false; 200 return false;
187 } 201 }
202
203 public List<ClassMapping> getClassMappingChain(ClassEntry obfClass) {
204 List<ClassMapping> mappingChain = Lists.newArrayList();
205 ClassMapping classMapping = null;
206 for (ClassEntry obfClassEntry : obfClass.getClassChain()) {
207 if (mappingChain.isEmpty()) {
208 classMapping = m_classesByObf.get(obfClassEntry.getName());
209 } else if (classMapping != null) {
210 classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName());
211 }
212 mappingChain.add(classMapping);
213 }
214 return mappingChain;
215 }
188} 216}
diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java
index 16f700d2..d7766dc8 100644
--- a/src/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -13,10 +13,10 @@ package cuchaz.enigma.mapping;
13import java.io.IOException; 13import java.io.IOException;
14import java.io.ObjectOutputStream; 14import java.io.ObjectOutputStream;
15import java.io.OutputStream; 15import java.io.OutputStream;
16import java.util.List;
16import java.util.Set; 17import java.util.Set;
17import java.util.zip.GZIPOutputStream; 18import java.util.zip.GZIPOutputStream;
18 19
19import cuchaz.enigma.Constants;
20import cuchaz.enigma.analysis.JarIndex; 20import cuchaz.enigma.analysis.JarIndex;
21 21
22public class MappingsRenamer { 22public class MappingsRenamer {
@@ -30,48 +30,43 @@ public class MappingsRenamer {
30 } 30 }
31 31
32 public void setClassName(ClassEntry obf, String deobfName) { 32 public void setClassName(ClassEntry obf, String deobfName) {
33 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass());
34 ClassEntry targetEntry = new ClassEntry(deobfName);
35 if (m_mappings.containsDeobfClass(deobfName) || m_index.containsObfClass(targetEntry)) {
36 throw new IllegalNameException(deobfName, "There is already a class with that name");
37 }
38 33
39 ClassMapping classMapping = getOrCreateClassMapping(obf); 34 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass());
40 35
41 if (obf.isInnerClass()) { 36 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf);
42 classMapping.setInnerClassName(obf.getInnerClassName(), deobfName); 37 if (mappingChain.size() == 1) {
38
39 if (deobfName != null) {
40 // make sure we don't rename to an existing obf or deobf class
41 if (m_mappings.containsDeobfClass(deobfName) || m_index.containsObfClass(new ClassEntry(deobfName))) {
42 throw new IllegalNameException(deobfName, "There is already a class with that name");
43 }
44 }
45
46 ClassMapping classMapping = mappingChain.get(0);
47 m_mappings.setClassDeobfName(classMapping, deobfName);
48
43 } else { 49 } else {
44 if (classMapping.getDeobfName() != null) { 50
45 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null; 51 ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2);
46 assert (wasRemoved); 52
53 if (deobfName != null) {
54 // make sure we don't rename to an existing obf or deobf inner class
55 if (outerClassMapping.hasInnerClassByDeobf(deobfName) || outerClassMapping.hasInnerClassByObfSimple(deobfName)) {
56 throw new IllegalNameException(deobfName, "There is already a class with that name");
57 }
47 } 58 }
48 classMapping.setDeobfName(deobfName); 59
49 boolean wasAdded = m_mappings.m_classesByDeobf.put(deobfName, classMapping) == null; 60 outerClassMapping.setInnerClassName(obf, deobfName);
50 assert (wasAdded);
51 } 61 }
52 } 62 }
53 63
54 public void removeClassMapping(ClassEntry obf) { 64 public void removeClassMapping(ClassEntry obf) {
55 ClassMapping classMapping = getClassMapping(obf); 65 setClassName(obf, null);
56 if (obf.isInnerClass()) {
57 classMapping.setInnerClassName(obf.getName(), null);
58 } else {
59 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
60 assert (wasRemoved);
61 classMapping.setDeobfName(null);
62 }
63 } 66 }
64 67
65 public void markClassAsDeobfuscated(ClassEntry obf) { 68 public void markClassAsDeobfuscated(ClassEntry obf) {
66 ClassMapping classMapping = getOrCreateClassMapping(obf); 69 setClassName(obf, obf.isInnerClass() ? obf.getInnermostClassName() : obf.getSimpleName());
67 if (obf.isInnerClass()) {
68 String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName();
69 classMapping.setInnerClassName(innerClassName, innerClassName);
70 } else {
71 classMapping.setDeobfName(obf.getName());
72 boolean wasAdded = m_mappings.m_classesByDeobf.put(obf.getName(), classMapping) == null;
73 assert (wasAdded);
74 }
75 } 70 }
76 71
77 public void setFieldName(FieldEntry obf, String deobfName) { 72 public void setFieldName(FieldEntry obf, String deobfName) {
@@ -81,17 +76,17 @@ public class MappingsRenamer {
81 throw new IllegalNameException(deobfName, "There is already a field with that name"); 76 throw new IllegalNameException(deobfName, "There is already a field with that name");
82 } 77 }
83 78
84 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 79 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
85 classMapping.setFieldName(obf.getName(), obf.getType(), deobfName); 80 classMapping.setFieldName(obf.getName(), obf.getType(), deobfName);
86 } 81 }
87 82
88 public void removeFieldMapping(FieldEntry obf) { 83 public void removeFieldMapping(FieldEntry obf) {
89 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry()); 84 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
90 classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType())); 85 classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType()));
91 } 86 }
92 87
93 public void markFieldAsDeobfuscated(FieldEntry obf) { 88 public void markFieldAsDeobfuscated(FieldEntry obf) {
94 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 89 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
95 classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName()); 90 classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName());
96 } 91 }
97 92
@@ -121,7 +116,7 @@ public class MappingsRenamer {
121 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); 116 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
122 } 117 }
123 118
124 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 119 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
125 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName); 120 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
126 } 121 }
127 122
@@ -132,7 +127,7 @@ public class MappingsRenamer {
132 } 127 }
133 128
134 public void removeMethodMapping(MethodEntry obf) { 129 public void removeMethodMapping(MethodEntry obf) {
135 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 130 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
136 classMapping.setMethodName(obf.getName(), obf.getSignature(), null); 131 classMapping.setMethodName(obf.getName(), obf.getSignature(), null);
137 } 132 }
138 133
@@ -143,7 +138,7 @@ public class MappingsRenamer {
143 } 138 }
144 139
145 public void markMethodAsDeobfuscated(MethodEntry obf) { 140 public void markMethodAsDeobfuscated(MethodEntry obf) {
146 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 141 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
147 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName()); 142 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName());
148 } 143 }
149 144
@@ -154,17 +149,17 @@ public class MappingsRenamer {
154 throw new IllegalNameException(deobfName, "There is already an argument with that name"); 149 throw new IllegalNameException(deobfName, "There is already an argument with that name");
155 } 150 }
156 151
157 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 152 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
158 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName); 153 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
159 } 154 }
160 155
161 public void removeArgumentMapping(ArgumentEntry obf) { 156 public void removeArgumentMapping(ArgumentEntry obf) {
162 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry()); 157 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
163 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex()); 158 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex());
164 } 159 }
165 160
166 public void markArgumentAsDeobfuscated(ArgumentEntry obf) { 161 public void markArgumentAsDeobfuscated(ArgumentEntry obf) {
167 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry()); 162 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
168 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); 163 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
169 } 164 }
170 165
@@ -204,34 +199,31 @@ public class MappingsRenamer {
204 gzipout.finish(); 199 gzipout.finish();
205 } 200 }
206 201
207 private ClassMapping getClassMapping(ClassEntry obfClassEntry) {
208 return m_mappings.m_classesByObf.get(obfClassEntry.getOuterClassName());
209 }
210
211 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { 202 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) {
212 String obfClassName = obfClassEntry.getOuterClassName(); 203 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry);
213 ClassMapping classMapping = m_mappings.m_classesByObf.get(obfClassName); 204 return mappingChain.get(mappingChain.size() - 1);
214 if (classMapping == null) { 205 }
215 classMapping = new ClassMapping(obfClassName); 206
216 boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null; 207 private List<ClassMapping> getOrCreateClassMappingChain(ClassEntry obfClassEntry) {
217 assert (obfWasAdded); 208 List<ClassEntry> classChain = obfClassEntry.getClassChain();
218 } 209 List<ClassMapping> mappingChain = m_mappings.getClassMappingChain(obfClassEntry);
219 return classMapping; 210 for (int i=0; i<classChain.size(); i++) {
220 } 211 ClassEntry classEntry = classChain.get(i);
221 212 ClassMapping classMapping = mappingChain.get(i);
222 private ClassMapping getClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) { 213 if (classMapping == null) {
223 ClassMapping classMapping = getClassMapping(obfClassEntry); 214
224 if (obfClassEntry.isInDefaultPackage()) { 215 // create it
225 classMapping = classMapping.getInnerClassByObf(obfClassEntry.getInnerClassName()); 216 classMapping = new ClassMapping(classEntry.getName());
226 } 217 mappingChain.set(i, classMapping);
227 return classMapping; 218
228 } 219 // add it to the right parent
229 220 if (i == 0) {
230 private ClassMapping getOrCreateClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) { 221 m_mappings.addClassMapping(classMapping);
231 ClassMapping classMapping = getOrCreateClassMapping(obfClassEntry); 222 } else {
232 if (obfClassEntry.isInnerClass()) { 223 mappingChain.get(i-1).addInnerClassMapping(classMapping);
233 classMapping = classMapping.getOrCreateInnerClass(obfClassEntry.getInnerClassName()); 224 }
225 }
234 } 226 }
235 return classMapping; 227 return mappingChain;
236 } 228 }
237} 229}
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
index d3b6e771..fb187b90 100644
--- a/src/cuchaz/enigma/mapping/Translator.java
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -24,6 +24,13 @@ public class Translator {
24 private Map<String,ClassMapping> m_classes; 24 private Map<String,ClassMapping> m_classes;
25 private TranslationIndex m_index; 25 private TranslationIndex m_index;
26 26
27 private ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() {
28 @Override
29 public String replace(String className) {
30 return translateEntry(new ClassEntry(className)).getName();
31 }
32 };
33
27 public Translator() { 34 public Translator() {
28 m_direction = null; 35 m_direction = null;
29 m_classes = Maps.newHashMap(); 36 m_classes = Maps.newHashMap();
@@ -69,48 +76,16 @@ public class Translator {
69 } 76 }
70 } 77 }
71 78
72 public String translateClass(String className) {
73 return translate(new ClassEntry(className));
74 }
75
76 public String translate(ClassEntry in) { 79 public String translate(ClassEntry in) {
77 80 ClassEntry translated = translateEntry(in);
78 if (in.isInnerClass()) { 81 if (translated.equals(in)) {
79 82 return null;
80 // translate everything in the class chain, or return null
81 List<ClassMapping> mappingsChain = getClassMappingChain(in);
82 StringBuilder buf = new StringBuilder();
83 for (ClassMapping classMapping : mappingsChain) {
84 if (classMapping == null) {
85 return null;
86 }
87 boolean isFirstClass = buf.length() == 0;
88 String name = m_direction.choose(
89 classMapping.getDeobfName(),
90 isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName()
91 );
92 if (name == null) {
93 return null;
94 }
95 if (!isFirstClass) {
96 buf.append("$");
97 }
98 buf.append(name);
99 }
100 return buf.toString();
101
102 } else {
103
104 // normal classes are easier
105 ClassMapping classMapping = m_classes.get(in.getName());
106 if (classMapping == null) {
107 return null;
108 }
109 return m_direction.choose(
110 classMapping.getDeobfName(),
111 classMapping.getObfFullName()
112 );
113 } 83 }
84 return translated.getName();
85 }
86
87 public String translateClass(String className) {
88 return translate(new ClassEntry(className));
114 } 89 }
115 90
116 public ClassEntry translateEntry(ClassEntry in) { 91 public ClassEntry translateEntry(ClassEntry in) {
@@ -264,21 +239,11 @@ public class Translator {
264 } 239 }
265 240
266 public Type translateType(Type type) { 241 public Type translateType(Type type) {
267 return new Type(type, new ClassNameReplacer() { 242 return new Type(type, m_classNameReplacer);
268 @Override
269 public String replace(String className) {
270 return translateClass(className);
271 }
272 });
273 } 243 }
274 244
275 public Signature translateSignature(Signature signature) { 245 public Signature translateSignature(Signature signature) {
276 return new Signature(signature, new ClassNameReplacer() { 246 return new Signature(signature, m_classNameReplacer);
277 @Override
278 public String replace(String className) {
279 return translateClass(className);
280 }
281 });
282 } 247 }
283 248
284 private ClassMapping findClassMapping(ClassEntry in) { 249 private ClassMapping findClassMapping(ClassEntry in) {
@@ -302,8 +267,8 @@ public class Translator {
302 ClassMapping innerClassMapping = null; 267 ClassMapping innerClassMapping = null;
303 if (outerClassMapping != null) { 268 if (outerClassMapping != null) {
304 innerClassMapping = m_direction.choose( 269 innerClassMapping = m_direction.choose(
305 outerClassMapping.getInnerClassByObf(parts[i]), 270 outerClassMapping.getInnerClassByObfSimple(parts[i]),
306 outerClassMapping.getInnerClassByDeobfThenObf(parts[i]) 271 outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i])
307 ); 272 );
308 } 273 }
309 mappingsChain.add(innerClassMapping); 274 mappingsChain.add(innerClassMapping);
diff --git a/test/cuchaz/enigma/TestDeobfed.java b/test/cuchaz/enigma/TestDeobfed.java
index 3c2ae51d..ca349d7c 100644
--- a/test/cuchaz/enigma/TestDeobfed.java
+++ b/test/cuchaz/enigma/TestDeobfed.java
@@ -34,21 +34,24 @@ public class TestDeobfed {
34 newClass("none/b"), 34 newClass("none/b"),
35 newClass("none/c"), 35 newClass("none/c"),
36 newClass("none/d"), 36 newClass("none/d"),
37 newClass("none/d$e"), 37 newClass("none/d$1"),
38 newClass("none/e"),
38 newClass("none/f"), 39 newClass("none/f"),
39 newClass("none/g"), 40 newClass("none/g"),
41 newClass("none/g$a"),
42 newClass("none/g$a$a"),
43 newClass("none/g$b"),
44 newClass("none/g$b$a"),
40 newClass("none/h"), 45 newClass("none/h"),
41 newClass("none/h$i"), 46 newClass("none/h$a"),
42 newClass("none/h$i$j"), 47 newClass("none/h$a$a"),
43 newClass("none/h$k"), 48 newClass("none/h$b"),
44 newClass("none/h$k$l"), 49 newClass("none/h$b$a"),
45 newClass("none/m"), 50 newClass("none/h$b$a$a"),
46 newClass("none/m$n"), 51 newClass("none/h$b$a$b"),
47 newClass("none/m$n$o"), 52 newClass("none/i"),
48 newClass("none/m$p"), 53 newClass("none/i$a"),
49 newClass("none/m$p$q"), 54 newClass("none/i$b")
50 newClass("none/m$p$q$r"),
51 newClass("none/m$p$q$s")
52 )); 55 ));
53 } 56 }
54 57
@@ -60,20 +63,23 @@ public class TestDeobfed {
60 deobfuscator.getSourceTree("none/b"); 63 deobfuscator.getSourceTree("none/b");
61 deobfuscator.getSourceTree("none/c"); 64 deobfuscator.getSourceTree("none/c");
62 deobfuscator.getSourceTree("none/d"); 65 deobfuscator.getSourceTree("none/d");
63 deobfuscator.getSourceTree("none/d$e"); 66 deobfuscator.getSourceTree("none/d$1");
67 deobfuscator.getSourceTree("none/e");
64 deobfuscator.getSourceTree("none/f"); 68 deobfuscator.getSourceTree("none/f");
65 deobfuscator.getSourceTree("none/g"); 69 deobfuscator.getSourceTree("none/g");
70 deobfuscator.getSourceTree("none/g$a");
71 deobfuscator.getSourceTree("none/g$a$a");
72 deobfuscator.getSourceTree("none/g$b");
73 deobfuscator.getSourceTree("none/g$b$a");
66 deobfuscator.getSourceTree("none/h"); 74 deobfuscator.getSourceTree("none/h");
67 deobfuscator.getSourceTree("none/h$i"); 75 deobfuscator.getSourceTree("none/h$a");
68 deobfuscator.getSourceTree("none/h$i$j"); 76 deobfuscator.getSourceTree("none/h$a$a");
69 deobfuscator.getSourceTree("none/h$k"); 77 deobfuscator.getSourceTree("none/h$b");
70 deobfuscator.getSourceTree("none/h$k$l"); 78 deobfuscator.getSourceTree("none/h$b$a");
71 deobfuscator.getSourceTree("none/m"); 79 deobfuscator.getSourceTree("none/h$b$a$a");
72 deobfuscator.getSourceTree("none/m$n"); 80 deobfuscator.getSourceTree("none/h$b$a$b");
73 deobfuscator.getSourceTree("none/m$n$o"); 81 deobfuscator.getSourceTree("none/i");
74 deobfuscator.getSourceTree("none/m$p"); 82 deobfuscator.getSourceTree("none/i$a");
75 deobfuscator.getSourceTree("none/m$p$q"); 83 deobfuscator.getSourceTree("none/i$b");
76 deobfuscator.getSourceTree("none/m$p$q$r");
77 deobfuscator.getSourceTree("none/m$p$q$s");
78 } 84 }
79} 85}
diff --git a/test/cuchaz/enigma/TestInnerClasses.java b/test/cuchaz/enigma/TestInnerClasses.java
index 2eb5accc..014a4613 100644
--- a/test/cuchaz/enigma/TestInnerClasses.java
+++ b/test/cuchaz/enigma/TestInnerClasses.java
@@ -29,19 +29,19 @@ public class TestInnerClasses {
29 private Deobfuscator m_deobfuscator; 29 private Deobfuscator m_deobfuscator;
30 30
31 private static final ClassEntry AnonymousOuter = newClass("none/a"); 31 private static final ClassEntry AnonymousOuter = newClass("none/a");
32 private static final ClassEntry AnonymousInner = newClass("none/b"); 32 private static final ClassEntry AnonymousInner = newClass("none/a$1");
33 private static final ClassEntry SimpleOuter = newClass("none/g"); 33 private static final ClassEntry SimpleOuter = newClass("none/d");
34 private static final ClassEntry SimpleInner = newClass("none/h"); 34 private static final ClassEntry SimpleInner = newClass("none/d$a");
35 private static final ClassEntry ConstructorArgsOuter = newClass("none/e"); 35 private static final ClassEntry ConstructorArgsOuter = newClass("none/c");
36 private static final ClassEntry ConstructorArgsInner = newClass("none/f"); 36 private static final ClassEntry ConstructorArgsInner = newClass("none/c$a");
37 private static final ClassEntry AnonymousWithScopeArgsOuter = newClass("none/c"); 37 private static final ClassEntry AnonymousWithScopeArgsOuter = newClass("none/b");
38 private static final ClassEntry AnonymousWithScopeArgsInner = newClass("none/d"); 38 private static final ClassEntry AnonymousWithScopeArgsInner = newClass("none/b$1");
39 private static final ClassEntry AnonymousWithOuterAccessOuter = newClass("none/i"); 39 private static final ClassEntry AnonymousWithOuterAccessOuter = newClass("none/e");
40 private static final ClassEntry AnonymousWithOuterAccessInner = newClass("none/j"); 40 private static final ClassEntry AnonymousWithOuterAccessInner = newClass("none/e$1");
41 private static final ClassEntry ClassTreeRoot = newClass("none/k"); 41 private static final ClassEntry ClassTreeRoot = newClass("none/f");
42 private static final ClassEntry ClassTreeLevel1 = newClass("none/l"); 42 private static final ClassEntry ClassTreeLevel1 = newClass("none/f$a");
43 private static final ClassEntry ClassTreeLevel2 = newClass("none/m"); 43 private static final ClassEntry ClassTreeLevel2 = newClass("none/f$a$a");
44 private static final ClassEntry ClassTreeLevel3 = newClass("none/n"); 44 private static final ClassEntry ClassTreeLevel3 = newClass("none/f$a$a$a");
45 45
46 public TestInnerClasses() 46 public TestInnerClasses()
47 throws Exception { 47 throws Exception {
@@ -101,7 +101,7 @@ public class TestInnerClasses {
101 101
102 // level 1 102 // level 1
103 ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 103 ClassEntry fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
104 + "$" + ClassTreeLevel1.getSimpleName() 104 + "$" + ClassTreeLevel1.getInnermostClassName()
105 ); 105 );
106 assertThat(m_index.containsObfClass(fullClassEntry), is(true)); 106 assertThat(m_index.containsObfClass(fullClassEntry), is(true));
107 assertThat(m_index.getOuterClass(ClassTreeLevel1), is(ClassTreeRoot)); 107 assertThat(m_index.getOuterClass(ClassTreeLevel1), is(ClassTreeRoot));
@@ -109,8 +109,8 @@ public class TestInnerClasses {
109 109
110 // level 2 110 // level 2
111 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 111 fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
112 + "$" + ClassTreeLevel1.getSimpleName() 112 + "$" + ClassTreeLevel1.getInnermostClassName()
113 + "$" + ClassTreeLevel2.getSimpleName() 113 + "$" + ClassTreeLevel2.getInnermostClassName()
114 ); 114 );
115 assertThat(m_index.containsObfClass(fullClassEntry), is(true)); 115 assertThat(m_index.containsObfClass(fullClassEntry), is(true));
116 assertThat(m_index.getOuterClass(ClassTreeLevel2), is(ClassTreeLevel1)); 116 assertThat(m_index.getOuterClass(ClassTreeLevel2), is(ClassTreeLevel1));
@@ -118,9 +118,9 @@ public class TestInnerClasses {
118 118
119 // level 3 119 // level 3
120 fullClassEntry = new ClassEntry(ClassTreeRoot.getName() 120 fullClassEntry = new ClassEntry(ClassTreeRoot.getName()
121 + "$" + ClassTreeLevel1.getSimpleName() 121 + "$" + ClassTreeLevel1.getInnermostClassName()
122 + "$" + ClassTreeLevel2.getSimpleName() 122 + "$" + ClassTreeLevel2.getInnermostClassName()
123 + "$" + ClassTreeLevel3.getSimpleName() 123 + "$" + ClassTreeLevel3.getInnermostClassName()
124 ); 124 );
125 assertThat(m_index.containsObfClass(fullClassEntry), is(true)); 125 assertThat(m_index.containsObfClass(fullClassEntry), is(true));
126 assertThat(m_index.getOuterClass(ClassTreeLevel3), is(ClassTreeLevel2)); 126 assertThat(m_index.getOuterClass(ClassTreeLevel3), is(ClassTreeLevel2));
diff --git a/test/cuchaz/enigma/TestSourceIndex.java b/test/cuchaz/enigma/TestSourceIndex.java
index 94bf941d..13971249 100644
--- a/test/cuchaz/enigma/TestSourceIndex.java
+++ b/test/cuchaz/enigma/TestSourceIndex.java
@@ -24,7 +24,7 @@ import cuchaz.enigma.mapping.ClassEntry;
24 24
25public class TestSourceIndex { 25public class TestSourceIndex {
26 26
27 @Test 27 // TEMP @Test
28 public void indexEverything() 28 public void indexEverything()
29 throws Exception { 29 throws Exception {
30 30
diff --git a/test/cuchaz/enigma/TestTranslator.java b/test/cuchaz/enigma/TestTranslator.java
index 02526050..45c69bb2 100644
--- a/test/cuchaz/enigma/TestTranslator.java
+++ b/test/cuchaz/enigma/TestTranslator.java
@@ -101,26 +101,31 @@ public class TestTranslator {
101 public void innerClasses() { 101 public void innerClasses() {
102 102
103 // classes 103 // classes
104 assertMapping(newClass("none/h"), newClass("deobf/H_OuterClass")); 104 assertMapping(newClass("none/g"), newClass("deobf/G_OuterClass"));
105 assertMapping(newClass("none/h$i"), newClass("deobf/H_OuterClass$I_InnerClass")); 105 assertMapping(newClass("none/g$a"), newClass("deobf/G_OuterClass$A_InnerClass"));
106 assertMapping(newClass("none/h$i$j"), newClass("deobf/H_OuterClass$I_InnerClass$J_InnerInnerClass")); 106 assertMapping(newClass("none/g$a$a"), newClass("deobf/G_OuterClass$A_InnerClass$A_InnerInnerClass"));
107 assertMapping(newClass("none/h$k"), newClass("deobf/H_OuterClass$k")); 107 assertMapping(newClass("none/g$b"), newClass("deobf/G_OuterClass$b"));
108 assertMapping(newClass("none/h$k$l"), newClass("deobf/H_OuterClass$k$L_NamedInnerClass")); 108 assertMapping(newClass("none/g$b$a"), newClass("deobf/G_OuterClass$b$A_NamedInnerClass"));
109 109
110 // fields 110 // fields
111 assertMapping(newField("none/h$i", "a", "I"), newField("deobf/H_OuterClass$I_InnerClass", "f1", "I")); 111 assertMapping(newField("none/g$a", "a", "I"), newField("deobf/G_OuterClass$A_InnerClass", "f1", "I"));
112 assertMapping(newField("none/h$i", "a", "Ljava/lang/String;"), newField("deobf/H_OuterClass$I_InnerClass", "f2", "Ljava/lang/String;")); 112 assertMapping(newField("none/g$a", "a", "Ljava/lang/String;"), newField("deobf/G_OuterClass$A_InnerClass", "f2", "Ljava/lang/String;"));
113 assertMapping(newField("none/h$i$j", "a", "I"), newField("deobf/H_OuterClass$I_InnerClass$J_InnerInnerClass", "f3", "I")); 113 assertMapping(newField("none/g$a$a", "a", "I"), newField("deobf/G_OuterClass$A_InnerClass$A_InnerInnerClass", "f3", "I"));
114 assertMapping(newField("none/h$k$l", "a", "I"), newField("deobf/H_OuterClass$k$L_NamedInnerClass", "f4", "I")); 114 assertMapping(newField("none/g$b$a", "a", "I"), newField("deobf/G_OuterClass$b$A_NamedInnerClass", "f4", "I"));
115 115
116 // methods 116 // methods
117 assertMapping(newMethod("none/h$i", "a", "()V"), newMethod("deobf/H_OuterClass$I_InnerClass", "m1", "()V")); 117 assertMapping(newMethod("none/g$a", "a", "()V"), newMethod("deobf/G_OuterClass$A_InnerClass", "m1", "()V"));
118 assertMapping(newMethod("none/h$i$j", "a", "()V"), newMethod("deobf/H_OuterClass$I_InnerClass$J_InnerInnerClass", "m2", "()V")); 118 assertMapping(newMethod("none/g$a$a", "a", "()V"), newMethod("deobf/G_OuterClass$A_InnerClass$A_InnerInnerClass", "m2", "()V"));
119 } 119 }
120 120
121 @Test 121 @Test
122 public void namelessClass() { 122 public void namelessClass() {
123 assertMapping(newClass("none/m"), newClass("none/m")); 123 assertMapping(newClass("none/h"), newClass("none/h"));
124 }
125
126 @Test
127 public void testGenerics() {
128 // TODO
124 } 129 }
125 130
126 private void assertMapping(Entry obf, Entry deobf) { 131 private void assertMapping(Entry obf, Entry deobf) {
diff --git a/test/cuchaz/enigma/inputs/translation/G_ObjectMethods.java b/test/cuchaz/enigma/inputs/translation/F_ObjectMethods.java
index ebad5a38..4e091797 100644
--- a/test/cuchaz/enigma/inputs/translation/G_ObjectMethods.java
+++ b/test/cuchaz/enigma/inputs/translation/F_ObjectMethods.java
@@ -1,6 +1,6 @@
1package cuchaz.enigma.inputs.translation; 1package cuchaz.enigma.inputs.translation;
2 2
3public class G_ObjectMethods { 3public class F_ObjectMethods {
4 4
5 public void callEmAll() 5 public void callEmAll()
6 throws Throwable { 6 throws Throwable {
diff --git a/test/cuchaz/enigma/inputs/translation/H_OuterClass.java b/test/cuchaz/enigma/inputs/translation/G_OuterClass.java
index 995c65d2..0856afed 100644
--- a/test/cuchaz/enigma/inputs/translation/H_OuterClass.java
+++ b/test/cuchaz/enigma/inputs/translation/G_OuterClass.java
@@ -1,16 +1,16 @@
1package cuchaz.enigma.inputs.translation; 1package cuchaz.enigma.inputs.translation;
2 2
3 3
4public class H_OuterClass { 4public class G_OuterClass {
5 5
6 public class I_InnerClass { 6 public class A_InnerClass {
7 7
8 public int f1; 8 public int f1;
9 public String f2; 9 public String f2;
10 10
11 public void m1() {} 11 public void m1() {}
12 12
13 public class J_InnerInnerClass { 13 public class A_InnerInnerClass {
14 14
15 public int f3; 15 public int f3;
16 16
@@ -18,8 +18,8 @@ public class H_OuterClass {
18 } 18 }
19 } 19 }
20 20
21 public class K_NamelessClass { 21 public class B_NamelessClass {
22 public class L_NamedInnerClass { 22 public class A_NamedInnerClass {
23 public int f4; 23 public int f4;
24 } 24 }
25 } 25 }
diff --git a/test/cuchaz/enigma/inputs/translation/H_NamelessClass.java b/test/cuchaz/enigma/inputs/translation/H_NamelessClass.java
new file mode 100644
index 00000000..5802d789
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/translation/H_NamelessClass.java
@@ -0,0 +1,28 @@
1package cuchaz.enigma.inputs.translation;
2
3
4public class H_NamelessClass {
5
6 public class A_InnerClass {
7
8 public int f1;
9 public String f2;
10
11 public void m1() {}
12
13 public class A_InnerInnerClass {
14
15 public int f3;
16
17 public void m2() {}
18 }
19 }
20
21 public class B_NamelessClass {
22 public class A_NamedInnerClass {
23 public int f4;
24 public class A_AnotherInnerClass {}
25 public class B_YetAnotherInnerClass {}
26 }
27 }
28}
diff --git a/test/cuchaz/enigma/inputs/translation/I_Generics.java b/test/cuchaz/enigma/inputs/translation/I_Generics.java
new file mode 100644
index 00000000..191931a8
--- /dev/null
+++ b/test/cuchaz/enigma/inputs/translation/I_Generics.java
@@ -0,0 +1,25 @@
1package cuchaz.enigma.inputs.translation;
2
3import java.util.List;
4import java.util.Map;
5
6
7public class I_Generics {
8
9 public class A_Type {
10 }
11
12 public List<Integer> f1;
13 public List<A_Type> f2;
14 public Map<A_Type,A_Type> f3;
15
16 public class B_Generic<T> {
17 public T f4;
18 public T m1() {
19 return null;
20 }
21 }
22
23 public B_Generic<Integer> f5;
24 public B_Generic<A_Type> f6;
25}
diff --git a/test/cuchaz/enigma/inputs/translation/M_NamelessClass.java b/test/cuchaz/enigma/inputs/translation/M_NamelessClass.java
deleted file mode 100644
index 5d8acbc7..00000000
--- a/test/cuchaz/enigma/inputs/translation/M_NamelessClass.java
+++ /dev/null
@@ -1,28 +0,0 @@
1package cuchaz.enigma.inputs.translation;
2
3
4public class M_NamelessClass {
5
6 public class N_InnerClass {
7
8 public int f1;
9 public String f2;
10
11 public void m1() {}
12
13 public class O_InnerInnerClass {
14
15 public int f3;
16
17 public void m2() {}
18 }
19 }
20
21 public class P_NamelessClass {
22 public class Q_NamedInnerClass {
23 public int f4;
24 public class R_AnotherInnerClass {}
25 public class S_YetAnotherInnerClass {}
26 }
27 }
28}
diff --git a/test/cuchaz/enigma/resources/translation.mappings b/test/cuchaz/enigma/resources/translation.mappings
index 5dffaf1d..55bd7e5c 100644
--- a/test/cuchaz/enigma/resources/translation.mappings
+++ b/test/cuchaz/enigma/resources/translation.mappings
@@ -17,15 +17,16 @@ CLASS none/c deobf/C_SubClass
17 FIELD c f4 I 17 FIELD c f4 I
18 METHOD a m1 ()I 18 METHOD a m1 ()I
19 METHOD c m3 ()I 19 METHOD c m3 ()I
20CLASS none/h deobf/H_OuterClass 20CLASS none/g deobf/G_OuterClass
21 CLASS none/i I_InnerClass 21 CLASS none/g$a A_InnerClass
22 CLASS none/j J_InnerInnerClass 22 CLASS none/g$a$a A_InnerInnerClass
23 FIELD a f3 I 23 FIELD a f3 I
24 METHOD a m2 ()V 24 METHOD a m2 ()V
25 FIELD a f1 I 25 FIELD a f1 I
26 FIELD a f2 Ljava/lang/String; 26 FIELD a f2 Ljava/lang/String;
27 METHOD a m1 ()V 27 METHOD a m1 ()V
28 CLASS none/k 28 CLASS none/g$b
29 CLASS none/l L_NamedInnerClass 29 CLASS none/g$b$a A_NamedInnerClass
30 FIELD a f4 I 30 FIELD a f4 I
31CLASS none/m \ No newline at end of file 31CLASS none/h
32CLASS none/i I_Generics