summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/gui/FieldMatchingGui.java
diff options
context:
space:
mode:
authorGravatar jeff2015-03-11 11:03:16 -0400
committerGravatar jeff2015-03-11 11:03:16 -0400
commite33b4003a5c423894e7aef575faff359dd1d33b1 (patch)
tree6fa674b5ff8dbc699a44b6423149ad7e6eaae250 /src/cuchaz/enigma/gui/FieldMatchingGui.java
parentnothing of consequence (diff)
downloadenigma-fork-e33b4003a5c423894e7aef575faff359dd1d33b1.tar.gz
enigma-fork-e33b4003a5c423894e7aef575faff359dd1d33b1.tar.xz
enigma-fork-e33b4003a5c423894e7aef575faff359dd1d33b1.zip
generalized field matching
added method matching
Diffstat (limited to 'src/cuchaz/enigma/gui/FieldMatchingGui.java')
-rw-r--r--src/cuchaz/enigma/gui/FieldMatchingGui.java474
1 files changed, 0 insertions, 474 deletions
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/FieldMatchingGui.java
deleted file mode 100644
index 3f4a378..0000000
--- a/src/cuchaz/enigma/gui/FieldMatchingGui.java
+++ /dev/null
@@ -1,474 +0,0 @@
1package cuchaz.enigma.gui;
2
3import java.awt.BorderLayout;
4import java.awt.Container;
5import java.awt.Dimension;
6import java.awt.FlowLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.awt.event.KeyAdapter;
10import java.awt.event.KeyEvent;
11import java.util.Collection;
12import java.util.List;
13import java.util.Map;
14
15import javax.swing.BoxLayout;
16import javax.swing.ButtonGroup;
17import javax.swing.JButton;
18import javax.swing.JFrame;
19import javax.swing.JLabel;
20import javax.swing.JPanel;
21import javax.swing.JRadioButton;
22import javax.swing.JScrollPane;
23import javax.swing.JSplitPane;
24import javax.swing.WindowConstants;
25import javax.swing.text.Highlighter.HighlightPainter;
26
27import com.beust.jcommander.internal.Lists;
28import com.beust.jcommander.internal.Maps;
29
30import cuchaz.enigma.Constants;
31import cuchaz.enigma.Deobfuscator;
32import cuchaz.enigma.analysis.EntryReference;
33import cuchaz.enigma.analysis.SourceIndex;
34import cuchaz.enigma.analysis.Token;
35import cuchaz.enigma.convert.ClassMatches;
36import cuchaz.enigma.convert.FieldMatches;
37import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
38import cuchaz.enigma.mapping.ClassEntry;
39import cuchaz.enigma.mapping.Entry;
40import cuchaz.enigma.mapping.FieldEntry;
41import de.sciss.syntaxpane.DefaultSyntaxKit;
42
43
44public class FieldMatchingGui {
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
77 public static interface SaveListener {
78 public void save(FieldMatches matches);
79 }
80
81 // controls
82 private JFrame m_frame;
83 private Map<SourceType,JRadioButton> m_sourceTypeButtons;
84 private ClassSelector m_sourceClasses;
85 private CodeReader m_sourceReader;
86 private CodeReader m_destReader;
87 private JButton m_matchButton;
88 private JButton m_unmatchableButton;
89 private JLabel m_sourceLabel;
90 private JLabel m_destLabel;
91 private HighlightPainter m_unmatchedHighlightPainter;
92 private HighlightPainter m_matchedHighlightPainter;
93
94 private ClassMatches m_classMatches;
95 private FieldMatches m_fieldMatches;
96 private Deobfuscator m_sourceDeobfuscator;
97 private Deobfuscator m_destDeobfuscator;
98 private SaveListener m_saveListener;
99 private SourceType m_sourceType;
100 private ClassEntry m_obfSourceClass;
101 private ClassEntry m_obfDestClass;
102 private FieldEntry m_obfSourceField;
103 private FieldEntry m_obfDestField;
104
105 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
106
107 m_classMatches = classMatches;
108 m_fieldMatches = fieldMatches;
109 m_sourceDeobfuscator = sourceDeobfuscator;
110 m_destDeobfuscator = destDeobfuscator;
111
112 // init frame
113 m_frame = new JFrame(Constants.Name + " - Field Matcher");
114 final Container pane = m_frame.getContentPane();
115 pane.setLayout(new BorderLayout());
116
117 // init classes side
118 JPanel classesPanel = new JPanel();
119 classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS));
120 classesPanel.setPreferredSize(new Dimension(200, 0));
121 pane.add(classesPanel, BorderLayout.WEST);
122 classesPanel.add(new JLabel("Classes"));
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
142 m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
143 m_sourceClasses.setListener(new ClassSelectionListener() {
144 @Override
145 public void onSelectClass(ClassEntry classEntry) {
146 setSourceClass(classEntry);
147 }
148 });
149 JScrollPane sourceScroller = new JScrollPane(m_sourceClasses);
150 classesPanel.add(sourceScroller);
151
152 // init readers
153 DefaultSyntaxKit.initKit();
154 m_sourceReader = new CodeReader();
155 m_sourceReader.setSelectionListener(new CodeReader.SelectionListener() {
156 @Override
157 public void onSelect(EntryReference<Entry,Entry> reference) {
158 if (reference != null) {
159 onSelectSource(reference.entry);
160 } else {
161 onSelectSource(null);
162 }
163 }
164 });
165 m_destReader = new CodeReader();
166 m_destReader.setSelectionListener(new CodeReader.SelectionListener() {
167 @Override
168 public void onSelect(EntryReference<Entry,Entry> reference) {
169 if (reference != null) {
170 onSelectDest(reference.entry);
171 } else {
172 onSelectDest(null);
173 }
174 }
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);
190
191 // init all the splits
192 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_sourceReader), new JScrollPane(m_destReader));
193 splitRight.setResizeWeight(0.5); // resize 50:50
194 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight);
195 splitLeft.setResizeWeight(0); // let the right side take all the slack
196 pane.add(splitLeft, BorderLayout.CENTER);
197 splitLeft.resetToPreferredSizes();
198
199 // init bottom panel
200 JPanel bottomPanel = new JPanel();
201 bottomPanel.setLayout(new FlowLayout());
202 pane.add(bottomPanel, BorderLayout.SOUTH);
203
204 m_matchButton = new JButton();
205 m_unmatchableButton = new JButton();
206
207 m_sourceLabel = new JLabel();
208 bottomPanel.add(m_sourceLabel);
209 bottomPanel.add(m_matchButton);
210 bottomPanel.add(m_unmatchableButton);
211 m_destLabel = new JLabel();
212 bottomPanel.add(m_destLabel);
213
214 // show the frame
215 pane.doLayout();
216 m_frame.setSize(1024, 576);
217 m_frame.setMinimumSize(new Dimension(640, 480));
218 m_frame.setVisible(true);
219 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
220
221 m_unmatchedHighlightPainter = new ObfuscatedHighlightPainter();
222 m_matchedHighlightPainter = new DeobfuscatedHighlightPainter();
223
224 // init state
225 m_saveListener = null;
226 m_obfSourceClass = null;
227 m_obfDestClass = null;
228 m_obfSourceField = null;
229 m_obfDestField = null;
230 setSourceType(SourceType.getDefault());
231 updateButtons();
232 }
233
234 protected void setSourceType(SourceType val) {
235 m_sourceType = val;
236 updateSourceClasses();
237 }
238
239 public void setSaveListener(SaveListener val) {
240 m_saveListener = val;
241 }
242
243 private void updateSourceClasses() {
244
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 }
262 }
263
264 protected void setSourceClass(ClassEntry sourceClass) {
265
266 m_obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass);
267 m_obfDestClass = m_classMatches.getUniqueMatches().get(m_obfSourceClass);
268 if (m_obfDestClass == null) {
269 throw new Error("No matching dest class for source class: " + m_obfSourceClass);
270 }
271
272 m_sourceReader.decompileClass(m_obfSourceClass, m_sourceDeobfuscator, false, new Runnable() {
273 @Override
274 public void run() {
275 updateSourceHighlights();
276 }
277 });
278 m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, false, new Runnable() {
279 @Override
280 public void run() {
281 updateDestHighlights();
282 }
283 });
284 }
285
286 protected void updateSourceHighlights() {
287 highlightFields(m_sourceReader, m_sourceDeobfuscator, m_fieldMatches.matches().keySet(), m_fieldMatches.getUnmatchedSourceFields());
288 }
289
290 protected void updateDestHighlights() {
291 highlightFields(m_destReader, m_destDeobfuscator, m_fieldMatches.matches().values(), m_fieldMatches.getUnmatchedDestFields());
292 }
293
294 private void highlightFields(CodeReader reader, Deobfuscator deobfuscator, Collection<FieldEntry> obfMatchedFields, Collection<FieldEntry> obfUnmatchedFields) {
295 reader.clearHighlights();
296 SourceIndex index = reader.getSourceIndex();
297
298 // matched fields
299 for (FieldEntry obfFieldEntry : obfMatchedFields) {
300 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry);
301 Token token = index.getDeclarationToken(deobfFieldEntry);
302 if (token != null) {
303 reader.setHighlightedToken(token, m_matchedHighlightPainter);
304 }
305 }
306
307 // unmatched fields
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);
313 }
314 }
315 }
316
317 private boolean isSelectionMatched() {
318 return m_obfSourceField != null && m_obfDestField != null
319 && m_fieldMatches.isMatched(m_obfSourceField, m_obfDestField);
320 }
321
322 protected void onSelectSource(Entry source) {
323
324 // start with no selection
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 }
342 }
343 }
344
345 updateButtons();
346 }
347
348 protected void onSelectDest(Entry dest) {
349
350 // start with no selection
351 if (isSelectionMatched()) {
352 setSource(null);
353 }
354 setDest(null);
355
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 }
368 }
369 }
370
371 updateButtons();
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() {
397
398 GuiTricks.deactivateButton(m_matchButton);
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 }
425 }
426
427 protected void match() {
428
429 // update the field matches
430 m_fieldMatches.makeMatch(m_obfSourceField, m_obfDestField);
431 save();
432
433 // update the ui
434 onSelectSource(null);
435 onSelectDest(null);
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);
464 updateSourceHighlights();
465 updateDestHighlights();
466 updateSourceClasses();
467 }
468
469 private void save() {
470 if (m_saveListener != null) {
471 m_saveListener.save(m_fieldMatches);
472 }
473 }
474}