summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2014-09-03 00:20:36 -0400
committerGravatar jeff2014-09-03 00:20:36 -0400
commitb5338883d271779c335842c07047d60136316167 (patch)
tree006477e8c1ea0ade75ae8a9003abaf1978995fd7 /src
parentfixed bug with export progress bar (diff)
downloadenigma-b5338883d271779c335842c07047d60136316167.tar.gz
enigma-b5338883d271779c335842c07047d60136316167.tar.xz
enigma-b5338883d271779c335842c07047d60136316167.zip
big refactor to better model class/method mappings with no deobf name
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java2
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java2
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java111
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java90
-rw-r--r--src/cuchaz/enigma/mapping/MappingsReader.java155
-rw-r--r--src/cuchaz/enigma/mapping/MappingsRenamer.java14
-rw-r--r--src/cuchaz/enigma/mapping/MappingsWriter.java29
-rw-r--r--src/cuchaz/enigma/mapping/MethodMapping.java16
-rw-r--r--src/cuchaz/enigma/mapping/NameValidator.java12
9 files changed, 276 insertions, 155 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index d15c25f9..526534da 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -192,7 +192,7 @@ public class Deobfuscator
192 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out 192 // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
193 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name 193 // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name
194 ClassMapping classMapping = m_mappings.getClassByObf( className ); 194 ClassMapping classMapping = m_mappings.getClassByObf( className );
195 if( classMapping != null ) 195 if( classMapping != null && classMapping.getDeobfName() != null )
196 { 196 {
197 className = classMapping.getDeobfName(); 197 className = classMapping.getDeobfName();
198 } 198 }
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index c0fb2e40..5057db2d 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -167,6 +167,8 @@ public class GuiController
167 167
168 public boolean entryHasMapping( Entry deobfEntry ) 168 public boolean entryHasMapping( Entry deobfEntry )
169 { 169 {
170 // TEMP
171 System.out.println( deobfEntry + " -> " + m_deobfuscator.obfuscateEntry( deobfEntry ) );
170 return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); 172 return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) );
171 } 173 }
172 174
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index 5faaf2a1..bce16cc5 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -29,7 +29,11 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
29 private Map<String,MethodMapping> m_methodsByObf; 29 private Map<String,MethodMapping> m_methodsByObf;
30 private Map<String,MethodMapping> m_methodsByDeobf; 30 private Map<String,MethodMapping> m_methodsByDeobf;
31 31
32 // NOTE: this argument order is important for the MethodReader/MethodWriter 32 public ClassMapping( String obfName )
33 {
34 this( obfName, null );
35 }
36
33 public ClassMapping( String obfName, String deobfName ) 37 public ClassMapping( String obfName, String deobfName )
34 { 38 {
35 m_obfName = obfName; 39 m_obfName = obfName;
@@ -60,14 +64,19 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
60 64
61 public Iterable<ClassMapping> innerClasses( ) 65 public Iterable<ClassMapping> innerClasses( )
62 { 66 {
63 assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); 67 assert( m_innerClassesByObf.size() >= m_innerClassesByDeobf.size() );
64 return m_innerClassesByObf.values(); 68 return m_innerClassesByObf.values();
65 } 69 }
66 70
67 protected void addInnerClassMapping( ClassMapping classMapping ) 71 public void addInnerClassMapping( ClassMapping classMapping )
68 { 72 {
69 m_innerClassesByObf.put( classMapping.getObfName(), classMapping ); 73 boolean obfWasAdded = m_innerClassesByObf.put( classMapping.getObfName(), classMapping ) == null;
70 m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ); 74 assert( obfWasAdded );
75 if( classMapping.getDeobfName() != null )
76 {
77 boolean deobfWasAdded = m_innerClassesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null;
78 assert( deobfWasAdded );
79 }
71 } 80 }
72 81
73 public ClassMapping getOrCreateInnerClass( String obfName ) 82 public ClassMapping getOrCreateInnerClass( String obfName )
@@ -75,9 +84,9 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
75 ClassMapping classMapping = m_innerClassesByObf.get( obfName ); 84 ClassMapping classMapping = m_innerClassesByObf.get( obfName );
76 if( classMapping == null ) 85 if( classMapping == null )
77 { 86 {
78 classMapping = new ClassMapping( obfName, obfName ); 87 classMapping = new ClassMapping( obfName );
79 m_innerClassesByObf.put( obfName, classMapping ); 88 boolean wasAdded = m_innerClassesByObf.put( obfName, classMapping ) == null;
80 m_innerClassesByDeobf.put( obfName, classMapping ); 89 assert( wasAdded );
81 } 90 }
82 return classMapping; 91 return classMapping;
83 } 92 }
@@ -115,9 +124,11 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
115 public void setInnerClassName( String obfName, String deobfName ) 124 public void setInnerClassName( String obfName, String deobfName )
116 { 125 {
117 ClassMapping classMapping = getOrCreateInnerClass( obfName ); 126 ClassMapping classMapping = getOrCreateInnerClass( obfName );
118 m_innerClassesByDeobf.remove( classMapping.getDeobfName() ); 127 boolean wasRemoved = m_innerClassesByDeobf.remove( classMapping.getDeobfName() ) != null;
128 assert( wasRemoved );
119 classMapping.setDeobfName( deobfName ); 129 classMapping.setDeobfName( deobfName );
120 m_innerClassesByDeobf.put( deobfName, classMapping ); 130 boolean wasAdded = m_innerClassesByDeobf.put( deobfName, classMapping ) == null;
131 assert( wasAdded );
121 } 132 }
122 133
123 //// FIELDS //////// 134 //// FIELDS ////////
@@ -128,7 +139,7 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
128 return m_fieldsByObf.values(); 139 return m_fieldsByObf.values();
129 } 140 }
130 141
131 protected void addFieldMapping( FieldMapping fieldMapping ) 142 public void addFieldMapping( FieldMapping fieldMapping )
132 { 143 {
133 if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) ) 144 if( m_fieldsByObf.containsKey( fieldMapping.getObfName() ) )
134 { 145 {
@@ -138,8 +149,10 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
138 { 149 {
139 throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() ); 150 throw new Error( "Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName() );
140 } 151 }
141 m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ); 152 boolean obfWasAdded = m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping ) == null;
142 m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ); 153 assert( obfWasAdded );
154 boolean deobfWasAdded = m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping ) == null;
155 assert( deobfWasAdded );
143 assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() ); 156 assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() );
144 } 157 }
145 158
@@ -169,38 +182,47 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
169 if( fieldMapping == null ) 182 if( fieldMapping == null )
170 { 183 {
171 fieldMapping = new FieldMapping( obfName, deobfName ); 184 fieldMapping = new FieldMapping( obfName, deobfName );
172 m_fieldsByObf.put( obfName, fieldMapping ); 185 boolean obfWasAdded = m_fieldsByObf.put( obfName, fieldMapping ) == null;
173 m_fieldsByDeobf.put( deobfName, fieldMapping ); 186 assert( obfWasAdded );
187 }
188 else
189 {
190 boolean wasRemoved = m_fieldsByDeobf.remove( fieldMapping.getDeobfName() ) != null;
191 assert( wasRemoved );
174 } 192 }
175
176 m_fieldsByDeobf.remove( fieldMapping.getDeobfName() );
177 fieldMapping.setDeobfName( deobfName ); 193 fieldMapping.setDeobfName( deobfName );
178 m_fieldsByDeobf.put( deobfName, fieldMapping ); 194 boolean wasAdded = m_fieldsByDeobf.put( deobfName, fieldMapping ) == null;
195 assert( wasAdded );
179 } 196 }
180 197
181 //// METHODS //////// 198 //// METHODS ////////
182 199
183 public Iterable<MethodMapping> methods( ) 200 public Iterable<MethodMapping> methods( )
184 { 201 {
185 assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); 202 assert( m_methodsByObf.size() >= m_methodsByDeobf.size() );
186 return m_methodsByObf.values(); 203 return m_methodsByObf.values();
187 } 204 }
188 205
189 protected void addMethodMapping( MethodMapping methodMapping ) 206 public void addMethodMapping( MethodMapping methodMapping )
190 { 207 {
191 String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); 208 String obfKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() );
192 String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() );
193 if( m_methodsByObf.containsKey( obfKey ) ) 209 if( m_methodsByObf.containsKey( obfKey ) )
194 { 210 {
195 throw new Error( "Already have mapping for " + m_obfName + "." + obfKey ); 211 throw new Error( "Already have mapping for " + m_obfName + "." + obfKey );
196 } 212 }
197 if( m_methodsByDeobf.containsKey( deobfKey ) ) 213 boolean wasAdded = m_methodsByObf.put( obfKey, methodMapping ) == null;
214 assert( wasAdded );
215 if( methodMapping.getDeobfName() != null )
198 { 216 {
199 throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey ); 217 String deobfKey = getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() );
218 if( m_methodsByDeobf.containsKey( deobfKey ) )
219 {
220 throw new Error( "Already have mapping for " + m_deobfName + "." + deobfKey );
221 }
222 boolean deobfWasAdded = m_methodsByDeobf.put( deobfKey, methodMapping ) == null;
223 assert( deobfWasAdded );
200 } 224 }
201 m_methodsByObf.put( obfKey, methodMapping ); 225 assert( m_methodsByObf.size() >= m_methodsByDeobf.size() );
202 m_methodsByDeobf.put( deobfKey, methodMapping );
203 assert( m_methodsByObf.size() == m_methodsByDeobf.size() );
204 } 226 }
205 227
206 public MethodMapping getMethodByObf( String obfName, String signature ) 228 public MethodMapping getMethodByObf( String obfName, String signature )
@@ -231,13 +253,17 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
231 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) ); 253 MethodMapping methodMapping = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) );
232 if( methodMapping == null ) 254 if( methodMapping == null )
233 { 255 {
234 methodMapping = createMethodIndex( obfName, obfSignature ); 256 methodMapping = createMethodMapping( obfName, obfSignature );
257 }
258 else
259 {
260 boolean wasRemoved = m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) ) != null;
261 assert( wasRemoved );
235 } 262 }
236
237 m_methodsByDeobf.remove( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ) );
238 methodMapping.setDeobfName( deobfName ); 263 methodMapping.setDeobfName( deobfName );
239 methodMapping.setDeobfSignature( deobfSignature ); 264 methodMapping.setDeobfSignature( deobfSignature );
240 m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ); 265 boolean wasAdded = m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodMapping ) == null;
266 assert( wasAdded );
241 } 267 }
242 268
243 public void updateDeobfMethodSignatures( Translator translator ) 269 public void updateDeobfMethodSignatures( Translator translator )
@@ -255,17 +281,16 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
255 MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) ); 281 MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) );
256 if( methodIndex == null ) 282 if( methodIndex == null )
257 { 283 {
258 methodIndex = createMethodIndex( obfMethodName, obfMethodSignature ); 284 methodIndex = createMethodMapping( obfMethodName, obfMethodSignature );
259 } 285 }
260 methodIndex.setArgumentName( argumentIndex, argumentName ); 286 methodIndex.setArgumentName( argumentIndex, argumentName );
261 } 287 }
262 288
263 private MethodMapping createMethodIndex( String obfName, String obfSignature ) 289 private MethodMapping createMethodMapping( String obfName, String obfSignature )
264 { 290 {
265 MethodMapping methodMapping = new MethodMapping( obfName, obfName, obfSignature, obfSignature ); 291 MethodMapping methodMapping = new MethodMapping( obfName, obfSignature );
266 String key = getMethodKey( obfName, obfSignature ); 292 boolean wasAdded = m_methodsByObf.put( getMethodKey( obfName, obfSignature ), methodMapping ) == null;
267 m_methodsByObf.put( key, methodMapping ); 293 assert( wasAdded );
268 m_methodsByDeobf.put( key, methodMapping );
269 return methodMapping; 294 return methodMapping;
270 } 295 }
271 296
@@ -308,9 +333,10 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
308 { 333 {
309 if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) ) 334 if( innerClassMapping.renameObfClass( oldObfClassName, newObfClassName ) )
310 { 335 {
311 m_innerClassesByObf.remove( oldObfClassName ); 336 boolean wasRemoved = m_innerClassesByObf.remove( oldObfClassName ) != null;
312 m_innerClassesByObf.put( newObfClassName, innerClassMapping ); 337 assert( wasRemoved );
313 assert( m_innerClassesByObf.size() == m_innerClassesByDeobf.size() ); 338 boolean wasAdded = m_innerClassesByObf.put( newObfClassName, innerClassMapping ) == null;
339 assert( wasAdded );
314 } 340 }
315 } 341 }
316 342
@@ -320,9 +346,10 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping>
320 String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ); 346 String oldMethodKey = getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() );
321 if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) ) 347 if( methodMapping.renameObfClass( oldObfClassName, newObfClassName ) )
322 { 348 {
323 m_methodsByObf.remove( oldMethodKey ); 349 boolean wasRemoved = m_methodsByObf.remove( oldMethodKey ) != null;
324 m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ); 350 assert( wasRemoved );
325 assert( m_methodsByObf.size() == m_methodsByDeobf.size() ); 351 boolean wasAdded = m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping ) == null;
352 assert( wasAdded );
326 } 353 }
327 } 354 }
328 355
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index f52094fd..99cb85f0 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -47,7 +47,10 @@ public class Mappings implements Serializable
47 for( ClassMapping classMapping : classes ) 47 for( ClassMapping classMapping : classes )
48 { 48 {
49 m_classesByObf.put( classMapping.getObfName(), classMapping ); 49 m_classesByObf.put( classMapping.getObfName(), classMapping );
50 m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); 50 if( classMapping.getDeobfName() != null )
51 {
52 m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
53 }
51 } 54 }
52 } 55 }
53 56
@@ -68,23 +71,27 @@ public class Mappings implements Serializable
68 71
69 public Collection<ClassMapping> classes( ) 72 public Collection<ClassMapping> classes( )
70 { 73 {
71 assert( m_classesByObf.size() == m_classesByDeobf.size() ); 74 assert( m_classesByObf.size() >= m_classesByDeobf.size() );
72 return m_classesByObf.values(); 75 return m_classesByObf.values();
73 } 76 }
74 77
75 protected void addClassMapping( ClassMapping classMapping ) 78 public void addClassMapping( ClassMapping classMapping )
76 { 79 {
77 if( m_classesByObf.containsKey( classMapping.getObfName() ) ) 80 if( m_classesByObf.containsKey( classMapping.getObfName() ) )
78 { 81 {
79 throw new Error( "Already have mapping for " + classMapping.getObfName() ); 82 throw new Error( "Already have mapping for " + classMapping.getObfName() );
80 } 83 }
81 if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) ) 84 boolean obfWasAdded = m_classesByObf.put( classMapping.getObfName(), classMapping ) == null;
85 assert( obfWasAdded );
86 if( classMapping.getDeobfName() != null )
82 { 87 {
83 throw new Error( "Already have mapping for " + classMapping.getDeobfName() ); 88 if( m_classesByDeobf.containsKey( classMapping.getDeobfName() ) )
89 {
90 throw new Error( "Already have mapping for " + classMapping.getDeobfName() );
91 }
92 boolean deobfWasAdded = m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null;
93 assert( deobfWasAdded );
84 } 94 }
85 m_classesByObf.put( classMapping.getObfName(), classMapping );
86 m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
87 assert( m_classesByObf.size() == m_classesByDeobf.size() );
88 } 95 }
89 96
90 public ClassMapping getClassByObf( ClassEntry entry ) 97 public ClassMapping getClassByObf( ClassEntry entry )
@@ -99,7 +106,7 @@ public class Mappings implements Serializable
99 106
100 public ClassMapping getClassByDeobf( ClassEntry entry ) 107 public ClassMapping getClassByDeobf( ClassEntry entry )
101 { 108 {
102 return getClassByObf( entry.getName() ); 109 return getClassByDeobf( entry.getName() );
103 } 110 }
104 111
105 public ClassMapping getClassByDeobf( String deobfName ) 112 public ClassMapping getClassByDeobf( String deobfName )
@@ -109,26 +116,52 @@ public class Mappings implements Serializable
109 116
110 public Translator getTranslator( TranslationIndex index, TranslationDirection direction ) 117 public Translator getTranslator( TranslationIndex index, TranslationDirection direction )
111 { 118 {
112 if( direction == TranslationDirection.Obfuscating ) 119 switch( direction )
113 { 120 {
114 // deobfuscate the index 121 case Deobfuscating:
115 index = new TranslationIndex( index ); 122
116 Map<String,String> renames = Maps.newHashMap(); 123 return new Translator( direction, m_classesByObf, index );
117 for( ClassMapping classMapping : classes() ) 124
118 { 125 case Obfuscating:
119 renames.put( classMapping.getObfName(), classMapping.getDeobfName() ); 126
120 for( ClassMapping innerClassMapping : classMapping.innerClasses() ) 127 // deobfuscate the index
128 index = new TranslationIndex( index );
129 Map<String,String> renames = Maps.newHashMap();
130 for( ClassMapping classMapping : classes() )
121 { 131 {
122 renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() ); 132 if( classMapping.getDeobfName() != null )
133 {
134 renames.put( classMapping.getObfName(), classMapping.getDeobfName() );
135 }
136 for( ClassMapping innerClassMapping : classMapping.innerClasses() )
137 {
138 if( innerClassMapping.getDeobfName() != null )
139 {
140 renames.put( innerClassMapping.getObfName(), innerClassMapping.getDeobfName() );
141 }
142 }
123 } 143 }
124 } 144 index.renameClasses( renames );
125 index.renameClasses( renames ); 145
146 // fill in the missing deobf class entries with obf entries
147 Map<String,ClassMapping> classes = Maps.newHashMap();
148 for( ClassMapping classMapping : classes() )
149 {
150 if( classMapping.getDeobfName() != null )
151 {
152 classes.put( classMapping.getDeobfName(), classMapping );
153 }
154 else
155 {
156 classes.put( classMapping.getObfName(), classMapping );
157 }
158 }
159
160 return new Translator( direction, classes, index );
161
162 default:
163 throw new Error( "Invalid translation direction!" );
126 } 164 }
127 return new Translator(
128 direction,
129 direction.choose( m_classesByObf, m_classesByDeobf ),
130 index
131 );
132 } 165 }
133 166
134 public static Mappings newFromStream( InputStream in ) 167 public static Mappings newFromStream( InputStream in )
@@ -162,9 +195,10 @@ public class Mappings implements Serializable
162 { 195 {
163 if( classMapping.renameObfClass( oldObfName, newObfName ) ) 196 if( classMapping.renameObfClass( oldObfName, newObfName ) )
164 { 197 {
165 m_classesByObf.remove( oldObfName ); 198 boolean wasRemoved = m_classesByObf.remove( oldObfName ) != null;
166 m_classesByObf.put( newObfName, classMapping ); 199 assert( wasRemoved );
167 assert( m_classesByObf.size() == m_classesByDeobf.size() ); 200 boolean wasAdded = m_classesByObf.put( newObfName, classMapping ) == null;
201 assert( wasAdded );
168 } 202 }
169 } 203 }
170 } 204 }
diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java
index 9f42b42c..7888836e 100644
--- a/src/cuchaz/enigma/mapping/MappingsReader.java
+++ b/src/cuchaz/enigma/mapping/MappingsReader.java
@@ -14,13 +14,10 @@ import java.io.BufferedReader;
14import java.io.IOException; 14import java.io.IOException;
15import java.io.Reader; 15import java.io.Reader;
16import java.util.Deque; 16import java.util.Deque;
17import java.util.NoSuchElementException;
18import java.util.Scanner;
19 17
20import com.google.common.collect.Queues; 18import com.google.common.collect.Queues;
21 19
22import cuchaz.enigma.Constants; 20import cuchaz.enigma.Constants;
23import cuchaz.enigma.Util;
24import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater; 21import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
25 22
26public class MappingsReader 23public class MappingsReader
@@ -73,89 +70,99 @@ public class MappingsReader
73 mappingStack.pop(); 70 mappingStack.pop();
74 } 71 }
75 72
76 Scanner scanner = new Scanner( line ); 73 String[] parts = line.trim().split( "\\s" );
77 try 74 try
78 { 75 {
79 while( scanner.hasNext() ) 76 // read the first token
77 String token = parts[0];
78
79 if( token.equalsIgnoreCase( "CLASS" ) )
80 { 80 {
81 // read the first token 81 ClassMapping classMapping = readClass( parts );
82 String token = scanner.next(); 82 if( indent == 0 )
83
84 if( token.equalsIgnoreCase( "CLASS" ) )
85 { 83 {
86 ClassMapping classMapping = readClass( scanner ); 84 // outer class
87 if( indent == 0 ) 85 mappings.addClassMapping( classMapping );
88 { 86 }
89 // outer class 87 else if( indent == 1 )
90 mappings.addClassMapping( classMapping ); 88 {
91 } 89 // inner class
92 else if( indent == 1 ) 90 if( !( mappingStack.getFirst() instanceof ClassMapping ) )
93 {
94 // inner class
95 if( !( mappingStack.getFirst() instanceof ClassMapping ) )
96 {
97 throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" );
98 }
99 ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping );
100 }
101 else
102 { 91 {
103 throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" ); 92 throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" );
104 } 93 }
105 mappingStack.push( classMapping ); 94 ((ClassMapping)mappingStack.getFirst()).addInnerClassMapping( classMapping );
106 } 95 }
107 else if( token.equalsIgnoreCase( "FIELD" ) ) 96 else
108 { 97 {
109 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) 98 throw new MappingParseException( lineNumber, "Unexpected CLASS entry here!" );
110 {
111 throw new MappingParseException( lineNumber, "Unexpected FIELD entry here!" );
112 }
113 ((ClassMapping)mappingStack.getFirst()).addFieldMapping( readField( scanner ) );
114 } 99 }
115 else if( token.equalsIgnoreCase( "METHOD" ) ) 100 mappingStack.push( classMapping );
101 }
102 else if( token.equalsIgnoreCase( "FIELD" ) )
103 {
104 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) )
116 { 105 {
117 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) ) 106 throw new MappingParseException( lineNumber, "Unexpected FIELD entry here!" );
118 {
119 throw new MappingParseException( lineNumber, "Unexpected METHOD entry here!" );
120 }
121 MethodMapping methodMapping = readMethod( scanner );
122 ((ClassMapping)mappingStack.getFirst()).addMethodMapping( methodMapping );
123 mappingStack.push( methodMapping );
124 } 107 }
125 else if( token.equalsIgnoreCase( "ARG" ) ) 108 ((ClassMapping)mappingStack.getFirst()).addFieldMapping( readField( parts ) );
109 }
110 else if( token.equalsIgnoreCase( "METHOD" ) )
111 {
112 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof ClassMapping) )
126 { 113 {
127 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof MethodMapping) ) 114 throw new MappingParseException( lineNumber, "Unexpected METHOD entry here!" );
128 { 115 }
129 throw new MappingParseException( lineNumber, "Unexpected ARG entry here!" ); 116 MethodMapping methodMapping = readMethod( parts );
130 } 117 ((ClassMapping)mappingStack.getFirst()).addMethodMapping( methodMapping );
131 ((MethodMapping)mappingStack.getFirst()).addArgumentMapping( readArgument( scanner ) ); 118 mappingStack.push( methodMapping );
119 }
120 else if( token.equalsIgnoreCase( "ARG" ) )
121 {
122 if( mappingStack.isEmpty() || !(mappingStack.getFirst() instanceof MethodMapping) )
123 {
124 throw new MappingParseException( lineNumber, "Unexpected ARG entry here!" );
132 } 125 }
126 ((MethodMapping)mappingStack.getFirst()).addArgumentMapping( readArgument( parts ) );
133 } 127 }
134 } 128 }
135 catch( NoSuchElementException ex ) 129 catch( ArrayIndexOutOfBoundsException | NumberFormatException ex )
136 { 130 {
137 throw new MappingParseException( lineNumber, "Malformed line!" ); 131 throw new MappingParseException( lineNumber, "Malformed line!" );
138 } 132 }
139 finally
140 {
141 Util.closeQuietly( scanner );
142 }
143 } 133 }
144 134
145 return mappings; 135 return mappings;
146 } 136 }
147 137
148 private ArgumentMapping readArgument( Scanner scanner ) 138 private ArgumentMapping readArgument( String[] parts )
149 { 139 {
150 return new ArgumentMapping( scanner.nextInt(), scanner.next() ); 140 return new ArgumentMapping( Integer.parseInt( parts[1] ), parts[2] );
151 } 141 }
152 142
153 private ClassMapping readClass( Scanner scanner ) 143 private ClassMapping readClass( String[] parts )
154 { 144 {
155 return new ClassMapping( 145 if( parts.length == 2 )
156 moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), 146 {
157 moveClassOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) 147 String obfName = parts[1];
158 ); 148 return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) );
149 }
150 else
151 {
152 String obfName = parts[1];
153 String deobfName = parts[2];
154 if( obfName.equals( deobfName ) )
155 {
156 return new ClassMapping( moveClassOutOfDefaultPackage( obfName, Constants.NonePackage ) );
157 }
158 else
159 {
160 return new ClassMapping(
161 moveClassOutOfDefaultPackage( parts[1], Constants.NonePackage ),
162 moveClassOutOfDefaultPackage( parts[2], Constants.NonePackage )
163 );
164 }
165 }
159 } 166 }
160 167
161 private String moveClassOutOfDefaultPackage( String className, String newPackageName ) 168 private String moveClassOutOfDefaultPackage( String className, String newPackageName )
@@ -168,18 +175,34 @@ public class MappingsReader
168 return className; 175 return className;
169 } 176 }
170 177
171 private FieldMapping readField( Scanner scanner ) 178 private FieldMapping readField( String[] parts )
172 { 179 {
173 return new FieldMapping( scanner.next(), scanner.next() ); 180 return new FieldMapping( parts[1], parts[2] );
174 } 181 }
175 182
176 private MethodMapping readMethod( Scanner scanner ) 183 private MethodMapping readMethod( String[] parts )
177 { 184 {
178 return new MethodMapping( 185 if( parts.length == 3 )
179 scanner.next(), scanner.next(), 186 {
180 moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ), 187 String obfName = parts[1];
181 moveSignatureOutOfDefaultPackage( scanner.next(), Constants.NonePackage ) 188 String obfSignature = moveSignatureOutOfDefaultPackage( parts[2], Constants.NonePackage );
182 ); 189 return new MethodMapping( obfName, obfSignature );
190 }
191 else
192 {
193 String obfName = parts[1];
194 String deobfName = parts[2];
195 String obfSignature = moveSignatureOutOfDefaultPackage( parts[3], Constants.NonePackage );
196 String deobfSignature = moveSignatureOutOfDefaultPackage( parts[4], Constants.NonePackage );
197 if( obfName.equals( deobfName ) )
198 {
199 return new MethodMapping( obfName, obfSignature );
200 }
201 else
202 {
203 return new MethodMapping( obfName, obfSignature, deobfName, deobfSignature );
204 }
205 }
183 } 206 }
184 207
185 private String moveSignatureOutOfDefaultPackage( String signature, final String newPackageName ) 208 private String moveSignatureOutOfDefaultPackage( String signature, final String newPackageName )
diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java
index 9d036d8f..f84b2489 100644
--- a/src/cuchaz/enigma/mapping/MappingsRenamer.java
+++ b/src/cuchaz/enigma/mapping/MappingsRenamer.java
@@ -46,9 +46,11 @@ public class MappingsRenamer
46 } 46 }
47 else 47 else
48 { 48 {
49 m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ); 49 boolean wasRemoved = m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() ) != null;
50 assert( wasRemoved );
50 classMapping.setDeobfName( deobfName ); 51 classMapping.setDeobfName( deobfName );
51 m_mappings.m_classesByDeobf.put( deobfName, classMapping ); 52 boolean wasAdded = m_mappings.m_classesByDeobf.put( deobfName, classMapping ) == null;
53 assert( wasAdded );
52 } 54 }
53 55
54 updateDeobfMethodSignatures(); 56 updateDeobfMethodSignatures();
@@ -132,9 +134,11 @@ public class MappingsRenamer
132 ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName ); 134 ClassMapping classMapping = m_mappings.m_classesByObf.get( obfClassName );
133 if( classMapping == null ) 135 if( classMapping == null )
134 { 136 {
135 classMapping = new ClassMapping( obfClassName, obfClassName ); 137 classMapping = new ClassMapping( obfClassName );
136 m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ); 138 boolean obfWasAdded = m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping ) == null;
137 m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ); 139 assert( obfWasAdded );
140 boolean deobfWasAdded = m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping ) == null;
141 assert( deobfWasAdded );
138 } 142 }
139 return classMapping; 143 return classMapping;
140 } 144 }
diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java
index 62035713..ea6e6558 100644
--- a/src/cuchaz/enigma/mapping/MappingsWriter.java
+++ b/src/cuchaz/enigma/mapping/MappingsWriter.java
@@ -37,7 +37,14 @@ public class MappingsWriter
37 private void write( PrintWriter out, ClassMapping classMapping, int depth ) 37 private void write( PrintWriter out, ClassMapping classMapping, int depth )
38 throws IOException 38 throws IOException
39 { 39 {
40 out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() ); 40 if( classMapping.getDeobfName() == null )
41 {
42 out.format( "%sCLASS %s\n", getIndent( depth ), classMapping.getObfName() );
43 }
44 else
45 {
46 out.format( "%sCLASS %s %s\n", getIndent( depth ), classMapping.getObfName(), classMapping.getDeobfName() );
47 }
41 48
42 for( ClassMapping innerClassMapping : sorted( classMapping.innerClasses() ) ) 49 for( ClassMapping innerClassMapping : sorted( classMapping.innerClasses() ) )
43 { 50 {
@@ -64,11 +71,21 @@ public class MappingsWriter
64 private void write( PrintWriter out, MethodMapping methodMapping, int depth ) 71 private void write( PrintWriter out, MethodMapping methodMapping, int depth )
65 throws IOException 72 throws IOException
66 { 73 {
67 out.format( "%sMETHOD %s %s %s %s\n", 74 if( methodMapping.getDeobfName() == null )
68 getIndent( depth ), 75 {
69 methodMapping.getObfName(), methodMapping.getDeobfName(), 76 out.format( "%sMETHOD %s %s\n",
70 methodMapping.getObfSignature(), methodMapping.getDeobfSignature() 77 getIndent( depth ),
71 ); 78 methodMapping.getObfName(), methodMapping.getObfSignature()
79 );
80 }
81 else
82 {
83 out.format( "%sMETHOD %s %s %s %s\n",
84 getIndent( depth ),
85 methodMapping.getObfName(), methodMapping.getDeobfName(),
86 methodMapping.getObfSignature(), methodMapping.getDeobfSignature()
87 );
88 }
72 89
73 for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) ) 90 for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) )
74 { 91 {
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index bf83bd21..e59cb2eb 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -26,8 +26,12 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping>
26 private String m_deobfSignature; 26 private String m_deobfSignature;
27 private Map<Integer,ArgumentMapping> m_arguments; 27 private Map<Integer,ArgumentMapping> m_arguments;
28 28
29 // NOTE: this argument order is important for the MethodReader/MethodWriter 29 public MethodMapping( String obfName, String obfSignature )
30 public MethodMapping( String obfName, String deobfName, String obfSignature, String deobfSignature ) 30 {
31 this( obfName, obfSignature, null, null );
32 }
33
34 public MethodMapping( String obfName, String obfSignature, String deobfName, String deobfSignature )
31 { 35 {
32 m_obfName = obfName; 36 m_obfName = obfName;
33 m_deobfName = NameValidator.validateMethodName( deobfName ); 37 m_deobfName = NameValidator.validateMethodName( deobfName );
@@ -69,9 +73,10 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping>
69 return m_arguments.values(); 73 return m_arguments.values();
70 } 74 }
71 75
72 protected void addArgumentMapping( ArgumentMapping argumentMapping ) 76 public void addArgumentMapping( ArgumentMapping argumentMapping )
73 { 77 {
74 m_arguments.put( argumentMapping.getIndex(), argumentMapping ); 78 boolean wasAdded = m_arguments.put( argumentMapping.getIndex(), argumentMapping ) == null;
79 assert( wasAdded );
75 } 80 }
76 81
77 public String getObfArgumentName( int index ) 82 public String getObfArgumentName( int index )
@@ -102,7 +107,8 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping>
102 if( argumentMapping == null ) 107 if( argumentMapping == null )
103 { 108 {
104 argumentMapping = new ArgumentMapping( index, name ); 109 argumentMapping = new ArgumentMapping( index, name );
105 m_arguments.put( index, argumentMapping ); 110 boolean wasAdded = m_arguments.put( index, argumentMapping ) == null;
111 assert( wasAdded );
106 } 112 }
107 else 113 else
108 { 114 {
diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java
index 6df893fb..9adf1ac1 100644
--- a/src/cuchaz/enigma/mapping/NameValidator.java
+++ b/src/cuchaz/enigma/mapping/NameValidator.java
@@ -57,7 +57,11 @@ public class NameValidator
57 57
58 public static String validateClassName( String name ) 58 public static String validateClassName( String name )
59 { 59 {
60 if( name == null || !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) 60 if( name == null )
61 {
62 return null;
63 }
64 if( !ClassPattern.matcher( name ).matches() || ReservedWords.contains( name ) )
61 { 65 {
62 throw new IllegalNameException( name, "This doesn't look like a legal class name" ); 66 throw new IllegalNameException( name, "This doesn't look like a legal class name" );
63 } 67 }
@@ -70,7 +74,11 @@ public class NameValidator
70 74
71 public static String validateFieldName( String name ) 75 public static String validateFieldName( String name )
72 { 76 {
73 if( name == null || !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) ) 77 if( name == null )
78 {
79 return null;
80 }
81 if( !IdentifierPattern.matcher( name ).matches() || ReservedWords.contains( name ) )
74 { 82 {
75 throw new IllegalNameException( name, "This doesn't look like a legal identifier" ); 83 throw new IllegalNameException( name, "This doesn't look like a legal identifier" );
76 } 84 }