diff options
| author | 2017-03-08 08:17:04 +0100 | |
|---|---|---|
| committer | 2017-03-08 08:17:04 +0100 | |
| commit | 6e464ea251cab63c776ece0b2a356f1498ffa294 (patch) | |
| tree | 5ed30c03f5ac4cd2d6877874f5ede576049954f7 /src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java | |
| parent | Drop unix case style and implement hashCode when equals is overrided (diff) | |
| download | enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.gz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.tar.xz enigma-fork-6e464ea251cab63c776ece0b2a356f1498ffa294.zip | |
Follow Fabric guidelines
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java | 815 |
1 files changed, 404 insertions, 411 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java index 671f85f..4f5231f 100644 --- a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java +++ b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java | |||
| @@ -8,25 +8,11 @@ | |||
| 8 | * Contributors: | 8 | * Contributors: |
| 9 | * Jeff Martin - initial API and implementation | 9 | * Jeff Martin - initial API and implementation |
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | |||
| 11 | package cuchaz.enigma.gui; | 12 | package cuchaz.enigma.gui; |
| 12 | 13 | ||
| 13 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 14 | import com.google.common.collect.Maps; | 15 | import com.google.common.collect.Maps; |
| 15 | |||
| 16 | import java.awt.BorderLayout; | ||
| 17 | import java.awt.Container; | ||
| 18 | import java.awt.Dimension; | ||
| 19 | import java.awt.FlowLayout; | ||
| 20 | import java.awt.event.ActionListener; | ||
| 21 | import java.awt.event.KeyAdapter; | ||
| 22 | import java.awt.event.KeyEvent; | ||
| 23 | import java.util.Collection; | ||
| 24 | import java.util.List; | ||
| 25 | import java.util.Map; | ||
| 26 | |||
| 27 | import javax.swing.*; | ||
| 28 | import javax.swing.text.Highlighter.HighlightPainter; | ||
| 29 | |||
| 30 | import cuchaz.enigma.Constants; | 16 | import cuchaz.enigma.Constants; |
| 31 | import cuchaz.enigma.Deobfuscator; | 17 | import cuchaz.enigma.Deobfuscator; |
| 32 | import cuchaz.enigma.analysis.SourceIndex; | 18 | import cuchaz.enigma.analysis.SourceIndex; |
| @@ -39,403 +25,410 @@ import cuchaz.enigma.mapping.ClassEntry; | |||
| 39 | import cuchaz.enigma.mapping.Entry; | 25 | import cuchaz.enigma.mapping.Entry; |
| 40 | import de.sciss.syntaxpane.DefaultSyntaxKit; | 26 | import de.sciss.syntaxpane.DefaultSyntaxKit; |
| 41 | 27 | ||
| 28 | import javax.swing.*; | ||
| 29 | import javax.swing.text.Highlighter.HighlightPainter; | ||
| 30 | import java.awt.*; | ||
| 31 | import java.awt.event.ActionListener; | ||
| 32 | import java.awt.event.KeyAdapter; | ||
| 33 | import java.awt.event.KeyEvent; | ||
| 34 | import java.util.Collection; | ||
| 35 | import java.util.List; | ||
| 36 | import java.util.Map; | ||
| 42 | 37 | ||
| 43 | public class MemberMatchingGui<T extends Entry> { | 38 | public class MemberMatchingGui<T extends Entry> { |
| 44 | 39 | ||
| 45 | private enum SourceType { | 40 | // controls |
| 46 | Matched { | 41 | private JFrame frame; |
| 47 | @Override | 42 | private Map<SourceType, JRadioButton> sourceTypeButtons; |
| 48 | public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { | 43 | private ClassSelector sourceClasses; |
| 49 | return matches.getSourceClassesWithoutUnmatchedEntries(); | 44 | private CodeReader sourceReader; |
| 50 | } | 45 | private CodeReader destReader; |
| 51 | }, | 46 | private JButton matchButton; |
| 52 | Unmatched { | 47 | private JButton unmatchableButton; |
| 53 | @Override | 48 | private JLabel sourceLabel; |
| 54 | public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { | 49 | private JLabel destLabel; |
| 55 | return matches.getSourceClassesWithUnmatchedEntries(); | 50 | private HighlightPainter unmatchedHighlightPainter; |
| 56 | } | 51 | private HighlightPainter matchedHighlightPainter; |
| 57 | }; | 52 | private ClassMatches classMatches; |
| 58 | 53 | private MemberMatches<T> memberMatches; | |
| 59 | public JRadioButton newRadio(ActionListener listener, ButtonGroup group) { | 54 | private Deobfuscator sourceDeobfuscator; |
| 60 | JRadioButton button = new JRadioButton(name(), this == getDefault()); | 55 | private Deobfuscator destDeobfuscator; |
| 61 | button.setActionCommand(name()); | 56 | private SaveListener<T> saveListener; |
| 62 | button.addActionListener(listener); | 57 | private SourceType sourceType; |
| 63 | group.add(button); | 58 | private ClassEntry obfSourceClass; |
| 64 | return button; | 59 | private ClassEntry obfDestClass; |
| 65 | } | 60 | private T obfSourceEntry; |
| 66 | 61 | private T obfDestEntry; | |
| 67 | public abstract <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches); | 62 | public MemberMatchingGui(ClassMatches classMatches, MemberMatches<T> fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { |
| 68 | 63 | ||
| 69 | public static SourceType getDefault() { | 64 | this.classMatches = classMatches; |
| 70 | return values()[0]; | 65 | memberMatches = fieldMatches; |
| 71 | } | 66 | this.sourceDeobfuscator = sourceDeobfuscator; |
| 72 | } | 67 | this.destDeobfuscator = destDeobfuscator; |
| 73 | 68 | ||
| 74 | public interface SaveListener<T extends Entry> { | 69 | // init frame |
| 75 | void save(MemberMatches<T> matches); | 70 | frame = new JFrame(Constants.NAME + " - Member Matcher"); |
| 76 | } | 71 | final Container pane = frame.getContentPane(); |
| 77 | 72 | pane.setLayout(new BorderLayout()); | |
| 78 | // controls | 73 | |
| 79 | private JFrame frame; | 74 | // init classes side |
| 80 | private Map<SourceType, JRadioButton> sourceTypeButtons; | 75 | JPanel classesPanel = new JPanel(); |
| 81 | private ClassSelector sourceClasses; | 76 | classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS)); |
| 82 | private CodeReader sourceReader; | 77 | classesPanel.setPreferredSize(new Dimension(200, 0)); |
| 83 | private CodeReader destReader; | 78 | pane.add(classesPanel, BorderLayout.WEST); |
| 84 | private JButton matchButton; | 79 | classesPanel.add(new JLabel("Classes")); |
| 85 | private JButton unmatchableButton; | 80 | |
| 86 | private JLabel sourceLabel; | 81 | // init source type radios |
| 87 | private JLabel destLabel; | 82 | JPanel sourceTypePanel = new JPanel(); |
| 88 | private HighlightPainter unmatchedHighlightPainter; | 83 | classesPanel.add(sourceTypePanel); |
| 89 | private HighlightPainter matchedHighlightPainter; | 84 | sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS)); |
| 90 | private ClassMatches classMatches; | 85 | ActionListener sourceTypeListener = event -> setSourceType(SourceType.valueOf(event.getActionCommand())); |
| 91 | private MemberMatches<T> memberMatches; | 86 | ButtonGroup sourceTypeButtons = new ButtonGroup(); |
| 92 | private Deobfuscator sourceDeobfuscator; | 87 | this.sourceTypeButtons = Maps.newHashMap(); |
| 93 | private Deobfuscator destDeobfuscator; | 88 | for (SourceType sourceType : SourceType.values()) { |
| 94 | private SaveListener<T> saveListener; | 89 | JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); |
| 95 | private SourceType sourceType; | 90 | this.sourceTypeButtons.put(sourceType, button); |
| 96 | private ClassEntry obfSourceClass; | 91 | sourceTypePanel.add(button); |
| 97 | private ClassEntry obfDestClass; | 92 | } |
| 98 | private T obfSourceEntry; | 93 | |
| 99 | private T obfDestEntry; | 94 | sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); |
| 100 | 95 | sourceClasses.setSelectionListener(this::setSourceClass); | |
| 101 | public MemberMatchingGui(ClassMatches classMatches, MemberMatches<T> fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { | 96 | JScrollPane sourceScroller = new JScrollPane(sourceClasses); |
| 102 | 97 | classesPanel.add(sourceScroller); | |
| 103 | this.classMatches = classMatches; | 98 | |
| 104 | memberMatches = fieldMatches; | 99 | // init readers |
| 105 | this.sourceDeobfuscator = sourceDeobfuscator; | 100 | DefaultSyntaxKit.initKit(); |
| 106 | this.destDeobfuscator = destDeobfuscator; | 101 | sourceReader = new CodeReader(); |
| 107 | 102 | sourceReader.setSelectionListener(reference -> | |
| 108 | // init frame | 103 | { |
| 109 | frame = new JFrame(Constants.NAME + " - Member Matcher"); | 104 | if (reference != null) { |
| 110 | final Container pane = frame.getContentPane(); | 105 | onSelectSource(reference.entry); |
| 111 | pane.setLayout(new BorderLayout()); | 106 | } else { |
| 112 | 107 | onSelectSource(null); | |
| 113 | // init classes side | 108 | } |
| 114 | JPanel classesPanel = new JPanel(); | 109 | }); |
| 115 | classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS)); | 110 | destReader = new CodeReader(); |
| 116 | classesPanel.setPreferredSize(new Dimension(200, 0)); | 111 | destReader.setSelectionListener(reference -> |
| 117 | pane.add(classesPanel, BorderLayout.WEST); | 112 | { |
| 118 | classesPanel.add(new JLabel("Classes")); | 113 | if (reference != null) { |
| 119 | 114 | onSelectDest(reference.entry); | |
| 120 | // init source type radios | 115 | } else { |
| 121 | JPanel sourceTypePanel = new JPanel(); | 116 | onSelectDest(null); |
| 122 | classesPanel.add(sourceTypePanel); | 117 | } |
| 123 | sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS)); | 118 | }); |
| 124 | ActionListener sourceTypeListener = event -> setSourceType(SourceType.valueOf(event.getActionCommand())); | 119 | |
| 125 | ButtonGroup sourceTypeButtons = new ButtonGroup(); | 120 | // add key bindings |
| 126 | this.sourceTypeButtons = Maps.newHashMap(); | 121 | KeyAdapter keyListener = new KeyAdapter() { |
| 127 | for (SourceType sourceType : SourceType.values()) { | 122 | @Override |
| 128 | JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); | 123 | public void keyPressed(KeyEvent event) { |
| 129 | this.sourceTypeButtons.put(sourceType, button); | 124 | if (event.getKeyCode() == KeyEvent.VK_M) |
| 130 | sourceTypePanel.add(button); | 125 | matchButton.doClick(); |
| 131 | } | 126 | } |
| 132 | 127 | }; | |
| 133 | sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); | 128 | sourceReader.addKeyListener(keyListener); |
| 134 | sourceClasses.setSelectionListener(this::setSourceClass); | 129 | destReader.addKeyListener(keyListener); |
| 135 | JScrollPane sourceScroller = new JScrollPane(sourceClasses); | 130 | |
| 136 | classesPanel.add(sourceScroller); | 131 | // init all the splits |
| 137 | 132 | JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(sourceReader), new JScrollPane( | |
| 138 | // init readers | 133 | destReader)); |
| 139 | DefaultSyntaxKit.initKit(); | 134 | splitRight.setResizeWeight(0.5); // resize 50:50 |
| 140 | sourceReader = new CodeReader(); | 135 | JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight); |
| 141 | sourceReader.setSelectionListener(reference -> | 136 | splitLeft.setResizeWeight(0); // let the right side take all the slack |
| 142 | { | 137 | pane.add(splitLeft, BorderLayout.CENTER); |
| 143 | if (reference != null) { | 138 | splitLeft.resetToPreferredSizes(); |
| 144 | onSelectSource(reference.entry); | 139 | |
| 145 | } else { | 140 | // init bottom panel |
| 146 | onSelectSource(null); | 141 | JPanel bottomPanel = new JPanel(); |
| 147 | } | 142 | bottomPanel.setLayout(new FlowLayout()); |
| 148 | }); | 143 | pane.add(bottomPanel, BorderLayout.SOUTH); |
| 149 | destReader = new CodeReader(); | 144 | |
| 150 | destReader.setSelectionListener(reference -> | 145 | matchButton = new JButton(); |
| 151 | { | 146 | unmatchableButton = new JButton(); |
| 152 | if (reference != null) { | 147 | |
| 153 | onSelectDest(reference.entry); | 148 | sourceLabel = new JLabel(); |
| 154 | } else { | 149 | bottomPanel.add(sourceLabel); |
| 155 | onSelectDest(null); | 150 | bottomPanel.add(matchButton); |
| 156 | } | 151 | bottomPanel.add(unmatchableButton); |
| 157 | }); | 152 | destLabel = new JLabel(); |
| 158 | 153 | bottomPanel.add(destLabel); | |
| 159 | // add key bindings | 154 | |
| 160 | KeyAdapter keyListener = new KeyAdapter() { | 155 | // show the frame |
| 161 | @Override | 156 | pane.doLayout(); |
| 162 | public void keyPressed(KeyEvent event) { | 157 | frame.setSize(1024, 576); |
| 163 | if (event.getKeyCode() == KeyEvent.VK_M) | 158 | frame.setMinimumSize(new Dimension(640, 480)); |
| 164 | matchButton.doClick(); | 159 | frame.setVisible(true); |
| 165 | } | 160 | frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); |
| 166 | }; | 161 | |
| 167 | sourceReader.addKeyListener(keyListener); | 162 | unmatchedHighlightPainter = new ObfuscatedHighlightPainter(); |
| 168 | destReader.addKeyListener(keyListener); | 163 | matchedHighlightPainter = new DeobfuscatedHighlightPainter(); |
| 169 | 164 | ||
| 170 | // init all the splits | 165 | // init state |
| 171 | JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(sourceReader), new JScrollPane( | 166 | saveListener = null; |
| 172 | destReader)); | 167 | obfSourceClass = null; |
| 173 | splitRight.setResizeWeight(0.5); // resize 50:50 | 168 | obfDestClass = null; |
| 174 | JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight); | 169 | obfSourceEntry = null; |
| 175 | splitLeft.setResizeWeight(0); // let the right side take all the slack | 170 | obfDestEntry = null; |
| 176 | pane.add(splitLeft, BorderLayout.CENTER); | 171 | setSourceType(SourceType.getDefault()); |
| 177 | splitLeft.resetToPreferredSizes(); | 172 | updateButtons(); |
| 178 | 173 | } | |
| 179 | // init bottom panel | 174 | |
| 180 | JPanel bottomPanel = new JPanel(); | 175 | protected void setSourceType(SourceType val) { |
| 181 | bottomPanel.setLayout(new FlowLayout()); | 176 | sourceType = val; |
| 182 | pane.add(bottomPanel, BorderLayout.SOUTH); | 177 | updateSourceClasses(); |
| 183 | 178 | } | |
| 184 | matchButton = new JButton(); | 179 | |
| 185 | unmatchableButton = new JButton(); | 180 | public void setSaveListener(SaveListener<T> val) { |
| 186 | 181 | saveListener = val; | |
| 187 | sourceLabel = new JLabel(); | 182 | } |
| 188 | bottomPanel.add(sourceLabel); | 183 | |
| 189 | bottomPanel.add(matchButton); | 184 | private void updateSourceClasses() { |
| 190 | bottomPanel.add(unmatchableButton); | 185 | |
| 191 | destLabel = new JLabel(); | 186 | String selectedPackage = sourceClasses.getSelectedPackage(); |
| 192 | bottomPanel.add(destLabel); | 187 | |
| 193 | 188 | List<ClassEntry> deobfClassEntries = Lists.newArrayList(); | |
| 194 | // show the frame | 189 | for (ClassEntry entry : sourceType.getObfSourceClasses(memberMatches)) { |
| 195 | pane.doLayout(); | 190 | deobfClassEntries.add(sourceDeobfuscator.deobfuscateEntry(entry)); |
| 196 | frame.setSize(1024, 576); | 191 | } |
| 197 | frame.setMinimumSize(new Dimension(640, 480)); | 192 | sourceClasses.setClasses(deobfClassEntries); |
| 198 | frame.setVisible(true); | 193 | |
| 199 | frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); | 194 | if (selectedPackage != null) { |
| 200 | 195 | sourceClasses.expandPackage(selectedPackage); | |
| 201 | unmatchedHighlightPainter = new ObfuscatedHighlightPainter(); | 196 | } |
| 202 | matchedHighlightPainter = new DeobfuscatedHighlightPainter(); | 197 | |
| 203 | 198 | for (SourceType sourceType : SourceType.values()) { | |
| 204 | // init state | 199 | sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", |
| 205 | saveListener = null; | 200 | sourceType.name(), sourceType.getObfSourceClasses(memberMatches).size() |
| 206 | obfSourceClass = null; | 201 | )); |
| 207 | obfDestClass = null; | 202 | } |
| 208 | obfSourceEntry = null; | 203 | } |
| 209 | obfDestEntry = null; | 204 | |
| 210 | setSourceType(SourceType.getDefault()); | 205 | protected void setSourceClass(ClassEntry sourceClass) { |
| 211 | updateButtons(); | 206 | |
| 212 | } | 207 | obfSourceClass = sourceDeobfuscator.obfuscateEntry(sourceClass); |
| 213 | 208 | obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); | |
| 214 | protected void setSourceType(SourceType val) { | 209 | if (obfDestClass == null) { |
| 215 | sourceType = val; | 210 | throw new Error("No matching dest class for source class: " + obfSourceClass); |
| 216 | updateSourceClasses(); | 211 | } |
| 217 | } | 212 | |
| 218 | 213 | sourceReader.decompileClass(obfSourceClass, sourceDeobfuscator, false, this::updateSourceHighlights); | |
| 219 | public void setSaveListener(SaveListener<T> val) { | 214 | destReader.decompileClass(obfDestClass, destDeobfuscator, false, this::updateDestHighlights); |
| 220 | saveListener = val; | 215 | } |
| 221 | } | 216 | |
| 222 | 217 | protected void updateSourceHighlights() { | |
| 223 | private void updateSourceClasses() { | 218 | highlightEntries(sourceReader, sourceDeobfuscator, memberMatches.matches().keySet(), memberMatches.getUnmatchedSourceEntries()); |
| 224 | 219 | } | |
| 225 | String selectedPackage = sourceClasses.getSelectedPackage(); | 220 | |
| 226 | 221 | protected void updateDestHighlights() { | |
| 227 | List<ClassEntry> deobfClassEntries = Lists.newArrayList(); | 222 | highlightEntries(destReader, destDeobfuscator, memberMatches.matches().values(), memberMatches.getUnmatchedDestEntries()); |
| 228 | for (ClassEntry entry : sourceType.getObfSourceClasses(memberMatches)) { | 223 | } |
| 229 | deobfClassEntries.add(sourceDeobfuscator.deobfuscateEntry(entry)); | 224 | |
| 230 | } | 225 | private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection<T> obfMatchedEntries, Collection<T> obfUnmatchedEntries) { |
| 231 | sourceClasses.setClasses(deobfClassEntries); | 226 | reader.clearHighlights(); |
| 232 | 227 | // matched fields | |
| 233 | if (selectedPackage != null) { | 228 | updateHighlighted(obfMatchedEntries, deobfuscator, reader, matchedHighlightPainter); |
| 234 | sourceClasses.expandPackage(selectedPackage); | 229 | // unmatched fields |
| 235 | } | 230 | updateHighlighted(obfUnmatchedEntries, deobfuscator, reader, unmatchedHighlightPainter); |
| 236 | 231 | } | |
| 237 | for (SourceType sourceType : SourceType.values()) { | 232 | |
| 238 | sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", | 233 | private void updateHighlighted(Collection<T> entries, Deobfuscator deobfuscator, CodeReader reader, HighlightPainter painter) { |
| 239 | sourceType.name(), sourceType.getObfSourceClasses(memberMatches).size() | 234 | SourceIndex index = reader.getSourceIndex(); |
| 240 | )); | 235 | for (T obfT : entries) { |
| 241 | } | 236 | T deobfT = deobfuscator.deobfuscateEntry(obfT); |
| 242 | } | 237 | Token token = index.getDeclarationToken(deobfT); |
| 243 | 238 | if (token != null) { | |
| 244 | protected void setSourceClass(ClassEntry sourceClass) { | 239 | reader.setHighlightedToken(token, painter); |
| 245 | 240 | } | |
| 246 | obfSourceClass = sourceDeobfuscator.obfuscateEntry(sourceClass); | 241 | } |
| 247 | obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); | 242 | } |
| 248 | if (obfDestClass == null) { | 243 | |
| 249 | throw new Error("No matching dest class for source class: " + obfSourceClass); | 244 | private boolean isSelectionMatched() { |
| 250 | } | 245 | return obfSourceEntry != null && obfDestEntry != null |
| 251 | 246 | && memberMatches.isMatched(obfSourceEntry, obfDestEntry); | |
| 252 | sourceReader.decompileClass(obfSourceClass, sourceDeobfuscator, false, this::updateSourceHighlights); | 247 | } |
| 253 | destReader.decompileClass(obfDestClass, destDeobfuscator, false, this::updateDestHighlights); | 248 | |
| 254 | } | 249 | protected void onSelectSource(Entry source) { |
| 255 | 250 | ||
| 256 | protected void updateSourceHighlights() { | 251 | // start with no selection |
| 257 | highlightEntries(sourceReader, sourceDeobfuscator, memberMatches.matches().keySet(), memberMatches.getUnmatchedSourceEntries()); | 252 | if (isSelectionMatched()) { |
| 258 | } | 253 | setDest(null); |
| 259 | 254 | } | |
| 260 | protected void updateDestHighlights() { | 255 | setSource(null); |
| 261 | highlightEntries(destReader, destDeobfuscator, memberMatches.matches().values(), memberMatches.getUnmatchedDestEntries()); | 256 | |
| 262 | } | 257 | // then look for a valid source selection |
| 263 | 258 | if (source != null) { | |
| 264 | private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection<T> obfMatchedEntries, Collection<T> obfUnmatchedEntries) { | 259 | |
| 265 | reader.clearHighlights(); | 260 | // this looks really scary, but it's actually ok |
| 266 | // matched fields | 261 | // Deobfuscator.obfuscateEntry can handle all implementations of Entry |
| 267 | updateHighlighted(obfMatchedEntries, deobfuscator, reader, matchedHighlightPainter); | 262 | // and MemberMatches.hasSource() will only pass entries that actually match T |
| 268 | // unmatched fields | 263 | @SuppressWarnings("unchecked") |
| 269 | updateHighlighted(obfUnmatchedEntries, deobfuscator, reader, unmatchedHighlightPainter); | 264 | T sourceEntry = (T) source; |
| 270 | } | 265 | |
| 271 | 266 | T obfSourceEntry = sourceDeobfuscator.obfuscateEntry(sourceEntry); | |
| 272 | private void updateHighlighted(Collection<T> entries, Deobfuscator deobfuscator, CodeReader reader, HighlightPainter painter) | 267 | if (memberMatches.hasSource(obfSourceEntry)) { |
| 273 | { | 268 | setSource(obfSourceEntry); |
| 274 | SourceIndex index = reader.getSourceIndex(); | 269 | |
| 275 | for (T obfT : entries) { | 270 | // look for a matched dest too |
| 276 | T deobfT = deobfuscator.deobfuscateEntry(obfT); | 271 | T obfDestEntry = memberMatches.matches().get(obfSourceEntry); |
| 277 | Token token = index.getDeclarationToken(deobfT); | 272 | if (obfDestEntry != null) { |
| 278 | if (token != null) { | 273 | setDest(obfDestEntry); |
| 279 | reader.setHighlightedToken(token, painter); | 274 | } |
| 280 | } | 275 | } |
| 281 | } | 276 | } |
| 282 | } | 277 | |
| 283 | 278 | updateButtons(); | |
| 284 | private boolean isSelectionMatched() { | 279 | } |
| 285 | return obfSourceEntry != null && obfDestEntry != null | 280 | |
| 286 | && memberMatches.isMatched(obfSourceEntry, obfDestEntry); | 281 | protected void onSelectDest(Entry dest) { |
| 287 | } | 282 | |
| 288 | 283 | // start with no selection | |
| 289 | protected void onSelectSource(Entry source) { | 284 | if (isSelectionMatched()) { |
| 290 | 285 | setSource(null); | |
| 291 | // start with no selection | 286 | } |
| 292 | if (isSelectionMatched()) { | 287 | setDest(null); |
| 293 | setDest(null); | 288 | |
| 294 | } | 289 | // then look for a valid dest selection |
| 295 | setSource(null); | 290 | if (dest != null) { |
| 296 | 291 | ||
| 297 | // then look for a valid source selection | 292 | // this looks really scary, but it's actually ok |
| 298 | if (source != null) { | 293 | // Deobfuscator.obfuscateEntry can handle all implementations of Entry |
| 299 | 294 | // and MemberMatches.hasSource() will only pass entries that actually match T | |
| 300 | // this looks really scary, but it's actually ok | 295 | @SuppressWarnings("unchecked") |
| 301 | // Deobfuscator.obfuscateEntry can handle all implementations of Entry | 296 | T destEntry = (T) dest; |
| 302 | // and MemberMatches.hasSource() will only pass entries that actually match T | 297 | |
| 303 | @SuppressWarnings("unchecked") | 298 | T obfDestEntry = destDeobfuscator.obfuscateEntry(destEntry); |
| 304 | T sourceEntry = (T) source; | 299 | if (memberMatches.hasDest(obfDestEntry)) { |
| 305 | 300 | setDest(obfDestEntry); | |
| 306 | T obfSourceEntry = sourceDeobfuscator.obfuscateEntry(sourceEntry); | 301 | |
| 307 | if (memberMatches.hasSource(obfSourceEntry)) { | 302 | // look for a matched source too |
| 308 | setSource(obfSourceEntry); | 303 | T obfSourceEntry = memberMatches.matches().inverse().get(obfDestEntry); |
| 309 | 304 | if (obfSourceEntry != null) { | |
| 310 | // look for a matched dest too | 305 | setSource(obfSourceEntry); |
| 311 | T obfDestEntry = memberMatches.matches().get(obfSourceEntry); | 306 | } |
| 312 | if (obfDestEntry != null) { | 307 | } |
| 313 | setDest(obfDestEntry); | 308 | } |
| 314 | } | 309 | |
| 315 | } | 310 | updateButtons(); |
| 316 | } | 311 | } |
| 317 | 312 | ||
| 318 | updateButtons(); | 313 | private void setSource(T obfEntry) { |
| 319 | } | 314 | if (obfEntry == null) { |
| 320 | 315 | obfSourceEntry = null; | |
| 321 | protected void onSelectDest(Entry dest) { | 316 | sourceLabel.setText(""); |
| 322 | 317 | } else { | |
| 323 | // start with no selection | 318 | obfSourceEntry = obfEntry; |
| 324 | if (isSelectionMatched()) { | 319 | sourceLabel.setText(getEntryLabel(obfEntry, sourceDeobfuscator)); |
| 325 | setSource(null); | 320 | } |
| 326 | } | 321 | } |
| 327 | setDest(null); | 322 | |
| 328 | 323 | private void setDest(T obfEntry) { | |
| 329 | // then look for a valid dest selection | 324 | if (obfEntry == null) { |
| 330 | if (dest != null) { | 325 | obfDestEntry = null; |
| 331 | 326 | destLabel.setText(""); | |
| 332 | // this looks really scary, but it's actually ok | 327 | } else { |
| 333 | // Deobfuscator.obfuscateEntry can handle all implementations of Entry | 328 | obfDestEntry = obfEntry; |
| 334 | // and MemberMatches.hasSource() will only pass entries that actually match T | 329 | destLabel.setText(getEntryLabel(obfEntry, destDeobfuscator)); |
| 335 | @SuppressWarnings("unchecked") | 330 | } |
| 336 | T destEntry = (T) dest; | 331 | } |
| 337 | 332 | ||
| 338 | T obfDestEntry = destDeobfuscator.obfuscateEntry(destEntry); | 333 | private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) { |
| 339 | if (memberMatches.hasDest(obfDestEntry)) { | 334 | // show obfuscated and deobfuscated names, but no types/signatures |
| 340 | setDest(obfDestEntry); | 335 | T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry); |
| 341 | 336 | return String.format("%s (%s)", deobfEntry.getName(), obfEntry.getName()); | |
| 342 | // look for a matched source too | 337 | } |
| 343 | T obfSourceEntry = memberMatches.matches().inverse().get(obfDestEntry); | 338 | |
| 344 | if (obfSourceEntry != null) { | 339 | private void updateButtons() { |
| 345 | setSource(obfSourceEntry); | 340 | |
| 346 | } | 341 | GuiTricks.deactivateButton(matchButton); |
| 347 | } | 342 | GuiTricks.deactivateButton(unmatchableButton); |
| 348 | } | 343 | |
| 349 | 344 | if (obfSourceEntry != null && obfDestEntry != null) { | |
| 350 | updateButtons(); | 345 | if (memberMatches.isMatched(obfSourceEntry, obfDestEntry)) |
| 351 | } | 346 | GuiTricks.activateButton(matchButton, "Unmatch", event -> unmatch()); |
| 352 | 347 | else if (!memberMatches.isMatchedSourceEntry(obfSourceEntry) && !memberMatches.isMatchedDestEntry( | |
| 353 | private void setSource(T obfEntry) { | 348 | obfDestEntry)) |
| 354 | if (obfEntry == null) { | 349 | GuiTricks.activateButton(matchButton, "Match", event -> match()); |
| 355 | obfSourceEntry = null; | 350 | } else if (obfSourceEntry != null) |
| 356 | sourceLabel.setText(""); | 351 | GuiTricks.activateButton(unmatchableButton, "Set Unmatchable", event -> unmatchable()); |
| 357 | } else { | 352 | } |
| 358 | obfSourceEntry = obfEntry; | 353 | |
| 359 | sourceLabel.setText(getEntryLabel(obfEntry, sourceDeobfuscator)); | 354 | protected void match() { |
| 360 | } | 355 | |
| 361 | } | 356 | // update the field matches |
| 362 | 357 | memberMatches.makeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); | |
| 363 | private void setDest(T obfEntry) { | 358 | save(); |
| 364 | if (obfEntry == null) { | 359 | |
| 365 | obfDestEntry = null; | 360 | // update the ui |
| 366 | destLabel.setText(""); | 361 | onSelectSource(null); |
| 367 | } else { | 362 | onSelectDest(null); |
| 368 | obfDestEntry = obfEntry; | 363 | updateSourceHighlights(); |
| 369 | destLabel.setText(getEntryLabel(obfEntry, destDeobfuscator)); | 364 | updateDestHighlights(); |
| 370 | } | 365 | updateSourceClasses(); |
| 371 | } | 366 | } |
| 372 | 367 | ||
| 373 | private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) { | 368 | protected void unmatch() { |
| 374 | // show obfuscated and deobfuscated names, but no types/signatures | 369 | |
| 375 | T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry); | 370 | // update the field matches |
| 376 | return String.format("%s (%s)", deobfEntry.getName(), obfEntry.getName()); | 371 | memberMatches.unmakeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); |
| 377 | } | 372 | save(); |
| 378 | 373 | ||
| 379 | private void updateButtons() { | 374 | // update the ui |
| 380 | 375 | onSelectSource(null); | |
| 381 | GuiTricks.deactivateButton(matchButton); | 376 | onSelectDest(null); |
| 382 | GuiTricks.deactivateButton(unmatchableButton); | 377 | updateSourceHighlights(); |
| 383 | 378 | updateDestHighlights(); | |
| 384 | if (obfSourceEntry != null && obfDestEntry != null) { | 379 | updateSourceClasses(); |
| 385 | if (memberMatches.isMatched(obfSourceEntry, obfDestEntry)) | 380 | } |
| 386 | GuiTricks.activateButton(matchButton, "Unmatch", event -> unmatch()); | 381 | |
| 387 | else if (!memberMatches.isMatchedSourceEntry(obfSourceEntry) && !memberMatches.isMatchedDestEntry( | 382 | protected void unmatchable() { |
| 388 | obfDestEntry)) | 383 | |
| 389 | GuiTricks.activateButton(matchButton, "Match", event -> match()); | 384 | // update the field matches |
| 390 | } else if (obfSourceEntry != null) | 385 | memberMatches.makeSourceUnmatchable(obfSourceEntry, sourceDeobfuscator); |
| 391 | GuiTricks.activateButton(unmatchableButton, "Set Unmatchable", event -> unmatchable()); | 386 | save(); |
| 392 | } | 387 | |
| 393 | 388 | // update the ui | |
| 394 | protected void match() { | 389 | onSelectSource(null); |
| 395 | 390 | onSelectDest(null); | |
| 396 | // update the field matches | 391 | updateSourceHighlights(); |
| 397 | memberMatches.makeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); | 392 | updateDestHighlights(); |
| 398 | save(); | 393 | updateSourceClasses(); |
| 399 | 394 | } | |
| 400 | // update the ui | 395 | |
| 401 | onSelectSource(null); | 396 | private void save() { |
| 402 | onSelectDest(null); | 397 | if (saveListener != null) { |
| 403 | updateSourceHighlights(); | 398 | saveListener.save(memberMatches); |
| 404 | updateDestHighlights(); | 399 | } |
| 405 | updateSourceClasses(); | 400 | } |
| 406 | } | 401 | |
| 407 | 402 | private enum SourceType { | |
| 408 | protected void unmatch() { | 403 | Matched { |
| 409 | 404 | @Override | |
| 410 | // update the field matches | 405 | public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { |
| 411 | memberMatches.unmakeMatch(obfSourceEntry, obfDestEntry, sourceDeobfuscator, destDeobfuscator); | 406 | return matches.getSourceClassesWithoutUnmatchedEntries(); |
| 412 | save(); | 407 | } |
| 413 | 408 | }, | |
| 414 | // update the ui | 409 | Unmatched { |
| 415 | onSelectSource(null); | 410 | @Override |
| 416 | onSelectDest(null); | 411 | public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) { |
| 417 | updateSourceHighlights(); | 412 | return matches.getSourceClassesWithUnmatchedEntries(); |
| 418 | updateDestHighlights(); | 413 | } |
| 419 | updateSourceClasses(); | 414 | }; |
| 420 | } | 415 | |
| 421 | 416 | public static SourceType getDefault() { | |
| 422 | protected void unmatchable() { | 417 | return values()[0]; |
| 423 | 418 | } | |
| 424 | // update the field matches | 419 | |
| 425 | memberMatches.makeSourceUnmatchable(obfSourceEntry, sourceDeobfuscator); | 420 | public JRadioButton newRadio(ActionListener listener, ButtonGroup group) { |
| 426 | save(); | 421 | JRadioButton button = new JRadioButton(name(), this == getDefault()); |
| 427 | 422 | button.setActionCommand(name()); | |
| 428 | // update the ui | 423 | button.addActionListener(listener); |
| 429 | onSelectSource(null); | 424 | group.add(button); |
| 430 | onSelectDest(null); | 425 | return button; |
| 431 | updateSourceHighlights(); | 426 | } |
| 432 | updateDestHighlights(); | 427 | |
| 433 | updateSourceClasses(); | 428 | public abstract <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches); |
| 434 | } | 429 | } |
| 435 | 430 | ||
| 436 | private void save() { | 431 | public interface SaveListener<T extends Entry> { |
| 437 | if (saveListener != null) { | 432 | void save(MemberMatches<T> matches); |
| 438 | saveListener.save(memberMatches); | 433 | } |
| 439 | } | ||
| 440 | } | ||
| 441 | } | 434 | } |