summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/mapping
diff options
context:
space:
mode:
authorGravatar Thog2017-03-08 08:17:04 +0100
committerGravatar Thog2017-03-08 08:17:04 +0100
commit6e464ea251cab63c776ece0b2a356f1498ffa294 (patch)
tree5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/mapping
parentDrop unix case style and implement hashCode when equals is overrided (diff)
downloadenigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz
enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/mapping')
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java185
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java55
-rw-r--r--src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java3
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ClassEntry.java295
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ClassMapping.java1042
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java3
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java175
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Entry.java9
-rw-r--r--src/main/java/cuchaz/enigma/mapping/EntryFactory.java217
-rw-r--r--src/main/java/cuchaz/enigma/mapping/FieldEntry.java139
-rw-r--r--src/main/java/cuchaz/enigma/mapping/FieldMapping.java180
-rw-r--r--src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java186
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java453
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsChecker.java155
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java340
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java70
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java633
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java112
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MemberMapping.java6
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MethodEntry.java145
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MethodMapping.java393
-rw-r--r--src/main/java/cuchaz/enigma/mapping/NameValidator.java89
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java91
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Signature.java154
-rw-r--r--src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java125
-rw-r--r--src/main/java/cuchaz/enigma/mapping/TranslationDirection.java27
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Translator.java655
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Type.java431
28 files changed, 3159 insertions, 3209 deletions
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
index 662516d..9154cc2 100644
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
@@ -8,102 +8,103 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.utils.Utils; 14import cuchaz.enigma.utils.Utils;
14 15
15public class ArgumentEntry implements Entry { 16public class ArgumentEntry implements Entry {
16 17
17 private BehaviorEntry behaviorEntry; 18 private BehaviorEntry behaviorEntry;
18 private int index; 19 private int index;
19 private String name; 20 private String name;
20 21
21 public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) { 22 public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) {
22 if (behaviorEntry == null) { 23 if (behaviorEntry == null) {
23 throw new IllegalArgumentException("Behavior cannot be null!"); 24 throw new IllegalArgumentException("Behavior cannot be null!");
24 } 25 }
25 if (index < 0) { 26 if (index < 0) {
26 throw new IllegalArgumentException("Index must be non-negative!"); 27 throw new IllegalArgumentException("Index must be non-negative!");
27 } 28 }
28 if (name == null) { 29 if (name == null) {
29 throw new IllegalArgumentException("Argument name cannot be null!"); 30 throw new IllegalArgumentException("Argument name cannot be null!");
30 } 31 }
31 32
32 this.behaviorEntry = behaviorEntry; 33 this.behaviorEntry = behaviorEntry;
33 this.index = index; 34 this.index = index;
34 this.name = name; 35 this.name = name;
35 } 36 }
36 37
37 public ArgumentEntry(ArgumentEntry other) { 38 public ArgumentEntry(ArgumentEntry other) {
38 this.behaviorEntry = other.getBehaviorEntry(); 39 this.behaviorEntry = other.getBehaviorEntry();
39 this.index = other.index; 40 this.index = other.index;
40 this.name = other.name; 41 this.name = other.name;
41 } 42 }
42 43
43 public ArgumentEntry(ArgumentEntry other, String newClassName) { 44 public ArgumentEntry(ArgumentEntry other, String newClassName) {
44 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName)); 45 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName));
45 this.index = other.index; 46 this.index = other.index;
46 this.name = other.name; 47 this.name = other.name;
47 } 48 }
48 49
49 public ArgumentEntry(ArgumentEntry other, BehaviorEntry entry) { 50 public ArgumentEntry(ArgumentEntry other, BehaviorEntry entry) {
50 this.behaviorEntry = entry; 51 this.behaviorEntry = entry;
51 this.index = other.index; 52 this.index = other.index;
52 this.name = other.name; 53 this.name = other.name;
53 } 54 }
54 55
55 public BehaviorEntry getBehaviorEntry() { 56 public BehaviorEntry getBehaviorEntry() {
56 return this.behaviorEntry; 57 return this.behaviorEntry;
57 } 58 }
58 59
59 public int getIndex() { 60 public int getIndex() {
60 return this.index; 61 return this.index;
61 } 62 }
62 63
63 @Override 64 @Override
64 public String getName() { 65 public String getName() {
65 return this.name; 66 return this.name;
66 } 67 }
67 68
68 @Override 69 @Override
69 public ClassEntry getClassEntry() { 70 public ClassEntry getClassEntry() {
70 return this.behaviorEntry.getClassEntry(); 71 return this.behaviorEntry.getClassEntry();
71 } 72 }
72 73
73 @Override 74 @Override
74 public String getClassName() { 75 public String getClassName() {
75 return this.behaviorEntry.getClassName(); 76 return this.behaviorEntry.getClassName();
76 } 77 }
77 78
78 @Override 79 @Override
79 public ArgumentEntry cloneToNewClass(ClassEntry classEntry) { 80 public ArgumentEntry cloneToNewClass(ClassEntry classEntry) {
80 return new ArgumentEntry(this, classEntry.getName()); 81 return new ArgumentEntry(this, classEntry.getName());
81 } 82 }
82 83
83 public String getMethodName() { 84 public String getMethodName() {
84 return this.behaviorEntry.getName(); 85 return this.behaviorEntry.getName();
85 } 86 }
86 87
87 public Signature getMethodSignature() { 88 public Signature getMethodSignature() {
88 return this.behaviorEntry.getSignature(); 89 return this.behaviorEntry.getSignature();
89 } 90 }
90 91
91 @Override 92 @Override
92 public int hashCode() { 93 public int hashCode() {
93 return Utils.combineHashesOrdered(this.behaviorEntry, Integer.valueOf(this.index).hashCode(), this.name.hashCode()); 94 return Utils.combineHashesOrdered(this.behaviorEntry, Integer.valueOf(this.index).hashCode(), this.name.hashCode());
94 } 95 }
95 96
96 @Override 97 @Override
97 public boolean equals(Object other) { 98 public boolean equals(Object other) {
98 return other instanceof ArgumentEntry && equals((ArgumentEntry) other); 99 return other instanceof ArgumentEntry && equals((ArgumentEntry) other);
99 } 100 }
100 101
101 public boolean equals(ArgumentEntry other) { 102 public boolean equals(ArgumentEntry other) {
102 return this.behaviorEntry.equals(other.behaviorEntry) && this.index == other.index && this.name.equals(other.name); 103 return this.behaviorEntry.equals(other.behaviorEntry) && this.index == other.index && this.name.equals(other.name);
103 } 104 }
104 105
105 @Override 106 @Override
106 public String toString() { 107 public String toString() {
107 return this.behaviorEntry.toString() + "(" + this.index + ":" + this.name + ")"; 108 return this.behaviorEntry + "(" + this.index + ":" + this.name + ")";
108 } 109 }
109} 110}
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
index e3f8927..91ecd10 100644
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -8,42 +8,43 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13public class ArgumentMapping implements Comparable<ArgumentMapping> { 14public class ArgumentMapping implements Comparable<ArgumentMapping> {
14 15
15 private int index; 16 private int index;
16 private String name; 17 private String name;
17 18
18 // NOTE: this argument order is important for the MethodReader/MethodWriter 19 // NOTE: this argument order is important for the MethodReader/MethodWriter
19 public ArgumentMapping(int index, String name) { 20 public ArgumentMapping(int index, String name) {
20 this.index = index; 21 this.index = index;
21 this.name = NameValidator.validateArgumentName(name); 22 this.name = NameValidator.validateArgumentName(name);
22 } 23 }
23 24
24 public ArgumentMapping(ArgumentMapping other) { 25 public ArgumentMapping(ArgumentMapping other) {
25 this.index = other.index; 26 this.index = other.index;
26 this.name = other.name; 27 this.name = other.name;
27 } 28 }
28 29
29 public int getIndex() { 30 public int getIndex() {
30 return this.index; 31 return this.index;
31 } 32 }
32 33
33 public String getName() { 34 public String getName() {
34 return this.name; 35 return this.name;
35 } 36 }
36 37
37 public void setName(String val) { 38 public void setName(String val) {
38 this.name = NameValidator.validateArgumentName(val); 39 this.name = NameValidator.validateArgumentName(val);
39 } 40 }
40 41
41 public ArgumentEntry getObfEntry(BehaviorEntry behaviorEntry) { 42 public ArgumentEntry getObfEntry(BehaviorEntry behaviorEntry) {
42 return new ArgumentEntry(behaviorEntry, index, name); 43 return new ArgumentEntry(behaviorEntry, index, name);
43 } 44 }
44 45
45 @Override 46 @Override
46 public int compareTo(ArgumentMapping other) { 47 public int compareTo(ArgumentMapping other) {
47 return Integer.compare(this.index, other.index); 48 return Integer.compare(this.index, other.index);
48 } 49 }
49} 50}
diff --git a/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java b/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
index f5c6c05..04b4ebc 100644
--- a/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/BehaviorEntry.java
@@ -8,8 +8,9 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13public interface BehaviorEntry extends Entry { 14public interface BehaviorEntry extends Entry {
14 Signature getSignature(); 15 Signature getSignature();
15} 16}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
index 398b135..788811f 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
@@ -16,151 +17,151 @@ import java.util.List;
16 17
17public class ClassEntry implements Entry { 18public class ClassEntry implements Entry {
18 19
19 private String name; 20 private String name;
20 21
21 public ClassEntry(String className) { 22 public ClassEntry(String className) {
22 if (className == null) { 23 if (className == null) {
23 throw new IllegalArgumentException("Class name cannot be null!"); 24 throw new IllegalArgumentException("Class name cannot be null!");
24 } 25 }
25 if (className.indexOf('.') >= 0) { 26 if (className.indexOf('.') >= 0) {
26 throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className); 27 throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className);
27 } 28 }
28 29
29 this.name = className; 30 this.name = className;
30 31
31 if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) { 32 if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) {
32 throw new IllegalArgumentException("Inner class must not have a package: " + className); 33 throw new IllegalArgumentException("Inner class must not have a package: " + className);
33 } 34 }
34 } 35 }
35 36
36 public ClassEntry(ClassEntry other) { 37 public ClassEntry(ClassEntry other) {
37 this.name = other.name; 38 this.name = other.name;
38 } 39 }
39 40
40 @Override 41 @Override
41 public String getName() { 42 public String getName() {
42 return this.name; 43 return this.name;
43 } 44 }
44 45
45 @Override 46 @Override
46 public String getClassName() { 47 public String getClassName() {
47 return this.name; 48 return this.name;
48 } 49 }
49 50
50 @Override 51 @Override
51 public ClassEntry getClassEntry() { 52 public ClassEntry getClassEntry() {
52 return this; 53 return this;
53 } 54 }
54 55
55 @Override 56 @Override
56 public ClassEntry cloneToNewClass(ClassEntry classEntry) { 57 public ClassEntry cloneToNewClass(ClassEntry classEntry) {
57 return classEntry; 58 return classEntry;
58 } 59 }
59 60
60 @Override 61 @Override
61 public int hashCode() { 62 public int hashCode() {
62 return this.name.hashCode(); 63 return this.name.hashCode();
63 } 64 }
64 65
65 @Override 66 @Override
66 public boolean equals(Object other) { 67 public boolean equals(Object other) {
67 return other instanceof ClassEntry && equals((ClassEntry) other); 68 return other instanceof ClassEntry && equals((ClassEntry) other);
68 } 69 }
69 70
70 public boolean equals(ClassEntry other) { 71 public boolean equals(ClassEntry other) {
71 return other != null && this.name.equals(other.name); 72 return other != null && this.name.equals(other.name);
72 } 73 }
73 74
74 @Override 75 @Override
75 public String toString() { 76 public String toString() {
76 return this.name; 77 return this.name;
77 } 78 }
78 79
79 public boolean isInnerClass() { 80 public boolean isInnerClass() {
80 return this.name.lastIndexOf('$') >= 0; 81 return this.name.lastIndexOf('$') >= 0;
81 } 82 }
82 83
83 public List<String> getClassChainNames() { 84 public List<String> getClassChainNames() {
84 return Lists.newArrayList(this.name.split("\\$")); 85 return Lists.newArrayList(this.name.split("\\$"));
85 } 86 }
86 87
87 public List<ClassEntry> getClassChain() { 88 public List<ClassEntry> getClassChain() {
88 List<ClassEntry> entries = Lists.newArrayList(); 89 List<ClassEntry> entries = Lists.newArrayList();
89 StringBuilder buf = new StringBuilder(); 90 StringBuilder buf = new StringBuilder();
90 for (String name : getClassChainNames()) { 91 for (String name : getClassChainNames()) {
91 if (buf.length() > 0) { 92 if (buf.length() > 0) {
92 buf.append("$"); 93 buf.append("$");
93 } 94 }
94 buf.append(name); 95 buf.append(name);
95 entries.add(new ClassEntry(buf.toString())); 96 entries.add(new ClassEntry(buf.toString()));
96 } 97 }
97 return entries; 98 return entries;
98 } 99 }
99 100
100 public String getOutermostClassName() { 101 public String getOutermostClassName() {
101 if (isInnerClass()) { 102 if (isInnerClass()) {
102 return this.name.substring(0, this.name.indexOf('$')); 103 return this.name.substring(0, this.name.indexOf('$'));
103 } 104 }
104 return this.name; 105 return this.name;
105 } 106 }
106 107
107 public ClassEntry getOutermostClassEntry() { 108 public ClassEntry getOutermostClassEntry() {
108 return new ClassEntry(getOutermostClassName()); 109 return new ClassEntry(getOutermostClassName());
109 } 110 }
110 111
111 public String getOuterClassName() { 112 public String getOuterClassName() {
112 if (!isInnerClass()) { 113 if (!isInnerClass()) {
113 throw new Error("This is not an inner class!"); 114 throw new Error("This is not an inner class!");
114 } 115 }
115 return this.name.substring(0, this.name.lastIndexOf('$')); 116 return this.name.substring(0, this.name.lastIndexOf('$'));
116 } 117 }
117 118
118 public ClassEntry getOuterClassEntry() { 119 public ClassEntry getOuterClassEntry() {
119 return new ClassEntry(getOuterClassName()); 120 return new ClassEntry(getOuterClassName());
120 } 121 }
121 122
122 public String getInnermostClassName() { 123 public String getInnermostClassName() {
123 if (!isInnerClass()) { 124 if (!isInnerClass()) {
124 throw new Error("This is not an inner class!"); 125 throw new Error("This is not an inner class!");
125 } 126 }
126 return this.name.substring(this.name.lastIndexOf('$') + 1); 127 return this.name.substring(this.name.lastIndexOf('$') + 1);
127 } 128 }
128 129
129 public boolean isInDefaultPackage() { 130 public boolean isInDefaultPackage() {
130 return this.name.indexOf('/') < 0; 131 return this.name.indexOf('/') < 0;
131 } 132 }
132 133
133 public String getPackageName() { 134 public String getPackageName() {
134 int pos = this.name.lastIndexOf('/'); 135 int pos = this.name.lastIndexOf('/');
135 if (pos > 0) { 136 if (pos > 0) {
136 return this.name.substring(0, pos); 137 return this.name.substring(0, pos);
137 } 138 }
138 return null; 139 return null;
139 } 140 }
140 141
141 public String getSimpleName() { 142 public String getSimpleName() {
142 int pos = this.name.lastIndexOf('/'); 143 int pos = this.name.lastIndexOf('/');
143 if (pos > 0) { 144 if (pos > 0) {
144 return this.name.substring(pos + 1); 145 return this.name.substring(pos + 1);
145 } 146 }
146 return this.name; 147 return this.name;
147 } 148 }
148 149
149 public ClassEntry buildClassEntry(List<ClassEntry> classChain) { 150 public ClassEntry buildClassEntry(List<ClassEntry> classChain) {
150 assert (classChain.contains(this)); 151 assert (classChain.contains(this));
151 StringBuilder buf = new StringBuilder(); 152 StringBuilder buf = new StringBuilder();
152 for (ClassEntry chainEntry : classChain) { 153 for (ClassEntry chainEntry : classChain) {
153 if (buf.length() == 0) { 154 if (buf.length() == 0) {
154 buf.append(chainEntry.getName()); 155 buf.append(chainEntry.getName());
155 } else { 156 } else {
156 buf.append("$"); 157 buf.append("$");
157 buf.append(chainEntry.isInnerClass() ? chainEntry.getInnermostClassName() : chainEntry.getSimpleName()); 158 buf.append(chainEntry.isInnerClass() ? chainEntry.getInnermostClassName() : chainEntry.getSimpleName());
158 } 159 }
159 160
160 if (chainEntry == this) { 161 if (chainEntry == this) {
161 break; 162 break;
162 } 163 }
163 } 164 }
164 return new ClassEntry(buf.toString()); 165 return new ClassEntry(buf.toString());
165 } 166 }
166} 167}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
index a261c91..178dd3c 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
@@ -8,540 +8,530 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Maps; 14import com.google.common.collect.Maps;
15import cuchaz.enigma.throwables.MappingConflict;
14 16
15import java.util.ArrayList; 17import java.util.ArrayList;
16import java.util.Map; 18import java.util.Map;
17 19
18import cuchaz.enigma.throwables.MappingConflict;
19
20// FIXME: Enigma doesn't support inner classes of inner class????! 20// FIXME: Enigma doesn't support inner classes of inner class????!
21public class ClassMapping implements Comparable<ClassMapping> { 21public class ClassMapping implements Comparable<ClassMapping> {
22 22
23 private String obfFullName; 23 private String obfFullName;
24 private String obfSimpleName; 24 private String obfSimpleName;
25 private String deobfName; 25 private String deobfName;
26 private String previousDeobfName; 26 private String previousDeobfName;
27 private Map<String, ClassMapping> innerClassesByObfSimple; 27 private Map<String, ClassMapping> innerClassesByObfSimple;
28 private Map<String, ClassMapping> innerClassesByObfFull; 28 private Map<String, ClassMapping> innerClassesByObfFull;
29 private Map<String, ClassMapping> innerClassesByDeobf; 29 private Map<String, ClassMapping> innerClassesByDeobf;
30 private Map<String, FieldMapping> fieldsByObf; 30 private Map<String, FieldMapping> fieldsByObf;
31 private Map<String, FieldMapping> fieldsByDeobf; 31 private Map<String, FieldMapping> fieldsByDeobf;
32 private Map<String, MethodMapping> methodsByObf; 32 private Map<String, MethodMapping> methodsByObf;
33 private Map<String, MethodMapping> methodsByDeobf; 33 private Map<String, MethodMapping> methodsByDeobf;
34 private boolean isDirty; 34 private boolean isDirty;
35 private Mappings.EntryModifier modifier; 35 private Mappings.EntryModifier modifier;
36 36
37 public ClassMapping(String obfFullName) 37 public ClassMapping(String obfFullName) {
38 { 38 this(obfFullName, null, Mappings.EntryModifier.UNCHANGED);
39 this(obfFullName, null, Mappings.EntryModifier.UNCHANGED); 39 }
40 } 40
41 41 public ClassMapping(String obfFullName, String deobfName) {
42 public ClassMapping(String obfFullName, String deobfName) 42 this(obfFullName, deobfName, Mappings.EntryModifier.UNCHANGED);
43 { 43 }
44 this(obfFullName, deobfName, Mappings.EntryModifier.UNCHANGED); 44
45 } 45 public ClassMapping(String obfFullName, String deobfName, Mappings.EntryModifier modifier) {
46 46 this.obfFullName = obfFullName;
47 public ClassMapping(String obfFullName, String deobfName, Mappings.EntryModifier modifier) 47 ClassEntry classEntry = new ClassEntry(obfFullName);
48 { 48 obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName();
49 this.obfFullName = obfFullName; 49 previousDeobfName = null;
50 ClassEntry classEntry = new ClassEntry(obfFullName); 50 this.deobfName = NameValidator.validateClassName(deobfName, false);
51 obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); 51 innerClassesByObfSimple = Maps.newHashMap();
52 previousDeobfName = null; 52 innerClassesByObfFull = Maps.newHashMap();
53 this.deobfName = NameValidator.validateClassName(deobfName, false); 53 innerClassesByDeobf = Maps.newHashMap();
54 innerClassesByObfSimple = Maps.newHashMap(); 54 fieldsByObf = Maps.newHashMap();
55 innerClassesByObfFull = Maps.newHashMap(); 55 fieldsByDeobf = Maps.newHashMap();
56 innerClassesByDeobf = Maps.newHashMap(); 56 methodsByObf = Maps.newHashMap();
57 fieldsByObf = Maps.newHashMap(); 57 methodsByDeobf = Maps.newHashMap();
58 fieldsByDeobf = Maps.newHashMap(); 58 isDirty = true;
59 methodsByObf = Maps.newHashMap(); 59 this.modifier = modifier;
60 methodsByDeobf = Maps.newHashMap(); 60 }
61 isDirty = true; 61
62 this.modifier = modifier; 62 public static boolean isSimpleClassName(String name) {
63 } 63 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
64 64 }
65 public String getObfFullName() { 65
66 return obfFullName; 66 public String getObfFullName() {
67 } 67 return obfFullName;
68 68 }
69 public String getObfSimpleName() { 69
70 return obfSimpleName; 70 public String getObfSimpleName() {
71 } 71 return obfSimpleName;
72 72 }
73 public String getPreviousDeobfName() { 73
74 return previousDeobfName; 74 public String getPreviousDeobfName() {
75 } 75 return previousDeobfName;
76 76 }
77 public String getDeobfName() { 77
78 return deobfName; 78 public String getDeobfName() {
79 } 79 return deobfName;
80 80 }
81 public void setDeobfName(String val) { 81
82 previousDeobfName = deobfName; 82 //// INNER CLASSES ////////
83 deobfName = NameValidator.validateClassName(val, false); 83
84 this.isDirty = true; 84 public void setDeobfName(String val) {
85 } 85 previousDeobfName = deobfName;
86 86 deobfName = NameValidator.validateClassName(val, false);
87 //// INNER CLASSES //////// 87 this.isDirty = true;
88 88 }
89 public Iterable<ClassMapping> innerClasses() { 89
90 assert (innerClassesByObfSimple.size() >= innerClassesByDeobf.size()); 90 public Iterable<ClassMapping> innerClasses() {
91 return innerClassesByObfSimple.values(); 91 assert (innerClassesByObfSimple.size() >= innerClassesByDeobf.size());
92 } 92 return innerClassesByObfSimple.values();
93 93 }
94 public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict { 94
95 // FIXME: dirty hack, that can get into issues, but it's a temp fix! 95 public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict {
96 if (this.innerClassesByObfFull.containsKey(classMapping.getObfSimpleName())) { 96 // FIXME: dirty hack, that can get into issues, but it's a temp fix!
97 throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName()); 97 if (this.innerClassesByObfFull.containsKey(classMapping.getObfSimpleName())) {
98 } 98 throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName());
99 innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); 99 }
100 innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping); 100 innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping);
101 101 innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping);
102 if (classMapping.getDeobfName() != null) { 102
103 if (this.innerClassesByDeobf.containsKey(classMapping.getDeobfName())) { 103 if (classMapping.getDeobfName() != null) {
104 throw new MappingConflict("classes", classMapping.getDeobfName(), this.innerClassesByDeobf.get(classMapping.getDeobfName()).getDeobfName()); 104 if (this.innerClassesByDeobf.containsKey(classMapping.getDeobfName())) {
105 } 105 throw new MappingConflict("classes", classMapping.getDeobfName(), this.innerClassesByDeobf.get(classMapping.getDeobfName()).getDeobfName());
106 innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping); 106 }
107 } 107 innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping);
108 this.isDirty = true; 108 }
109 } 109 this.isDirty = true;
110 110 }
111 public void removeInnerClassMapping(ClassMapping classMapping) { 111
112 innerClassesByObfFull.remove(classMapping.getObfFullName()); 112 public void removeInnerClassMapping(ClassMapping classMapping) {
113 boolean obfWasRemoved = innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null; 113 innerClassesByObfFull.remove(classMapping.getObfFullName());
114 assert (obfWasRemoved); 114 boolean obfWasRemoved = innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null;
115 if (classMapping.getDeobfName() != null) { 115 assert (obfWasRemoved);
116 boolean deobfWasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; 116 if (classMapping.getDeobfName() != null) {
117 assert (deobfWasRemoved); 117 boolean deobfWasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
118 } 118 assert (deobfWasRemoved);
119 this.isDirty = true; 119 }
120 } 120 this.isDirty = true;
121 121 }
122 public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) { 122
123 ClassMapping classMapping = innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName()); 123 public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) {
124 if (classMapping == null) { 124 ClassMapping classMapping = innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName());
125 classMapping = new ClassMapping(obfInnerClass.getName()); 125 if (classMapping == null) {
126 innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); 126 classMapping = new ClassMapping(obfInnerClass.getName());
127 boolean wasAdded = innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; 127 innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping);
128 assert (wasAdded); 128 boolean wasAdded = innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null;
129 this.isDirty = true; 129 assert (wasAdded);
130 } 130 this.isDirty = true;
131 return classMapping; 131 }
132 } 132 return classMapping;
133 133 }
134 public ClassMapping getInnerClassByObfSimple(String obfSimpleName) { 134
135 assert (isSimpleClassName(obfSimpleName)); 135 public ClassMapping getInnerClassByObfSimple(String obfSimpleName) {
136 return innerClassesByObfSimple.get(obfSimpleName); 136 assert (isSimpleClassName(obfSimpleName));
137 } 137 return innerClassesByObfSimple.get(obfSimpleName);
138 138 }
139 public ClassMapping getInnerClassByDeobf(String deobfName) { 139
140 assert (isSimpleClassName(deobfName)); 140 public ClassMapping getInnerClassByDeobf(String deobfName) {
141 return innerClassesByDeobf.get(deobfName); 141 assert (isSimpleClassName(deobfName));
142 } 142 return innerClassesByDeobf.get(deobfName);
143 143 }
144 public ClassMapping getInnerClassByDeobfThenObfSimple(String name) { 144
145 ClassMapping classMapping = getInnerClassByDeobf(name); 145 public ClassMapping getInnerClassByDeobfThenObfSimple(String name) {
146 if (classMapping == null) { 146 ClassMapping classMapping = getInnerClassByDeobf(name);
147 classMapping = getInnerClassByObfSimple(name); 147 if (classMapping == null) {
148 } 148 classMapping = getInnerClassByObfSimple(name);
149 return classMapping; 149 }
150 } 150 return classMapping;
151 151 }
152 public String getDeobfInnerClassName(String obfSimpleName) { 152
153 assert (isSimpleClassName(obfSimpleName)); 153 public String getDeobfInnerClassName(String obfSimpleName) {
154 ClassMapping classMapping = innerClassesByObfSimple.get(obfSimpleName); 154 assert (isSimpleClassName(obfSimpleName));
155 if (classMapping != null) { 155 ClassMapping classMapping = innerClassesByObfSimple.get(obfSimpleName);
156 return classMapping.getDeobfName(); 156 if (classMapping != null) {
157 } 157 return classMapping.getDeobfName();
158 return null; 158 }
159 } 159 return null;
160 160 }
161 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) { 161
162 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass); 162 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) {
163 if (classMapping.getDeobfName() != null) { 163 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass);
164 boolean wasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; 164 if (classMapping.getDeobfName() != null) {
165 assert (wasRemoved); 165 boolean wasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
166 } 166 assert (wasRemoved);
167 classMapping.setDeobfName(deobfName); 167 }
168 if (deobfName != null) { 168 classMapping.setDeobfName(deobfName);
169 assert (isSimpleClassName(deobfName)); 169 if (deobfName != null) {
170 boolean wasAdded = innerClassesByDeobf.put(deobfName, classMapping) == null; 170 assert (isSimpleClassName(deobfName));
171 assert (wasAdded); 171 boolean wasAdded = innerClassesByDeobf.put(deobfName, classMapping) == null;
172 } 172 assert (wasAdded);
173 this.isDirty = true; 173 }
174 } 174 this.isDirty = true;
175 175 }
176 public boolean hasInnerClassByObfSimple(String obfSimpleName) { 176
177 return innerClassesByObfSimple.containsKey(obfSimpleName); 177 public boolean hasInnerClassByObfSimple(String obfSimpleName) {
178 } 178 return innerClassesByObfSimple.containsKey(obfSimpleName);
179 179 }
180 public boolean hasInnerClassByDeobf(String deobfName) { 180
181 return innerClassesByDeobf.containsKey(deobfName); 181 //// FIELDS ////////
182 } 182
183 183 public boolean hasInnerClassByDeobf(String deobfName) {
184 184 return innerClassesByDeobf.containsKey(deobfName);
185 //// FIELDS //////// 185 }
186 186
187 public Iterable<FieldMapping> fields() { 187 public Iterable<FieldMapping> fields() {
188 assert (fieldsByObf.size() == fieldsByDeobf.size()); 188 assert (fieldsByObf.size() == fieldsByDeobf.size());
189 return fieldsByObf.values(); 189 return fieldsByObf.values();
190 } 190 }
191 191
192 public boolean containsObfField(String obfName, Type obfType) { 192 public boolean containsObfField(String obfName, Type obfType) {
193 return fieldsByObf.containsKey(getFieldKey(obfName, obfType)); 193 return fieldsByObf.containsKey(getFieldKey(obfName, obfType));
194 } 194 }
195 195
196 public boolean containsDeobfField(String deobfName, Type deobfType) { 196 public boolean containsDeobfField(String deobfName, Type deobfType) {
197 return fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType)); 197 return fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType));
198 } 198 }
199 199
200 public void addFieldMapping(FieldMapping fieldMapping) { 200 public void addFieldMapping(FieldMapping fieldMapping) {
201 String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); 201 String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
202 if (fieldsByObf.containsKey(obfKey)) { 202 if (fieldsByObf.containsKey(obfKey)) {
203 throw new Error("Already have mapping for " + obfFullName + "." + obfKey); 203 throw new Error("Already have mapping for " + obfFullName + "." + obfKey);
204 } 204 }
205 if (fieldMapping.getDeobfName() != null) { 205 if (fieldMapping.getDeobfName() != null) {
206 String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); 206 String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType());
207 if (fieldsByDeobf.containsKey(deobfKey)) { 207 if (fieldsByDeobf.containsKey(deobfKey)) {
208 throw new Error("Already have mapping for " + deobfName + "." + deobfKey); 208 throw new Error("Already have mapping for " + deobfName + "." + deobfKey);
209 } 209 }
210 boolean deobfWasAdded = fieldsByDeobf.put(deobfKey, fieldMapping) == null; 210 boolean deobfWasAdded = fieldsByDeobf.put(deobfKey, fieldMapping) == null;
211 assert (deobfWasAdded); 211 assert (deobfWasAdded);
212 } 212 }
213 boolean obfWasAdded = fieldsByObf.put(obfKey, fieldMapping) == null; 213 boolean obfWasAdded = fieldsByObf.put(obfKey, fieldMapping) == null;
214 assert (obfWasAdded); 214 assert (obfWasAdded);
215 this.isDirty = true; 215 this.isDirty = true;
216 } 216 }
217 217
218 public void removeFieldMapping(FieldMapping fieldMapping) { 218 public void removeFieldMapping(FieldMapping fieldMapping) {
219 boolean obfWasRemoved = fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType())) != null; 219 boolean obfWasRemoved = fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType())) != null;
220 assert (obfWasRemoved); 220 assert (obfWasRemoved);
221 if (fieldMapping.getDeobfName() != null) { 221 if (fieldMapping.getDeobfName() != null) {
222 boolean deobfWasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null; 222 boolean deobfWasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null;
223 assert (deobfWasRemoved); 223 assert (deobfWasRemoved);
224 } 224 }
225 this.isDirty = true; 225 this.isDirty = true;
226 } 226 }
227 227
228 public FieldMapping getFieldByObf(String obfName, Type obfType) { 228 public FieldMapping getFieldByObf(String obfName, Type obfType) {
229 return fieldsByObf.get(getFieldKey(obfName, obfType)); 229 return fieldsByObf.get(getFieldKey(obfName, obfType));
230 } 230 }
231 231
232 public FieldMapping getFieldByDeobf(String deobfName, Type obfType) { 232 public FieldMapping getFieldByDeobf(String deobfName, Type obfType) {
233 return fieldsByDeobf.get(getFieldKey(deobfName, obfType)); 233 return fieldsByDeobf.get(getFieldKey(deobfName, obfType));
234 } 234 }
235 235
236 public String getObfFieldName(String deobfName, Type obfType) { 236 public String getObfFieldName(String deobfName, Type obfType) {
237 FieldMapping fieldMapping = fieldsByDeobf.get(getFieldKey(deobfName, obfType)); 237 FieldMapping fieldMapping = fieldsByDeobf.get(getFieldKey(deobfName, obfType));
238 if (fieldMapping != null) { 238 if (fieldMapping != null) {
239 return fieldMapping.getObfName(); 239 return fieldMapping.getObfName();
240 } 240 }
241 return null; 241 return null;
242 } 242 }
243 243
244 public String getDeobfFieldName(String obfName, Type obfType) { 244 public String getDeobfFieldName(String obfName, Type obfType) {
245 FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType)); 245 FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType));
246 if (fieldMapping != null) { 246 if (fieldMapping != null) {
247 return fieldMapping.getDeobfName(); 247 return fieldMapping.getDeobfName();
248 } 248 }
249 return null; 249 return null;
250 } 250 }
251 251
252 private String getFieldKey(String name, Type type) { 252 private String getFieldKey(String name, Type type) {
253 if (name == null) { 253 if (name == null) {
254 throw new IllegalArgumentException("name cannot be null!"); 254 throw new IllegalArgumentException("name cannot be null!");
255 } 255 }
256 if (type == null) { 256 if (type == null) {
257 throw new IllegalArgumentException("type cannot be null!"); 257 throw new IllegalArgumentException("type cannot be null!");
258 } 258 }
259 return name + ":" + type; 259 return name + ":" + type;
260 } 260 }
261 261
262 public void setFieldName(String obfName, Type obfType, String deobfName) { 262 public void setFieldName(String obfName, Type obfType, String deobfName) {
263 assert (deobfName != null); 263 assert (deobfName != null);
264 FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType)); 264 FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfType));
265 if (fieldMapping == null) { 265 if (fieldMapping == null) {
266 fieldMapping = new FieldMapping(obfName, obfType, deobfName, Mappings.EntryModifier.UNCHANGED); 266 fieldMapping = new FieldMapping(obfName, obfType, deobfName, Mappings.EntryModifier.UNCHANGED);
267 boolean obfWasAdded = fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null; 267 boolean obfWasAdded = fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null;
268 assert (obfWasAdded); 268 assert (obfWasAdded);
269 } else { 269 } else {
270 boolean wasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfType)) != null; 270 boolean wasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfType)) != null;
271 assert (wasRemoved); 271 assert (wasRemoved);
272 } 272 }
273 fieldMapping.setDeobfName(deobfName); 273 fieldMapping.setDeobfName(deobfName);
274 if (deobfName != null) { 274 if (deobfName != null) {
275 boolean wasAdded = fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null; 275 boolean wasAdded = fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null;
276 assert (wasAdded); 276 assert (wasAdded);
277 } 277 }
278 this.isDirty = true; 278 this.isDirty = true;
279 } 279 }
280 280
281 public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) { 281 //// METHODS ////////
282 assert(newObfName != null); 282
283 FieldMapping fieldMapping = fieldsByObf.remove(getFieldKey(oldObfName, obfType)); 283 public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) {
284 assert(fieldMapping != null); 284 assert (newObfName != null);
285 fieldMapping.setObfName(newObfName); 285 FieldMapping fieldMapping = fieldsByObf.remove(getFieldKey(oldObfName, obfType));
286 fieldMapping.setObfType(newObfType); 286 assert (fieldMapping != null);
287 boolean obfWasAdded = fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null; 287 fieldMapping.setObfName(newObfName);
288 assert(obfWasAdded); 288 fieldMapping.setObfType(newObfType);
289 this.isDirty = true; 289 boolean obfWasAdded = fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null;
290 } 290 assert (obfWasAdded);
291 291 this.isDirty = true;
292 //// METHODS //////// 292 }
293 293
294 public Iterable<MethodMapping> methods() { 294 public Iterable<MethodMapping> methods() {
295 assert (methodsByObf.size() >= methodsByDeobf.size()); 295 assert (methodsByObf.size() >= methodsByDeobf.size());
296 return methodsByObf.values(); 296 return methodsByObf.values();
297 } 297 }
298 298
299 public boolean containsObfMethod(String obfName, Signature obfSignature) { 299 public boolean containsObfMethod(String obfName, Signature obfSignature) {
300 return methodsByObf.containsKey(getMethodKey(obfName, obfSignature)); 300 return methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
301 } 301 }
302 302
303 public boolean containsDeobfMethod(String deobfName, Signature obfSignature) { 303 public boolean containsDeobfMethod(String deobfName, Signature obfSignature) {
304 return methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature)); 304 return methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature));
305 } 305 }
306 306
307 public void addMethodMapping(MethodMapping methodMapping) { 307 public void addMethodMapping(MethodMapping methodMapping) {
308 String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); 308 String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
309 if (methodsByObf.containsKey(obfKey)) { 309 if (methodsByObf.containsKey(obfKey)) {
310 throw new Error("Already have mapping for " + obfFullName + "." + obfKey); 310 throw new Error("Already have mapping for " + obfFullName + "." + obfKey);
311 } 311 }
312 boolean wasAdded = methodsByObf.put(obfKey, methodMapping) == null; 312 boolean wasAdded = methodsByObf.put(obfKey, methodMapping) == null;
313 assert (wasAdded); 313 assert (wasAdded);
314 if (methodMapping.getDeobfName() != null) { 314 if (methodMapping.getDeobfName() != null) {
315 String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature()); 315 String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature());
316 if (methodsByDeobf.containsKey(deobfKey)) { 316 if (methodsByDeobf.containsKey(deobfKey)) {
317 throw new Error("Already have mapping for " + deobfName + "." + deobfKey); 317 throw new Error("Already have mapping for " + deobfName + "." + deobfKey);
318 } 318 }
319 boolean deobfWasAdded = methodsByDeobf.put(deobfKey, methodMapping) == null; 319 boolean deobfWasAdded = methodsByDeobf.put(deobfKey, methodMapping) == null;
320 assert (deobfWasAdded); 320 assert (deobfWasAdded);
321 } 321 }
322 this.isDirty = true; 322 this.isDirty = true;
323 assert (methodsByObf.size() >= methodsByDeobf.size()); 323 assert (methodsByObf.size() >= methodsByDeobf.size());
324 } 324 }
325 325
326 public void removeMethodMapping(MethodMapping methodMapping) { 326 public void removeMethodMapping(MethodMapping methodMapping) {
327 boolean obfWasRemoved = methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null; 327 boolean obfWasRemoved = methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null;
328 assert (obfWasRemoved); 328 assert (obfWasRemoved);
329 if (methodMapping.getDeobfName() != null) { 329 if (methodMapping.getDeobfName() != null) {
330 boolean deobfWasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; 330 boolean deobfWasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
331 assert (deobfWasRemoved); 331 assert (deobfWasRemoved);
332 } 332 }
333 this.isDirty = true; 333 this.isDirty = true;
334 } 334 }
335 335
336 public MethodMapping getMethodByObf(String obfName, Signature obfSignature) { 336 public MethodMapping getMethodByObf(String obfName, Signature obfSignature) {
337 return methodsByObf.get(getMethodKey(obfName, obfSignature)); 337 return methodsByObf.get(getMethodKey(obfName, obfSignature));
338 } 338 }
339 339
340 public MethodMapping getMethodByDeobf(String deobfName, Signature obfSignature) { 340 public MethodMapping getMethodByDeobf(String deobfName, Signature obfSignature) {
341 return methodsByDeobf.get(getMethodKey(deobfName, obfSignature)); 341 return methodsByDeobf.get(getMethodKey(deobfName, obfSignature));
342 } 342 }
343 343
344 private String getMethodKey(String name, Signature signature) { 344 private String getMethodKey(String name, Signature signature) {
345 if (name == null) { 345 if (name == null) {
346 throw new IllegalArgumentException("name cannot be null!"); 346 throw new IllegalArgumentException("name cannot be null!");
347 } 347 }
348 if (signature == null) { 348 if (signature == null) {
349 throw new IllegalArgumentException("signature cannot be null!"); 349 throw new IllegalArgumentException("signature cannot be null!");
350 } 350 }
351 return name + signature; 351 return name + signature;
352 } 352 }
353 353
354 public void setMethodName(String obfName, Signature obfSignature, String deobfName) { 354 public void setMethodName(String obfName, Signature obfSignature, String deobfName) {
355 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfName, obfSignature)); 355 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfName, obfSignature));
356 if (methodMapping == null) { 356 if (methodMapping == null) {
357 methodMapping = createMethodMapping(obfName, obfSignature); 357 methodMapping = createMethodMapping(obfName, obfSignature);
358 } else if (methodMapping.getDeobfName() != null) { 358 } else if (methodMapping.getDeobfName() != null) {
359 boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; 359 boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
360 assert (wasRemoved); 360 assert (wasRemoved);
361 } 361 }
362 methodMapping.setDeobfName(deobfName); 362 methodMapping.setDeobfName(deobfName);
363 if (deobfName != null) { 363 if (deobfName != null) {
364 boolean wasAdded = methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; 364 boolean wasAdded = methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null;
365 assert (wasAdded); 365 assert (wasAdded);
366 } 366 }
367 this.isDirty = true; 367 this.isDirty = true;
368 } 368 }
369 369
370 public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) { 370 //// ARGUMENTS ////////
371 assert(newObfName != null); 371
372 MethodMapping methodMapping = methodsByObf.remove(getMethodKey(oldObfName, obfSignature)); 372 public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) {
373 assert(methodMapping != null); 373 assert (newObfName != null);
374 methodMapping.setObfName(newObfName); 374 MethodMapping methodMapping = methodsByObf.remove(getMethodKey(oldObfName, obfSignature));
375 methodMapping.setObfSignature(newObfSignature); 375 assert (methodMapping != null);
376 boolean obfWasAdded = methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null; 376 methodMapping.setObfName(newObfName);
377 assert(obfWasAdded); 377 methodMapping.setObfSignature(newObfSignature);
378 this.isDirty = true; 378 boolean obfWasAdded = methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null;
379 } 379 assert (obfWasAdded);
380 380 this.isDirty = true;
381 //// ARGUMENTS //////// 381 }
382 382
383 public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) { 383 public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) {
384 assert (argumentName != null); 384 assert (argumentName != null);
385 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)); 385 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature));
386 if (methodMapping == null) { 386 if (methodMapping == null) {
387 methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); 387 methodMapping = createMethodMapping(obfMethodName, obfMethodSignature);
388 } 388 }
389 methodMapping.setArgumentName(argumentIndex, argumentName); 389 methodMapping.setArgumentName(argumentIndex, argumentName);
390 this.isDirty = true; 390 this.isDirty = true;
391 } 391 }
392 392
393 public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) { 393 public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) {
394 methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); 394 methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex);
395 this.isDirty = true; 395 this.isDirty = true;
396 } 396 }
397 397
398 private MethodMapping createMethodMapping(String obfName, Signature obfSignature) { 398 private MethodMapping createMethodMapping(String obfName, Signature obfSignature) {
399 MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); 399 MethodMapping methodMapping = new MethodMapping(obfName, obfSignature);
400 boolean wasAdded = methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; 400 boolean wasAdded = methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null;
401 assert (wasAdded); 401 assert (wasAdded);
402 this.isDirty = true; 402 this.isDirty = true;
403 return methodMapping; 403 return methodMapping;
404 } 404 }
405 405
406 @Override 406 @Override
407 public String toString() { 407 public String toString() {
408 StringBuilder buf = new StringBuilder(); 408 StringBuilder buf = new StringBuilder();
409 buf.append(obfFullName); 409 buf.append(obfFullName);
410 buf.append(" <-> "); 410 buf.append(" <-> ");
411 buf.append(deobfName); 411 buf.append(deobfName);
412 buf.append("\n"); 412 buf.append("\n");
413 buf.append("Fields:\n"); 413 buf.append("Fields:\n");
414 for (FieldMapping fieldMapping : fields()) { 414 for (FieldMapping fieldMapping : fields()) {
415 buf.append("\t"); 415 buf.append("\t");
416 buf.append(fieldMapping.getObfName()); 416 buf.append(fieldMapping.getObfName());
417 buf.append(" <-> "); 417 buf.append(" <-> ");
418 buf.append(fieldMapping.getDeobfName()); 418 buf.append(fieldMapping.getDeobfName());
419 buf.append("\n"); 419 buf.append("\n");
420 } 420 }
421 buf.append("Methods:\n"); 421 buf.append("Methods:\n");
422 for (MethodMapping methodMapping : methodsByObf.values()) { 422 for (MethodMapping methodMapping : methodsByObf.values()) {
423 buf.append(methodMapping.toString()); 423 buf.append(methodMapping);
424 buf.append("\n"); 424 buf.append("\n");
425 } 425 }
426 buf.append("Inner Classes:\n"); 426 buf.append("Inner Classes:\n");
427 for (ClassMapping classMapping : innerClassesByObfSimple.values()) { 427 for (ClassMapping classMapping : innerClassesByObfSimple.values()) {
428 buf.append("\t"); 428 buf.append("\t");
429 buf.append(classMapping.getObfSimpleName()); 429 buf.append(classMapping.getObfSimpleName());
430 buf.append(" <-> "); 430 buf.append(" <-> ");
431 buf.append(classMapping.getDeobfName()); 431 buf.append(classMapping.getDeobfName());
432 buf.append("\n"); 432 buf.append("\n");
433 } 433 }
434 return buf.toString(); 434 return buf.toString();
435 } 435 }
436 436
437 @Override 437 @Override
438 public int compareTo(ClassMapping other) { 438 public int compareTo(ClassMapping other) {
439 // sort by a, b, c, ... aa, ab, etc 439 // sort by a, b, c, ... aa, ab, etc
440 if (obfFullName.length() != other.obfFullName.length()) { 440 if (obfFullName.length() != other.obfFullName.length()) {
441 return obfFullName.length() - other.obfFullName.length(); 441 return obfFullName.length() - other.obfFullName.length();
442 } 442 }
443 return obfFullName.compareTo(other.obfFullName); 443 return obfFullName.compareTo(other.obfFullName);
444 } 444 }
445 445
446 public boolean renameObfClass(String oldObfClassName, String newObfClassName) { 446 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
447 447
448 // rename inner classes 448 // rename inner classes
449 for (ClassMapping innerClassMapping : new ArrayList<>(innerClassesByObfSimple.values())) { 449 for (ClassMapping innerClassMapping : new ArrayList<>(innerClassesByObfSimple.values())) {
450 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { 450 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
451 boolean wasRemoved = innerClassesByObfSimple.remove(oldObfClassName) != null; 451 boolean wasRemoved = innerClassesByObfSimple.remove(oldObfClassName) != null;
452 assert (wasRemoved); 452 assert (wasRemoved);
453 boolean wasAdded = innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null; 453 boolean wasAdded = innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null;
454 assert (wasAdded); 454 assert (wasAdded);
455 } 455 }
456 } 456 }
457 457
458 // rename field types 458 // rename field types
459 for (FieldMapping fieldMapping : new ArrayList<>(fieldsByObf.values())) { 459 for (FieldMapping fieldMapping : new ArrayList<>(fieldsByObf.values())) {
460 String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); 460 String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
461 if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) { 461 if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) {
462 boolean wasRemoved = fieldsByObf.remove(oldFieldKey) != null; 462 boolean wasRemoved = fieldsByObf.remove(oldFieldKey) != null;
463 assert (wasRemoved); 463 assert (wasRemoved);
464 boolean wasAdded = fieldsByObf 464 boolean wasAdded = fieldsByObf
465 .put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null; 465 .put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null;
466 assert (wasAdded); 466 assert (wasAdded);
467 } 467 }
468 } 468 }
469 469
470 // rename method signatures 470 // rename method signatures
471 for (MethodMapping methodMapping : new ArrayList<>(methodsByObf.values())) { 471 for (MethodMapping methodMapping : new ArrayList<>(methodsByObf.values())) {
472 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); 472 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
473 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { 473 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
474 boolean wasRemoved = methodsByObf.remove(oldMethodKey) != null; 474 boolean wasRemoved = methodsByObf.remove(oldMethodKey) != null;
475 assert (wasRemoved); 475 assert (wasRemoved);
476 boolean wasAdded = methodsByObf 476 boolean wasAdded = methodsByObf
477 .put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null; 477 .put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
478 assert (wasAdded); 478 assert (wasAdded);
479 } 479 }
480 } 480 }
481 481
482 if (obfFullName.equals(oldObfClassName)) { 482 if (obfFullName.equals(oldObfClassName)) {
483 // rename this class 483 // rename this class
484 obfFullName = newObfClassName; 484 obfFullName = newObfClassName;
485 return true; 485 return true;
486 } 486 }
487 this.isDirty = true; 487 this.isDirty = true;
488 return false; 488 return false;
489 } 489 }
490 490
491 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { 491 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
492 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); 492 MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
493 return methodMapping != null && methodMapping.containsArgument(name); 493 return methodMapping != null && methodMapping.containsArgument(name);
494 } 494 }
495 495
496 public static boolean isSimpleClassName(String name) { 496 public ClassEntry getObfEntry() {
497 return name.indexOf('/') < 0 && name.indexOf('$') < 0; 497 return new ClassEntry(obfFullName);
498 } 498 }
499 499
500 public ClassEntry getObfEntry() { 500 public boolean isDirty() {
501 return new ClassEntry(obfFullName); 501 return isDirty;
502 } 502 }
503 503
504 public boolean isDirty() 504 public void resetDirty() {
505 { 505 this.isDirty = false;
506 return isDirty; 506 }
507 } 507
508 508 public Mappings.EntryModifier getModifier() {
509 public void resetDirty() 509 return modifier;
510 { 510 }
511 this.isDirty = false; 511
512 } 512 public void setModifier(Mappings.EntryModifier modifier) {
513 513 if (this.modifier != modifier)
514 public void setModifier(Mappings.EntryModifier modifier) 514 this.isDirty = true;
515 { 515 this.modifier = modifier;
516 if (this.modifier != modifier) 516 }
517 this.isDirty = true; 517
518 this.modifier = modifier; 518 public void setFieldModifier(String obfName, Type obfType, Mappings.EntryModifier modifier) {
519 } 519 FieldMapping fieldMapping = fieldsByObf.computeIfAbsent(getFieldKey(obfName, obfType),
520 520 k -> new FieldMapping(obfName, obfType, null, Mappings.EntryModifier.UNCHANGED));
521 public Mappings.EntryModifier getModifier() 521
522 { 522 if (fieldMapping.getModifier() != modifier) {
523 return modifier; 523 fieldMapping.setModifier(modifier);
524 } 524 this.isDirty = true;
525 525 }
526 public void setFieldModifier(String obfName, Type obfType, Mappings.EntryModifier modifier) { 526 }
527 FieldMapping fieldMapping = fieldsByObf.computeIfAbsent(getFieldKey(obfName, obfType), 527
528 k -> new FieldMapping(obfName, obfType, null, Mappings.EntryModifier.UNCHANGED)); 528 public void setMethodModifier(String obfName, Signature sig, Mappings.EntryModifier modifier) {
529 529 MethodMapping methodMapping = methodsByObf.computeIfAbsent(getMethodKey(obfName, sig),
530 if (fieldMapping.getModifier() != modifier) 530 k -> new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED));
531 { 531
532 fieldMapping.setModifier(modifier); 532 if (methodMapping.getModifier() != modifier) {
533 this.isDirty = true; 533 methodMapping.setModifier(modifier);
534 } 534 this.isDirty = true;
535 } 535 }
536 536 }
537 public void setMethodModifier(String obfName, Signature sig, Mappings.EntryModifier modifier) {
538 MethodMapping methodMapping = methodsByObf.computeIfAbsent(getMethodKey(obfName, sig),
539 k -> new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED));
540
541 if (methodMapping.getModifier() != modifier)
542 {
543 methodMapping.setModifier(modifier);
544 this.isDirty = true;
545 }
546 }
547} 537}
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java b/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
index dc833bb..801c410 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassNameReplacer.java
@@ -8,8 +8,9 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13public interface ClassNameReplacer { 14public interface ClassNameReplacer {
14 String replace(String className); 15 String replace(String className);
15} 16}
diff --git a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java b/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
index 4c79820..20e5113 100644
--- a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java
@@ -8,97 +8,98 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.utils.Utils; 14import cuchaz.enigma.utils.Utils;
14 15
15public class ConstructorEntry implements BehaviorEntry { 16public class ConstructorEntry implements BehaviorEntry {
16 17
17 private ClassEntry classEntry; 18 private ClassEntry classEntry;
18 private Signature signature; 19 private Signature signature;
19 20
20 public ConstructorEntry(ClassEntry classEntry) { 21 public ConstructorEntry(ClassEntry classEntry) {
21 this(classEntry, null); 22 this(classEntry, null);
22 } 23 }
23 24
24 public ConstructorEntry(ClassEntry classEntry, Signature signature) { 25 public ConstructorEntry(ClassEntry classEntry, Signature signature) {
25 if (classEntry == null) { 26 if (classEntry == null) {
26 throw new IllegalArgumentException("Class cannot be null!"); 27 throw new IllegalArgumentException("Class cannot be null!");
27 } 28 }
28 29
29 this.classEntry = classEntry; 30 this.classEntry = classEntry;
30 this.signature = signature; 31 this.signature = signature;
31 } 32 }
32 33
33 public ConstructorEntry(ConstructorEntry other, String newClassName) { 34 public ConstructorEntry(ConstructorEntry other, String newClassName) {
34 this.classEntry = new ClassEntry(newClassName); 35 this.classEntry = new ClassEntry(newClassName);
35 this.signature = other.signature; 36 this.signature = other.signature;
36 } 37 }
37 38
38 @Override 39 @Override
39 public ClassEntry getClassEntry() { 40 public ClassEntry getClassEntry() {
40 return this.classEntry; 41 return this.classEntry;
41 } 42 }
42 43
43 @Override 44 @Override
44 public String getName() { 45 public String getName() {
45 if (isStatic()) { 46 if (isStatic()) {
46 return "<clinit>"; 47 return "<clinit>";
47 } 48 }
48 return "<init>"; 49 return "<init>";
49 } 50 }
50 51
51 public boolean isStatic() { 52 public boolean isStatic() {
52 return this.signature == null; 53 return this.signature == null;
53 } 54 }
54 55
55 @Override 56 @Override
56 public Signature getSignature() { 57 public Signature getSignature() {
57 return this.signature; 58 return this.signature;
58 } 59 }
59 60
60 @Override 61 @Override
61 public String getClassName() { 62 public String getClassName() {
62 return this.classEntry.getName(); 63 return this.classEntry.getName();
63 } 64 }
64 65
65 @Override 66 @Override
66 public ConstructorEntry cloneToNewClass(ClassEntry classEntry) { 67 public ConstructorEntry cloneToNewClass(ClassEntry classEntry) {
67 return new ConstructorEntry(this, classEntry.getName()); 68 return new ConstructorEntry(this, classEntry.getName());
68 } 69 }
69 70
70 @Override 71 @Override
71 public int hashCode() { 72 public int hashCode() {
72 if (isStatic()) { 73 if (isStatic()) {
73 return Utils.combineHashesOrdered(this.classEntry); 74 return Utils.combineHashesOrdered(this.classEntry);
74 } else { 75 } else {
75 return Utils.combineHashesOrdered(this.classEntry, this.signature); 76 return Utils.combineHashesOrdered(this.classEntry, this.signature);
76 } 77 }
77 } 78 }
78 79
79 @Override 80 @Override
80 public boolean equals(Object other) { 81 public boolean equals(Object other) {
81 return other instanceof ConstructorEntry && equals((ConstructorEntry) other); 82 return other instanceof ConstructorEntry && equals((ConstructorEntry) other);
82 } 83 }
83 84
84 public boolean equals(ConstructorEntry other) { 85 public boolean equals(ConstructorEntry other) {
85 if (isStatic() != other.isStatic()) { 86 if (isStatic() != other.isStatic()) {
86 return false; 87 return false;
87 } 88 }
88 89
89 if (isStatic()) { 90 if (isStatic()) {
90 return this.classEntry.equals(other.classEntry); 91 return this.classEntry.equals(other.classEntry);
91 } else { 92 } else {
92 return this.classEntry.equals(other.classEntry) && this.signature.equals(other.signature); 93 return this.classEntry.equals(other.classEntry) && this.signature.equals(other.signature);
93 } 94 }
94 } 95 }
95 96
96 @Override 97 @Override
97 public String toString() { 98 public String toString() {
98 if (isStatic()) { 99 if (isStatic()) {
99 return this.classEntry.getName() + "." + getName(); 100 return this.classEntry.getName() + "." + getName();
100 } else { 101 } else {
101 return this.classEntry.getName() + "." + getName() + this.signature; 102 return this.classEntry.getName() + "." + getName() + this.signature;
102 } 103 }
103 } 104 }
104} 105}
diff --git a/src/main/java/cuchaz/enigma/mapping/Entry.java b/src/main/java/cuchaz/enigma/mapping/Entry.java
index 95747d5..c79510b 100644
--- a/src/main/java/cuchaz/enigma/mapping/Entry.java
+++ b/src/main/java/cuchaz/enigma/mapping/Entry.java
@@ -8,14 +8,15 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13public interface Entry { 14public interface Entry {
14 String getName(); 15 String getName();
15 16
16 String getClassName(); 17 String getClassName();
17 18
18 ClassEntry getClassEntry(); 19 ClassEntry getClassEntry();
19 20
20 Entry cloneToNewClass(ClassEntry classEntry); 21 Entry cloneToNewClass(ClassEntry classEntry);
21} 22}
diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
index ce4b948..993bb64 100644
--- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
+++ b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.analysis.JarIndex; 14import cuchaz.enigma.analysis.JarIndex;
@@ -20,112 +21,112 @@ import javassist.expr.NewExpr;
20 21
21public class EntryFactory { 22public class EntryFactory {
22 23
23 public static ClassEntry getClassEntry(CtClass c) { 24 public static ClassEntry getClassEntry(CtClass c) {
24 return new ClassEntry(Descriptor.toJvmName(c.getName())); 25 return new ClassEntry(Descriptor.toJvmName(c.getName()));
25 } 26 }
26 27
27 public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) { 28 public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) {
28 ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfFullName()); 29 ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfFullName());
29 return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry)); 30 return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry));
30 } 31 }
31 32
32 private static ClassEntry getObfClassEntry(ClassMapping classMapping) { 33 private static ClassEntry getObfClassEntry(ClassMapping classMapping) {
33 return new ClassEntry(classMapping.getObfFullName()); 34 return new ClassEntry(classMapping.getObfFullName());
34 } 35 }
35 36
36 public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { 37 public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) {
37 return new ClassEntry(classMapping.getDeobfName()); 38 return new ClassEntry(classMapping.getDeobfName());
38 } 39 }
39 40
40 public static ClassEntry getSuperclassEntry(CtClass c) { 41 public static ClassEntry getSuperclassEntry(CtClass c) {
41 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); 42 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
42 } 43 }
43 44
44 public static FieldEntry getFieldEntry(CtField field) { 45 public static FieldEntry getFieldEntry(CtField field) {
45 return new FieldEntry(getClassEntry(field.getDeclaringClass()), field.getName(), new Type(field.getFieldInfo().getDescriptor())); 46 return new FieldEntry(getClassEntry(field.getDeclaringClass()), field.getName(), new Type(field.getFieldInfo().getDescriptor()));
46 } 47 }
47 48
48 public static FieldEntry getFieldEntry(FieldAccess call) { 49 public static FieldEntry getFieldEntry(FieldAccess call) {
49 return new FieldEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getFieldName(), new Type(call.getSignature())); 50 return new FieldEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getFieldName(), new Type(call.getSignature()));
50 } 51 }
51 52
52 public static FieldEntry getFieldEntry(String className, String name, String type) { 53 public static FieldEntry getFieldEntry(String className, String name, String type) {
53 return new FieldEntry(new ClassEntry(className), name, new Type(type)); 54 return new FieldEntry(new ClassEntry(className), name, new Type(type));
54 } 55 }
55 56
56 public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) { 57 public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) {
57 return new FieldEntry(getObfClassEntry(classMapping), fieldMapping.getObfName(), fieldMapping.getObfType()); 58 return new FieldEntry(getObfClassEntry(classMapping), fieldMapping.getObfName(), fieldMapping.getObfType());
58 } 59 }
59 60
60 public static MethodEntry getMethodEntry(CtMethod method) { 61 public static MethodEntry getMethodEntry(CtMethod method) {
61 return new MethodEntry(getClassEntry(method.getDeclaringClass()), method.getName(), new Signature(method.getMethodInfo().getDescriptor())); 62 return new MethodEntry(getClassEntry(method.getDeclaringClass()), method.getName(), new Signature(method.getMethodInfo().getDescriptor()));
62 } 63 }
63 64
64 public static MethodEntry getMethodEntry(MethodCall call) { 65 public static MethodEntry getMethodEntry(MethodCall call) {
65 return new MethodEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getMethodName(), new Signature(call.getSignature())); 66 return new MethodEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), call.getMethodName(), new Signature(call.getSignature()));
66 } 67 }
67 68
68 public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { 69 public static ConstructorEntry getConstructorEntry(CtConstructor constructor) {
69 if (constructor.isClassInitializer()) { 70 if (constructor.isClassInitializer()) {
70 return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass())); 71 return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass()));
71 } else { 72 } else {
72 return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass()), new Signature(constructor.getMethodInfo().getDescriptor())); 73 return new ConstructorEntry(getClassEntry(constructor.getDeclaringClass()), new Signature(constructor.getMethodInfo().getDescriptor()));
73 } 74 }
74 } 75 }
75 76
76 public static ConstructorEntry getConstructorEntry(ConstructorCall call) { 77 public static ConstructorEntry getConstructorEntry(ConstructorCall call) {
77 return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature())); 78 return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature()));
78 } 79 }
79 80
80 public static ConstructorEntry getConstructorEntry(NewExpr call) { 81 public static ConstructorEntry getConstructorEntry(NewExpr call) {
81 return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature())); 82 return new ConstructorEntry(new ClassEntry(Descriptor.toJvmName(call.getClassName())), new Signature(call.getSignature()));
82 } 83 }
83 84
84 public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { 85 public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) {
85 if (behavior instanceof CtMethod) { 86 if (behavior instanceof CtMethod) {
86 return getMethodEntry((CtMethod) behavior); 87 return getMethodEntry((CtMethod) behavior);
87 } else if (behavior instanceof CtConstructor) { 88 } else if (behavior instanceof CtConstructor) {
88 return getConstructorEntry((CtConstructor) behavior); 89 return getConstructorEntry((CtConstructor) behavior);
89 } 90 }
90 throw new Error("behavior is neither Method nor Constructor!"); 91 throw new Error("behavior is neither Method nor Constructor!");
91 } 92 }
92 93
93 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) { 94 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) {
94 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature)); 95 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature));
95 } 96 }
96 97
97 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) { 98 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) {
98 return getBehaviorEntry(new ClassEntry(className), behaviorName); 99 return getBehaviorEntry(new ClassEntry(className), behaviorName);
99 } 100 }
100 101
101 public static BehaviorEntry getBehaviorEntry(String className) { 102 public static BehaviorEntry getBehaviorEntry(String className) {
102 return new ConstructorEntry(new ClassEntry(className)); 103 return new ConstructorEntry(new ClassEntry(className));
103 } 104 }
104 105
105 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) { 106 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) {
106 switch (behaviorName) { 107 switch (behaviorName) {
107 case "<init>": 108 case "<init>":
108 return new ConstructorEntry(classEntry, behaviorSignature); 109 return new ConstructorEntry(classEntry, behaviorSignature);
109 case "<clinit>": 110 case "<clinit>":
110 return new ConstructorEntry(classEntry); 111 return new ConstructorEntry(classEntry);
111 default: 112 default:
112 return new MethodEntry(classEntry, behaviorName, behaviorSignature); 113 return new MethodEntry(classEntry, behaviorName, behaviorSignature);
113 } 114 }
114 } 115 }
115 116
116 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) { 117 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) {
117 if(behaviorName.equals("<clinit>")) { 118 if (behaviorName.equals("<clinit>")) {
118 return new ConstructorEntry(classEntry); 119 return new ConstructorEntry(classEntry);
119 } else { 120 } else {
120 throw new IllegalArgumentException("Only class initializers don't have signatures"); 121 throw new IllegalArgumentException("Only class initializers don't have signatures");
121 } 122 }
122 } 123 }
123 124
124 public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { 125 public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) {
125 return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); 126 return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
126 } 127 }
127 128
128 public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) { 129 public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) {
129 return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping); 130 return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping);
130 } 131 }
131} 132}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
index 9980e8e..0f1f506 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java
@@ -8,79 +8,80 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.utils.Utils; 14import cuchaz.enigma.utils.Utils;
14 15
15public class FieldEntry implements Entry { 16public class FieldEntry implements Entry {
16 17
17 private ClassEntry classEntry; 18 private ClassEntry classEntry;
18 private String name; 19 private String name;
19 private Type type; 20 private Type type;
20 21
21 // NOTE: this argument order is important for the MethodReader/MethodWriter 22 // NOTE: this argument order is important for the MethodReader/MethodWriter
22 public FieldEntry(ClassEntry classEntry, String name, Type type) { 23 public FieldEntry(ClassEntry classEntry, String name, Type type) {
23 if (classEntry == null) { 24 if (classEntry == null) {
24 throw new IllegalArgumentException("Class cannot be null!"); 25 throw new IllegalArgumentException("Class cannot be null!");
25 } 26 }
26 if (name == null) { 27 if (name == null) {
27 throw new IllegalArgumentException("Field name cannot be null!"); 28 throw new IllegalArgumentException("Field name cannot be null!");
28 } 29 }
29 if (type == null) { 30 if (type == null) {
30 throw new IllegalArgumentException("Field type cannot be null!"); 31 throw new IllegalArgumentException("Field type cannot be null!");
31 } 32 }
32 33
33 this.classEntry = classEntry; 34 this.classEntry = classEntry;
34 this.name = name; 35 this.name = name;
35 this.type = type; 36 this.type = type;
36 } 37 }
37 38
38 public FieldEntry(FieldEntry other, ClassEntry newClassEntry) { 39 public FieldEntry(FieldEntry other, ClassEntry newClassEntry) {
39 this.classEntry = newClassEntry; 40 this.classEntry = newClassEntry;
40 this.name = other.name; 41 this.name = other.name;
41 this.type = other.type; 42 this.type = other.type;
42 } 43 }
43 44
44 @Override 45 @Override
45 public ClassEntry getClassEntry() { 46 public ClassEntry getClassEntry() {
46 return this.classEntry; 47 return this.classEntry;
47 } 48 }
48 49
49 @Override 50 @Override
50 public String getName() { 51 public String getName() {
51 return this.name; 52 return this.name;
52 } 53 }
53 54
54 @Override 55 @Override
55 public String getClassName() { 56 public String getClassName() {
56 return this.classEntry.getName(); 57 return this.classEntry.getName();
57 } 58 }
58 59
59 public Type getType() { 60 public Type getType() {
60 return this.type; 61 return this.type;
61 } 62 }
62 63
63 @Override 64 @Override
64 public FieldEntry cloneToNewClass(ClassEntry classEntry) { 65 public FieldEntry cloneToNewClass(ClassEntry classEntry) {
65 return new FieldEntry(this, classEntry); 66 return new FieldEntry(this, classEntry);
66 } 67 }
67 68
68 @Override 69 @Override
69 public int hashCode() { 70 public int hashCode() {
70 return Utils.combineHashesOrdered(this.classEntry, this.name, this.type); 71 return Utils.combineHashesOrdered(this.classEntry, this.name, this.type);
71 } 72 }
72 73
73 @Override 74 @Override
74 public boolean equals(Object other) { 75 public boolean equals(Object other) {
75 return other instanceof FieldEntry && equals((FieldEntry) other); 76 return other instanceof FieldEntry && equals((FieldEntry) other);
76 } 77 }
77 78
78 public boolean equals(FieldEntry other) { 79 public boolean equals(FieldEntry other) {
79 return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.type.equals(other.type); 80 return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.type.equals(other.type);
80 } 81 }
81 82
82 @Override 83 @Override
83 public String toString() { 84 public String toString() {
84 return this.classEntry.getName() + "." + this.name + ":" + this.type; 85 return this.classEntry.getName() + "." + this.name + ":" + this.type;
85 } 86 }
86} 87}
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
index 22ba307..cd761b4 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
@@ -8,103 +8,99 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.throwables.IllegalNameException; 14import cuchaz.enigma.throwables.IllegalNameException;
14 15
15public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<FieldEntry> { 16public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<FieldEntry> {
16 17
17 private String obfName; 18 private String obfName;
18 private String deobfName; 19 private String deobfName;
19 private Type obfType; 20 private Type obfType;
20 private Mappings.EntryModifier modifier; 21 private Mappings.EntryModifier modifier;
21 22
22 public FieldMapping(String obfName, Type obfType, String deobfName, Mappings.EntryModifier modifier) { 23 public FieldMapping(String obfName, Type obfType, String deobfName, Mappings.EntryModifier modifier) {
23 this.obfName = obfName; 24 this.obfName = obfName;
24 this.deobfName = NameValidator.validateFieldName(deobfName); 25 this.deobfName = NameValidator.validateFieldName(deobfName);
25 this.obfType = obfType; 26 this.obfType = obfType;
26 this.modifier = modifier; 27 this.modifier = modifier;
27 } 28 }
28 29
29 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { 30 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) {
30 this.obfName = other.obfName; 31 this.obfName = other.obfName;
31 this.deobfName = other.deobfName; 32 this.deobfName = other.deobfName;
32 this.modifier = other.modifier; 33 this.modifier = other.modifier;
33 this.obfType = new Type(other.obfType, obfClassNameReplacer); 34 this.obfType = new Type(other.obfType, obfClassNameReplacer);
34 } 35 }
35 36
36 @Override 37 @Override
37 public FieldEntry getObfEntry(ClassEntry classEntry) { 38 public FieldEntry getObfEntry(ClassEntry classEntry) {
38 return new FieldEntry(classEntry, this.obfName, this.obfType); 39 return new FieldEntry(classEntry, this.obfName, this.obfType);
39 } 40 }
40 41
41 @Override 42 @Override
42 public String getObfName() { 43 public String getObfName() {
43 return this.obfName; 44 return this.obfName;
44 } 45 }
45 46
46 public String getDeobfName() { 47 public void setObfName(String name) {
47 return this.deobfName; 48 try {
48 } 49 NameValidator.validateMethodName(name);
49 50 } catch (IllegalNameException ex) {
50 public void setDeobfName(String val) { 51 // Invalid name, damn obfuscation! Map to a deob name with another name to avoid issues
51 this.deobfName = NameValidator.validateFieldName(val); 52 if (this.deobfName == null) {
52 } 53 System.err.println("WARNING: " + name + " is conflicting, auto deobfuscate to " + (name + "_auto_deob"));
53 54 setDeobfName(name + "_auto_deob");
54 public void setObfName(String name) { 55 }
55 try 56 }
56 { 57 this.obfName = name;
57 NameValidator.validateMethodName(name); 58 }
58 } catch (IllegalNameException ex) 59
59 { 60 public String getDeobfName() {
60 // Invalid name, damn obfuscation! Map to a deob name with another name to avoid issues 61 return this.deobfName;
61 if (this.deobfName == null) 62 }
62 { 63
63 System.err.println("WARNING: " + name + " is conflicting, auto deobfuscate to " + (name + "_auto_deob")); 64 public void setDeobfName(String val) {
64 setDeobfName(name + "_auto_deob"); 65 this.deobfName = NameValidator.validateFieldName(val);
65 } 66 }
66 } 67
67 this.obfName = name; 68 public Type getObfType() {
68 } 69 return this.obfType;
69 70 }
70 public Type getObfType() { 71
71 return this.obfType; 72 public void setObfType(Type val) {
72 } 73 this.obfType = val;
73 74 }
74 public void setObfType(Type val) { 75
75 this.obfType = val; 76 public Mappings.EntryModifier getModifier() {
76 } 77 return modifier;
77 78 }
78 public void setModifier(Mappings.EntryModifier modifier) 79
79 { 80 public void setModifier(Mappings.EntryModifier modifier) {
80 this.modifier = modifier; 81 this.modifier = modifier;
81 } 82 }
82 83
83 public Mappings.EntryModifier getModifier() 84 @Override
84 { 85 public int compareTo(FieldMapping other) {
85 return modifier; 86 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType);
86 } 87 }
87 88
88 @Override 89 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
89 public int compareTo(FieldMapping other) { 90 // rename obf classes in the type
90 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); 91 Type newType = new Type(this.obfType, className ->
91 } 92 {
92 93 if (className.equals(oldObfClassName)) {
93 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { 94 return newObfClassName;
94 // rename obf classes in the type 95 }
95 Type newType = new Type(this.obfType, className -> 96 return null;
96 { 97 });
97 if (className.equals(oldObfClassName)) { 98
98 return newObfClassName; 99 if (!newType.equals(this.obfType)) {
99 } 100 this.obfType = newType;
100 return null; 101 return true;
101 }); 102 }
102 103 return false;
103 if (!newType.equals(this.obfType)) { 104 }
104 this.obfType = newType;
105 return true;
106 }
107 return false;
108 }
109 105
110} 106}
diff --git a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
index 8bbaaaf..2bb5e3f 100644
--- a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java
@@ -7,98 +7,96 @@ import cuchaz.enigma.utils.Utils;
7 * Created by Thog 7 * Created by Thog
8 * 19/10/2016 8 * 19/10/2016
9 */ 9 */
10public class LocalVariableEntry implements Entry 10public class LocalVariableEntry implements Entry {
11{ 11
12 12 protected final BehaviorEntry behaviorEntry;
13 protected final BehaviorEntry behaviorEntry; 13 protected final String name;
14 protected final String name; 14 protected final Type type;
15 protected final Type type; 15 protected final int index;
16 protected final int index; 16
17 17 public LocalVariableEntry(BehaviorEntry behaviorEntry, int index, String name, Type type) {
18 public LocalVariableEntry(BehaviorEntry behaviorEntry, int index, String name, Type type) { 18 if (behaviorEntry == null) {
19 if (behaviorEntry == null) { 19 throw new IllegalArgumentException("Behavior cannot be null!");
20 throw new IllegalArgumentException("Behavior cannot be null!"); 20 }
21 } 21 if (index < 0) {
22 if (index < 0) { 22 throw new IllegalArgumentException("Index must be non-negative!");
23 throw new IllegalArgumentException("Index must be non-negative!"); 23 }
24 } 24 if (name == null) {
25 if (name == null) { 25 throw new IllegalArgumentException("Variable name cannot be null!");
26 throw new IllegalArgumentException("Variable name cannot be null!"); 26 }
27 } 27 if (type == null) {
28 if (type == null) { 28 throw new IllegalArgumentException("Variable type cannot be null!");
29 throw new IllegalArgumentException("Variable type cannot be null!"); 29 }
30 } 30
31 31 this.behaviorEntry = behaviorEntry;
32 this.behaviorEntry = behaviorEntry; 32 this.name = name;
33 this.name = name; 33 this.type = type;
34 this.type = type; 34 this.index = index;
35 this.index = index; 35 }
36 } 36
37 37 public LocalVariableEntry(LocalVariableEntry other, ClassEntry newClassEntry) {
38 38 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(newClassEntry);
39 public LocalVariableEntry(LocalVariableEntry other, ClassEntry newClassEntry) { 39 this.name = other.name;
40 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(newClassEntry); 40 this.type = other.type;
41 this.name = other.name; 41 this.index = other.index;
42 this.type = other.type; 42 }
43 this.index = other.index; 43
44 } 44 public BehaviorEntry getBehaviorEntry() {
45 45 return this.behaviorEntry;
46 public BehaviorEntry getBehaviorEntry() { 46 }
47 return this.behaviorEntry; 47
48 } 48 public Type getType() {
49 49 return type;
50 public Type getType() { 50 }
51 return type; 51
52 } 52 public int getIndex() {
53 53 return index;
54 public int getIndex() { 54 }
55 return index; 55
56 } 56 @Override
57 57 public String getName() {
58 @Override 58 return this.name;
59 public String getName() { 59 }
60 return this.name; 60
61 } 61 @Override
62 62 public ClassEntry getClassEntry() {
63 @Override 63 return this.behaviorEntry.getClassEntry();
64 public ClassEntry getClassEntry() { 64 }
65 return this.behaviorEntry.getClassEntry(); 65
66 } 66 @Override
67 67 public String getClassName() {
68 @Override 68 return this.behaviorEntry.getClassName();
69 public String getClassName() { 69 }
70 return this.behaviorEntry.getClassName(); 70
71 } 71 @Override
72 72 public LocalVariableEntry cloneToNewClass(ClassEntry classEntry) {
73 @Override 73 return new LocalVariableEntry(this, classEntry);
74 public LocalVariableEntry cloneToNewClass(ClassEntry classEntry) { 74 }
75 return new LocalVariableEntry(this, classEntry); 75
76 } 76 public String getMethodName() {
77 77 return this.behaviorEntry.getName();
78 public String getMethodName() { 78 }
79 return this.behaviorEntry.getName(); 79
80 } 80 public Signature getMethodSignature() {
81 81 return this.behaviorEntry.getSignature();
82 public Signature getMethodSignature() { 82 }
83 return this.behaviorEntry.getSignature(); 83
84 } 84 @Override
85 85 public int hashCode() {
86 @Override 86 return Utils.combineHashesOrdered(this.behaviorEntry, this.type.hashCode(), this.name.hashCode(), Integer.hashCode(this.index));
87 public int hashCode() { 87 }
88 return Utils.combineHashesOrdered(this.behaviorEntry, this.type.hashCode(), this.name.hashCode(), Integer.hashCode(this.index)); 88
89 } 89 @Override
90 90 public boolean equals(Object other) {
91 @Override 91 return other instanceof LocalVariableEntry && equals((LocalVariableEntry) other);
92 public boolean equals(Object other) { 92 }
93 return other instanceof LocalVariableEntry && equals((LocalVariableEntry) other); 93
94 } 94 public boolean equals(LocalVariableEntry other) {
95 95 return this.behaviorEntry.equals(other.behaviorEntry) && this.type.equals(other.type) && this.name.equals(other.name) && this.index == other.index;
96 public boolean equals(LocalVariableEntry other) { 96 }
97 return this.behaviorEntry.equals(other.behaviorEntry) && this.type.equals(other.type) && this.name.equals(other.name) && this.index == other.index; 97
98 } 98 @Override
99 99 public String toString() {
100 @Override 100 return this.behaviorEntry + "(" + this.index + ":" + this.name + ":" + this.type + ")";
101 public String toString() { 101 }
102 return this.behaviorEntry.toString() + "(" + this.index + ":" + this.name + ":" + this.type + ")";
103 }
104} 102}
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index d493dcf..33dd3c5 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -8,246 +8,237 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
16import com.google.common.collect.Sets;
17import cuchaz.enigma.analysis.TranslationIndex;
18import cuchaz.enigma.throwables.MappingConflict;
15 19
16import java.io.File; 20import java.io.File;
17import java.io.IOException; 21import java.io.IOException;
18import java.util.*; 22import java.util.*;
19 23
20import com.google.common.collect.Sets;
21import cuchaz.enigma.analysis.TranslationIndex;
22import cuchaz.enigma.throwables.MappingConflict;
23
24public class Mappings { 24public class Mappings {
25 25
26 protected Map<String, ClassMapping> classesByObf; 26 private final FormatType originMapping;
27 protected Map<String, ClassMapping> classesByDeobf; 27 protected Map<String, ClassMapping> classesByObf;
28 private final FormatType originMapping; 28 protected Map<String, ClassMapping> classesByDeobf;
29 private Mappings previousState; 29 private Mappings previousState;
30 30
31 public Mappings() 31 public Mappings() {
32 { 32 this(FormatType.ENIGMA_DIRECTORY);
33 this(FormatType.ENIGMA_DIRECTORY); 33 }
34 } 34
35 35 public Mappings(FormatType originMapping) {
36 public Mappings(FormatType originMapping) { 36 this.originMapping = originMapping;
37 this.originMapping = originMapping; 37 this.classesByObf = Maps.newHashMap();
38 this.classesByObf = Maps.newHashMap(); 38 this.classesByDeobf = Maps.newHashMap();
39 this.classesByDeobf = Maps.newHashMap(); 39 this.previousState = null;
40 this.previousState = null; 40 }
41 } 41
42 42 public Collection<ClassMapping> classes() {
43 public Collection<ClassMapping> classes() { 43 assert (this.classesByObf.size() >= this.classesByDeobf.size());
44 assert (this.classesByObf.size() >= this.classesByDeobf.size()); 44 return this.classesByObf.values();
45 return this.classesByObf.values(); 45 }
46 } 46
47 47 public void addClassMapping(ClassMapping classMapping) throws MappingConflict {
48 public void addClassMapping(ClassMapping classMapping) throws MappingConflict { 48 if (this.classesByObf.containsKey(classMapping.getObfFullName())) {
49 if (this.classesByObf.containsKey(classMapping.getObfFullName())) { 49 throw new MappingConflict("class", classMapping.getObfFullName(), this.classesByObf.get(classMapping.getObfFullName()).getObfFullName());
50 throw new MappingConflict("class", classMapping.getObfFullName(), this.classesByObf.get(classMapping.getObfFullName()).getObfFullName()); 50 }
51 } 51 this.classesByObf.put(classMapping.getObfFullName(), classMapping);
52 this.classesByObf.put(classMapping.getObfFullName(), classMapping); 52
53 53 if (classMapping.getDeobfName() != null) {
54 if (classMapping.getDeobfName() != null) { 54 if (this.classesByDeobf.containsKey(classMapping.getDeobfName())) {
55 if (this.classesByDeobf.containsKey(classMapping.getDeobfName())) { 55 throw new MappingConflict("class", classMapping.getDeobfName(), this.classesByDeobf.get(classMapping.getDeobfName()).getDeobfName());
56 throw new MappingConflict("class", classMapping.getDeobfName(), this.classesByDeobf.get(classMapping.getDeobfName()).getDeobfName()); 56 }
57 } 57 this.classesByDeobf.put(classMapping.getDeobfName(), classMapping);
58 this.classesByDeobf.put(classMapping.getDeobfName(), classMapping); 58 }
59 } 59 }
60 } 60
61 61 public void removeClassMapping(ClassMapping classMapping) {
62 public void removeClassMapping(ClassMapping classMapping) { 62 boolean obfWasRemoved = this.classesByObf.remove(classMapping.getObfFullName()) != null;
63 boolean obfWasRemoved = this.classesByObf.remove(classMapping.getObfFullName()) != null; 63 assert (obfWasRemoved);
64 assert (obfWasRemoved); 64 if (classMapping.getDeobfName() != null) {
65 if (classMapping.getDeobfName() != null) { 65 boolean deobfWasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null;
66 boolean deobfWasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null; 66 assert (deobfWasRemoved);
67 assert (deobfWasRemoved); 67 }
68 } 68 }
69 } 69
70 70 public ClassMapping getClassByObf(ClassEntry entry) {
71 71 return getClassByObf(entry.getName());
72 public ClassMapping getClassByObf(ClassEntry entry) { 72 }
73 return getClassByObf(entry.getName()); 73
74 } 74 public ClassMapping getClassByObf(String obfName) {
75 75 return this.classesByObf.get(obfName);
76 public ClassMapping getClassByObf(String obfName) { 76 }
77 return this.classesByObf.get(obfName); 77
78 } 78 public ClassMapping getClassByDeobf(ClassEntry entry) {
79 79 return getClassByDeobf(entry.getName());
80 public ClassMapping getClassByDeobf(ClassEntry entry) { 80 }
81 return getClassByDeobf(entry.getName()); 81
82 } 82 public ClassMapping getClassByDeobf(String deobfName) {
83 83 return this.classesByDeobf.get(deobfName);
84 public ClassMapping getClassByDeobf(String deobfName) { 84 }
85 return this.classesByDeobf.get(deobfName); 85
86 } 86 public void setClassDeobfName(ClassMapping classMapping, String deobfName) {
87 87 if (classMapping.getDeobfName() != null) {
88 public void setClassDeobfName(ClassMapping classMapping, String deobfName) { 88 boolean wasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null;
89 if (classMapping.getDeobfName() != null) { 89 assert (wasRemoved);
90 boolean wasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null; 90 }
91 assert (wasRemoved); 91 classMapping.setDeobfName(deobfName);
92 } 92 if (deobfName != null) {
93 classMapping.setDeobfName(deobfName); 93 boolean wasAdded = this.classesByDeobf.put(deobfName, classMapping) == null;
94 if (deobfName != null) { 94 assert (wasAdded);
95 boolean wasAdded = this.classesByDeobf.put(deobfName, classMapping) == null; 95 }
96 assert (wasAdded); 96 }
97 } 97
98 } 98 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) {
99 99 switch (direction) {
100 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) { 100 case Deobfuscating:
101 switch (direction) { 101
102 case Deobfuscating: 102 return new Translator(direction, this.classesByObf, index);
103 103
104 return new Translator(direction, this.classesByObf, index); 104 case Obfuscating:
105 105
106 case Obfuscating: 106 // fill in the missing deobf class entries with obf entries
107 107 Map<String, ClassMapping> classes = Maps.newHashMap();
108 // fill in the missing deobf class entries with obf entries 108 for (ClassMapping classMapping : classes()) {
109 Map<String, ClassMapping> classes = Maps.newHashMap(); 109 if (classMapping.getDeobfName() != null) {
110 for (ClassMapping classMapping : classes()) { 110 classes.put(classMapping.getDeobfName(), classMapping);
111 if (classMapping.getDeobfName() != null) { 111 } else {
112 classes.put(classMapping.getDeobfName(), classMapping); 112 classes.put(classMapping.getObfFullName(), classMapping);
113 } else { 113 }
114 classes.put(classMapping.getObfFullName(), classMapping); 114 }
115 } 115
116 } 116 // translate the translation index
117 117 // NOTE: this isn't actually recursive
118 // translate the translation index 118 TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index));
119 // NOTE: this isn't actually recursive 119
120 TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index)); 120 return new Translator(direction, classes, deobfIndex);
121 121
122 return new Translator(direction, classes, deobfIndex); 122 default:
123 123 throw new Error("Invalid translation direction!");
124 default: 124 }
125 throw new Error("Invalid translation direction!"); 125 }
126 } 126
127 } 127 @Override
128 128 public String toString() {
129 @Override 129 StringBuilder buf = new StringBuilder();
130 public String toString() { 130 for (ClassMapping classMapping : this.classesByObf.values()) {
131 StringBuilder buf = new StringBuilder(); 131 buf.append(classMapping);
132 for (ClassMapping classMapping : this.classesByObf.values()) { 132 buf.append("\n");
133 buf.append(classMapping.toString()); 133 }
134 buf.append("\n"); 134 return buf.toString();
135 } 135 }
136 return buf.toString(); 136
137 } 137 public void renameObfClass(String oldObfName, String newObfName) {
138 138 new ArrayList<>(classes()).stream().filter(classMapping -> classMapping.renameObfClass(oldObfName, newObfName)).forEach(classMapping -> {
139 public void renameObfClass(String oldObfName, String newObfName) { 139 boolean wasRemoved = this.classesByObf.remove(oldObfName) != null;
140 new ArrayList<>(classes()).stream().filter(classMapping -> classMapping.renameObfClass(oldObfName, newObfName)).forEach(classMapping -> { 140 assert (wasRemoved);
141 boolean wasRemoved = this.classesByObf.remove(oldObfName) != null; 141 boolean wasAdded = this.classesByObf.put(newObfName, classMapping) == null;
142 assert (wasRemoved); 142 assert (wasAdded);
143 boolean wasAdded = this.classesByObf.put(newObfName, classMapping) == null; 143 });
144 assert (wasAdded); 144 }
145 }); 145
146 } 146 public Set<String> getAllObfClassNames() {
147 147 final Set<String> classNames = Sets.newHashSet();
148 public Set<String> getAllObfClassNames() { 148 for (ClassMapping classMapping : classes()) {
149 final Set<String> classNames = Sets.newHashSet(); 149
150 for (ClassMapping classMapping : classes()) { 150 // add the class name
151 151 classNames.add(classMapping.getObfFullName());
152 // add the class name 152
153 classNames.add(classMapping.getObfFullName()); 153 // add classes from method signatures
154 154 for (MethodMapping methodMapping : classMapping.methods()) {
155 // add classes from method signatures 155 for (Type type : methodMapping.getObfSignature().types()) {
156 for (MethodMapping methodMapping : classMapping.methods()) { 156 if (type.hasClass()) {
157 for (Type type : methodMapping.getObfSignature().types()) { 157 classNames.add(type.getClassEntry().getClassName());
158 if (type.hasClass()) { 158 }
159 classNames.add(type.getClassEntry().getClassName()); 159 }
160 } 160 }
161 } 161 }
162 } 162 return classNames;
163 } 163 }
164 return classNames; 164
165 } 165 public boolean containsDeobfClass(String deobfName) {
166 166 return this.classesByDeobf.containsKey(deobfName);
167 public boolean containsDeobfClass(String deobfName) { 167 }
168 return this.classesByDeobf.containsKey(deobfName); 168
169 } 169 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) {
170 170 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
171 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) { 171 return classMapping != null && classMapping.containsDeobfField(deobfName, obfType);
172 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); 172 }
173 return classMapping != null && classMapping.containsDeobfField(deobfName, obfType); 173
174 } 174 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) {
175 175 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
176 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) { 176 if (classMapping != null)
177 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); 177 for (FieldMapping fieldMapping : classMapping.fields())
178 if (classMapping != null) 178 if (deobfName.equals(fieldMapping.getDeobfName()) || deobfName.equals(fieldMapping.getObfName()))
179 for (FieldMapping fieldMapping : classMapping.fields()) 179 return true;
180 if (deobfName.equals(fieldMapping.getDeobfName()) || deobfName.equals(fieldMapping.getObfName())) 180
181 return true; 181 return false;
182 182 }
183 return false; 183
184 } 184 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) {
185 185 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName());
186 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) { 186 return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature);
187 ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); 187 }
188 return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature); 188
189 } 189 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
190 190 ClassMapping classMapping = this.classesByObf.get(obfBehaviorEntry.getClassName());
191 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { 191 return classMapping != null && classMapping.containsArgument(obfBehaviorEntry, name);
192 ClassMapping classMapping = this.classesByObf.get(obfBehaviorEntry.getClassName()); 192 }
193 return classMapping != null && classMapping.containsArgument(obfBehaviorEntry, name); 193
194 } 194 public List<ClassMapping> getClassMappingChain(ClassEntry obfClass) {
195 195 List<ClassMapping> mappingChain = Lists.newArrayList();
196 public List<ClassMapping> getClassMappingChain(ClassEntry obfClass) { 196 ClassMapping classMapping = null;
197 List<ClassMapping> mappingChain = Lists.newArrayList(); 197 for (ClassEntry obfClassEntry : obfClass.getClassChain()) {
198 ClassMapping classMapping = null; 198 if (mappingChain.isEmpty()) {
199 for (ClassEntry obfClassEntry : obfClass.getClassChain()) { 199 classMapping = this.classesByObf.get(obfClassEntry.getName());
200 if (mappingChain.isEmpty()) { 200 } else if (classMapping != null) {
201 classMapping = this.classesByObf.get(obfClassEntry.getName()); 201 classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName());
202 } else if (classMapping != null) { 202 }
203 classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName()); 203 mappingChain.add(classMapping);
204 } 204 }
205 mappingChain.add(classMapping); 205 return mappingChain;
206 } 206 }
207 return mappingChain; 207
208 } 208 public FormatType getOriginMappingFormat() {
209 209 return originMapping;
210 public FormatType getOriginMappingFormat() 210 }
211 { 211
212 return originMapping; 212 public void savePreviousState() {
213 } 213 this.previousState = new Mappings(this.originMapping);
214 214 this.previousState.classesByDeobf = Maps.newHashMap(this.classesByDeobf);
215 public void savePreviousState() 215 this.previousState.classesByObf = Maps.newHashMap(this.classesByObf);
216 { 216 classesByDeobf.values().forEach(ClassMapping::resetDirty);
217 this.previousState = new Mappings(this.originMapping); 217 classesByObf.values().forEach(ClassMapping::resetDirty);
218 this.previousState.classesByDeobf = Maps.newHashMap(this.classesByDeobf); 218 }
219 this.previousState.classesByObf = Maps.newHashMap(this.classesByObf); 219
220 classesByDeobf.values().forEach(ClassMapping::resetDirty); 220 public void saveEnigmaMappings(File file, boolean isDirectoryFormat) throws IOException {
221 classesByObf.values().forEach(ClassMapping::resetDirty); 221 new MappingsEnigmaWriter().write(file, this, isDirectoryFormat);
222 } 222 this.savePreviousState();
223 223 }
224 public void saveEnigmaMappings(File file, boolean isDirectoryFormat) throws IOException 224
225 { 225 public void saveSRGMappings(File file) throws IOException {
226 new MappingsEnigmaWriter().write(file, this, isDirectoryFormat); 226 new MappingsSRGWriter().write(file, this);
227 this.savePreviousState(); 227 }
228 } 228
229 229 public Mappings getPreviousState() {
230 public void saveSRGMappings(File file) throws IOException 230 return previousState;
231 { 231 }
232 new MappingsSRGWriter().write(file, this); 232
233 } 233 public enum FormatType {
234 234 ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE
235 public Mappings getPreviousState() { 235 }
236 return previousState; 236
237 } 237 public enum EntryModifier {
238 238 UNCHANGED, PUBLIC, PROTECTED, PRIVATE;
239 public enum FormatType 239
240 { 240 public String getFormattedName() {
241 ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE 241 return " ACC:" + super.toString();
242 } 242 }
243 243 }
244 public enum EntryModifier
245 {
246 UNCHANGED, PUBLIC, PROTECTED, PRIVATE;
247
248 public String getFormattedName()
249 {
250 return " ACC:" + super.toString();
251 }
252 }
253} 244}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
index 6cf279d..172641b 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java
@@ -8,91 +8,90 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
15
16import java.util.Map;
17
18import cuchaz.enigma.analysis.JarIndex; 16import cuchaz.enigma.analysis.JarIndex;
19 17
18import java.util.Map;
20 19
21public class MappingsChecker { 20public class MappingsChecker {
22 21
23 private JarIndex index; 22 private JarIndex index;
24 private Map<ClassEntry, ClassMapping> droppedClassMappings; 23 private Map<ClassEntry, ClassMapping> droppedClassMappings;
25 private Map<ClassEntry, ClassMapping> droppedInnerClassMappings; 24 private Map<ClassEntry, ClassMapping> droppedInnerClassMappings;
26 private Map<FieldEntry, FieldMapping> droppedFieldMappings; 25 private Map<FieldEntry, FieldMapping> droppedFieldMappings;
27 private Map<BehaviorEntry, MethodMapping> droppedMethodMappings; 26 private Map<BehaviorEntry, MethodMapping> droppedMethodMappings;
28 27
29 public MappingsChecker(JarIndex index) { 28 public MappingsChecker(JarIndex index) {
30 this.index = index; 29 this.index = index;
31 this.droppedClassMappings = Maps.newHashMap(); 30 this.droppedClassMappings = Maps.newHashMap();
32 this.droppedInnerClassMappings = Maps.newHashMap(); 31 this.droppedInnerClassMappings = Maps.newHashMap();
33 this.droppedFieldMappings = Maps.newHashMap(); 32 this.droppedFieldMappings = Maps.newHashMap();
34 this.droppedMethodMappings = Maps.newHashMap(); 33 this.droppedMethodMappings = Maps.newHashMap();
35 } 34 }
36 35
37 public Map<ClassEntry, ClassMapping> getDroppedClassMappings() { 36 public Map<ClassEntry, ClassMapping> getDroppedClassMappings() {
38 return this.droppedClassMappings; 37 return this.droppedClassMappings;
39 } 38 }
40 39
41 public Map<ClassEntry, ClassMapping> getDroppedInnerClassMappings() { 40 public Map<ClassEntry, ClassMapping> getDroppedInnerClassMappings() {
42 return this.droppedInnerClassMappings; 41 return this.droppedInnerClassMappings;
43 } 42 }
44 43
45 public Map<FieldEntry, FieldMapping> getDroppedFieldMappings() { 44 public Map<FieldEntry, FieldMapping> getDroppedFieldMappings() {
46 return this.droppedFieldMappings; 45 return this.droppedFieldMappings;
47 } 46 }
48 47
49 public Map<BehaviorEntry, MethodMapping> getDroppedMethodMappings() { 48 public Map<BehaviorEntry, MethodMapping> getDroppedMethodMappings() {
50 return this.droppedMethodMappings; 49 return this.droppedMethodMappings;
51 } 50 }
52 51
53 public void dropBrokenMappings(Mappings mappings) { 52 public void dropBrokenMappings(Mappings mappings) {
54 for (ClassMapping classMapping : Lists.newArrayList(mappings.classes())) { 53 for (ClassMapping classMapping : Lists.newArrayList(mappings.classes())) {
55 if (!checkClassMapping(classMapping)) { 54 if (!checkClassMapping(classMapping)) {
56 mappings.removeClassMapping(classMapping); 55 mappings.removeClassMapping(classMapping);
57 this.droppedClassMappings.put(EntryFactory.getObfClassEntry(this.index, classMapping), classMapping); 56 this.droppedClassMappings.put(EntryFactory.getObfClassEntry(this.index, classMapping), classMapping);
58 } 57 }
59 } 58 }
60 } 59 }
61 60
62 private boolean checkClassMapping(ClassMapping classMapping) { 61 private boolean checkClassMapping(ClassMapping classMapping) {
63 62
64 // check the class 63 // check the class
65 ClassEntry classEntry = EntryFactory.getObfClassEntry(this.index, classMapping); 64 ClassEntry classEntry = EntryFactory.getObfClassEntry(this.index, classMapping);
66 if (!this.index.getObfClassEntries().contains(classEntry)) { 65 if (!this.index.getObfClassEntries().contains(classEntry)) {
67 return false; 66 return false;
68 } 67 }
69 68
70 // check the fields 69 // check the fields
71 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { 70 for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) {
72 FieldEntry obfFieldEntry = EntryFactory.getObfFieldEntry(classMapping, fieldMapping); 71 FieldEntry obfFieldEntry = EntryFactory.getObfFieldEntry(classMapping, fieldMapping);
73 if (!this.index.containsObfField(obfFieldEntry)) { 72 if (!this.index.containsObfField(obfFieldEntry)) {
74 classMapping.removeFieldMapping(fieldMapping); 73 classMapping.removeFieldMapping(fieldMapping);
75 this.droppedFieldMappings.put(obfFieldEntry, fieldMapping); 74 this.droppedFieldMappings.put(obfFieldEntry, fieldMapping);
76 } 75 }
77 } 76 }
78 77
79 // check methods 78 // check methods
80 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { 79 for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) {
81 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); 80 BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping);
82 if (!this.index.containsObfBehavior(obfBehaviorEntry)) { 81 if (!this.index.containsObfBehavior(obfBehaviorEntry)) {
83 classMapping.removeMethodMapping(methodMapping); 82 classMapping.removeMethodMapping(methodMapping);
84 this.droppedMethodMappings.put(obfBehaviorEntry, methodMapping); 83 this.droppedMethodMappings.put(obfBehaviorEntry, methodMapping);
85 } 84 }
86 } 85 }
87 86
88 // check inner classes 87 // check inner classes
89 for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) { 88 for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) {
90 if (!checkClassMapping(innerClassMapping)) { 89 if (!checkClassMapping(innerClassMapping)) {
91 classMapping.removeInnerClassMapping(innerClassMapping); 90 classMapping.removeInnerClassMapping(innerClassMapping);
92 this.droppedInnerClassMappings.put(EntryFactory.getObfClassEntry(this.index, innerClassMapping), innerClassMapping); 91 this.droppedInnerClassMappings.put(EntryFactory.getObfClassEntry(this.index, innerClassMapping), innerClassMapping);
93 } 92 }
94 } 93 }
95 94
96 return true; 95 return true;
97 } 96 }
98} 97}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
index cdfed72..a0d4313 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
@@ -8,178 +8,170 @@ import cuchaz.enigma.throwables.MappingParseException;
8import java.io.*; 8import java.io.*;
9import java.util.Deque; 9import java.util.Deque;
10 10
11public class MappingsEnigmaReader 11public class MappingsEnigmaReader {
12{ 12
13 13 public Mappings read(File file) throws IOException, MappingParseException {
14 public Mappings read(File file) throws IOException, MappingParseException { 14 Mappings mappings;
15 Mappings mappings; 15
16 16 // Multiple file
17 // Multiple file 17 if (file.isDirectory()) {
18 if (file.isDirectory()) 18 mappings = new Mappings(Mappings.FormatType.ENIGMA_DIRECTORY);
19 { 19 readDirectory(mappings, file);
20 mappings = new Mappings(Mappings.FormatType.ENIGMA_DIRECTORY); 20 } else {
21 readDirectory(mappings, file); 21 mappings = new Mappings();
22 } 22 readFile(mappings, file);
23 else 23 }
24 { 24 return mappings;
25 mappings = new Mappings(); 25 }
26 readFile(mappings, file); 26
27 } 27 public void readDirectory(Mappings mappings, File directory) throws IOException, MappingParseException {
28 return mappings; 28 File[] files = directory.listFiles();
29 } 29 if (files != null) {
30 30 for (File file : files) {
31 public void readDirectory(Mappings mappings, File directory) throws IOException, MappingParseException { 31 if (file.isFile() && !file.getName().startsWith(".") && file.getName().endsWith(".mapping"))
32 File[] files = directory.listFiles(); 32 readFile(mappings, file);
33 if (files != null) { 33 else if (file.isDirectory())
34 for (File file : files) { 34 readDirectory(mappings, file.getAbsoluteFile());
35 if (file.isFile() && !file.getName().startsWith(".") && file.getName().endsWith(".mapping")) 35 }
36 readFile(mappings, file); 36 mappings.savePreviousState();
37 else if (file.isDirectory()) 37 } else
38 readDirectory(mappings, file.getAbsoluteFile()); 38 throw new IOException("Cannot access directory" + directory.getAbsolutePath());
39 } 39 }
40 mappings.savePreviousState(); 40
41 } 41 public Mappings readFile(Mappings mappings, File file) throws IOException, MappingParseException {
42 else 42
43 throw new IOException("Cannot access directory" + directory.getAbsolutePath()); 43 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8));
44 } 44 Deque<Object> mappingStack = Queues.newArrayDeque();
45 45
46 public Mappings readFile(Mappings mappings, File file) throws IOException, MappingParseException { 46 int lineNumber = 0;
47 47 String line;
48 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)); 48 while ((line = in.readLine()) != null) {
49 Deque<Object> mappingStack = Queues.newArrayDeque(); 49 lineNumber++;
50 50
51 int lineNumber = 0; 51 // strip comments
52 String line; 52 int commentPos = line.indexOf('#');
53 while ((line = in.readLine()) != null) { 53 if (commentPos >= 0) {
54 lineNumber++; 54 line = line.substring(0, commentPos);
55 55 }
56 // strip comments 56
57 int commentPos = line.indexOf('#'); 57 // skip blank lines
58 if (commentPos >= 0) { 58 if (line.trim().length() <= 0) {
59 line = line.substring(0, commentPos); 59 continue;
60 } 60 }
61 61
62 // skip blank lines 62 // get the indent of this line
63 if (line.trim().length() <= 0) { 63 int indent = 0;
64 continue; 64 for (int i = 0; i < line.length(); i++) {
65 } 65 if (line.charAt(i) != '\t') {
66 66 break;
67 // get the indent of this line 67 }
68 int indent = 0; 68 indent++;
69 for (int i = 0; i < line.length(); i++) { 69 }
70 if (line.charAt(i) != '\t') { 70
71 break; 71 // handle stack pops
72 } 72 while (indent < mappingStack.size()) {
73 indent++; 73 mappingStack.pop();
74 } 74 }
75 75
76 // handle stack pops 76 String[] parts = line.trim().split("\\s");
77 while (indent < mappingStack.size()) { 77 try {
78 mappingStack.pop(); 78 // read the first token
79 } 79 String token = parts[0];
80 80
81 String[] parts = line.trim().split("\\s"); 81 if (token.equalsIgnoreCase("CLASS")) {
82 try { 82 ClassMapping classMapping;
83 // read the first token 83 if (indent <= 0) {
84 String token = parts[0]; 84 // outer class
85 85 classMapping = readClass(parts, false);
86 if (token.equalsIgnoreCase("CLASS")) { 86 mappings.addClassMapping(classMapping);
87 ClassMapping classMapping; 87 } else {
88 if (indent <= 0) { 88
89 // outer class 89 // inner class
90 classMapping = readClass(parts, false); 90 if (!(mappingStack.peek() instanceof ClassMapping)) {
91 mappings.addClassMapping(classMapping); 91 throw new MappingParseException(file, lineNumber, "Unexpected CLASS entry here!");
92 } else { 92 }
93 93
94 // inner class 94 classMapping = readClass(parts, true);
95 if (!(mappingStack.peek() instanceof ClassMapping)) { 95 ((ClassMapping) mappingStack.peek()).addInnerClassMapping(classMapping);
96 throw new MappingParseException(file, lineNumber, "Unexpected CLASS entry here!"); 96 }
97 } 97 mappingStack.push(classMapping);
98 98 } else if (token.equalsIgnoreCase("FIELD")) {
99 classMapping = readClass(parts, true); 99 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof ClassMapping)) {
100 ((ClassMapping) mappingStack.peek()).addInnerClassMapping(classMapping); 100 throw new MappingParseException(file, lineNumber, "Unexpected FIELD entry here!");
101 } 101 }
102 mappingStack.push(classMapping); 102 ((ClassMapping) mappingStack.peek()).addFieldMapping(readField(parts));
103 } else if (token.equalsIgnoreCase("FIELD")) { 103 } else if (token.equalsIgnoreCase("METHOD")) {
104 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof ClassMapping)) { 104 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof ClassMapping)) {
105 throw new MappingParseException(file, lineNumber, "Unexpected FIELD entry here!"); 105 throw new MappingParseException(file, lineNumber, "Unexpected METHOD entry here!");
106 } 106 }
107 ((ClassMapping) mappingStack.peek()).addFieldMapping(readField(parts)); 107 MethodMapping methodMapping = readMethod(parts);
108 } else if (token.equalsIgnoreCase("METHOD")) { 108 ((ClassMapping) mappingStack.peek()).addMethodMapping(methodMapping);
109 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof ClassMapping)) { 109 mappingStack.push(methodMapping);
110 throw new MappingParseException(file, lineNumber, "Unexpected METHOD entry here!"); 110 } else if (token.equalsIgnoreCase("ARG")) {
111 } 111 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof MethodMapping)) {
112 MethodMapping methodMapping = readMethod(parts); 112 throw new MappingParseException(file, lineNumber, "Unexpected ARG entry here!");
113 ((ClassMapping) mappingStack.peek()).addMethodMapping(methodMapping); 113 }
114 mappingStack.push(methodMapping); 114 ((MethodMapping) mappingStack.peek()).addArgumentMapping(readArgument(parts));
115 } else if (token.equalsIgnoreCase("ARG")) { 115 }
116 if (mappingStack.isEmpty() || !(mappingStack.peek() instanceof MethodMapping)) { 116 } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException ex) {
117 throw new MappingParseException(file, lineNumber, "Unexpected ARG entry here!"); 117 throw new MappingParseException(file, lineNumber, "Malformed line:\n" + line);
118 } 118 } catch (MappingConflict e) {
119 ((MethodMapping) mappingStack.peek()).addArgumentMapping(readArgument(parts)); 119 throw new MappingParseException(file, lineNumber, e.getMessage());
120 } 120 }
121 } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException ex) { 121 }
122 throw new MappingParseException(file, lineNumber, "Malformed line:\n" + line); 122 in.close();
123 } catch (MappingConflict e) { 123 return mappings;
124 throw new MappingParseException(file, lineNumber, e.getMessage()); 124 }
125 } 125
126 } 126 private ArgumentMapping readArgument(String[] parts) {
127 in.close(); 127 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]);
128 return mappings; 128 }
129 } 129
130 130 private ClassMapping readClass(String[] parts, boolean makeSimple) {
131 private ArgumentMapping readArgument(String[] parts) { 131 if (parts.length == 2) {
132 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]); 132 return new ClassMapping(parts[1]);
133 } 133 } else if (parts.length == 3) {
134 134 boolean access = parts[2].startsWith("ACC:");
135 private ClassMapping readClass(String[] parts, boolean makeSimple) { 135 ClassMapping mapping;
136 if (parts.length == 2) { 136 if (access)
137 return new ClassMapping(parts[1]); 137 mapping = new ClassMapping(parts[1], null, Mappings.EntryModifier.valueOf(parts[2].substring(4)));
138 } else if (parts.length == 3) { 138 else
139 boolean access = parts[2].startsWith("ACC:"); 139 mapping = new ClassMapping(parts[1], parts[2]);
140 ClassMapping mapping; 140
141 if (access) 141 return mapping;
142 mapping = new ClassMapping(parts[1], null, Mappings.EntryModifier.valueOf(parts[2].substring(4))); 142 } else if (parts.length == 4)
143 else 143 return new ClassMapping(parts[1], parts[2], Mappings.EntryModifier.valueOf(parts[3].substring(4)));
144 mapping = new ClassMapping(parts[1], parts[2]); 144 return null;
145 145 }
146 return mapping; 146
147 } else if (parts.length == 4) 147 /* TEMP */
148 return new ClassMapping(parts[1], parts[2], Mappings.EntryModifier.valueOf(parts[3].substring(4))); 148 protected FieldMapping readField(String[] parts) {
149 return null; 149 FieldMapping mapping = null;
150 } 150 if (parts.length == 4) {
151 151 boolean access = parts[3].startsWith("ACC:");
152 /* TEMP */ 152 if (access)
153 protected FieldMapping readField(String[] parts) { 153 mapping = new FieldMapping(parts[1], new Type(parts[2]), null,
154 FieldMapping mapping = null; 154 Mappings.EntryModifier.valueOf(parts[3].substring(4)));
155 if (parts.length == 4) 155 else
156 { 156 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED);
157 boolean access = parts[3].startsWith("ACC:"); 157 } else if (parts.length == 5)
158 if (access) 158 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4)));
159 mapping = new FieldMapping(parts[1], new Type(parts[2]), null, 159 return mapping;
160 Mappings.EntryModifier.valueOf(parts[3].substring(4))); 160 }
161 else 161
162 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED); 162 private MethodMapping readMethod(String[] parts) {
163 } 163 MethodMapping mapping = null;
164 else if (parts.length == 5) 164 if (parts.length == 3)
165 mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4))); 165 mapping = new MethodMapping(parts[1], new Signature(parts[2]));
166 return mapping; 166 else if (parts.length == 4) {
167 } 167 boolean access = parts[3].startsWith("ACC:");
168 168 if (access)
169 private MethodMapping readMethod(String[] parts) { 169 mapping = new MethodMapping(parts[1], new Signature(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4)));
170 MethodMapping mapping = null; 170 else
171 if (parts.length == 3) 171 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2]);
172 mapping = new MethodMapping(parts[1], new Signature(parts[2])); 172 } else if (parts.length == 5)
173 else if (parts.length == 4){ 173 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2],
174 boolean access = parts[3].startsWith("ACC:"); 174 Mappings.EntryModifier.valueOf(parts[4].substring(4)));
175 if (access) 175 return mapping;
176 mapping = new MethodMapping(parts[1], new Signature(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4))); 176 }
177 else
178 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2]);
179 }
180 else if (parts.length == 5)
181 mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2],
182 Mappings.EntryModifier.valueOf(parts[4].substring(4)));
183 return mapping;
184 }
185} 177}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
index 6c57200..ba1b258 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java
@@ -4,10 +4,11 @@
4 * are made available under the terms of the GNU Lesser General Public 4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at 5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html 6 * http://www.gnu.org/licenses/lgpl.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.base.Charsets; 14import com.google.common.base.Charsets;
@@ -18,15 +19,13 @@ import java.util.Collections;
18import java.util.List; 19import java.util.List;
19 20
20public class MappingsEnigmaWriter { 21public class MappingsEnigmaWriter {
21 22
22 public void write(File out, Mappings mappings, boolean isDirectoryFormat) throws IOException { 23 public void write(File out, Mappings mappings, boolean isDirectoryFormat) throws IOException {
23 if (!isDirectoryFormat) 24 if (!isDirectoryFormat) {
24 {
25 PrintWriter outputWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(out), Charsets.UTF_8)); 25 PrintWriter outputWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(out), Charsets.UTF_8));
26 write(outputWriter, mappings); 26 write(outputWriter, mappings);
27 outputWriter.close(); 27 outputWriter.close();
28 } 28 } else
29 else
30 writeAsDirectory(out, mappings); 29 writeAsDirectory(out, mappings);
31 } 30 }
32 31
@@ -42,8 +41,7 @@ public class MappingsEnigmaWriter {
42 File result; 41 File result;
43 if (classMapping.getDeobfName() == null) 42 if (classMapping.getDeobfName() == null)
44 result = obFile; 43 result = obFile;
45 else 44 else {
46 {
47 // Make sure that old version of the file doesn't exist 45 // Make sure that old version of the file doesn't exist
48 if (obFile.exists()) 46 if (obFile.exists())
49 obFile.delete(); 47 obFile.delete();
@@ -59,19 +57,16 @@ public class MappingsEnigmaWriter {
59 } 57 }
60 58
61 // Remove dropped mappings 59 // Remove dropped mappings
62 if (mappings.getPreviousState() != null) 60 if (mappings.getPreviousState() != null) {
63 {
64 List<ClassMapping> droppedClassMappings = new ArrayList<>(mappings.getPreviousState().classes()); 61 List<ClassMapping> droppedClassMappings = new ArrayList<>(mappings.getPreviousState().classes());
65 List<ClassMapping> classMappings = new ArrayList<>(mappings.classes()); 62 List<ClassMapping> classMappings = new ArrayList<>(mappings.classes());
66 droppedClassMappings.removeAll(classMappings); 63 droppedClassMappings.removeAll(classMappings);
67 for (ClassMapping classMapping : droppedClassMappings) 64 for (ClassMapping classMapping : droppedClassMappings) {
68 {
69 File obFile = new File(target, classMapping.getObfFullName() + ".mapping"); 65 File obFile = new File(target, classMapping.getObfFullName() + ".mapping");
70 File result; 66 File result;
71 if (classMapping.getDeobfName() == null) 67 if (classMapping.getDeobfName() == null)
72 result = obFile; 68 result = obFile;
73 else 69 else {
74 {
75 // Make sure that old version of the file doesn't exist 70 // Make sure that old version of the file doesn't exist
76 if (obFile.exists()) 71 if (obFile.exists())
77 obFile.delete(); 72 obFile.delete();
@@ -86,18 +81,15 @@ public class MappingsEnigmaWriter {
86 private void deletePreviousClassMapping(File target, ClassMapping classMapping) { 81 private void deletePreviousClassMapping(File target, ClassMapping classMapping) {
87 File prevFile = null; 82 File prevFile = null;
88 // Deob rename 83 // Deob rename
89 if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() != null && !classMapping.getPreviousDeobfName().equals(classMapping.getDeobfName())) 84 if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() != null && !classMapping.getPreviousDeobfName().equals(classMapping.getDeobfName())) {
90 {
91 prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping"); 85 prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping");
92 } 86 }
93 // Deob to ob rename 87 // Deob to ob rename
94 else if (classMapping.getDeobfName() == null && classMapping.getPreviousDeobfName() != null) 88 else if (classMapping.getDeobfName() == null && classMapping.getPreviousDeobfName() != null) {
95 {
96 prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping"); 89 prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping");
97 } 90 }
98 // Ob to Deob rename 91 // Ob to Deob rename
99 else if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() == null) 92 else if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() == null) {
100 {
101 prevFile = new File(target, classMapping.getObfFullName() + ".mapping"); 93 prevFile = new File(target, classMapping.getObfFullName() + ".mapping");
102 } 94 }
103 95
@@ -110,50 +102,56 @@ public class MappingsEnigmaWriter {
110 write(out, classMapping, 0); 102 write(out, classMapping, 0);
111 } 103 }
112 } 104 }
113 105
114 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { 106 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException {
115 if (classMapping.getDeobfName() == null) { 107 if (classMapping.getDeobfName() == null) {
116 out.format("%sCLASS %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName()); 108 out.format("%sCLASS %s%s\n", getIndent(depth), classMapping.getObfFullName(),
109 classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName());
117 } else { 110 } else {
118 out.format("%sCLASS %s %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName()); 111 out.format("%sCLASS %s %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName(),
112 classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName());
119 } 113 }
120 114
121 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { 115 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) {
122 write(out, innerClassMapping, depth + 1); 116 write(out, innerClassMapping, depth + 1);
123 } 117 }
124 118
125 for (FieldMapping fieldMapping : sorted(classMapping.fields())) { 119 for (FieldMapping fieldMapping : sorted(classMapping.fields())) {
126 write(out, fieldMapping, depth + 1); 120 write(out, fieldMapping, depth + 1);
127 } 121 }
128 122
129 for (MethodMapping methodMapping : sorted(classMapping.methods())) { 123 for (MethodMapping methodMapping : sorted(classMapping.methods())) {
130 write(out, methodMapping, depth + 1); 124 write(out, methodMapping, depth + 1);
131 } 125 }
132 } 126 }
133 127
134 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) { 128 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) {
135 if (fieldMapping.getDeobfName() == null) 129 if (fieldMapping.getDeobfName() == null)
136 out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName()); 130 out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfType().toString(),
131 fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
137 else 132 else
138 out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName()); 133 out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString(),
134 fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName());
139 } 135 }
140 136
141 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException { 137 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException {
142 if (methodMapping.getDeobfName() == null) { 138 if (methodMapping.getDeobfName() == null) {
143 out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" :methodMapping.getModifier().getFormattedName()); 139 out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature(),
140 methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName());
144 } else { 141 } else {
145 out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName()); 142 out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature(),
143 methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName());
146 } 144 }
147 145
148 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) { 146 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) {
149 write(out, argumentMapping, depth + 1); 147 write(out, argumentMapping, depth + 1);
150 } 148 }
151 } 149 }
152 150
153 private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) { 151 private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) {
154 out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName()); 152 out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName());
155 } 153 }
156 154
157 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) { 155 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) {
158 List<T> out = new ArrayList<>(); 156 List<T> out = new ArrayList<>();
159 for (T t : classes) { 157 for (T t : classes) {
@@ -162,7 +160,7 @@ public class MappingsEnigmaWriter {
162 Collections.sort(out); 160 Collections.sort(out);
163 return out; 161 return out;
164 } 162 }
165 163
166 private String getIndent(int depth) { 164 private String getIndent(int depth) {
167 StringBuilder buf = new StringBuilder(); 165 StringBuilder buf = new StringBuilder();
168 for (int i = 0; i < depth; i++) { 166 for (int i = 0; i < depth; i++) {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
index e1428ea..7126d2b 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -8,8 +8,14 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
14import com.google.common.collect.Lists;
15import cuchaz.enigma.analysis.JarIndex;
16import cuchaz.enigma.throwables.IllegalNameException;
17import cuchaz.enigma.throwables.MappingConflict;
18
13import java.io.IOException; 19import java.io.IOException;
14import java.io.ObjectOutputStream; 20import java.io.ObjectOutputStream;
15import java.io.OutputStream; 21import java.io.OutputStream;
@@ -17,324 +23,315 @@ import java.util.List;
17import java.util.Set; 23import java.util.Set;
18import java.util.zip.GZIPOutputStream; 24import java.util.zip.GZIPOutputStream;
19 25
20import com.google.common.collect.Lists;
21import cuchaz.enigma.analysis.JarIndex;
22import cuchaz.enigma.throwables.IllegalNameException;
23import cuchaz.enigma.throwables.MappingConflict;
24
25public class MappingsRenamer { 26public class MappingsRenamer {
26 27
27 private JarIndex index; 28 private JarIndex index;
28 private Mappings mappings; 29 private Mappings mappings;
29 30
30 public MappingsRenamer(JarIndex index, Mappings mappings) { 31 public MappingsRenamer(JarIndex index, Mappings mappings) {
31 this.index = index; 32 this.index = index;
32 this.mappings = mappings; 33 this.mappings = mappings;
33 } 34 }
34 35
35 public void setMappings(Mappings mappings) 36 public void setMappings(Mappings mappings) {
36 { 37 this.mappings = mappings;
37 this.mappings = mappings; 38 }
38 } 39
39 40 public void setClassName(ClassEntry obf, String deobfName) {
40 public void setClassName(ClassEntry obf, String deobfName) { 41
41 42 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass());
42 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass()); 43
43 44 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf);
44 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf); 45 if (mappingChain.size() == 1) {
45 if (mappingChain.size() == 1) { 46
46 47 if (deobfName != null) {
47 if (deobfName != null) { 48 // make sure we don't rename to an existing obf or deobf class
48 // make sure we don't rename to an existing obf or deobf class 49 if (mappings.containsDeobfClass(deobfName) || index.containsObfClass(new ClassEntry(deobfName))) {
49 if (mappings.containsDeobfClass(deobfName) || index.containsObfClass(new ClassEntry(deobfName))) { 50 throw new IllegalNameException(deobfName, "There is already a class with that name");
50 throw new IllegalNameException(deobfName, "There is already a class with that name"); 51 }
51 } 52 }
52 } 53
53 54 ClassMapping classMapping = mappingChain.get(0);
54 ClassMapping classMapping = mappingChain.get(0); 55 mappings.setClassDeobfName(classMapping, deobfName);
55 mappings.setClassDeobfName(classMapping, deobfName); 56
56 57 } else {
57 } else { 58
58 59 ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2);
59 ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); 60
60 61 if (deobfName != null) {
61 if (deobfName != null) { 62 // make sure we don't rename to an existing obf or deobf inner class
62 // make sure we don't rename to an existing obf or deobf inner class 63 if (outerClassMapping.hasInnerClassByDeobf(deobfName) || outerClassMapping.hasInnerClassByObfSimple(deobfName)) {
63 if (outerClassMapping.hasInnerClassByDeobf(deobfName) || outerClassMapping.hasInnerClassByObfSimple(deobfName)) { 64 throw new IllegalNameException(deobfName, "There is already a class with that name");
64 throw new IllegalNameException(deobfName, "There is already a class with that name"); 65 }
65 } 66 }
66 } 67
67 68 outerClassMapping.setInnerClassName(obf, deobfName);
68 outerClassMapping.setInnerClassName(obf, deobfName); 69 }
69 } 70 }
70 } 71
71 72 public void removeClassMapping(ClassEntry obf) {
72 public void removeClassMapping(ClassEntry obf) { 73 setClassName(obf, null);
73 setClassName(obf, null); 74 }
74 } 75
75 76 public void markClassAsDeobfuscated(ClassEntry obf) {
76 public void markClassAsDeobfuscated(ClassEntry obf) { 77 String deobfName = obf.isInnerClass() ? obf.getInnermostClassName() : obf.getName();
77 String deobfName = obf.isInnerClass() ? obf.getInnermostClassName() : obf.getName(); 78 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf);
78 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf); 79 if (mappingChain.size() == 1) {
79 if (mappingChain.size() == 1) { 80 ClassMapping classMapping = mappingChain.get(0);
80 ClassMapping classMapping = mappingChain.get(0); 81 mappings.setClassDeobfName(classMapping, deobfName);
81 mappings.setClassDeobfName(classMapping, deobfName); 82 } else {
82 } else { 83 ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2);
83 ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); 84 outerClassMapping.setInnerClassName(obf, deobfName);
84 outerClassMapping.setInnerClassName(obf, deobfName); 85 }
85 } 86 }
86 } 87
87 88 public void setFieldName(FieldEntry obf, String deobfName) {
88 public void setFieldName(FieldEntry obf, String deobfName) { 89 deobfName = NameValidator.validateFieldName(deobfName);
89 deobfName = NameValidator.validateFieldName(deobfName); 90 FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType());
90 FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType()); 91 ClassEntry definedClass = null;
91 ClassEntry definedClass = null; 92 if (mappings.containsDeobfField(obf.getClassEntry(), deobfName) || index.containsEntryWithSameName(targetEntry))
92 if (mappings.containsDeobfField(obf.getClassEntry(), deobfName) || index.containsEntryWithSameName(targetEntry)) 93 definedClass = obf.getClassEntry();
93 definedClass = obf.getClassEntry(); 94 else {
94 else { 95 for (ClassEntry ancestorEntry : this.index.getTranslationIndex().getAncestry(obf.getClassEntry())) {
95 for (ClassEntry ancestorEntry : this.index.getTranslationIndex().getAncestry(obf.getClassEntry())) { 96 if (mappings.containsDeobfField(ancestorEntry, deobfName) || index.containsEntryWithSameName(targetEntry.cloneToNewClass(ancestorEntry))) {
96 if (mappings.containsDeobfField(ancestorEntry, deobfName) || index.containsEntryWithSameName(targetEntry.cloneToNewClass(ancestorEntry))) { 97 definedClass = ancestorEntry;
97 definedClass = ancestorEntry; 98 break;
98 break; 99 }
99 } 100 }
100 } 101 }
101 } 102
102 103 if (definedClass != null) {
103 if (definedClass != null) { 104 String className = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(definedClass.getClassName());
104 String className = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(definedClass.getClassName()); 105 if (className == null)
105 if (className == null) 106 className = definedClass.getClassName();
106 className = definedClass.getClassName(); 107 throw new IllegalNameException(deobfName, "There is already a field with that name in " + className);
107 throw new IllegalNameException(deobfName, "There is already a field with that name in " + className); 108 }
108 } 109
109 110 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
110 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 111 classMapping.setFieldName(obf.getName(), obf.getType(), deobfName);
111 classMapping.setFieldName(obf.getName(), obf.getType(), deobfName); 112 }
112 } 113
113 114 public void removeFieldMapping(FieldEntry obf) {
114 public void removeFieldMapping(FieldEntry obf) { 115 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
115 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 116 classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType()));
116 classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType())); 117 }
117 } 118
118 119 public void markFieldAsDeobfuscated(FieldEntry obf) {
119 public void markFieldAsDeobfuscated(FieldEntry obf) { 120 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
120 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 121 classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName());
121 classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName()); 122 }
122 } 123
123 124 private void validateMethodTreeName(MethodEntry entry, String deobfName) {
124 private void validateMethodTreeName(MethodEntry entry, String deobfName) { 125 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, entry.getSignature());
125 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, entry.getSignature()); 126
126 127 // TODO: Verify if I don't break things
127 // TODO: Verify if I don't break things 128 ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry());
128 ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry()); 129 if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getSignature()) && classMapping.getMethodByObf(entry.getName(), entry.getSignature()) != classMapping.getMethodByDeobf(deobfName, entry.getSignature()))
129 if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getSignature()) && classMapping.getMethodByObf(entry.getName(), entry.getSignature()) != classMapping.getMethodByDeobf(deobfName, entry.getSignature())) 130 || index.containsObfBehavior(targetEntry)) {
130 || index.containsObfBehavior(targetEntry)) { 131 String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(entry.getClassName());
131 String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(entry.getClassName()); 132 if (deobfClassName == null) {
132 if (deobfClassName == null) { 133 deobfClassName = entry.getClassName();
133 deobfClassName = entry.getClassName(); 134 }
134 } 135 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
135 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); 136 }
136 } 137
137 138 for (ClassEntry child : index.getTranslationIndex().getSubclass(entry.getClassEntry())) {
138 for (ClassEntry child : index.getTranslationIndex().getSubclass(entry.getClassEntry())) { 139 validateMethodTreeName(entry.cloneToNewClass(child), deobfName);
139 validateMethodTreeName(entry.cloneToNewClass(child), deobfName); 140 }
140 } 141 }
141 } 142
142 143 public void setMethodTreeName(MethodEntry obf, String deobfName) {
143 public void setMethodTreeName(MethodEntry obf, String deobfName) { 144 Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obf);
144 Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obf); 145
145 146 deobfName = NameValidator.validateMethodName(deobfName);
146 deobfName = NameValidator.validateMethodName(deobfName); 147 for (MethodEntry entry : implementations) {
147 for (MethodEntry entry : implementations) { 148 validateMethodTreeName(entry, deobfName);
148 validateMethodTreeName(entry, deobfName); 149 }
149 } 150
150 151 for (MethodEntry entry : implementations) {
151 for (MethodEntry entry : implementations) { 152 setMethodName(entry, deobfName);
152 setMethodName(entry, deobfName); 153 }
153 } 154 }
154 } 155
155 156 public void setMethodName(MethodEntry obf, String deobfName) {
156 public void setMethodName(MethodEntry obf, String deobfName) { 157 deobfName = NameValidator.validateMethodName(deobfName);
157 deobfName = NameValidator.validateMethodName(deobfName); 158 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature());
158 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); 159 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
159 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 160
160 161 // TODO: Verify if I don't break things
161 // TODO: Verify if I don't break things 162 if ((mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) && classMapping.getMethodByObf(obf.getName(), obf.getSignature()) != classMapping.getMethodByDeobf(deobfName, obf.getSignature()))
162 if ((mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) && classMapping.getMethodByObf(obf.getName(), obf.getSignature()) != classMapping.getMethodByDeobf(deobfName, obf.getSignature())) 163 || index.containsObfBehavior(targetEntry)) {
163 || index.containsObfBehavior(targetEntry)) { 164 String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(obf.getClassName());
164 String deobfClassName = mappings.getTranslator(TranslationDirection.Deobfuscating, index.getTranslationIndex()).translateClass(obf.getClassName()); 165 if (deobfClassName == null) {
165 if (deobfClassName == null) { 166 deobfClassName = obf.getClassName();
166 deobfClassName = obf.getClassName(); 167 }
167 } 168 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
168 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); 169 }
169 } 170
170 171 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
171 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName); 172 }
172 } 173
173 174 public void removeMethodTreeMapping(MethodEntry obf) {
174 public void removeMethodTreeMapping(MethodEntry obf) { 175 index.getRelatedMethodImplementations(obf).forEach(this::removeMethodMapping);
175 index.getRelatedMethodImplementations(obf).forEach(this::removeMethodMapping); 176 }
176 } 177
177 178 public void removeMethodMapping(MethodEntry obf) {
178 public void removeMethodMapping(MethodEntry obf) { 179 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
179 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 180 classMapping.setMethodName(obf.getName(), obf.getSignature(), null);
180 classMapping.setMethodName(obf.getName(), obf.getSignature(), null); 181 }
181 } 182
182 183 public void markMethodTreeAsDeobfuscated(MethodEntry obf) {
183 public void markMethodTreeAsDeobfuscated(MethodEntry obf) { 184 index.getRelatedMethodImplementations(obf).forEach(this::markMethodAsDeobfuscated);
184 index.getRelatedMethodImplementations(obf).forEach(this::markMethodAsDeobfuscated); 185 }
185 } 186
186 187 public void markMethodAsDeobfuscated(MethodEntry obf) {
187 public void markMethodAsDeobfuscated(MethodEntry obf) { 188 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
188 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 189 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName());
189 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName()); 190 }
190 } 191
191 192 public void setArgumentTreeName(ArgumentEntry obf, String deobfName) {
192 public void setArgumentTreeName(ArgumentEntry obf, String deobfName) { 193 if (!(obf.getBehaviorEntry() instanceof MethodEntry)) {
193 if (!(obf.getBehaviorEntry() instanceof MethodEntry)) { 194 setArgumentName(obf, deobfName);
194 setArgumentName(obf, deobfName); 195 return;
195 return; 196 }
196 } 197
197 198 MethodEntry obfMethod = (MethodEntry) obf.getBehaviorEntry();
198 MethodEntry obfMethod = (MethodEntry) obf.getBehaviorEntry(); 199
199 200 Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obfMethod);
200 Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obfMethod); 201 for (MethodEntry entry : implementations) {
201 for (MethodEntry entry : implementations) { 202 ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry());
202 ClassMapping classMapping = mappings.getClassByObf(entry.getClassEntry()); 203 if (classMapping != null) {
203 if (classMapping != null) { 204 MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getSignature());
204 MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getSignature()); 205 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
205 // NOTE: don't need to check arguments for name collisions with names determined by Procyon 206 // TODO: Verify if I don't break things
206 // TODO: Verify if I don't break things 207 if (mapping != null) {
207 if (mapping != null) { 208 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
208 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) { 209 if (argumentMapping.getIndex() != obf.getIndex()) {
209 if (argumentMapping.getIndex() != obf.getIndex()) { 210 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
210 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName) 211 || argumentMapping.getName().equals(deobfName)) {
211 || argumentMapping.getName().equals(deobfName)) { 212 throw new IllegalNameException(deobfName, "There is already an argument with that name");
212 throw new IllegalNameException(deobfName, "There is already an argument with that name"); 213 }
213 } 214 }
214 } 215 }
215 } 216 }
216 } 217 }
217 } 218 }
218 } 219
219 220 for (MethodEntry entry : implementations) {
220 for (MethodEntry entry : implementations) { 221 setArgumentName(new ArgumentEntry(obf, entry), deobfName);
221 setArgumentName(new ArgumentEntry(obf, entry), deobfName); 222 }
222 } 223 }
223 } 224
224 225 public void setArgumentName(ArgumentEntry obf, String deobfName) {
225 public void setArgumentName(ArgumentEntry obf, String deobfName) { 226 deobfName = NameValidator.validateArgumentName(deobfName);
226 deobfName = NameValidator.validateArgumentName(deobfName); 227 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
227 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 228 MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodSignature());
228 MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodSignature()); 229 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
229 // NOTE: don't need to check arguments for name collisions with names determined by Procyon 230 // TODO: Verify if I don't break things
230 // TODO: Verify if I don't break things 231 if (mapping != null) {
231 if (mapping != null) { 232 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) {
232 for (ArgumentMapping argumentMapping : Lists.newArrayList(mapping.arguments())) { 233 if (argumentMapping.getIndex() != obf.getIndex()) {
233 if (argumentMapping.getIndex() != obf.getIndex()) { 234 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName)
234 if (mapping.getDeobfArgumentName(argumentMapping.getIndex()).equals(deobfName) 235 || argumentMapping.getName().equals(deobfName)) {
235 || argumentMapping.getName().equals(deobfName)) { 236 throw new IllegalNameException(deobfName, "There is already an argument with that name");
236 throw new IllegalNameException(deobfName, "There is already an argument with that name"); 237 }
237 } 238 }
238 } 239 }
239 } 240 }
240 } 241
241 242 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
242 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName); 243 }
243 } 244
244 245 public void removeArgumentMapping(ArgumentEntry obf) {
245 public void removeArgumentMapping(ArgumentEntry obf) { 246 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
246 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 247 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex());
247 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex()); 248 }
248 } 249
249 250 public void markArgumentAsDeobfuscated(ArgumentEntry obf) {
250 public void markArgumentAsDeobfuscated(ArgumentEntry obf) { 251 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry());
251 ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); 252 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
252 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); 253 }
253 } 254
254 255 public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) {
255 public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) { 256 classMapping.removeFieldMapping(fieldMapping);
256 classMapping.removeFieldMapping(fieldMapping); 257 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
257 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); 258 if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfType())) {
258 if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfType())) { 259 if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfType())) {
259 if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfType())) { 260 targetClassMapping.addFieldMapping(fieldMapping);
260 targetClassMapping.addFieldMapping(fieldMapping); 261 return true;
261 return true; 262 } else {
262 } else { 263 System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName());
263 System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName()); 264 }
264 } 265 }
265 } 266 return false;
266 return false; 267 }
267 } 268
268 269 public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) {
269 public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) { 270 classMapping.removeMethodMapping(methodMapping);
270 classMapping.removeMethodMapping(methodMapping); 271 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
271 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); 272 if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) {
272 if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) { 273 if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) {
273 if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) { 274 targetClassMapping.addMethodMapping(methodMapping);
274 targetClassMapping.addMethodMapping(methodMapping); 275 return true;
275 return true; 276 } else {
276 } else { 277 System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature());
277 System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature()); 278 }
278 } 279 }
279 } 280 return false;
280 return false; 281 }
281 } 282
282 283 public void write(OutputStream out) throws IOException {
283 public void write(OutputStream out) throws IOException { 284 // TEMP: just use the object output for now. We can find a more efficient storage format later
284 // TEMP: just use the object output for now. We can find a more efficient storage format later 285 GZIPOutputStream gzipout = new GZIPOutputStream(out);
285 GZIPOutputStream gzipout = new GZIPOutputStream(out); 286 ObjectOutputStream oout = new ObjectOutputStream(gzipout);
286 ObjectOutputStream oout = new ObjectOutputStream(gzipout); 287 oout.writeObject(this);
287 oout.writeObject(this); 288 gzipout.finish();
288 gzipout.finish(); 289 }
289 } 290
290 291 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) {
291 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { 292 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry);
292 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry); 293 return mappingChain.get(mappingChain.size() - 1);
293 return mappingChain.get(mappingChain.size() - 1); 294 }
294 } 295
295 296 private List<ClassMapping> getOrCreateClassMappingChain(ClassEntry obfClassEntry) {
296 private List<ClassMapping> getOrCreateClassMappingChain(ClassEntry obfClassEntry) { 297 List<ClassEntry> classChain = obfClassEntry.getClassChain();
297 List<ClassEntry> classChain = obfClassEntry.getClassChain(); 298 List<ClassMapping> mappingChain = mappings.getClassMappingChain(obfClassEntry);
298 List<ClassMapping> mappingChain = mappings.getClassMappingChain(obfClassEntry); 299 for (int i = 0; i < classChain.size(); i++) {
299 for (int i = 0; i < classChain.size(); i++) { 300 ClassEntry classEntry = classChain.get(i);
300 ClassEntry classEntry = classChain.get(i); 301 ClassMapping classMapping = mappingChain.get(i);
301 ClassMapping classMapping = mappingChain.get(i); 302 if (classMapping == null) {
302 if (classMapping == null) { 303
303 304 // create it
304 // create it 305 classMapping = new ClassMapping(classEntry.getName());
305 classMapping = new ClassMapping(classEntry.getName()); 306 mappingChain.set(i, classMapping);
306 mappingChain.set(i, classMapping); 307
307 308 // add it to the right parent
308 // add it to the right parent 309 try {
309 try { 310 if (i == 0) {
310 if (i == 0) { 311 mappings.addClassMapping(classMapping);
311 mappings.addClassMapping(classMapping); 312 } else {
312 } else { 313 mappingChain.get(i - 1).addInnerClassMapping(classMapping);
313 mappingChain.get(i - 1).addInnerClassMapping(classMapping); 314 }
314 } 315 } catch (MappingConflict mappingConflict) {
315 } catch (MappingConflict mappingConflict) { 316 mappingConflict.printStackTrace();
316 mappingConflict.printStackTrace(); 317 }
317 } 318 }
318 } 319 }
319 } 320 return mappingChain;
320 return mappingChain; 321 }
321 } 322
322 323 public void setClassModifier(ClassEntry obEntry, Mappings.EntryModifier modifier) {
323 public void setClassModifier(ClassEntry obEntry, Mappings.EntryModifier modifier) 324 ClassMapping classMapping = getOrCreateClassMapping(obEntry);
324 { 325 classMapping.setModifier(modifier);
325 ClassMapping classMapping = getOrCreateClassMapping(obEntry); 326 }
326 classMapping.setModifier(modifier); 327
327 } 328 public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier) {
328 329 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
329 public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier) 330 classMapping.setFieldModifier(obEntry.getName(), obEntry.getType(), modifier);
330 { 331 }
331 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry()); 332
332 classMapping.setFieldModifier(obEntry.getName(), obEntry.getType(), modifier); 333 public void setMethodModifier(BehaviorEntry obEntry, Mappings.EntryModifier modifier) {
333 } 334 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
334 335 classMapping.setMethodModifier(obEntry.getName(), obEntry.getSignature(), modifier);
335 public void setMethodModifier(BehaviorEntry obEntry, Mappings.EntryModifier modifier) 336 }
336 {
337 ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry());
338 classMapping.setMethodModifier(obEntry.getName(), obEntry.getSignature(), modifier);
339 }
340} 337}
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
index a3f0cc8..b0eb826 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java
@@ -13,69 +13,67 @@ import java.util.List;
13 */ 13 */
14public class MappingsSRGWriter { 14public class MappingsSRGWriter {
15 15
16 public void write(File file, Mappings mappings) throws IOException { 16 public void write(File file, Mappings mappings) throws IOException {
17 if(file.exists()){ 17 if (file.exists()) {
18 file.delete(); 18 file.delete();
19 } 19 }
20 file.createNewFile(); 20 file.createNewFile();
21 21
22 TranslationIndex index = new TranslationIndex(); 22 TranslationIndex index = new TranslationIndex();
23 23
24 PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8)); 24 PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), Charsets.UTF_8));
25 List<String> fieldMappings = new ArrayList<>(); 25 List<String> fieldMappings = new ArrayList<>();
26 List<String> methodMappings = new ArrayList<>(); 26 List<String> methodMappings = new ArrayList<>();
27 for (ClassMapping classMapping : sorted(mappings.classes())) { 27 for (ClassMapping classMapping : sorted(mappings.classes())) {
28 if(classMapping.getDeobfName() == null || classMapping.getObfSimpleName() == null || classMapping.getDeobfName() == null){ 28 if (classMapping.getDeobfName() == null || classMapping.getObfSimpleName() == null || classMapping.getDeobfName() == null) {
29 continue; 29 continue;
30 } 30 }
31 writer.write("CL: " + classMapping.getObfSimpleName() + " " + classMapping.getDeobfName()); 31 writer.write("CL: " + classMapping.getObfSimpleName() + " " + classMapping.getDeobfName());
32 writer.write(System.lineSeparator()); 32 writer.write(System.lineSeparator());
33 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { 33 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) {
34 if(innerClassMapping.getDeobfName() == null || innerClassMapping.getObfSimpleName() == null || innerClassMapping.getDeobfName() == null){ 34 if (innerClassMapping.getDeobfName() == null || innerClassMapping.getObfSimpleName() == null || innerClassMapping.getDeobfName() == null) {
35 continue; 35 continue;
36 } 36 }
37 String innerClassName = classMapping.getObfSimpleName() + "$" + innerClassMapping.getObfSimpleName(); 37 String innerClassName = classMapping.getObfSimpleName() + "$" + innerClassMapping.getObfSimpleName();
38 String innerDeobfClassName = classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName(); 38 String innerDeobfClassName = classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName();
39 writer.write("CL: " + innerClassName + " " + classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName()); 39 writer.write("CL: " + innerClassName + " " + classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName());
40 writer.write(System.lineSeparator()); 40 writer.write(System.lineSeparator());
41 for (FieldMapping fieldMapping : sorted(innerClassMapping.fields())) { 41 for (FieldMapping fieldMapping : sorted(innerClassMapping.fields())) {
42 fieldMappings.add("FD: " + innerClassName + "/" + fieldMapping.getObfName() + " " + innerDeobfClassName + "/" + fieldMapping.getDeobfName()); 42 fieldMappings.add("FD: " + innerClassName + "/" + fieldMapping.getObfName() + " " + innerDeobfClassName + "/" + fieldMapping.getDeobfName());
43 } 43 }
44 44
45 for (MethodMapping methodMapping : sorted(innerClassMapping.methods())) { 45 for (MethodMapping methodMapping : sorted(innerClassMapping.methods())) {
46 methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString() + " " + innerDeobfClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); 46 methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature() + " " + innerDeobfClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature()));
47 } 47 }
48 } 48 }
49 49
50 for (FieldMapping fieldMapping : sorted(classMapping.fields())) { 50 for (FieldMapping fieldMapping : sorted(classMapping.fields())) {
51 fieldMappings.add("FD: " + classMapping.getObfFullName() + "/" + fieldMapping.getObfName() + " " + classMapping.getDeobfName() + "/" + fieldMapping.getDeobfName()); 51 fieldMappings.add("FD: " + classMapping.getObfFullName() + "/" + fieldMapping.getObfName() + " " + classMapping.getDeobfName() + "/" + fieldMapping.getDeobfName());
52 } 52 }
53 53
54 for (MethodMapping methodMapping : sorted(classMapping.methods())) { 54 for (MethodMapping methodMapping : sorted(classMapping.methods())) {
55 methodMappings.add("MD: " + classMapping.getObfFullName() + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString() + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); 55 methodMappings.add("MD: " + classMapping.getObfFullName() + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature() + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature()));
56 } 56 }
57 } 57 }
58 for(String fd : fieldMappings){ 58 for (String fd : fieldMappings) {
59 writer.write(fd); 59 writer.write(fd);
60 writer.write(System.lineSeparator()); 60 writer.write(System.lineSeparator());
61 } 61 }
62 62
63 for(String md : methodMappings){ 63 for (String md : methodMappings) {
64 writer.write(md); 64 writer.write(md);
65 writer.write(System.lineSeparator()); 65 writer.write(System.lineSeparator());
66 } 66 }
67 67
68 writer.close();
69 }
68 70
69 writer.close(); 71 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) {
70 } 72 List<T> out = new ArrayList<>();
71 73 for (T t : classes) {
72 74 out.add(t);
73 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) { 75 }
74 List<T> out = new ArrayList<>(); 76 Collections.sort(out);
75 for (T t : classes) { 77 return out;
76 out.add(t); 78 }
77 }
78 Collections.sort(out);
79 return out;
80 }
81} 79}
diff --git a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
index 90c096f..d4514d4 100644
--- a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
@@ -8,11 +8,11 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12 11
12package cuchaz.enigma.mapping;
13 13
14public interface MemberMapping<T extends Entry> { 14public interface MemberMapping<T extends Entry> {
15 T getObfEntry(ClassEntry classEntry); 15 T getObfEntry(ClassEntry classEntry);
16 16
17 String getObfName(); 17 String getObfName();
18} 18}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
index 4d7ed8f..9c3058c 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java
@@ -8,82 +8,83 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import cuchaz.enigma.utils.Utils; 14import cuchaz.enigma.utils.Utils;
14 15
15public class MethodEntry implements BehaviorEntry { 16public class MethodEntry implements BehaviorEntry {
16 17
17 private ClassEntry classEntry; 18 private ClassEntry classEntry;
18 private String name; 19 private String name;
19 private Signature signature; 20 private Signature signature;
20 21
21 public MethodEntry(ClassEntry classEntry, String name, Signature signature) { 22 public MethodEntry(ClassEntry classEntry, String name, Signature signature) {
22 if (classEntry == null) { 23 if (classEntry == null) {
23 throw new IllegalArgumentException("Class cannot be null!"); 24 throw new IllegalArgumentException("Class cannot be null!");
24 } 25 }
25 if (name == null) { 26 if (name == null) {
26 throw new IllegalArgumentException("Method name cannot be null!"); 27 throw new IllegalArgumentException("Method name cannot be null!");
27 } 28 }
28 if (signature == null) { 29 if (signature == null) {
29 throw new IllegalArgumentException("Method signature cannot be null!"); 30 throw new IllegalArgumentException("Method signature cannot be null!");
30 } 31 }
31 if (name.startsWith("<")) { 32 if (name.startsWith("<")) {
32 throw new IllegalArgumentException("Don't use MethodEntry for a constructor!"); 33 throw new IllegalArgumentException("Don't use MethodEntry for a constructor!");
33 } 34 }
34 35
35 this.classEntry = classEntry; 36 this.classEntry = classEntry;
36 this.name = name; 37 this.name = name;
37 this.signature = signature; 38 this.signature = signature;
38 } 39 }
39 40
40 public MethodEntry(MethodEntry other, String newClassName) { 41 public MethodEntry(MethodEntry other, String newClassName) {
41 this.classEntry = new ClassEntry(newClassName); 42 this.classEntry = new ClassEntry(newClassName);
42 this.name = other.name; 43 this.name = other.name;
43 this.signature = other.signature; 44 this.signature = other.signature;
44 } 45 }
45 46
46 @Override 47 @Override
47 public ClassEntry getClassEntry() { 48 public ClassEntry getClassEntry() {
48 return this.classEntry; 49 return this.classEntry;
49 } 50 }
50 51
51 @Override 52 @Override
52 public String getName() { 53 public String getName() {
53 return this.name; 54 return this.name;
54 } 55 }
55 56
56 @Override 57 @Override
57 public Signature getSignature() { 58 public Signature getSignature() {
58 return this.signature; 59 return this.signature;
59 } 60 }
60 61
61 @Override 62 @Override
62 public String getClassName() { 63 public String getClassName() {
63 return this.classEntry.getName(); 64 return this.classEntry.getName();
64 } 65 }
65 66
66 @Override 67 @Override
67 public MethodEntry cloneToNewClass(ClassEntry classEntry) { 68 public MethodEntry cloneToNewClass(ClassEntry classEntry) {
68 return new MethodEntry(this, classEntry.getName()); 69 return new MethodEntry(this, classEntry.getName());
69 } 70 }
70 71
71 @Override 72 @Override
72 public int hashCode() { 73 public int hashCode() {
73 return Utils.combineHashesOrdered(this.classEntry, this.name, this.signature); 74 return Utils.combineHashesOrdered(this.classEntry, this.name, this.signature);
74 } 75 }
75 76
76 @Override 77 @Override
77 public boolean equals(Object other) { 78 public boolean equals(Object other) {
78 return other instanceof MethodEntry && equals((MethodEntry) other); 79 return other instanceof MethodEntry && equals((MethodEntry) other);
79 } 80 }
80 81
81 public boolean equals(MethodEntry other) { 82 public boolean equals(MethodEntry other) {
82 return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.signature.equals(other.signature); 83 return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.signature.equals(other.signature);
83 } 84 }
84 85
85 @Override 86 @Override
86 public String toString() { 87 public String toString() {
87 return this.classEntry.getName() + "." + this.name + this.signature; 88 return this.classEntry.getName() + "." + this.name + this.signature;
88 } 89 }
89} 90}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
index e0aeea2..1524ce6 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
@@ -8,211 +8,206 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Maps; 14import com.google.common.collect.Maps;
14
15import java.util.Map;
16
17import cuchaz.enigma.throwables.IllegalNameException; 15import cuchaz.enigma.throwables.IllegalNameException;
18import cuchaz.enigma.throwables.MappingConflict; 16import cuchaz.enigma.throwables.MappingConflict;
19 17
18import java.util.Map;
19
20public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<BehaviorEntry> { 20public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<BehaviorEntry> {
21 21
22 private String obfName; 22 private String obfName;
23 private String deobfName; 23 private String deobfName;
24 private Signature obfSignature; 24 private Signature obfSignature;
25 private Map<Integer, ArgumentMapping> arguments; 25 private Map<Integer, ArgumentMapping> arguments;
26 private Mappings.EntryModifier modifier; 26 private Mappings.EntryModifier modifier;
27 27
28 public MethodMapping(String obfName, Signature obfSignature) { 28 public MethodMapping(String obfName, Signature obfSignature) {
29 this(obfName, obfSignature, null,Mappings.EntryModifier.UNCHANGED); 29 this(obfName, obfSignature, null, Mappings.EntryModifier.UNCHANGED);
30 } 30 }
31 31
32 public MethodMapping(String obfName, Signature obfSignature, String deobfName) { 32 public MethodMapping(String obfName, Signature obfSignature, String deobfName) {
33 this(obfName, obfSignature, deobfName, Mappings.EntryModifier.UNCHANGED); 33 this(obfName, obfSignature, deobfName, Mappings.EntryModifier.UNCHANGED);
34 } 34 }
35 35
36 public MethodMapping(String obfName, Signature obfSignature, String deobfName, Mappings.EntryModifier modifier) { 36 public MethodMapping(String obfName, Signature obfSignature, String deobfName, Mappings.EntryModifier modifier) {
37 if (obfName == null) { 37 if (obfName == null) {
38 throw new IllegalArgumentException("obf name cannot be null!"); 38 throw new IllegalArgumentException("obf name cannot be null!");
39 } 39 }
40 if (obfSignature == null) { 40 if (obfSignature == null) {
41 throw new IllegalArgumentException("obf signature cannot be null!"); 41 throw new IllegalArgumentException("obf signature cannot be null!");
42 } 42 }
43 this.obfName = obfName; 43 this.obfName = obfName;
44 this.deobfName = NameValidator.validateMethodName(deobfName); 44 this.deobfName = NameValidator.validateMethodName(deobfName);
45 this.obfSignature = obfSignature; 45 this.obfSignature = obfSignature;
46 this.arguments = Maps.newTreeMap(); 46 this.arguments = Maps.newTreeMap();
47 this.modifier = modifier; 47 this.modifier = modifier;
48 } 48 }
49 49
50 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { 50 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) {
51 this.obfName = other.obfName; 51 this.obfName = other.obfName;
52 this.deobfName = other.deobfName; 52 this.deobfName = other.deobfName;
53 this.modifier = other.modifier; 53 this.modifier = other.modifier;
54 this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer); 54 this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer);
55 this.arguments = Maps.newTreeMap(); 55 this.arguments = Maps.newTreeMap();
56 for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) { 56 for (Map.Entry<Integer, ArgumentMapping> entry : other.arguments.entrySet()) {
57 this.arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue())); 57 this.arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue()));
58 } 58 }
59 } 59 }
60 60
61 @Override 61 @Override
62 public String getObfName() { 62 public String getObfName() {
63 return this.obfName; 63 return this.obfName;
64 } 64 }
65 65
66 public String getDeobfName() { 66 public void setObfName(String name) {
67 return this.deobfName; 67 try {
68 } 68 NameValidator.validateMethodName(name);
69 69 } catch (IllegalNameException ex) {
70 public void setDeobfName(String val) { 70 // Invalid name, damn obfuscation! Map to a deob name with another name to avoid issues
71 this.deobfName = NameValidator.validateMethodName(val); 71 if (this.deobfName == null) {
72 } 72 System.err.println("WARNING: " + name + " is conflicting, auto deobfuscate to " + (name + "_auto_deob"));
73 73 setDeobfName(name + "_auto_deob");
74 public Signature getObfSignature() { 74 }
75 return this.obfSignature; 75 }
76 } 76 this.obfName = name;
77 77 }
78 public void setObfName(String name) { 78
79 try 79 public String getDeobfName() {
80 { 80 return this.deobfName;
81 NameValidator.validateMethodName(name); 81 }
82 } catch (IllegalNameException ex) 82
83 { 83 public void setDeobfName(String val) {
84 // Invalid name, damn obfuscation! Map to a deob name with another name to avoid issues 84 this.deobfName = NameValidator.validateMethodName(val);
85 if (this.deobfName == null) 85 }
86 { 86
87 System.err.println("WARNING: " + name + " is conflicting, auto deobfuscate to " + (name + "_auto_deob")); 87 public Signature getObfSignature() {
88 setDeobfName(name + "_auto_deob"); 88 return this.obfSignature;
89 } 89 }
90 } 90
91 this.obfName = name; 91 public void setObfSignature(Signature val) {
92 } 92 this.obfSignature = val;
93 93 }
94 public void setObfSignature(Signature val) { 94
95 this.obfSignature = val; 95 public Iterable<ArgumentMapping> arguments() {
96 } 96 return this.arguments.values();
97 97 }
98 public Iterable<ArgumentMapping> arguments() { 98
99 return this.arguments.values(); 99 public void addArgumentMapping(ArgumentMapping argumentMapping) throws MappingConflict {
100 } 100 if (this.arguments.containsKey(argumentMapping.getIndex())) {
101 101 throw new MappingConflict("argument", argumentMapping.getName(), this.arguments.get(argumentMapping.getIndex()).getName());
102 public void addArgumentMapping(ArgumentMapping argumentMapping) throws MappingConflict { 102 }
103 if (this.arguments.containsKey(argumentMapping.getIndex())) { 103 this.arguments.put(argumentMapping.getIndex(), argumentMapping);
104 throw new MappingConflict("argument", argumentMapping.getName(), this.arguments.get(argumentMapping.getIndex()).getName()); 104 }
105 } 105
106 this.arguments.put(argumentMapping.getIndex(), argumentMapping); 106 public String getObfArgumentName(int index) {
107 } 107 ArgumentMapping argumentMapping = this.arguments.get(index);
108 108 if (argumentMapping != null) {
109 public String getObfArgumentName(int index) { 109 return argumentMapping.getName();
110 ArgumentMapping argumentMapping = this.arguments.get(index); 110 }
111 if (argumentMapping != null) { 111
112 return argumentMapping.getName(); 112 return null;
113 } 113 }
114 114
115 return null; 115 public String getDeobfArgumentName(int index) {
116 } 116 ArgumentMapping argumentMapping = this.arguments.get(index);
117 117 if (argumentMapping != null) {
118 public String getDeobfArgumentName(int index) { 118 return argumentMapping.getName();
119 ArgumentMapping argumentMapping = this.arguments.get(index); 119 }
120 if (argumentMapping != null) { 120
121 return argumentMapping.getName(); 121 return null;
122 } 122 }
123 123
124 return null; 124 public void setArgumentName(int index, String name) {
125 } 125 ArgumentMapping argumentMapping = this.arguments.get(index);
126 126 if (argumentMapping == null) {
127 public void setArgumentName(int index, String name) { 127 argumentMapping = new ArgumentMapping(index, name);
128 ArgumentMapping argumentMapping = this.arguments.get(index); 128 boolean wasAdded = this.arguments.put(index, argumentMapping) == null;
129 if (argumentMapping == null) { 129 assert (wasAdded);
130 argumentMapping = new ArgumentMapping(index, name); 130 } else {
131 boolean wasAdded = this.arguments.put(index, argumentMapping) == null; 131 argumentMapping.setName(name);
132 assert (wasAdded); 132 }
133 } else { 133 }
134 argumentMapping.setName(name); 134
135 } 135 public void removeArgumentName(int index) {
136 } 136 boolean wasRemoved = this.arguments.remove(index) != null;
137 137 assert (wasRemoved);
138 public void removeArgumentName(int index) { 138 }
139 boolean wasRemoved = this.arguments.remove(index) != null; 139
140 assert (wasRemoved); 140 @Override
141 } 141 public String toString() {
142 142 StringBuilder buf = new StringBuilder();
143 @Override 143 buf.append("\t");
144 public String toString() { 144 buf.append(this.obfName);
145 StringBuilder buf = new StringBuilder(); 145 buf.append(" <-> ");
146 buf.append("\t"); 146 buf.append(this.deobfName);
147 buf.append(this.obfName); 147 buf.append("\n");
148 buf.append(" <-> "); 148 buf.append("\t");
149 buf.append(this.deobfName); 149 buf.append(this.obfSignature);
150 buf.append("\n"); 150 buf.append("\n");
151 buf.append("\t"); 151 buf.append("\tArguments:\n");
152 buf.append(this.obfSignature); 152 for (ArgumentMapping argumentMapping : this.arguments.values()) {
153 buf.append("\n"); 153 buf.append("\t\t");
154 buf.append("\tArguments:\n"); 154 buf.append(argumentMapping.getIndex());
155 for (ArgumentMapping argumentMapping : this.arguments.values()) { 155 buf.append(" -> ");
156 buf.append("\t\t"); 156 buf.append(argumentMapping.getName());
157 buf.append(argumentMapping.getIndex()); 157 buf.append("\n");
158 buf.append(" -> "); 158 }
159 buf.append(argumentMapping.getName()); 159 return buf.toString();
160 buf.append("\n"); 160 }
161 } 161
162 return buf.toString(); 162 @Override
163 } 163 public int compareTo(MethodMapping other) {
164 164 return (this.obfName + this.obfSignature).compareTo(other.obfName + other.obfSignature);
165 @Override 165 }
166 public int compareTo(MethodMapping other) { 166
167 return (this.obfName + this.obfSignature).compareTo(other.obfName + other.obfSignature); 167 public boolean containsArgument(String name) {
168 } 168 for (ArgumentMapping argumentMapping : this.arguments.values()) {
169 169 if (argumentMapping.getName().equals(name)) {
170 public boolean containsArgument(String name) { 170 return true;
171 for (ArgumentMapping argumentMapping : this.arguments.values()) { 171 }
172 if (argumentMapping.getName().equals(name)) { 172 }
173 return true; 173 return false;
174 } 174 }
175 } 175
176 return false; 176 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
177 } 177 // rename obf classes in the signature
178 178 Signature newSignature = new Signature(this.obfSignature, className ->
179 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { 179 {
180 // rename obf classes in the signature 180 if (className.equals(oldObfClassName)) {
181 Signature newSignature = new Signature(this.obfSignature, className -> 181 return newObfClassName;
182 { 182 }
183 if (className.equals(oldObfClassName)) { 183 return null;
184 return newObfClassName; 184 });
185 } 185
186 return null; 186 if (!newSignature.equals(this.obfSignature)) {
187 }); 187 this.obfSignature = newSignature;
188 188 return true;
189 if (!newSignature.equals(this.obfSignature)) { 189 }
190 this.obfSignature = newSignature; 190 return false;
191 return true; 191 }
192 } 192
193 return false; 193 public boolean isConstructor() {
194 } 194 return this.obfName.startsWith("<");
195 195 }
196 public boolean isConstructor() { 196
197 return this.obfName.startsWith("<"); 197 @Override
198 } 198 public BehaviorEntry getObfEntry(ClassEntry classEntry) {
199 199 if (isConstructor()) {
200 @Override 200 return new ConstructorEntry(classEntry, this.obfSignature);
201 public BehaviorEntry getObfEntry(ClassEntry classEntry) { 201 } else {
202 if (isConstructor()) { 202 return new MethodEntry(classEntry, this.obfName, this.obfSignature);
203 return new ConstructorEntry(classEntry, this.obfSignature); 203 }
204 } else { 204 }
205 return new MethodEntry(classEntry, this.obfName, this.obfSignature); 205
206 } 206 public Mappings.EntryModifier getModifier() {
207 } 207 return modifier;
208 208 }
209 public Mappings.EntryModifier getModifier() 209
210 { 210 public void setModifier(Mappings.EntryModifier modifier) {
211 return modifier; 211 this.modifier = modifier;
212 } 212 }
213
214 public void setModifier(Mappings.EntryModifier modifier)
215 {
216 this.modifier = modifier;
217 }
218} 213}
diff --git a/src/main/java/cuchaz/enigma/mapping/NameValidator.java b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
index 6925b72..aa3dc4d 100644
--- a/src/main/java/cuchaz/enigma/mapping/NameValidator.java
+++ b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
@@ -8,61 +8,62 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
14import cuchaz.enigma.throwables.IllegalNameException;
15import javassist.bytecode.Descriptor;
16
13import java.util.Arrays; 17import java.util.Arrays;
14import java.util.List; 18import java.util.List;
15import java.util.regex.Pattern; 19import java.util.regex.Pattern;
16 20
17import cuchaz.enigma.throwables.IllegalNameException;
18import javassist.bytecode.Descriptor;
19
20public class NameValidator { 21public class NameValidator {
21 22
22 private static final Pattern IdentifierPattern; 23 private static final Pattern IdentifierPattern;
23 private static final Pattern ClassPattern; 24 private static final Pattern ClassPattern;
24 private static final List<String> ReservedWords = Arrays.asList( 25 private static final List<String> ReservedWords = Arrays.asList(
25 "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", 26 "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized",
26 "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", 27 "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte",
27 "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", 28 "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch",
28 "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", 29 "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
29 "long", "strictfp", "volatile", "const", "float", "native", "super", "while" 30 "long", "strictfp", "volatile", "const", "float", "native", "super", "while"
30 ); 31 );
31 32
32 static { 33 static {
33 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; 34 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*";
34 IdentifierPattern = Pattern.compile(identifierRegex); 35 IdentifierPattern = Pattern.compile(identifierRegex);
35 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex)); 36 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex));
36 } 37 }
37 38
38 public static String validateClassName(String name, boolean packageRequired) { 39 public static String validateClassName(String name, boolean packageRequired) {
39 if (name == null) { 40 if (name == null) {
40 return null; 41 return null;
41 } 42 }
42 if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) { 43 if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) {
43 throw new IllegalNameException(name, "This doesn't look like a legal class name"); 44 throw new IllegalNameException(name, "This doesn't look like a legal class name");
44 } 45 }
45 if (packageRequired && new ClassEntry(name).getPackageName() == null) { 46 if (packageRequired && new ClassEntry(name).getPackageName() == null) {
46 throw new IllegalNameException(name, "Class must be in a package"); 47 throw new IllegalNameException(name, "Class must be in a package");
47 } 48 }
48 return Descriptor.toJvmName(name); 49 return Descriptor.toJvmName(name);
49 } 50 }
50 51
51 public static String validateFieldName(String name) { 52 public static String validateFieldName(String name) {
52 if (name == null) { 53 if (name == null) {
53 return null; 54 return null;
54 } 55 }
55 if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) { 56 if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) {
56 throw new IllegalNameException(name, "This doesn't look like a legal identifier"); 57 throw new IllegalNameException(name, "This doesn't look like a legal identifier");
57 } 58 }
58 return name; 59 return name;
59 } 60 }
60 61
61 public static String validateMethodName(String name) { 62 public static String validateMethodName(String name) {
62 return validateFieldName(name); 63 return validateFieldName(name);
63 } 64 }
64 65
65 public static String validateArgumentName(String name) { 66 public static String validateArgumentName(String name) {
66 return validateFieldName(name); 67 return validateFieldName(name);
67 } 68 }
68} 69}
diff --git a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
index 51fed83..33d930d 100644
--- a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
+++ b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.strobel.assembler.metadata.*; 14import com.strobel.assembler.metadata.*;
@@ -16,57 +17,51 @@ import java.util.List;
16 17
17public class ProcyonEntryFactory { 18public class ProcyonEntryFactory {
18 19
19 private static String getErasedSignature(MemberReference def) 20 private static String getErasedSignature(MemberReference def) {
20 { 21 if (!(def instanceof MethodReference))
21 if (!(def instanceof MethodReference)) 22 return def.getErasedSignature();
22 return def.getErasedSignature(); 23 MethodReference methodReference = (MethodReference) def;
23 MethodReference methodReference = (MethodReference) def; 24 StringBuilder builder = new StringBuilder("(");
24 StringBuilder builder = new StringBuilder("("); 25 for (ParameterDefinition param : methodReference.getParameters()) {
25 for (ParameterDefinition param : methodReference.getParameters()) 26 TypeReference paramType = param.getParameterType();
26 { 27 if (paramType.getErasedSignature().equals("Ljava/lang/Object;") && paramType.hasExtendsBound() && paramType.getExtendsBound() instanceof CompoundTypeReference) {
27 TypeReference paramType = param.getParameterType(); 28 List<TypeReference> interfaces = ((CompoundTypeReference) paramType.getExtendsBound()).getInterfaces();
28 if (paramType.getErasedSignature().equals("Ljava/lang/Object;") && paramType.hasExtendsBound() && paramType.getExtendsBound() instanceof CompoundTypeReference) 29 interfaces.forEach((inter) -> builder.append(inter.getErasedSignature()));
29 { 30 } else
30 List<TypeReference> interfaces = ((CompoundTypeReference) paramType.getExtendsBound()).getInterfaces(); 31 builder.append(paramType.getErasedSignature());
31 interfaces.forEach((inter) -> builder.append(inter.getErasedSignature())); 32 }
32 } 33 builder.append(")");
33 else
34 builder.append(paramType.getErasedSignature());
35 }
36 builder.append(")");
37 34
38 TypeReference returnType = methodReference.getReturnType(); 35 TypeReference returnType = methodReference.getReturnType();
39 if (returnType.getErasedSignature().equals("Ljava/lang/Object;") && returnType.hasExtendsBound() && returnType.getExtendsBound() instanceof CompoundTypeReference) 36 if (returnType.getErasedSignature().equals("Ljava/lang/Object;") && returnType.hasExtendsBound() && returnType.getExtendsBound() instanceof CompoundTypeReference) {
40 { 37 List<TypeReference> interfaces = ((CompoundTypeReference) returnType.getExtendsBound()).getInterfaces();
41 List<TypeReference> interfaces = ((CompoundTypeReference) returnType.getExtendsBound()).getInterfaces(); 38 interfaces.forEach((inter) -> builder.append(inter.getErasedSignature()));
42 interfaces.forEach((inter) -> builder.append(inter.getErasedSignature())); 39 } else
43 } 40 builder.append(returnType.getErasedSignature());
44 else 41 return builder.toString();
45 builder.append(returnType.getErasedSignature()); 42 }
46 return builder.toString();
47 }
48 43
49 public static FieldEntry getFieldEntry(MemberReference def) { 44 public static FieldEntry getFieldEntry(MemberReference def) {
50 return new FieldEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Type(def.getErasedSignature())); 45 return new FieldEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Type(def.getErasedSignature()));
51 } 46 }
52 47
53 public static MethodEntry getMethodEntry(MemberReference def) { 48 public static MethodEntry getMethodEntry(MemberReference def) {
54 return new MethodEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Signature(getErasedSignature(def))); 49 return new MethodEntry(new ClassEntry(def.getDeclaringType().getInternalName()), def.getName(), new Signature(getErasedSignature(def)));
55 } 50 }
56 51
57 public static ConstructorEntry getConstructorEntry(MethodReference def) { 52 public static ConstructorEntry getConstructorEntry(MethodReference def) {
58 if (def.isTypeInitializer()) { 53 if (def.isTypeInitializer()) {
59 return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName())); 54 return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()));
60 } else { 55 } else {
61 return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()), new Signature(def.getErasedSignature())); 56 return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()), new Signature(def.getErasedSignature()));
62 } 57 }
63 } 58 }
64 59
65 public static BehaviorEntry getBehaviorEntry(MethodReference def) { 60 public static BehaviorEntry getBehaviorEntry(MethodReference def) {
66 if (def.isConstructor() || def.isTypeInitializer()) { 61 if (def.isConstructor() || def.isTypeInitializer()) {
67 return getConstructorEntry(def); 62 return getConstructorEntry(def);
68 } else { 63 } else {
69 return getMethodEntry(def); 64 return getMethodEntry(def);
70 } 65 }
71 } 66 }
72} 67}
diff --git a/src/main/java/cuchaz/enigma/mapping/Signature.java b/src/main/java/cuchaz/enigma/mapping/Signature.java
index f30b606..78130d6 100644
--- a/src/main/java/cuchaz/enigma/mapping/Signature.java
+++ b/src/main/java/cuchaz/enigma/mapping/Signature.java
@@ -8,99 +8,99 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
15import cuchaz.enigma.utils.Utils;
14 16
15import java.util.List; 17import java.util.List;
16 18
17import cuchaz.enigma.utils.Utils;
18
19public class Signature { 19public class Signature {
20 20
21 private List<Type> argumentTypes; 21 private List<Type> argumentTypes;
22 private Type returnType; 22 private Type returnType;
23 23
24 public Signature(String signature) { 24 public Signature(String signature) {
25 try { 25 try {
26 this.argumentTypes = Lists.newArrayList(); 26 this.argumentTypes = Lists.newArrayList();
27 int i = 0; 27 int i = 0;
28 while (i < signature.length()) { 28 while (i < signature.length()) {
29 char c = signature.charAt(i); 29 char c = signature.charAt(i);
30 if (c == '(') { 30 if (c == '(') {
31 assert (this.argumentTypes.isEmpty()); 31 assert (this.argumentTypes.isEmpty());
32 assert (this.returnType == null); 32 assert (this.returnType == null);
33 i++; 33 i++;
34 } else if (c == ')') { 34 } else if (c == ')') {
35 i++; 35 i++;
36 break; 36 break;
37 } else { 37 } else {
38 String type = Type.parseFirst(signature.substring(i)); 38 String type = Type.parseFirst(signature.substring(i));
39 this.argumentTypes.add(new Type(type)); 39 this.argumentTypes.add(new Type(type));
40 i += type.length(); 40 i += type.length();
41 } 41 }
42 } 42 }
43 this.returnType = new Type(Type.parseFirst(signature.substring(i))); 43 this.returnType = new Type(Type.parseFirst(signature.substring(i)));
44 } catch (Exception ex) { 44 } catch (Exception ex) {
45 throw new IllegalArgumentException("Unable to parse signature: " + signature, ex); 45 throw new IllegalArgumentException("Unable to parse signature: " + signature, ex);
46 } 46 }
47 } 47 }
48 48
49 public Signature(Signature other, ClassNameReplacer replacer) { 49 public Signature(Signature other, ClassNameReplacer replacer) {
50 this.argumentTypes = Lists.newArrayList(other.argumentTypes); 50 this.argumentTypes = Lists.newArrayList(other.argumentTypes);
51 for (int i = 0; i < this.argumentTypes.size(); i++) { 51 for (int i = 0; i < this.argumentTypes.size(); i++) {
52 this.argumentTypes.set(i, new Type(this.argumentTypes.get(i), replacer)); 52 this.argumentTypes.set(i, new Type(this.argumentTypes.get(i), replacer));
53 } 53 }
54 this.returnType = new Type(other.returnType, replacer); 54 this.returnType = new Type(other.returnType, replacer);
55 } 55 }
56 56
57 public List<Type> getArgumentTypes() { 57 public List<Type> getArgumentTypes() {
58 return this.argumentTypes; 58 return this.argumentTypes;
59 } 59 }
60 60
61 public Type getReturnType() { 61 public Type getReturnType() {
62 return this.returnType; 62 return this.returnType;
63 } 63 }
64 64
65 @Override 65 @Override
66 public String toString() { 66 public String toString() {
67 StringBuilder buf = new StringBuilder(); 67 StringBuilder buf = new StringBuilder();
68 buf.append("("); 68 buf.append("(");
69 for (Type type : this.argumentTypes) { 69 for (Type type : this.argumentTypes) {
70 buf.append(type.toString()); 70 buf.append(type);
71 } 71 }
72 buf.append(")"); 72 buf.append(")");
73 buf.append(this.returnType.toString()); 73 buf.append(this.returnType);
74 return buf.toString(); 74 return buf.toString();
75 } 75 }
76 76
77 public Iterable<Type> types() { 77 public Iterable<Type> types() {
78 List<Type> types = Lists.newArrayList(); 78 List<Type> types = Lists.newArrayList();
79 types.addAll(this.argumentTypes); 79 types.addAll(this.argumentTypes);
80 types.add(this.returnType); 80 types.add(this.returnType);
81 return types; 81 return types;
82 } 82 }
83 83
84 @Override 84 @Override
85 public boolean equals(Object other) { 85 public boolean equals(Object other) {
86 return other instanceof Signature && equals((Signature) other); 86 return other instanceof Signature && equals((Signature) other);
87 } 87 }
88 88
89 public boolean equals(Signature other) { 89 public boolean equals(Signature other) {
90 return this.argumentTypes.equals(other.argumentTypes) && this.returnType.equals(other.returnType); 90 return this.argumentTypes.equals(other.argumentTypes) && this.returnType.equals(other.returnType);
91 } 91 }
92 92
93 @Override 93 @Override
94 public int hashCode() { 94 public int hashCode() {
95 return Utils.combineHashesOrdered(this.argumentTypes.hashCode(), this.returnType.hashCode()); 95 return Utils.combineHashesOrdered(this.argumentTypes.hashCode(), this.returnType.hashCode());
96 } 96 }
97 97
98 public boolean hasClass(ClassEntry classEntry) { 98 public boolean hasClass(ClassEntry classEntry) {
99 for (Type type : types()) { 99 for (Type type : types()) {
100 if (type.hasClass() && type.getClassEntry().equals(classEntry)) { 100 if (type.hasClass() && type.getClassEntry().equals(classEntry)) {
101 return true; 101 return true;
102 } 102 }
103 } 103 }
104 return false; 104 return false;
105 } 105 }
106} 106}
diff --git a/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java b/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java
index 9864333..ddc5af4 100644
--- a/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java
+++ b/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
@@ -18,74 +19,74 @@ import java.util.List;
18 19
19public class SignatureUpdater { 20public class SignatureUpdater {
20 21
21 public interface ClassNameUpdater { 22 public static String update(String signature, ClassNameUpdater updater) {
22 String update(String className); 23 try {
23 } 24 StringBuilder buf = new StringBuilder();
24 25
25 public static String update(String signature, ClassNameUpdater updater) { 26 // read the signature character-by-character
26 try { 27 StringReader reader = new StringReader(signature);
27 StringBuilder buf = new StringBuilder(); 28 int i;
29 while ((i = reader.read()) != -1) {
30 char c = (char) i;
28 31
29 // read the signature character-by-character 32 // does this character start a class name?
30 StringReader reader = new StringReader(signature); 33 if (c == 'L') {
31 int i; 34 // update the class name and add it to the buffer
32 while ((i = reader.read()) != -1) { 35 buf.append('L');
33 char c = (char) i; 36 String className = readClass(reader);
37 if (className == null) {
38 throw new IllegalArgumentException("Malformed signature: " + signature);
39 }
40 buf.append(updater.update(className));
41 buf.append(';');
42 } else {
43 // copy the character into the buffer
44 buf.append(c);
45 }
46 }
34 47
35 // does this character start a class name? 48 return buf.toString();
36 if (c == 'L') { 49 } catch (IOException ex) {
37 // update the class name and add it to the buffer 50 // I'm pretty sure a StringReader will never throw one of these
38 buf.append('L'); 51 throw new Error(ex);
39 String className = readClass(reader); 52 }
40 if (className == null) { 53 }
41 throw new IllegalArgumentException("Malformed signature: " + signature);
42 }
43 buf.append(updater.update(className));
44 buf.append(';');
45 } else {
46 // copy the character into the buffer
47 buf.append(c);
48 }
49 }
50 54
51 return buf.toString(); 55 private static String readClass(StringReader reader) throws IOException {
52 } catch (IOException ex) { 56 // read all the characters in the buffer until we hit a ';'
53 // I'm pretty sure a StringReader will never throw one of these 57 // remember to treat generics correctly
54 throw new Error(ex); 58 StringBuilder buf = new StringBuilder();
55 } 59 int depth = 0;
56 } 60 int i;
61 while ((i = reader.read()) != -1) {
62 char c = (char) i;
57 63
58 private static String readClass(StringReader reader) throws IOException { 64 if (c == '<') {
59 // read all the characters in the buffer until we hit a ';' 65 depth++;
60 // remember to treat generics correctly 66 } else if (c == '>') {
61 StringBuilder buf = new StringBuilder(); 67 depth--;
62 int depth = 0; 68 } else if (depth == 0) {
63 int i; 69 if (c == ';') {
64 while ((i = reader.read()) != -1) { 70 return buf.toString();
65 char c = (char) i; 71 } else {
72 buf.append(c);
73 }
74 }
75 }
66 76
67 if (c == '<') { 77 return null;
68 depth++; 78 }
69 } else if (c == '>') {
70 depth--;
71 } else if (depth == 0) {
72 if (c == ';') {
73 return buf.toString();
74 } else {
75 buf.append(c);
76 }
77 }
78 }
79 79
80 return null; 80 public static List<String> getClasses(String signature) {
81 } 81 final List<String> classNames = Lists.newArrayList();
82 update(signature, className -> {
83 classNames.add(className);
84 return className;
85 });
86 return classNames;
87 }
82 88
83 public static List<String> getClasses(String signature) { 89 public interface ClassNameUpdater {
84 final List<String> classNames = Lists.newArrayList(); 90 String update(String className);
85 update(signature, className -> { 91 }
86 classNames.add(className);
87 return className;
88 });
89 return classNames;
90 }
91} 92}
diff --git a/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java b/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
index 8329d0d..17e3187 100644
--- a/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
+++ b/src/main/java/cuchaz/enigma/mapping/TranslationDirection.java
@@ -8,22 +8,23 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13public enum TranslationDirection { 14public enum TranslationDirection {
14 15
15 Deobfuscating { 16 Deobfuscating {
16 @Override 17 @Override
17 public <T> T choose(T deobfChoice, T obfChoice) { 18 public <T> T choose(T deobfChoice, T obfChoice) {
18 return deobfChoice; 19 return deobfChoice;
19 } 20 }
20 }, 21 },
21 Obfuscating { 22 Obfuscating {
22 @Override 23 @Override
23 public <T> T choose(T deobfChoice, T obfChoice) { 24 public <T> T choose(T deobfChoice, T obfChoice) {
24 return obfChoice; 25 return obfChoice;
25 } 26 }
26 }; 27 };
27 28
28 public abstract <T> T choose(T deobfChoice, T obfChoice); 29 public abstract <T> T choose(T deobfChoice, T obfChoice);
29} 30}
diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java
index e94009e..8d464fc 100644
--- a/src/main/java/cuchaz/enigma/mapping/Translator.java
+++ b/src/main/java/cuchaz/enigma/mapping/Translator.java
@@ -8,348 +8,335 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
16import cuchaz.enigma.analysis.TranslationIndex;
15 17
16import java.util.List; 18import java.util.List;
17import java.util.Map; 19import java.util.Map;
18 20
19import cuchaz.enigma.analysis.TranslationIndex;
20
21public class Translator { 21public class Translator {
22 22
23 private TranslationDirection direction; 23 private TranslationDirection direction;
24 private Map<String, ClassMapping> classes; 24 private Map<String, ClassMapping> classes;
25 private TranslationIndex index; 25 private TranslationIndex index;
26 26
27 private ClassNameReplacer classNameReplacer = className -> translateEntry(new ClassEntry(className)).getName(); 27 private ClassNameReplacer classNameReplacer = className -> translateEntry(new ClassEntry(className)).getName();
28 28
29 public Translator() { 29 public Translator() {
30 this.direction = null; 30 this.direction = null;
31 this.classes = Maps.newHashMap(); 31 this.classes = Maps.newHashMap();
32 this.index = new TranslationIndex(); 32 this.index = new TranslationIndex();
33 } 33 }
34 34
35 public Translator(TranslationDirection direction, Map<String, ClassMapping> classes, TranslationIndex index) { 35 public Translator(TranslationDirection direction, Map<String, ClassMapping> classes, TranslationIndex index) {
36 this.direction = direction; 36 this.direction = direction;
37 this.classes = classes; 37 this.classes = classes;
38 this.index = index; 38 this.index = index;
39 } 39 }
40 40
41 public TranslationDirection getDirection() { 41 public TranslationDirection getDirection() {
42 return direction; 42 return direction;
43 } 43 }
44 44
45 public TranslationIndex getTranslationIndex() { 45 public TranslationIndex getTranslationIndex() {
46 return index; 46 return index;
47 } 47 }
48 48
49 @SuppressWarnings("unchecked") 49 @SuppressWarnings("unchecked")
50 public <T extends Entry> T translateEntry(T entry) { 50 public <T extends Entry> T translateEntry(T entry) {
51 if (entry instanceof ClassEntry) { 51 if (entry instanceof ClassEntry) {
52 return (T) translateEntry((ClassEntry) entry); 52 return (T) translateEntry((ClassEntry) entry);
53 } else if (entry instanceof FieldEntry) { 53 } else if (entry instanceof FieldEntry) {
54 return (T) translateEntry((FieldEntry) entry); 54 return (T) translateEntry((FieldEntry) entry);
55 } else if (entry instanceof MethodEntry) { 55 } else if (entry instanceof MethodEntry) {
56 return (T) translateEntry((MethodEntry) entry); 56 return (T) translateEntry((MethodEntry) entry);
57 } else if (entry instanceof ConstructorEntry) { 57 } else if (entry instanceof ConstructorEntry) {
58 return (T) translateEntry((ConstructorEntry) entry); 58 return (T) translateEntry((ConstructorEntry) entry);
59 } else if (entry instanceof ArgumentEntry) { 59 } else if (entry instanceof ArgumentEntry) {
60 return (T) translateEntry((ArgumentEntry) entry); 60 return (T) translateEntry((ArgumentEntry) entry);
61 } else if (entry instanceof LocalVariableEntry) { 61 } else if (entry instanceof LocalVariableEntry) {
62 return (T) translateEntry((LocalVariableEntry) entry); 62 return (T) translateEntry((LocalVariableEntry) entry);
63 } else { 63 } else {
64 throw new Error("Unknown entry type: " + entry.getClass().getName()); 64 throw new Error("Unknown entry type: " + entry.getClass().getName());
65 } 65 }
66 } 66 }
67 67
68 public <T extends Entry> String translate(T entry) { 68 public <T extends Entry> String translate(T entry) {
69 if (entry instanceof ClassEntry) { 69 if (entry instanceof ClassEntry) {
70 return translate((ClassEntry) entry); 70 return translate((ClassEntry) entry);
71 } else if (entry instanceof FieldEntry) { 71 } else if (entry instanceof FieldEntry) {
72 return translate((FieldEntry) entry); 72 return translate((FieldEntry) entry);
73 } else if (entry instanceof MethodEntry) { 73 } else if (entry instanceof MethodEntry) {
74 return translate((MethodEntry) entry); 74 return translate((MethodEntry) entry);
75 } else if (entry instanceof ConstructorEntry) { 75 } else if (entry instanceof ConstructorEntry) {
76 return translate(entry); 76 return translate(entry);
77 } else if (entry instanceof ArgumentEntry) { 77 } else if (entry instanceof ArgumentEntry) {
78 return translate((ArgumentEntry) entry); 78 return translate((ArgumentEntry) entry);
79 } else if (entry instanceof LocalVariableEntry) { 79 } else if (entry instanceof LocalVariableEntry) {
80 return translate((LocalVariableEntry) entry); 80 return translate((LocalVariableEntry) entry);
81 } else { 81 } else {
82 throw new Error("Unknown entry type: " + entry.getClass().getName()); 82 throw new Error("Unknown entry type: " + entry.getClass().getName());
83 } 83 }
84 } 84 }
85 85
86 public String translate(LocalVariableEntry in) 86 public String translate(LocalVariableEntry in) {
87 { 87 LocalVariableEntry translated = translateEntry(in);
88 LocalVariableEntry translated = translateEntry(in); 88 if (translated.equals(in)) {
89 if (translated.equals(in)) { 89 return null;
90 return null; 90 }
91 } 91 return translated.getName();
92 return translated.getName(); 92 }
93 } 93
94 94 public LocalVariableEntry translateEntry(LocalVariableEntry in) {
95 public LocalVariableEntry translateEntry(LocalVariableEntry in) 95 // TODO: Implement it
96 { 96 return in;
97 // TODO: Implement it 97 }
98 return in; 98
99 } 99 public String translate(ClassEntry in) {
100 100 ClassEntry translated = translateEntry(in);
101 public String translate(ClassEntry in) { 101 if (translated.equals(in)) {
102 ClassEntry translated = translateEntry(in); 102 return null;
103 if (translated.equals(in)) { 103 }
104 return null; 104 return translated.getName();
105 } 105 }
106 return translated.getName(); 106
107 } 107 public String translateClass(String className) {
108 108 return translate(new ClassEntry(className));
109 public String translateClass(String className) { 109 }
110 return translate(new ClassEntry(className)); 110
111 } 111 public ClassEntry translateEntry(ClassEntry in) {
112 112
113 public ClassEntry translateEntry(ClassEntry in) { 113 if (in.isInnerClass()) {
114 114
115 if (in.isInnerClass()) { 115 // translate as much of the class chain as we can
116 116 List<ClassMapping> mappingsChain = getClassMappingChain(in);
117 // translate as much of the class chain as we can 117 String[] obfClassNames = in.getName().split("\\$");
118 List<ClassMapping> mappingsChain = getClassMappingChain(in); 118 StringBuilder buf = new StringBuilder();
119 String[] obfClassNames = in.getName().split("\\$"); 119 for (int i = 0; i < obfClassNames.length; i++) {
120 StringBuilder buf = new StringBuilder(); 120 boolean isFirstClass = buf.length() == 0;
121 for (int i = 0; i < obfClassNames.length; i++) { 121 String className = null;
122 boolean isFirstClass = buf.length() == 0; 122 ClassMapping classMapping = mappingsChain.get(i);
123 String className = null; 123 if (classMapping != null) {
124 ClassMapping classMapping = mappingsChain.get(i); 124 className = this.direction.choose(
125 if (classMapping != null) { 125 classMapping.getDeobfName(),
126 className = this.direction.choose( 126 isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName()
127 classMapping.getDeobfName(), 127 );
128 isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName() 128 }
129 ); 129 if (className == null) {
130 } 130 className = obfClassNames[i];
131 if (className == null) { 131 }
132 className = obfClassNames[i]; 132 if (!isFirstClass) {
133 } 133 buf.append("$");
134 if (!isFirstClass) { 134 }
135 buf.append("$"); 135 buf.append(className);
136 } 136 }
137 buf.append(className); 137 return new ClassEntry(buf.toString());
138 } 138
139 return new ClassEntry(buf.toString()); 139 } else {
140 140
141 } else { 141 // normal classes are easy
142 142 ClassMapping classMapping = this.classes.get(in.getName());
143 // normal classes are easy 143 if (classMapping == null) {
144 ClassMapping classMapping = this.classes.get(in.getName()); 144 return in;
145 if (classMapping == null) { 145 }
146 return in; 146 return this.direction.choose(
147 } 147 classMapping.getDeobfName() != null ? new ClassEntry(classMapping.getDeobfName()) : in,
148 return this.direction.choose( 148 new ClassEntry(classMapping.getObfFullName())
149 classMapping.getDeobfName() != null ? new ClassEntry(classMapping.getDeobfName()) : in, 149 );
150 new ClassEntry(classMapping.getObfFullName()) 150 }
151 ); 151 }
152 } 152
153 } 153 public String translate(FieldEntry in) {
154 154
155 public String translate(FieldEntry in) { 155 // resolve the class entry
156 156 ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in);
157 // resolve the class entry 157 if (resolvedClassEntry != null) {
158 ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in); 158
159 if (resolvedClassEntry != null) { 159 // look for the class
160 160 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
161 // look for the class 161 if (classMapping != null) {
162 ClassMapping classMapping = findClassMapping(resolvedClassEntry); 162
163 if (classMapping != null) { 163 // look for the field
164 164 String translatedName = this.direction.choose(
165 // look for the field 165 classMapping.getDeobfFieldName(in.getName(), in.getType()),
166 String translatedName = this.direction.choose( 166 classMapping.getObfFieldName(in.getName(), translateType(in.getType()))
167 classMapping.getDeobfFieldName(in.getName(), in.getType()), 167 );
168 classMapping.getObfFieldName(in.getName(), translateType(in.getType())) 168 if (translatedName != null) {
169 ); 169 return translatedName;
170 if (translatedName != null) { 170 }
171 return translatedName; 171 }
172 } 172 }
173 } 173 return null;
174 } 174 }
175 return null; 175
176 } 176 public FieldEntry translateEntry(FieldEntry in) {
177 177 String name = translate(in);
178 public FieldEntry translateEntry(FieldEntry in) { 178 if (name == null) {
179 String name = translate(in); 179 name = in.getName();
180 if (name == null) { 180 }
181 name = in.getName(); 181 return new FieldEntry(translateEntry(in.getClassEntry()), name, translateType(in.getType()));
182 } 182 }
183 return new FieldEntry(translateEntry(in.getClassEntry()), name, translateType(in.getType())); 183
184 } 184 public String translate(MethodEntry in) {
185 185 // resolve the class entry
186 public String translate(MethodEntry in) { 186 ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in, true);
187 // resolve the class entry 187 if (resolvedClassEntry != null) {
188 ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in, true); 188
189 if (resolvedClassEntry != null) { 189 // look for class
190 190 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
191 // look for class 191 if (classMapping != null) {
192 ClassMapping classMapping = findClassMapping(resolvedClassEntry); 192
193 if (classMapping != null) { 193 // look for the method
194 194 MethodMapping methodMapping = this.direction.choose(
195 // look for the method 195 classMapping.getMethodByObf(in.getName(), in.getSignature()),
196 MethodMapping methodMapping = this.direction.choose( 196 classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))
197 classMapping.getMethodByObf(in.getName(), in.getSignature()), 197 );
198 classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature())) 198 if (methodMapping != null) {
199 ); 199 return this.direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName());
200 if (methodMapping != null) { 200 }
201 return this.direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); 201 }
202 } 202 }
203 } 203 return null;
204 } 204 }
205 return null; 205
206 } 206 public MethodEntry translateEntry(MethodEntry in) {
207 207 String name = translate(in);
208 public MethodEntry translateEntry(MethodEntry in) { 208 if (name == null) {
209 String name = translate(in); 209 name = in.getName();
210 if (name == null) { 210 }
211 name = in.getName(); 211 return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature()));
212 } 212 }
213 return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature())); 213
214 } 214 public ConstructorEntry translateEntry(ConstructorEntry in) {
215 215 if (in.isStatic()) {
216 public ConstructorEntry translateEntry(ConstructorEntry in) { 216 return new ConstructorEntry(translateEntry(in.getClassEntry()));
217 if (in.isStatic()) { 217 } else {
218 return new ConstructorEntry(translateEntry(in.getClassEntry())); 218 return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature()));
219 } else { 219 }
220 return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature())); 220 }
221 } 221
222 } 222 public BehaviorEntry translateEntry(BehaviorEntry in) {
223 223 if (in instanceof MethodEntry) {
224 public BehaviorEntry translateEntry(BehaviorEntry in) { 224 return translateEntry((MethodEntry) in);
225 if (in instanceof MethodEntry) { 225 } else if (in instanceof ConstructorEntry) {
226 return translateEntry((MethodEntry) in); 226 return translateEntry((ConstructorEntry) in);
227 } else if (in instanceof ConstructorEntry) { 227 }
228 return translateEntry((ConstructorEntry) in); 228 throw new Error("Wrong entry type!");
229 } 229 }
230 throw new Error("Wrong entry type!"); 230
231 } 231 // TODO: support not identical behavior (specific to constructor)
232 232 public String translate(ArgumentEntry in) {
233 // TODO: support not identical behavior (specific to constructor) 233 String classTranslate = translateArgument(in);
234 public String translate(ArgumentEntry in) 234
235 { 235 // Not found in this class
236 String classTranslate = translateArgument(in); 236 if (classTranslate == null) {
237 237 List<ClassEntry> ancestry = this.index.getAncestry(in.getClassEntry());
238 // Not found in this class 238
239 if (classTranslate == null) 239 // Check in mother class for the arg
240 { 240 for (ClassEntry entry : ancestry) {
241 List<ClassEntry> ancestry = this.index.getAncestry(in.getClassEntry()); 241 ArgumentEntry motherArg = in.cloneToNewClass(entry);
242 242 if (this.index.entryExists(motherArg)) {
243 // Check in mother class for the arg 243 String result = translateArgument(motherArg);
244 for (ClassEntry entry : ancestry) 244 if (result != null)
245 { 245 return result;
246 ArgumentEntry motherArg = in.cloneToNewClass(entry); 246 }
247 if (this.index.entryExists(motherArg)) 247 }
248 { 248 }
249 String result = translateArgument(motherArg); 249 return classTranslate;
250 if (result != null) 250 }
251 return result; 251
252 } 252 public String translateArgument(ArgumentEntry in) {
253 } 253 // look for identical behavior in superclasses
254 } 254 ClassEntry entry = in.getClassEntry();
255 return classTranslate; 255
256 } 256 if (entry != null) {
257 257 // look for the class
258 public String translateArgument(ArgumentEntry in) { 258 ClassMapping classMapping = findClassMapping(entry);
259 // look for identical behavior in superclasses 259 if (classMapping != null) {
260 ClassEntry entry = in.getClassEntry(); 260
261 261 // look for the method
262 if (entry != null) 262 MethodMapping methodMapping = this.direction.choose(
263 { 263 classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()),
264 // look for the class 264 classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature()))
265 ClassMapping classMapping = findClassMapping(entry); 265 );
266 if (classMapping != null) { 266 if (methodMapping != null) {
267 267 return this.direction.choose(
268 // look for the method 268 methodMapping.getDeobfArgumentName(in.getIndex()),
269 MethodMapping methodMapping = this.direction.choose( 269 methodMapping.getObfArgumentName(in.getIndex())
270 classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()), 270 );
271 classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature())) 271 }
272 ); 272 }
273 if (methodMapping != null) { 273 }
274 return this.direction.choose( 274 return null;
275 methodMapping.getDeobfArgumentName(in.getIndex()), 275 }
276 methodMapping.getObfArgumentName(in.getIndex()) 276
277 ); 277 public ArgumentEntry translateEntry(ArgumentEntry in) {
278 } 278 String name = translate(in);
279 } 279 if (name == null) {
280 } 280 name = in.getName();
281 return null; 281 }
282 } 282 return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name);
283 283 }
284 public ArgumentEntry translateEntry(ArgumentEntry in) { 284
285 String name = translate(in); 285 public Type translateType(Type type) {
286 if (name == null) { 286 return new Type(type, this.classNameReplacer);
287 name = in.getName(); 287 }
288 } 288
289 return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name); 289 public Signature translateSignature(Signature signature) {
290 } 290 return new Signature(signature, this.classNameReplacer);
291 291 }
292 public Type translateType(Type type) { 292
293 return new Type(type, this.classNameReplacer); 293 private ClassMapping findClassMapping(ClassEntry in) {
294 } 294 List<ClassMapping> mappingChain = getClassMappingChain(in);
295 295 return mappingChain.get(mappingChain.size() - 1);
296 public Signature translateSignature(Signature signature) { 296 }
297 return new Signature(signature, this.classNameReplacer); 297
298 } 298 private List<ClassMapping> getClassMappingChain(ClassEntry in) {
299 299
300 private ClassMapping findClassMapping(ClassEntry in) { 300 // get a list of all the classes in the hierarchy
301 List<ClassMapping> mappingChain = getClassMappingChain(in); 301 String[] parts = in.getName().split("\\$");
302 return mappingChain.get(mappingChain.size() - 1); 302 List<ClassMapping> mappingsChain = Lists.newArrayList();
303 } 303
304 304 // get mappings for the outer class
305 private List<ClassMapping> getClassMappingChain(ClassEntry in) { 305 ClassMapping outerClassMapping = this.classes.get(parts[0]);
306 306 mappingsChain.add(outerClassMapping);
307 // get a list of all the classes in the hierarchy 307
308 String[] parts = in.getName().split("\\$"); 308 for (int i = 1; i < parts.length; i++) {
309 List<ClassMapping> mappingsChain = Lists.newArrayList(); 309
310 310 // get mappings for the inner class
311 // get mappings for the outer class 311 ClassMapping innerClassMapping = null;
312 ClassMapping outerClassMapping = this.classes.get(parts[0]); 312 if (outerClassMapping != null) {
313 mappingsChain.add(outerClassMapping); 313 innerClassMapping = this.direction.choose(
314 314 outerClassMapping.getInnerClassByObfSimple(parts[i]),
315 for (int i = 1; i < parts.length; i++) { 315 outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i])
316 316 );
317 // get mappings for the inner class 317 }
318 ClassMapping innerClassMapping = null; 318 mappingsChain.add(innerClassMapping);
319 if (outerClassMapping != null) { 319 outerClassMapping = innerClassMapping;
320 innerClassMapping = this.direction.choose( 320 }
321 outerClassMapping.getInnerClassByObfSimple(parts[i]), 321
322 outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i]) 322 assert (mappingsChain.size() == parts.length);
323 ); 323 return mappingsChain;
324 } 324 }
325 mappingsChain.add(innerClassMapping); 325
326 outerClassMapping = innerClassMapping; 326 public Mappings.EntryModifier getModifier(Entry entry) {
327 } 327 ClassMapping classMapping = findClassMapping(entry.getClassEntry());
328 328 if (classMapping != null && !entry.getName().equals("<clinit>")) {
329 assert (mappingsChain.size() == parts.length); 329 if (entry instanceof ClassEntry)
330 return mappingsChain; 330 return classMapping.getModifier();
331 } 331 else if (entry instanceof FieldEntry) {
332 332 FieldMapping fieldMapping = classMapping.getFieldByObf(entry.getName(), ((FieldEntry) entry).getType());
333 public Mappings.EntryModifier getModifier(Entry entry) 333 return fieldMapping != null ? fieldMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
334 { 334 } else if (entry instanceof BehaviorEntry) {
335 ClassMapping classMapping = findClassMapping(entry.getClassEntry()); 335 MethodMapping methodMapping = classMapping.getMethodByObf(entry.getName(), ((BehaviorEntry) entry).getSignature());
336 if (classMapping != null && !entry.getName().equals("<clinit>")) 336 return methodMapping != null ? methodMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
337 { 337 } else
338 if (entry instanceof ClassEntry) 338 throw new Error("Unknown entry type: " + entry.getClass().getName());
339 return classMapping.getModifier(); 339 }
340 else if (entry instanceof FieldEntry) 340 return Mappings.EntryModifier.UNCHANGED;
341 { 341 }
342 FieldMapping fieldMapping = classMapping.getFieldByObf(entry.getName(), ((FieldEntry) entry).getType());
343 return fieldMapping != null ? fieldMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
344 }
345 else if (entry instanceof BehaviorEntry)
346 {
347 MethodMapping methodMapping = classMapping.getMethodByObf(entry.getName(), ((BehaviorEntry) entry).getSignature());
348 return methodMapping != null ? methodMapping.getModifier() : Mappings.EntryModifier.UNCHANGED;
349 }
350 else
351 throw new Error("Unknown entry type: " + entry.getClass().getName());
352 }
353 return Mappings.EntryModifier.UNCHANGED;
354 }
355} 342}
diff --git a/src/main/java/cuchaz/enigma/mapping/Type.java b/src/main/java/cuchaz/enigma/mapping/Type.java
index 8136e13..609bd64 100644
--- a/src/main/java/cuchaz/enigma/mapping/Type.java
+++ b/src/main/java/cuchaz/enigma/mapping/Type.java
@@ -8,6 +8,7 @@
8 * Contributors: 8 * Contributors:
9 * Jeff Martin - initial API and implementation 9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/ 10 ******************************************************************************/
11
11package cuchaz.enigma.mapping; 12package cuchaz.enigma.mapping;
12 13
13import com.google.common.collect.Maps; 14import com.google.common.collect.Maps;
@@ -16,219 +17,219 @@ import java.util.Map;
16 17
17public class Type { 18public class Type {
18 19
19 public enum Primitive { 20 protected String name;
20 Byte('B'), 21
21 Character('C'), 22 public Type(String name) {
22 Short('S'), 23
23 Integer('I'), 24 // don't deal with generics
24 Long('J'), 25 // this is just for raw jvm types
25 Float('F'), 26 if (name.charAt(0) == 'T' || name.indexOf('<') >= 0 || name.indexOf('>') >= 0) {
26 Double('D'), 27 throw new IllegalArgumentException("don't use with generic types or templates: " + name);
27 Boolean('Z'); 28 }
28 29
29 private static final Map<Character, Primitive> lookup; 30 this.name = name;
30 31 }
31 static { 32
32 lookup = Maps.newTreeMap(); 33 public Type(Type other, ClassNameReplacer replacer) {
33 for (Primitive val : values()) { 34 this.name = other.name;
34 lookup.put(val.getCode(), val); 35 if (other.isClass()) {
35 } 36 String replacedName = replacer.replace(other.getClassEntry().getClassName());
36 } 37 if (replacedName != null) {
37 38 this.name = "L" + replacedName + ";";
38 public static Primitive get(char code) { 39 }
39 return lookup.get(code); 40 } else if (other.isArray() && other.hasClass()) {
40 } 41 String replacedName = replacer.replace(other.getClassEntry().getClassName());
41 42 if (replacedName != null) {
42 private char code; 43 this.name = Type.getArrayPrefix(other.getArrayDimension()) + "L" + replacedName + ";";
43 44 }
44 Primitive(char code) { 45 }
45 this.code = code; 46 }
46 } 47
47 48 public static String parseFirst(String in) {
48 public char getCode() { 49
49 return this.code; 50 if (in == null || in.length() <= 0) {
50 } 51 throw new IllegalArgumentException("No type to parse, input is empty!");
51 } 52 }
52 53
53 public static String parseFirst(String in) { 54 // read one type from the input
54 55
55 if (in == null || in.length() <= 0) { 56 char c = in.charAt(0);
56 throw new IllegalArgumentException("No type to parse, input is empty!"); 57
57 } 58 // first check for void
58 59 if (c == 'V') {
59 // read one type from the input 60 return "V";
60 61 }
61 char c = in.charAt(0); 62
62 63 // then check for primitives
63 // first check for void 64 Primitive primitive = Primitive.get(c);
64 if (c == 'V') { 65 if (primitive != null) {
65 return "V"; 66 return in.substring(0, 1);
66 } 67 }
67 68
68 // then check for primitives 69 // then check for classes
69 Primitive primitive = Primitive.get(c); 70 if (c == 'L') {
70 if (primitive != null) { 71 return readClass(in);
71 return in.substring(0, 1); 72 }
72 } 73
73 74 // then check for templates
74 // then check for classes 75 if (c == 'T') {
75 if (c == 'L') { 76 return readClass(in);
76 return readClass(in); 77 }
77 } 78
78 79 // then check for arrays
79 // then check for templates 80 int dim = countArrayDimension(in);
80 if (c == 'T') { 81 if (dim > 0) {
81 return readClass(in); 82 String arrayType = Type.parseFirst(in.substring(dim));
82 } 83 return in.substring(0, dim + arrayType.length());
83 84 }
84 // then check for arrays 85
85 int dim = countArrayDimension(in); 86 throw new IllegalArgumentException("don't know how to parse: " + in);
86 if (dim > 0) { 87 }
87 String arrayType = Type.parseFirst(in.substring(dim)); 88
88 return in.substring(0, dim + arrayType.length()); 89 private static String getArrayPrefix(int dimension) {
89 } 90 StringBuilder buf = new StringBuilder();
90 91 for (int i = 0; i < dimension; i++) {
91 throw new IllegalArgumentException("don't know how to parse: " + in); 92 buf.append("[");
92 } 93 }
93 94 return buf.toString();
94 protected String name; 95 }
95 96
96 public Type(String name) { 97 private static int countArrayDimension(String in) {
97 98 int i = 0;
98 // don't deal with generics 99 while (i < in.length() && in.charAt(i) == '[')
99 // this is just for raw jvm types 100 i++;
100 if (name.charAt(0) == 'T' || name.indexOf('<') >= 0 || name.indexOf('>') >= 0) { 101 return i;
101 throw new IllegalArgumentException("don't use with generic types or templates: " + name); 102 }
102 } 103
103 104 private static String readClass(String in) {
104 this.name = name; 105 // read all the characters in the buffer until we hit a ';'
105 } 106 // include the parameters too
106 107 StringBuilder buf = new StringBuilder();
107 public Type(Type other, ClassNameReplacer replacer) { 108 int depth = 0;
108 this.name = other.name; 109 for (int i = 0; i < in.length(); i++) {
109 if (other.isClass()) { 110 char c = in.charAt(i);
110 String replacedName = replacer.replace(other.getClassEntry().getClassName()); 111 buf.append(c);
111 if (replacedName != null) { 112
112 this.name = "L" + replacedName + ";"; 113 if (c == '<') {
113 } 114 depth++;
114 } else if (other.isArray() && other.hasClass()) { 115 } else if (c == '>') {
115 String replacedName = replacer.replace(other.getClassEntry().getClassName()); 116 depth--;
116 if (replacedName != null) { 117 } else if (depth == 0 && c == ';') {
117 this.name = Type.getArrayPrefix(other.getArrayDimension()) + "L" + replacedName + ";"; 118 return buf.toString();
118 } 119 }
119 } 120 }
120 } 121 return null;
121 122 }
122 @Override 123
123 public String toString() { 124 @Override
124 return this.name; 125 public String toString() {
125 } 126 return this.name;
126 127 }
127 public boolean isVoid() { 128
128 return this.name.length() == 1 && this.name.charAt(0) == 'V'; 129 public boolean isVoid() {
129 } 130 return this.name.length() == 1 && this.name.charAt(0) == 'V';
130 131 }
131 public boolean isPrimitive() { 132
132 return this.name.length() == 1 && Primitive.get(this.name.charAt(0)) != null; 133 public boolean isPrimitive() {
133 } 134 return this.name.length() == 1 && Primitive.get(this.name.charAt(0)) != null;
134 135 }
135 public Primitive getPrimitive() { 136
136 if (!isPrimitive()) { 137 public Primitive getPrimitive() {
137 throw new IllegalStateException("not a primitive"); 138 if (!isPrimitive()) {
138 } 139 throw new IllegalStateException("not a primitive");
139 return Primitive.get(this.name.charAt(0)); 140 }
140 } 141 return Primitive.get(this.name.charAt(0));
141 142 }
142 public boolean isClass() { 143
143 return this.name.charAt(0) == 'L' && this.name.charAt(this.name.length() - 1) == ';'; 144 public boolean isClass() {
144 } 145 return this.name.charAt(0) == 'L' && this.name.charAt(this.name.length() - 1) == ';';
145 146 }
146 public ClassEntry getClassEntry() { 147
147 if (isClass()) { 148 public ClassEntry getClassEntry() {
148 String name = this.name.substring(1, this.name.length() - 1); 149 if (isClass()) {
149 150 String name = this.name.substring(1, this.name.length() - 1);
150 int pos = name.indexOf('<'); 151
151 if (pos >= 0) { 152 int pos = name.indexOf('<');
152 // remove the parameters from the class name 153 if (pos >= 0) {
153 name = name.substring(0, pos); 154 // remove the parameters from the class name
154 } 155 name = name.substring(0, pos);
155 156 }
156 return new ClassEntry(name); 157
157 158 return new ClassEntry(name);
158 } else if (isArray() && getArrayType().isClass()) { 159
159 return getArrayType().getClassEntry(); 160 } else if (isArray() && getArrayType().isClass()) {
160 } else { 161 return getArrayType().getClassEntry();
161 throw new IllegalStateException("type doesn't have a class"); 162 } else {
162 } 163 throw new IllegalStateException("type doesn't have a class");
163 } 164 }
164 165 }
165 public boolean isArray() { 166
166 return this.name.charAt(0) == '['; 167 public boolean isArray() {
167 } 168 return this.name.charAt(0) == '[';
168 169 }
169 public int getArrayDimension() { 170
170 if (!isArray()) { 171 public int getArrayDimension() {
171 throw new IllegalStateException("not an array"); 172 if (!isArray()) {
172 } 173 throw new IllegalStateException("not an array");
173 return countArrayDimension(this.name); 174 }
174 } 175 return countArrayDimension(this.name);
175 176 }
176 public Type getArrayType() { 177
177 if (!isArray()) { 178 public Type getArrayType() {
178 throw new IllegalStateException("not an array"); 179 if (!isArray()) {
179 } 180 throw new IllegalStateException("not an array");
180 return new Type(this.name.substring(getArrayDimension(), this.name.length())); 181 }
181 } 182 return new Type(this.name.substring(getArrayDimension(), this.name.length()));
182 183 }
183 private static String getArrayPrefix(int dimension) { 184
184 StringBuilder buf = new StringBuilder(); 185 public boolean hasClass() {
185 for (int i = 0; i < dimension; i++) { 186 return isClass() || (isArray() && getArrayType().hasClass());
186 buf.append("["); 187 }
187 } 188
188 return buf.toString(); 189 @Override
189 } 190 public boolean equals(Object other) {
190 191 return other instanceof Type && equals((Type) other);
191 public boolean hasClass() { 192 }
192 return isClass() || (isArray() && getArrayType().hasClass()); 193
193 } 194 public boolean equals(Type other) {
194 195 return this.name.equals(other.name);
195 @Override 196 }
196 public boolean equals(Object other) { 197
197 return other instanceof Type && equals((Type) other); 198 public int hashCode() {
198 } 199 return this.name.hashCode();
199 200 }
200 public boolean equals(Type other) { 201
201 return this.name.equals(other.name); 202 public enum Primitive {
202 } 203 Byte('B'),
203 204 Character('C'),
204 public int hashCode() { 205 Short('S'),
205 return this.name.hashCode(); 206 Integer('I'),
206 } 207 Long('J'),
207 208 Float('F'),
208 private static int countArrayDimension(String in) { 209 Double('D'),
209 int i = 0; 210 Boolean('Z');
210 while (i < in.length() && in.charAt(i) == '[') 211
211 i++; 212 private static final Map<Character, Primitive> lookup;
212 return i; 213
213 } 214 static {
214 215 lookup = Maps.newTreeMap();
215 private static String readClass(String in) { 216 for (Primitive val : values()) {
216 // read all the characters in the buffer until we hit a ';' 217 lookup.put(val.getCode(), val);
217 // include the parameters too 218 }
218 StringBuilder buf = new StringBuilder(); 219 }
219 int depth = 0; 220
220 for (int i = 0; i < in.length(); i++) { 221 private char code;
221 char c = in.charAt(i); 222
222 buf.append(c); 223 Primitive(char code) {
223 224 this.code = code;
224 if (c == '<') { 225 }
225 depth++; 226
226 } else if (c == '>') { 227 public static Primitive get(char code) {
227 depth--; 228 return lookup.get(code);
228 } else if (depth == 0 && c == ';') { 229 }
229 return buf.toString(); 230
230 } 231 public char getCode() {
231 } 232 return this.code;
232 return null; 233 }
233 } 234 }
234} 235}