summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/ClassMapper.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/convert/ClassMapper.java')
-rw-r--r--src/cuchaz/enigma/convert/ClassMapper.java297
1 files changed, 0 insertions, 297 deletions
diff --git a/src/cuchaz/enigma/convert/ClassMapper.java b/src/cuchaz/enigma/convert/ClassMapper.java
deleted file mode 100644
index fd6ab92..0000000
--- a/src/cuchaz/enigma/convert/ClassMapper.java
+++ /dev/null
@@ -1,297 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.convert;
12
13import java.io.File;
14import java.io.FileReader;
15import java.io.FileWriter;
16import java.io.IOException;
17import java.util.Arrays;
18import java.util.Collections;
19import java.util.Iterator;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
23import java.util.TreeMap;
24import java.util.jar.JarFile;
25
26import javassist.CtClass;
27
28import com.beust.jcommander.internal.Sets;
29import com.google.common.collect.Maps;
30
31import cuchaz.enigma.Constants;
32import cuchaz.enigma.TranslatingTypeLoader;
33import cuchaz.enigma.analysis.JarIndex;
34import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
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;
41
42public class ClassMapper
43{
44 public static void main( String[] args )
45 throws IOException, MappingParseException
46 {
47 // TEMP
48 JarFile fromJar = new JarFile( new File( "input/1.8-pre1.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" );
52
53 // compute the matching
54 ClassMatching matching = ClassMapper.computeMatching( fromJar, toJar );
55
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() );
138 }
139
140 public static ClassMatching computeMatching( JarFile sourceJar, JarFile destJar )
141 {
142 // index jars
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;
156 for( boolean useRawNames : Arrays.asList( false, true ) )
157 {
158 for( boolean useReferences : Arrays.asList( false, true ) )
159 {
160 int numMatches = 0;
161 do
162 {
163 SidedClassNamer sourceNamer = null;
164 SidedClassNamer destNamer = null;
165 if( matching != null )
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 }
175
176 // get the entries left to match
177 Set<ClassEntry> sourceClassEntries = sourceIndex.getObfClassEntries();
178 Set<ClassEntry> destClassEntries = destIndex.getObfClassEntries();
179 if( matching != null )
180 {
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() )
197 {
198 sourceClassEntries.add( c.getClassEntry() );
199 matching.removeSource( c );
200 }
201 for( ClassIdentity c : matching.getUnmatchedDestClasses() )
202 {
203 destClassEntries.add( c.getClassEntry() );
204 matching.removeDest( c );
205 }
206 }
207 else
208 {
209 matching = new ClassMatching();
210 }
211
212 // compute a matching for the classes
213 for( ClassEntry classEntry : sourceClassEntries )
214 {
215 CtClass c = sourceLoader.loadClass( classEntry.getName() );
216 ClassIdentity sourceClass = new ClassIdentity( c, sourceNamer, sourceIndex, useReferences, useRawNames );
217 matching.addSource( sourceClass );
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 );
228 }
229 while( matching.getUniqueMatches().size() - numMatches > 0 );
230 }
231 }
232
233 /* DEBUG: show some ambiguous matches
234 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>>>( )
236 {
237 @Override
238 public int compare( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> a, Map.Entry<List<ClassIdentity>,List<ClassIdentity>> b )
239 {
240 String aName = a.getKey().get( 0 ).getClassEntry().getName();
241 String bName = b.getKey().get( 0 ).getClassEntry().getName();
242 return aName.compareTo( bName );
243 }
244 } );
245 for( Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry : ambiguousMatches )
246 {
247 for( ClassIdentity c : entry.getKey() )
248 {
249 System.out.print( c.getClassEntry().getName() + " " );
250 }
251 System.out.println();
252 }
253 Map.Entry<List<ClassIdentity>,List<ClassIdentity>> entry = ambiguousMatches.get( 7 );
254 for( ClassIdentity c : entry.getKey() )
255 {
256 System.out.println( c );
257 }
258 for( ClassIdentity c : entry.getKey() )
259 {
260 System.out.println( decompile( sourceLoader, c.getClassEntry() ) );
261 }
262 */
263
264 return matching;
265 }
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
285 /* DEBUG
286 private static String decompile( TranslatingTypeLoader loader, ClassEntry classEntry )
287 {
288 PlainTextOutput output = new PlainTextOutput();
289 DecompilerSettings settings = DecompilerSettings.javaDefaults();
290 settings.setForceExplicitImports( true );
291 settings.setShowSyntheticMembers( true );
292 settings.setTypeLoader( loader );
293 Decompiler.decompile( classEntry.getName(), output, settings );
294 return output.toString();
295 }
296 */
297}