From 9f7432134c4fccd5dcda4a7f505ad3cc8cab7a69 Mon Sep 17 00:00:00 2001 From: Skylot Date: Tue, 28 Feb 2023 16:04:13 +0000 Subject: [PATCH] feat(gui): show loaded mapping file in input nodes --- .../main/java/jadx/api/data/ICodeData.java | 2 + .../java/jadx/api/data/impl/JadxCodeData.java | 5 + .../java/jadx/gui/treemodel/JInputFile.java | 5 + .../jadx/gui/treemodel/JInputMapping.java | 99 +++++++++++++++++++ .../java/jadx/gui/treemodel/JInputScript.java | 5 + .../main/java/jadx/gui/treemodel/JInputs.java | 10 +- .../src/main/java/jadx/gui/ui/MainWindow.java | 21 ++-- .../icons/nodes/abbreviatePackageNames.svg | 7 ++ .../mappings/load/MappingsVisitor.java | 8 +- 9 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 jadx-gui/src/main/java/jadx/gui/treemodel/JInputMapping.java create mode 100644 jadx-gui/src/main/resources/icons/nodes/abbreviatePackageNames.svg diff --git a/jadx-core/src/main/java/jadx/api/data/ICodeData.java b/jadx-core/src/main/java/jadx/api/data/ICodeData.java index 17518359d..96ac1764c 100644 --- a/jadx-core/src/main/java/jadx/api/data/ICodeData.java +++ b/jadx-core/src/main/java/jadx/api/data/ICodeData.java @@ -7,4 +7,6 @@ public interface ICodeData { List getComments(); List getRenames(); + + boolean isEmpty(); } diff --git a/jadx-core/src/main/java/jadx/api/data/impl/JadxCodeData.java b/jadx-core/src/main/java/jadx/api/data/impl/JadxCodeData.java index ccc60e6e6..c0a149926 100644 --- a/jadx-core/src/main/java/jadx/api/data/impl/JadxCodeData.java +++ b/jadx-core/src/main/java/jadx/api/data/impl/JadxCodeData.java @@ -28,4 +28,9 @@ public class JadxCodeData implements ICodeData { public void setRenames(List renames) { this.renames = renames; } + + @Override + public boolean isEmpty() { + return comments.isEmpty() && renames.isEmpty(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputFile.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputFile.java index 98f576907..9378c6d29 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputFile.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputFile.java @@ -40,4 +40,9 @@ public class JInputFile extends JNode { public String makeString() { return filePath.getFileName().toString(); } + + @Override + public String getTooltip() { + return filePath.normalize().toAbsolutePath().toString(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputMapping.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputMapping.java new file mode 100644 index 000000000..776a15eb9 --- /dev/null +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputMapping.java @@ -0,0 +1,99 @@ +package jadx.gui.treemodel; + +import java.nio.file.Path; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JPopupMenu; + +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jadx.api.ICodeInfo; +import jadx.api.impl.SimpleCodeInfo; +import jadx.core.utils.exceptions.JadxRuntimeException; +import jadx.core.utils.files.FileUtils; +import jadx.gui.ui.MainWindow; +import jadx.gui.ui.TabbedPane; +import jadx.gui.ui.codearea.CodeContentPanel; +import jadx.gui.ui.panel.ContentPanel; +import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; +import jadx.gui.utils.ui.SimpleMenuItem; + +public class JInputMapping extends JEditableNode { + private static final Logger LOG = LoggerFactory.getLogger(JInputMapping.class); + + private static final ImageIcon MAPPING_ICON = UiUtils.openSvgIcon("nodes/abbreviatePackageNames"); + + private final Path mappingPath; + private final String name; + + public JInputMapping(Path mappingPath) { + this.mappingPath = mappingPath; + this.name = mappingPath.getFileName().toString(); + } + + @Override + public ContentPanel getContentPanel(TabbedPane tabbedPane) { + return new CodeContentPanel(tabbedPane, this); + } + + @Override + public @NotNull ICodeInfo getCodeInfo() { + try { + return new SimpleCodeInfo(FileUtils.readFile(mappingPath)); + } catch (Exception e) { + throw new JadxRuntimeException("Failed to read mapping file: " + mappingPath.toAbsolutePath(), e); + } + } + + @Override + public void save(String newContent) { + try { + FileUtils.writeFile(mappingPath, newContent); + LOG.debug("Mapping saved: {}", mappingPath.toAbsolutePath()); + } catch (Exception e) { + throw new JadxRuntimeException("Failed to write mapping file: " + mappingPath.toAbsolutePath(), e); + } + } + + @Override + public JPopupMenu onTreePopupMenu(MainWindow mainWindow) { + JPopupMenu menu = new JPopupMenu(); + menu.add(new SimpleMenuItem(NLS.str("popup.remove"), mainWindow::closeMappingsAndRemoveFromProject)); + return menu; + } + + @Override + public String getSyntaxName() { + return SyntaxConstants.SYNTAX_STYLE_NONE; + } + + @Override + public JClass getJParent() { + return null; + } + + @Override + public Icon getIcon() { + return MAPPING_ICON; + } + + @Override + public String getName() { + return name; + } + + @Override + public String makeString() { + return name; + } + + @Override + public String getTooltip() { + return mappingPath.normalize().toAbsolutePath().toString(); + } +} diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputScript.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputScript.java index 37861e825..a1595a8a0 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputScript.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputScript.java @@ -93,4 +93,9 @@ public class JInputScript extends JEditableNode { public String makeString() { return name; } + + @Override + public String getTooltip() { + return scriptPath.normalize().toAbsolutePath().toString(); + } } diff --git a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java index be8d94392..22d9d10b0 100644 --- a/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java +++ b/jadx-gui/src/main/java/jadx/gui/treemodel/JInputs.java @@ -1,5 +1,6 @@ package jadx.gui.treemodel; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Iterator; @@ -10,6 +11,7 @@ import javax.swing.ImageIcon; import jadx.core.utils.files.FileUtils; import jadx.gui.JadxWrapper; +import jadx.gui.settings.JadxProject; import jadx.gui.utils.NLS; import jadx.gui.utils.UiUtils; @@ -17,7 +19,8 @@ public class JInputs extends JNode { private static final ImageIcon INPUTS_ICON = UiUtils.openSvgIcon("nodes/projectStructure"); public JInputs(JadxWrapper wrapper) { - List inputs = wrapper.getProject().getFilePaths(); + JadxProject project = wrapper.getProject(); + List inputs = project.getFilePaths(); List files = FileUtils.expandDirs(inputs); List scripts = new ArrayList<>(); Iterator it = files.iterator(); @@ -31,6 +34,11 @@ public class JInputs extends JNode { add(new JInputFiles(files)); add(new JInputScripts(scripts)); + + Path mappingsPath = project.getMappingsPath(); + if (mappingsPath != null && Files.isRegularFile(mappingsPath)) { + add(new JInputMapping(mappingsPath)); + } } @Override diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 7808b5e8f..17ca39675 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -410,7 +410,7 @@ public class MainWindow extends JFrame { reopen(); } - private void closeMappingsAndRemoveFromProject() { + public void closeMappingsAndRemoveFromProject() { project.setMappingsPath(null); currentMappingFormat = null; } @@ -718,9 +718,8 @@ public class MainWindow extends JFrame { saveProjectAction.setEnabled(loaded && !project.isSaved()); openMappingsMenu.setEnabled(loaded); saveMappingsAction.setEnabled(loaded && renamesChanged && project.getMappingsPath() != null); - saveMappingsAsMenu.setEnabled(loaded - && (!project.getCodeData().getRenames().isEmpty() || !project.getCodeData().getComments().isEmpty())); - closeMappingsAction.setEnabled(loaded && project.getMappingsPath() != null); + saveMappingsAsMenu.setEnabled(loaded && !project.getCodeData().isEmpty()); + closeMappingsAction.setEnabled(project.getMappingsPath() != null); deobfToggleBtn.setSelected(settings.isDeobfuscationOn()); Path projectPath = project.getProjectPath(); @@ -1013,6 +1012,9 @@ public class MainWindow extends JFrame { liveReloadMenuItem = new JCheckBoxMenuItem(liveReload); liveReloadMenuItem.setState(project.isEnableLiveReload()); + ActionHandler openProGuardMappings = new ActionHandler(ev -> openMappings(MappingFormat.PROGUARD)); + openProGuardMappings.setNameAndDesc("Proguard"); + Action openTiny2Mappings = new AbstractAction("Tiny v2 file") { @Override public void actionPerformed(ActionEvent e) { @@ -1038,6 +1040,7 @@ public class MainWindow extends JFrame { openEnigmaDirMappings.putValue(Action.SHORT_DESCRIPTION, "Enigma directory"); openMappingsMenu = new JMenu(NLS.str("file.open_mappings")); + openMappingsMenu.add(openProGuardMappings); openMappingsMenu.add(openTiny2Mappings); openMappingsMenu.add(openEnigmaMappings); openMappingsMenu.add(openEnigmaDirMappings); @@ -1050,6 +1053,9 @@ public class MainWindow extends JFrame { }; saveMappingsAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.save_mappings")); + ActionHandler saveProGuardMappings = new ActionHandler(ev -> saveMappingsAs(MappingFormat.PROGUARD)); + saveProGuardMappings.setNameAndDesc("Proguard"); + Action saveMappingsAsTiny2 = new AbstractAction("Tiny v2 file") { @Override public void actionPerformed(ActionEvent e) { @@ -1075,6 +1081,7 @@ public class MainWindow extends JFrame { saveMappingsAsEnigmaDir.putValue(Action.SHORT_DESCRIPTION, "Enigma directory"); saveMappingsAsMenu = new JMenu(NLS.str("file.save_mappings_as")); + saveMappingsAsMenu.add(saveProGuardMappings); saveMappingsAsMenu.add(saveMappingsAsTiny2); saveMappingsAsMenu.add(saveMappingsAsEnigma); saveMappingsAsMenu.add(saveMappingsAsEnigmaDir); @@ -1765,8 +1772,10 @@ public class MainWindow extends JFrame { public void destroyDebuggerPanel() { saveSplittersInfo(); - debuggerPanel.setVisible(false); - debuggerPanel = null; + if (debuggerPanel != null) { + debuggerPanel.setVisible(false); + debuggerPanel = null; + } } public void showHeapUsageBar() { diff --git a/jadx-gui/src/main/resources/icons/nodes/abbreviatePackageNames.svg b/jadx-gui/src/main/resources/icons/nodes/abbreviatePackageNames.svg new file mode 100644 index 000000000..4d540c156 --- /dev/null +++ b/jadx-gui/src/main/resources/icons/nodes/abbreviatePackageNames.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java index d0973d4b0..e419c8ba9 100644 --- a/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java +++ b/jadx-plugins/jadx-rename-mappings/src/main/java/jadx/plugins/mappings/load/MappingsVisitor.java @@ -40,11 +40,11 @@ public class MappingsVisitor implements JadxPreparePass { private void process(RootNode root) { for (ClassNode cls : root.getClasses()) { - ClassMapping mapping = mappingTree.getClass(cls.getClassInfo().makeRawFullName().replace('.', '/')); - if (mapping == null) { - continue; + String clsRawName = cls.getClassInfo().makeRawFullName().replace('.', '/'); + ClassMapping mapping = mappingTree.getClass(clsRawName); + if (mapping != null) { + processClass(cls, mapping); } - processClass(cls, mapping); } }