summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2014-08-31 14:41:24 -0400
committerGravatar jeff2014-08-31 14:41:24 -0400
commitd3fc0b55515e81ae1b10fa16129f05b0241271f0 (patch)
treee0359362ca9af0cb1573c665392c7de10c9bead2 /src
parentdebugging class matcher... almost got it! (diff)
downloadenigma-d3fc0b55515e81ae1b10fa16129f05b0241271f0.tar.gz
enigma-d3fc0b55515e81ae1b10fa16129f05b0241271f0.tar.xz
enigma-d3fc0b55515e81ae1b10fa16129f05b0241271f0.zip
fixed lots of bugs in the mappings converter. It's finally ready. =)
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java23
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java260
-rw-r--r--src/cuchaz/enigma/convert/ClassMatching.java26
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java29
4 files changed, 194 insertions, 144 deletions
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index 8de71288..bd2824b3 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -60,7 +60,6 @@ import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
60public class ClassIdentity 60public class ClassIdentity
61{ 61{
62 private ClassEntry m_classEntry; 62 private ClassEntry m_classEntry;
63 private String m_rawName;
64 private SidedClassNamer m_namer; 63 private SidedClassNamer m_namer;
65 private Multiset<String> m_fields; 64 private Multiset<String> m_fields;
66 private Multiset<String> m_methods; 65 private Multiset<String> m_methods;
@@ -71,18 +70,13 @@ public class ClassIdentity
71 private Multiset<String> m_implementations; 70 private Multiset<String> m_implementations;
72 private Multiset<String> m_references; 71 private Multiset<String> m_references;
73 72
74 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames ) 73 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences )
75 { 74 {
76 m_namer = namer; 75 m_namer = namer;
77 76
78 // stuff from the bytecode 77 // stuff from the bytecode
79 78
80 m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) ); 79 m_classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) );
81 m_rawName = "";
82 if( useRawNames )
83 {
84 m_rawName = m_classEntry.getName();
85 }
86 m_fields = HashMultiset.create(); 80 m_fields = HashMultiset.create();
87 for( CtField field : c.getDeclaredFields() ) 81 for( CtField field : c.getDeclaredFields() )
88 { 82 {
@@ -186,12 +180,6 @@ public class ClassIdentity
186 buf.append( " " ); 180 buf.append( " " );
187 buf.append( hashCode() ); 181 buf.append( hashCode() );
188 buf.append( "\n" ); 182 buf.append( "\n" );
189 if( m_rawName.length() > 0 )
190 {
191 buf.append( "\traw name: " );
192 buf.append( m_rawName );
193 buf.append( "\n" );
194 }
195 for( String field : m_fields ) 183 for( String field : m_fields )
196 { 184 {
197 buf.append( "\tfield " ); 185 buf.append( "\tfield " );
@@ -439,8 +427,7 @@ public class ClassIdentity
439 427
440 public boolean equals( ClassIdentity other ) 428 public boolean equals( ClassIdentity other )
441 { 429 {
442 return m_rawName.equals( other.m_rawName ) 430 return m_fields.equals( other.m_fields )
443 && m_fields.equals( other.m_fields )
444 && m_methods.equals( other.m_methods ) 431 && m_methods.equals( other.m_methods )
445 && m_constructors.equals( other.m_constructors ) 432 && m_constructors.equals( other.m_constructors )
446 && m_staticInitializer.equals( other.m_staticInitializer ) 433 && m_staticInitializer.equals( other.m_staticInitializer )
@@ -454,7 +441,6 @@ public class ClassIdentity
454 public int hashCode( ) 441 public int hashCode( )
455 { 442 {
456 List<Object> objs = Lists.newArrayList(); 443 List<Object> objs = Lists.newArrayList();
457 objs.add( m_rawName );
458 objs.addAll( m_fields ); 444 objs.addAll( m_fields );
459 objs.addAll( m_methods ); 445 objs.addAll( m_methods );
460 objs.addAll( m_constructors ); 446 objs.addAll( m_constructors );
@@ -473,6 +459,11 @@ public class ClassIdentity
473 + getNumMatches( m_constructors, other.m_constructors ); 459 + getNumMatches( m_constructors, other.m_constructors );
474 } 460 }
475 461
462 public int getMaxMatchScore( )
463 {
464 return m_fields.size() + m_methods.size() + m_constructors.size();
465 }
466
476 public boolean matches( CtClass c ) 467 public boolean matches( CtClass c )
477 { 468 {
478 // just compare declaration counts 469 // just compare declaration counts
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index ac07a5bd..b551da25 100644
--- a/src/cuchaz/enigma/convert/ClassMatcher.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -14,17 +14,14 @@ import java.io.File;
14import java.io.FileReader; 14import java.io.FileReader;
15import java.io.FileWriter; 15import java.io.FileWriter;
16import java.io.IOException; 16import java.io.IOException;
17import java.util.AbstractMap;
18import java.util.ArrayList; 17import java.util.ArrayList;
19import java.util.Arrays; 18import java.util.Arrays;
20import java.util.Collection; 19import java.util.Collection;
21import java.util.Collections; 20import java.util.Collections;
22import java.util.Comparator; 21import java.util.Comparator;
23import java.util.Iterator;
24import java.util.List; 22import java.util.List;
25import java.util.Map; 23import java.util.Map;
26import java.util.Set; 24import java.util.Set;
27import java.util.TreeMap;
28import java.util.jar.JarFile; 25import java.util.jar.JarFile;
29 26
30import javassist.CtBehavior; 27import javassist.CtBehavior;
@@ -32,9 +29,11 @@ import javassist.CtClass;
32 29
33import com.beust.jcommander.internal.Lists; 30import com.beust.jcommander.internal.Lists;
34import com.beust.jcommander.internal.Sets; 31import com.beust.jcommander.internal.Sets;
32import com.google.common.collect.ArrayListMultimap;
35import com.google.common.collect.BiMap; 33import com.google.common.collect.BiMap;
36import com.google.common.collect.HashBiMap; 34import com.google.common.collect.HashBiMap;
37import com.google.common.collect.Maps; 35import com.google.common.collect.Maps;
36import com.google.common.collect.Multimap;
38 37
39import cuchaz.enigma.TranslatingTypeLoader; 38import cuchaz.enigma.TranslatingTypeLoader;
40import cuchaz.enigma.analysis.JarIndex; 39import cuchaz.enigma.analysis.JarIndex;
@@ -55,22 +54,28 @@ public class ClassMatcher
55 { 54 {
56 // TEMP 55 // TEMP
57 JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); 56 JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) );
58 JarFile destJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); 57 JarFile destJar = new JarFile( new File( "input/1.8-pre3.jar" ) );
59 File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); 58 File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" );
60 File outMappingsFile = new File( "../minecraft-mappings/1.8-pre2.mappings" ); 59 File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" );
60
61 // define a matching to use when the automated system cannot find a match
62 Map<String,String> fallbackMatching = Maps.newHashMap();
63 fallbackMatching.put( "none/ayb", "none/ayb" );
64 fallbackMatching.put( "none/ayd", "none/ayd" );
65 fallbackMatching.put( "none/bgk", "none/bgk" );
61 66
62 // do the conversion 67 // do the conversion
63 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); 68 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) );
64 convertMappings( sourceJar, destJar, mappings ); 69 convertMappings( sourceJar, destJar, mappings, fallbackMatching );
65 70
66 // write out the convert mappings 71 // write out the converted mappings
67 FileWriter writer = new FileWriter( outMappingsFile ); 72 FileWriter writer = new FileWriter( outMappingsFile );
68 new MappingsWriter().write( writer, mappings ); 73 new MappingsWriter().write( writer, mappings );
69 writer.close(); 74 writer.close();
70 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); 75 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() );
71 } 76 }
72 77
73 private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings ) 78 private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings, Map<String,String> fallbackMatching )
74 { 79 {
75 // index jars 80 // index jars
76 System.out.println( "Indexing source jar..." ); 81 System.out.println( "Indexing source jar..." );
@@ -83,58 +88,77 @@ public class ClassMatcher
83 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); 88 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex );
84 89
85 // compute the matching 90 // compute the matching
86 ClassMatching matching = ClassMatcher.computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); 91 ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader );
87 92
88 // start the class conversion map with the unique and ambiguous matchings 93 // start the class conversion map with the unique and ambiguous matchings
89 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap(); 94 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap();
90 95
91 // probabilistically match the unmatched source classes 96 // get all the obf class names used in the mappings
92 for( ClassIdentity sourceClass : new ArrayList<ClassIdentity>( matching.getUnmatchedSourceClasses() ) ) 97 Set<String> usedClassNames = mappings.getAllObfClassNames();
98 Set<String> allClassNames = Sets.newHashSet();
99 for( ClassEntry classEntry : sourceIndex.getObfClassEntries() )
100 {
101 allClassNames.add( classEntry.getName() );
102 }
103 usedClassNames.retainAll( allClassNames );
104
105 // probabilistically match the non-uniquely-matched source classes
106 for( Map.Entry<ClassIdentity,List<ClassIdentity>> entry : conversionMap.values() )
93 { 107 {
108 ClassIdentity sourceClass = entry.getKey();
109 List<ClassIdentity> destClasses = entry.getValue();
110
111 // skip classes that are uniquely matched
112 if( destClasses.size() == 1 )
113 {
114 continue;
115 }
116
117 // skip classes that aren't used in the mappings
118 if( !usedClassNames.contains( sourceClass.getClassEntry().getName() ) )
119 {
120 continue;
121 }
122
94 System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); 123 System.out.println( "No exact match for source class " + sourceClass.getClassEntry() );
95 124
96 // find the closest classes 125 // find the closest classes
97 TreeMap<Integer,ClassIdentity> scoredMatches = Maps.newTreeMap( Collections.reverseOrder() ); 126 Multimap<Integer,ClassIdentity> scoredMatches = ArrayListMultimap.create();
98 for( ClassIdentity c : matching.getUnmatchedDestClasses() ) 127 for( ClassIdentity c : destClasses )
99 { 128 {
100 scoredMatches.put( sourceClass.getMatchScore( c ), c ); 129 scoredMatches.put( sourceClass.getMatchScore( c ), c );
101 } 130 }
102 Iterator<Map.Entry<Integer,ClassIdentity>> iter = scoredMatches.entrySet().iterator(); 131 List<Integer> scores = new ArrayList<Integer>( scoredMatches.keySet() );
103 for( int i=0; i<10 && iter.hasNext(); i++ ) 132 Collections.sort( scores, Collections.reverseOrder() );
104 { 133 printScoredMatches( sourceClass.getMaxMatchScore(), scores, scoredMatches );
105 Map.Entry<Integer,ClassIdentity> score = iter.next();
106 System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) );
107 }
108 134
109 // does the best match have a non-zero score and the same name? 135 // does the best match have a non-zero score and the same name?
110 Map.Entry<Integer,ClassIdentity> bestMatch = scoredMatches.firstEntry(); 136 int bestScore = scores.get( 0 );
111 if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) ) 137 Collection<ClassIdentity> bestMatches = scoredMatches.get( bestScore );
138 if( bestScore > 0 && bestMatches.size() == 1 )
112 { 139 {
113 // use it 140 ClassIdentity bestMatch = bestMatches.iterator().next();
114 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() ); 141 if( bestMatch.getClassEntry().equals( sourceClass.getClassEntry() ) )
115 conversionMap.put( 142 {
116 sourceClass.getClassEntry().getName(), 143 // use it
117 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, Arrays.asList( bestMatch.getValue() ) ) 144 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName() );
118 ); 145 destClasses.clear();
146 destClasses.add( bestMatch );
147 }
119 } 148 }
120 } 149 }
121 150
122 // use the matching to convert the mappings 151 // use the matching to convert the mappings
123 BiMap<String,String> classConversion = HashBiMap.create(); 152 BiMap<String,String> classConversion = HashBiMap.create();
124 Set<String> unmatchedSourceClasses = Sets.newHashSet(); 153 Set<String> unmatchedSourceClasses = Sets.newHashSet();
125 for( String className : mappings.getAllObfClassNames() ) 154 for( String className : usedClassNames )
126 { 155 {
127 // is there a match for this class? 156 // is there a match for this class?
128 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( className ); 157 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( className );
129 ClassIdentity sourceClass = entry.getKey(); 158 ClassIdentity sourceClass = entry.getKey();
130 List<ClassIdentity> matches = entry.getValue(); 159 List<ClassIdentity> matches = entry.getValue();
131 160
132 if( matches.isEmpty() ) 161 if( matches.size() == 1 )
133 {
134 // no match! =(
135 unmatchedSourceClasses.add( className );
136 }
137 else if( matches.size() == 1 )
138 { 162 {
139 // unique match! We're good to go! 163 // unique match! We're good to go!
140 classConversion.put( 164 classConversion.put(
@@ -142,10 +166,21 @@ public class ClassMatcher
142 matches.get( 0 ).getClassEntry().getName() 166 matches.get( 0 ).getClassEntry().getName()
143 ); 167 );
144 } 168 }
145 else if( matches.size() > 1 ) 169 else
146 { 170 {
147 // too many matches! =( 171 // no match, check the fallback matching
148 unmatchedSourceClasses.add( className ); 172 String fallbackMatch = fallbackMatching.get( className );
173 if( fallbackMatch != null )
174 {
175 classConversion.put(
176 sourceClass.getClassEntry().getName(),
177 fallbackMatch
178 );
179 }
180 else
181 {
182 unmatchedSourceClasses.add( className );
183 }
149 } 184 }
150 } 185 }
151 186
@@ -176,17 +211,11 @@ public class ClassMatcher
176 } 211 }
177 } 212 }
178 213
179 // TEMP: show some classes 214 // convert the mappings
180 for( String className : Arrays.asList( "none/em", "none/ej", "none/en" ) )
181 {
182 System.out.println( String.format( "check: %s -> %s", className, classConversion.get( className ) ) );
183 }
184
185 // convert the classes
186 mappings.renameObfClasses( classConversion ); 215 mappings.renameObfClasses( classConversion );
187 216
188 // look for method matches 217 // check the method matches
189 System.out.println( "Matching methods..." ); 218 System.out.println( "Checking methods..." );
190 for( ClassMapping classMapping : mappings.classes() ) 219 for( ClassMapping classMapping : mappings.classes() )
191 { 220 {
192 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); 221 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() );
@@ -234,91 +263,93 @@ public class ClassMatcher
234 } 263 }
235 } 264 }
236 } 265 }
266
267 System.out.println( "Done!" );
237 } 268 }
238 269
239 public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) 270 public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader )
240 { 271 {
241 System.out.println( "Matching classes..." ); 272 System.out.println( "Matching classes..." );
242 ClassMatching matching = null; 273 ClassMatching matching = null;
243 for( boolean useRawNames : Arrays.asList( false/*, true*/ ) ) 274 for( boolean useReferences : Arrays.asList( false, true ) )
244 { 275 {
245 for( boolean useReferences : Arrays.asList( false, true ) ) 276 int numMatches = 0;
277 do
246 { 278 {
247 int numMatches = 0; 279 SidedClassNamer sourceNamer = null;
248 do 280 SidedClassNamer destNamer = null;
281 if( matching != null )
249 { 282 {
250 SidedClassNamer sourceNamer = null; 283 // build a class namer
251 SidedClassNamer destNamer = null; 284 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() );
252 if( matching != null ) 285 sourceNamer = namer.getSourceNamer();
253 { 286 destNamer = namer.getDestNamer();
254 // build a class namer
255 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() );
256 sourceNamer = namer.getSourceNamer();
257 destNamer = namer.getDestNamer();
258
259 // note the number of matches
260 numMatches = matching.getUniqueMatches().size();
261 }
262 287
263 // get the entries left to match 288 // note the number of matches
264 Set<ClassEntry> sourceClassEntries = sourceIndex.getObfClassEntries(); 289 numMatches = matching.getUniqueMatches().size();
265 Set<ClassEntry> destClassEntries = destIndex.getObfClassEntries(); 290 }
266 if( matching != null ) 291
292 // get the entries left to match
293 Set<ClassEntry> sourceClassEntries = Sets.newHashSet();
294 Set<ClassEntry> destClassEntries = Sets.newHashSet();
295 if( matching == null )
296 {
297 sourceClassEntries.addAll( sourceIndex.getObfClassEntries() );
298 destClassEntries.addAll( destIndex.getObfClassEntries() );
299 matching = new ClassMatching();
300 }
301 else
302 {
303 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() )
267 { 304 {
268 sourceClassEntries.clear(); 305 for( ClassIdentity c : entry.getKey() )
269 destClassEntries.clear();
270 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() )
271 {
272 for( ClassIdentity c : entry.getKey() )
273 {
274 sourceClassEntries.add( c.getClassEntry() );
275 matching.removeSource( c );
276 }
277 for( ClassIdentity c : entry.getValue() )
278 {
279 destClassEntries.add( c.getClassEntry() );
280 matching.removeDest( c );
281 }
282 }
283 for( ClassIdentity c : matching.getUnmatchedSourceClasses() )
284 { 306 {
285 sourceClassEntries.add( c.getClassEntry() ); 307 sourceClassEntries.add( c.getClassEntry() );
286 matching.removeSource( c ); 308 matching.removeSource( c );
287 } 309 }
288 for( ClassIdentity c : matching.getUnmatchedDestClasses() ) 310 for( ClassIdentity c : entry.getValue() )
289 { 311 {
290 destClassEntries.add( c.getClassEntry() ); 312 destClassEntries.add( c.getClassEntry() );
291 matching.removeDest( c ); 313 matching.removeDest( c );
292 } 314 }
293 } 315 }
294 else 316 for( ClassIdentity c : matching.getUnmatchedSourceClasses() )
295 { 317 {
296 matching = new ClassMatching(); 318 sourceClassEntries.add( c.getClassEntry() );
319 matching.removeSource( c );
297 } 320 }
298 321 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
299 // compute a matching for the classes
300 for( ClassEntry classEntry : sourceClassEntries )
301 {
302 CtClass c = sourceLoader.loadClass( classEntry.getName() );
303 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames );
304 matching.addSource( sourceClass );
305 }
306 for( ClassEntry classEntry : destClassEntries )
307 { 322 {
308 CtClass c = destLoader.loadClass( classEntry.getName() ); 323 destClassEntries.add( c.getClassEntry() );
309 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames ); 324 matching.removeDest( c );
310 matching.matchDestClass( destClass );
311 } 325 }
312
313 // TEMP
314 System.out.println( matching );
315 } 326 }
316 while( matching.getUniqueMatches().size() - numMatches > 0 ); 327
328 // compute a matching for the classes
329 for( ClassEntry classEntry : sourceClassEntries )
330 {
331 CtClass c = sourceLoader.loadClass( classEntry.getName() );
332 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences );
333 matching.addSource( sourceClass );
334 }
335 for( ClassEntry classEntry : destClassEntries )
336 {
337 CtClass c = destLoader.loadClass( classEntry.getName() );
338 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences );
339 matching.matchDestClass( destClass );
340 }
341
342 // TEMP
343 System.out.println( matching );
317 } 344 }
345 while( matching.getUniqueMatches().size() - numMatches > 0 );
318 } 346 }
319 347
320 // DEBUG: check the class matches 348 // check the class matches
321 System.out.println( "Checking class matches..." ); 349 System.out.println( "Checking class matches..." );
350 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() );
351 SidedClassNamer sourceNamer = namer.getSourceNamer();
352 SidedClassNamer destNamer = namer.getDestNamer();
322 for( Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet() ) 353 for( Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet() )
323 { 354 {
324 // check source 355 // check source
@@ -327,7 +358,7 @@ public class ClassMatcher
327 assert( sourceC != null ) 358 assert( sourceC != null )
328 : "Unable to load source class " + sourceClass.getClassEntry(); 359 : "Unable to load source class " + sourceClass.getClassEntry();
329 assert( sourceClass.matches( sourceC ) ) 360 assert( sourceClass.matches( sourceC ) )
330 : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, null, sourceIndex, false, false ); 361 : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, sourceNamer, sourceIndex, false );
331 362
332 // check dest 363 // check dest
333 ClassIdentity destClass = entry.getValue(); 364 ClassIdentity destClass = entry.getValue();
@@ -335,7 +366,7 @@ public class ClassMatcher
335 assert( destC != null ) 366 assert( destC != null )
336 : "Unable to load dest class " + destClass.getClassEntry(); 367 : "Unable to load dest class " + destClass.getClassEntry();
337 assert( destClass.matches( destC ) ) 368 assert( destClass.matches( destC ) )
338 : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, null, destIndex, false, false ); 369 : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, destNamer, destIndex, false );
339 } 370 }
340 371
341 // warn about the ambiguous matchings 372 // warn about the ambiguous matchings
@@ -372,6 +403,27 @@ public class ClassMatcher
372 return matching; 403 return matching;
373 } 404 }
374 405
406 private static void printScoredMatches( int maxScore, List<Integer> scores, Multimap<Integer,ClassIdentity> scoredMatches )
407 {
408 int numScoredMatchesShown = 0;
409 for( int score : scores )
410 {
411 for( ClassIdentity scoredMatch : scoredMatches.get( score ) )
412 {
413 System.out.println( String.format( "\tScore: %3d %3.0f%% %s",
414 score,
415 100.0*score/maxScore,
416 scoredMatch.getClassEntry().getName()
417 ) );
418
419 if( numScoredMatchesShown++ > 10 )
420 {
421 return;
422 }
423 }
424 }
425 }
426
375 private static List<String> getClassNames( Collection<ClassIdentity> classes ) 427 private static List<String> getClassNames( Collection<ClassIdentity> classes )
376 { 428 {
377 List<String> out = Lists.newArrayList(); 429 List<String> out = Lists.newArrayList();
diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java
index ef5a7d8a..6ce8c887 100644
--- a/src/cuchaz/enigma/convert/ClassMatching.java
+++ b/src/cuchaz/enigma/convert/ClassMatching.java
@@ -183,7 +183,7 @@ public class ClassMatching
183 { 183 {
184 conversion.put( 184 conversion.put(
185 sourceClass.getClassEntry().getName(), 185 sourceClass.getClassEntry().getName(),
186 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, new ArrayList<ClassIdentity>() ) 186 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, getUnmatchedDestClasses() )
187 ); 187 );
188 } 188 }
189 return conversion; 189 return conversion;
@@ -193,25 +193,11 @@ public class ClassMatching
193 public String toString( ) 193 public String toString( )
194 { 194 {
195 StringBuilder buf = new StringBuilder(); 195 StringBuilder buf = new StringBuilder();
196 196 buf.append( String.format( "%12s%8s%8s\n", "", "Source", "Dest" ) );
197 buf.append( "Source classes: " ); 197 buf.append( String.format( "%12s%8d%8d\n", "Classes", getSourceClasses().size(), getDestClasses().size() ) );
198 buf.append( getSourceClasses().size() ); 198 buf.append( String.format( "%12s%8d%8d\n", "Unique", getUniqueMatches().size(), getUniqueMatches().size() ) );
199 buf.append( "\n\tUnique: " ); 199 buf.append( String.format( "%12s%8d%8d\n", "Ambiguous", getNumAmbiguousSourceMatches(), getNumAmbiguousDestMatches() ) );
200 buf.append( getUniqueMatches().size() ); 200 buf.append( String.format( "%12s%8d%8d\n", "Unmatched", getUnmatchedSourceClasses().size(), getUnmatchedDestClasses().size() ) );
201 buf.append( "\n\tAmbiguous: " );
202 buf.append( getNumAmbiguousSourceMatches() );
203 buf.append( "\n\tUnmatched: " );
204 buf.append( getUnmatchedSourceClasses().size() );
205
206 buf.append( "\nDest classes: " );
207 buf.append( getDestClasses().size() );
208 buf.append( "\n\tUnique: " );
209 buf.append( getUniqueMatches().size() );
210 buf.append( "\n\tAmbiguous: " );
211 buf.append( getNumAmbiguousDestMatches() );
212 buf.append( "\n\tUnmatched: " );
213 buf.append( getUnmatchedDestClasses().size() );
214
215 return buf.toString(); 201 return buf.toString();
216 } 202 }
217} 203}
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index c92f8de0..4b47d160 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -15,15 +15,17 @@ import java.io.InputStream;
15import java.io.ObjectInputStream; 15import java.io.ObjectInputStream;
16import java.io.Serializable; 16import java.io.Serializable;
17import java.util.ArrayList; 17import java.util.ArrayList;
18import java.util.List;
19import java.util.Map; 18import java.util.Map;
19import java.util.Set;
20import java.util.zip.GZIPInputStream; 20import java.util.zip.GZIPInputStream;
21 21
22import com.beust.jcommander.internal.Sets;
22import com.google.common.collect.Maps; 23import com.google.common.collect.Maps;
23 24
24import cuchaz.enigma.Util; 25import cuchaz.enigma.Util;
25import cuchaz.enigma.analysis.Ancestries; 26import cuchaz.enigma.analysis.Ancestries;
26import cuchaz.enigma.analysis.DeobfuscatedAncestries; 27import cuchaz.enigma.analysis.DeobfuscatedAncestries;
28import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
27 29
28public class Mappings implements Serializable 30public class Mappings implements Serializable
29{ 31{
@@ -163,9 +165,28 @@ public class Mappings implements Serializable
163 } 165 }
164 } 166 }
165 167
166 public List<String> getAllObfClassNames( ) 168 public Set<String> getAllObfClassNames( )
167 { 169 {
168 // TODO: implement this 170 final Set<String> classNames = Sets.newHashSet();
169 return null; 171 for( ClassMapping classMapping : classes() )
172 {
173 // add the class name
174 classNames.add( classMapping.getObfName() );
175
176 // add classes from method signatures
177 for( MethodMapping methodMapping : classMapping.methods() )
178 {
179 SignatureUpdater.update( methodMapping.getObfSignature(), new ClassNameUpdater( )
180 {
181 @Override
182 public String update( String className )
183 {
184 classNames.add( className );
185 return className;
186 }
187 } );
188 }
189 }
190 return classNames;
170 } 191 }
171} 192}