summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/MappingsConverter.java
diff options
context:
space:
mode:
authorGravatar jeff2015-02-28 23:36:47 -0500
committerGravatar jeff2015-02-28 23:36:47 -0500
commit88671184e20b3ad3791125cf96c83ca048cb2861 (patch)
tree6c86f1ea61666ff2584b434d5f8df4d3fd83263c /src/cuchaz/enigma/convert/MappingsConverter.java
parentswitch to better-maintained version of JSyntaxPane (diff)
downloadenigma-fork-88671184e20b3ad3791125cf96c83ca048cb2861.tar.gz
enigma-fork-88671184e20b3ad3791125cf96c83ca048cb2861.tar.xz
enigma-fork-88671184e20b3ad3791125cf96c83ca048cb2861.zip
refactor converter a bit for upcoming convert gui
Diffstat (limited to 'src/cuchaz/enigma/convert/MappingsConverter.java')
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
new file mode 100644
index 0000000..d0f9382
--- /dev/null
+++ b/src/cuchaz/enigma/convert/MappingsConverter.java
@@ -0,0 +1,180 @@
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.util.Arrays;
14import java.util.Iterator;
15import java.util.LinkedHashMap;
16import java.util.Map;
17import java.util.jar.JarFile;
18
19import com.google.common.collect.BiMap;
20import com.google.common.collect.Maps;
21
22import cuchaz.enigma.analysis.JarIndex;
23import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
24import cuchaz.enigma.mapping.ClassEntry;
25import cuchaz.enigma.mapping.Mappings;
26
27public class MappingsConverter {
28
29 public static Matches computeMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) {
30
31 // index jars
32 System.out.println("Indexing source jar...");
33 JarIndex sourceIndex = new JarIndex();
34 sourceIndex.indexJar(sourceJar, false);
35 System.out.println("Indexing dest jar...");
36 JarIndex destIndex = new JarIndex();
37 destIndex.indexJar(destJar, false);
38
39 // compute the matching
40 ClassMatching matching = computeMatching(sourceJar, sourceIndex, destJar, destIndex);
41 return new Matches(matching.matches());
42 }
43
44 public static ClassMatching computeMatching(JarFile sourceJar, JarIndex sourceIndex, JarFile destJar, JarIndex destIndex) {
45
46 System.out.println("Iteratively matching classes");
47
48 ClassMatching lastMatching = null;
49 int round = 0;
50 SidedClassNamer sourceNamer = null;
51 SidedClassNamer destNamer = null;
52 for (boolean useReferences : Arrays.asList(false, true)) {
53
54 int numUniqueMatchesLastTime = 0;
55 if (lastMatching != null) {
56 numUniqueMatchesLastTime = lastMatching.uniqueMatches().size();
57 }
58
59 while (true) {
60
61 System.out.println("Round " + (++round) + "...");
62
63 // init the matching with identity settings
64 ClassMatching matching = new ClassMatching(
65 new ClassIdentifier(sourceJar, sourceIndex, sourceNamer, useReferences),
66 new ClassIdentifier(destJar, destIndex, destNamer, useReferences)
67 );
68
69 if (lastMatching == null) {
70 // search all classes
71 matching.match(sourceIndex.getObfClassEntries(), destIndex.getObfClassEntries());
72 } else {
73 // we already know about these matches
74 matching.addKnownMatches(lastMatching.uniqueMatches());
75
76 // search unmatched and ambiguously-matched classes
77 matching.match(lastMatching.unmatchedSourceClasses(), lastMatching.unmatchedDestClasses());
78 for (ClassMatch match : lastMatching.ambiguousMatches()) {
79 matching.match(match.sourceClasses, match.destClasses);
80 }
81 }
82 System.out.println(matching);
83 BiMap<ClassEntry,ClassEntry> uniqueMatches = matching.uniqueMatches();
84
85 // did we match anything new this time?
86 if (uniqueMatches.size() > numUniqueMatchesLastTime) {
87 numUniqueMatchesLastTime = uniqueMatches.size();
88 lastMatching = matching;
89 } else {
90 break;
91 }
92
93 // update the namers
94 ClassNamer namer = new ClassNamer(uniqueMatches);
95 sourceNamer = namer.getSourceNamer();
96 destNamer = namer.getDestNamer();
97 }
98 }
99
100 return lastMatching;
101 }
102
103 public static void convertMappings(Mappings mappings, BiMap<ClassEntry,ClassEntry> changes) {
104
105 // sort the changes so classes are renamed in the correct order
106 // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b
107 LinkedHashMap<ClassEntry,ClassEntry> sortedChanges = Maps.newLinkedHashMap();
108 int numChangesLeft = changes.size();
109 while (!changes.isEmpty()) {
110 Iterator<Map.Entry<ClassEntry,ClassEntry>> iter = changes.entrySet().iterator();
111 while (iter.hasNext()) {
112 Map.Entry<ClassEntry,ClassEntry> change = iter.next();
113 if (changes.containsKey(change.getValue())) {
114 sortedChanges.put(change.getKey(), change.getValue());
115 iter.remove();
116 }
117 }
118
119 // did we remove any changes?
120 if (numChangesLeft - changes.size() > 0) {
121 // keep going
122 numChangesLeft = changes.size();
123 } else {
124 // can't sort anymore. There must be a loop
125 break;
126 }
127 }
128 if (!changes.isEmpty()) {
129 throw new Error("Unable to sort class changes! There must be a cycle.");
130 }
131
132 // convert the mappings in the correct class order
133 for (Map.Entry<ClassEntry,ClassEntry> entry : sortedChanges.entrySet()) {
134 mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName());
135 }
136 }
137
138 /* TODO: after we get a mapping, check to see that the other entries match
139 public static void checkMethods() {
140
141 // check the method matches
142 System.out.println("Checking methods...");
143 for (ClassMapping classMapping : mappings.classes()) {
144 ClassEntry classEntry = new ClassEntry(classMapping.getObfFullName());
145 for (MethodMapping methodMapping : classMapping.methods()) {
146
147 // skip constructors
148 if (methodMapping.getObfName().equals("<init>")) {
149 continue;
150 }
151
152 MethodEntry methodEntry = new MethodEntry(
153 classEntry,
154 methodMapping.getObfName(),
155 methodMapping.getObfSignature()
156 );
157 if (!destIndex.containsObfBehavior(methodEntry)) {
158 System.err.println("WARNING: method doesn't match: " + methodEntry);
159
160 // TODO: show methods if needed
161 // show the available methods
162 System.err.println("\tAvailable dest methods:");
163 CtClass c = destLoader.loadClass(classMapping.getObfFullName());
164 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
165 System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior));
166 }
167
168 System.err.println("\tAvailable source methods:");
169 c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfFullName()));
170 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
171 System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior));
172 }
173 }
174 }
175 }
176
177 System.out.println("Done!");
178 }
179 */
180}