From f0f17d70eb9e00a954fc8a6aad1dcf1fc4d6445c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 30 Sep 2023 15:34:53 +0200 Subject: [PATCH] ABCExplorer - show selected script/method/trait/class in main window --- .../jpexs/decompiler/flash/gui/MainPanel.java | 36 ++- .../flash/gui/abc/ABCExplorerDialog.java | 224 +++++++++++++++++- .../decompiler/flash/gui/abc/ABCPanel.java | 1 + .../locales/abc/ABCExplorerDialog.properties | 5 + .../abc/ABCExplorerDialog_cs.properties | 5 + 5 files changed, 261 insertions(+), 10 deletions(-) diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index e1055f557..397cdb2ba 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2010-2023 JPEXS - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -2442,6 +2442,26 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } + public void gotoScriptTrait(SWF swf, String scriptName, int classIndex, int traitIndex) { + abcPanel.decompiledTextArea.addScriptListener(new Runnable() { + @Override + public void run() { + if (abcPanel != null) { + abcPanel.decompiledTextArea.removeScriptListener(this); + boolean classChanged = false; + if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) { + abcPanel.decompiledTextArea.setClassIndex(classIndex); + classChanged = true; + } + if (traitIndex != -10) { + abcPanel.decompiledTextArea.gotoTrait(traitIndex); + } + } + } + }); + gotoScriptName(swf, scriptName); + } + public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) { View.checkAccess(); @@ -2641,7 +2661,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se for (TreeItem t : allItems) { if (t instanceof ScriptPack) { ScriptPack sp = (ScriptPack) t; - Openable s = sp.getOpenable(); //Fixme for ABCs + Openable s = sp.getOpenable(); //Fixme for ABCs if (!scopeAs3.containsKey(s)) { scopeAs3.put(s, new ArrayList<>()); } @@ -3848,7 +3868,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (openable instanceof SWF) { swf = (SWF) openable; } - //FIXME for ABCs + //FIXME for ABCs if (swf == null) { return; @@ -4992,7 +5012,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se previewPanel.showFlashViewerPanel(); previewPanel.showSwf(swf); - //} + //} } } else if ((treeItem instanceof PlaceObjectTypeTag)) {// && (previewPanel != dumpPreviewPanel)) { previewPanel.showDisplayEditTagPanel((PlaceObjectTypeTag) treeItem, frame); @@ -5304,7 +5324,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se System.out.println("seekSamples = "+seekSamples); System.out.println("============"); }catch(Exception ex){ - + } }*/ if (treeItem instanceof HeaderItem) { @@ -5987,7 +6007,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se dialog.toFront(); } } else { - dialog = new ABCExplorerDialog(mainFrame.getWindow(), openable, abc); + dialog = new ABCExplorerDialog(mainFrame.getWindow(), this, openable, abc); abcExplorerDialogs.put(openable, dialog); dialog.setVisible(true); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCExplorerDialog.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCExplorerDialog.java index 67ef1c80f..82d4adb83 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCExplorerDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCExplorerDialog.java @@ -18,6 +18,8 @@ package com.jpexs.decompiler.flash.gui.abc; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.avm2.instructions.AVM2Instruction; +import com.jpexs.decompiler.flash.abc.avm2.instructions.construction.NewFunctionIns; import com.jpexs.decompiler.flash.abc.types.ABCException; import com.jpexs.decompiler.flash.abc.types.ClassInfo; import com.jpexs.decompiler.flash.abc.types.Float4; @@ -39,8 +41,10 @@ import com.jpexs.decompiler.flash.abc.types.traits.Traits; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.gui.AppDialog; import com.jpexs.decompiler.flash.gui.FasterScrollPane; +import com.jpexs.decompiler.flash.gui.MainPanel; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.helpers.CodeFormatting; +import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.helpers.StringBuilderTextWriter; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DoABC2Tag; @@ -94,9 +98,11 @@ public class ABCExplorerDialog extends AppDialog { private final List abcFrames = new ArrayList<>(); private final JTabbedPane mainTabbedPane; private final JTabbedPane cpTabbedPane; + private MainPanel mainPanel; - public ABCExplorerDialog(Window owner, Openable openable, ABC abc) { + public ABCExplorerDialog(Window owner, MainPanel mainPanel, Openable openable, ABC abc) { super(owner); + this.mainPanel = mainPanel; Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); @@ -333,6 +339,46 @@ public class ABCExplorerDialog extends AppDialog { return null; } Object selection = tree.getLastSelectedPathComponent(); + + if (selection instanceof ValueWithIndex) { + ValueWithIndex vwi = (ValueWithIndex) selection; + if (vwi.getType() == TreeType.SCRIPT_INFO) { + JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.script"), View.getIcon("show16")); + showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed); + menu.add(showInMainWindowMenuItem); + } + + if (vwi.getType() == TreeType.METHOD_INFO || vwi.getType() == TreeType.METHOD_BODY) { + JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.method"), View.getIcon("show16")); + showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed); + menu.add(showInMainWindowMenuItem); + } + + if (vwi.getType() == TreeType.INSTANCE_INFO || vwi.getType() == TreeType.CLASS_INFO) { + JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.class"), View.getIcon("show16")); + showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed); + menu.add(showInMainWindowMenuItem); + } + } + if (selection instanceof SubValue) { + SubValue sv = (SubValue) selection; + + switch (sv.getIcon()) { + case TRAIT_CLASS: + case TRAIT_CONST: + case TRAIT_FUNCTION: + case TRAIT_GETTER: + case TRAIT_METHOD: + case TRAIT_SETTER: + case TRAIT_SLOT: + if (!(sv.parentValue instanceof MethodBody)) { + JMenuItem showInMainWindowMenuItem = new JMenuItem(translate("show.trait"), View.getIcon("show16")); + showInMainWindowMenuItem.addActionListener(this::showInMainWindowActionPerformed); + menu.add(showInMainWindowMenuItem); + } + break; + } + } if (selection != null) { JMenuItem copyRowMenuItem = new JMenuItem(translate("copy.row"), View.getIcon("copy16")); copyRowMenuItem.addActionListener(this::copyRowActionPerformed); @@ -361,7 +407,7 @@ public class ABCExplorerDialog extends AppDialog { menu.add(copyRawStringValueMenuItem); } } else if (selection instanceof SubValue) { - SubValue sv = (SubValue) selection; + SubValue sv = (SubValue) selection; JMenuItem copyTitleMenuItem = new JMenuItem(translate("copy.title"), View.getIcon("copy16")); copyTitleMenuItem.addActionListener(this::copyTitleActionPerformed); menu.add(copyTitleMenuItem); @@ -396,6 +442,180 @@ public class ABCExplorerDialog extends AppDialog { } } + private boolean showMethodInfo(int round, ABC abc, int methodInfo, int searchMethodInfo, int scriptIndex, int classIndex, int globalTraitIndex) { + boolean found = false; + if (methodInfo == searchMethodInfo) { + found = true; + } else if (round == 2) { + MethodBody body = abc.findBody(methodInfo); + if (body != null) { + for (AVM2Instruction ins : body.getCode().code) { + if (ins.definition instanceof NewFunctionIns) { + if (ins.operands[0] == methodInfo) { + found = true; + break; + } + } + } + } + } + if (found) { + DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc); + String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString()); + mainPanel.gotoScriptTrait(abc.getSwf(), scriptName, classIndex, globalTraitIndex); + } + return found; + } + + private boolean showMethodInfoTraits(int round, int scriptIndex, int classIndex, int methodInfo, ABC abc, Traits traits, int traitsType) { + for (int j = 0; j < traits.traits.size(); j++) { + Trait t = (Trait) traits.traits.get(j); + int globalTraitIndex = j; + if (traitsType == GraphTextWriter.TRAIT_INSTANCE_INITIALIZER) { + globalTraitIndex += abc.class_info.get(classIndex).static_traits.traits.size(); + } + if (t instanceof TraitClass) { + TraitClass tc = (TraitClass) t; + if (showMethodInfo(round, abc, abc.class_info.get(tc.class_info).cinit_index, methodInfo, scriptIndex, tc.class_info, GraphTextWriter.TRAIT_CLASS_INITIALIZER)) { + return true; + } + + if (showMethodInfo(round, abc, abc.instance_info.get(tc.class_info).iinit_index, methodInfo, scriptIndex, tc.class_info, GraphTextWriter.TRAIT_INSTANCE_INITIALIZER)) { + return true; + } + + if (showMethodInfoTraits(round, scriptIndex, tc.class_info, methodInfo, abc, abc.class_info.get(tc.class_info).static_traits, GraphTextWriter.TRAIT_CLASS_INITIALIZER)) { + return true; + } + if (showMethodInfoTraits(round, scriptIndex, tc.class_info, methodInfo, abc, abc.instance_info.get(tc.class_info).instance_traits, GraphTextWriter.TRAIT_INSTANCE_INITIALIZER)) { + return true; + } + } + if (t instanceof TraitMethodGetterSetter) { + TraitMethodGetterSetter tmgs = (TraitMethodGetterSetter) t; + if (showMethodInfo(round, abc, tmgs.method_info, methodInfo, scriptIndex, classIndex, globalTraitIndex)) { + return true; + } + } + if (t instanceof TraitFunction) { + TraitFunction tf = (TraitFunction) t; + if (showMethodInfo(round, abc, tf.method_info, methodInfo, scriptIndex, classIndex, globalTraitIndex)) { + return true; + } + } + } + return false; + } + + private void showMethodInfo(int methodInfo) { + ABC abc = getSelectedAbc(); + for (int round = 1; round <= 2; round++) { + for (int i = 0; i < abc.script_info.size(); i++) { + if (showMethodInfo(round, abc, abc.script_info.get(i).init_index, methodInfo, i, -1, GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) { + return; + } + if (showMethodInfoTraits(round, i, -1, methodInfo, abc, abc.script_info.get(i).traits, GraphTextWriter.TRAIT_SCRIPT_INITIALIZER)) { + return; + } + } + } + } + + private void showInMainWindowActionPerformed(ActionEvent e) { + Object selection = getCurrentTree().getLastSelectedPathComponent(); + ABC abc = getSelectedAbc(); + if (selection instanceof ValueWithIndex) { + ValueWithIndex vwi = (ValueWithIndex) selection; + int scriptIndex = -1; + switch (vwi.type) { + case SCRIPT_INFO: + scriptIndex = vwi.getIndex(); + DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc); + String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString()); + mainPanel.gotoScriptName(abc.getSwf(), scriptName); + break; + case METHOD_BODY: + MethodBody body = (MethodBody) vwi.getRawValue(); + if (body != null) { + showMethodInfo(body.method_info); + } + break; + case METHOD_INFO: + showMethodInfo(vwi.getIndex()); + break; + case INSTANCE_INFO: + case CLASS_INFO: + int classIndex = vwi.getIndex(); + loopc: for (int i = 0; i < abc.script_info.size(); i++) { + for (int j = 0; j < abc.script_info.get(i).traits.traits.size(); j++) { + Trait t = (Trait) abc.script_info.get(i).traits.traits.get(j); + if (t instanceof TraitClass) { + TraitClass tc = (TraitClass) t; + if (tc.class_info == classIndex) { + scriptIndex = i; + break loopc; + } + } + } + } + if (scriptIndex != -1) { + DottedChain scriptNameDc2 = abc.script_info.get(scriptIndex).getSimplePackName(abc); + String scriptName2 = (scriptNameDc2 == null ? "script_" + scriptIndex : scriptNameDc2.toRawString()); + mainPanel.gotoScriptTrait(abc.getSwf(), scriptName2, classIndex, GraphTextWriter.TRAIT_CLASS_INITIALIZER); + } + break; + } + } + if (selection instanceof SubValue) { + SubValue sv = (SubValue) selection; + switch (sv.getIcon()) { + case TRAIT_CLASS: + case TRAIT_CONST: + case TRAIT_FUNCTION: + case TRAIT_GETTER: + case TRAIT_METHOD: + case TRAIT_SETTER: + case TRAIT_SLOT: + int traitIndex = sv.getIndex(); + int globalTraitIndex = traitIndex; + SubValue sv1 = (SubValue) sv.getParent(); + ValueWithIndex wvi = (ValueWithIndex) sv1.getParent(); + int scriptIndex = -1; + int classIndex = -1; + if (sv.getParentValue() instanceof ScriptInfo) { + scriptIndex = wvi.getIndex(); + } else { + classIndex = wvi.getIndex(); + if (sv.getParentValue() instanceof InstanceInfo) { + globalTraitIndex += abc.class_info.get(classIndex).static_traits.traits.size(); + } + + loopi: + for (int i = 0; i < abc.script_info.size(); i++) { + for (int j = 0; j < abc.script_info.get(i).traits.traits.size(); j++) { + Trait t = (Trait) abc.script_info.get(i).traits.traits.get(j); + if (t instanceof TraitClass) { + TraitClass tc = (TraitClass) t; + if (tc.class_info == classIndex) { + scriptIndex = i; + break loopi; + } + } + } + } + } + + if (scriptIndex != -1) { + DottedChain scriptNameDc = abc.script_info.get(scriptIndex).getSimplePackName(abc); + String scriptName = (scriptNameDc == null ? "script_" + scriptIndex : scriptNameDc.toRawString()); + mainPanel.gotoScriptTrait(abc.getSwf(), scriptName, classIndex, globalTraitIndex); + } + + break; + } + } + } + private void copyTitleActionPerformed(ActionEvent e) { Object selection = getCurrentTree().getLastSelectedPathComponent(); if (selection instanceof SimpleValue) { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 8b558a5a4..a86c28ca4 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -1460,6 +1460,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener