summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassMatcher.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/convert/ClassMatcher.java')
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java412
1 files changed, 169 insertions, 243 deletions
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index 290d90a..fc39ed0 100644
--- a/src/cuchaz/enigma/convert/ClassMatcher.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -49,102 +49,92 @@ import cuchaz.enigma.mapping.MappingsWriter;
49import cuchaz.enigma.mapping.MethodEntry; 49import cuchaz.enigma.mapping.MethodEntry;
50import cuchaz.enigma.mapping.MethodMapping; 50import cuchaz.enigma.mapping.MethodMapping;
51 51
52public class ClassMatcher 52public class ClassMatcher {
53{ 53
54 public static void main( String[] args ) 54 public static void main(String[] args) throws IOException, MappingParseException {
55 throws IOException, MappingParseException
56 {
57 // TEMP 55 // TEMP
58 JarFile sourceJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); 56 JarFile sourceJar = new JarFile(new File("input/1.8-pre3.jar"));
59 JarFile destJar = new JarFile( new File( "input/1.8.jar" ) ); 57 JarFile destJar = new JarFile(new File("input/1.8.jar"));
60 File inMappingsFile = new File( "../Enigma Mappings/1.8-pre3.mappings" ); 58 File inMappingsFile = new File("../Enigma Mappings/1.8-pre3.mappings");
61 File outMappingsFile = new File( "../Enigma Mappings/1.8.mappings" ); 59 File outMappingsFile = new File("../Enigma Mappings/1.8.mappings");
62 60
63 // define a matching to use when the automated system cannot find a match 61 // define a matching to use when the automated system cannot find a match
64 Map<String,String> fallbackMatching = Maps.newHashMap(); 62 Map<String,String> fallbackMatching = Maps.newHashMap();
65 fallbackMatching.put( "none/ayb", "none/ayf" ); 63 fallbackMatching.put("none/ayb", "none/ayf");
66 fallbackMatching.put( "none/ayd", "none/ayd" ); 64 fallbackMatching.put("none/ayd", "none/ayd");
67 fallbackMatching.put( "none/bgk", "unknown/bgk" ); 65 fallbackMatching.put("none/bgk", "unknown/bgk");
68 66
69 // do the conversion 67 // do the conversion
70 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) ); 68 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile));
71 convertMappings( sourceJar, destJar, mappings, fallbackMatching ); 69 convertMappings(sourceJar, destJar, mappings, fallbackMatching);
72 70
73 // write out the converted mappings 71 // write out the converted mappings
74 FileWriter writer = new FileWriter( outMappingsFile ); 72 FileWriter writer = new FileWriter(outMappingsFile);
75 new MappingsWriter().write( writer, mappings ); 73 new MappingsWriter().write(writer, mappings);
76 writer.close(); 74 writer.close();
77 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); 75 System.out.println("Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath());
78 } 76 }
79 77
80 private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings, Map<String,String> fallbackMatching ) 78 private static void convertMappings(JarFile sourceJar, JarFile destJar, Mappings mappings, Map<String,String> fallbackMatching) {
81 {
82 // index jars 79 // index jars
83 System.out.println( "Indexing source jar..." ); 80 System.out.println("Indexing source jar...");
84 JarIndex sourceIndex = new JarIndex(); 81 JarIndex sourceIndex = new JarIndex();
85 sourceIndex.indexJar( sourceJar, false ); 82 sourceIndex.indexJar(sourceJar, false);
86 System.out.println( "Indexing dest jar..." ); 83 System.out.println("Indexing dest jar...");
87 JarIndex destIndex = new JarIndex(); 84 JarIndex destIndex = new JarIndex();
88 destIndex.indexJar( destJar, false ); 85 destIndex.indexJar(destJar, false);
89 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex ); 86 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader(sourceJar, sourceIndex);
90 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); 87 TranslatingTypeLoader destLoader = new TranslatingTypeLoader(destJar, destIndex);
91 88
92 // compute the matching 89 // compute the matching
93 ClassMatching matching = computeMatching( sourceIndex, sourceLoader, destIndex, destLoader ); 90 ClassMatching matching = computeMatching(sourceIndex, sourceLoader, destIndex, destLoader);
94 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> matchingIndex = matching.getIndex(); 91 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> matchingIndex = matching.getIndex();
95 92
96 // get all the obf class names used in the mappings 93 // get all the obf class names used in the mappings
97 Set<String> usedClassNames = mappings.getAllObfClassNames(); 94 Set<String> usedClassNames = mappings.getAllObfClassNames();
98 Set<String> allClassNames = Sets.newHashSet(); 95 Set<String> allClassNames = Sets.newHashSet();
99 for( ClassEntry classEntry : sourceIndex.getObfClassEntries() ) 96 for (ClassEntry classEntry : sourceIndex.getObfClassEntries()) {
100 { 97 allClassNames.add(classEntry.getName());
101 allClassNames.add( classEntry.getName() );
102 } 98 }
103 usedClassNames.retainAll( allClassNames ); 99 usedClassNames.retainAll(allClassNames);
104 System.out.println( "Used " + usedClassNames.size() + " classes in the mappings" ); 100 System.out.println("Used " + usedClassNames.size() + " classes in the mappings");
105 101
106 // probabilistically match the non-uniquely-matched source classes 102 // probabilistically match the non-uniquely-matched source classes
107 for( Map.Entry<ClassIdentity,List<ClassIdentity>> entry : matchingIndex.values() ) 103 for (Map.Entry<ClassIdentity,List<ClassIdentity>> entry : matchingIndex.values()) {
108 {
109 ClassIdentity sourceClass = entry.getKey(); 104 ClassIdentity sourceClass = entry.getKey();
110 List<ClassIdentity> destClasses = entry.getValue(); 105 List<ClassIdentity> destClasses = entry.getValue();
111 106
112 // skip classes that are uniquely matched 107 // skip classes that are uniquely matched
113 if( destClasses.size() == 1 ) 108 if (destClasses.size() == 1) {
114 {
115 continue; 109 continue;
116 } 110 }
117 111
118 // skip classes that aren't used in the mappings 112 // skip classes that aren't used in the mappings
119 if( !usedClassNames.contains( sourceClass.getClassEntry().getName() ) ) 113 if (!usedClassNames.contains(sourceClass.getClassEntry().getName())) {
120 {
121 continue; 114 continue;
122 } 115 }
123 116
124 System.out.println( "No exact match for source class " + sourceClass.getClassEntry() ); 117 System.out.println("No exact match for source class " + sourceClass.getClassEntry());
125 118
126 // find the closest classes 119 // find the closest classes
127 Multimap<Integer,ClassIdentity> scoredMatches = ArrayListMultimap.create(); 120 Multimap<Integer,ClassIdentity> scoredMatches = ArrayListMultimap.create();
128 for( ClassIdentity c : destClasses ) 121 for (ClassIdentity c : destClasses) {
129 { 122 scoredMatches.put(sourceClass.getMatchScore(c), c);
130 scoredMatches.put( sourceClass.getMatchScore( c ), c );
131 } 123 }
132 List<Integer> scores = new ArrayList<Integer>( scoredMatches.keySet() ); 124 List<Integer> scores = new ArrayList<Integer>(scoredMatches.keySet());
133 Collections.sort( scores, Collections.reverseOrder() ); 125 Collections.sort(scores, Collections.reverseOrder());
134 printScoredMatches( sourceClass.getMaxMatchScore(), scores, scoredMatches ); 126 printScoredMatches(sourceClass.getMaxMatchScore(), scores, scoredMatches);
135 127
136 // does the best match have a non-zero score and the same name? 128 // does the best match have a non-zero score and the same name?
137 int bestScore = scores.get( 0 ); 129 int bestScore = scores.get(0);
138 Collection<ClassIdentity> bestMatches = scoredMatches.get( bestScore ); 130 Collection<ClassIdentity> bestMatches = scoredMatches.get(bestScore);
139 if( bestScore > 0 && bestMatches.size() == 1 ) 131 if (bestScore > 0 && bestMatches.size() == 1) {
140 {
141 ClassIdentity bestMatch = bestMatches.iterator().next(); 132 ClassIdentity bestMatch = bestMatches.iterator().next();
142 if( bestMatch.getClassEntry().equals( sourceClass.getClassEntry() ) ) 133 if (bestMatch.getClassEntry().equals(sourceClass.getClassEntry())) {
143 {
144 // use it 134 // use it
145 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName() ); 135 System.out.println("\tAutomatically choosing likely match: " + bestMatch.getClassEntry().getName());
146 destClasses.clear(); 136 destClasses.clear();
147 destClasses.add( bestMatch ); 137 destClasses.add(bestMatch);
148 } 138 }
149 } 139 }
150 } 140 }
@@ -152,63 +142,46 @@ public class ClassMatcher
152 // group the matching into unique and non-unique matches 142 // group the matching into unique and non-unique matches
153 BiMap<String,String> matchedClassNames = HashBiMap.create(); 143 BiMap<String,String> matchedClassNames = HashBiMap.create();
154 Set<String> unmatchedSourceClassNames = Sets.newHashSet(); 144 Set<String> unmatchedSourceClassNames = Sets.newHashSet();
155 for( String className : usedClassNames ) 145 for (String className : usedClassNames) {
156 {
157 // is there a match for this class? 146 // is there a match for this class?
158 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = matchingIndex.get( className ); 147 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = matchingIndex.get(className);
159 ClassIdentity sourceClass = entry.getKey(); 148 ClassIdentity sourceClass = entry.getKey();
160 List<ClassIdentity> matches = entry.getValue(); 149 List<ClassIdentity> matches = entry.getValue();
161 150
162 if( matches.size() == 1 ) 151 if (matches.size() == 1) {
163 {
164 // unique match! We're good to go! 152 // unique match! We're good to go!
165 matchedClassNames.put( 153 matchedClassNames.put(sourceClass.getClassEntry().getName(), matches.get(0).getClassEntry().getName());
166 sourceClass.getClassEntry().getName(), 154 } else {
167 matches.get( 0 ).getClassEntry().getName()
168 );
169 }
170 else
171 {
172 // no match, check the fallback matching 155 // no match, check the fallback matching
173 String fallbackMatch = fallbackMatching.get( className ); 156 String fallbackMatch = fallbackMatching.get(className);
174 if( fallbackMatch != null ) 157 if (fallbackMatch != null) {
175 { 158 matchedClassNames.put(sourceClass.getClassEntry().getName(), fallbackMatch);
176 matchedClassNames.put( 159 } else {
177 sourceClass.getClassEntry().getName(), 160 unmatchedSourceClassNames.add(className);
178 fallbackMatch
179 );
180 }
181 else
182 {
183 unmatchedSourceClassNames.add( className );
184 } 161 }
185 } 162 }
186 } 163 }
187 164
188 // report unmatched classes 165 // report unmatched classes
189 if( !unmatchedSourceClassNames.isEmpty() ) 166 if (!unmatchedSourceClassNames.isEmpty()) {
190 { 167 System.err.println("ERROR: there were unmatched classes!");
191 System.err.println( "ERROR: there were unmatched classes!" ); 168 for (String className : unmatchedSourceClassNames) {
192 for( String className : unmatchedSourceClassNames ) 169 System.err.println("\t" + className);
193 {
194 System.err.println( "\t" + className );
195 } 170 }
196 return; 171 return;
197 } 172 }
198 173
199 // get the class name changes from the matched class names 174 // get the class name changes from the matched class names
200 Map<String,String> classChanges = Maps.newHashMap(); 175 Map<String,String> classChanges = Maps.newHashMap();
201 for( Map.Entry<String,String> entry : matchedClassNames.entrySet() ) 176 for (Map.Entry<String,String> entry : matchedClassNames.entrySet()) {
202 { 177 if (!entry.getKey().equals(entry.getValue())) {
203 if( !entry.getKey().equals( entry.getValue() ) ) 178 classChanges.put(entry.getKey(), entry.getValue());
204 { 179 System.out.println(String.format("Class change: %s -> %s", entry.getKey(), entry.getValue()));
205 classChanges.put( entry.getKey(), entry.getValue() );
206 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) );
207 /* DEBUG 180 /* DEBUG
208 System.out.println( String.format( "\n%s\n%s", 181 System.out.println(String.format("\n%s\n%s",
209 new ClassIdentity( sourceLoader.loadClass( entry.getKey() ), null, sourceIndex, false, false ), 182 new ClassIdentity(sourceLoader.loadClass(entry.getKey()), null, sourceIndex, false, false),
210 new ClassIdentity( destLoader.loadClass( entry.getValue() ), null, destIndex, false, false ) 183 new ClassIdentity( destLoader.loadClass(entry.getValue()), null, destIndex, false, false)
211 ) ); 184 ));
212 */ 185 */
213 } 186 }
214 } 187 }
@@ -217,52 +190,42 @@ public class ClassMatcher
217 // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b 190 // 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(); 191 LinkedHashMap<String,String> orderedClassChanges = Maps.newLinkedHashMap();
219 int numChangesLeft = classChanges.size(); 192 int numChangesLeft = classChanges.size();
220 while( !classChanges.isEmpty() ) 193 while (!classChanges.isEmpty()) {
221 {
222 Iterator<Map.Entry<String,String>> iter = classChanges.entrySet().iterator(); 194 Iterator<Map.Entry<String,String>> iter = classChanges.entrySet().iterator();
223 while( iter.hasNext() ) 195 while (iter.hasNext()) {
224 {
225 Map.Entry<String,String> entry = iter.next(); 196 Map.Entry<String,String> entry = iter.next();
226 if( classChanges.get( entry.getValue() ) == null ) 197 if (classChanges.get(entry.getValue()) == null) {
227 { 198 orderedClassChanges.put(entry.getKey(), entry.getValue());
228 orderedClassChanges.put( entry.getKey(), entry.getValue() );
229 iter.remove(); 199 iter.remove();
230 } 200 }
231 } 201 }
232 202
233 // did we remove any changes? 203 // did we remove any changes?
234 if( numChangesLeft - classChanges.size() > 0 ) 204 if (numChangesLeft - classChanges.size() > 0) {
235 {
236 // keep going 205 // keep going
237 numChangesLeft = classChanges.size(); 206 numChangesLeft = classChanges.size();
238 } 207 } else {
239 else
240 {
241 // can't sort anymore. There must be a loop 208 // can't sort anymore. There must be a loop
242 break; 209 break;
243 } 210 }
244 } 211 }
245 if( classChanges.size() > 0 ) 212 if (classChanges.size() > 0) {
246 { 213 throw new Error(String.format("Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size()));
247 throw new Error( String.format( "Unable to sort %d/%d class changes!", classChanges.size(), matchedClassNames.size() ) );
248 } 214 }
249 215
250 // convert the mappings in the correct class order 216 // convert the mappings in the correct class order
251 for( Map.Entry<String,String> entry : orderedClassChanges.entrySet() ) 217 for (Map.Entry<String,String> entry : orderedClassChanges.entrySet()) {
252 { 218 mappings.renameObfClass(entry.getKey(), entry.getValue());
253 mappings.renameObfClass( entry.getKey(), entry.getValue() );
254 } 219 }
255 220
256 // check the method matches 221 // check the method matches
257 System.out.println( "Checking methods..." ); 222 System.out.println("Checking methods...");
258 for( ClassMapping classMapping : mappings.classes() ) 223 for (ClassMapping classMapping : mappings.classes()) {
259 { 224 ClassEntry classEntry = new ClassEntry(classMapping.getObfName());
260 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() ); 225 for (MethodMapping methodMapping : classMapping.methods()) {
261 for( MethodMapping methodMapping : classMapping.methods() ) 226
262 {
263 // skip constructors 227 // skip constructors
264 if( methodMapping.getObfName().equals( "<init>" ) ) 228 if (methodMapping.getObfName().equals("<init>")) {
265 {
266 continue; 229 continue;
267 } 230 }
268 231
@@ -271,56 +234,51 @@ public class ClassMatcher
271 methodMapping.getObfName(), 234 methodMapping.getObfName(),
272 methodMapping.getObfSignature() 235 methodMapping.getObfSignature()
273 ); 236 );
274 if( !destIndex.containsObfBehavior( methodEntry ) ) 237 if (!destIndex.containsObfBehavior(methodEntry)) {
275 { 238 System.err.println("WARNING: method doesn't match: " + methodEntry);
276 System.err.println( "WARNING: method doesn't match: " + methodEntry );
277 239
278 // show the available methods 240 // show the available methods
279 System.err.println( "\tAvailable dest methods:" ); 241 System.err.println("\tAvailable dest methods:");
280 CtClass c = destLoader.loadClass( classMapping.getObfName() ); 242 CtClass c = destLoader.loadClass(classMapping.getObfName());
281 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 243 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
282 {
283 MethodEntry declaredMethodEntry = new MethodEntry( 244 MethodEntry declaredMethodEntry = new MethodEntry(
284 new ClassEntry( classMapping.getObfName() ), 245 new ClassEntry(classMapping.getObfName()),
285 behavior.getName(), 246 behavior.getName(),
286 behavior.getSignature() 247 behavior.getSignature()
287 ); 248 );
288 System.err.println( "\t\t" + declaredMethodEntry ); 249 System.err.println("\t\t" + declaredMethodEntry);
289 } 250 }
290 251
291 System.err.println( "\tAvailable source methods:" ); 252 System.err.println("\tAvailable source methods:");
292 c = sourceLoader.loadClass( matchedClassNames.inverse().get( classMapping.getObfName() ) ); 253 c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName()));
293 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 254 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
294 {
295 MethodEntry declaredMethodEntry = new MethodEntry( 255 MethodEntry declaredMethodEntry = new MethodEntry(
296 new ClassEntry( classMapping.getObfName() ), 256 new ClassEntry(classMapping.getObfName()),
297 behavior.getName(), 257 behavior.getName(),
298 behavior.getSignature() 258 behavior.getSignature()
299 ); 259 );
300 System.err.println( "\t\t" + declaredMethodEntry ); 260 System.err.println("\t\t" + declaredMethodEntry);
301 } 261 }
302 } 262 }
303 } 263 }
304 } 264 }
305 265
306 System.out.println( "Done!" ); 266 System.out.println("Done!");
307 } 267 }
308 268
309 public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader ) 269 public static ClassMatching computeMatching(JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader) {
310 { 270
311 System.out.println( "Matching classes..." ); 271 System.out.println("Matching classes...");
272
312 ClassMatching matching = null; 273 ClassMatching matching = null;
313 for( boolean useReferences : Arrays.asList( false, true ) ) 274 for (boolean useReferences : Arrays.asList(false, true)) {
314 {
315 int numMatches = 0; 275 int numMatches = 0;
316 do 276 do {
317 {
318 SidedClassNamer sourceNamer = null; 277 SidedClassNamer sourceNamer = null;
319 SidedClassNamer destNamer = null; 278 SidedClassNamer destNamer = null;
320 if( matching != null ) 279 if (matching != null) {
321 {
322 // build a class namer 280 // build a class namer
323 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); 281 ClassNamer namer = new ClassNamer(matching.getUniqueMatches());
324 sourceNamer = namer.getSourceNamer(); 282 sourceNamer = namer.getSourceNamer();
325 destNamer = namer.getDestNamer(); 283 destNamer = namer.getDestNamer();
326 284
@@ -331,158 +289,126 @@ public class ClassMatcher
331 // get the entries left to match 289 // get the entries left to match
332 Set<ClassEntry> sourceClassEntries = Sets.newHashSet(); 290 Set<ClassEntry> sourceClassEntries = Sets.newHashSet();
333 Set<ClassEntry> destClassEntries = Sets.newHashSet(); 291 Set<ClassEntry> destClassEntries = Sets.newHashSet();
334 if( matching == null ) 292 if (matching == null) {
335 { 293 sourceClassEntries.addAll(sourceIndex.getObfClassEntries());
336 sourceClassEntries.addAll( sourceIndex.getObfClassEntries() ); 294 destClassEntries.addAll(destIndex.getObfClassEntries());
337 destClassEntries.addAll( destIndex.getObfClassEntries() );
338 matching = new ClassMatching(); 295 matching = new ClassMatching();
339 } 296 } else {
340 else 297 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet()) {
341 { 298 for (ClassIdentity c : entry.getKey()) {
342 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() ) 299 sourceClassEntries.add(c.getClassEntry());
343 { 300 matching.removeSource(c);
344 for( ClassIdentity c : entry.getKey() )
345 {
346 sourceClassEntries.add( c.getClassEntry() );
347 matching.removeSource( c );
348 } 301 }
349 for( ClassIdentity c : entry.getValue() ) 302 for (ClassIdentity c : entry.getValue()) {
350 { 303 destClassEntries.add(c.getClassEntry());
351 destClassEntries.add( c.getClassEntry() ); 304 matching.removeDest(c);
352 matching.removeDest( c );
353 } 305 }
354 } 306 }
355 for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) 307 for (ClassIdentity c : matching.getUnmatchedSourceClasses()) {
356 { 308 sourceClassEntries.add(c.getClassEntry());
357 sourceClassEntries.add( c.getClassEntry() ); 309 matching.removeSource(c);
358 matching.removeSource( c );
359 } 310 }
360 for( ClassIdentity c : matching.getUnmatchedDestClasses() ) 311 for (ClassIdentity c : matching.getUnmatchedDestClasses()) {
361 { 312 destClassEntries.add(c.getClassEntry());
362 destClassEntries.add( c.getClassEntry() ); 313 matching.removeDest(c);
363 matching.removeDest( c );
364 } 314 }
365 } 315 }
366 316
367 // compute a matching for the classes 317 // compute a matching for the classes
368 for( ClassEntry classEntry : sourceClassEntries ) 318 for (ClassEntry classEntry : sourceClassEntries) {
369 { 319 CtClass c = sourceLoader.loadClass(classEntry.getName());
370 CtClass c = sourceLoader.loadClass( classEntry.getName() ); 320 ClassIdentity sourceClass = new ClassIdentity(c, sourceNamer, sourceIndex, useReferences);
371 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences ); 321 matching.addSource(sourceClass);
372 matching.addSource( sourceClass );
373 } 322 }
374 for( ClassEntry classEntry : destClassEntries ) 323 for (ClassEntry classEntry : destClassEntries) {
375 { 324 CtClass c = destLoader.loadClass(classEntry.getName());
376 CtClass c = destLoader.loadClass( classEntry.getName() ); 325 ClassIdentity destClass = new ClassIdentity(c, destNamer, destIndex, useReferences);
377 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences ); 326 matching.matchDestClass(destClass);
378 matching.matchDestClass( destClass );
379 } 327 }
380 328
381 // TEMP 329 // TEMP
382 System.out.println( matching ); 330 System.out.println(matching);
383 } 331 } while (matching.getUniqueMatches().size() - numMatches > 0);
384 while( matching.getUniqueMatches().size() - numMatches > 0 );
385 } 332 }
386 333
387 // check the class matches 334 // check the class matches
388 System.out.println( "Checking class matches..." ); 335 System.out.println("Checking class matches...");
389 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); 336 ClassNamer namer = new ClassNamer(matching.getUniqueMatches());
390 SidedClassNamer sourceNamer = namer.getSourceNamer(); 337 SidedClassNamer sourceNamer = namer.getSourceNamer();
391 SidedClassNamer destNamer = namer.getDestNamer(); 338 SidedClassNamer destNamer = namer.getDestNamer();
392 for( Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet() ) 339 for (Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet()) {
393 { 340
394 // check source 341 // check source
395 ClassIdentity sourceClass = entry.getKey(); 342 ClassIdentity sourceClass = entry.getKey();
396 CtClass sourceC = sourceLoader.loadClass( sourceClass.getClassEntry().getName() ); 343 CtClass sourceC = sourceLoader.loadClass(sourceClass.getClassEntry().getName());
397 assert( sourceC != null ) 344 assert (sourceC != null) : "Unable to load source class " + sourceClass.getClassEntry();
398 : "Unable to load source class " + sourceClass.getClassEntry(); 345 assert (sourceClass.matches(sourceC)) : "Source " + sourceClass + " doesn't match " + new ClassIdentity(sourceC, sourceNamer, sourceIndex, false);
399 assert( sourceClass.matches( sourceC ) )
400 : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, sourceNamer, sourceIndex, false );
401 346
402 // check dest 347 // check dest
403 ClassIdentity destClass = entry.getValue(); 348 ClassIdentity destClass = entry.getValue();
404 CtClass destC = destLoader.loadClass( destClass.getClassEntry().getName() ); 349 CtClass destC = destLoader.loadClass(destClass.getClassEntry().getName());
405 assert( destC != null ) 350 assert (destC != null) : "Unable to load dest class " + destClass.getClassEntry();
406 : "Unable to load dest class " + destClass.getClassEntry(); 351 assert (destClass.matches(destC)) : "Dest " + destClass + " doesn't match " + new ClassIdentity(destC, destNamer, destIndex, false);
407 assert( destClass.matches( destC ) )
408 : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, destNamer, destIndex, false );
409 } 352 }
410 353
411 // warn about the ambiguous matchings 354 // warn about the ambiguous matchings
412 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( matching.getAmbiguousMatches().entrySet() ); 355 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>(matching.getAmbiguousMatches().entrySet());
413 Collections.sort( ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( ) 356 Collections.sort(ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>() {
414 {
415 @Override 357 @Override
416 public int compare( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b ) 358 public int compare(Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b) {
417 { 359 String aName = a.getKey().get(0).getClassEntry().getName();
418 String aName = a.getKey().get( 0 ).getClassEntry().getName(); 360 String bName = b.getKey().get(0).getClassEntry().getName();
419 String bName = b.getKey().get( 0 ).getClassEntry().getName(); 361 return aName.compareTo(bName);
420 return aName.compareTo( bName );
421 } 362 }
422 } ); 363 });
423 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches ) 364 for (Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches) {
424 { 365 System.out.println("Ambiguous matching:");
425 System.out.println( "Ambiguous matching:" ); 366 System.out.println("\tSource: " + getClassNames(entry.getKey()));
426 System.out.println( "\tSource: " + getClassNames( entry.getKey() ) ); 367 System.out.println("\tDest: " + getClassNames(entry.getValue()));
427 System.out.println( "\tDest: " + getClassNames( entry.getValue() ) );
428 } 368 }
429 369
430 /* DEBUG 370 /* DEBUG
431 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 ); 371 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 );
432 for( ClassIdentity c : entry.getKey() ) 372 for (ClassIdentity c : entry.getKey()) {
433 { 373 System.out.println(c);
434 System.out.println( c );
435 } 374 }
436 for( ClassIdentity c : entry.getKey() ) 375 for(ClassIdentity c : entry.getKey()) {
437 { 376 System.out.println(decompile(sourceLoader, c.getClassEntry()));
438 System.out.println( decompile( sourceLoader, c.getClassEntry() ) );
439 } 377 }
440 */ 378 */
441 379
442 return matching; 380 return matching;
443 } 381 }
444 382
445 private static void printScoredMatches( int maxScore, List<Integer> scores, Multimap<Integer,ClassIdentity> scoredMatches ) 383 private static void printScoredMatches(int maxScore, List<Integer> scores, Multimap<Integer,ClassIdentity> scoredMatches) {
446 {
447 int numScoredMatchesShown = 0; 384 int numScoredMatchesShown = 0;
448 for( int score : scores ) 385 for (int score : scores) {
449 { 386 for (ClassIdentity scoredMatch : scoredMatches.get(score)) {
450 for( ClassIdentity scoredMatch : scoredMatches.get( score ) ) 387 System.out.println(String.format("\tScore: %3d %3.0f%% %s", score, 100.0 * score / maxScore, scoredMatch.getClassEntry().getName()));
451 { 388 if (numScoredMatchesShown++ > 10) {
452 System.out.println( String.format( "\tScore: %3d %3.0f%% %s",
453 score,
454 100.0*score/maxScore,
455 scoredMatch.getClassEntry().getName()
456 ) );
457
458 if( numScoredMatchesShown++ > 10 )
459 {
460 return; 389 return;
461 } 390 }
462 } 391 }
463 } 392 }
464 } 393 }
465 394
466 private static List<String> getClassNames( Collection<ClassIdentity> classes ) 395 private static List<String> getClassNames(Collection<ClassIdentity> classes) {
467 {
468 List<String> out = Lists.newArrayList(); 396 List<String> out = Lists.newArrayList();
469 for( ClassIdentity c : classes ) 397 for (ClassIdentity c : classes) {
470 { 398 out.add(c.getClassEntry().getName());
471 out.add( c.getClassEntry().getName() );
472 } 399 }
473 Collections.sort( out ); 400 Collections.sort(out);
474 return out; 401 return out;
475 } 402 }
476 403
477 /* DEBUG 404 /* DEBUG
478 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) 405 private static String decompile(TranslatingTypeLoader loader, ClassEntry classEntry) {
479 {
480 PlainTextOutput output = new PlainTextOutput(); 406 PlainTextOutput output = new PlainTextOutput();
481 DecompilerSettings settings = DecompilerSettings.javaDefaults(); 407 DecompilerSettings settings = DecompilerSettings.javaDefaults();
482 settings.setForceExplicitImports( true ); 408 settings.setForceExplicitImports(true);
483 settings.setShowSyntheticMembers( true ); 409 settings.setShowSyntheticMembers(true);
484 settings.setTypeLoader( loader ); 410 settings.setTypeLoader(loader);
485 Decompiler.decompile( classEntry.getName(), output, settings ); 411 Decompiler.decompile(classEntry.getName(), output, settings);
486 return output.toString(); 412 return output.toString();
487 } 413 }
488 */ 414 */