summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassMapper.java
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/cuchaz/enigma/convert/ClassMapper.java202
1 files changed, 128 insertions, 74 deletions
diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java
index 5a16a1c..fe48c50 100644
--- a/src/cuchaz/enigma/convert/ClassMapper.java
+++ b/src/cuchaz/enigma/convert/ClassMapper.java
@@ -12,31 +12,20 @@ package cuchaz.enigma.convert;
12 12
13import java.io.File; 13import java.io.File;
14import java.io.IOException; 14import java.io.IOException;
15import java.util.Collection; 15import java.util.Arrays;
16import java.util.List; 16import java.util.List;
17import java.util.Map; 17import java.util.Map;
18import java.util.Set;
18import java.util.jar.JarFile; 19import java.util.jar.JarFile;
19 20
20import javassist.CtClass; 21import javassist.CtClass;
21 22import cuchaz.enigma.TranslatingTypeLoader;
22import com.beust.jcommander.internal.Lists; 23import cuchaz.enigma.analysis.JarIndex;
23import com.beust.jcommander.internal.Maps; 24import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
24import com.google.common.collect.ArrayListMultimap;
25import com.google.common.collect.Multimap;
26
27import cuchaz.enigma.analysis.JarClassIterator;
28import cuchaz.enigma.mapping.ClassEntry; 25import cuchaz.enigma.mapping.ClassEntry;
29 26
30public class ClassMapper 27public class ClassMapper
31{ 28{
32 private int m_numSourceClasses;
33 private int m_numDestClasses;
34 private Multimap<ClassIdentity,ClassIdentity> m_sourceClasses;
35 private Multimap<ClassIdentity,ClassIdentity> m_destClasses;
36 private List<ClassIdentity> m_unmatchedSourceClasses;
37 private List<ClassIdentity> m_unmatchedDestClasses;
38 private Map<ClassEntry,ClassIdentity> m_sourceKeyIndex;
39
40 public static void main( String[] args ) 29 public static void main( String[] args )
41 throws IOException 30 throws IOException
42 { 31 {
@@ -44,81 +33,146 @@ public class ClassMapper
44 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); 33 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) );
45 JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); 34 JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) );
46 35
47 ClassMapper mapper = new ClassMapper( fromJar, toJar ); 36 // compute the matching
48 System.out.println( String.format( "Mapped %d/%d source classes (%d unmatched) to %d/%d dest classes (%d unmatched)", 37 ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar );
49 mapper.m_sourceClasses.size(), mapper.m_numSourceClasses, mapper.m_unmatchedSourceClasses.size(), 38
50 mapper.m_destClasses.size(), mapper.m_numDestClasses, mapper.m_unmatchedDestClasses.size() 39 // TODO: use the matching to convert the mappings
51 ) );
52 } 40 }
53 41
54 public ClassMapper( JarFile sourceJar, JarFile destJar ) 42 public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar )
55 { 43 {
56 m_numSourceClasses = JarClassIterator.getClassEntries( sourceJar ).size(); 44 // index jars
57 m_numDestClasses = JarClassIterator.getClassEntries( destJar ).size(); 45 System.out.println( "Indexing source jar..." );
46 JarIndex sourceIndex = new JarIndex();
47 sourceIndex.indexJar( sourceJar );
48 System.out.println( "Indexing dest jar..." );
49 JarIndex destIndex = new JarIndex();
50 destIndex.indexJar( destJar );
58 51
59 // compute identities for the source classes 52 System.out.println( "Computing matching..." );
60 m_sourceClasses = ArrayListMultimap.create();
61 m_sourceKeyIndex = Maps.newHashMap();
62 for( CtClass c : JarClassIterator.classes( sourceJar ) )
63 {
64 ClassIdentity sourceClass = new ClassIdentity( c );
65 m_sourceClasses.put( sourceClass, sourceClass );
66 m_sourceKeyIndex.put( sourceClass.getClassEntry(), sourceClass );
67 }
68 53
69 // match the dest classes to the source classes 54 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex );
70 m_destClasses = ArrayListMultimap.create(); 55 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex );
71 m_unmatchedDestClasses = Lists.newArrayList(); 56
72 for( CtClass c : JarClassIterator.classes( destJar ) ) 57 ClassMatching matching = null;
58 for( boolean useReferences : Arrays.asList( false, true ) )
73 { 59 {
74 ClassIdentity destClass = new ClassIdentity( c ); 60 int numMatches = 0;
75 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get( destClass ); 61 do
76 if( matchedSourceClasses.isEmpty() )
77 {
78 // unmatched dest class
79 m_unmatchedDestClasses.add( destClass );
80 }
81 else
82 { 62 {
83 ClassIdentity sourceClass = matchedSourceClasses.iterator().next(); 63 SidedClassNamer sourceNamer = null;
84 m_destClasses.put( sourceClass, destClass ); 64 SidedClassNamer destNamer = null;
65 if( matching != null )
66 {
67 // build a class namer
68 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() );
69 sourceNamer = namer.getSourceNamer();
70 destNamer = namer.getDestNamer();
71
72 // note the number of matches
73 numMatches = matching.getUniqueMatches().size();
74 }
75
76 // get the entries left to match
77 Set<ClassEntry> sourceClassEntries = sourceIndex.getObfClassEntries();
78 Set<ClassEntry> destClassEntries = destIndex.getObfClassEntries();
79 if( matching != null )
80 {
81 sourceClassEntries.clear();
82 destClassEntries.clear();
83 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() )
84 {
85 for( ClassIdentity c : entry.getKey() )
86 {
87 sourceClassEntries.add( c.getClassEntry() );
88 matching.removeSource( c );
89 }
90 for( ClassIdentity c : entry.getValue() )
91 {
92 destClassEntries.add( c.getClassEntry() );
93 matching.removeDest( c );
94 }
95 }
96 for( ClassIdentity c : matching.getUnmatchedSourceClasses() )
97 {
98 sourceClassEntries.add( c.getClassEntry() );
99 matching.removeSource( c );
100 }
101 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
102 {
103 destClassEntries.add( c.getClassEntry() );
104 matching.removeDest( c );
105 }
106 }
107 else
108 {
109 matching = new ClassMatching();
110 }
111
112 // compute a matching for the classes
113 for( ClassEntry classEntry : sourceClassEntries )
114 {
115 CtClass c = sourceLoader.loadClass( classEntry.getName() );
116 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences );
117 matching.addSource( sourceClass );
118 }
119 for( ClassEntry classEntry : destClassEntries )
120 {
121 CtClass c = destLoader.loadClass( classEntry.getName() );
122 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences );
123 matching.matchDestClass( destClass );
124 }
125
126 // TEMP
127 System.out.println( matching );
85 } 128 }
129 while( matching.getUniqueMatches().size() - numMatches > 0 );
86 } 130 }
87 131
88 // get unmatched source classes 132 /* DEBUG: show some ambiguous matches
89 m_unmatchedSourceClasses = Lists.newArrayList(); 133 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( matching.getAmbiguousMatches().entrySet() );
90 for( ClassIdentity sourceClass : m_sourceClasses.keySet() ) 134 Collections.sort( ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( )
91 { 135 {
92 Collection<ClassIdentity> matchedSourceClasses = m_sourceClasses.get( sourceClass ); 136 @Override
93 Collection<ClassIdentity> matchedDestClasses = m_destClasses.get( sourceClass ); 137 public int compare( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b )
94 if( matchedDestClasses.isEmpty() )
95 { 138 {
96 m_unmatchedSourceClasses.add( sourceClass ); 139 String aName = a.getKey().get( 0 ).getClassEntry().getName();
140 String bName = b.getKey().get( 0 ).getClassEntry().getName();
141 return aName.compareTo( bName );
97 } 142 }
98 else if( matchedDestClasses.size() > 1 ) 143 } );
144 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches )
145 {
146 for( ClassIdentity c : entry.getKey() )
99 { 147 {
100 // warn about identity collisions 148 System.out.print( c.getClassEntry().getName() + " " );
101 System.err.println( String.format( "WARNING: identity collision:\n\tSource: %s\n\t Dest: %s",
102 getClassEntries( matchedSourceClasses ),
103 getClassEntries( matchedDestClasses )
104 ) );
105 } 149 }
150 System.out.println();
151 }
152 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 );
153 for( ClassIdentity c : entry.getKey() )
154 {
155 System.out.println( c );
106 } 156 }
157 for( ClassIdentity c : entry.getKey() )
158 {
159 System.out.println( decompile( sourceLoader, c.getClassEntry() ) );
160 }
161 */
162
163 return matching;
107 } 164 }
108 165
109 public Map.Entry<Collection<ClassEntry>,Collection<ClassEntry>> getMapping( ClassEntry sourceEntry ) 166 /* DEBUG
167 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry )
110 { 168 {
111 // TODO 169 PlainTextOutput output = new PlainTextOutput();
112 return null; 170 DecompilerSettings settings = DecompilerSettings.javaDefaults();
113 } 171 settings.setForceExplicitImports( true );
114 172 settings.setShowSyntheticMembers( true );
115 private Collection<ClassEntry> getClassEntries( Collection<ClassIdentity> classes ) 173 settings.setTypeLoader( loader );
116 { 174 Decompiler.decompile( classEntry.getName(), output, settings );
117 List<ClassEntry> entries = Lists.newArrayList(); 175 return output.toString();
118 for( ClassIdentity c : classes )
119 {
120 entries.add( c.getClassEntry() );
121 }
122 return entries;
123 } 176 }
177 */
124} 178}