diff --git a/CHANGELOG.md b/CHANGELOG.md index db1eeaf38..f838d14b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file. - [#1459], [#1832], [#1849] AS1/2 direct editation - Error dialog when saved value (UI16, SI16, ...) exceeds its limit and this code cannot be saved. - Attach tag menu (Like DefineScaling grid to DefineSprite, etc.) - Better tag error handling - these tags now got error icon +- Show in Hex dump command from other views for tags +- Show in Taglist command from dump view for tags ### Fixed - Flash viewer - subtract blend mode diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 3bce8f757..180b72bb8 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -1146,6 +1146,10 @@ public abstract class MainFrameMenu implements MenuBuilder { viewResourcesActionPerformed(null); } + public void showTagListView() { + viewTagListActionPerformed(null); + } + private void viewResourcesActionPerformed(ActionEvent evt) { Configuration.dumpView.set(false); mainFrame.getPanel().showView(MainPanel.VIEW_RESOURCES); diff --git a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java index ecb7cc178..e6e598b94 100644 --- a/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java +++ b/src/com/jpexs/decompiler/flash/gui/dumpview/DumpTree.java @@ -79,6 +79,7 @@ import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont; import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.helpers.Helper; import com.jpexs.helpers.MemoryInputStream; import java.awt.Color; @@ -186,7 +187,7 @@ public class DumpTree extends JTree { case DefineSoundTag.NAME: case SoundStreamHeadTag.NAME: case SoundStreamHead2Tag.NAME: - case SoundStreamBlockTag.NAME: + case SoundStreamBlockTag.NAME: nodeType = TreeNodeType.SOUND; break; case DefineBinaryDataTag.NAME: @@ -290,14 +291,19 @@ public class DumpTree extends JTree { parseInstructionsMenuItem.setIcon(View.getIcon("parse16")); contextPopupMenu.add(parseInstructionsMenuItem); - final JMenuItem gotoTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources")); - gotoTagMenuItem.addActionListener(this::gotoTagButtonActionPerformed); - gotoTagMenuItem.setIcon(View.getIcon("folder16")); - contextPopupMenu.add(gotoTagMenuItem); + final JMenuItem showInResourcesTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources")); + showInResourcesTagMenuItem.addActionListener(this::showInResourcesTagButtonActionPerformed); + showInResourcesTagMenuItem.setIcon(View.getIcon("folder16")); + contextPopupMenu.add(showInResourcesTagMenuItem); + + final JMenuItem showInTagListTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInTagList")); + showInTagListTagMenuItem.addActionListener(this::showInTagListTagButtonActionPerformed); + showInTagListTagMenuItem.setIcon(View.getIcon("taglist16")); + contextPopupMenu.add(showInTagListTagMenuItem); final JMenuItem gotoActionListMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources")); gotoActionListMenuItem.addActionListener(this::gotoActionListButtonActionPerformed); - gotoActionListMenuItem.setIcon(View.getIcon("folder16")); + gotoActionListMenuItem.setIcon(View.getIcon("folder16")); contextPopupMenu.add(gotoActionListMenuItem); final JMenuItem gotoMethodMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources")); @@ -328,7 +334,8 @@ public class DumpTree extends JTree { parseActionsMenuItem.setVisible(false); parseAbcMenuItem.setVisible(false); parseInstructionsMenuItem.setVisible(false); - gotoTagMenuItem.setVisible(false); + showInResourcesTagMenuItem.setVisible(false); + showInTagListTagMenuItem.setVisible(false); gotoActionListMenuItem.setVisible(false); gotoMethodMenuItem.setVisible(false); @@ -365,7 +372,8 @@ public class DumpTree extends JTree { switch (specialType) { case TAG: - gotoTagMenuItem.setVisible(true); + showInResourcesTagMenuItem.setVisible(true); + showInTagListTagMenuItem.setVisible(true); break; case ACTION_BYTES: gotoActionListMenuItem.setVisible(true); @@ -417,7 +425,7 @@ public class DumpTree extends JTree { fc.setCurrentDirectory(new File(selDir)); if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { File sf = Helper.fixDialogFile(fc.getSelectedFile()); - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(sf))) { + try ( OutputStream fos = new BufferedOutputStream(new FileOutputStream(sf))) { byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData; if (decompress) { fos.write(SWFInputStream.uncompressByteArray(data, (int) dumpInfo.startByte, (int) (dumpInfo.getEndByte() - dumpInfo.startByte + 1))); @@ -493,10 +501,10 @@ public class DumpTree extends JTree { private Tag searchTimelinedForTag(Timelined timelined, long address) { for (Tag tag : timelined.getTags()) { if (tag.getOriginalRange().getPos() == address) { - return tag; + return tag; } if (tag instanceof DefineSpriteTag) { - Tag subSpriteFound = searchTimelinedForTag(((DefineSpriteTag)tag), address); + Tag subSpriteFound = searchTimelinedForTag(((DefineSpriteTag) tag), address); if (subSpriteFound != null) { return subSpriteFound; } @@ -504,14 +512,29 @@ public class DumpTree extends JTree { } return null; } - - private void gotoTagButtonActionPerformed(ActionEvent evt) { + + private void showInTagListTagButtonActionPerformed(ActionEvent evt) { TreePath[] paths = getSelectionPaths(); DumpInfoSpecial dumpInfo = (DumpInfoSpecial) paths[0].getLastPathComponent(); SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); long address = (long) (Long) dumpInfo.specialValue; - + + Tag foundTag = searchTimelinedForTag(swf, address); + + if (foundTag != null) { + mainPanel.getMainFrame().getMenu().showTagListView(); + mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), foundTag); + } + } + + private void showInResourcesTagButtonActionPerformed(ActionEvent evt) { + TreePath[] paths = getSelectionPaths(); + DumpInfoSpecial dumpInfo = (DumpInfoSpecial) paths[0].getLastPathComponent(); + + SWF swf = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf(); + long address = (long) (Long) dumpInfo.specialValue; + Tag foundTag = searchTimelinedForTag(swf, address); if (foundTag != null) { @@ -566,4 +589,41 @@ public class DumpTree extends JTree { expandPath(new TreePath(new Object[]{root, dtm.getChild(root, i)})); } } + + public void setSelectedTag(Tag tag) { + DumpTreeModel model = getModel(); + DumpInfo d = model.getRoot(); + for (DumpInfo sd : d.getChildInfos()) { + if (sd instanceof DumpInfoSwfNode) { + DumpInfoSwfNode si = (DumpInfoSwfNode) sd; + if (si.getSwf() == tag.getSwf()) { + + long address = tag.getOriginalRange().getPos(); + DumpInfo di = si; + while (model.getChildCount(di) > 0) { + boolean found = false; + for (DumpInfo child : di.getChildInfos()) { + if (child.startByte > address) { + break; + } + if (child.getEndByte() >= address) { + di = child; + found = true; + } + } + if (!found) { + break; + } + } + di = di.parent; // tagId is selected, lets select the tag instead + TreePath selPath = model.getDumpInfoPath(di); + if (selPath != null) { + setSelectionPath(selPath); + scrollPathToVisible(selPath); + } + break; + } + } + } + } } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 2625b4523..d8a4c50ac 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -904,4 +904,6 @@ error.action.save.valueTooLarge = Code cannot be saved. Binary representation of than the maximum limit of bytes allowed.\r\nThere is a limit of how many bytes can be stored in an action tag \ and/or ActionDefineFunction/2.\r\nYou can try to shorten the script and/or the functions it contains and try again. -contextmenu.attachTag = Attach tag \ No newline at end of file +contextmenu.attachTag = Attach tag + +contextmenu.showInHexDump = Show Hex dump \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index ddbebc926..3f033dc28 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -874,4 +874,6 @@ error.action.save.valueTooLarge = K\u00f3d nem\u016f\u017ee b\u00fdt ulo\u017een ne\u017e je povolen\u00fd maxim\u00e1ln\u00ed limit po\u010dtu bajt\u016f.\r\nExistuje limit kolik bajt\u016f lze ulo\u017eit do action tagu \ a/nebo ActionDefineFunction/2.\r\nM\u016f\u017eete zkusit zkr\u00e1tit skript a/nebo funkce, kter\u00e9 obsahuje, a zkusit to znovu. -contextmenu.attachTag = Nav\u00e1zat tag \ No newline at end of file +contextmenu.attachTag = Nav\u00e1zat tag + +contextmenu.showInHexDump = Zobrazit Hex dump \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index bd8bc9dbe..989d3180a 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.action.Action; import com.jpexs.decompiler.flash.action.parser.ActionParseException; import com.jpexs.decompiler.flash.action.parser.script.ActionScript2Parser; import com.jpexs.decompiler.flash.amf.amf3.ListSet; +import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.AppDialog; import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.SelectTagPositionDialog; @@ -92,7 +93,6 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Reference; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.IOException; @@ -186,6 +186,8 @@ public class TagTreeContextMenu extends JPopupMenu { private JMenuItem showInResourcesViewTagMenuItem; private JMenuItem showInTagListViewTagMenuItem; + + private JMenuItem showInHexDumpViewTagMenuItem; private JMenuItem addFramesMenuItem; @@ -283,6 +285,11 @@ public class TagTreeContextMenu extends JPopupMenu { showInTagListViewTagMenuItem.addActionListener(this::showInTagListViewActionPerformed); showInTagListViewTagMenuItem.setIcon(View.getIcon("taglist16")); add(showInTagListViewTagMenuItem); + + showInHexDumpViewTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInHexDump")); + showInHexDumpViewTagMenuItem.addActionListener(this::showInHexDumpViewActionPerformed); + showInHexDumpViewTagMenuItem.setIcon(View.getIcon("viewhex16")); + add(showInHexDumpViewTagMenuItem); addTagInsideMenu = new JMenu(mainPanel.translate("contextmenu.addTagInside")); addTagInsideMenu.setIcon(View.getIcon("addtag16")); @@ -606,6 +613,7 @@ public class TagTreeContextMenu extends JPopupMenu { moveTagMenuItem.setVisible(items.size() == 1 && (items.get(0) instanceof Tag)); showInResourcesViewTagMenuItem.setVisible(false); showInTagListViewTagMenuItem.setVisible(false); + showInHexDumpViewTagMenuItem.setVisible(false); addFramesMenuItem.setVisible(false); addFramesBeforeMenuItem.setVisible(false); addFramesAfterMenuItem.setVisible(false); @@ -750,6 +758,10 @@ public class TagTreeContextMenu extends JPopupMenu { if (mainPanel.getCurrentView() == MainPanel.VIEW_RESOURCES && !isFolder) { showInTagListViewTagMenuItem.setVisible(true); } + + if (firstItem instanceof Tag) { + showInHexDumpViewTagMenuItem.setVisible(true); + } } if (allSelectedIsInTheSameSwf && allSelectedIsTag && swfs.size() > 1) { @@ -2285,6 +2297,16 @@ public class TagTreeContextMenu extends JPopupMenu { mainPanel.setTagTreeSelectedNode(mainPanel.tagListTree, item); mainPanel.updateMenu(); } + + private void showInHexDumpViewActionPerformed(ActionEvent evt) { + if (mainPanel.isModified()) { + ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("message.warning.hexViewNotUpToDate"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, Configuration.warningHexViewNotUpToDate); + } + TreeItem item = getTree().getCurrentTreeItem(); + mainPanel.showView(MainPanel.VIEW_DUMP); + mainPanel.dumpTree.setSelectedTag((Tag) item); + mainPanel.updateMenu(); + } private void moveTagActionPerformed(ActionEvent evt) { List items = getTree().getSelected();