diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java index 4b9fa5952..66af1855c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/ClassSelector.java @@ -21,6 +21,7 @@ import java.util.Comparator; import java.util.EventObject; import java.util.List; +import java.util.Map; import javax.swing.JTree; import javax.swing.event.CellEditorListener; @@ -33,6 +34,7 @@ import javax.swing.tree.TreePath; import cuchaz.enigma.gui.node.ClassSelectorClassNode; +import cuchaz.enigma.gui.panels.classlists.ClassPanel; import cuchaz.enigma.gui.util.GuiUtil; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.utils.validation.ValidationContext; @@ -40,6 +42,7 @@ public class ClassSelector extends JTree { public static final Comparator DEOBF_CLASS_COMPARATOR = Comparator.comparing(ClassEntry::getFullName); + private final ClassPanel parentPanel; private final Comparator comparator; private final GuiController controller; @@ -47,9 +50,10 @@ public class ClassSelector extends JTree { private ClassSelectionListener selectionListener; private RenameSelectionListener renameSelectionListener; - public ClassSelector(Gui gui, Comparator comparator, boolean isRenamable) { - this.comparator = comparator; + public ClassSelector(ClassPanel panel, Gui gui, Comparator comparator, boolean isRenamable) { + this.parentPanel = panel; this.controller = gui.getController(); + this.comparator = comparator; // configure the tree control setEditable(true); @@ -153,7 +157,7 @@ public void editingStopped(ChangeEvent e) { Object prevData = node.getUserObject(); Object objectData = node.getUserObject() instanceof ClassEntry ? new ClassEntry(((ClassEntry) prevData).getPackageName() + "/" + data) : data; gui.validateImmediateAction(vc -> { - renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node); + renameSelectionListener.onSelectionRename(vc, node.getUserObject(), objectData, node, parentPanel); if (vc.canProceed()) { node.setUserObject(objectData); // Make sure that it's modified @@ -212,6 +216,13 @@ public ClassEntry getSelectedClass() { return null; } + public int getClassesCount() { + return packageManager == null ? 0 : Math.toIntExact(packageManager.getClassToNodeMap().entrySet() + .stream() + .map(Map.Entry::getKey) + .count()); + } + public enum State { EXPANDED, SELECTED @@ -300,6 +311,6 @@ public interface ClassSelectionListener { } public interface RenameSelectionListener { - void onSelectionRename(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node); + void onSelectionRename(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node, ClassPanel panel); } } diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java index b3117ce22..e1e6b0787 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/Gui.java @@ -57,11 +57,13 @@ import cuchaz.enigma.gui.elements.MainWindow; import cuchaz.enigma.gui.elements.MenuBar; import cuchaz.enigma.gui.elements.ValidatableUi; -import cuchaz.enigma.gui.panels.DeobfPanel; import cuchaz.enigma.gui.panels.EditorPanel; import cuchaz.enigma.gui.panels.IdentifierPanel; -import cuchaz.enigma.gui.panels.ObfPanel; import cuchaz.enigma.gui.panels.StructurePanel; +import cuchaz.enigma.gui.panels.classlists.ClassPanel; +import cuchaz.enigma.gui.panels.classlists.FullDeobfPanel; +import cuchaz.enigma.gui.panels.classlists.ObfPanel; +import cuchaz.enigma.gui.panels.classlists.PartialDeobfPanel; import cuchaz.enigma.gui.renderer.MessageListCellRenderer; import cuchaz.enigma.gui.util.GuiUtil; import cuchaz.enigma.gui.util.LanguageUtil; @@ -73,6 +75,7 @@ import cuchaz.enigma.translation.mapping.EntryRemapper; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.Entry; +import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; import cuchaz.enigma.utils.I18n; import cuchaz.enigma.utils.validation.ParameterizedMessage; import cuchaz.enigma.utils.validation.ValidationContext; @@ -88,7 +91,8 @@ public class Gui { private final MenuBar menuBar; private final ObfPanel obfPanel; - private final DeobfPanel deobfPanel; + private final PartialDeobfPanel partialDeobfPanel; + private final FullDeobfPanel fullDeobfPanel; private final IdentifierPanel infoPanel; private final StructurePanel structurePanel; private final InheritanceTree inheritanceTree; @@ -98,7 +102,8 @@ public class Gui { private final EditorTabbedPane editorTabbedPane; private final JPanel classesPanel = new JPanel(new BorderLayout()); - private final JSplitPane splitClasses; + private final JSplitPane splitObfAndDeobf; + private final JSplitPane splitPartialDeobfAndFullDeobf; private final JTabbedPane tabs = new JTabbedPane(); private final CollapsibleTabbedPane logTabs = new CollapsibleTabbedPane(JTabbedPane.BOTTOM); private final JSplitPane logSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, tabs, logTabs); @@ -127,15 +132,17 @@ public Gui(EnigmaProfile profile, Set editableTypes) { this.editableTypes = editableTypes; this.controller = new GuiController(this, profile); this.structurePanel = new StructurePanel(this); - this.deobfPanel = new DeobfPanel(this); - this.infoPanel = new IdentifierPanel(this); this.obfPanel = new ObfPanel(this); + this.partialDeobfPanel = new PartialDeobfPanel(this); + this.fullDeobfPanel = new FullDeobfPanel(this); + this.infoPanel = new IdentifierPanel(this); this.menuBar = new MenuBar(this); this.inheritanceTree = new InheritanceTree(this); this.implementationsTree = new ImplementationsTree(this); this.callsTree = new CallsTree(this); this.editorTabbedPane = new EditorTabbedPane(this); - this.splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.deobfPanel); + this.splitPartialDeobfAndFullDeobf = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.partialDeobfPanel, this.fullDeobfPanel); + this.splitObfAndDeobf = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, this.obfPanel, this.splitPartialDeobfAndFullDeobf); this.setupUi(); @@ -157,7 +164,11 @@ private void setupUi() { this.exportJarFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - this.splitClasses.setResizeWeight(0.3); + // obfPanel gets 33% of screen height + this.splitObfAndDeobf.setResizeWeight(0.33); + // The two deobfPanels equally share the remaining 66% + this.splitPartialDeobfAndFullDeobf.setResizeWeight(0.5); + this.classesPanel.setPreferredSize(ScaleUtil.getDimension(250, 0)); // layout controls @@ -200,11 +211,12 @@ public void actionPerformed(ActionEvent e) { // restore state int[] layout = UiConfig.getLayout(); - if (layout.length >= 4) { - this.splitClasses.setDividerLocation(layout[0]); - this.splitCenter.setDividerLocation(layout[1]); - this.splitRight.setDividerLocation(layout[2]); - this.logSplit.setDividerLocation(layout[3]); + if (layout.length >= 5) { + this.splitObfAndDeobf.setDividerLocation(layout[0]); + this.splitPartialDeobfAndFullDeobf.setDividerLocation(layout[1]); + this.splitCenter.setDividerLocation(layout[2]); + this.splitRight.setDividerLocation(layout[3]); + this.logSplit.setDividerLocation(layout[4]); } this.mainWindow.statusBar().addPermanentComponent(this.connectionStatusLabel); @@ -246,7 +258,13 @@ public GuiController getController() { public void setSingleClassTree(boolean singleClassTree) { this.singleClassTree = singleClassTree; this.classesPanel.removeAll(); - this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses); + + if (isSingleClassTree()) { + this.classesPanel.add(fullDeobfPanel); + } else { + this.classesPanel.add(splitObfAndDeobf); + } + getController().refreshClasses(); retranslateUi(); } @@ -264,7 +282,13 @@ public void onFinishOpenJar(String jarName) { // update gui this.mainWindow.setTitle(Enigma.NAME + " - " + jarName); this.classesPanel.removeAll(); - this.classesPanel.add(isSingleClassTree() ? deobfPanel : splitClasses); + + if (isSingleClassTree()) { + this.classesPanel.add(fullDeobfPanel); + } else { + this.classesPanel.add(splitObfAndDeobf); + } + this.editorTabbedPane.closeAllEditorTabs(); // update menu @@ -278,7 +302,8 @@ public void onCloseJar() { // update gui this.mainWindow.setTitle(Enigma.NAME); setObfClasses(null); - setDeobfClasses(null); + setPartiallyDeobfClasses(null); + setFullyDeobfClasses(null); this.editorTabbedPane.closeAllEditorTabs(); this.classesPanel.removeAll(); @@ -313,11 +338,18 @@ public void showReference(EntryReference, Entry> reference) { } public void setObfClasses(Collection obfClasses) { - this.obfPanel.obfClasses.setClasses(obfClasses); + this.obfPanel.classes.setClasses(obfClasses); + this.obfPanel.updateCounter(); } - public void setDeobfClasses(Collection deobfClasses) { - this.deobfPanel.deobfClasses.setClasses(deobfClasses); + public void setPartiallyDeobfClasses(Collection partiallyDeobfClasses) { + this.partialDeobfPanel.classes.setClasses(partiallyDeobfClasses); + this.partialDeobfPanel.updateCounter(); + } + + public void setFullyDeobfClasses(Collection fullyDeobfClasses) { + this.fullDeobfPanel.classes.setClasses(fullyDeobfClasses); + this.fullDeobfPanel.updateCounter(); } public void setMappingsFile(Path path) { @@ -464,7 +496,12 @@ public void close() { private void exit() { UiConfig.setWindowPos("Main Window", this.mainWindow.frame().getLocationOnScreen()); UiConfig.setWindowSize("Main Window", this.mainWindow.frame().getSize()); - UiConfig.setLayout(this.splitClasses.getDividerLocation(), this.splitCenter.getDividerLocation(), this.splitRight.getDividerLocation(), this.logSplit.getDividerLocation()); + UiConfig.setLayout( + this.splitObfAndDeobf.getDividerLocation(), + this.splitPartialDeobfAndFullDeobf.getDividerLocation(), + this.splitCenter.getDividerLocation(), + this.splitRight.getDividerLocation(), + this.logSplit.getDividerLocation()); UiConfig.save(); if (searchDialog != null) { @@ -482,7 +519,7 @@ public void redraw() { frame.repaint(); } - public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node) { + public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object data, DefaultMutableTreeNode node, ClassPanel panel) { if (data instanceof String) { // package rename for (int i = 0; i < node.getChildCount(); i++) { @@ -490,12 +527,11 @@ public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); - onRenameFromClassTree(vc, prevDataChild, dataChild, node); + onRenameFromClassTree(vc, prevDataChild, dataChild, node, panel); } node.setUserObject(data); - // Ob package will never be modified, just reload deob view - this.deobfPanel.deobfClasses.reload(); + panel.reload(); } else if (data instanceof ClassEntry) { // class rename @@ -511,48 +547,99 @@ public void onRenameFromClassTree(ValidationContext vc, Object prevData, Object } } - public void moveClassTree(Entry obfEntry, String newName) { + public enum RenameDirection { + OBF_TO_DEOBF, + OBF_TO_OBF, + DEOBF_TO_OBF, + DEOBF_TO_DEOBF + } + + public void moveClassTreeIfNecessary(Entry obfEntry, String newName) { String oldEntry = obfEntry.getContainingClass().getPackageName(); String newEntry = new ClassEntry(newName).getPackageName(); - moveClassTree(obfEntry, oldEntry == null, newEntry == null); + RenameDirection direction = null; + + if (oldEntry == null && newEntry != null) { + direction = RenameDirection.OBF_TO_DEOBF; + } else if (oldEntry == null && newEntry == null) { + direction = RenameDirection.OBF_TO_OBF; + } else if (oldEntry != null && newEntry == null) { + direction = RenameDirection.DEOBF_TO_OBF; + } else if (oldEntry != null && newEntry != null) { + direction = RenameDirection.DEOBF_TO_DEOBF; + } + + moveClassTreeIfNecessary(obfEntry, direction); } // TODO: getExpansionState will *not* actually update itself based on name changes! - public void moveClassTree(Entry obfEntry, boolean isOldOb, boolean isNewOb) { - ClassEntry classEntry = obfEntry.getContainingClass(); - - List stateDeobf = this.deobfPanel.deobfClasses.getExpansionState(); - List stateObf = this.obfPanel.obfClasses.getExpansionState(); - - // Ob -> deob - if (!isNewOb) { - this.deobfPanel.deobfClasses.moveClassIn(classEntry); - this.obfPanel.obfClasses.removeEntry(classEntry); - this.deobfPanel.deobfClasses.reload(); - this.obfPanel.obfClasses.reload(); - } else if (!isOldOb) { // Deob -> ob - this.obfPanel.obfClasses.moveClassIn(classEntry); - this.deobfPanel.deobfClasses.removeEntry(classEntry); - this.deobfPanel.deobfClasses.reload(); - this.obfPanel.obfClasses.reload(); - } else if (isOldOb) { // Local move - this.obfPanel.obfClasses.moveClassIn(classEntry); - this.obfPanel.obfClasses.reload(); - } else { - this.deobfPanel.deobfClasses.moveClassIn(classEntry); - this.deobfPanel.deobfClasses.reload(); + public void moveClassTreeIfNecessary(Entry modifiedEntry, RenameDirection entryRenameDirection) { + ClassEntry classEntry = modifiedEntry.getTopLevelClass(); + + // Local variables aren't indexed, so them being (de)obfuscated can't be safely checked + // in all places. As a workaround, we simply ignore them, so their mapping status + // doesn't contribute to the mapped/unmapped status of their parent classes. + if (modifiedEntry instanceof LocalVariableEntry) { + return; } - this.deobfPanel.deobfClasses.restoreExpansionState(stateDeobf); - this.obfPanel.obfClasses.restoreExpansionState(stateObf); + List statePartialDeobf = partialDeobfPanel.classes.getExpansionState(); + List stateFullDeobf = fullDeobfPanel.classes.getExpansionState(); + List stateObf = obfPanel.classes.getExpansionState(); + + switch (entryRenameDirection) { + case OBF_TO_DEOBF: + obfPanel.classes.removeEntry(classEntry); + obfPanel.reload(); + + case DEOBF_TO_DEOBF: + if (controller.project.isFullyDeobfuscated(classEntry)) { + partialDeobfPanel.classes.removeEntry(classEntry); + fullDeobfPanel.classes.moveClassIn(classEntry); + fullDeobfPanel.classes.setSelectionClass(classEntry); + } else { + fullDeobfPanel.classes.removeEntry(classEntry); + partialDeobfPanel.classes.moveClassIn(classEntry); + partialDeobfPanel.classes.setSelectionClass(classEntry); + } + + partialDeobfPanel.reload(); + fullDeobfPanel.reload(); + break; + + case DEOBF_TO_OBF: + if (controller.project.isAtLeastPartiallyDeobfuscated(classEntry)) { + moveClassTreeIfNecessary(modifiedEntry, RenameDirection.DEOBF_TO_DEOBF); + break; + } + + partialDeobfPanel.classes.removeEntry(classEntry); + fullDeobfPanel.classes.removeEntry(classEntry); + partialDeobfPanel.reload(); + fullDeobfPanel.reload(); + + case OBF_TO_OBF: + obfPanel.classes.moveClassIn(classEntry); + obfPanel.classes.setSelectionClass(classEntry); + obfPanel.reload(); + break; + } + + obfPanel.classes.restoreExpansionState(stateObf); + partialDeobfPanel.classes.restoreExpansionState(statePartialDeobf); + fullDeobfPanel.classes.restoreExpansionState(stateFullDeobf); } public ObfPanel getObfPanel() { return obfPanel; } - public DeobfPanel getDeobfPanel() { - return deobfPanel; + public PartialDeobfPanel getPartialDeobfPanel() { + return partialDeobfPanel; + } + + public FullDeobfPanel getFullDeobfPanel() { + return fullDeobfPanel; } public SearchDialog getSearchDialog() { @@ -627,7 +714,8 @@ public void retranslateUi() { this.menuBar.retranslateUi(); this.obfPanel.retranslateUi(); - this.deobfPanel.retranslateUi(); + this.partialDeobfPanel.retranslateUi(); + this.fullDeobfPanel.retranslateUi(); this.infoPanel.retranslateUi(); this.structurePanel.retranslateUi(); this.editorTabbedPane.retranslateUi(); diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 0eb9a167a..aad23cf5b 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java @@ -43,10 +43,10 @@ import cuchaz.enigma.analysis.MethodReferenceTreeNode; import cuchaz.enigma.analysis.StructureTreeNode; import cuchaz.enigma.analysis.StructureTreeOptions; -import cuchaz.enigma.api.service.ObfuscationTestService; import cuchaz.enigma.classhandle.ClassHandle; import cuchaz.enigma.classhandle.ClassHandleProvider; import cuchaz.enigma.classprovider.ClasspathClassProvider; +import cuchaz.enigma.gui.Gui.RenameDirection; import cuchaz.enigma.gui.config.NetConfig; import cuchaz.enigma.gui.config.UiConfig; import cuchaz.enigma.gui.dialog.ProgressDialog; @@ -67,7 +67,6 @@ import cuchaz.enigma.source.DecompilerService; import cuchaz.enigma.source.SourceIndex; import cuchaz.enigma.source.Token; -import cuchaz.enigma.translation.TranslateResult; import cuchaz.enigma.translation.Translator; import cuchaz.enigma.translation.mapping.EntryChange; import cuchaz.enigma.translation.mapping.EntryMapping; @@ -393,40 +392,30 @@ public void refreshClasses() { } List obfClasses = Lists.newArrayList(); - List deobfClasses = Lists.newArrayList(); - this.addSeparatedClasses(obfClasses, deobfClasses); + List partiallyDeobfClasses = Lists.newArrayList(); + List fullyDeobfClasses = Lists.newArrayList(); + this.addSeparatedClasses(obfClasses, partiallyDeobfClasses, fullyDeobfClasses); this.gui.setObfClasses(obfClasses); - this.gui.setDeobfClasses(deobfClasses); + this.gui.setPartiallyDeobfClasses(partiallyDeobfClasses); + this.gui.setFullyDeobfClasses(fullyDeobfClasses); } - public void addSeparatedClasses(List obfClasses, List deobfClasses) { - EntryRemapper mapper = project.getMapper(); - + public void addSeparatedClasses(List obfClasses, List partiallyDeobfClasses, List fullyDeobfClasses) { Collection classes = project.getJarIndex().getEntryIndex().getClasses(); Stream visibleClasses = classes.stream().filter(entry -> !entry.isInnerClass()); visibleClasses.forEach(entry -> { if (gui.isSingleClassTree()) { - deobfClasses.add(entry); + fullyDeobfClasses.add(entry); return; } - TranslateResult result = mapper.extendedDeobfuscate(entry); - ClassEntry deobfEntry = result.getValue(); - - List obfService = enigma.getServices().get(ObfuscationTestService.TYPE); - boolean obfuscated = result.isObfuscated() && deobfEntry.equals(entry); - - if (obfuscated && !obfService.isEmpty()) { - if (obfService.stream().anyMatch(service -> service.testDeobfuscated(entry))) { - obfuscated = false; - } - } - - if (obfuscated) { + if (!project.isAtLeastPartiallyDeobfuscated(entry)) { obfClasses.add(entry); + } else if (project.isFullyDeobfuscated(entry)) { + fullyDeobfClasses.add(entry); } else { - deobfClasses.add(entry); + partiallyDeobfClasses.add(entry); } }); } @@ -533,9 +522,20 @@ private void applyChange0(ValidationContext vc, EntryChange change) { EntryMapping mapping = EntryUtil.applyChange(vc, this.project.getMapper(), change); boolean renamed = !change.getDeobfName().isUnchanged(); + RenameDirection direction = null; + + if (renamed) { + if (prev.targetName() == null && mapping.targetName() != null) { + direction = RenameDirection.OBF_TO_DEOBF; + } else if (prev.targetName() == null && mapping.targetName() == null) { + direction = RenameDirection.OBF_TO_OBF; + } else if (prev.targetName() != null && mapping.targetName() == null) { + direction = RenameDirection.DEOBF_TO_OBF; + } else if (prev.targetName() != null && mapping.targetName() != null) { + direction = RenameDirection.DEOBF_TO_DEOBF; + } - if (renamed && target instanceof ClassEntry && !((ClassEntry) target).isInnerClass()) { - this.gui.moveClassTree(target, prev.targetName() == null, mapping.targetName() == null); + this.gui.moveClassTreeIfNecessary(target, direction); } if (!Objects.equals(prev.targetName(), mapping.targetName())) { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java index c4541fc67..a51f3106a 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/NestedPackages.java @@ -75,6 +75,14 @@ public DefaultMutableTreeNode getRoot() { return root; } + public Map getPackageToNodeMap() { + return packageToNode; + } + + public Map getClassToNodeMap() { + return classToNode; + } + public TreePath getPackagePath(String packageName) { DefaultMutableTreeNode node = packageToNode.getOrDefault(packageName, root); return new TreePath(node.getPath()); diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java index cdf27cac9..ba743a2c5 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/config/UiConfig.java @@ -77,19 +77,28 @@ public static void setScaleFactor(float scale) { * *
    *
  • [0] - The height of the obfuscated classes panel
  • - *
  • [1] - The width of the classes panel
  • - *
  • [2] - The width of the center panel
  • - *
  • [3] - The height of the tabs panel. Only used if the logs panel should appear
  • + *
  • [1] - The height of the partially deobfuscated classes panel
  • + *
  • [2] - The width of the classes panel
  • + *
  • [3] - The width of the center panel
  • + *
  • [4] - The height of the tabs panel. Only used if the logs panel should appear
  • *
* - * @return an integer array composed of these 4 dimensions + * @return an integer array composed of these 5 dimensions */ public static int[] getLayout() { - return swing.data().section("Main Window").getIntArray("Layout").orElseGet(() -> new int[]{-1, -1, -1, -1}); + Optional savedData = swing.data().section("Main Window").getIntArray("Layout"); + + // In older versions of Enigma, only four array entries were present. + // If such an old config is loaded, discard it (not worth the effort of converting) + if (savedData.isPresent() && savedData.get().length == 5) { + return savedData.get(); + } else { + return new int[] { -1, -1, -1, -1, -1 }; + } } - public static void setLayout(int leftV, int left, int right, int rightH) { - swing.data().section("Main Window").setIntArray("Layout", new int[]{leftV, left, right, rightH}); + public static void setLayout(int obfV, int partialObfV, int left, int right, int rightH) { + swing.data().section("Main Window").setIntArray("Layout", new int[] { obfV, partialObfV, left, right, rightH }); } public static LookAndFeel getLookAndFeel() { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java index 7814dd811..713c71635 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java @@ -43,12 +43,14 @@ import cuchaz.enigma.analysis.index.EntryIndex; import cuchaz.enigma.gui.Gui; import cuchaz.enigma.gui.GuiController; +import cuchaz.enigma.gui.panels.classlists.ClassPanel; import cuchaz.enigma.gui.search.SearchEntry; import cuchaz.enigma.gui.search.SearchUtil; import cuchaz.enigma.gui.util.AbstractListCellRenderer; import cuchaz.enigma.gui.util.GuiUtil; import cuchaz.enigma.gui.util.ScaleUtil; import cuchaz.enigma.translation.representation.entry.ClassEntry; +import cuchaz.enigma.translation.representation.entry.Entry; import cuchaz.enigma.translation.representation.entry.FieldEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; import cuchaz.enigma.translation.representation.entry.ParentedEntry; @@ -183,19 +185,28 @@ private void openEntry(SearchEntryImpl e) { su.hit(e); parent.getController().navigateTo(e.obf); + boolean atLeastPartiallyDeobfuscated; + Entry classToSelect; + ClassPanel panel; + if (e.obf instanceof ClassEntry) { - if (e.deobf != null) { - parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf); - } else { - parent.getObfPanel().obfClasses.setSelectionClass((ClassEntry) e.obf); - } + atLeastPartiallyDeobfuscated = e.deobf != null || parent.getController().project.isAtLeastPartiallyDeobfuscated(e.obf); + classToSelect = e.deobf != null && atLeastPartiallyDeobfuscated ? e.deobf : e.obf; } else { - if (e.deobf != null) { - parent.getDeobfPanel().deobfClasses.setSelectionClass((ClassEntry) e.deobf.getParent()); - } else { - parent.getObfPanel().obfClasses.setSelectionClass((ClassEntry) e.obf.getParent()); - } + atLeastPartiallyDeobfuscated = e.deobf != null || parent.getController().project.isAtLeastPartiallyDeobfuscated(e.obf.getTopLevelClass()); + classToSelect = e.deobf != null && atLeastPartiallyDeobfuscated ? e.deobf.getTopLevelClass() : e.obf.getTopLevelClass(); } + + if (!atLeastPartiallyDeobfuscated) { + panel = parent.getObfPanel(); + } else if (parent.getController().project.isFullyDeobfuscated(classToSelect)) { + panel = parent.getFullDeobfPanel(); + } else { + panel = parent.getPartialDeobfPanel(); + } + + panel.classes.setSelectionClass((ClassEntry) classToSelect); + panel.classes.requestFocus(); } private void close() { diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ClassPanelContextMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ClassPanelContextMenu.java new file mode 100644 index 000000000..e8f8d1d4e --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/ClassPanelContextMenu.java @@ -0,0 +1,62 @@ +package cuchaz.enigma.gui.elements; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.tree.TreePath; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.panels.classlists.ClassPanel; +import cuchaz.enigma.utils.I18n; + +public class ClassPanelContextMenu { + private final JPopupMenu ui; + private final JMenuItem renamePackage = new JMenuItem(); + private final JMenuItem renameClass = new JMenuItem(); + private final JMenuItem expandAll = new JMenuItem(); + private final JMenuItem collapseAll = new JMenuItem(); + + public ClassPanelContextMenu(ClassPanel panel) { + this.ui = new JPopupMenu(); + + this.ui.add(this.renamePackage); + this.ui.add(this.renameClass); + this.ui.addSeparator(); + this.ui.add(this.expandAll); + this.ui.add(this.collapseAll); + + ClassSelector classes = panel.classes; + + this.renamePackage.addActionListener(a -> { + TreePath path; + + if (classes.getSelectedClass() != null) { + // Rename parent package if selected path is a class + path = classes.getSelectionPath().getParentPath(); + } else { + // Rename selected path if it's already a package + path = classes.getSelectionPath(); + } + + classes.getUI().startEditingAtPath(classes, path); + }); + this.renameClass.addActionListener(a -> classes.getUI().startEditingAtPath(classes, classes.getSelectionPath())); + this.expandAll.addActionListener(a -> classes.expandAll()); + this.collapseAll.addActionListener(a -> classes.collapseAll()); + + this.retranslateUi(); + } + + public void show(ClassSelector classes, int x, int y) { + // Only enable rename class if selected path is a class + this.renameClass.setEnabled(classes.getSelectedClass() != null); + + this.ui.show(classes, x, y); + } + + public void retranslateUi() { + this.renamePackage.setText(I18n.translate("popup_menu.class_panel.rename_package")); + this.renameClass.setText(I18n.translate("popup_menu.class_panel.rename_class")); + this.expandAll.setText(I18n.translate("popup_menu.class_panel.expand_all")); + this.collapseAll.setText(I18n.translate("popup_menu.class_panel.collapse_all")); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java deleted file mode 100644 index bcc6dc6fe..000000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/DeobfPanelPopupMenu.java +++ /dev/null @@ -1,62 +0,0 @@ -package cuchaz.enigma.gui.elements; - -import javax.swing.JMenuItem; -import javax.swing.JPopupMenu; -import javax.swing.tree.TreePath; - -import cuchaz.enigma.gui.ClassSelector; -import cuchaz.enigma.gui.panels.DeobfPanel; -import cuchaz.enigma.utils.I18n; - -public class DeobfPanelPopupMenu { - private final JPopupMenu ui; - private final JMenuItem renamePackage = new JMenuItem(); - private final JMenuItem renameClass = new JMenuItem(); - private final JMenuItem expandAll = new JMenuItem(); - private final JMenuItem collapseAll = new JMenuItem(); - - public DeobfPanelPopupMenu(DeobfPanel panel) { - this.ui = new JPopupMenu(); - - this.ui.add(this.renamePackage); - this.ui.add(this.renameClass); - this.ui.addSeparator(); - this.ui.add(this.expandAll); - this.ui.add(this.collapseAll); - - ClassSelector deobfClasses = panel.deobfClasses; - - this.renamePackage.addActionListener(a -> { - TreePath path; - - if (deobfClasses.getSelectedClass() != null) { - // Rename parent package if selected path is a class - path = deobfClasses.getSelectionPath().getParentPath(); - } else { - // Rename selected path if it's already a package - path = deobfClasses.getSelectionPath(); - } - - deobfClasses.getUI().startEditingAtPath(deobfClasses, path); - }); - this.renameClass.addActionListener(a -> deobfClasses.getUI().startEditingAtPath(deobfClasses, deobfClasses.getSelectionPath())); - this.expandAll.addActionListener(a -> deobfClasses.expandAll()); - this.collapseAll.addActionListener(a -> deobfClasses.collapseAll()); - - this.retranslateUi(); - } - - public void show(ClassSelector deobfClasses, int x, int y) { - // Only enable rename class if selected path is a class - this.renameClass.setEnabled(deobfClasses.getSelectedClass() != null); - - this.ui.show(deobfClasses, x, y); - } - - public void retranslateUi() { - this.renamePackage.setText(I18n.translate("popup_menu.deobf_panel.rename_package")); - this.renameClass.setText(I18n.translate("popup_menu.deobf_panel.rename_class")); - this.expandAll.setText(I18n.translate("popup_menu.deobf_panel.expand_all")); - this.collapseAll.setText(I18n.translate("popup_menu.deobf_panel.collapse_all")); - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java deleted file mode 100644 index 5d1d0f2be..000000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/DeobfPanel.java +++ /dev/null @@ -1,57 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import java.awt.BorderLayout; -import java.awt.event.MouseEvent; - -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; - -import cuchaz.enigma.gui.ClassSelector; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.elements.DeobfPanelPopupMenu; -import cuchaz.enigma.gui.util.GuiUtil; -import cuchaz.enigma.utils.I18n; - -public class DeobfPanel extends JPanel { - public final ClassSelector deobfClasses; - private final JLabel title = new JLabel(); - - public final DeobfPanelPopupMenu deobfPanelPopupMenu; - - private final Gui gui; - - public DeobfPanel(Gui gui) { - this.gui = gui; - - this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); - this.deobfClasses.setSelectionListener(gui.getController()::navigateTo); - this.deobfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); - this.deobfPanelPopupMenu = new DeobfPanelPopupMenu(this); - - this.setLayout(new BorderLayout()); - this.add(this.title, BorderLayout.NORTH); - this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER); - - this.deobfClasses.addMouseListener(GuiUtil.onMousePress(this::onPress)); - - this.retranslateUi(); - } - - private void onPress(MouseEvent e) { - if (SwingUtilities.isRightMouseButton(e)) { - deobfClasses.setSelectionRow(deobfClasses.getClosestRowForLocation(e.getX(), e.getY())); - int i = deobfClasses.getRowForPath(deobfClasses.getSelectionPath()); - - if (i != -1) { - deobfPanelPopupMenu.show(deobfClasses, e.getX(), e.getY()); - } - } - } - - public void retranslateUi() { - this.title.setText(I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.deobfuscated")); - this.deobfPanelPopupMenu.retranslateUi(); - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java deleted file mode 100644 index f82e66633..000000000 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/ObfPanel.java +++ /dev/null @@ -1,49 +0,0 @@ -package cuchaz.enigma.gui.panels; - -import java.awt.BorderLayout; -import java.util.Comparator; - -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; - -import cuchaz.enigma.gui.ClassSelector; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.translation.representation.entry.ClassEntry; -import cuchaz.enigma.utils.I18n; - -public class ObfPanel extends JPanel { - public final ClassSelector obfClasses; - private final JLabel title = new JLabel(); - - private final Gui gui; - - public ObfPanel(Gui gui) { - this.gui = gui; - - Comparator obfClassComparator = (a, b) -> { - String aname = a.getFullName(); - String bname = b.getFullName(); - - if (aname.length() != bname.length()) { - return aname.length() - bname.length(); - } - - return aname.compareTo(bname); - }; - - this.obfClasses = new ClassSelector(gui, obfClassComparator, false); - this.obfClasses.setSelectionListener(gui.getController()::navigateTo); - this.obfClasses.setRenameSelectionListener(gui::onRenameFromClassTree); - - this.setLayout(new BorderLayout()); - this.add(this.title, BorderLayout.NORTH); - this.add(new JScrollPane(this.obfClasses), BorderLayout.CENTER); - - this.retranslateUi(); - } - - public void retranslateUi() { - this.title.setText(I18n.translate("info_panel.classes.obfuscated")); - } -} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ClassPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ClassPanel.java new file mode 100644 index 000000000..015294e91 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ClassPanel.java @@ -0,0 +1,62 @@ +package cuchaz.enigma.gui.panels.classlists; + +import java.awt.BorderLayout; +import java.awt.event.MouseEvent; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.gui.elements.ClassPanelContextMenu; +import cuchaz.enigma.gui.util.GuiUtil; + +public abstract class ClassPanel extends JPanel { + public final ClassSelector classes; + protected final JLabel title = new JLabel(); + protected final ClassPanelContextMenu contextMenu; + protected final Gui gui; + + public ClassPanel(Gui gui) { + this.gui = gui; + + this.classes = getClassSelector(); + this.classes.addMouseListener(GuiUtil.onMousePress(this::onPress)); + this.classes.setSelectionListener(gui.getController()::navigateTo); + this.classes.setRenameSelectionListener(gui::onRenameFromClassTree); + this.contextMenu = new ClassPanelContextMenu(this); + + this.setLayout(new BorderLayout()); + this.add(this.title, BorderLayout.NORTH); + this.add(new JScrollPane(this.classes), BorderLayout.CENTER); + + this.retranslateUi(); + } + + protected abstract ClassSelector getClassSelector(); + + protected void onPress(MouseEvent e) { + if (SwingUtilities.isRightMouseButton(e)) { + classes.setSelectionRow(classes.getClosestRowForLocation(e.getX(), e.getY())); + int i = classes.getRowForPath(classes.getSelectionPath()); + + if (i != -1) { + contextMenu.show(classes, e.getX(), e.getY()); + } + } + } + + public void reload() { + classes.reload(); + updateCounter(); + }; + + public void retranslateUi() { + updateCounter(); + contextMenu.retranslateUi(); + } + + public abstract void updateCounter(); +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/FullDeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/FullDeobfPanel.java new file mode 100644 index 000000000..444ad6d3b --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/FullDeobfPanel.java @@ -0,0 +1,23 @@ +package cuchaz.enigma.gui.panels.classlists; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.utils.I18n; + +public class FullDeobfPanel extends ClassPanel { + public FullDeobfPanel(Gui gui) { + super(gui); + } + + @Override + protected ClassSelector getClassSelector() { + return new ClassSelector(this, gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); + } + + @Override + public void updateCounter() { + this.title.setText(String.format("%s (%s)", + I18n.translate(gui.isSingleClassTree() ? "info_panel.classes" : "info_panel.classes.fully_deobfuscated"), + classes.getClassesCount())); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ObfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ObfPanel.java new file mode 100644 index 000000000..b90284612 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/ObfPanel.java @@ -0,0 +1,37 @@ +package cuchaz.enigma.gui.panels.classlists; + +import java.util.Comparator; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import cuchaz.enigma.utils.I18n; + +public class ObfPanel extends ClassPanel { + public ObfPanel(Gui gui) { + super(gui); + } + + @Override + protected ClassSelector getClassSelector() { + Comparator obfClassComparator = (a, b) -> { + String aname = a.getFullName(); + String bname = b.getFullName(); + + if (aname.length() != bname.length()) { + return aname.length() - bname.length(); + } + + return aname.compareTo(bname); + }; + + return new ClassSelector(this, gui, obfClassComparator, true); + } + + @Override + public void updateCounter() { + this.title.setText(String.format("%s (%s)", + I18n.translate("info_panel.classes.obfuscated"), + classes.getClassesCount())); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/PartialDeobfPanel.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/PartialDeobfPanel.java new file mode 100644 index 000000000..b61ffd479 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/panels/classlists/PartialDeobfPanel.java @@ -0,0 +1,23 @@ +package cuchaz.enigma.gui.panels.classlists; + +import cuchaz.enigma.gui.ClassSelector; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.utils.I18n; + +public class PartialDeobfPanel extends ClassPanel { + public PartialDeobfPanel(Gui gui) { + super(gui); + } + + @Override + protected ClassSelector getClassSelector() { + return new ClassSelector(this, gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); + } + + @Override + public void updateCounter() { + this.title.setText(String.format("%s (%s)", + I18n.translate("info_panel.classes.partially_deobfuscated"), + classes.getClassesCount())); + } +} diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java index 99b5572bf..4d2bf1a2c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/stats/StatsGenerator.java @@ -115,7 +115,7 @@ public StatsResult generate(ProgressListener progress, Set included } private void update(Map counts, Entry entry) { - if (project.isObfuscated(entry)) { + if (!project.isAtLeastPartiallyDeobfuscated(entry)) { String parent = mapper.deobfuscate(entry.getAncestry().get(0)).getName().replace('/', '.'); counts.put(parent, counts.getOrDefault(parent, 0) + 1); } diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java index 15d5e9809..b3bd00bb4 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java @@ -32,16 +32,19 @@ import cuchaz.enigma.source.DecompilerService; import cuchaz.enigma.source.SourceSettings; import cuchaz.enigma.translation.ProposingTranslator; +import cuchaz.enigma.translation.TranslateResult; import cuchaz.enigma.translation.Translator; import cuchaz.enigma.translation.mapping.EntryMapping; import cuchaz.enigma.translation.mapping.EntryRemapper; import cuchaz.enigma.translation.mapping.MappingsChecker; +import cuchaz.enigma.translation.mapping.ResolutionStrategy; import cuchaz.enigma.translation.mapping.tree.DeltaTrackingTree; import cuchaz.enigma.translation.mapping.tree.EntryTree; import cuchaz.enigma.translation.representation.entry.ClassEntry; import cuchaz.enigma.translation.representation.entry.Entry; import cuchaz.enigma.translation.representation.entry.LocalVariableEntry; import cuchaz.enigma.translation.representation.entry.MethodEntry; +import cuchaz.enigma.translation.representation.entry.ParentedEntry; import cuchaz.enigma.utils.I18n; public class EnigmaProject { @@ -162,36 +165,101 @@ public boolean isRenamable(EntryReference, Entry> obfReference) { return obfReference.isNamed() && isRenamable(obfReference.getNameableEntry()); } - public boolean isObfuscated(Entry entry) { - String name = entry.getName(); + /** + * Checks whether the provided entry or some of its potential children + * are deobfuscated. Local variables are not being considered. + */ + public boolean isAtLeastPartiallyDeobfuscated(Entry entry) { + return testDeobfuscated(entry, false); + } - List obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE); + /** + * Checks whether the provided entry and all of its potential children + * are deobfuscated. Local variables are not being considered. + */ + public boolean isFullyDeobfuscated(Entry entry) { + return testDeobfuscated(entry, true); + } - if (!obfuscationTestServices.isEmpty()) { - for (ObfuscationTestService service : obfuscationTestServices) { - if (service.testDeobfuscated(entry)) { - return false; - } + private boolean testDeobfuscated(Entry entry, boolean mustBeFullyDeobf) { + boolean obfuscationDetected = false; + + // Target name check + TranslateResult> targetName = mapper.extendedDeobfuscate(entry); + + if (targetName != null && !targetName.isObfuscated()) { + if (!mustBeFullyDeobf) { + return true; + } + } else { + obfuscationDetected = true; + + if (mustBeFullyDeobf) { + return false; } } + // Name Proposal check List nameProposalServices = this.getEnigma().getServices().get(NameProposalService.TYPE); - if (!nameProposalServices.isEmpty()) { + if (!mustBeFullyDeobf && !nameProposalServices.isEmpty()) { for (NameProposalService service : nameProposalServices) { if (service.proposeName(entry, mapper).isPresent()) { + return true; + } + } + } + + // Obfuscation Test Services check + List obfuscationTestServices = this.getEnigma().getServices().get(ObfuscationTestService.TYPE); + + if (!obfuscationTestServices.isEmpty()) { + for (ObfuscationTestService service : obfuscationTestServices) { + if (service.testDeobfuscated(entry)) { + if (!mustBeFullyDeobf) { + return true; + } + } else { + obfuscationDetected = true; + } + + if (mustBeFullyDeobf && obfuscationDetected) { return false; } } } - String mappedName = mapper.deobfuscate(entry).getName(); + // Obfuscated children check + List renamableChildren = jarIndex.getChildrenByClass().entries() + .stream() + .filter(item -> item.getKey().equals(entry)) + .map(Map.Entry::getValue) + .filter(item -> isRenamable(item) + // No constructors + && !item.getName().equals("") + && !item.getName().equals("") + // Don't check inherited members + && jarIndex.getEntryResolver().resolveFirstEntry(item, ResolutionStrategy.RESOLVE_ROOT).getParent().equals(entry)) + .toList(); + for (ParentedEntry child : renamableChildren) { + if (isAtLeastPartiallyDeobfuscated(child)) { + if (!mustBeFullyDeobf) { + return true; + } + } else { + obfuscationDetected = true; + } - if (mappedName != null && !mappedName.isEmpty() && !mappedName.equals(name)) { - return false; + if (mustBeFullyDeobf && obfuscationDetected) { + return false; + } } - return true; + if (mustBeFullyDeobf) { + return !obfuscationDetected; + } else { + return false; + } } public JarExport exportRemappedJar(ProgressListener progress) { diff --git a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java index b3ba8965b..2cdeae18c 100644 --- a/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java +++ b/enigma/src/main/java/cuchaz/enigma/analysis/StructureTreeNode.java @@ -48,12 +48,12 @@ public void load(EnigmaProject project, StructureTreeOptions options) { case ALL -> children; case OBFUSCATED -> children // remove deobfuscated members if only obfuscated, unless it's an inner class - .filter(e -> (e instanceof ClassEntry) || (project.isObfuscated(e) && project.isRenamable(e))) + .filter(e -> (e instanceof ClassEntry) || (!project.isAtLeastPartiallyDeobfuscated(e) && project.isRenamable(e))) // keep constructor methods if the class is obfuscated - .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || project.isObfuscated(e.getParent())); - case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) || (!project.isObfuscated(e) && project.isRenamable(e)) + .filter(e -> !(e instanceof MethodEntry m && m.isConstructor()) || !project.isAtLeastPartiallyDeobfuscated(e.getParent())); + case DEOBFUSCATED -> children.filter(e -> (e instanceof ClassEntry) || (project.isAtLeastPartiallyDeobfuscated(e) && project.isRenamable(e)) // keep constructor methods if the class is deobfuscated - || (e instanceof MethodEntry m && m.isConstructor()) && !project.isObfuscated(e.getParent())); + || (e instanceof MethodEntry m && m.isConstructor()) && project.isAtLeastPartiallyDeobfuscated(e.getParent())); }; children = switch (options.documentationVisibility()) { diff --git a/enigma/src/main/resources/lang/en_us.json b/enigma/src/main/resources/lang/en_us.json index 4ec2f087e..33227c60a 100644 --- a/enigma/src/main/resources/lang/en_us.json +++ b/enigma/src/main/resources/lang/en_us.json @@ -84,10 +84,10 @@ "popup_menu.editor_tab.close_others": "Close Others", "popup_menu.editor_tab.close_left": "Close All to the Left", "popup_menu.editor_tab.close_right": "Close All to the Right", - "popup_menu.deobf_panel.rename_package": "Rename Package", - "popup_menu.deobf_panel.rename_class": "Rename Class", - "popup_menu.deobf_panel.expand_all": "Expand All", - "popup_menu.deobf_panel.collapse_all": "Collapse All", + "popup_menu.class_panel.rename_package": "Rename Package", + "popup_menu.class_panel.rename_class": "Rename Class", + "popup_menu.class_panel.expand_all": "Expand All", + "popup_menu.class_panel.collapse_all": "Collapse All", "editor.decompiling": "Decompiling...", "editor.decompile_error": "An error was encountered while decompiling.", @@ -95,7 +95,8 @@ "info_panel.classes": "Classes", "info_panel.classes.obfuscated": "Obfuscated Classes", - "info_panel.classes.deobfuscated": "De-obfuscated Classes", + "info_panel.classes.partially_deobfuscated": "Partially Deobfuscated Classes", + "info_panel.classes.fully_deobfuscated": "Fully Deobfuscated Classes", "info_panel.identifier": "Identifier Info", "info_panel.identifier.none": "No identifier selected", "info_panel.identifier.variable": "Variable", diff --git a/enigma/src/main/resources/lang/fr_fr.json b/enigma/src/main/resources/lang/fr_fr.json index d3d0c2976..5a591153c 100644 --- a/enigma/src/main/resources/lang/fr_fr.json +++ b/enigma/src/main/resources/lang/fr_fr.json @@ -84,17 +84,16 @@ "popup_menu.editor_tab.close_others": "Fermer les autres", "popup_menu.editor_tab.close_left": "Tout fermer sur la gauche", "popup_menu.editor_tab.close_right": "Tout fermer sur la droite", - "popup_menu.deobf_panel.rename_package": "Renommer le package", - "popup_menu.deobf_panel.rename_class": "Renommer la classe", - "popup_menu.deobf_panel.expand_all": "Tout développer", - "popup_menu.deobf_panel.collapse_all": "Tout réduire", + "popup_menu.class_panel.rename_package": "Renommer le package", + "popup_menu.class_panel.rename_class": "Renommer la classe", + "popup_menu.class_panel.expand_all": "Tout développer", + "popup_menu.class_panel.collapse_all": "Tout réduire", "editor.decompiling": "Décompilation...", "editor.decompile_error": "Une erreur est survenue lors de la décompilation.", "editor.remap_error": "Une erreur est survenue lors du remapping.", "info_panel.classes.obfuscated": "Classes obfusquées", - "info_panel.classes.deobfuscated": "Classes déobfusquées", "info_panel.identifier": "Informations sur l'identifiant", "info_panel.identifier.none": "Aucun identifiant sélectionné", "info_panel.identifier.variable": "Variable", diff --git a/enigma/src/main/resources/lang/ja_jp.json b/enigma/src/main/resources/lang/ja_jp.json index 09e7ee08b..2e1fe73e5 100644 --- a/enigma/src/main/resources/lang/ja_jp.json +++ b/enigma/src/main/resources/lang/ja_jp.json @@ -84,10 +84,10 @@ "popup_menu.editor_tab.close_others": "他を閉じる", "popup_menu.editor_tab.close_left": "左のタブを全て閉じる", "popup_menu.editor_tab.close_right": "右のタブを全て閉じる", - "popup_menu.deobf_panel.rename_package": "パッケージをリネーム", - "popup_menu.deobf_panel.rename_class": "クラスをリネーム", - "popup_menu.deobf_panel.expand_all": "全て展開", - "popup_menu.deobf_panel.collapse_all": "全て折りたたむ", + "popup_menu.class_panel.rename_package": "パッケージをリネーム", + "popup_menu.class_panel.rename_class": "クラスをリネーム", + "popup_menu.class_panel.expand_all": "全て展開", + "popup_menu.class_panel.collapse_all": "全て折りたたむ", "editor.decompiling": "デコンパイル中...", "editor.decompile_error": "デコンパイル中にエラーが発生しました", @@ -95,7 +95,6 @@ "info_panel.classes": "クラス一覧", "info_panel.classes.obfuscated": "難読化されたクラス", - "info_panel.classes.deobfuscated": "難読化解除されたクラス", "info_panel.identifier": "識別子情報", "info_panel.identifier.none": "識別子が選択されていません", "info_panel.identifier.variable": "変数", diff --git a/enigma/src/main/resources/lang/zh_cn.json b/enigma/src/main/resources/lang/zh_cn.json index fe806fb37..2fcc25254 100644 --- a/enigma/src/main/resources/lang/zh_cn.json +++ b/enigma/src/main/resources/lang/zh_cn.json @@ -57,7 +57,6 @@ "popup_menu.reset_obfuscated": "重置混淆", "info_panel.classes.obfuscated": "混淆类", - "info_panel.classes.deobfuscated": "反混淆类", "info_panel.identifier": "标识符信息", "info_panel.identifier.none": "未选择标识符", "info_panel.identifier.variable": "变量",