summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassMatcher.java
diff options
context:
space:
mode:
authorGravatar jeff2014-08-31 16:14:45 -0400
committerGravatar jeff2014-08-31 16:14:45 -0400
commit4e9c52d5fc5d23e8a77857e712654596203acb31 (patch)
treec4a48493e6d60dfec9df326dac2b1ef229aedffd /src/cuchaz/enigma/convert/ClassMatcher.java
parentfixed lots of bugs in the mappings converter. It's finally ready. =) (diff)
downloadenigma-fork-4e9c52d5fc5d23e8a77857e712654596203acb31.tar.gz
enigma-fork-4e9c52d5fc5d23e8a77857e712654596203acb31.tar.xz
enigma-fork-4e9c52d5fc5d23e8a77857e712654596203acb31.zip
fixed mapping conversion bug with class rename order
Diffstat (limited to 'src/cuchaz/enigma/convert/ClassMatcher.java')
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java83
1 files changed, 61 insertions, 22 deletions
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index b551da2..0821bd3 100644
--- a/src/cuchaz/enigma/convert/ClassMatcher.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -19,6 +19,8 @@ import java.util.Arrays;
19import java.util.Collection; 19import java.util.Collection;
20import java.util.Collections; 20import java.util.Collections;
21import java.util.Comparator; 21import java.util.Comparator;
22import java.util.Iterator;
23import java.util.LinkedHashMap;
22import java.util.List; 24import java.util.List;
23import java.util.Map; 25import java.util.Map;
24import java.util.Set; 26import java.util.Set;
@@ -89,9 +91,7 @@ public class ClassMatcher
89 91
90 // compute the matching 92 // compute the matching
91 ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); 93 ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader );
92 94 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> matchingIndex = matching.getIndex();
93 // start the class conversion map with the unique and ambiguous matchings
94 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap();
95 95
96 // get all the obf class names used in the mappings 96 // get all the obf class names used in the mappings
97 Set<String> usedClassNames = mappings.getAllObfClassNames(); 97 Set<String> usedClassNames = mappings.getAllObfClassNames();
@@ -101,9 +101,10 @@ public class ClassMatcher
101 allClassNames.add( classEntry.getName() ); 101 allClassNames.add( classEntry.getName() );
102 } 102 }
103 usedClassNames.retainAll( allClassNames ); 103 usedClassNames.retainAll( allClassNames );
104 System.out.println( "Used " + usedClassNames.size() + " classes in the mappings" );
104 105
105 // probabilistically match the non-uniquely-matched source classes 106 // probabilistically match the non-uniquely-matched source classes
106 for( Map.Entry<ClassIdentity,List<ClassIdentity>> entry : conversionMap.values() ) 107 for( Map.Entry<ClassIdentity,List<ClassIdentity>> entry : matchingIndex.values() )
107 { 108 {
108 ClassIdentity sourceClass = entry.getKey(); 109 ClassIdentity sourceClass = entry.getKey();
109 List<ClassIdentity> destClasses = entry.getValue(); 110 List<ClassIdentity> destClasses = entry.getValue();
@@ -148,20 +149,20 @@ public class ClassMatcher
148 } 149 }
149 } 150 }
150 151
151 // use the matching to convert the mappings 152 // group the matching into unique and non-unique matches
152 BiMap<String,String> classConversion = HashBiMap.create(); 153 BiMap<String,String> matchedClassNames = HashBiMap.create();
153 Set<String> unmatchedSourceClasses = Sets.newHashSet(); 154 Set<String> unmatchedSourceClassNames = Sets.newHashSet();
154 for( String className : usedClassNames ) 155 for( String className : usedClassNames )
155 { 156 {
156 // is there a match for this class? 157 // is there a match for this class?
157 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( className ); 158 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = matchingIndex.get( className );
158 ClassIdentity sourceClass = entry.getKey(); 159 ClassIdentity sourceClass = entry.getKey();
159 List<ClassIdentity> matches = entry.getValue(); 160 List<ClassIdentity> matches = entry.getValue();
160 161
161 if( matches.size() == 1 ) 162 if( matches.size() == 1 )
162 { 163 {
163 // unique match! We're good to go! 164 // unique match! We're good to go!
164 classConversion.put( 165 matchedClassNames.put(
165 sourceClass.getClassEntry().getName(), 166 sourceClass.getClassEntry().getName(),
166 matches.get( 0 ).getClassEntry().getName() 167 matches.get( 0 ).getClassEntry().getName()
167 ); 168 );
@@ -172,35 +173,36 @@ public class ClassMatcher
172 String fallbackMatch = fallbackMatching.get( className ); 173 String fallbackMatch = fallbackMatching.get( className );
173 if( fallbackMatch != null ) 174 if( fallbackMatch != null )
174 { 175 {
175 classConversion.put( 176 matchedClassNames.put(
176 sourceClass.getClassEntry().getName(), 177 sourceClass.getClassEntry().getName(),
177 fallbackMatch 178 fallbackMatch
178 ); 179 );
179 } 180 }
180 else 181 else
181 { 182 {
182 unmatchedSourceClasses.add( className ); 183 unmatchedSourceClassNames.add( className );
183 } 184 }
184 } 185 }
185 } 186 }
186 187
187 // remove (and warn about) unmatched classes 188 // report unmatched classes
188 if( !unmatchedSourceClasses.isEmpty() ) 189 if( !unmatchedSourceClassNames.isEmpty() )
189 { 190 {
190 System.err.println( "WARNING: there were unmatched classes!" ); 191 System.err.println( "ERROR: there were unmatched classes!" );
191 for( String className : unmatchedSourceClasses ) 192 for( String className : unmatchedSourceClassNames )
192 { 193 {
193 System.err.println( "\t" + className ); 194 System.err.println( "\t" + className );
194 mappings.removeClassByObfName( className );
195 } 195 }
196 System.err.println( "Mappings for these classes have been removed." ); 196 return;
197 } 197 }
198 198
199 // show the class name changes 199 // get the class name changes from the matched class names
200 for( Map.Entry<String,String> entry : classConversion.entrySet() ) 200 Map<String,String> classChanges = Maps.newHashMap();
201 for( Map.Entry<String,String> entry : matchedClassNames.entrySet() )
201 { 202 {
202 if( !entry.getKey().equals( entry.getValue() ) ) 203 if( !entry.getKey().equals( entry.getValue() ) )
203 { 204 {
205 classChanges.put( entry.getKey(), entry.getValue() );
204 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); 206 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) );
205 /* DEBUG 207 /* DEBUG
206 System.out.println( String.format( "\n%s\n%s", 208 System.out.println( String.format( "\n%s\n%s",
@@ -211,8 +213,45 @@ public class ClassMatcher
211 } 213 }
212 } 214 }
213 215
214 // convert the mappings 216 // sort the changes so classes are renamed in the correct order
215 mappings.renameObfClasses( classConversion ); 217 // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b
218 LinkedHashMap<String,String> orderedClassChanges = Maps.newLinkedHashMap();
219 int numChangesLeft = classChanges.size();
220 while( !classChanges.isEmpty() )
221 {
222 Iterator<Map.Entry<String,String>> iter = classChanges.entrySet().iterator();
223 while( iter.hasNext() )
224 {
225 Map.Entry<String,String> entry = iter.next();
226 if( classChanges.get( entry.getValue() ) == null )
227 {
228 orderedClassChanges.put( entry.getKey(), entry.getValue() );
229 iter.remove();
230 }
231 }
232
233 // did we remove any changes?
234 if( numChangesLeft - classChanges.size() > 0 )
235 {
236 // keep going
237 numChangesLeft = classChanges.size();
238 }
239 else
240 {
241 // can't sort anymore. There must be a loop
242 break;
243 }
244 }
245 if( classChanges.size() > 0 )
246 {
247 throw new Error( String.format( "Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size() ) );
248 }
249
250 // convert the mappings in the correct class order
251 for( Map.Entry<String,String> entry : orderedClassChanges.entrySet() )
252 {
253 mappings.renameObfClass( entry.getKey(), entry.getValue() );
254 }
216 255
217 // check the method matches 256 // check the method matches
218 System.out.println( "Checking methods..." ); 257 System.out.println( "Checking methods..." );
@@ -250,7 +289,7 @@ public class ClassMatcher
250 } 289 }
251 290
252 System.err.println( "\tAvailable source methods:" ); 291 System.err.println( "\tAvailable source methods:" );
253 c = sourceLoader.loadClass( classConversion.inverse().get( classMapping.getObfName() ) ); 292 c = sourceLoader.loadClass( matchedClassNames.inverse().get( classMapping.getObfName() ) );
254 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 293 for( CtBehavior behavior : c.getDeclaredBehaviors() )
255 { 294 {
256 MethodEntry declaredMethodEntry = new MethodEntry( 295 MethodEntry declaredMethodEntry = new MethodEntry(