summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/mapping
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/mapping')
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java6
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java5
-rw-r--r--src/main/java/cuchaz/enigma/mapping/ClassMapping.java87
-rw-r--r--src/main/java/cuchaz/enigma/mapping/EntryFactory.java20
-rw-r--r--src/main/java/cuchaz/enigma/mapping/EntryPair.java22
-rw-r--r--src/main/java/cuchaz/enigma/mapping/FieldMapping.java39
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java44
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java6
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java40
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MemberMapping.java2
-rw-r--r--src/main/java/cuchaz/enigma/mapping/MethodMapping.java50
-rw-r--r--src/main/java/cuchaz/enigma/mapping/NameValidator.java11
-rw-r--r--src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java91
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Translator.java8
14 files changed, 428 insertions, 3 deletions
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
index 1409fc4..741849a 100644
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
+++ b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java
@@ -34,6 +34,12 @@ public class ArgumentEntry implements Entry {
34 this.name = name; 34 this.name = name;
35 } 35 }
36 36
37 public ArgumentEntry(ArgumentEntry other) {
38 this.behaviorEntry = other.getBehaviorEntry();
39 this.index = other.index;
40 this.name = other.name;
41 }
42
37 public ArgumentEntry(ArgumentEntry other, String newClassName) { 43 public ArgumentEntry(ArgumentEntry other, String newClassName) {
38 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName)); 44 this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName));
39 this.index = other.index; 45 this.index = other.index;
diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
index 918395f..d117de0 100644
--- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -21,6 +21,11 @@ public class ArgumentMapping implements Comparable<ArgumentMapping> {
21 this.name = NameValidator.validateArgumentName(name); 21 this.name = NameValidator.validateArgumentName(name);
22 } 22 }
23 23
24 public ArgumentMapping(ArgumentMapping other) {
25 this.index = other.index;
26 this.name = other.name;
27 }
28
24 public int getIndex() { 29 public int getIndex() {
25 return this.index; 30 return this.index;
26 } 31 }
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
index b2c076a..36b35f7 100644
--- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java
@@ -12,6 +12,7 @@ package cuchaz.enigma.mapping;
12 12
13import com.google.common.collect.Maps; 13import com.google.common.collect.Maps;
14 14
15import java.util.ArrayList;
15import java.util.Map; 16import java.util.Map;
16 17
17import cuchaz.enigma.throwables.MappingConflict; 18import cuchaz.enigma.throwables.MappingConflict;
@@ -119,6 +120,15 @@ public class ClassMapping implements Comparable<ClassMapping> {
119 return classMapping; 120 return classMapping;
120 } 121 }
121 122
123 public String getDeobfInnerClassName(String obfSimpleName) {
124 assert (isSimpleClassName(obfSimpleName));
125 ClassMapping classMapping = m_innerClassesByObfSimple.get(obfSimpleName);
126 if (classMapping != null) {
127 return classMapping.getDeobfName();
128 }
129 return null;
130 }
131
122 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) { 132 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) {
123 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass); 133 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass);
124 if (classMapping.getDeobfName() != null) { 134 if (classMapping.getDeobfName() != null) {
@@ -149,6 +159,10 @@ public class ClassMapping implements Comparable<ClassMapping> {
149 return m_fieldsByObf.values(); 159 return m_fieldsByObf.values();
150 } 160 }
151 161
162 public boolean containsObfField(String obfName, Type obfType) {
163 return m_fieldsByObf.containsKey(getFieldKey(obfName, obfType));
164 }
165
152 public boolean containsDeobfField(String deobfName, Type deobfType) { 166 public boolean containsDeobfField(String deobfName, Type deobfType) {
153 return m_fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType)); 167 return m_fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType));
154 } 168 }
@@ -182,6 +196,10 @@ public class ClassMapping implements Comparable<ClassMapping> {
182 return m_fieldsByObf.get(getFieldKey(obfName, obfType)); 196 return m_fieldsByObf.get(getFieldKey(obfName, obfType));
183 } 197 }
184 198
199 public FieldMapping getFieldByDeobf(String deobfName, Type obfType) {
200 return m_fieldsByDeobf.get(getFieldKey(deobfName, obfType));
201 }
202
185 public String getObfFieldName(String deobfName, Type obfType) { 203 public String getObfFieldName(String deobfName, Type obfType) {
186 FieldMapping fieldMapping = m_fieldsByDeobf.get(getFieldKey(deobfName, obfType)); 204 FieldMapping fieldMapping = m_fieldsByDeobf.get(getFieldKey(deobfName, obfType));
187 if (fieldMapping != null) { 205 if (fieldMapping != null) {
@@ -227,6 +245,16 @@ public class ClassMapping implements Comparable<ClassMapping> {
227 } 245 }
228 } 246 }
229 247
248 public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) {
249 assert(newObfName != null);
250 FieldMapping fieldMapping = m_fieldsByObf.remove(getFieldKey(oldObfName, obfType));
251 assert(fieldMapping != null);
252 fieldMapping.setObfName(newObfName);
253 fieldMapping.setObfType(newObfType);
254 boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null;
255 assert(obfWasAdded);
256 }
257
230 //// METHODS //////// 258 //// METHODS ////////
231 259
232 public Iterable<MethodMapping> methods() { 260 public Iterable<MethodMapping> methods() {
@@ -234,6 +262,10 @@ public class ClassMapping implements Comparable<ClassMapping> {
234 return m_methodsByObf.values(); 262 return m_methodsByObf.values();
235 } 263 }
236 264
265 public boolean containsObfMethod(String obfName, Signature obfSignature) {
266 return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
267 }
268
237 public boolean containsDeobfMethod(String deobfName, Signature obfSignature) { 269 public boolean containsDeobfMethod(String deobfName, Signature obfSignature) {
238 return m_methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature)); 270 return m_methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature));
239 } 271 }
@@ -298,6 +330,16 @@ public class ClassMapping implements Comparable<ClassMapping> {
298 } 330 }
299 } 331 }
300 332
333 public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) {
334 assert(newObfName != null);
335 MethodMapping methodMapping = m_methodsByObf.remove(getMethodKey(oldObfName, obfSignature));
336 assert(methodMapping != null);
337 methodMapping.setObfName(newObfName);
338 methodMapping.setObfSignature(newObfSignature);
339 boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null;
340 assert(obfWasAdded);
341 }
342
301 //// ARGUMENTS //////// 343 //// ARGUMENTS ////////
302 344
303 public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) { 345 public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) {
@@ -360,6 +402,48 @@ public class ClassMapping implements Comparable<ClassMapping> {
360 return m_obfFullName.compareTo(other.m_obfFullName); 402 return m_obfFullName.compareTo(other.m_obfFullName);
361 } 403 }
362 404
405 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
406
407 // rename inner classes
408 for (ClassMapping innerClassMapping : new ArrayList<>(m_innerClassesByObfSimple.values())) {
409 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
410 boolean wasRemoved = m_innerClassesByObfSimple.remove(oldObfClassName) != null;
411 assert (wasRemoved);
412 boolean wasAdded = m_innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null;
413 assert (wasAdded);
414 }
415 }
416
417 // rename field types
418 for (FieldMapping fieldMapping : new ArrayList<>(m_fieldsByObf.values())) {
419 String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
420 if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) {
421 boolean wasRemoved = m_fieldsByObf.remove(oldFieldKey) != null;
422 assert (wasRemoved);
423 boolean wasAdded = m_fieldsByObf.put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null;
424 assert (wasAdded);
425 }
426 }
427
428 // rename method signatures
429 for (MethodMapping methodMapping : new ArrayList<>(m_methodsByObf.values())) {
430 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
431 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
432 boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null;
433 assert (wasRemoved);
434 boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
435 assert (wasAdded);
436 }
437 }
438
439 if (m_obfFullName.equals(oldObfClassName)) {
440 // rename this class
441 m_obfFullName = newObfClassName;
442 return true;
443 }
444 return false;
445 }
446
363 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { 447 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
364 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); 448 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
365 return methodMapping != null && methodMapping.containsArgument(name); 449 return methodMapping != null && methodMapping.containsArgument(name);
@@ -369,4 +453,7 @@ public class ClassMapping implements Comparable<ClassMapping> {
369 return name.indexOf('/') < 0 && name.indexOf('$') < 0; 453 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
370 } 454 }
371 455
456 public ClassEntry getObfEntry() {
457 return new ClassEntry(m_obfFullName);
458 }
372} 459}
diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
index 2351dcf..ce4b948 100644
--- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
+++ b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java
@@ -33,6 +33,10 @@ public class EntryFactory {
33 return new ClassEntry(classMapping.getObfFullName()); 33 return new ClassEntry(classMapping.getObfFullName());
34 } 34 }
35 35
36 public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) {
37 return new ClassEntry(classMapping.getDeobfName());
38 }
39
36 public static ClassEntry getSuperclassEntry(CtClass c) { 40 public static ClassEntry getSuperclassEntry(CtClass c) {
37 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); 41 return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass()));
38 } 42 }
@@ -90,6 +94,10 @@ public class EntryFactory {
90 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature)); 94 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature));
91 } 95 }
92 96
97 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) {
98 return getBehaviorEntry(new ClassEntry(className), behaviorName);
99 }
100
93 public static BehaviorEntry getBehaviorEntry(String className) { 101 public static BehaviorEntry getBehaviorEntry(String className) {
94 return new ConstructorEntry(new ClassEntry(className)); 102 return new ConstructorEntry(new ClassEntry(className));
95 } 103 }
@@ -105,7 +113,19 @@ public class EntryFactory {
105 } 113 }
106 } 114 }
107 115
116 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) {
117 if(behaviorName.equals("<clinit>")) {
118 return new ConstructorEntry(classEntry);
119 } else {
120 throw new IllegalArgumentException("Only class initializers don't have signatures");
121 }
122 }
123
108 public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { 124 public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) {
109 return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); 125 return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature());
110 } 126 }
127
128 public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) {
129 return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping);
130 }
111} 131}
diff --git a/src/main/java/cuchaz/enigma/mapping/EntryPair.java b/src/main/java/cuchaz/enigma/mapping/EntryPair.java
new file mode 100644
index 0000000..1c93d53
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/EntryPair.java
@@ -0,0 +1,22 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
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/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
index 3ec1af0..1b59660 100644
--- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java
@@ -22,6 +22,17 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie
22 this.obfType = obfType; 22 this.obfType = obfType;
23 } 23 }
24 24
25 public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) {
26 this.obfName = other.obfName;
27 this.deobfName = other.deobfName;
28 this.obfType = new Type(other.obfType, obfClassNameReplacer);
29 }
30
31 @Override
32 public FieldEntry getObfEntry(ClassEntry classEntry) {
33 return new FieldEntry(classEntry, this.obfName, this.obfType);
34 }
35
25 @Override 36 @Override
26 public String getObfName() { 37 public String getObfName() {
27 return this.obfName; 38 return this.obfName;
@@ -35,12 +46,40 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie
35 this.deobfName = NameValidator.validateFieldName(val); 46 this.deobfName = NameValidator.validateFieldName(val);
36 } 47 }
37 48
49 public void setObfName(String val) {
50 this.obfName = NameValidator.validateFieldName(val);
51 }
52
38 public Type getObfType() { 53 public Type getObfType() {
39 return this.obfType; 54 return this.obfType;
40 } 55 }
41 56
57 public void setObfType(Type val) {
58 this.obfType = val;
59 }
60
42 @Override 61 @Override
43 public int compareTo(FieldMapping other) { 62 public int compareTo(FieldMapping other) {
44 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); 63 return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType);
45 } 64 }
65
66 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
67 // rename obf classes in the type
68 Type newType = new Type(this.obfType, new ClassNameReplacer() {
69 @Override
70 public String replace(String className) {
71 if (className.equals(oldObfClassName)) {
72 return newObfClassName;
73 }
74 return null;
75 }
76 });
77
78 if (!newType.equals(this.obfType)) {
79 this.obfType = newType;
80 return true;
81 }
82 return false;
83 }
84
46} 85}
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index 538c67e..171ddf1 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -13,10 +13,13 @@ package cuchaz.enigma.mapping;
13import com.google.common.collect.Lists; 13import com.google.common.collect.Lists;
14import com.google.common.collect.Maps; 14import com.google.common.collect.Maps;
15 15
16import java.util.ArrayList;
16import java.util.Collection; 17import java.util.Collection;
17import java.util.List; 18import java.util.List;
18import java.util.Map; 19import java.util.Map;
20import java.util.Set;
19 21
22import com.google.common.collect.Sets;
20import cuchaz.enigma.analysis.TranslationIndex; 23import cuchaz.enigma.analysis.TranslationIndex;
21import cuchaz.enigma.throwables.MappingConflict; 24import cuchaz.enigma.throwables.MappingConflict;
22 25
@@ -65,10 +68,23 @@ public class Mappings {
65 } 68 }
66 } 69 }
67 70
71
72 public ClassMapping getClassByObf(ClassEntry entry) {
73 return getClassByObf(entry.getName());
74 }
75
68 public ClassMapping getClassByObf(String obfName) { 76 public ClassMapping getClassByObf(String obfName) {
69 return this.classesByObf.get(obfName); 77 return this.classesByObf.get(obfName);
70 } 78 }
71 79
80 public ClassMapping getClassByDeobf(ClassEntry entry) {
81 return getClassByDeobf(entry.getName());
82 }
83
84 public ClassMapping getClassByDeobf(String deobfName) {
85 return this.classesByDeobf.get(deobfName);
86 }
87
72 public void setClassDeobfName(ClassMapping classMapping, String deobfName) { 88 public void setClassDeobfName(ClassMapping classMapping, String deobfName) {
73 if (classMapping.getDeobfName() != null) { 89 if (classMapping.getDeobfName() != null) {
74 boolean wasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null; 90 boolean wasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null;
@@ -120,6 +136,34 @@ public class Mappings {
120 return buf.toString(); 136 return buf.toString();
121 } 137 }
122 138
139 public void renameObfClass(String oldObfName, String newObfName) {
140 new ArrayList<>(classes()).stream().filter(classMapping -> classMapping.renameObfClass(oldObfName, newObfName)).forEach(classMapping -> {
141 boolean wasRemoved = this.classesByObf.remove(oldObfName) != null;
142 assert (wasRemoved);
143 boolean wasAdded = this.classesByObf.put(newObfName, classMapping) == null;
144 assert (wasAdded);
145 });
146 }
147
148 public Set<String> getAllObfClassNames() {
149 final Set<String> classNames = Sets.newHashSet();
150 for (ClassMapping classMapping : classes()) {
151
152 // add the class name
153 classNames.add(classMapping.getObfFullName());
154
155 // add classes from method signatures
156 for (MethodMapping methodMapping : classMapping.methods()) {
157 for (Type type : methodMapping.getObfSignature().types()) {
158 if (type.hasClass()) {
159 classNames.add(type.getClassEntry().getClassName());
160 }
161 }
162 }
163 }
164 return classNames;
165 }
166
123 public boolean containsDeobfClass(String deobfName) { 167 public boolean containsDeobfClass(String deobfName) {
124 return this.classesByDeobf.containsKey(deobfName); 168 return this.classesByDeobf.containsKey(deobfName);
125 } 169 }
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
index 70f3f18..a27f72e 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java
@@ -85,7 +85,7 @@ public class MappingsEnigmaReader
85 ClassMapping classMapping; 85 ClassMapping classMapping;
86 if (indent <= 0) { 86 if (indent <= 0) {
87 // outer class 87 // outer class
88 classMapping = readClass(parts); 88 classMapping = readClass(parts, false);
89 mappings.addClassMapping(classMapping); 89 mappings.addClassMapping(classMapping);
90 } else { 90 } else {
91 91
@@ -94,7 +94,7 @@ public class MappingsEnigmaReader
94 throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!"); 94 throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!");
95 } 95 }
96 96
97 classMapping = readClass(parts); 97 classMapping = readClass(parts, true);
98 ((ClassMapping) mappingStack.peek()).addInnerClassMapping(classMapping); 98 ((ClassMapping) mappingStack.peek()).addInnerClassMapping(classMapping);
99 } 99 }
100 mappingStack.push(classMapping); 100 mappingStack.push(classMapping);
@@ -130,7 +130,7 @@ public class MappingsEnigmaReader
130 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]); 130 return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]);
131 } 131 }
132 132
133 private ClassMapping readClass(String[] parts) { 133 private ClassMapping readClass(String[] parts, boolean makeSimple) {
134 if (parts.length == 2) { 134 if (parts.length == 2) {
135 return new ClassMapping(parts[1]); 135 return new ClassMapping(parts[1]);
136 } else { 136 } else {
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
index afb8c97..8002813 100644
--- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -10,8 +10,12 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.mapping; 11package cuchaz.enigma.mapping;
12 12
13import java.io.IOException;
14import java.io.ObjectOutputStream;
15import java.io.OutputStream;
13import java.util.List; 16import java.util.List;
14import java.util.Set; 17import java.util.Set;
18import java.util.zip.GZIPOutputStream;
15 19
16import cuchaz.enigma.analysis.JarIndex; 20import cuchaz.enigma.analysis.JarIndex;
17import cuchaz.enigma.throwables.IllegalNameException; 21import cuchaz.enigma.throwables.IllegalNameException;
@@ -165,6 +169,42 @@ public class MappingsRenamer {
165 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); 169 classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName());
166 } 170 }
167 171
172 public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) {
173 classMapping.removeFieldMapping(fieldMapping);
174 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
175 if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfType())) {
176 if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfType())) {
177 targetClassMapping.addFieldMapping(fieldMapping);
178 return true;
179 } else {
180 System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName());
181 }
182 }
183 return false;
184 }
185
186 public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) {
187 classMapping.removeMethodMapping(methodMapping);
188 ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass);
189 if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) {
190 if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) {
191 targetClassMapping.addMethodMapping(methodMapping);
192 return true;
193 } else {
194 System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature());
195 }
196 }
197 return false;
198 }
199
200 public void write(OutputStream out) throws IOException {
201 // TEMP: just use the object output for now. We can find a more efficient storage format later
202 GZIPOutputStream gzipout = new GZIPOutputStream(out);
203 ObjectOutputStream oout = new ObjectOutputStream(gzipout);
204 oout.writeObject(this);
205 gzipout.finish();
206 }
207
168 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { 208 private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) {
169 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry); 209 List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry);
170 return mappingChain.get(mappingChain.size() - 1); 210 return mappingChain.get(mappingChain.size() - 1);
diff --git a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
index 590c830..90c096f 100644
--- a/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MemberMapping.java
@@ -12,5 +12,7 @@ package cuchaz.enigma.mapping;
12 12
13 13
14public interface MemberMapping<T extends Entry> { 14public interface MemberMapping<T extends Entry> {
15 T getObfEntry(ClassEntry classEntry);
16
15 String getObfName(); 17 String getObfName();
16} 18}
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
index 6e7c1ef..99b9c88 100644
--- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java
@@ -39,6 +39,16 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
39 this.obfSignature = obfSignature; 39 this.obfSignature = obfSignature;
40 this.arguments = Maps.newTreeMap(); 40 this.arguments = Maps.newTreeMap();
41 } 41 }
42
43 public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) {
44 this.obfName = other.obfName;
45 this.deobfName = other.deobfName;
46 this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer);
47 this.arguments = Maps.newTreeMap();
48 for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) {
49 this.arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue()));
50 }
51 }
42 52
43 @Override 53 @Override
44 public String getObfName() { 54 public String getObfName() {
@@ -57,6 +67,14 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
57 return this.obfSignature; 67 return this.obfSignature;
58 } 68 }
59 69
70 public void setObfName(String name) {
71 this.obfName = NameValidator.validateMethodName(name);
72 }
73
74 public void setObfSignature(Signature val) {
75 this.obfSignature = val;
76 }
77
60 public Iterable<ArgumentMapping> arguments() { 78 public Iterable<ArgumentMapping> arguments() {
61 return this.arguments.values(); 79 return this.arguments.values();
62 } 80 }
@@ -137,4 +155,36 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B
137 } 155 }
138 return false; 156 return false;
139 } 157 }
158
159 public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) {
160 // rename obf classes in the signature
161 Signature newSignature = new Signature(this.obfSignature, new ClassNameReplacer() {
162 @Override
163 public String replace(String className) {
164 if (className.equals(oldObfClassName)) {
165 return newObfClassName;
166 }
167 return null;
168 }
169 });
170
171 if (!newSignature.equals(this.obfSignature)) {
172 this.obfSignature = newSignature;
173 return true;
174 }
175 return false;
176 }
177
178 public boolean isConstructor() {
179 return this.obfName.startsWith("<");
180 }
181
182 @Override
183 public BehaviorEntry getObfEntry(ClassEntry classEntry) {
184 if (isConstructor()) {
185 return new ConstructorEntry(classEntry, this.obfSignature);
186 } else {
187 return new MethodEntry(classEntry, this.obfName, this.obfSignature);
188 }
189 }
140} 190}
diff --git a/src/main/java/cuchaz/enigma/mapping/NameValidator.java b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
index 15b0314..7be83c7 100644
--- a/src/main/java/cuchaz/enigma/mapping/NameValidator.java
+++ b/src/main/java/cuchaz/enigma/mapping/NameValidator.java
@@ -32,6 +32,17 @@ public class NameValidator {
32 static { 32 static {
33 33
34 // java allows all kinds of weird characters... 34 // java allows all kinds of weird characters...
35 StringBuilder startChars = new StringBuilder();
36 StringBuilder partChars = new StringBuilder();
37 for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) {
38 if (Character.isJavaIdentifierStart(i)) {
39 startChars.appendCodePoint(i);
40 }
41 if (Character.isJavaIdentifierPart(i)) {
42 partChars.appendCodePoint(i);
43 }
44 }
45
35 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; 46 String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*";
36 IdentifierPattern = Pattern.compile(identifierRegex); 47 IdentifierPattern = Pattern.compile(identifierRegex);
37 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex)); 48 ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex));
diff --git a/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java b/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java
new file mode 100644
index 0000000..9864333
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java
@@ -0,0 +1,91 @@
1/*******************************************************************************
2 * Copyright (c) 2015 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Lesser General Public
5 * License v3.0 which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/lgpl.html
7 * <p>
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import com.google.common.collect.Lists;
14
15import java.io.IOException;
16import java.io.StringReader;
17import java.util.List;
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;
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;
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, className -> {
86 classNames.add(className);
87 return className;
88 });
89 return classNames;
90 }
91}
diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java
index 125e03f..bebac4e 100644
--- a/src/main/java/cuchaz/enigma/mapping/Translator.java
+++ b/src/main/java/cuchaz/enigma/mapping/Translator.java
@@ -38,6 +38,14 @@ public class Translator {
38 this.index = index; 38 this.index = index;
39 } 39 }
40 40
41 public TranslationDirection getDirection() {
42 return direction;
43 }
44
45 public TranslationIndex getTranslationIndex() {
46 return index;
47 }
48
41 @SuppressWarnings("unchecked") 49 @SuppressWarnings("unchecked")
42 public <T extends Entry> T translateEntry(T entry) { 50 public <T extends Entry> T translateEntry(T entry) {
43 if (entry instanceof ClassEntry) { 51 if (entry instanceof ClassEntry) {