diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java index 6a9112776..625f0add1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Frame.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; @@ -47,6 +48,8 @@ public class Frame implements TreeItem { public List actions = new ArrayList<>(); + public List actionContainers = new ArrayList<>(); + public List innerTags = new ArrayList<>(); public ShowFrameTag showFrameTag = null; // can be null for the last frame diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 782b00368..c1658f149 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.tags.StartSound2Tag; import com.jpexs.decompiler.flash.tags.StartSoundTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; +import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -74,11 +75,13 @@ public class Timeline { private final List asmSources = new ArrayList<>(); + private final List asmSourceContainers = new ArrayList<>(); + private final Map actionFrames = new HashMap<>(); private AS2Package as2RootPackage; - private final List otherTags = new ArrayList<>(); + public final List otherTags = new ArrayList<>(); private boolean initialized = false; @@ -109,6 +112,7 @@ public class Timeline { frames.clear(); depthMaxFrame.clear(); asmSources.clear(); + asmSourceContainers.clear(); actionFrames.clear(); otherTags.clear(); as2RootPackage = new AS2Package(null, null, swf); @@ -168,10 +172,23 @@ public class Timeline { frame.layersChanged = true; boolean newFrameNeeded = false; for (Tag t : tags) { - if (ShowFrameTag.isNestedTagType(t.getId())) { + boolean isNested = ShowFrameTag.isNestedTagType(t.getId()); + if (isNested) { newFrameNeeded = true; frame.innerTags.add(t); } + + if (t instanceof ASMSourceContainer) { + ASMSourceContainer asmSourceContainer = (ASMSourceContainer) t; + if (!asmSourceContainer.getSubItems().isEmpty()) { + if (isNested) { + frame.actionContainers.add(asmSourceContainer); + } else { + asmSourceContainers.add(asmSourceContainer); + } + } + } + if (t instanceof StartSoundTag) { newFrameNeeded = true; frame.sounds.add(((StartSoundTag) t).soundId); diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 47e267189..ab0c4d388 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -272,6 +272,10 @@ public class CommandLineArgumentParser { out.println(" " + (cnt++) + ") -replace (|) [methodBodyIndex1] [(|) [methodBodyIndex2]]..."); out.println(" ...replaces the data of the specified BinaryData, Image, DefineSound tag or Script"); out.println(" ...methodBodyIndexN parameter should be specified if and only if the imported entity is an AS3 P-Code"); + printCmdLineUsageExamples(out); + } + + private static void printCmdLineUsageExamples(PrintStream out) { out.println(); out.println("Examples:"); out.println("java -jar ffdec.jar myfile.swf"); @@ -380,39 +384,51 @@ public class CommandLineArgumentParser { return null; } } - if (nextParam.equals("-removefromcontextmenu")) { + + String command = ""; + if (nextParam.startsWith("-")) { + command = nextParam.substring(1); + } + + if (command.equals("removefromcontextmenu")) { + if (!args.isEmpty()) { + badArguments(command); + } ContextMenuTools.addToContextMenu(false, true); System.exit(0); - } else if (nextParam.equals("-addtocontextmenu")) { + } else if (command.equals("addtocontextmenu")) { + if (!args.isEmpty()) { + badArguments(command); + } ContextMenuTools.addToContextMenu(true, true); System.exit(0); - } else if (nextParam.equals("-proxy")) { + } else if (command.equals("proxy")) { parseProxy(args); - } else if (nextParam.equals("-export")) { + } else if (command.equals("export")) { parseExport(selectionClasses, selection, selectionIds, args, handler, traceLevel, format, zoom); - } else if (nextParam.equals("-compress")) { + } else if (command.equals("compress")) { parseCompress(args); - } else if (nextParam.equals("-decompress")) { + } else if (command.equals("decompress")) { parseDecompress(args); - } else if (nextParam.equals("-swf2xml")) { + } else if (command.equals("swf2xml")) { parseSwf2Xml(args); - } else if (nextParam.equals("-xml2swf")) { + } else if (command.equals("xml2swf")) { parseXml2Swf(args); - } else if (nextParam.equals("-extract")) { + } else if (command.equals("extract")) { parseExtract(args); - } else if (nextParam.equals("-renameinvalididentifiers")) { + } else if (command.equals("renameinvalididentifiers")) { parseRenameInvalidIdentifiers(args); - } else if (nextParam.equals("-dumpswf")) { + } else if (command.equals("dumpswf")) { parseDumpSwf(args); - } else if (nextParam.equals("-dumpas2")) { + } else if (command.equals("dumpas2")) { parseDumpAS2(args); - } else if (nextParam.equals("-dumpas3")) { + } else if (command.equals("dumpas3")) { parseDumpAS3(args); - } else if (nextParam.equals("-flashpaper2pdf")) { + } else if (command.equals("flashpaper2pdf")) { parseFlashPaperToPdf(selection, zoom, args); - } else if (nextParam.equals("-replace")) { + } else if (command.equals("replace")) { parseReplace(args); - } else if (nextParam.equals("-as3compiler")) { + } else if (command.equals("as3compiler")) { ActionScriptParser.compile(null /*?*/, args.pop(), args.pop(), 0); } else if (nextParam.equals("-help") || nextParam.equals("--help") || nextParam.equals("/?") || nextParam.equals("\\_") /* /? translates as this on windows */) { printHeader(); @@ -454,6 +470,10 @@ public class CommandLineArgumentParser { } public static void badArguments() { + badArguments(null); + } + + public static void badArguments(String command) { System.err.println("Error: Bad Commandline Arguments!"); printCmdLineUsage(); System.exit(1); @@ -1149,9 +1169,9 @@ public class CommandLineArgumentParser { } try { - Helper.readTextFile(args.pop()); + String xml = Helper.readTextFile(args.pop()); SWF swf = new SWF(); - new SwfXmlImporter().importSwf(swf, null); + new SwfXmlImporter().importSwf(swf, xml); swf.saveTo(new BufferedOutputStream(new FileOutputStream(args.pop()))); } catch (IOException ex) { Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); diff --git a/src/com/jpexs/decompiler/flash/gui/LoadingDialog.java b/src/com/jpexs/decompiler/flash/gui/LoadingDialog.java index ba497869c..c1ca40af2 100644 --- a/src/com/jpexs/decompiler/flash/gui/LoadingDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/LoadingDialog.java @@ -38,8 +38,6 @@ public class LoadingDialog extends AppDialog implements ImageObserver { private final JLabel detailLabel; - private LoadingPanel loadingPanel; - JProgressBar progressBar = new JProgressBar(0, 100); public void setDetail(String d) { @@ -78,27 +76,18 @@ public class LoadingDialog extends AppDialog implements ImageObserver { cnt.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); cnt.setLayout(new BorderLayout()); - //loadingPanel = new LoadingPanel(50, 50); - //loadingPanel.setPreferredSize(new Dimension(100, 100)); - //add(loadingPanel, BorderLayout.WEST); JPanel pan = new JPanel(); pan.setLayout(new ListLayout(5)); - //pan.setPreferredSize(new Dimension(120, 150)); JLabel loadingLabel = new JLabel(translate("loadingpleasewait")); - //loadingLabel.setBounds(0, 30, 150, 20); loadingLabel.setHorizontalAlignment(SwingConstants.CENTER); detailLabel = new JLabel("", JLabel.CENTER); detailLabel.setPreferredSize(new Dimension(loadingLabel.getPreferredSize())); detailLabel.setHorizontalAlignment(SwingConstants.CENTER); - //detailLabel.setBounds(0, 45, 150, 20); - //progressBar.setBounds(0, 70, 125, 25); pan.add(loadingLabel); pan.add(detailLabel); pan.add(progressBar); cnt.add(pan, BorderLayout.CENTER); - //progressBar.setVisible(false); progressBar.setStringPainted(true); - //progressBar.setVisible(false); View.setWindowIcon(this); detailLabel.setHorizontalAlignment(SwingConstants.LEFT); addWindowListener(new WindowAdapter() { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index e662479c5..adeda0c80 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -24,12 +24,15 @@ import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DoActionTag; +import com.jpexs.decompiler.flash.tags.DoInitActionTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; @@ -220,6 +223,13 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { boolean allSelectedIsTagOrFrame = true; for (TreeItem item : items) { if (!(item instanceof Tag) && !(item instanceof Frame)) { + if (item instanceof TagScript) { + Tag tag = ((TagScript) item).getTag(); + if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) { + continue; + } + } + allSelectedIsTagOrFrame = false; break; } @@ -459,6 +469,8 @@ public class TagTreeContextMenu extends JPopupMenu implements ActionListener { for (TreeItem tag : sel) { if (tag instanceof Tag) { tagsToRemove.add((Tag) tag); + } else if (tag instanceof TagScript) { + tagsToRemove.add(((TagScript) tag).getTag()); } else if (tag instanceof Frame) { Frame frameNode = (Frame) tag; Frame frame = frameNode.timeline.getFrames().get(frameNode.frame); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 1ee542419..2bbab518b 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -86,10 +86,13 @@ public class TagTreeModel implements TreeModel { private final boolean addAllFolders; + private final Map tagScriptCache; + public TagTreeModel(List swfs, boolean addAllFolders) { this.swfs = new ArrayList<>(); this.swfFolders = new HashMap<>(); this.addAllFolders = addAllFolders; + this.tagScriptCache = new HashMap<>(); Main.startWork(AppStrings.translate("work.buildingscripttree") + "..."); for (SWFList swfList : swfs) { if (swfList.isBundle) { @@ -256,35 +259,32 @@ public class TagTreeModel implements TreeModel { subNodes.addAll(timeline.getAS2RootPackage().subPackages.values()); subNodes.addAll(timeline.getAS2RootPackage().scripts.values()); - for (Tag tag : swf.tags) { + for (Tag tag : timeline.otherTags) { + boolean hasInnerFrames = false; + List tagSubNodes = new ArrayList<>(); if (tag instanceof Timelined) { - List tagSubNodes = new ArrayList<>(); - boolean hasInnerFrames = false; - for (Frame frame : ((Timelined) tag).getTimeline().getFrames()) { - if (!frame.actions.isEmpty()) { + Timeline timeline2 = ((Timelined) tag).getTimeline(); + for (Frame frame : timeline2.getFrames()) { + if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { FrameScript frameScript = new FrameScript(swf, frame); tagSubNodes.add(frameScript); hasInnerFrames = true; } } + } - if (!hasInnerFrames) { - if (tag instanceof ASMSourceContainer) { - for (ASMSource asm : ((ASMSourceContainer) tag).getSubItems()) { - tagSubNodes.add(asm); - } - } + if (tag instanceof ASMSourceContainer) { + for (ASMSource asm : ((ASMSourceContainer) tag).getSubItems()) { + tagSubNodes.add(asm); } + } - if (!tagSubNodes.isEmpty()) { - TagScript ts = new TagScript(swf, tag, tagSubNodes); - if (hasInnerFrames) { - subFrames.add(ts); - } else { - subNodes.add(ts); - } - } else if (tag instanceof ASMSource) { - TagScript ts = new TagScript(swf, tag, tagSubNodes); + if (!tagSubNodes.isEmpty()) { + TagScript ts = new TagScript(swf, tag, tagSubNodes); + tagScriptCache.put(tag, ts); + if (hasInnerFrames) { + subFrames.add(ts); + } else { subNodes.add(ts); } } @@ -293,7 +293,7 @@ public class TagTreeModel implements TreeModel { subNodes.addAll(subFrames); for (Frame frame : timeline.getFrames()) { - if (!frame.actions.isEmpty()) { + if (!frame.actions.isEmpty() || !frame.actionContainers.isEmpty()) { FrameScript frameScript = new FrameScript(swf, frame); subNodes.add(frameScript); } @@ -463,7 +463,30 @@ public class TagTreeModel implements TreeModel { } else if (parentNode instanceof AS2Package) { return ((AS2Package) parentNode).getChild(index); } else if (parentNode instanceof FrameScript) { - return ((FrameScript) parentNode).getFrame().actions.get(index); + Frame parentFrame = ((FrameScript) parentNode).getFrame(); + TreeItem result; + if (index < parentFrame.actionContainers.size()) { + result = parentFrame.actionContainers.get(index); + } else { + index -= parentFrame.actionContainers.size(); + result = parentFrame.actions.get(index); + } + if (result instanceof Tag) { + Tag resultTag = (Tag) result; + TagScript tagScript = tagScriptCache.get(resultTag); + if (tagScript == null) { + List subNodes = new ArrayList<>(); + if (result instanceof ASMSourceContainer) { + for (ASMSource item : ((ASMSourceContainer) result).getSubItems()) { + subNodes.add(item); + } + } + tagScript = new TagScript(result.getSwf(), resultTag, subNodes); + tagScriptCache.put(resultTag, tagScript); + } + result = tagScript; + } + return result; } else if (parentNode instanceof TagScript) { return ((TagScript) parentNode).getFrames().get(index); } else if (parentNode instanceof ClassesListTreeModel) { @@ -498,7 +521,8 @@ public class TagTreeModel implements TreeModel { } else if (parentNode instanceof AS2Package) { return ((AS2Package) parentNode).getChildCount(); } else if (parentNode instanceof FrameScript) { - return ((FrameScript) parentNode).getFrame().actions.size(); + Frame parentFrame = ((FrameScript) parentNode).getFrame(); + return parentFrame.actionContainers.size() + parentFrame.actions.size(); } else if (parentNode instanceof TagScript) { return ((TagScript) parentNode).getFrames().size(); } else if (parentNode instanceof ClassesListTreeModel) { @@ -541,7 +565,15 @@ public class TagTreeModel implements TreeModel { } else if (parentNode instanceof AS2Package) { return ((AS2Package) parentNode).getIndexOfChild(childNode); } else if (parentNode instanceof FrameScript) { - return ((FrameScript) parentNode).getFrame().actions.indexOf(childNode); + Frame parentFrame = ((FrameScript) parentNode).getFrame(); + if (childNode instanceof TagScript) { + childNode = ((TagScript) childNode).getTag(); + } + if (childNode instanceof ASMSourceContainer) { + return parentFrame.actionContainers.indexOf(childNode); + } else { + return parentFrame.actionContainers.size() + parentFrame.actions.indexOf(childNode); + } } else if (parentNode instanceof TagScript) { return ((TagScript) parentNode).getFrames().indexOf(childNode); } else if (parentNode instanceof ClassesListTreeModel) {