summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/gui/FieldMatchingGui.java
diff options
context:
space:
mode:
authorGravatar jeff2015-03-10 00:55:03 -0400
committerGravatar jeff2015-03-10 00:55:03 -0400
commit430df87ba5d855ca29bc53a5765a2862d2209098 (patch)
treeee427f009da8b29e7a66a4b4ce882120f9bb2cbf /src/cuchaz/enigma/gui/FieldMatchingGui.java
parentfield matcher is starting to be useful (diff)
downloadenigma-fork-430df87ba5d855ca29bc53a5765a2862d2209098.tar.gz
enigma-fork-430df87ba5d855ca29bc53a5765a2862d2209098.tar.xz
enigma-fork-430df87ba5d855ca29bc53a5765a2862d2209098.zip
tweaks and improvements to field matching gui
Diffstat (limited to 'src/cuchaz/enigma/gui/FieldMatchingGui.java')
-rw-r--r--src/cuchaz/enigma/gui/FieldMatchingGui.java317
1 files changed, 251 insertions, 66 deletions
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/FieldMatchingGui.java
index ef374c8..3f4a378 100644
--- a/src/cuchaz/enigma/gui/FieldMatchingGui.java
+++ b/src/cuchaz/enigma/gui/FieldMatchingGui.java
@@ -6,20 +6,26 @@ import java.awt.Dimension;
6import java.awt.FlowLayout; 6import java.awt.FlowLayout;
7import java.awt.event.ActionEvent; 7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener; 8import java.awt.event.ActionListener;
9import java.awt.event.KeyAdapter;
10import java.awt.event.KeyEvent;
9import java.util.Collection; 11import java.util.Collection;
10import java.util.Set; 12import java.util.List;
13import java.util.Map;
11 14
12import javax.swing.BoxLayout; 15import javax.swing.BoxLayout;
16import javax.swing.ButtonGroup;
13import javax.swing.JButton; 17import javax.swing.JButton;
14import javax.swing.JFrame; 18import javax.swing.JFrame;
15import javax.swing.JLabel; 19import javax.swing.JLabel;
16import javax.swing.JPanel; 20import javax.swing.JPanel;
21import javax.swing.JRadioButton;
17import javax.swing.JScrollPane; 22import javax.swing.JScrollPane;
18import javax.swing.JSplitPane; 23import javax.swing.JSplitPane;
19import javax.swing.WindowConstants; 24import javax.swing.WindowConstants;
20import javax.swing.text.Highlighter.HighlightPainter; 25import javax.swing.text.Highlighter.HighlightPainter;
21 26
22import com.google.common.collect.Sets; 27import com.beust.jcommander.internal.Lists;
28import com.beust.jcommander.internal.Maps;
23 29
24import cuchaz.enigma.Constants; 30import cuchaz.enigma.Constants;
25import cuchaz.enigma.Deobfuscator; 31import cuchaz.enigma.Deobfuscator;
@@ -37,16 +43,49 @@ import de.sciss.syntaxpane.DefaultSyntaxKit;
37 43
38public class FieldMatchingGui { 44public class FieldMatchingGui {
39 45
46 private static enum SourceType {
47 Matched {
48
49 @Override
50 public Collection<ClassEntry> getObfSourceClasses(FieldMatches matches) {
51 return matches.getSourceClassesWithoutUnmatchedFields();
52 }
53 },
54 Unmatched {
55
56 @Override
57 public Collection<ClassEntry> getObfSourceClasses(FieldMatches matches) {
58 return matches.getSourceClassesWithUnmatchedFields();
59 }
60 };
61
62 public JRadioButton newRadio(ActionListener listener, ButtonGroup group) {
63 JRadioButton button = new JRadioButton(name(), this == getDefault());
64 button.setActionCommand(name());
65 button.addActionListener(listener);
66 group.add(button);
67 return button;
68 }
69
70 public abstract Collection<ClassEntry> getObfSourceClasses(FieldMatches matches);
71
72 public static SourceType getDefault() {
73 return values()[0];
74 }
75 }
76
40 public static interface SaveListener { 77 public static interface SaveListener {
41 public void save(FieldMatches matches); 78 public void save(FieldMatches matches);
42 } 79 }
43 80
44 // controls 81 // controls
45 private JFrame m_frame; 82 private JFrame m_frame;
83 private Map<SourceType,JRadioButton> m_sourceTypeButtons;
46 private ClassSelector m_sourceClasses; 84 private ClassSelector m_sourceClasses;
47 private CodeReader m_sourceReader; 85 private CodeReader m_sourceReader;
48 private CodeReader m_destReader; 86 private CodeReader m_destReader;
49 private JButton m_matchButton; 87 private JButton m_matchButton;
88 private JButton m_unmatchableButton;
50 private JLabel m_sourceLabel; 89 private JLabel m_sourceLabel;
51 private JLabel m_destLabel; 90 private JLabel m_destLabel;
52 private HighlightPainter m_unmatchedHighlightPainter; 91 private HighlightPainter m_unmatchedHighlightPainter;
@@ -57,12 +96,11 @@ public class FieldMatchingGui {
57 private Deobfuscator m_sourceDeobfuscator; 96 private Deobfuscator m_sourceDeobfuscator;
58 private Deobfuscator m_destDeobfuscator; 97 private Deobfuscator m_destDeobfuscator;
59 private SaveListener m_saveListener; 98 private SaveListener m_saveListener;
99 private SourceType m_sourceType;
60 private ClassEntry m_obfSourceClass; 100 private ClassEntry m_obfSourceClass;
61 private ClassEntry m_obfDestClass; 101 private ClassEntry m_obfDestClass;
62 private FieldEntry m_obfSourceField; 102 private FieldEntry m_obfSourceField;
63 private FieldEntry m_obfDestField; 103 private FieldEntry m_obfDestField;
64 private Set<FieldEntry> m_obfUnmatchedSourceFields;
65 private Set<FieldEntry> m_obfUnmatchedDestFields;
66 104
67 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 105 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
68 106
@@ -83,6 +121,24 @@ public class FieldMatchingGui {
83 pane.add(classesPanel, BorderLayout.WEST); 121 pane.add(classesPanel, BorderLayout.WEST);
84 classesPanel.add(new JLabel("Classes")); 122 classesPanel.add(new JLabel("Classes"));
85 123
124 // init source type radios
125 JPanel sourceTypePanel = new JPanel();
126 classesPanel.add(sourceTypePanel);
127 sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS));
128 ActionListener sourceTypeListener = new ActionListener() {
129 @Override
130 public void actionPerformed(ActionEvent event) {
131 setSourceType(SourceType.valueOf(event.getActionCommand()));
132 }
133 };
134 ButtonGroup sourceTypeButtons = new ButtonGroup();
135 m_sourceTypeButtons = Maps.newHashMap();
136 for (SourceType sourceType : SourceType.values()) {
137 JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons);
138 m_sourceTypeButtons.put(sourceType, button);
139 sourceTypePanel.add(button);
140 }
141
86 m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); 142 m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
87 m_sourceClasses.setListener(new ClassSelectionListener() { 143 m_sourceClasses.setListener(new ClassSelectionListener() {
88 @Override 144 @Override
@@ -117,6 +173,20 @@ public class FieldMatchingGui {
117 } 173 }
118 } 174 }
119 }); 175 });
176
177 // add key bindings
178 KeyAdapter keyListener = new KeyAdapter() {
179 @Override
180 public void keyPressed(KeyEvent event) {
181 switch (event.getKeyCode()) {
182 case KeyEvent.VK_M:
183 m_matchButton.doClick();
184 break;
185 }
186 }
187 };
188 m_sourceReader.addKeyListener(keyListener);
189 m_destReader.addKeyListener(keyListener);
120 190
121 // init all the splits 191 // init all the splits
122 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_sourceReader), new JScrollPane(m_destReader)); 192 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_sourceReader), new JScrollPane(m_destReader));
@@ -131,17 +201,13 @@ public class FieldMatchingGui {
131 bottomPanel.setLayout(new FlowLayout()); 201 bottomPanel.setLayout(new FlowLayout());
132 pane.add(bottomPanel, BorderLayout.SOUTH); 202 pane.add(bottomPanel, BorderLayout.SOUTH);
133 203
134 m_matchButton = new JButton("Match"); 204 m_matchButton = new JButton();
135 m_matchButton.addActionListener(new ActionListener() { 205 m_unmatchableButton = new JButton();
136 @Override
137 public void actionPerformed(ActionEvent event) {
138 match();
139 }
140 });
141 206
142 m_sourceLabel = new JLabel(); 207 m_sourceLabel = new JLabel();
143 bottomPanel.add(m_sourceLabel); 208 bottomPanel.add(m_sourceLabel);
144 bottomPanel.add(m_matchButton); 209 bottomPanel.add(m_matchButton);
210 bottomPanel.add(m_unmatchableButton);
145 m_destLabel = new JLabel(); 211 m_destLabel = new JLabel();
146 bottomPanel.add(m_destLabel); 212 bottomPanel.add(m_destLabel);
147 213
@@ -161,10 +227,13 @@ public class FieldMatchingGui {
161 m_obfDestClass = null; 227 m_obfDestClass = null;
162 m_obfSourceField = null; 228 m_obfSourceField = null;
163 m_obfDestField = null; 229 m_obfDestField = null;
164 m_obfUnmatchedSourceFields = null; 230 setSourceType(SourceType.getDefault());
165 m_obfUnmatchedDestFields = null; 231 updateButtons();
232 }
233
234 protected void setSourceType(SourceType val) {
235 m_sourceType = val;
166 updateSourceClasses(); 236 updateSourceClasses();
167 updateMatchButton();
168 } 237 }
169 238
170 public void setSaveListener(SaveListener val) { 239 public void setSaveListener(SaveListener val) {
@@ -172,26 +241,41 @@ public class FieldMatchingGui {
172 } 241 }
173 242
174 private void updateSourceClasses() { 243 private void updateSourceClasses() {
175 m_sourceClasses.setClasses(m_fieldMatches.getSourceClassesWithUnmatchedFields()); 244
176 m_sourceClasses.expandAll(); 245 String selectedPackage = m_sourceClasses.getSelectedPackage();
246
247 List<ClassEntry> deobfClassEntries = Lists.newArrayList();
248 for (ClassEntry entry : m_sourceType.getObfSourceClasses(m_fieldMatches)) {
249 deobfClassEntries.add(m_sourceDeobfuscator.deobfuscateEntry(entry));
250 }
251 m_sourceClasses.setClasses(deobfClassEntries);
252
253 if (selectedPackage != null) {
254 m_sourceClasses.expandPackage(selectedPackage);
255 }
256
257 for (SourceType sourceType : SourceType.values()) {
258 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)",
259 sourceType.name(), sourceType.getObfSourceClasses(m_fieldMatches).size()
260 ));
261 }
177 } 262 }
178 263
179 protected void setSourceClass(ClassEntry obfSourceClass) { 264 protected void setSourceClass(ClassEntry sourceClass) {
180 265
181 m_obfSourceClass = obfSourceClass; 266 m_obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass);
182 m_obfDestClass = m_classMatches.getUniqueMatches().get(obfSourceClass); 267 m_obfDestClass = m_classMatches.getUniqueMatches().get(m_obfSourceClass);
183 if (m_obfDestClass == null) { 268 if (m_obfDestClass == null) {
184 throw new Error("No matching dest class for source class: " + m_obfSourceClass); 269 throw new Error("No matching dest class for source class: " + m_obfSourceClass);
185 } 270 }
186 271
187 updateUnmatchedFields(); 272 m_sourceReader.decompileClass(m_obfSourceClass, m_sourceDeobfuscator, false, new Runnable() {
188 m_sourceReader.decompileClass(m_obfSourceClass, m_sourceDeobfuscator, new Runnable() {
189 @Override 273 @Override
190 public void run() { 274 public void run() {
191 updateSourceHighlights(); 275 updateSourceHighlights();
192 } 276 }
193 }); 277 });
194 m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, new Runnable() { 278 m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, false, new Runnable() {
195 @Override 279 @Override
196 public void run() { 280 public void run() {
197 updateDestHighlights(); 281 updateDestHighlights();
@@ -199,71 +283,145 @@ public class FieldMatchingGui {
199 }); 283 });
200 } 284 }
201 285
202 private void updateUnmatchedFields() {
203 m_obfUnmatchedSourceFields = Sets.newHashSet(m_fieldMatches.getUnmatchedSourceFields(m_obfSourceClass));
204 m_obfUnmatchedDestFields = Sets.newHashSet();
205 for (FieldEntry destFieldEntry : m_destDeobfuscator.getJarIndex().getObfFieldEntries(m_obfDestClass)) {
206 if (!m_fieldMatches.isDestMatched(destFieldEntry)) {
207 m_obfUnmatchedDestFields.add(destFieldEntry);
208 }
209 }
210 }
211
212 protected void updateSourceHighlights() { 286 protected void updateSourceHighlights() {
213 highlightFields(m_sourceReader, m_sourceDeobfuscator, m_obfUnmatchedSourceFields, m_fieldMatches.matches().keySet()); 287 highlightFields(m_sourceReader, m_sourceDeobfuscator, m_fieldMatches.matches().keySet(), m_fieldMatches.getUnmatchedSourceFields());
214 } 288 }
215 289
216 protected void updateDestHighlights() { 290 protected void updateDestHighlights() {
217 highlightFields(m_destReader, m_destDeobfuscator, m_obfUnmatchedDestFields, m_fieldMatches.matches().values()); 291 highlightFields(m_destReader, m_destDeobfuscator, m_fieldMatches.matches().values(), m_fieldMatches.getUnmatchedDestFields());
218 } 292 }
219 293
220 private void highlightFields(CodeReader reader, Deobfuscator deobfuscator, Collection<FieldEntry> obfFieldEntries, Collection<FieldEntry> obfMatchedFieldEntries) { 294 private void highlightFields(CodeReader reader, Deobfuscator deobfuscator, Collection<FieldEntry> obfMatchedFields, Collection<FieldEntry> obfUnmatchedFields) {
221 reader.clearHighlights(); 295 reader.clearHighlights();
222 SourceIndex index = reader.getSourceIndex(); 296 SourceIndex index = reader.getSourceIndex();
223 for (FieldEntry obfFieldEntry : obfFieldEntries) { 297
298 // matched fields
299 for (FieldEntry obfFieldEntry : obfMatchedFields) {
224 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry); 300 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry);
225 Token token = index.getDeclarationToken(deobfFieldEntry); 301 Token token = index.getDeclarationToken(deobfFieldEntry);
226 if (token == null) { 302 if (token != null) {
227 System.err.println("WARNING: Can't find declaration token for " + deobfFieldEntry); 303 reader.setHighlightedToken(token, m_matchedHighlightPainter);
228 } else { 304 }
229 reader.setHighlightedToken( 305 }
230 token, 306
231 obfMatchedFieldEntries.contains(obfFieldEntry) ? m_matchedHighlightPainter : m_unmatchedHighlightPainter 307 // unmatched fields
232 ); 308 for (FieldEntry obfFieldEntry : obfUnmatchedFields) {
309 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry);
310 Token token = index.getDeclarationToken(deobfFieldEntry);
311 if (token != null) {
312 reader.setHighlightedToken(token, m_unmatchedHighlightPainter);
233 } 313 }
234 } 314 }
235 } 315 }
236 316
237 protected void onSelectSource(Entry entry) { 317 private boolean isSelectionMatched() {
238 m_sourceLabel.setText(""); 318 return m_obfSourceField != null && m_obfDestField != null
239 m_obfSourceField = null; 319 && m_fieldMatches.isMatched(m_obfSourceField, m_obfDestField);
240 if (entry != null && entry instanceof FieldEntry) { 320 }
241 FieldEntry fieldEntry = (FieldEntry)entry; 321
242 FieldEntry obfFieldEntry = m_sourceDeobfuscator.obfuscateEntry(fieldEntry); 322 protected void onSelectSource(Entry source) {
243 if (m_obfUnmatchedSourceFields.contains(obfFieldEntry)) { 323
244 m_obfSourceField = obfFieldEntry; 324 // start with no selection
245 m_sourceLabel.setText(fieldEntry.getName() + " " + fieldEntry.getType().toString()); 325 if (isSelectionMatched()) {
326 setDest(null);
327 }
328 setSource(null);
329
330 // then look for a valid source selection
331 if (source != null && source instanceof FieldEntry) {
332 FieldEntry sourceField = (FieldEntry)source;
333 FieldEntry obfSourceField = m_sourceDeobfuscator.obfuscateEntry(sourceField);
334 if (m_fieldMatches.hasSource(obfSourceField)) {
335 setSource(obfSourceField);
336
337 // look for a matched dest too
338 FieldEntry obfDestField = m_fieldMatches.matches().get(obfSourceField);
339 if (obfDestField != null) {
340 setDest(obfDestField);
341 }
246 } 342 }
247 } 343 }
248 updateMatchButton(); 344
345 updateButtons();
249 } 346 }
250 347
251 protected void onSelectDest(Entry entry) { 348 protected void onSelectDest(Entry dest) {
252 m_destLabel.setText(""); 349
253 m_obfDestField = null; 350 // start with no selection
254 if (entry != null && entry instanceof FieldEntry) { 351 if (isSelectionMatched()) {
255 FieldEntry fieldEntry = (FieldEntry)entry; 352 setSource(null);
256 FieldEntry obfFieldEntry = m_destDeobfuscator.obfuscateEntry(fieldEntry); 353 }
257 if (m_obfUnmatchedDestFields.contains(obfFieldEntry)) { 354 setDest(null);
258 m_obfDestField = obfFieldEntry; 355
259 m_destLabel.setText(fieldEntry.getName() + " " + fieldEntry.getType().toString()); 356 // then look for a valid dest selection
357 if (dest != null && dest instanceof FieldEntry) {
358 FieldEntry destField = (FieldEntry)dest;
359 FieldEntry obfDestField = m_destDeobfuscator.obfuscateEntry(destField);
360 if (m_fieldMatches.hasDest(obfDestField)) {
361 setDest(obfDestField);
362
363 // look for a matched source too
364 FieldEntry obfSourceField = m_fieldMatches.matches().inverse().get(obfDestField);
365 if (obfSourceField != null) {
366 setSource(obfSourceField);
367 }
260 } 368 }
261 } 369 }
262 updateMatchButton(); 370
371 updateButtons();
263 } 372 }
373
374 private void setSource(FieldEntry obfField) {
375 if (obfField == null) {
376 m_obfSourceField = obfField;
377 m_sourceLabel.setText("");
378 } else {
379 m_obfSourceField = obfField;
380 FieldEntry deobfField = m_sourceDeobfuscator.deobfuscateEntry(obfField);
381 m_sourceLabel.setText(deobfField.getName() + " " + deobfField.getType().toString());
382 }
383 }
384
385 private void setDest(FieldEntry obfField) {
386 if (obfField == null) {
387 m_obfDestField = obfField;
388 m_destLabel.setText("");
389 } else {
390 m_obfDestField = obfField;
391 FieldEntry deobfField = m_destDeobfuscator.deobfuscateEntry(obfField);
392 m_destLabel.setText(deobfField.getName() + " " + deobfField.getType().toString());
393 }
394 }
395
396 private void updateButtons() {
264 397
265 private void updateMatchButton() { 398 GuiTricks.deactivateButton(m_matchButton);
266 m_matchButton.setEnabled(m_obfSourceField != null && m_obfDestField != null); 399 GuiTricks.deactivateButton(m_unmatchableButton);
400
401 if (m_obfSourceField != null && m_obfDestField != null) {
402 if (m_fieldMatches.isMatched(m_obfSourceField, m_obfDestField)) {
403 GuiTricks.activateButton(m_matchButton, "Unmatch", new ActionListener() {
404 @Override
405 public void actionPerformed(ActionEvent event) {
406 unmatch();
407 }
408 });
409 } else if (!m_fieldMatches.isMatchedSourceField(m_obfSourceField) && !m_fieldMatches.isMatchedDestField(m_obfDestField)) {
410 GuiTricks.activateButton(m_matchButton, "Match", new ActionListener() {
411 @Override
412 public void actionPerformed(ActionEvent event) {
413 match();
414 }
415 });
416 }
417 } else if (m_obfSourceField != null) {
418 GuiTricks.activateButton(m_unmatchableButton, "Set Unmatchable", new ActionListener() {
419 @Override
420 public void actionPerformed(ActionEvent event) {
421 unmatchable();
422 }
423 });
424 }
267 } 425 }
268 426
269 protected void match() { 427 protected void match() {
@@ -275,7 +433,34 @@ public class FieldMatchingGui {
275 // update the ui 433 // update the ui
276 onSelectSource(null); 434 onSelectSource(null);
277 onSelectDest(null); 435 onSelectDest(null);
278 updateUnmatchedFields(); 436 updateSourceHighlights();
437 updateDestHighlights();
438 updateSourceClasses();
439 }
440
441 protected void unmatch() {
442
443 // update the field matches
444 m_fieldMatches.unmakeMatch(m_obfSourceField, m_obfDestField);
445 save();
446
447 // update the ui
448 onSelectSource(null);
449 onSelectDest(null);
450 updateSourceHighlights();
451 updateDestHighlights();
452 updateSourceClasses();
453 }
454
455 protected void unmatchable() {
456
457 // update the field matches
458 m_fieldMatches.makeSourceUnmatchable(m_obfSourceField);
459 save();
460
461 // update the ui
462 onSelectSource(null);
463 onSelectDest(null);
279 updateSourceHighlights(); 464 updateSourceHighlights();
280 updateDestHighlights(); 465 updateDestHighlights();
281 updateSourceClasses(); 466 updateSourceClasses();