summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassMapper.java
diff options
context:
space:
mode:
authorGravatar jeff2014-08-30 14:14:54 -0400
committerGravatar jeff2014-08-30 14:14:54 -0400
commit63172120a39a315e29bc38ea6634741797b3dcab (patch)
tree9030b8678aaca06982ae4d1032298f52ab833e09 /src/cuchaz/enigma/convert/ClassMapper.java
parentgot a decent class matcher working (diff)
downloadenigma-fork-63172120a39a315e29bc38ea6634741797b3dcab.tar.gz
enigma-fork-63172120a39a315e29bc38ea6634741797b3dcab.tar.xz
enigma-fork-63172120a39a315e29bc38ea6634741797b3dcab.zip
finished class matching for now, need to work on class member matching
Diffstat (limited to 'src/cuchaz/enigma/convert/ClassMapper.java')
-rw-r--r--src/cuchaz/enigma/convert/ClassMapper.java229
1 files changed, 174 insertions, 55 deletions
diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java
index fe48c50..fd6ab92 100644
--- a/src/cuchaz/enigma/convert/ClassMapper.java
+++ b/src/cuchaz/enigma/convert/ClassMapper.java
@@ -11,32 +11,130 @@
11package cuchaz.enigma.convert; 11package cuchaz.enigma.convert;
12 12
13import java.io.File; 13import java.io.File;
14import java.io.FileReader;
15import java.io.FileWriter;
14import java.io.IOException; 16import java.io.IOException;
15import java.util.Arrays; 17import java.util.Arrays;
18import java.util.Collections;
19import java.util.Iterator;
16import java.util.List; 20import java.util.List;
17import java.util.Map; 21import java.util.Map;
18import java.util.Set; 22import java.util.Set;
23import java.util.TreeMap;
19import java.util.jar.JarFile; 24import java.util.jar.JarFile;
20 25
21import javassist.CtClass; 26import javassist.CtClass;
27
28import com.beust.jcommander.internal.Sets;
29import com.google.common.collect.Maps;
30
31import cuchaz.enigma.Constants;
22import cuchaz.enigma.TranslatingTypeLoader; 32import cuchaz.enigma.TranslatingTypeLoader;
23import cuchaz.enigma.analysis.JarIndex; 33import cuchaz.enigma.analysis.JarIndex;
24import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 34import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
25import cuchaz.enigma.mapping.ClassEntry; 35import cuchaz.enigma.mapping.ClassEntry;
36import cuchaz.enigma.mapping.ClassMapping;
37import cuchaz.enigma.mapping.MappingParseException;
38import cuchaz.enigma.mapping.Mappings;
39import cuchaz.enigma.mapping.MappingsReader;
40import cuchaz.enigma.mapping.MappingsWriter;
26 41
27public class ClassMapper 42public class ClassMapper
28{ 43{
29 public static void main( String[] args ) 44 public static void main( String[] args )
30 throws IOException 45 throws IOException, MappingParseException
31 { 46 {
32 // TEMP 47 // TEMP
33 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); 48 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) );
34 JarFile toJar = new JarFile( new File( "input/1.8-pre2.jar" ) ); 49 JarFile toJar = new JarFile( new File( "input/1.8-pre3.jar" ) );
50 File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" );
51 File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" );
35 52
36 // compute the matching 53 // compute the matching
37 ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar ); 54 ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar );
38 55
39 // TODO: use the matching to convert the mappings 56 // use the matching to convert the mappings
57 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) );
58 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap();
59 Map<String,String> finalConversion = Maps.newHashMap();
60 Set<String> unmatchedSourceClasses = Sets.newHashSet();
61 for( ClassMapping classMapping : mappings.classes() )
62 {
63 // is there a match for this class?
64 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( classMapping.getObfName() );
65 ClassIdentity sourceClass = entry.getKey();
66 List<ClassIdentity> matches = entry.getValue();
67
68 if( matches.isEmpty() )
69 {
70 // no match! =(
71 System.out.println( "No exact match for source class " + classMapping.getObfName() );
72
73 // find the closest classes
74 TreeMap<Integer,ClassIdentity> scoredMatches = Maps.newTreeMap( Collections.reverseOrder() );
75 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
76 {
77 scoredMatches.put( sourceClass.getMatchScore( c ), c );
78 }
79 Iterator<Map.Entry<Integer,ClassIdentity>> iter = scoredMatches.entrySet().iterator();
80 for( int i=0; i<10 && iter.hasNext(); i++ )
81 {
82 Map.Entry<Integer,ClassIdentity> score = iter.next();
83 System.out.println( String.format( "\tScore: %3d %s", score.getKey(), score.getValue().getClassEntry().getName() ) );
84 }
85
86 // does the best match have a non-zero score and the same name?
87 Map.Entry<Integer,ClassIdentity> bestMatch = scoredMatches.firstEntry();
88 if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) )
89 {
90 // use it
91 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() );
92 addFinalConversion( finalConversion, sourceClass, bestMatch.getValue() );
93 }
94 else
95 {
96 unmatchedSourceClasses.add( classMapping.getObfName() );
97 }
98 }
99 if( matches.size() == 1 )
100 {
101 // unique match! We're good to go!
102 addFinalConversion( finalConversion, sourceClass, matches.get( 0 ) );
103 }
104 else if( matches.size() > 1 )
105 {
106 // too many matches! =(
107 unmatchedSourceClasses.add( classMapping.getObfName() );
108 }
109 }
110
111 // remove (and warn about) unmatched classes
112 if( !unmatchedSourceClasses.isEmpty() )
113 {
114 System.err.println( "WARNING: there were unmatched classes!" );
115 for( String className : unmatchedSourceClasses )
116 {
117 System.err.println( "\t" + className );
118 mappings.removeClassByObfName( className );
119 }
120 System.err.println( "Mappings for these classes have been removed." );
121 }
122
123 // show the class name changes
124 for( Map.Entry<String,String> entry : finalConversion.entrySet() )
125 {
126 if( !entry.getKey().equals( entry.getValue() ) )
127 {
128 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) );
129 }
130 }
131
132 // do the final conversion
133 mappings.renameObfClasses( finalConversion );
134 FileWriter writer = new FileWriter( outMappingsFile );
135 new MappingsWriter().write( writer, mappings );
136 writer.close();
137 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() );
40 } 138 }
41 139
42 public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar ) 140 public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar )
@@ -55,78 +153,81 @@ public class ClassMapper
55 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex ); 153 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex );
56 154
57 ClassMatching matching = null; 155 ClassMatching matching = null;
58 for( boolean useReferences : Arrays.asList( false, true ) ) 156 for( boolean useRawNames : Arrays.asList( false, true ) )
59 { 157 {
60 int numMatches = 0; 158 for( boolean useReferences : Arrays.asList( false, true ) )
61 do
62 { 159 {
63 SidedClassNamer sourceNamer = null; 160 int numMatches = 0;
64 SidedClassNamer destNamer = null; 161 do
65 if( matching != null )
66 { 162 {
67 // build a class namer 163 SidedClassNamer sourceNamer = null;
68 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() ); 164 SidedClassNamer destNamer = null;
69 sourceNamer = namer.getSourceNamer(); 165 if( matching != null )
70 destNamer = namer.getDestNamer(); 166 {
167 // build a class namer
168 ClassNamer namer = new ClassNamer( matching.getUniqueMatches() );
169 sourceNamer = namer.getSourceNamer();
170 destNamer = namer.getDestNamer();
171
172 // note the number of matches
173 numMatches = matching.getUniqueMatches().size();
174 }
71 175
72 // note the number of matches 176 // get the entries left to match
73 numMatches = matching.getUniqueMatches().size(); 177 Set<ClassEntry> sourceClassEntries = sourceIndex.getObfClassEntries();
74 } 178 Set<ClassEntry> destClassEntries = destIndex.getObfClassEntries();
75 179 if( matching != null )
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 { 180 {
85 for( ClassIdentity c : entry.getKey() ) 181 sourceClassEntries.clear();
182 destClassEntries.clear();
183 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : matching.getAmbiguousMatches().entrySet() )
184 {
185 for( ClassIdentity c : entry.getKey() )
186 {
187 sourceClassEntries.add( c.getClassEntry() );
188 matching.removeSource( c );
189 }
190 for( ClassIdentity c : entry.getValue() )
191 {
192 destClassEntries.add( c.getClassEntry() );
193 matching.removeDest( c );
194 }
195 }
196 for( ClassIdentity c : matching.getUnmatchedSourceClasses() )
86 { 197 {
87 sourceClassEntries.add( c.getClassEntry() ); 198 sourceClassEntries.add( c.getClassEntry() );
88 matching.removeSource( c ); 199 matching.removeSource( c );
89 } 200 }
90 for( ClassIdentity c : entry.getValue() ) 201 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
91 { 202 {
92 destClassEntries.add( c.getClassEntry() ); 203 destClassEntries.add( c.getClassEntry() );
93 matching.removeDest( c ); 204 matching.removeDest( c );
94 } 205 }
95 } 206 }
96 for( ClassIdentity c : matching.getUnmatchedSourceClasses() ) 207 else
97 { 208 {
98 sourceClassEntries.add( c.getClassEntry() ); 209 matching = new ClassMatching();
99 matching.removeSource( c );
100 } 210 }
101 for( ClassIdentity c : matching.getUnmatchedDestClasses() ) 211
212 // compute a matching for the classes
213 for( ClassEntry classEntry : sourceClassEntries )
102 { 214 {
103 destClassEntries.add( c.getClassEntry() ); 215 CtClass c = sourceLoader.loadClass( classEntry.getName() );
104 matching.removeDest( c ); 216 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames );
217 matching.addSource( sourceClass );
105 } 218 }
219 for( ClassEntry classEntry : destClassEntries )
220 {
221 CtClass c = destLoader.loadClass( classEntry.getName() );
222 ClassIdentity destClass = new ClassIdentity( c, destNamer, destIndex, useReferences, useRawNames );
223 matching.matchDestClass( destClass );
224 }
225
226 // TEMP
227 System.out.println( matching );
106 } 228 }
107 else 229 while( matching.getUniqueMatches().size() - numMatches > 0 );
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 );
128 } 230 }
129 while( matching.getUniqueMatches().size() - numMatches > 0 );
130 } 231 }
131 232
132 /* DEBUG: show some ambiguous matches 233 /* DEBUG: show some ambiguous matches
@@ -163,6 +264,24 @@ public class ClassMapper
163 return matching; 264 return matching;
164 } 265 }
165 266
267 private static void addFinalConversion( Map<String,String> finalConversion, ClassIdentity sourceClass, ClassIdentity destClass )
268 {
269 // flatten inner classes since these are all obf classes in the none package
270 String sourceClassName = sourceClass.getClassEntry().getName();
271 if( sourceClass.getClassEntry().isInnerClass() )
272 {
273 sourceClassName = Constants.NonePackage + "/" + sourceClass.getClassEntry().getInnerClassName();
274 }
275
276 String destClassName = destClass.getClassEntry().getName();
277 if( destClass.getClassEntry().isInnerClass() )
278 {
279 destClassName = Constants.NonePackage + "/" + destClass.getClassEntry().getInnerClassName();
280 }
281
282 finalConversion.put( sourceClassName, destClassName );
283 }
284
166 /* DEBUG 285 /* DEBUG
167 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry ) 286 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry )
168 { 287 {