summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java2
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java57
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java40
-rw-r--r--src/cuchaz/enigma/convert/ClassMatcher.java (renamed from src/cuchaz/enigma/convert/ClassMapper.java)265
-rw-r--r--src/cuchaz/enigma/convert/ClassMatching.java2
-rw-r--r--src/cuchaz/enigma/mapping/Mappings.java7
6 files changed, 246 insertions, 127 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index cc1465a..9a78f38 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -70,7 +70,7 @@ public class Deobfuscator
70 70
71 // build the jar index 71 // build the jar index
72 m_jarIndex = new JarIndex(); 72 m_jarIndex = new JarIndex();
73 m_jarIndex.indexJar( m_jar ); 73 m_jarIndex.indexJar( m_jar, true );
74 74
75 // config the decompiler 75 // config the decompiler
76 m_settings = DecompilerSettings.javaDefaults(); 76 m_settings = DecompilerSettings.javaDefaults();
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index b479b69..4279ded 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -79,7 +79,7 @@ public class JarIndex
79 m_bridgeMethods = Maps.newHashMap(); 79 m_bridgeMethods = Maps.newHashMap();
80 } 80 }
81 81
82 public void indexJar( JarFile jar ) 82 public void indexJar( JarFile jar, boolean buildInnerClasses )
83 { 83 {
84 // step 1: read the class names 84 // step 1: read the class names
85 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) ) 85 for( ClassEntry classEntry : JarClassIterator.getClassEntries( jar ) )
@@ -125,40 +125,43 @@ public class JarIndex
125 } 125 }
126 } 126 }
127 127
128 // step 4: index inner classes and anonymous classes 128 if( buildInnerClasses )
129 for( CtClass c : JarClassIterator.classes( jar ) )
130 { 129 {
131 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage ); 130 // step 4: index inner classes and anonymous classes
132 String outerClassName = findOuterClass( c ); 131 for( CtClass c : JarClassIterator.classes( jar ) )
133 if( outerClassName != null )
134 { 132 {
135 String innerClassName = Descriptor.toJvmName( c.getName() ); 133 ClassRenamer.moveAllClassesOutOfDefaultPackage( c, Constants.NonePackage );
136 m_innerClasses.put( outerClassName, innerClassName ); 134 String outerClassName = findOuterClass( c );
137 m_outerClasses.put( innerClassName, outerClassName ); 135 if( outerClassName != null )
138
139 if( isAnonymousClass( c, outerClassName ) )
140 { 136 {
141 m_anonymousClasses.add( innerClassName ); 137 String innerClassName = Descriptor.toJvmName( c.getName() );
138 m_innerClasses.put( outerClassName, innerClassName );
139 m_outerClasses.put( innerClassName, outerClassName );
142 140
143 // DEBUG 141 if( isAnonymousClass( c, outerClassName ) )
144 //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName ); 142 {
145 } 143 m_anonymousClasses.add( innerClassName );
146 else 144
147 { 145 // DEBUG
148 // DEBUG 146 //System.out.println( "ANONYMOUS: " + outerClassName + "$" + innerClassName );
149 //System.out.println( "INNER: " + outerClassName + "$" + innerClassName ); 147 }
148 else
149 {
150 // DEBUG
151 //System.out.println( "INNER: " + outerClassName + "$" + innerClassName );
152 }
150 } 153 }
151 } 154 }
155
156 // step 5: update other indices with inner class info
157 Map<String,String> renames = Maps.newHashMap();
158 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() )
159 {
160 renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() );
161 }
162 renameClasses( renames );
152 } 163 }
153 164
154 // step 5: update other indices with inner class info
155 Map<String,String> renames = Maps.newHashMap();
156 for( Map.Entry<String,String> entry : m_outerClasses.entrySet() )
157 {
158 renames.put( entry.getKey(), entry.getValue() + "$" + new ClassEntry( entry.getKey() ).getSimpleName() );
159 }
160 renameClasses( renames );
161
162 // step 5: update other indices with bridge method info 165 // step 5: update other indices with bridge method info
163 renameMethods( m_bridgeMethods ); 166 renameMethods( m_bridgeMethods );
164 } 167 }
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java
index 980f31f..8de7128 100644
--- a/src/cuchaz/enigma/convert/ClassIdentity.java
+++ b/src/cuchaz/enigma/convert/ClassIdentity.java
@@ -16,7 +16,6 @@ import java.security.NoSuchAlgorithmException;
16import java.util.Enumeration; 16import java.util.Enumeration;
17import java.util.List; 17import java.util.List;
18import java.util.Map; 18import java.util.Map;
19import java.util.Set;
20 19
21import javassist.CannotCompileException; 20import javassist.CannotCompileException;
22import javassist.CtBehavior; 21import javassist.CtBehavior;
@@ -36,8 +35,9 @@ import javassist.expr.MethodCall;
36import javassist.expr.NewExpr; 35import javassist.expr.NewExpr;
37 36
38import com.beust.jcommander.internal.Maps; 37import com.beust.jcommander.internal.Maps;
39import com.beust.jcommander.internal.Sets; 38import com.google.common.collect.HashMultiset;
40import com.google.common.collect.Lists; 39import com.google.common.collect.Lists;
40import com.google.common.collect.Multiset;
41 41
42import cuchaz.enigma.Constants; 42import cuchaz.enigma.Constants;
43import cuchaz.enigma.Util; 43import cuchaz.enigma.Util;
@@ -62,14 +62,14 @@ public class ClassIdentity
62 private ClassEntry m_classEntry; 62 private ClassEntry m_classEntry;
63 private String m_rawName; 63 private String m_rawName;
64 private SidedClassNamer m_namer; 64 private SidedClassNamer m_namer;
65 private Set<String> m_fields; 65 private Multiset<String> m_fields;
66 private Set<String> m_methods; 66 private Multiset<String> m_methods;
67 private Set<String> m_constructors; 67 private Multiset<String> m_constructors;
68 private String m_staticInitializer; 68 private String m_staticInitializer;
69 private String m_extends; 69 private String m_extends;
70 private Set<String> m_implements; 70 private Multiset<String> m_implements;
71 private Set<String> m_implementations; 71 private Multiset<String> m_implementations;
72 private Set<String> m_references; 72 private Multiset<String> m_references;
73 73
74 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames ) 74 public ClassIdentity( CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences, boolean useRawNames )
75 { 75 {
@@ -83,17 +83,17 @@ public class ClassIdentity
83 { 83 {
84 m_rawName = m_classEntry.getName(); 84 m_rawName = m_classEntry.getName();
85 } 85 }
86 m_fields = Sets.newHashSet(); 86 m_fields = HashMultiset.create();
87 for( CtField field : c.getDeclaredFields() ) 87 for( CtField field : c.getDeclaredFields() )
88 { 88 {
89 m_fields.add( scrubSignature( field.getSignature() ) ); 89 m_fields.add( scrubSignature( field.getSignature() ) );
90 } 90 }
91 m_methods = Sets.newHashSet(); 91 m_methods = HashMultiset.create();
92 for( CtMethod method : c.getDeclaredMethods() ) 92 for( CtMethod method : c.getDeclaredMethods() )
93 { 93 {
94 m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) ); 94 m_methods.add( scrubSignature( method.getSignature() ) + "0x" + getBehaviorSignature( method ) );
95 } 95 }
96 m_constructors = Sets.newHashSet(); 96 m_constructors = HashMultiset.create();
97 for( CtConstructor constructor : c.getDeclaredConstructors() ) 97 for( CtConstructor constructor : c.getDeclaredConstructors() )
98 { 98 {
99 m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) ); 99 m_constructors.add( scrubSignature( constructor.getSignature() ) + "0x" + getBehaviorSignature( constructor ) );
@@ -108,7 +108,7 @@ public class ClassIdentity
108 { 108 {
109 m_extends = scrubClassName( c.getClassFile().getSuperclass() ); 109 m_extends = scrubClassName( c.getClassFile().getSuperclass() );
110 } 110 }
111 m_implements = Sets.newHashSet(); 111 m_implements = HashMultiset.create();
112 for( String interfaceName : c.getClassFile().getInterfaces() ) 112 for( String interfaceName : c.getClassFile().getInterfaces() )
113 { 113 {
114 m_implements.add( scrubClassName( interfaceName ) ); 114 m_implements.add( scrubClassName( interfaceName ) );
@@ -116,7 +116,7 @@ public class ClassIdentity
116 116
117 // stuff from the jar index 117 // stuff from the jar index
118 118
119 m_implementations = Sets.newHashSet(); 119 m_implementations = HashMultiset.create();
120 @SuppressWarnings( "unchecked" ) 120 @SuppressWarnings( "unchecked" )
121 Enumeration<ClassImplementationsTreeNode> implementations = index.getClassImplementations( null, m_classEntry ).children(); 121 Enumeration<ClassImplementationsTreeNode> implementations = index.getClassImplementations( null, m_classEntry ).children();
122 while( implementations.hasMoreElements() ) 122 while( implementations.hasMoreElements() )
@@ -125,7 +125,7 @@ public class ClassIdentity
125 m_implementations.add( scrubClassName( node.getClassEntry().getName() ) ); 125 m_implementations.add( scrubClassName( node.getClassEntry().getName() ) );
126 } 126 }
127 127
128 m_references = Sets.newHashSet(); 128 m_references = HashMultiset.create();
129 if( useReferences ) 129 if( useReferences )
130 { 130 {
131 for( CtField field : c.getDeclaredFields() ) 131 for( CtField field : c.getDeclaredFields() )
@@ -154,7 +154,7 @@ public class ClassIdentity
154 } 154 }
155 } 155 }
156 } 156 }
157 157
158 private void addReference( EntryReference<? extends Entry,BehaviorEntry> reference ) 158 private void addReference( EntryReference<? extends Entry,BehaviorEntry> reference )
159 { 159 {
160 if( reference.context.getSignature() != null ) 160 if( reference.context.getSignature() != null )
@@ -473,7 +473,15 @@ public class ClassIdentity
473 + getNumMatches( m_constructors, other.m_constructors ); 473 + getNumMatches( m_constructors, other.m_constructors );
474 } 474 }
475 475
476 private int getNumMatches( Set<String> a, Set<String> b ) 476 public boolean matches( CtClass c )
477 {
478 // just compare declaration counts
479 return m_fields.size() == c.getDeclaredFields().length
480 && m_methods.size() == c.getDeclaredMethods().length
481 && m_constructors.size() == c.getDeclaredConstructors().length;
482 }
483
484 private int getNumMatches( Multiset<String> a, Multiset<String> b )
477 { 485 {
478 int numMatches = 0; 486 int numMatches = 0;
479 for( String val : a ) 487 for( String val : a )
diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMatcher.java
index fd6ab92..ac07a5b 100644
--- a/src/cuchaz/enigma/convert/ClassMapper.java
+++ b/src/cuchaz/enigma/convert/ClassMatcher.java
@@ -14,8 +14,12 @@ 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.Arrays; 19import java.util.Arrays;
20import java.util.Collection;
18import java.util.Collections; 21import java.util.Collections;
22import java.util.Comparator;
19import java.util.Iterator; 23import java.util.Iterator;
20import java.util.List; 24import java.util.List;
21import java.util.Map; 25import java.util.Map;
@@ -23,12 +27,15 @@ import java.util.Set;
23import java.util.TreeMap; 27import java.util.TreeMap;
24import java.util.jar.JarFile; 28import java.util.jar.JarFile;
25 29
30import javassist.CtBehavior;
26import javassist.CtClass; 31import javassist.CtClass;
27 32
33import com.beust.jcommander.internal.Lists;
28import com.beust.jcommander.internal.Sets; 34import com.beust.jcommander.internal.Sets;
35import com.google.common.collect.BiMap;
36import com.google.common.collect.HashBiMap;
29import com.google.common.collect.Maps; 37import com.google.common.collect.Maps;
30 38
31import cuchaz.enigma.Constants;
32import cuchaz.enigma.TranslatingTypeLoader; 39import cuchaz.enigma.TranslatingTypeLoader;
33import cuchaz.enigma.analysis.JarIndex; 40import cuchaz.enigma.analysis.JarIndex;
34import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 41import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
@@ -38,73 +45,107 @@ import cuchaz.enigma.mapping.MappingParseException;
38import cuchaz.enigma.mapping.Mappings; 45import cuchaz.enigma.mapping.Mappings;
39import cuchaz.enigma.mapping.MappingsReader; 46import cuchaz.enigma.mapping.MappingsReader;
40import cuchaz.enigma.mapping.MappingsWriter; 47import cuchaz.enigma.mapping.MappingsWriter;
48import cuchaz.enigma.mapping.MethodEntry;
49import cuchaz.enigma.mapping.MethodMapping;
41 50
42public class ClassMapper 51public class ClassMatcher
43{ 52{
44 public static void main( String[] args ) 53 public static void main( String[] args )
45 throws IOException, MappingParseException 54 throws IOException, MappingParseException
46 { 55 {
47 // TEMP 56 // TEMP
48 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.jar" ) ); 57 JarFile sourceJar = new JarFile( new File( "input/1.8-pre1.jar" ) );
49 JarFile toJar = new JarFile( new File( "input/1.8-pre3.jar" ) ); 58 JarFile destJar = new JarFile( new File( "input/1.8-pre2.jar" ) );
50 File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" ); 59 File inMappingsFile = new File( "../minecraft-mappings/1.8-pre.mappings" );
51 File outMappingsFile = new File( "../minecraft-mappings/1.8-pre3.mappings" ); 60 File outMappingsFile = new File( "../minecraft-mappings/1.8-pre2.mappings" );
52 61
62 // do the conversion
63 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) );
64 convertMappings( sourceJar, destJar, mappings );
65
66 // write out the convert mappings
67 FileWriter writer = new FileWriter( outMappingsFile );
68 new MappingsWriter().write( writer, mappings );
69 writer.close();
70 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() );
71 }
72
73 private static void convertMappings( JarFile sourceJar, JarFile destJar, Mappings mappings )
74 {
75 // index jars
76 System.out.println( "Indexing source jar..." );
77 JarIndex sourceIndex = new JarIndex();
78 sourceIndex.indexJar( sourceJar, false );
79 System.out.println( "Indexing dest jar..." );
80 JarIndex destIndex = new JarIndex();
81 destIndex.indexJar( destJar, false );
82 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex );
83 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex );
84
53 // compute the matching 85 // compute the matching
54 ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar ); 86 ClassMatching matching = ClassMatcher.computeMatching( sourceIndex, sourceLoader, destIndex, destLoader );
55 87
56 // use the matching to convert the mappings 88 // start the class conversion map with the unique and ambiguous matchings
57 Mappings mappings = new MappingsReader().read( new FileReader( inMappingsFile ) );
58 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap(); 89 Map<String,Map.Entry<ClassIdentity,List<ClassIdentity>>> conversionMap = matching.getConversionMap();
59 Map<String,String> finalConversion = Maps.newHashMap(); 90
91 // probabilistically match the unmatched source classes
92 for( ClassIdentity sourceClass : new ArrayList<ClassIdentity>( matching.getUnmatchedSourceClasses() ) )
93 {
94 System.out.println( "No exact match for source class " + sourceClass.getClassEntry() );
95
96 // find the closest classes
97 TreeMap<Integer,ClassIdentity> scoredMatches = Maps.newTreeMap( Collections.reverseOrder() );
98 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
99 {
100 scoredMatches.put( sourceClass.getMatchScore( c ), c );
101 }
102 Iterator<Map.Entry<Integer,ClassIdentity>> iter = scoredMatches.entrySet().iterator();
103 for( int i=0; i<10 && iter.hasNext(); i++ )
104 {
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
109 // does the best match have a non-zero score and the same name?
110 Map.Entry<Integer,ClassIdentity> bestMatch = scoredMatches.firstEntry();
111 if( bestMatch.getKey() > 0 && bestMatch.getValue().getClassEntry().equals( sourceClass.getClassEntry() ) )
112 {
113 // use it
114 System.out.println( "\tAutomatically choosing likely match: " + bestMatch.getValue().getClassEntry().getName() );
115 conversionMap.put(
116 sourceClass.getClassEntry().getName(),
117 new AbstractMap.SimpleEntry<ClassIdentity,List<ClassIdentity>>( sourceClass, Arrays.asList( bestMatch.getValue() ) )
118 );
119 }
120 }
121
122 // use the matching to convert the mappings
123 BiMap<String,String> classConversion = HashBiMap.create();
60 Set<String> unmatchedSourceClasses = Sets.newHashSet(); 124 Set<String> unmatchedSourceClasses = Sets.newHashSet();
61 for( ClassMapping classMapping : mappings.classes() ) 125 for( String className : mappings.getAllObfClassNames() )
62 { 126 {
63 // is there a match for this class? 127 // is there a match for this class?
64 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( classMapping.getObfName() ); 128 Map.Entry<ClassIdentity,List<ClassIdentity>> entry = conversionMap.get( className );
65 ClassIdentity sourceClass = entry.getKey(); 129 ClassIdentity sourceClass = entry.getKey();
66 List<ClassIdentity> matches = entry.getValue(); 130 List<ClassIdentity> matches = entry.getValue();
67 131
68 if( matches.isEmpty() ) 132 if( matches.isEmpty() )
69 { 133 {
70 // no match! =( 134 // no match! =(
71 System.out.println( "No exact match for source class " + classMapping.getObfName() ); 135 unmatchedSourceClasses.add( className );
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 } 136 }
99 if( matches.size() == 1 ) 137 else if( matches.size() == 1 )
100 { 138 {
101 // unique match! We're good to go! 139 // unique match! We're good to go!
102 addFinalConversion( finalConversion, sourceClass, matches.get( 0 ) ); 140 classConversion.put(
141 sourceClass.getClassEntry().getName(),
142 matches.get( 0 ).getClassEntry().getName()
143 );
103 } 144 }
104 else if( matches.size() > 1 ) 145 else if( matches.size() > 1 )
105 { 146 {
106 // too many matches! =( 147 // too many matches! =(
107 unmatchedSourceClasses.add( classMapping.getObfName() ); 148 unmatchedSourceClasses.add( className );
108 } 149 }
109 } 150 }
110 151
@@ -121,39 +162,85 @@ public class ClassMapper
121 } 162 }
122 163
123 // show the class name changes 164 // show the class name changes
124 for( Map.Entry<String,String> entry : finalConversion.entrySet() ) 165 for( Map.Entry<String,String> entry : classConversion.entrySet() )
125 { 166 {
126 if( !entry.getKey().equals( entry.getValue() ) ) 167 if( !entry.getKey().equals( entry.getValue() ) )
127 { 168 {
128 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) ); 169 System.out.println( String.format( "Class change: %s -> %s", entry.getKey(), entry.getValue() ) );
170 /* DEBUG
171 System.out.println( String.format( "\n%s\n%s",
172 new ClassIdentity( sourceLoader.loadClass( entry.getKey() ), null, sourceIndex, false, false ),
173 new ClassIdentity( destLoader.loadClass( entry.getValue() ), null, destIndex, false, false )
174 ) );
175 */
129 } 176 }
130 } 177 }
131 178
132 // do the final conversion 179 // TEMP: show some classes
133 mappings.renameObfClasses( finalConversion ); 180 for( String className : Arrays.asList( "none/em", "none/ej", "none/en" ) )
134 FileWriter writer = new FileWriter( outMappingsFile ); 181 {
135 new MappingsWriter().write( writer, mappings ); 182 System.out.println( String.format( "check: %s -> %s", className, classConversion.get( className ) ) );
136 writer.close(); 183 }
137 System.out.println( "Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath() ); 184
185 // convert the classes
186 mappings.renameObfClasses( classConversion );
187
188 // look for method matches
189 System.out.println( "Matching methods..." );
190 for( ClassMapping classMapping : mappings.classes() )
191 {
192 ClassEntry classEntry = new ClassEntry( classMapping.getObfName() );
193 for( MethodMapping methodMapping : classMapping.methods() )
194 {
195 // skip constructors
196 if( methodMapping.getObfName().equals( "<init>" ) )
197 {
198 continue;
199 }
200
201 MethodEntry methodEntry = new MethodEntry(
202 classEntry,
203 methodMapping.getObfName(),
204 methodMapping.getObfSignature()
205 );
206 if( !destIndex.isMethodImplemented( methodEntry ) )
207 {
208 System.err.println( "WARNING: method doesn't match: " + methodEntry );
209
210 // show the available methods
211 System.err.println( "\tAvailable dest methods:" );
212 CtClass c = destLoader.loadClass( classMapping.getObfName() );
213 for( CtBehavior behavior : c.getDeclaredBehaviors() )
214 {
215 MethodEntry declaredMethodEntry = new MethodEntry(
216 new ClassEntry( classMapping.getObfName() ),
217 behavior.getName(),
218 behavior.getSignature()
219 );
220 System.err.println( "\t\t" + declaredMethodEntry );
221 }
222
223 System.err.println( "\tAvailable source methods:" );
224 c = sourceLoader.loadClass( classConversion.inverse().get( classMapping.getObfName() ) );
225 for( CtBehavior behavior : c.getDeclaredBehaviors() )
226 {
227 MethodEntry declaredMethodEntry = new MethodEntry(
228 new ClassEntry( classMapping.getObfName() ),
229 behavior.getName(),
230 behavior.getSignature()
231 );
232 System.err.println( "\t\t" + declaredMethodEntry );
233 }
234 }
235 }
236 }
138 } 237 }
139 238
140 public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar ) 239 public static ClassMatching computeMatching( JarIndex sourceIndex, TranslatingTypeLoader sourceLoader, JarIndex destIndex, TranslatingTypeLoader destLoader )
141 { 240 {
142 // index jars 241 System.out.println( "Matching classes..." );
143 System.out.println( "Indexing source jar..." );
144 JarIndex sourceIndex = new JarIndex();
145 sourceIndex.indexJar( sourceJar );
146 System.out.println( "Indexing dest jar..." );
147 JarIndex destIndex = new JarIndex();
148 destIndex.indexJar( destJar );
149
150 System.out.println( "Computing matching..." );
151
152 TranslatingTypeLoader sourceLoader = new TranslatingTypeLoader( sourceJar, sourceIndex );
153 TranslatingTypeLoader destLoader = new TranslatingTypeLoader( destJar, destIndex );
154
155 ClassMatching matching = null; 242 ClassMatching matching = null;
156 for( boolean useRawNames : Arrays.asList( false, true ) ) 243 for( boolean useRawNames : Arrays.asList( false/*, true*/ ) )
157 { 244 {
158 for( boolean useReferences : Arrays.asList( false, true ) ) 245 for( boolean useReferences : Arrays.asList( false, true ) )
159 { 246 {
@@ -230,7 +317,28 @@ public class ClassMapper
230 } 317 }
231 } 318 }
232 319
233 /* DEBUG: show some ambiguous matches 320 // DEBUG: check the class matches
321 System.out.println( "Checking class matches..." );
322 for( Map.Entry<ClassIdentity,ClassIdentity> entry : matching.getUniqueMatches().entrySet() )
323 {
324 // check source
325 ClassIdentity sourceClass = entry.getKey();
326 CtClass sourceC = sourceLoader.loadClass( sourceClass.getClassEntry().getName() );
327 assert( sourceC != null )
328 : "Unable to load source class " + sourceClass.getClassEntry();
329 assert( sourceClass.matches( sourceC ) )
330 : "Source " + sourceClass + " doesn't match " + new ClassIdentity( sourceC, null, sourceIndex, false, false );
331
332 // check dest
333 ClassIdentity destClass = entry.getValue();
334 CtClass destC = destLoader.loadClass( destClass.getClassEntry().getName() );
335 assert( destC != null )
336 : "Unable to load dest class " + destClass.getClassEntry();
337 assert( destClass.matches( destC ) )
338 : "Dest " + destClass + " doesn't match " + new ClassIdentity( destC, null, destIndex, false, false );
339 }
340
341 // warn about the ambiguous matchings
234 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( matching.getAmbiguousMatches().entrySet() ); 342 List<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>> ambiguousMatches = new ArrayList<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( matching.getAmbiguousMatches().entrySet() );
235 Collections.sort( ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( ) 343 Collections.sort( ambiguousMatches, new Comparator<Map.Entry<List<ClassIdentity>,List<ClassIdentity>>>( )
236 { 344 {
@@ -244,12 +352,12 @@ public class ClassMapper
244 } ); 352 } );
245 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches ) 353 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches )
246 { 354 {
247 for( ClassIdentity c : entry.getKey() ) 355 System.out.println( "Ambiguous matching:" );
248 { 356 System.out.println( "\tSource: " + getClassNames( entry.getKey() ) );
249 System.out.print( c.getClassEntry().getName() + " " ); 357 System.out.println( "\tDest: " + getClassNames( entry.getValue() ) );
250 }
251 System.out.println();
252 } 358 }
359
360 /* DEBUG
253 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 ); 361 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 );
254 for( ClassIdentity c : entry.getKey() ) 362 for( ClassIdentity c : entry.getKey() )
255 { 363 {
@@ -264,22 +372,15 @@ public class ClassMapper
264 return matching; 372 return matching;
265 } 373 }
266 374
267 private static void addFinalConversion( Map<String,String> finalConversion, ClassIdentity sourceClass, ClassIdentity destClass ) 375 private static List<String> getClassNames( Collection<ClassIdentity> classes )
268 { 376 {
269 // flatten inner classes since these are all obf classes in the none package 377 List<String> out = Lists.newArrayList();
270 String sourceClassName = sourceClass.getClassEntry().getName(); 378 for( ClassIdentity c : classes )
271 if( sourceClass.getClassEntry().isInnerClass() )
272 { 379 {
273 sourceClassName = Constants.NonePackage + "/" + sourceClass.getClassEntry().getInnerClassName(); 380 out.add( c.getClassEntry().getName() );
274 } 381 }
275 382 Collections.sort( out );
276 String destClassName = destClass.getClassEntry().getName(); 383 return out;
277 if( destClass.getClassEntry().isInnerClass() )
278 {
279 destClassName = Constants.NonePackage + "/" + destClass.getClassEntry().getInnerClassName();
280 }
281
282 finalConversion.put( sourceClassName, destClassName );
283 } 384 }
284 385
285 /* DEBUG 386 /* DEBUG
diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java
index 4e9fe39..ef5a7d8 100644
--- a/src/cuchaz/enigma/convert/ClassMatching.java
+++ b/src/cuchaz/enigma/convert/ClassMatching.java
@@ -96,7 +96,7 @@ public class ClassMatching
96 if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 ) 96 if( matchedSourceClasses.size() == 1 && matchedDestClasses.size() == 1 )
97 { 97 {
98 ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next(); 98 ClassIdentity matchedSourceClass = matchedSourceClasses.iterator().next();
99 ClassIdentity matchedDestClass = matchedSourceClasses.iterator().next(); 99 ClassIdentity matchedDestClass = matchedDestClasses.iterator().next();
100 uniqueMatches.put( matchedSourceClass, matchedDestClass ); 100 uniqueMatches.put( matchedSourceClass, matchedDestClass );
101 } 101 }
102 } 102 }
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
index 70bea25..c92f8de 100644
--- a/src/cuchaz/enigma/mapping/Mappings.java
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -15,6 +15,7 @@ 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;
18import java.util.Map; 19import java.util.Map;
19import java.util.zip.GZIPInputStream; 20import java.util.zip.GZIPInputStream;
20 21
@@ -161,4 +162,10 @@ public class Mappings implements Serializable
161 m_classesByDeobf.remove( classMapping.getDeobfName() ); 162 m_classesByDeobf.remove( classMapping.getDeobfName() );
162 } 163 }
163 } 164 }
165
166 public List<String> getAllObfClassNames( )
167 {
168 // TODO: implement this
169 return null;
170 }
164} 171}