summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/mapping
diff options
context:
space:
mode:
authorGravatar jeff2015-02-03 22:00:53 -0500
committerGravatar jeff2015-02-03 22:00:53 -0500
commit52ab426d8fad3dbee7e728f523a35af94facebda (patch)
tree146fadfd8e639a909d6c1d6a193e7eddeab0be4a /src/cuchaz/enigma/mapping
downloadenigma-fork-52ab426d8fad3dbee7e728f523a35af94facebda.tar.gz
enigma-fork-52ab426d8fad3dbee7e728f523a35af94facebda.tar.xz
enigma-fork-52ab426d8fad3dbee7e728f523a35af94facebda.zip
oops, don't depend on local procyon project
Diffstat (limited to 'src/cuchaz/enigma/mapping')
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentEntry.java116
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentMapping.java44
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorEntry.java15
-rw-r--r--src/cuchaz/enigma/mapping/BehaviorEntryFactory.java57
-rw-r--r--src/cuchaz/enigma/mapping/ClassEntry.java123
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java405
-rw-r--r--src/cuchaz/enigma/mapping/ConstructorEntry.java116
-rw-r--r--src/cuchaz/enigma/mapping/Entry.java18
-rw-r--r--src/cuchaz/enigma/mapping/EntryPair.java22
-rw-r--r--src/cuchaz/enigma/mapping/FieldEntry.java88
-rw-r--r--src/cuchaz/enigma/mapping/FieldMapping.java43
-rw-r--r--src/cuchaz/enigma/mapping/IllegalNameException.java44
-rw-r--r--src/cuchaz/enigma/mapping/JavassistUtil.java55
-rw-r--r--src/cuchaz/enigma/mapping/MappingParseException.java29
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java213
-rw-r--r--src/cuchaz/enigma/mapping/MappingsReader.java176
-rw-r--r--src/cuchaz/enigma/mapping/MappingsRenamer.java237
-rw-r--r--src/cuchaz/enigma/mapping/MappingsWriter.java88
-rw-r--r--src/cuchaz/enigma/mapping/MethodEntry.java104
-rw-r--r--src/cuchaz/enigma/mapping/MethodMapping.java162
-rw-r--r--src/cuchaz/enigma/mapping/NameValidator.java80
-rw-r--r--src/cuchaz/enigma/mapping/SignatureUpdater.java94
-rw-r--r--src/cuchaz/enigma/mapping/TranslationDirection.java29
-rw-r--r--src/cuchaz/enigma/mapping/Translator.java235
24 files changed, 2593 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java
new file mode 100644
index 0000000..2c15f4e
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java
@@ -0,0 +1,116 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class ArgumentEntry implements Entry, Serializable {
18
19 private static final long serialVersionUID = 4472172468162696006L;
20
21 private BehaviorEntry m_behaviorEntry;
22 private int m_index;
23 private String m_name;
24
25 public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) {
26 if (behaviorEntry == null) {
27 throw new IllegalArgumentException("Behavior cannot be null!");
28 }
29 if (index < 0) {
30 throw new IllegalArgumentException("Index must be non-negative!");
31 }
32 if (name == null) {
33 throw new IllegalArgumentException("Argument name cannot be null!");
34 }
35
36 m_behaviorEntry = behaviorEntry;
37 m_index = index;
38 m_name = name;
39 }
40
41 public ArgumentEntry(ArgumentEntry other) {
42 m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass(getClassEntry());
43 m_index = other.m_index;
44 m_name = other.m_name;
45 }
46
47 public ArgumentEntry(ArgumentEntry other, String newClassName) {
48 m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass(new ClassEntry(newClassName));
49 m_index = other.m_index;
50 m_name = other.m_name;
51 }
52
53 public BehaviorEntry getBehaviorEntry() {
54 return m_behaviorEntry;
55 }
56
57 public int getIndex() {
58 return m_index;
59 }
60
61 @Override
62 public String getName() {
63 return m_name;
64 }
65
66 @Override
67 public ClassEntry getClassEntry() {
68 return m_behaviorEntry.getClassEntry();
69 }
70
71 @Override
72 public String getClassName() {
73 return m_behaviorEntry.getClassName();
74 }
75
76 @Override
77 public ArgumentEntry cloneToNewClass(ClassEntry classEntry) {
78 return new ArgumentEntry(this, classEntry.getName());
79 }
80
81 public String getMethodName() {
82 return m_behaviorEntry.getName();
83 }
84
85 public String getMethodSignature() {
86 return m_behaviorEntry.getSignature();
87 }
88
89 @Override
90 public int hashCode() {
91 return Util.combineHashesOrdered(
92 m_behaviorEntry,
93 Integer.valueOf(m_index).hashCode(),
94 m_name.hashCode()
95 );
96 }
97
98 @Override
99 public boolean equals(Object other) {
100 if (other instanceof ArgumentEntry) {
101 return equals((ArgumentEntry)other);
102 }
103 return false;
104 }
105
106 public boolean equals(ArgumentEntry other) {
107 return m_behaviorEntry.equals(other.m_behaviorEntry)
108 && m_index == other.m_index
109 && m_name.equals(other.m_name);
110 }
111
112 @Override
113 public String toString() {
114 return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")";
115 }
116}
diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java
new file mode 100644
index 0000000..f4d8e77
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15public class ArgumentMapping implements Serializable, Comparable<ArgumentMapping> {
16
17 private static final long serialVersionUID = 8610742471440861315L;
18
19 private int m_index;
20 private String m_name;
21
22 // NOTE: this argument order is important for the MethodReader/MethodWriter
23 public ArgumentMapping(int index, String name) {
24 m_index = index;
25 m_name = NameValidator.validateArgumentName(name);
26 }
27
28 public int getIndex() {
29 return m_index;
30 }
31
32 public String getName() {
33 return m_name;
34 }
35
36 public void setName(String val) {
37 m_name = NameValidator.validateArgumentName(val);
38 }
39
40 @Override
41 public int compareTo(ArgumentMapping other) {
42 return Integer.compare(m_index, other.m_index);
43 }
44}
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java
new file mode 100644
index 0000000..f4200b8
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java
@@ -0,0 +1,15 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public interface BehaviorEntry extends Entry {
14 String getSignature();
15}
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
new file mode 100644
index 0000000..386faeb
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java
@@ -0,0 +1,57 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import javassist.CtBehavior;
14import javassist.CtConstructor;
15import javassist.CtMethod;
16import javassist.bytecode.Descriptor;
17
18public class BehaviorEntryFactory {
19
20 public static BehaviorEntry create(String className, String name, String signature) {
21 return create(new ClassEntry(className), name, signature);
22 }
23
24 public static BehaviorEntry create(ClassEntry classEntry, String name, String signature) {
25 if (name.equals("<init>")) {
26 return new ConstructorEntry(classEntry, signature);
27 } else if (name.equals("<clinit>")) {
28 return new ConstructorEntry(classEntry);
29 } else {
30 return new MethodEntry(classEntry, name, signature);
31 }
32 }
33
34 public static BehaviorEntry create(CtBehavior behavior) {
35 String className = Descriptor.toJvmName(behavior.getDeclaringClass().getName());
36 if (behavior instanceof CtMethod) {
37 return create(className, behavior.getName(), behavior.getSignature());
38 } else if (behavior instanceof CtConstructor) {
39 CtConstructor constructor = (CtConstructor)behavior;
40 if (constructor.isClassInitializer()) {
41 return create(className, "<clinit>", null);
42 } else {
43 return create(className, "<init>", constructor.getSignature());
44 }
45 } else {
46 throw new IllegalArgumentException("Unable to create BehaviorEntry from " + behavior);
47 }
48 }
49
50 public static BehaviorEntry createObf(ClassEntry classEntry, MethodMapping methodMapping) {
51 return create(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
52 }
53
54 public static BehaviorEntry createDeobf(ClassEntry classEntry, MethodMapping methodMapping) {
55 return create(classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature());
56 }
57}
diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java
new file mode 100644
index 0000000..cf41001
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ClassEntry.java
@@ -0,0 +1,123 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15public class ClassEntry implements Entry, Serializable {
16
17 private static final long serialVersionUID = 4235460580973955811L;
18
19 private String m_name;
20
21 public ClassEntry(String className) {
22 if (className == null) {
23 throw new IllegalArgumentException("Class name cannot be null!");
24 }
25 if (className.indexOf('.') >= 0) {
26 throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className);
27 }
28
29 m_name = className;
30
31 if (isInnerClass() && getInnerClassName().indexOf('/') >= 0) {
32 throw new IllegalArgumentException("Inner class must not have a package: " + className);
33 }
34 }
35
36 public ClassEntry(ClassEntry other) {
37 m_name = other.m_name;
38 }
39
40 @Override
41 public String getName() {
42 return m_name;
43 }
44
45 @Override
46 public String getClassName() {
47 return m_name;
48 }
49
50 @Override
51 public ClassEntry getClassEntry() {
52 return this;
53 }
54
55 @Override
56 public ClassEntry cloneToNewClass(ClassEntry classEntry) {
57 return classEntry;
58 }
59
60 @Override
61 public int hashCode() {
62 return m_name.hashCode();
63 }
64
65 @Override
66 public boolean equals(Object other) {
67 if (other instanceof ClassEntry) {
68 return equals((ClassEntry)other);
69 }
70 return false;
71 }
72
73 public boolean equals(ClassEntry other) {
74 return m_name.equals(other.m_name);
75 }
76
77 @Override
78 public String toString() {
79 return m_name;
80 }
81
82 public boolean isInnerClass() {
83 return m_name.lastIndexOf('$') >= 0;
84 }
85
86 public String getOuterClassName() {
87 if (isInnerClass()) {
88 return m_name.substring(0, m_name.lastIndexOf('$'));
89 }
90 return m_name;
91 }
92
93 public String getInnerClassName() {
94 if (!isInnerClass()) {
95 throw new Error("This is not an inner class!");
96 }
97 return m_name.substring(m_name.lastIndexOf('$') + 1);
98 }
99
100 public ClassEntry getOuterClassEntry() {
101 return new ClassEntry(getOuterClassName());
102 }
103
104 public boolean isInDefaultPackage() {
105 return m_name.indexOf('/') < 0;
106 }
107
108 public String getPackageName() {
109 int pos = m_name.lastIndexOf('/');
110 if (pos > 0) {
111 return m_name.substring(0, pos);
112 }
113 return null;
114 }
115
116 public String getSimpleName() {
117 int pos = m_name.lastIndexOf('/');
118 if (pos > 0) {
119 return m_name.substring(pos + 1);
120 }
121 return m_name;
122 }
123}
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
new file mode 100644
index 0000000..dbb8717
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -0,0 +1,405 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14import java.util.ArrayList;
15import java.util.Map;
16
17import com.google.common.collect.Maps;
18
19public class ClassMapping implements Serializable, Comparable<ClassMapping> {
20
21 private static final long serialVersionUID = -5148491146902340107L;
22
23 private String m_obfName;
24 private String m_deobfName;
25 private Map<String,ClassMapping> m_innerClassesByObf;
26 private Map<String,ClassMapping> m_innerClassesByDeobf;
27 private Map<String,FieldMapping> m_fieldsByObf;
28 private Map<String,FieldMapping> m_fieldsByDeobf;
29 private Map<String,MethodMapping> m_methodsByObf;
30 private Map<String,MethodMapping> m_methodsByDeobf;
31
32 public ClassMapping(String obfName) {
33 this(obfName, null);
34 }
35
36 public ClassMapping(String obfName, String deobfName) {
37 m_obfName = obfName;
38 m_deobfName = NameValidator.validateClassName(deobfName, false);
39 m_innerClassesByObf = Maps.newHashMap();
40 m_innerClassesByDeobf = Maps.newHashMap();
41 m_fieldsByObf = Maps.newHashMap();
42 m_fieldsByDeobf = Maps.newHashMap();
43 m_methodsByObf = Maps.newHashMap();
44 m_methodsByDeobf = Maps.newHashMap();
45 }
46
47 public String getObfName() {
48 return m_obfName;
49 }
50
51 public String getDeobfName() {
52 return m_deobfName;
53 }
54
55 public void setDeobfName(String val) {
56 m_deobfName = NameValidator.validateClassName(val, false);
57 }
58
59 //// INNER CLASSES ////////
60
61 public Iterable<ClassMapping> innerClasses() {
62 assert (m_innerClassesByObf.size() >= m_innerClassesByDeobf.size());
63 return m_innerClassesByObf.values();
64 }
65
66 public void addInnerClassMapping(ClassMapping classMapping) {
67 assert (isSimpleClassName(classMapping.getObfName()));
68 boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfName(), classMapping) == null;
69 assert (obfWasAdded);
70 if (classMapping.getDeobfName() != null) {
71 assert (isSimpleClassName(classMapping.getDeobfName()));
72 boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
73 assert (deobfWasAdded);
74 }
75 }
76
77 public void removeInnerClassMapping(ClassMapping classMapping) {
78 boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfName()) != null;
79 assert (obfWasRemoved);
80 if (classMapping.getDeobfName() != null) {
81 boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
82 assert (deobfWasRemoved);
83 }
84 }
85
86 public ClassMapping getOrCreateInnerClass(String obfName) {
87 assert (isSimpleClassName(obfName));
88 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
89 if (classMapping == null) {
90 classMapping = new ClassMapping(obfName);
91 boolean wasAdded = m_innerClassesByObf.put(obfName, classMapping) == null;
92 assert (wasAdded);
93 }
94 return classMapping;
95 }
96
97 public ClassMapping getInnerClassByObf(String obfName) {
98 assert (isSimpleClassName(obfName));
99 return m_innerClassesByObf.get(obfName);
100 }
101
102 public ClassMapping getInnerClassByDeobf(String deobfName) {
103 assert (isSimpleClassName(deobfName));
104 return m_innerClassesByDeobf.get(deobfName);
105 }
106
107 public ClassMapping getInnerClassByDeobfThenObf(String name) {
108 ClassMapping classMapping = getInnerClassByDeobf(name);
109 if (classMapping == null) {
110 classMapping = getInnerClassByObf(name);
111 }
112 return classMapping;
113 }
114
115 public String getObfInnerClassName(String deobfName) {
116 assert (isSimpleClassName(deobfName));
117 ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName);
118 if (classMapping != null) {
119 return classMapping.getObfName();
120 }
121 return null;
122 }
123
124 public String getDeobfInnerClassName(String obfName) {
125 assert (isSimpleClassName(obfName));
126 ClassMapping classMapping = m_innerClassesByObf.get(obfName);
127 if (classMapping != null) {
128 return classMapping.getDeobfName();
129 }
130 return null;
131 }
132
133 public void setInnerClassName(String obfName, String deobfName) {
134 assert (isSimpleClassName(obfName));
135 ClassMapping classMapping = getOrCreateInnerClass(obfName);
136 if (classMapping.getDeobfName() != null) {
137 boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
138 assert (wasRemoved);
139 }
140 classMapping.setDeobfName(deobfName);
141 if (deobfName != null) {
142 assert (isSimpleClassName(deobfName));
143 boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null;
144 assert (wasAdded);
145 }
146 }
147
148 //// FIELDS ////////
149
150 public Iterable<FieldMapping> fields() {
151 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
152 return m_fieldsByObf.values();
153 }
154
155 public boolean containsObfField(String obfName) {
156 return m_fieldsByObf.containsKey(obfName);
157 }
158
159 public boolean containsDeobfField(String deobfName) {
160 return m_fieldsByDeobf.containsKey(deobfName);
161 }
162
163 public void addFieldMapping(FieldMapping fieldMapping) {
164 if (m_fieldsByObf.containsKey(fieldMapping.getObfName())) {
165 throw new Error("Already have mapping for " + m_obfName + "." + fieldMapping.getObfName());
166 }
167 if (m_fieldsByDeobf.containsKey(fieldMapping.getDeobfName())) {
168 throw new Error("Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName());
169 }
170 boolean obfWasAdded = m_fieldsByObf.put(fieldMapping.getObfName(), fieldMapping) == null;
171 assert (obfWasAdded);
172 boolean deobfWasAdded = m_fieldsByDeobf.put(fieldMapping.getDeobfName(), fieldMapping) == null;
173 assert (deobfWasAdded);
174 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
175 }
176
177 public void removeFieldMapping(FieldMapping fieldMapping) {
178 boolean obfWasRemoved = m_fieldsByObf.remove(fieldMapping.getObfName()) != null;
179 assert (obfWasRemoved);
180 if (fieldMapping.getDeobfName() != null) {
181 boolean deobfWasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null;
182 assert (deobfWasRemoved);
183 }
184 }
185
186 public FieldMapping getFieldByObf(String obfName) {
187 return m_fieldsByObf.get(obfName);
188 }
189
190 public FieldMapping getFieldByDeobf(String deobfName) {
191 return m_fieldsByDeobf.get(deobfName);
192 }
193
194 public String getObfFieldName(String deobfName) {
195 FieldMapping fieldMapping = m_fieldsByDeobf.get(deobfName);
196 if (fieldMapping != null) {
197 return fieldMapping.getObfName();
198 }
199 return null;
200 }
201
202 public String getDeobfFieldName(String obfName) {
203 FieldMapping fieldMapping = m_fieldsByObf.get(obfName);
204 if (fieldMapping != null) {
205 return fieldMapping.getDeobfName();
206 }
207 return null;
208 }
209
210 public void setFieldName(String obfName, String deobfName) {
211 FieldMapping fieldMapping = m_fieldsByObf.get(obfName);
212 if (fieldMapping == null) {
213 fieldMapping = new FieldMapping(obfName, deobfName);
214 boolean obfWasAdded = m_fieldsByObf.put(obfName, fieldMapping) == null;
215 assert (obfWasAdded);
216 } else {
217 boolean wasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null;
218 assert (wasRemoved);
219 }
220 fieldMapping.setDeobfName(deobfName);
221 if (deobfName != null) {
222 boolean wasAdded = m_fieldsByDeobf.put(deobfName, fieldMapping) == null;
223 assert (wasAdded);
224 }
225 }
226
227 //// METHODS ////////
228
229 public Iterable<MethodMapping> methods() {
230 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
231 return m_methodsByObf.values();
232 }
233
234 public boolean containsObfMethod(String obfName, String obfSignature) {
235 return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
236 }
237
238 public boolean containsDeobfMethod(String deobfName, String deobfSignature) {
239 return m_methodsByDeobf.containsKey(getMethodKey(deobfName, deobfSignature));
240 }
241
242 public void addMethodMapping(MethodMapping methodMapping) {
243 String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
244 if (m_methodsByObf.containsKey(obfKey)) {
245 throw new Error("Already have mapping for " + m_obfName + "." + obfKey);
246 }
247 boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null;
248 assert (wasAdded);
249 if (methodMapping.getDeobfName() != null) {
250 String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature());
251 if (m_methodsByDeobf.containsKey(deobfKey)) {
252 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey);
253 }
254 boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null;
255 assert (deobfWasAdded);
256 }
257 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
258 }
259
260 public void removeMethodMapping(MethodMapping methodMapping) {
261 boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null;
262 assert (obfWasRemoved);
263 if (methodMapping.getDeobfName() != null) {
264 boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
265 assert (deobfWasRemoved);
266 }
267 }
268
269 public MethodMapping getMethodByObf(String obfName, String signature) {
270 return m_methodsByObf.get(getMethodKey(obfName, signature));
271 }
272
273 public MethodMapping getMethodByDeobf(String deobfName, String signature) {
274 return m_methodsByDeobf.get(getMethodKey(deobfName, signature));
275 }
276
277 private String getMethodKey(String name, String signature) {
278 if (name == null) {
279 throw new IllegalArgumentException("name cannot be null!");
280 }
281 if (signature == null) {
282 throw new IllegalArgumentException("signature cannot be null!");
283 }
284 return name + signature;
285 }
286
287 public void setMethodName(String obfName, String obfSignature, String deobfName) {
288 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature));
289 if (methodMapping == null) {
290 methodMapping = createMethodMapping(obfName, obfSignature);
291 } else if (methodMapping.getDeobfName() != null) {
292 boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
293 assert (wasRemoved);
294 }
295 methodMapping.setDeobfName(deobfName);
296 if (deobfName != null) {
297 boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null;
298 assert (wasAdded);
299 }
300 }
301
302 //// ARGUMENTS ////////
303
304 public void setArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName) {
305 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature));
306 if (methodMapping == null) {
307 methodMapping = createMethodMapping(obfMethodName, obfMethodSignature);
308 }
309 methodMapping.setArgumentName(argumentIndex, argumentName);
310 }
311
312 public void removeArgumentName(String obfMethodName, String obfMethodSignature, int argumentIndex) {
313 m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex);
314 }
315
316 private MethodMapping createMethodMapping(String obfName, String obfSignature) {
317 MethodMapping methodMapping = new MethodMapping(obfName, obfSignature);
318 boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null;
319 assert (wasAdded);
320 return methodMapping;
321 }
322
323 @Override
324 public String toString() {
325 StringBuilder buf = new StringBuilder();
326 buf.append(m_obfName);
327 buf.append(" <-> ");
328 buf.append(m_deobfName);
329 buf.append("\n");
330 buf.append("Fields:\n");
331 for (FieldMapping fieldMapping : fields()) {
332 buf.append("\t");
333 buf.append(fieldMapping.getObfName());
334 buf.append(" <-> ");
335 buf.append(fieldMapping.getDeobfName());
336 buf.append("\n");
337 }
338 buf.append("Methods:\n");
339 for (MethodMapping methodMapping : m_methodsByObf.values()) {
340 buf.append(methodMapping.toString());
341 buf.append("\n");
342 }
343 buf.append("Inner Classes:\n");
344 for (ClassMapping classMapping : m_innerClassesByObf.values()) {
345 buf.append("\t");
346 buf.append(classMapping.getObfName());
347 buf.append(" <-> ");
348 buf.append(classMapping.getDeobfName());
349 buf.append("\n");
350 }
351 return buf.toString();
352 }
353
354 @Override
355 public int compareTo(ClassMapping other) {
356 // sort by a, b, c, ... aa, ab, etc
357 if (m_obfName.length() != other.m_obfName.length()) {
358 return m_obfName.length() - other.m_obfName.length();
359 }
360 return m_obfName.compareTo(other.m_obfName);
361 }
362
363 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
364
365 // rename inner classes
366 for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObf.values())) {
367 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
368 boolean wasRemoved = m_innerClassesByObf.remove(oldObfClassName) != null;
369 assert (wasRemoved);
370 boolean wasAdded = m_innerClassesByObf.put(newObfClassName, innerClassMapping) == null;
371 assert (wasAdded);
372 }
373 }
374
375 // rename method signatures
376 for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) {
377 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
378 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
379 boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null;
380 assert (wasRemoved);
381 boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
382 assert (wasAdded);
383 }
384 }
385
386 if (m_obfName.equals(oldObfClassName)) {
387 // rename this class
388 m_obfName = newObfClassName;
389 return true;
390 }
391 return false;
392 }
393
394 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
395 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
396 if (methodMapping != null) {
397 return methodMapping.containsArgument(name);
398 }
399 return false;
400 }
401
402 public static boolean isSimpleClassName(String name) {
403 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
404 }
405}
diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java
new file mode 100644
index 0000000..ea0535f
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java
@@ -0,0 +1,116 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class ConstructorEntry implements BehaviorEntry, Serializable {
18
19 private static final long serialVersionUID = -868346075317366758L;
20
21 private ClassEntry m_classEntry;
22 private String m_signature;
23
24 public ConstructorEntry(ClassEntry classEntry) {
25 this(classEntry, null);
26 }
27
28 public ConstructorEntry(ClassEntry classEntry, String signature) {
29 if (classEntry == null) {
30 throw new IllegalArgumentException("Class cannot be null!");
31 }
32
33 m_classEntry = classEntry;
34 m_signature = signature;
35 }
36
37 public ConstructorEntry(ConstructorEntry other) {
38 m_classEntry = new ClassEntry(other.m_classEntry);
39 m_signature = other.m_signature;
40 }
41
42 public ConstructorEntry(ConstructorEntry other, String newClassName) {
43 m_classEntry = new ClassEntry(newClassName);
44 m_signature = other.m_signature;
45 }
46
47 @Override
48 public ClassEntry getClassEntry() {
49 return m_classEntry;
50 }
51
52 @Override
53 public String getName() {
54 if (isStatic()) {
55 return "<clinit>";
56 }
57 return "<init>";
58 }
59
60 public boolean isStatic() {
61 return m_signature == null;
62 }
63
64 @Override
65 public String getSignature() {
66 return m_signature;
67 }
68
69 @Override
70 public String getClassName() {
71 return m_classEntry.getName();
72 }
73
74 @Override
75 public ConstructorEntry cloneToNewClass(ClassEntry classEntry) {
76 return new ConstructorEntry(this, classEntry.getName());
77 }
78
79 @Override
80 public int hashCode() {
81 if (isStatic()) {
82 return Util.combineHashesOrdered(m_classEntry);
83 } else {
84 return Util.combineHashesOrdered(m_classEntry, m_signature);
85 }
86 }
87
88 @Override
89 public boolean equals(Object other) {
90 if (other instanceof ConstructorEntry) {
91 return equals((ConstructorEntry)other);
92 }
93 return false;
94 }
95
96 public boolean equals(ConstructorEntry other) {
97 if (isStatic() != other.isStatic()) {
98 return false;
99 }
100
101 if (isStatic()) {
102 return m_classEntry.equals(other.m_classEntry);
103 } else {
104 return m_classEntry.equals(other.m_classEntry) && m_signature.equals(other.m_signature);
105 }
106 }
107
108 @Override
109 public String toString() {
110 if (isStatic()) {
111 return m_classEntry.getName() + "." + getName();
112 } else {
113 return m_classEntry.getName() + "." + getName() + m_signature;
114 }
115 }
116}
diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java
new file mode 100644
index 0000000..39e1507
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Entry.java
@@ -0,0 +1,18 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public interface Entry {
14 String getName();
15 String getClassName();
16 ClassEntry getClassEntry();
17 Entry cloneToNewClass(ClassEntry classEntry);
18}
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java
new file mode 100644
index 0000000..60411c4
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/EntryPair.java
@@ -0,0 +1,22 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public class EntryPair<T extends Entry> {
14
15 public T obf;
16 public T deobf;
17
18 public EntryPair(T obf, T deobf) {
19 this.obf = obf;
20 this.deobf = deobf;
21 }
22}
diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java
new file mode 100644
index 0000000..6cc9eb7
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/FieldEntry.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class FieldEntry implements Entry, Serializable {
18
19 private static final long serialVersionUID = 3004663582802885451L;
20
21 private ClassEntry m_classEntry;
22 private String m_name;
23
24 // NOTE: this argument order is important for the MethodReader/MethodWriter
25 public FieldEntry(ClassEntry classEntry, String name) {
26 if (classEntry == null) {
27 throw new IllegalArgumentException("Class cannot be null!");
28 }
29 if (name == null) {
30 throw new IllegalArgumentException("Field name cannot be null!");
31 }
32
33 m_classEntry = classEntry;
34 m_name = name;
35 }
36
37 public FieldEntry(FieldEntry other) {
38 m_classEntry = new ClassEntry(other.m_classEntry);
39 m_name = other.m_name;
40 }
41
42 public FieldEntry(FieldEntry other, String newClassName) {
43 m_classEntry = new ClassEntry(newClassName);
44 m_name = other.m_name;
45 }
46
47 @Override
48 public ClassEntry getClassEntry() {
49 return m_classEntry;
50 }
51
52 @Override
53 public String getName() {
54 return m_name;
55 }
56
57 @Override
58 public String getClassName() {
59 return m_classEntry.getName();
60 }
61
62 @Override
63 public FieldEntry cloneToNewClass(ClassEntry classEntry) {
64 return new FieldEntry(this, classEntry.getName());
65 }
66
67 @Override
68 public int hashCode() {
69 return Util.combineHashesOrdered(m_classEntry, m_name);
70 }
71
72 @Override
73 public boolean equals(Object other) {
74 if (other instanceof FieldEntry) {
75 return equals((FieldEntry)other);
76 }
77 return false;
78 }
79
80 public boolean equals(FieldEntry other) {
81 return m_classEntry.equals(other.m_classEntry) && m_name.equals(other.m_name);
82 }
83
84 @Override
85 public String toString() {
86 return m_classEntry.getName() + "." + m_name;
87 }
88}
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
new file mode 100644
index 0000000..5f5c270
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -0,0 +1,43 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15public class FieldMapping implements Serializable, Comparable<FieldMapping> {
16
17 private static final long serialVersionUID = 8610742471440861315L;
18
19 private String m_obfName;
20 private String m_deobfName;
21
22 public FieldMapping(String obfName, String deobfName) {
23 m_obfName = obfName;
24 m_deobfName = NameValidator.validateFieldName(deobfName);
25 }
26
27 public String getObfName() {
28 return m_obfName;
29 }
30
31 public String getDeobfName() {
32 return m_deobfName;
33 }
34
35 public void setDeobfName(String val) {
36 m_deobfName = NameValidator.validateFieldName(val);
37 }
38
39 @Override
40 public int compareTo(FieldMapping other) {
41 return m_obfName.compareTo(other.m_obfName);
42 }
43}
diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java
new file mode 100644
index 0000000..aacaf3b
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/IllegalNameException.java
@@ -0,0 +1,44 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public class IllegalNameException extends RuntimeException {
14
15 private static final long serialVersionUID = -2279910052561114323L;
16
17 private String m_name;
18 private String m_reason;
19
20 public IllegalNameException(String name) {
21 this(name, null);
22 }
23
24 public IllegalNameException(String name, String reason) {
25 m_name = name;
26 m_reason = reason;
27 }
28
29 public String getReason() {
30 return m_reason;
31 }
32
33 @Override
34 public String getMessage() {
35 StringBuilder buf = new StringBuilder();
36 buf.append("Illegal name: ");
37 buf.append(m_name);
38 if (m_reason != null) {
39 buf.append(" because ");
40 buf.append(m_reason);
41 }
42 return buf.toString();
43 }
44}
diff --git a/src/cuchaz/enigma/mapping/JavassistUtil.java b/src/cuchaz/enigma/mapping/JavassistUtil.java
new file mode 100644
index 0000000..b011e0b
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/JavassistUtil.java
@@ -0,0 +1,55 @@
1package cuchaz.enigma.mapping;
2
3import javassist.CtBehavior;
4import javassist.CtClass;
5import javassist.CtConstructor;
6import javassist.CtField;
7import javassist.CtMethod;
8import javassist.bytecode.Descriptor;
9import cuchaz.enigma.mapping.BehaviorEntry;
10import cuchaz.enigma.mapping.ClassEntry;
11import cuchaz.enigma.mapping.ConstructorEntry;
12import cuchaz.enigma.mapping.FieldEntry;
13import cuchaz.enigma.mapping.MethodEntry;
14
15public class JavassistUtil {
16
17 public static ClassEntry getClassEntry(CtClass c) {
18 return new ClassEntry(Descriptor.toJvmName(c.getName()));
19 }
20
21 public static ClassEntry getSuperclassEntry(CtClass c) {
22 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
23 }
24
25 public static MethodEntry getMethodEntry(CtMethod method) {
26 return new MethodEntry(
27 getClassEntry(method.getDeclaringClass()),
28 method.getName(),
29 method.getMethodInfo().getDescriptor()
30 );
31 }
32
33 public static ConstructorEntry getConstructorEntry(CtConstructor constructor) {
34 return new ConstructorEntry(
35 getClassEntry(constructor.getDeclaringClass()),
36 constructor.getMethodInfo().getDescriptor()
37 );
38 }
39
40 public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) {
41 if (behavior instanceof CtMethod) {
42 return getMethodEntry((CtMethod)behavior);
43 } else if (behavior instanceof CtConstructor) {
44 return getConstructorEntry((CtConstructor)behavior);
45 }
46 throw new Error("behavior is neither Method nor Constructor!");
47 }
48
49 public static FieldEntry getFieldEntry(CtField field) {
50 return new FieldEntry(
51 getClassEntry(field.getDeclaringClass()),
52 field.getName()
53 );
54 }
55}
diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java
new file mode 100644
index 0000000..1974c22
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingParseException.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public class MappingParseException extends Exception {
14
15 private static final long serialVersionUID = -5487280332892507236L;
16
17 private int m_line;
18 private String m_message;
19
20 public MappingParseException(int line, String message) {
21 m_line = line;
22 m_message = message;
23 }
24
25 @Override
26 public String getMessage() {
27 return "Line " + m_line + ": " + m_message;
28 }
29}
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
new file mode 100644
index 0000000..cc560a8
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -0,0 +1,213 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.IOException;
14import java.io.InputStream;
15import java.io.ObjectInputStream;
16import java.io.Serializable;
17import java.util.ArrayList;
18import java.util.Collection;
19import java.util.Map;
20import java.util.Set;
21import java.util.zip.GZIPInputStream;
22
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
25
26import cuchaz.enigma.Util;
27import cuchaz.enigma.analysis.TranslationIndex;
28import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
29
30public class Mappings implements Serializable {
31
32 private static final long serialVersionUID = 4649790259460259026L;
33
34 protected Map<String,ClassMapping> m_classesByObf;
35 protected Map<String,ClassMapping> m_classesByDeobf;
36
37 public Mappings() {
38 m_classesByObf = Maps.newHashMap();
39 m_classesByDeobf = Maps.newHashMap();
40 }
41
42 public Mappings(Iterable<ClassMapping> classes) {
43 this();
44
45 for (ClassMapping classMapping : classes) {
46 m_classesByObf.put(classMapping.getObfName(), classMapping);
47 if (classMapping.getDeobfName() != null) {
48 m_classesByDeobf.put(classMapping.getDeobfName(), classMapping);
49 }
50 }
51 }
52
53 public static Mappings newFromResource(String resource) throws IOException {
54 InputStream in = null;
55 try {
56 in = Mappings.class.getResourceAsStream(resource);
57 return newFromStream(in);
58 } finally {
59 Util.closeQuietly(in);
60 }
61 }
62
63 public Collection<ClassMapping> classes() {
64 assert (m_classesByObf.size() >= m_classesByDeobf.size());
65 return m_classesByObf.values();
66 }
67
68 public void addClassMapping(ClassMapping classMapping) {
69 if (m_classesByObf.containsKey(classMapping.getObfName())) {
70 throw new Error("Already have mapping for " + classMapping.getObfName());
71 }
72 boolean obfWasAdded = m_classesByObf.put(classMapping.getObfName(), classMapping) == null;
73 assert (obfWasAdded);
74 if (classMapping.getDeobfName() != null) {
75 if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) {
76 throw new Error("Already have mapping for " + classMapping.getDeobfName());
77 }
78 boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
79 assert (deobfWasAdded);
80 }
81 }
82
83 public void removeClassMapping(ClassMapping classMapping) {
84 boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfName()) != null;
85 assert (obfWasRemoved);
86 if (classMapping.getDeobfName() != null) {
87 boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
88 assert (deobfWasRemoved);
89 }
90 }
91
92 public ClassMapping getClassByObf(ClassEntry entry) {
93 return getClassByObf(entry.getName());
94 }
95
96 public ClassMapping getClassByObf(String obfName) {
97 return m_classesByObf.get(obfName);
98 }
99
100 public ClassMapping getClassByDeobf(ClassEntry entry) {
101 return getClassByDeobf(entry.getName());
102 }
103
104 public ClassMapping getClassByDeobf(String deobfName) {
105 return m_classesByDeobf.get(deobfName);
106 }
107
108 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) {
109 switch (direction) {
110 case Deobfuscating:
111
112 return new Translator(direction, m_classesByObf, index);
113
114 case Obfuscating:
115
116 // fill in the missing deobf class entries with obf entries
117 Map<String,ClassMapping> classes = Maps.newHashMap();
118 for (ClassMapping classMapping : classes()) {
119 if (classMapping.getDeobfName() != null) {
120 classes.put(classMapping.getDeobfName(), classMapping);
121 } else {
122 classes.put(classMapping.getObfName(), classMapping);
123 }
124 }
125
126 // translate the translation index
127 // NOTE: this isn't actually recursive
128 TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index));
129
130 return new Translator(direction, classes, deobfIndex);
131
132 default:
133 throw new Error("Invalid translation direction!");
134 }
135 }
136
137 public static Mappings newFromStream(InputStream in) throws IOException {
138 try {
139 return (Mappings)new ObjectInputStream(new GZIPInputStream(in)).readObject();
140 } catch (ClassNotFoundException ex) {
141 throw new Error(ex);
142 }
143 }
144
145 @Override
146 public String toString() {
147 StringBuilder buf = new StringBuilder();
148 for (ClassMapping classMapping : m_classesByObf.values()) {
149 buf.append(classMapping.toString());
150 buf.append("\n");
151 }
152 return buf.toString();
153 }
154
155 public void renameObfClass(String oldObfName, String newObfName) {
156 for (ClassMapping classMapping : new ArrayList<ClassMapping>(classes())) {
157 if (classMapping.renameObfClass(oldObfName, newObfName)) {
158 boolean wasRemoved = m_classesByObf.remove(oldObfName) != null;
159 assert (wasRemoved);
160 boolean wasAdded = m_classesByObf.put(newObfName, classMapping) == null;
161 assert (wasAdded);
162 }
163 }
164 }
165
166 public Set<String> getAllObfClassNames() {
167 final Set<String> classNames = Sets.newHashSet();
168 for (ClassMapping classMapping : classes()) {
169 // add the class name
170 classNames.add(classMapping.getObfName());
171
172 // add classes from method signatures
173 for (MethodMapping methodMapping : classMapping.methods()) {
174 SignatureUpdater.update(methodMapping.getObfSignature(), new ClassNameUpdater() {
175 @Override
176 public String update(String className) {
177 classNames.add(className);
178 return className;
179 }
180 });
181 }
182 }
183 return classNames;
184 }
185
186 public boolean containsDeobfClass(String deobfName) {
187 return m_classesByDeobf.containsKey(deobfName);
188 }
189
190 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) {
191 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
192 if (classMapping != null) {
193 return classMapping.containsDeobfField(deobfName);
194 }
195 return false;
196 }
197
198 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, String deobfSignature) {
199 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
200 if (classMapping != null) {
201 return classMapping.containsDeobfMethod(deobfName, deobfSignature);
202 }
203 return false;
204 }
205
206 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
207 ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName());
208 if (classMapping != null) {
209 return classMapping.containsArgument(obfBehaviorEntry, name);
210 }
211 return false;
212 }
213}
diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java
new file mode 100644
index 0000000..72e829d
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingsReader.java
@@ -0,0 +1,176 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.BufferedReader;
14import java.io.IOException;
15import java.io.Reader;
16import java.util.Deque;
17
18import com.google.common.collect.Queues;
19
20import cuchaz.enigma.Constants;
21import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
22
23public class MappingsReader {
24
25 public Mappings read(Reader in) throws IOException, MappingParseException {
26 return read(new BufferedReader(in));
27 }
28
29 public Mappings read(BufferedReader in) throws IOException, MappingParseException {
30 Mappings mappings = new Mappings();
31 Deque<Object> mappingStack = Queues.newArrayDeque();
32
33 int lineNumber = 0;
34 String line = null;
35 while ( (line = in.readLine()) != null) {
36 lineNumber++;
37
38 // strip comments
39 int commentPos = line.indexOf('#');
40 if (commentPos >= 0) {
41 line = line.substring(0, commentPos);
42 }
43
44 // skip blank lines
45 if (line.trim().length() <= 0) {
46 continue;
47 }
48
49 // get the indent of this line
50 int indent = 0;
51 for (int i = 0; i < line.length(); i++) {
52 if (line.charAt(i) != '\t') {
53 break;
54 }
55 indent++;
56 }
57
58 // handle stack pops
59 while (indent < mappingStack.size()) {
60 mappingStack.pop();
61 }
62
63 String[] parts = line.trim().split("\\s");
64 try {
65 // read the first token
66 String token = parts[0];
67
68 if (token.equalsIgnoreCase("CLASS")) {
69 ClassMapping classMapping;
70 if (indent == 0) {
71 // outer class
72 classMapping = readClass(parts, false);
73 mappings.addClassMapping(classMapping);
74 } else if (indent == 1) {
75 // inner class
76 if (! (mappingStack.getFirst() instanceof ClassMapping)) {
77 throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!");
78 }
79
80 classMapping = readClass(parts, true);
81 ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping(classMapping);
82 } else {
83 throw new MappingParseException(lineNumber, "Unexpected CLASS entry nesting!");
84 }
85 mappingStack.push(classMapping);
86 } else if (token.equalsIgnoreCase("FIELD")) {
87 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof ClassMapping)) {
88 throw new MappingParseException(lineNumber, "Unexpected FIELD entry here!");
89 }
90 ((ClassMapping)mappingStack.getFirst()).addFieldMapping(readField(parts));
91 } else if (token.equalsIgnoreCase("METHOD")) {
92 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof ClassMapping)) {
93 throw new MappingParseException(lineNumber, "Unexpected METHOD entry here!");
94 }
95 MethodMapping methodMapping = readMethod(parts);
96 ((ClassMapping)mappingStack.getFirst()).addMethodMapping(methodMapping);
97 mappingStack.push(methodMapping);
98 } else if (token.equalsIgnoreCase("ARG")) {
99 if (mappingStack.isEmpty() || ! (mappingStack.getFirst() instanceof MethodMapping)) {
100 throw new MappingParseException(lineNumber, "Unexpected ARG entry here!");
101 }
102 ((MethodMapping)mappingStack.getFirst()).addArgumentMapping(readArgument(parts));
103 }
104 } catch (ArrayIndexOutOfBoundsException | NumberFormatException ex) {
105 throw new MappingParseException(lineNumber, "Malformed line!");
106 }
107 }
108
109 return mappings;
110 }
111
112 private ArgumentMapping readArgument(String[] parts) {
113 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]);
114 }
115
116 private ClassMapping readClass(String[] parts, boolean makeSimple) {
117 if (parts.length == 2) {
118 String obfName = processName(parts[1], makeSimple);
119 return new ClassMapping(obfName);
120 } else {
121 String obfName = processName(parts[1], makeSimple);
122 String deobfName = processName(parts[2], makeSimple);
123 return new ClassMapping(obfName, deobfName);
124 }
125 }
126
127 private String processName(String name, boolean makeSimple) {
128 if (makeSimple) {
129 return new ClassEntry(name).getSimpleName();
130 } else {
131 return moveClassOutOfDefaultPackage(name, Constants.NonePackage);
132 }
133 }
134
135 private String moveClassOutOfDefaultPackage(String className, String newPackageName) {
136 ClassEntry classEntry = new ClassEntry(className);
137 if (classEntry.isInDefaultPackage()) {
138 return newPackageName + "/" + classEntry.getName();
139 }
140 return className;
141 }
142
143 private FieldMapping readField(String[] parts) {
144 return new FieldMapping(parts[1], parts[2]);
145 }
146
147 private MethodMapping readMethod(String[] parts) {
148 if (parts.length == 3) {
149 String obfName = parts[1];
150 String obfSignature = moveSignatureOutOfDefaultPackage(parts[2], Constants.NonePackage);
151 return new MethodMapping(obfName, obfSignature);
152 } else {
153 String obfName = parts[1];
154 String deobfName = parts[2];
155 String obfSignature = moveSignatureOutOfDefaultPackage(parts[3], Constants.NonePackage);
156 if (obfName.equals(deobfName)) {
157 return new MethodMapping(obfName, obfSignature);
158 } else {
159 return new MethodMapping(obfName, obfSignature, deobfName);
160 }
161 }
162 }
163
164 private String moveSignatureOutOfDefaultPackage(String signature, final String newPackageName) {
165 return SignatureUpdater.update(signature, new ClassNameUpdater() {
166 @Override
167 public String update(String className) {
168 ClassEntry classEntry = new ClassEntry(className);
169 if (classEntry.isInDefaultPackage()) {
170 return newPackageName + "/" + className;
171 }
172 return className;
173 }
174 });
175 }
176}
diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java
new file mode 100644
index 0000000..3aac65a
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -0,0 +1,237 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.IOException;
14import java.io.ObjectOutputStream;
15import java.io.OutputStream;
16import java.util.Set;
17import java.util.zip.GZIPOutputStream;
18
19import cuchaz.enigma.Constants;
20import cuchaz.enigma.analysis.JarIndex;
21
22public class MappingsRenamer {
23
24 private JarIndex m_index;
25 private Mappings m_mappings;
26
27 public MappingsRenamer(JarIndex index, Mappings mappings) {
28 m_index = index;
29 m_mappings = mappings;
30 }
31
32 public void setClassName(ClassEntry obf, String deobfName) {
33 deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass());
34 ClassEntry targetEntry = new ClassEntry(deobfName);
35 if (m_mappings.containsDeobfClass(deobfName) || m_index.containsObfClass(targetEntry)) {
36 throw new IllegalNameException(deobfName, "There is already a class with that name");
37 }
38
39 ClassMapping classMapping = getOrCreateClassMapping(obf);
40
41 if (obf.isInnerClass()) {
42 classMapping.setInnerClassName(obf.getInnerClassName(), deobfName);
43 } else {
44 if (classMapping.getDeobfName() != null) {
45 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
46 assert (wasRemoved);
47 }
48 classMapping.setDeobfName(deobfName);
49 boolean wasAdded = m_mappings.m_classesByDeobf.put(deobfName, classMapping) == null;
50 assert (wasAdded);
51 }
52 }
53
54 public void removeClassMapping(ClassEntry obf) {
55 ClassMapping classMapping = getClassMapping(obf);
56 if (obf.isInnerClass()) {
57 classMapping.setInnerClassName(obf.getName(), null);
58 } else {
59 boolean wasRemoved = m_mappings.m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
60 assert (wasRemoved);
61 classMapping.setDeobfName(null);
62 }
63 }
64
65 public void markClassAsDeobfuscated(ClassEntry obf) {
66 ClassMapping classMapping = getOrCreateClassMapping(obf);
67 if (obf.isInnerClass()) {
68 String innerClassName = Constants.NonePackage + "/" + obf.getInnerClassName();
69 classMapping.setInnerClassName(innerClassName, innerClassName);
70 } else {
71 classMapping.setDeobfName(obf.getName());
72 boolean wasAdded = m_mappings.m_classesByDeobf.put(obf.getName(), classMapping) == null;
73 assert (wasAdded);
74 }
75 }
76
77 public void setFieldName(FieldEntry obf, String deobfName) {
78 deobfName = NameValidator.validateFieldName(deobfName);
79 FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName);
80 if (m_mappings.containsDeobfField(obf.getClassEntry(), deobfName) || m_index.containsObfField(targetEntry)) {
81 throw new IllegalNameException(deobfName, "There is already a field with that name");
82 }
83
84 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
85 classMapping.setFieldName(obf.getName(), deobfName);
86 }
87
88 public void removeFieldMapping(FieldEntry obf) {
89 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry());
90 classMapping.setFieldName(obf.getName(), null);
91 }
92
93 public void markFieldAsDeobfuscated(FieldEntry obf) {
94 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
95 classMapping.setFieldName(obf.getName(), obf.getName());
96 }
97
98 public void setMethodTreeName(MethodEntry obf, String deobfName) {
99 Set<MethodEntry> implementations = m_index.getRelatedMethodImplementations(obf);
100
101 deobfName = NameValidator.validateMethodName(deobfName);
102 for (MethodEntry entry : implementations) {
103 String deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateSignature(obf.getSignature());
104 MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature);
105 if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) {
106 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName());
107 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
108 }
109 }
110
111 for (MethodEntry entry : implementations) {
112 setMethodName(entry, deobfName);
113 }
114 }
115
116 public void setMethodName(MethodEntry obf, String deobfName) {
117 deobfName = NameValidator.validateMethodName(deobfName);
118 MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature());
119 if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) {
120 String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName());
121 throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName);
122 }
123
124 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
125 classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName);
126 }
127
128 public void removeMethodTreeMapping(MethodEntry obf) {
129 for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) {
130 removeMethodMapping(implementation);
131 }
132 }
133
134 public void removeMethodMapping(MethodEntry obf) {
135 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
136 classMapping.setMethodName(obf.getName(), obf.getSignature(), null);
137 }
138
139 public void markMethodTreeAsDeobfuscated(MethodEntry obf) {
140 for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) {
141 markMethodAsDeobfuscated(implementation);
142 }
143 }
144
145 public void markMethodAsDeobfuscated(MethodEntry obf) {
146 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
147 classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName());
148 }
149
150 public void setArgumentName(ArgumentEntry obf, String deobfName) {
151 deobfName = NameValidator.validateArgumentName(deobfName);
152 // NOTE: don't need to check arguments for name collisions with names determined by Procyon
153 if (m_mappings.containsArgument(obf.getBehaviorEntry(), deobfName)) {
154 throw new IllegalNameException(deobfName, "There is already an argument with that name");
155 }
156
157 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
158 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName);
159 }
160
161 public void removeArgumentMapping(ArgumentEntry obf) {
162 ClassMapping classMapping = getClassMappingOrInnerClassMapping(obf.getClassEntry());
163 classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex());
164 }
165
166 public void markArgumentAsDeobfuscated(ArgumentEntry obf) {
167 ClassMapping classMapping = getOrCreateClassMappingOrInnerClassMapping(obf.getClassEntry());
168 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
169 }
170
171 public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) {
172 classMapping.removeFieldMapping(fieldMapping);
173 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
174 if (!targetClassMapping.containsObfField(fieldMapping.getObfName())) {
175 if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName())) {
176 targetClassMapping.addFieldMapping(fieldMapping);
177 return true;
178 } else {
179 System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName());
180 }
181 }
182 return false;
183 }
184
185 public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) {
186 classMapping.removeMethodMapping(methodMapping);
187 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
188 if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) {
189 if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) {
190 targetClassMapping.addMethodMapping(methodMapping);
191 return true;
192 } else {
193 System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature());
194 }
195 }
196 return false;
197 }
198
199 public void write(OutputStream out) throws IOException {
200 // TEMP: just use the object output for now. We can find a more efficient storage format later
201 GZIPOutputStream gzipout = new GZIPOutputStream(out);
202 ObjectOutputStream oout = new ObjectOutputStream(gzipout);
203 oout.writeObject(this);
204 gzipout.finish();
205 }
206
207 private ClassMapping getClassMapping(ClassEntry obfClassEntry) {
208 return m_mappings.m_classesByObf.get(obfClassEntry.getOuterClassName());
209 }
210
211 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) {
212 String obfClassName = obfClassEntry.getOuterClassName();
213 ClassMapping classMapping = m_mappings.m_classesByObf.get(obfClassName);
214 if (classMapping == null) {
215 classMapping = new ClassMapping(obfClassName);
216 boolean obfWasAdded = m_mappings.m_classesByObf.put(classMapping.getObfName(), classMapping) == null;
217 assert (obfWasAdded);
218 }
219 return classMapping;
220 }
221
222 private ClassMapping getClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) {
223 ClassMapping classMapping = getClassMapping(obfClassEntry);
224 if (obfClassEntry.isInDefaultPackage()) {
225 classMapping = classMapping.getInnerClassByObf(obfClassEntry.getInnerClassName());
226 }
227 return classMapping;
228 }
229
230 private ClassMapping getOrCreateClassMappingOrInnerClassMapping(ClassEntry obfClassEntry) {
231 ClassMapping classMapping = getOrCreateClassMapping(obfClassEntry);
232 if (obfClassEntry.isInnerClass()) {
233 classMapping = classMapping.getOrCreateInnerClass(obfClassEntry.getInnerClassName());
234 }
235 return classMapping;
236 }
237}
diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java
new file mode 100644
index 0000000..5ac409f
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingsWriter.java
@@ -0,0 +1,88 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.IOException;
14import java.io.PrintWriter;
15import java.io.Writer;
16import java.util.ArrayList;
17import java.util.Collections;
18import java.util.List;
19
20public class MappingsWriter {
21
22 public void write(Writer out, Mappings mappings) throws IOException {
23 write(new PrintWriter(out), mappings);
24 }
25
26 public void write(PrintWriter out, Mappings mappings) throws IOException {
27 for (ClassMapping classMapping : sorted(mappings.classes())) {
28 write(out, classMapping, 0);
29 }
30 }
31
32 private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException {
33 if (classMapping.getDeobfName() == null) {
34 out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfName());
35 } else {
36 out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfName(), classMapping.getDeobfName());
37 }
38
39 for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) {
40 write(out, innerClassMapping, depth + 1);
41 }
42
43 for (FieldMapping fieldMapping : sorted(classMapping.fields())) {
44 write(out, fieldMapping, depth + 1);
45 }
46
47 for (MethodMapping methodMapping : sorted(classMapping.methods())) {
48 write(out, methodMapping, depth + 1);
49 }
50 }
51
52 private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException {
53 out.format("%sFIELD %s %s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName());
54 }
55
56 private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException {
57 if (methodMapping.getDeobfName() == null) {
58 out.format("%sMETHOD %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature());
59 } else {
60 out.format("%sMETHOD %s %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature());
61 }
62
63 for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) {
64 write(out, argumentMapping, depth + 1);
65 }
66 }
67
68 private void write(PrintWriter out, ArgumentMapping argumentMapping, int depth) throws IOException {
69 out.format("%sARG %d %s\n", getIndent(depth), argumentMapping.getIndex(), argumentMapping.getName());
70 }
71
72 private <T extends Comparable<T>> List<T> sorted(Iterable<T> classes) {
73 List<T> out = new ArrayList<T>();
74 for (T t : classes) {
75 out.add(t);
76 }
77 Collections.sort(out);
78 return out;
79 }
80
81 private String getIndent(int depth) {
82 StringBuilder buf = new StringBuilder();
83 for (int i = 0; i < depth; i++) {
84 buf.append("\t");
85 }
86 return buf.toString();
87 }
88}
diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java
new file mode 100644
index 0000000..beb490d
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MethodEntry.java
@@ -0,0 +1,104 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class MethodEntry implements BehaviorEntry, Serializable {
18
19 private static final long serialVersionUID = 4770915224467247458L;
20
21 private ClassEntry m_classEntry;
22 private String m_name;
23 private String m_signature;
24
25 public MethodEntry(ClassEntry classEntry, String name, String signature) {
26 if (classEntry == null) {
27 throw new IllegalArgumentException("Class cannot be null!");
28 }
29 if (name == null) {
30 throw new IllegalArgumentException("Method name cannot be null!");
31 }
32 if (signature == null) {
33 throw new IllegalArgumentException("Method signature cannot be null!");
34 }
35 if (name.startsWith("<")) {
36 throw new IllegalArgumentException("Don't use MethodEntry for a constructor!");
37 }
38
39 m_classEntry = classEntry;
40 m_name = name;
41 m_signature = signature;
42 }
43
44 public MethodEntry(MethodEntry other) {
45 m_classEntry = new ClassEntry(other.m_classEntry);
46 m_name = other.m_name;
47 m_signature = other.m_signature;
48 }
49
50 public MethodEntry(MethodEntry other, String newClassName) {
51 m_classEntry = new ClassEntry(newClassName);
52 m_name = other.m_name;
53 m_signature = other.m_signature;
54 }
55
56 @Override
57 public ClassEntry getClassEntry() {
58 return m_classEntry;
59 }
60
61 @Override
62 public String getName() {
63 return m_name;
64 }
65
66 @Override
67 public String getSignature() {
68 return m_signature;
69 }
70
71 @Override
72 public String getClassName() {
73 return m_classEntry.getName();
74 }
75
76 @Override
77 public MethodEntry cloneToNewClass(ClassEntry classEntry) {
78 return new MethodEntry(this, classEntry.getName());
79 }
80
81 @Override
82 public int hashCode() {
83 return Util.combineHashesOrdered(m_classEntry, m_name, m_signature);
84 }
85
86 @Override
87 public boolean equals(Object other) {
88 if (other instanceof MethodEntry) {
89 return equals((MethodEntry)other);
90 }
91 return false;
92 }
93
94 public boolean equals(MethodEntry other) {
95 return m_classEntry.equals(other.m_classEntry)
96 && m_name.equals(other.m_name)
97 && m_signature.equals(other.m_signature);
98 }
99
100 @Override
101 public String toString() {
102 return m_classEntry.getName() + "." + m_name + m_signature;
103 }
104}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
new file mode 100644
index 0000000..4dab3c6
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -0,0 +1,162 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.Serializable;
14import java.util.Map;
15import java.util.TreeMap;
16
17import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
18
19public class MethodMapping implements Serializable, Comparable<MethodMapping> {
20
21 private static final long serialVersionUID = -4409570216084263978L;
22
23 private String m_obfName;
24 private String m_deobfName;
25 private String m_obfSignature;
26 private Map<Integer,ArgumentMapping> m_arguments;
27
28 public MethodMapping(String obfName, String obfSignature) {
29 this(obfName, obfSignature, null);
30 }
31
32 public MethodMapping(String obfName, String obfSignature, String deobfName) {
33 if (obfName == null) {
34 throw new IllegalArgumentException("obf name cannot be null!");
35 }
36 if (obfSignature == null) {
37 throw new IllegalArgumentException("obf signature cannot be null!");
38 }
39 m_obfName = obfName;
40 m_deobfName = NameValidator.validateMethodName(deobfName);
41 m_obfSignature = obfSignature;
42 m_arguments = new TreeMap<Integer,ArgumentMapping>();
43 }
44
45 public String getObfName() {
46 return m_obfName;
47 }
48
49 public String getDeobfName() {
50 return m_deobfName;
51 }
52
53 public void setDeobfName(String val) {
54 m_deobfName = NameValidator.validateMethodName(val);
55 }
56
57 public String getObfSignature() {
58 return m_obfSignature;
59 }
60
61 public Iterable<ArgumentMapping> arguments() {
62 return m_arguments.values();
63 }
64
65 public boolean isConstructor() {
66 return m_obfName.startsWith("<");
67 }
68
69 public void addArgumentMapping(ArgumentMapping argumentMapping) {
70 boolean wasAdded = m_arguments.put(argumentMapping.getIndex(), argumentMapping) == null;
71 assert (wasAdded);
72 }
73
74 public String getObfArgumentName(int index) {
75 ArgumentMapping argumentMapping = m_arguments.get(index);
76 if (argumentMapping != null) {
77 return argumentMapping.getName();
78 }
79
80 return null;
81 }
82
83 public String getDeobfArgumentName(int index) {
84 ArgumentMapping argumentMapping = m_arguments.get(index);
85 if (argumentMapping != null) {
86 return argumentMapping.getName();
87 }
88
89 return null;
90 }
91
92 public void setArgumentName(int index, String name) {
93 ArgumentMapping argumentMapping = m_arguments.get(index);
94 if (argumentMapping == null) {
95 argumentMapping = new ArgumentMapping(index, name);
96 boolean wasAdded = m_arguments.put(index, argumentMapping) == null;
97 assert (wasAdded);
98 } else {
99 argumentMapping.setName(name);
100 }
101 }
102
103 public void removeArgumentName(int index) {
104 boolean wasRemoved = m_arguments.remove(index) != null;
105 assert (wasRemoved);
106 }
107
108 @Override
109 public String toString() {
110 StringBuilder buf = new StringBuilder();
111 buf.append("\t");
112 buf.append(m_obfName);
113 buf.append(" <-> ");
114 buf.append(m_deobfName);
115 buf.append("\n");
116 buf.append("\t");
117 buf.append(m_obfSignature);
118 buf.append("\n");
119 buf.append("\tArguments:\n");
120 for (ArgumentMapping argumentMapping : m_arguments.values()) {
121 buf.append("\t\t");
122 buf.append(argumentMapping.getIndex());
123 buf.append(" -> ");
124 buf.append(argumentMapping.getName());
125 buf.append("\n");
126 }
127 return buf.toString();
128 }
129
130 @Override
131 public int compareTo(MethodMapping other) {
132 return (m_obfName + m_obfSignature).compareTo(other.m_obfName + other.m_obfSignature);
133 }
134
135 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
136 // rename obf classes in the signature
137 String newSignature = SignatureUpdater.update(m_obfSignature, new ClassNameUpdater() {
138 @Override
139 public String update(String className) {
140 if (className.equals(oldObfClassName)) {
141 return newObfClassName;
142 }
143 return className;
144 }
145 });
146
147 if (newSignature != m_obfSignature) {
148 m_obfSignature = newSignature;
149 return true;
150 }
151 return false;
152 }
153
154 public boolean containsArgument(String name) {
155 for (ArgumentMapping argumentMapping : m_arguments.values()) {
156 if (argumentMapping.getName().equals(name)) {
157 return true;
158 }
159 }
160 return false;
161 }
162}
diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java
new file mode 100644
index 0000000..35a17f9
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/NameValidator.java
@@ -0,0 +1,80 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.util.Arrays;
14import java.util.List;
15import java.util.regex.Pattern;
16
17import javassist.bytecode.Descriptor;
18
19public class NameValidator {
20
21 private static final Pattern IdentifierPattern;
22 private static final Pattern ClassPattern;
23 private static final List<String> ReservedWords = Arrays.asList(
24 "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized",
25 "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte",
26 "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch",
27 "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally",
28 "long", "strictfp", "volatile", "const", "float", "native", "super", "while"
29 );
30
31 static {
32
33 // java allows all kinds of weird characters...
34 StringBuilder startChars = new StringBuilder();
35 StringBuilder partChars = new StringBuilder();
36 for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) {
37 if (Character.isJavaIdentifierStart(i)) {
38 startChars.appendCodePoint(i);
39 }
40 if (Character.isJavaIdentifierPart(i)) {
41 partChars.appendCodePoint(i);
42 }
43 }
44
45 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*";
46 IdentifierPattern = Pattern.compile(identifierRegex);
47 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex));
48 }
49
50 public static String validateClassName(String name, boolean packageRequired) {
51 if (name == null) {
52 return null;
53 }
54 if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) {
55 throw new IllegalNameException(name, "This doesn't look like a legal class name");
56 }
57 if (packageRequired && new ClassEntry(name).getPackageName() == null) {
58 throw new IllegalNameException(name, "Class must be in a package");
59 }
60 return Descriptor.toJvmName(name);
61 }
62
63 public static String validateFieldName(String name) {
64 if (name == null) {
65 return null;
66 }
67 if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) {
68 throw new IllegalNameException(name, "This doesn't look like a legal identifier");
69 }
70 return name;
71 }
72
73 public static String validateMethodName(String name) {
74 return validateFieldName(name);
75 }
76
77 public static String validateArgumentName(String name) {
78 return validateFieldName(name);
79 }
80}
diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java
new file mode 100644
index 0000000..3477cd5
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/SignatureUpdater.java
@@ -0,0 +1,94 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.io.IOException;
14import java.io.StringReader;
15import java.util.List;
16
17import com.google.common.collect.Lists;
18
19public class SignatureUpdater {
20
21 public interface ClassNameUpdater {
22 String update(String className);
23 }
24
25 public static String update(String signature, ClassNameUpdater updater) {
26 try {
27 StringBuilder buf = new StringBuilder();
28
29 // read the signature character-by-character
30 StringReader reader = new StringReader(signature);
31 int i = -1;
32 while ( (i = reader.read()) != -1) {
33 char c = (char)i;
34
35 // does this character start a class name?
36 if (c == 'L') {
37 // update the class name and add it to the buffer
38 buf.append('L');
39 String className = readClass(reader);
40 if (className == null) {
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
51 return buf.toString();
52 } catch (IOException ex) {
53 // I'm pretty sure a StringReader will never throw one of these
54 throw new Error(ex);
55 }
56 }
57
58 private static String readClass(StringReader reader) throws IOException {
59 // read all the characters in the buffer until we hit a ';'
60 // remember to treat generics correctly
61 StringBuilder buf = new StringBuilder();
62 int depth = 0;
63 int i = -1;
64 while ( (i = reader.read()) != -1) {
65 char c = (char)i;
66
67 if (c == '<') {
68 depth++;
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
80 return null;
81 }
82
83 public static List<String> getClasses(String signature) {
84 final List<String> classNames = Lists.newArrayList();
85 update(signature, new ClassNameUpdater() {
86 @Override
87 public String update(String className) {
88 classNames.add(className);
89 return className;
90 }
91 });
92 return classNames;
93 }
94}
diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java
new file mode 100644
index 0000000..d1b14cd
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/TranslationDirection.java
@@ -0,0 +1,29 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13public enum TranslationDirection {
14
15 Deobfuscating {
16 @Override
17 public <T> T choose(T deobfChoice, T obfChoice) {
18 return deobfChoice;
19 }
20 },
21 Obfuscating {
22 @Override
23 public <T> T choose(T deobfChoice, T obfChoice) {
24 return obfChoice;
25 }
26 };
27
28 public abstract <T> T choose(T deobfChoice, T obfChoice);
29}
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
new file mode 100644
index 0000000..a5a3e2f
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -0,0 +1,235 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.util.Map;
14
15import com.google.common.collect.Maps;
16
17import cuchaz.enigma.analysis.TranslationIndex;
18import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
19
20public class Translator {
21
22 private TranslationDirection m_direction;
23 private Map<String,ClassMapping> m_classes;
24 private TranslationIndex m_index;
25
26 public Translator() {
27 m_direction = null;
28 m_classes = Maps.newHashMap();
29 }
30
31 public Translator(TranslationDirection direction, Map<String,ClassMapping> classes, TranslationIndex index) {
32 m_direction = direction;
33 m_classes = classes;
34 m_index = index;
35 }
36
37 @SuppressWarnings("unchecked")
38 public <T extends Entry> T translateEntry(T entry) {
39 if (entry instanceof ClassEntry) {
40 return (T)translateEntry((ClassEntry)entry);
41 } else if (entry instanceof FieldEntry) {
42 return (T)translateEntry((FieldEntry)entry);
43 } else if (entry instanceof MethodEntry) {
44 return (T)translateEntry((MethodEntry)entry);
45 } else if (entry instanceof ConstructorEntry) {
46 return (T)translateEntry((ConstructorEntry)entry);
47 } else if (entry instanceof ArgumentEntry) {
48 return (T)translateEntry((ArgumentEntry)entry);
49 } else {
50 throw new Error("Unknown entry type: " + entry.getClass().getName());
51 }
52 }
53
54 public String translateClass(String className) {
55 return translate(new ClassEntry(className));
56 }
57
58 public String translate(ClassEntry in) {
59 ClassMapping classMapping = m_classes.get(in.getOuterClassName());
60 if (classMapping != null) {
61 if (in.isInnerClass()) {
62 // translate the inner class
63 String translatedInnerClassName = m_direction.choose(
64 classMapping.getDeobfInnerClassName(in.getInnerClassName()),
65 classMapping.getObfInnerClassName(in.getInnerClassName())
66 );
67 if (translatedInnerClassName != null) {
68 // try to translate the outer name
69 String translatedOuterClassName = m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName());
70 if (translatedOuterClassName != null) {
71 return translatedOuterClassName + "$" + translatedInnerClassName;
72 } else {
73 return in.getOuterClassName() + "$" + translatedInnerClassName;
74 }
75 }
76 } else {
77 // just return outer
78 return m_direction.choose(classMapping.getDeobfName(), classMapping.getObfName());
79 }
80 }
81 return null;
82 }
83
84 public ClassEntry translateEntry(ClassEntry in) {
85
86 // can we translate the inner class?
87 String name = translate(in);
88 if (name != null) {
89 return new ClassEntry(name);
90 }
91
92 if (in.isInnerClass()) {
93
94 // guess not. just translate the outer class name then
95 String outerClassName = translate(in.getOuterClassEntry());
96 if (outerClassName != null) {
97 return new ClassEntry(outerClassName + "$" + in.getInnerClassName());
98 }
99 }
100
101 return in;
102 }
103
104 public String translate(FieldEntry in) {
105
106 // resolve the class entry
107 ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in);
108 if (resolvedClassEntry != null) {
109
110 // look for the class
111 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
112 if (classMapping != null) {
113
114 // look for the field
115 String translatedName = m_direction.choose(
116 classMapping.getDeobfFieldName(in.getName()),
117 classMapping.getObfFieldName(in.getName())
118 );
119 if (translatedName != null) {
120 return translatedName;
121 }
122 }
123 }
124 return null;
125 }
126
127 public FieldEntry translateEntry(FieldEntry in) {
128 String name = translate(in);
129 if (name == null) {
130 name = in.getName();
131 }
132 return new FieldEntry(translateEntry(in.getClassEntry()), name);
133 }
134
135 public String translate(MethodEntry in) {
136
137 // resolve the class entry
138 ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in);
139 if (resolvedClassEntry != null) {
140
141 // look for class
142 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
143 if (classMapping != null) {
144
145 // look for the method
146 MethodMapping methodMapping = m_direction.choose(
147 classMapping.getMethodByObf(in.getName(), in.getSignature()),
148 classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))
149 );
150 if (methodMapping != null) {
151 return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName());
152 }
153 }
154 }
155 return null;
156 }
157
158 public MethodEntry translateEntry(MethodEntry in) {
159 String name = translate(in);
160 if (name == null) {
161 name = in.getName();
162 }
163 return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature()));
164 }
165
166 public ConstructorEntry translateEntry(ConstructorEntry in) {
167 if (in.isStatic()) {
168 return new ConstructorEntry(translateEntry(in.getClassEntry()));
169 } else {
170 return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature()));
171 }
172 }
173
174 public BehaviorEntry translateEntry(BehaviorEntry in) {
175 if (in instanceof MethodEntry) {
176 return translateEntry((MethodEntry)in);
177 } else if (in instanceof ConstructorEntry) {
178 return translateEntry((ConstructorEntry)in);
179 }
180 throw new Error("Wrong entry type!");
181 }
182
183 public String translate(ArgumentEntry in) {
184
185 // look for the class
186 ClassMapping classMapping = findClassMapping(in.getClassEntry());
187 if (classMapping != null) {
188
189 // look for the method
190 MethodMapping methodMapping = m_direction.choose(
191 classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()),
192 classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature()))
193 );
194 if (methodMapping != null) {
195 return m_direction.choose(
196 methodMapping.getDeobfArgumentName(in.getIndex()),
197 methodMapping.getObfArgumentName(in.getIndex())
198 );
199 }
200 }
201 return null;
202 }
203
204 public ArgumentEntry translateEntry(ArgumentEntry in) {
205 String name = translate(in);
206 if (name == null) {
207 name = in.getName();
208 }
209 return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name);
210 }
211
212 public String translateSignature(String signature) {
213 return SignatureUpdater.update(signature, new ClassNameUpdater() {
214 @Override
215 public String update(String className) {
216 String translatedName = translateClass(className);
217 if (translatedName != null) {
218 return translatedName;
219 }
220 return className;
221 }
222 });
223 }
224
225 private ClassMapping findClassMapping(ClassEntry classEntry) {
226 ClassMapping classMapping = m_classes.get(classEntry.getOuterClassName());
227 if (classMapping != null && classEntry.isInnerClass()) {
228 classMapping = m_direction.choose(
229 classMapping.getInnerClassByObf(classEntry.getInnerClassName()),
230 classMapping.getInnerClassByDeobfThenObf(classEntry.getInnerClassName())
231 );
232 }
233 return classMapping;
234 }
235}