summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/mapping/MappingsReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/mapping/MappingsReader.java')
-rw-r--r--src/cuchaz/enigma/mapping/MappingsReader.java176
1 files changed, 176 insertions, 0 deletions
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}