From 575d988ed4bad5644de08418aaa0cf0534202f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 15 Nov 2015 20:12:50 +0100 Subject: [PATCH] FlashPlayer path setting Library path setting Debugger main menu --- .../decompiler/flash/abc/ScriptPack.java | 2 +- .../flash/configuration/Configuration.java | 41 ++- .../configuration/ConfigurationDirectory.java | 32 ++ .../configuration/ConfigurationFile.java | 33 +++ .../flash/gui/AdvancedSettingsDialog.java | 68 ++++- .../decompiler/flash/gui/DebuggerHandler.java | 54 ++-- src/com/jpexs/decompiler/flash/gui/Main.java | 11 +- .../decompiler/flash/gui/MainFrameMenu.java | 280 +++++++++++++++++- .../flash/gui/graphics/continue16.png | Bin 0 -> 742 bytes .../flash/gui/graphics/continue32.png | Bin 0 -> 1971 bytes .../decompiler/flash/gui/graphics/debug16.png | Bin 0 -> 952 bytes .../decompiler/flash/gui/graphics/debug32.png | Bin 0 -> 2203 bytes .../decompiler/flash/gui/graphics/pause32.png | Bin 0 -> 1962 bytes .../decompiler/flash/gui/graphics/play32.png | Bin 0 -> 1971 bytes .../decompiler/flash/gui/graphics/stack16.png | Bin 0 -> 1444 bytes .../decompiler/flash/gui/graphics/stack32.png | Bin 0 -> 1984 bytes .../flash/gui/graphics/stepinto16.png | Bin 0 -> 381 bytes .../flash/gui/graphics/stepinto32.png | Bin 0 -> 682 bytes .../flash/gui/graphics/stepout16.png | Bin 0 -> 565 bytes .../flash/gui/graphics/stepout32.png | Bin 0 -> 1184 bytes .../flash/gui/graphics/stepover16.png | Bin 0 -> 673 bytes .../flash/gui/graphics/stepover32.png | Bin 0 -> 1579 bytes .../decompiler/flash/gui/graphics/stop32.png | Bin 0 -> 1930 bytes .../decompiler/flash/gui/graphics/watch16.png | Bin 0 -> 783 bytes .../decompiler/flash/gui/graphics/watch32.png | Bin 0 -> 1912 bytes .../locales/AdvancedSettingsDialog.properties | 12 + .../AdvancedSettingsDialog_cs.properties | 16 + .../flash/gui/locales/MainFrame.properties | 21 +- 28 files changed, 543 insertions(+), 27 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationDirectory.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationFile.java create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/continue16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/continue32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/debug16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/debug32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/pause32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/play32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stack16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stack32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepinto16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepinto32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepout16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepout32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepover16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stepover32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/stop32.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/watch16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/watch32.png diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 91130da18..f855e3ef0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -379,7 +379,7 @@ public class ScriptPack extends AS3ClassTreeItem { //String filepath = path.toString().replace('.', '/') + ".as"; String pkg = path.packageStr.toString(); String cls = path.className; - String filename = new File(directoryPath, path.packageStr.toFilePath()) + ";" + pkg + ";" + cls + ".as"; + String filename = new File(directoryPath, path.packageStr.toFilePath()) + ";" + pkg.replace(".", File.separator) + ";" + cls + ".as"; for (int bodyIndex : bodyToPosToLine.keySet()) { MethodBody b = abc.bodies.get(bodyIndex); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index c1bdf2c98..72f682e09 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -234,12 +234,15 @@ public class Configuration { public static final ConfigurationItem lastRenameType = null; @ConfigurationDefaultString(".") + @ConfigurationDirectory public static final ConfigurationItem lastSaveDir = null; @ConfigurationDefaultString(".") + @ConfigurationDirectory public static final ConfigurationItem lastOpenDir = null; @ConfigurationDefaultString(".") + @ConfigurationDirectory public static final ConfigurationItem lastExportDir = null; @ConfigurationDefaultString("en") @@ -502,6 +505,21 @@ public class Configuration { @ConfigurationCategory("ui") public static final ConfigurationItem autoOpenLoadedSWFs = null; + @ConfigurationDefaultString("") + @ConfigurationCategory("paths") + @ConfigurationFile + public static final ConfigurationItem playerLocation = null; + + @ConfigurationDefaultString("") + @ConfigurationCategory("paths") + @ConfigurationFile + public static final ConfigurationItem playerDebugLocation = null; + + @ConfigurationDefaultString("") + @ConfigurationCategory("paths") + @ConfigurationFile(".*\\.swc$") + public static final ConfigurationItem playerLibLocation = null; + private enum OSId { WINDOWS, OSX, UNIX @@ -761,6 +779,12 @@ public class Configuration { } catch (IOException ex) { Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); } + if (playerLibLocation.get("").isEmpty()) { + File swcFile = getPlayerSwcOld(); + if (swcFile != null) { + playerLibLocation.set(swcFile.getAbsolutePath()); + } + } } public static Object getDefaultValue(Field field) { @@ -838,7 +862,7 @@ public class Configuration { String proxyAddress = Configuration.updateProxyAddress.get(); URL url = new URL(urlString); - URLConnection uc = null; + URLConnection uc; if (proxyAddress != null && !proxyAddress.isEmpty()) { int port = 8080; if (proxyAddress.contains(":")) { @@ -900,6 +924,21 @@ public class Configuration { } public static File getPlayerSWC() { + String libLocation = playerLibLocation.get(""); + File ret = null; + if (!libLocation.isEmpty()) { + ret = new File(libLocation); + } + if (ret == null || !ret.exists()) { + ret = getPlayerSwcOld(); + if (ret != null) { + playerLibLocation.set(ret.getAbsolutePath()); + } + } + return ret; + } + + private static File getPlayerSwcOld() { File libsDir = getFlashLibPath(); if (libsDir != null && libsDir.exists()) { File[] libs = libsDir.listFiles(new FilenameFilter() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationDirectory.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationDirectory.java new file mode 100644 index 000000000..cc9516634 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationDirectory.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author JPEXS + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigurationDirectory { + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationFile.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationFile.java new file mode 100644 index 000000000..14aab6068 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/ConfigurationFile.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author JPEXS + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigurationFile { + + String value() default "^.*$"; +} diff --git a/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java b/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java index 064516cf7..e3e5e1e73 100644 --- a/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/AdvancedSettingsDialog.java @@ -18,8 +18,11 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationCategory; +import com.jpexs.decompiler.flash.configuration.ConfigurationDirectory; +import com.jpexs.decompiler.flash.configuration.ConfigurationFile; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; import com.jpexs.decompiler.flash.gui.helpers.SpringUtilities; +import com.jpexs.helpers.Helper; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -28,8 +31,11 @@ import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Insets; import java.awt.RenderingHints; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.text.ParseException; @@ -47,6 +53,8 @@ import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; @@ -56,6 +64,7 @@ import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.SpringLayout; import javax.swing.WindowConstants; +import javax.swing.filechooser.FileFilter; import javax.swing.table.DefaultTableModel; import org.pushingpixels.substance.api.ColorSchemeAssociationKind; import org.pushingpixels.substance.api.ComponentState; @@ -241,7 +250,7 @@ public class AdvancedSettingsDialog extends AppDialog { Map tabs = new HashMap<>(); getCategories(componentsMap, tabs, skinComboBox, getResourceBundle()); - String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "limit", "update", "debug", "other"}; + String catOrder[] = new String[]{"ui", "display", "decompilation", "script", "format", "export", "import", "paths", "limit", "update", "debug", "other"}; for (String cat : catOrder) { if (!tabs.containsKey(cat)) { @@ -256,6 +265,40 @@ public class AdvancedSettingsDialog extends AppDialog { pack(); } + public static String selectConfigFile(ConfigurationItem config, String current, String pattern) { + JFileChooser fc = new JFileChooser(); + fc.setSelectedFile(new File(current)); + fc.setMultiSelectionEnabled(false); + fc.setCurrentDirectory(new File((String) config.get())); + FileFilter allSupportedFilter = new FileFilter() { + private final String[] supportedExtensions = new String[]{".swf", ".gfx", ".swc", ".zip"}; + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + return f.getName().matches(pattern); + } + + @Override + public String getDescription() { + return ""; + } + }; + fc.setFileFilter(allSupportedFilter); + + fc.setAcceptAllFileFilterUsed(false); + JFrame f = new JFrame(); + View.setWindowIcon(f); + int returnVal = fc.showOpenDialog(f); + if (returnVal == JFileChooser.APPROVE_OPTION) { + return Helper.fixDialogFile(fc.getSelectedFile()).getAbsolutePath(); + } else { + return (String) config.get(); + } + } + public static void getCategories(Map componentsMap, Map tabs, JComboBox skinComboBox, ResourceBundle resourceBundle) { Map> categorized = new HashMap<>(); @@ -315,11 +358,15 @@ public class AdvancedSettingsDialog extends AppDialog { l.setToolTipText(description); configPanel.add(l); Component c = null; + Component addComponent = null; if (name.equals("gui.skin")) { skinComboBox.setToolTipText(description); skinComboBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, skinComboBox.getPreferredSize().height)); c = skinComboBox; } else if ((itemType == String.class) || (itemType == Integer.class) || (itemType == Long.class) || (itemType == Double.class) || (itemType == Float.class) || (itemType == Calendar.class)) { + ConfigurationFile confFile = field.getAnnotation(ConfigurationFile.class); + ConfigurationDirectory confDirectory = field.getAnnotation(ConfigurationDirectory.class); + JTextField tf = new JTextField(); Object val = item.get(); if (val == null) { @@ -332,7 +379,21 @@ public class AdvancedSettingsDialog extends AppDialog { } tf.setToolTipText(description); tf.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); + c = tf; + if (confFile != null) { //|| confDirectory != null) { + JPanel p = new JPanel(new BorderLayout()); + p.setMaximumSize(new Dimension(Integer.MAX_VALUE, tf.getPreferredSize().height)); + p.add(tf, BorderLayout.CENTER); + JButton butSelect = new JButton(View.getIcon("folderopen16")); + butSelect.setToolTipText(AppStrings.translate("FileChooser.openButtonText")); + butSelect.setMargin(new Insets(2, 2, 2, 2)); + butSelect.addActionListener((ActionEvent e) -> { + tf.setText(selectConfigFile(item, tf.getText(), confFile.value())); + }); + p.add(butSelect, BorderLayout.EAST); + addComponent = p; + } } else if (itemType == Boolean.class) { JCheckBox cb = new JCheckBox(); cb.setSelected((Boolean) item.get()); @@ -362,8 +423,11 @@ public class AdvancedSettingsDialog extends AppDialog { } componentsMap.put(name, c); + if (addComponent == null) { + addComponent = c; + } l.setLabelFor(c); - configPanel.add(c); + configPanel.add(addComponent); } catch (IllegalArgumentException | IllegalAccessException ex) { // Reflection exceptions. This should never happen throw new Error(ex.getMessage()); diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java index 058f3f615..d9055876d 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java +++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java @@ -27,8 +27,8 @@ import com.jpexs.debugger.flash.messages.in.InNumScript; import com.jpexs.debugger.flash.messages.in.InScript; import com.jpexs.debugger.flash.messages.in.InSwfInfo; import com.jpexs.decompiler.flash.abc.ClassPath; -import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.graph.DottedChain; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -38,10 +38,26 @@ import java.util.logging.Logger; /** * - * @author Jindra + * @author JPEXS */ public class DebuggerHandler implements DebugConnectionListener { + private boolean connected = false; + private DebuggerCommands commands = null; + private List swfs = new ArrayList<>(); + + public List getSwfs() { + return swfs; + } + + public boolean isConnected() { + return connected; + } + + public DebuggerCommands getCommands() { + return commands; + } + @Override public void connected(DebuggerConnection con) { @@ -54,17 +70,17 @@ public class DebuggerHandler implements DebugConnectionListener { rootLog.addHandler(ch); //rootLog.getHandlers()[0].setLevel(level); - final DebuggerCommands dc = new DebuggerCommands(con); - dc.stopWarning(); - dc.setStopOnFault(); - dc.setEnumerateOverride(); - dc.setNotifyFailure(); - dc.setInvokeSetters(); - dc.setSwfLoadNotify(); - dc.setGetterTimeout(1500); - dc.setSetterTimeout(5000); - dc.squelch(true); - List swfs = dc.getSwfInfo(1); + commands = new DebuggerCommands(con); + commands.stopWarning(); + commands.setStopOnFault(); + commands.setEnumerateOverride(); + commands.setNotifyFailure(); + commands.setInvokeSetters(); + commands.setSwfLoadNotify(); + commands.setGetterTimeout(1500); + commands.setSetterTimeout(5000); + commands.squelch(true); + swfs = commands.getSwfInfo(1); int numScript = con.getMessage(InNumScript.class).num; final Map moduleNames = new HashMap<>(); for (int i = 0; i < numScript; i++) { @@ -81,24 +97,26 @@ public class DebuggerHandler implements DebugConnectionListener { if (parts.length == 3) { String clsName = parts[2].replace(".as", ""); - String pkg = parts[1]; + String pkg = parts[1].replace("/", "\\").replace("\\", "."); modulePaths.put(mname, new ClassPath(DottedChain.parse(pkg), clsName)); } } con.getMessage(InAskBreakpoints.class); - //dc.addBreakPoint(15, 14); - dc.addBreakPoint(9, 26); con.addMessageListener(new DebugMessageListener() { @Override public void message(InBreakAt message) { - Logger.getLogger(DebuggerHandler.class.getName()).log(Level.WARNING, "break at {0}:{1}", new Object[]{moduleNames.get(message.file), message.line}); + Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "break at {0}:{1}", new Object[]{moduleNames.get(message.file), message.line}); + if (!modulePaths.containsKey(message.file)) { + return; + } String cls = modulePaths.get(message.file).toString(); Main.getMainFrame().getPanel().debuggerBreakAt(Main.getMainFrame().getPanel().getCurrentSwf(), cls, message.line); //dc.sendContinue(); } }); - dc.sendContinue(); + commands.sendContinue(); + connected = true; } } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 6b41bd7fe..7016ca3bc 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -151,6 +151,12 @@ public class Main { private static Debugger flashDebugger; + private static DebuggerHandler debugHandler = null; + + public static DebuggerHandler getDebugHandler() { + return debugHandler; + } + public static void ensureMainFrame() { if (mainFrame == null) { synchronized (Main.class) { @@ -1025,10 +1031,11 @@ public class Main { rootLog.getHandlers()[0].setLevel(level); */ flashDebugger = new Debugger(); - flashDebugger.addConnectionListener(new DebuggerHandler()); + debugHandler = new DebuggerHandler(); + flashDebugger.addConnectionListener(debugHandler); flashDebugger.start(); } catch (IOException ex) { - Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); + //ignore } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 015d6699c..b138eee1d 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.debugger.flash.DebuggerCommands; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFBundle; @@ -41,13 +42,19 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; +import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; import java.util.List; import java.util.Timer; import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractButton; @@ -635,6 +642,10 @@ public abstract class MainFrameMenu implements MenuBuilder { public void updateComponents(SWF swf) { this.swf = swf; + boolean isRunning = isRunning(); + boolean isDebugRunning = isDebugRunning(); + boolean isRunningOrDebugging = isRunning || isDebugRunning; + boolean swfSelected = swf != null; boolean isWorking = Main.isWorking(); List abcList = swf != null ? swf.getAbcList() : null; @@ -692,6 +703,19 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("/help/homePage", !isWorking); setMenuEnabled("_/about", !isWorking); setMenuEnabled("/help/about", !isWorking); + + setMenuEnabled("/execution/start/run", !isRunningOrDebugging); + setMenuEnabled("/execution/start/debug", !isRunningOrDebugging); + setMenuEnabled("/execution/start/stop", isRunningOrDebugging); + setMenuEnabled("/execution/debug", isDebugRunning); + setMenuEnabled("/execution/debug/pause", isDebugRunning); + setMenuEnabled("/execution/debug/stepOver", isDebugRunning); + setMenuEnabled("/execution/debug/stepInto", isDebugRunning); + setMenuEnabled("/execution/debug/stepOut", isDebugRunning); + setMenuEnabled("/execution/debug/continue", isDebugRunning); + setMenuEnabled("/execution/debug/stack", isDebugRunning); + setMenuEnabled("/execution/debug/watch", isDebugRunning); + } private void registerHotKeys() { @@ -774,6 +798,37 @@ public abstract class MainFrameMenu implements MenuBuilder { setGroupSelection("view", "/file/view/viewResources"); } + /* + menu.execution = Execution + menu.execution.start.run = Run + menu.execution.start.debug = Debug + menu.execution.start.stop = Stop + menu.execution.debug.pause = Pause + menu.execution.debug.stepOver = Step over + menu.execution.debug.stepInto = Step into + menu.execution.debug.stepOut = Step out + menu.execution.debug.continue = Continue + menu.execution.debug.stack = Stack... + menu.execution.debug.watch = New watch... + */ + addMenuItem("/execution", translate("menu.execution"), null, null, 0, null, false); + addMenuItem("/execution/start", translate("menu.execution.start"), null, null, 0, null, false); + addMenuItem("/execution/start/run", translate("menu.execution.start.run"), "play32", this::runActionPerformed, PRIORITY_TOP, null, true); + addMenuItem("/execution/start/debug", translate("menu.execution.start.debug"), "debug32", this::debugActionPerformed, PRIORITY_TOP, null, true); + addMenuItem("/execution/start/stop", translate("menu.execution.start.stop"), "stop32", this::stopActionPerformed, PRIORITY_TOP, null, true); + finishMenu("/execution/start"); + + addMenuItem("/execution/debug", translate("menu.execution.debug"), null, null, 0, null, false); + addMenuItem("/execution/debug/pause", translate("menu.execution.debug.pause"), "pause32", this::pauseActionPerformed, PRIORITY_TOP, null, true); + addMenuItem("/execution/debug/continue", translate("menu.execution.debug.continue"), "continue32", this::continueActionPerformed, PRIORITY_TOP, null, true); + addMenuItem("/execution/debug/stepOver", translate("menu.execution.debug.stepOver"), "stepover32", this::stepOverActionPerformed, PRIORITY_MEDIUM, null, true); + addMenuItem("/execution/debug/stepInto", translate("menu.execution.debug.stepInto"), "stepinto32", this::stepIntoActionPerformed, PRIORITY_MEDIUM, null, true); + addMenuItem("/execution/debug/stepOut", translate("menu.execution.debug.stepOut"), "stepout32", this::stepOutActionPerformed, PRIORITY_MEDIUM, null, true); + addMenuItem("/execution/debug/stack", translate("menu.execution.debug.stack"), "stack32", this::stackActionPerformed, PRIORITY_MEDIUM, null, true); + addMenuItem("/execution/debug/watch", translate("menu.execution.debug.watch"), "watch32", this::watchActionPerformed, PRIORITY_MEDIUM, null, true); + finishMenu("/execution/debug"); + finishMenu("/execution"); + addMenuItem("/tools", translate("menu.tools"), null, null, 0, null, false); addMenuItem("/tools/search", translate("menu.tools.search"), "search16", this::searchActionPerformed, PRIORITY_TOP, null, true); @@ -1017,10 +1072,216 @@ public abstract class MainFrameMenu implements MenuBuilder { manager.removeKeyEventDispatcher(keyEventDispatcher); } + private Process runProcess; + private boolean runProcessDebug; + private File runTempFile; + + public synchronized boolean isDebugRunning() { + return runProcess != null && runProcessDebug; + } + + public synchronized boolean isRunning() { + return runProcess != null && !runProcessDebug; + } + + private synchronized void setProcess(Process p) { + this.runProcess = p; + } + + private synchronized void freeRun() { + if (runTempFile != null) { + runTempFile.delete(); + runTempFile = null; + } + runProcess = null; + } + + private void runPlayer(String exePath, String file, String flashVars) { + if (!new File(file).exists()) { + return; + } + final Process proc; + if (flashVars != null && !flashVars.isEmpty()) { + file += "?" + flashVars; + } + try { + proc = Runtime.getRuntime().exec("\"" + exePath + "\" \"file://" + file + "\""); + + } catch (IOException ex) { + Logger.getLogger(MainFrameMenu.class + .getName()).log(Level.SEVERE, null, ex); + + return; + } + Thread t = new Thread() { + + @Override + public void run() { + try { + proc.waitFor(); + + } catch (InterruptedException ex) { + Logger.getLogger(MainFrameMenu.class + .getName()).log(Level.SEVERE, null, ex); + } + freeRun(); + updateComponents(); + } + + }; + t.start(); + synchronized (this) { + runProcess = proc; + } + updateComponents(); + } + + public boolean runActionPerformed(ActionEvent evt) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + return true; + } + if (swf == null) { + return true; + } + File tempFile; + try { + tempFile = File.createTempFile("ffdec_run_", ".swf"); + + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + swf.saveTo(fos); + } + } catch (IOException ex) { + return true; + + } + if (tempFile != null) { + synchronized (this) { + runTempFile = tempFile; + runProcessDebug = false; + } + runPlayer(playerLocation, tempFile.getAbsolutePath(), flashVars); + } + return true; + } + + public boolean debugActionPerformed(ActionEvent evt) { + String flashVars = "";//key=val&key2=val2 + String playerLocation = Configuration.playerDebugLocation.get(); + if (playerLocation.isEmpty() || (!new File(playerLocation).exists())) { + View.showMessageDialog(null, AppStrings.translate("message.playerpath.debug.notset"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE); + return true; + } + if (swf == null) { + return true; + } + File tempFile; + try { + tempFile = File.createTempFile("ffdec_debug_", ".swf"); + + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + swf.saveTo(fos); + } + //Inject Loader + SWF instrSWF = null; + try (FileInputStream fis = new FileInputStream(tempFile)) { + instrSWF = new SWF(fis, false, false); + + } catch (InterruptedException ex) { + Logger.getLogger(MainFrameMenu.class + .getName()).log(Level.SEVERE, null, ex); + } + if (instrSWF != null) { + instrSWF.enableDebugging(true, new File(".")); + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + instrSWF.saveTo(fos); + + } + } + + } catch (IOException ex) { + Logger.getLogger(MainFrameMenu.class + .getName()).log(Level.SEVERE, "Cannot inject debug info", ex); + + return true; + } + synchronized (this) { + runTempFile = tempFile; + runProcessDebug = true; + } + runPlayer(playerLocation, tempFile.getAbsolutePath(), flashVars); + return true; + } + + public boolean stopActionPerformed(ActionEvent evt) { + + synchronized (this) { + if (runProcess != null) { + runProcess.destroy(); + } + } + freeRun(); + + updateComponents(); + return true; + } + + public boolean pauseActionPerformed(ActionEvent evt) { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); + if (cmd != null) { + //TODO + } + return true; + } + + public boolean stepOverActionPerformed(ActionEvent evt) { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); + if (cmd != null) { + cmd.stepOver(); + } + return true; + } + + public boolean stepIntoActionPerformed(ActionEvent evt) { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); + if (cmd != null) { + cmd.stepInto(); + } + return true; + } + + public boolean stepOutActionPerformed(ActionEvent evt) { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); + if (cmd != null) { + cmd.stepOut(); + } + return true; + } + + public boolean continueActionPerformed(ActionEvent evt) { + DebuggerCommands cmd = Main.getDebugHandler().getCommands(); + if (cmd != null) { + cmd.stepContinue(); + } + return true; + } + + public boolean stackActionPerformed(ActionEvent evt) { + //TODO + return true; + } + + public boolean watchActionPerformed(ActionEvent evt) { + //TODO + return true; + } + public boolean dispatchKeyEvent(KeyEvent e) { if (((JFrame) mainFrame).isActive() && e.getID() == KeyEvent.KEY_PRESSED) { int code = e.getKeyCode(); - if (e.isControlDown() && e.isShiftDown()) { + if (e.isControlDown() && e.isShiftDown()) { //CTRL+SHIFT switch (code) { case KeyEvent.VK_O: return openActionPerformed(null); @@ -1041,13 +1302,28 @@ public abstract class MainFrameMenu implements MenuBuilder { case KeyEvent.VK_E: return export(false); } - } else if (e.isControlDown() && !e.isShiftDown()) { + } else if (e.isControlDown() && !e.isShiftDown()) { //CTRL switch (code) { + case KeyEvent.VK_F7: + return stepOutActionPerformed(null); + case KeyEvent.VK_F5: + return debugActionPerformed(null); case KeyEvent.VK_UP: return previousTag(); case KeyEvent.VK_DOWN: return nextTag(); } + } else if (!e.isControlDown() && !e.isShiftDown()) { //no modifier + switch (code) { + case KeyEvent.VK_F5: + return continueActionPerformed(null); + case KeyEvent.VK_F6: + return runActionPerformed(null); + case KeyEvent.VK_F7: + return stepIntoActionPerformed(null); + case KeyEvent.VK_F8: + return stepOverActionPerformed(null); + } } } diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/continue16.png b/src/com/jpexs/decompiler/flash/gui/graphics/continue16.png new file mode 100644 index 0000000000000000000000000000000000000000..184be23125a64eb0a80617582aa9e45c6f0e8c58 GIT binary patch literal 742 zcmVA-TnxX&OtGGJ9Wl9&at> z64AfGk*-8jW5*!%ji%`L0eUi4SZHM6v>KBKEQj>>WiQCI2u7w!vB_@dJWeh^$fvA-VU>18;| zfD;BK*&2BtFFTCx*GhLOySwhGvGONLMk=jWfx{L#JjFwu~?wkz~_uRx5khd9>ep_ zQ}9EA1QVX{MYpmC*>wNV`){a;^4cvEmdOU(IJj>co;;1C|MqG4zMMDdgu)ZP=!z-o z8gC5H$Dd0yohO>e5GDEMrE)}{e)%++CHk6Kf%JtZe9;vz()Y~7o2zXPM=?8>M|HWZ zlcVt+-N14ARN>it8@Voh;R#=KrSGC*&)N1?aqf9FMalVq=Hv}9FuzPnw&Ga@2NOxDg`J$q# zyMDH*0$W!WL8Ha4>l%7TG>k;`q?i4whyuTa`Ew*l^#AdeAZp(J6tQUZrBl^gpQ0u0 zb_ghy`O6CHT< zz4qRZsyEM{OhTS&d1Lpkdza)rM9Q0cqUauqfy1pxw@w(xB!@^#Zy5cf3U=PJki20O zh(crc>HVAUNF*U8#=LTG-J!b{6>iwGr2^-IQCt~`LniGKnJx;P=@vv$Bv_d*B&<*D zo9|c{j_9}%HL!6-E-qgF%BNOrEa*A;_a-MX9Rk9Noz;sn3QGQ1^VoVyGM(ZbgG_Fe z9Jkw$XhEe7nS5-8!?1EfmFwbhEGZlLO(QlW*SG=N* zbxsf{TDvvd<8ha7q&olNdd#$lW6p_`2-0m@-_jPufydY3=PxwC>yl_qF!v_E@4(5Q z0C{!u>iJLC+=i@{uPDhjlSO1JZUKt`bw7`an)kb~_o21;>GN;G z*fNhxF{D`W&?PVA$+$aS8o<8fn=%_(S@mbetvJeZA9DAnVJCFzu&ZcJ^} zk|89`Mmcd)CKqUek(xk)2cm`u7r9%oW!IKu;<-0I#9#JqqY8q?5WZ>15q} zTs$1=ZaCZ43!fs)q6#bmnkZvlrWbYfC-B#O+vx^mK-aD7SxQ-Akwy*pTzenJLzf#^ zHxmd4{_*nR=C-TkQczc$*$eD5jeHyvDf5s06G!%w^0+>uh0XkB)e{tz}Z1oZdi5)jvZ;j(Q3Aw{K%IT2-C~hkm<|} zYCA_xc0iAgbqh%o2)oGEN$=&a-Ao0XD5$NRm`Fx^*|4 zZX74VM}|cxK@S`~kIuIaK60Zk5FoK}=RTm*!kE9TvgE6ny7-=D^URvojp<47I^PE- zuH`c+Hxp09oHPN?{<#^~dIHDWj{oj861&c+G(mv>={?(cA-?dw2lMA8e zsVTP}yHKs~ff+!abkm&9@Ctab@e*1-4-R~M;Nc&UXdlOa@|BFQ&3f=;?b|(B>+dhj z$@DHR@|$YRHa!bBC*7P#xrb(5x)(Uu(294@c7&RLy=@B}(?b}xjZPxK{*3aRxpJ!Z zonY4bZT-V>&o>v%BP$Z`gSdI`n{MP%Xk65;)2N!p!Ww>g_#Do(b`O&Bt^8R*807Ms z?o#T6BEm$1r)rzVvX|$d>KG}@O!uJTYd&ktCe^hC$(|8R)Z;Se4URQ;;$mZyjnF8@R%C-cR7$@7V2rnkDWlHjy+!Iw6DLNw`rbhHsoO zWGC6EtvL4oewPcJdE4r6-{OF literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debug16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debug16.png new file mode 100644 index 0000000000000000000000000000000000000000..03e5eb2b4a330daf3443ac9cff3be3004ba9f582 GIT binary patch literal 952 zcmV;p14sOcP)Z_B&&>Cq|52*;?FU80($ZPib(jX% zP8=9N8`0Tv!!U@)V;C{B&afTtR_C?hFRDQ`?}BZSFjY+Osx4nw3cNh`9e1tN^4E4% zvU%I9tn?Oh$JF*z=eJ?nf>5+%egcU2M2p`yWKLud~yPPc6LTOYuJiz$4zc5_26BT@4%IACldru#87f?j@~;o z`8PWy&l?tudcQz4a)-Yrrw_j5>OS(!Q+eL}71@{)vjuN27FZ(3s?`dk!6|RJ^(W3n ziVrULxFu$zuP7*>rNwvb%}pG6d}9Tc(~TJ&$G$hWIDvw$XOfoYAvZ5hdututSKE%g zv*$gDT4+VZ8+NbVP-fJgRzPI!2b;O~tLoTz2$(m9NgQPL#-*2V)AJSUv2 zYQ~wGdm<}+8TwbXN1u>cCX1eBTlCfdOIJUHBlAI;N-{V-5D>EZQ7xG&CeN|cd13t< zvc^;V*70d$mPbge`tU%<+OE%tiY_AKgG6q5hz5r^qxW&T@@t|opRlQlZsyU{9Q>hE zyjZ*oT|4(@Hz(#qLRLnIUmxjdokL?>^f6+$?6gDZhX?we&dp*Wyt;v{7y zyJ_t`UZHEUA_wM&CFRw`_N^8E!A0ji=4OE`GDVnG{!j={xC_%0rzN_Azq$PynL z?%y#M;c|5gr9ELj&hgQ|{Rh~3hTg(&cwb8u!kiEohYp_?0q-rVWk_F=ot^v_dOF)1 zzSu0PcF?)+Jj2rHNAV2tgrb7a>wGyhBAtJs`O)du%c?5l0sgT6<)?)Iw~|FK{BQn0 a0t^5K5M5WnA=2sq0000sz2}DpJV=lF1a( z=@c%-6HVs^N8Y75VG`|H2}oBn=l)yKF>?Ku!-4YoQ1V%*sw#+Rng&HR;3x^SR}5_W z)$4faTCKnYeD~h>f`jjkQeQ0Lif@oHJweX7sD_t0w=JKF)ZN|381}o0V4hHckXhM-8&-K z&KSHmV=&fS1gwkE=)szKwZG{2$`-ZUN??({7abj&;MCN^%*9~mE`CVB`N+eyh~yHG z!j**fDQu{@3CZZbuDdp^>&nUVM7AWSrhZ#&{^|84p>VkI(@Q>cM@dzEYjg1RmhH>Z zei&r-@)A@m??Cvv#R&K<1cDNLj)rMRIN}$Ap&2mjFbb1nm^yO+W=chd7#@yRn0?yH zV@f*y>hSQ;Aqw6xTBZ~eAP=LAq?TmC-VXG)F9I4KdKIbH_9Om}BQP>C_-h*Bglgfh zsD~~4L_nIR1)auh$^tb`dzaUv{_}09UHf$m{HztHCxPupv6}Y1NRlAQli0;Bu)P7D zm6C}LDFmoFR4;EqHl>q}G8)%3WAe3wh`xCoY9a}VDOc8@`g6CTcGWhFo<0G`wo!Xa z3vG}Sdj#An6ZHrf#o#jwk?j=`g-ycIZ08fO4Gl(qiu_N#RQ*1&=Bvo+rN~GAB*MFF zSqFiy7h^__=2Ns<`8a%m5Om(d4HV_S6{uO2ko{rNVpB;I0Ud^trH!diA+0IW^lZ`{ zCo$;VEF>UNgc|vbh%i&hz&3+oj_(>uvD~@&&f6yv*}EmD$J>YqSUOC#;A*C31OcOv zg+-cKG)X6N76D2Win^L7Gg2*3(~y~f7I`aA^2_X9f1LdG!MMo_(tnh!B~WG;=MG6Tam+U_k0;B%S851q^bP zOj$zpOVo&Uht|^wc)ry$mVxw z2Se9{1xz(7s-64o1*%H#1k6p>b&)L`j56giTgY+iUYsNaHzu{Y2Xh51=HTh=Z@{rcTF&o2Hr0!~!% zkEL}kW=W{YF^aP(Sh_(q!5|>xvIPWDGMA4`AD~N#l+$6w6L4bZ={W_v0DO=sIcJg1 zUt9TetiBNo*6qaeC@K##)571}vf;@${aWMo`96e43aGq}^4eto=b)r7z!xkfVE5c- zEBGx5-PRC}={ZPi+!N8URrhGVgOD8MCbPiFA42QR-=Yc6c48O)(z^rSm_8Y&3HaOE zHy)CG!S-a%_sR!4Dg!>OsvmbmDzQrpT@fzHB{RZq>|;BA34KIn|JEmw(hgEZ^nV!W zlDp8hP3oVAx1-Nu!;0?^($k$1k@%ZOLab<6*ZQTBlG1iXQTzJ)dLH)OfTiW7Sd}A= z^+DH9Hv1WFeRnRqfX3)Muf=eB=&-;n&NFcwNQWVl_uq*owF>Ly8n(HDFr7DLP!(f+Y=5> zopnUM`Xm=zH{EMk!J+t|%NC1VEI}8Xoy}IT0~*eZyhHa0oM3F1Kv~(Xj_nM1Mal5) z2hrc0#E<$%@qi?|o6s2pF1&HlK2A*H9BibO?vElw_k&qNg*Q;*l3)qYC1#Xv2EE4- zIkpS;F&1+Rgu|gKRaM^dZn5wpl&hE7Gl=~pr?#!e4{w}@yI2d>n$jLYnze+izx$8< z@R_s!5peLD)c@^oy6>Z-z_DILBEQ7_G(5oyiy)-IH!|sTUs0vvEm>iT0%ZTtk4Naa z=iW8AXK^j=R7q0jnLjb3 zEYEB{@2}VN+-k2siA_`kFol23Yy@`-z?Sjqo4fuMH@foH*4 d7XFU_0|1!nZnLx5MJfOQ002ovPDHLkV1g3YJ)i&p literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/pause32.png b/src/com/jpexs/decompiler/flash/gui/graphics/pause32.png new file mode 100644 index 0000000000000000000000000000000000000000..3ab8b69db2782806559e5ba9cb057bdf899ea869 GIT binary patch literal 1962 zcmV;b2UYlqP)*DuuOMMXlQpx6u zJClcIxVFAE0pSa9apvO~`U zK$^0t{PuhEin3Nt&x86_75?%D0A+zl%7wmBn*cN^?}@FK?XMEXxv zftU8629FgT=8wsMYj++wbE7ji> z=57~^j3Y0QP;zJ>q`}5RH_;;kcQ<*7EbNOHimF%o@uBQtX%dtaWbFs;O32Q{n)#LQ3$Jwy9C^vx6Fx)%M#NP*oZ8KDD%DEr6ne5Z znj%%8Ls(;IrG#x)j>MUGtZ!Z-Id;@>wE?>@>ZAurbU5H^EWc3O3=T=?sqI)YtP~h# zIx4YBMyA6vcyV$NMY05NvCa$KzB}dg7y$^lkL})9ReKN710-3W^aA-wMWHH_u-0vO zpB2~8b23T96B2m9Aq&v0s5lk<;6A#0AL*tXP}-Yr-1qtX4JWR6^QRTLAVjB+NS&f? z)PTzw#kp{>>A6XB;5H$hXn8ro1N={8fOzia%w>62D` zRK8=~tGrosDZNKHbL7%^CV_+v8y`-)2uSMxPx3T8MfKKOvXy~~duz5I19$oMMc&K5 zSK{^~^E{wE_PV>A1tocpLh^{2#e*P>^{UY*H6YS|l?&H7shVaS%k@5Z#_^3Oo(Kby z1=#pw72I!fAFMsNeJ`>f(m}Nc04rj2u<3IPs+wb5lUW$MGk&Jw0?q6e3 z<$b=GAPqpu%osIeRQ`ewKF!ETA2PMj1tlZ1AV1TI2an!1OhTxYU%k}|=dL%ynH$Z} z-O+a2UGeqC2Q`1zAp4$?bfFh|HABJ(!a$_-q=DIkUY@^hQIe}*u4r@QX?pDI9zPod zAK&Wq)*W~MwyV6$f0ydK1&L0-T`&4-7R{FoAjwGmkW!HB#vF+cUpG>lkz}2Q;?Vzn wIZfmdnFg9MMH9UqhK=%4`m#9w^Pd0%0D9&Azh}>Zm;e9(07*qoM6N<$f;khPF8}}l literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/play32.png b/src/com/jpexs/decompiler/flash/gui/graphics/play32.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f7345f3713a730b613faf82026caaa0adb375c GIT binary patch literal 1971 zcmV;k2Tb^hP)FuzPnw&Ga@2NOxDg`J$q# zyMDH*0$W!WL8Ha4>l%7TG>k;`q?i4whyuTa`Ew*l^#AdeAZp(J6tQUZrBl^gpQ0u0 zb_ghy`O6CHT< zz4qRZsyEM{OhTS&d1Lpkdza)rM9Q0cqUauqfy1pxw@w(xB!@^#Zy5cf3U=PJki20O zh(crc>HVAUNF*U8#=LTG-J!b{6>iwGr2^-IQCt~`LniGKnJx;P=@vv$Bv_d*B&<*D zo9|c{j_9}%HL!6-E-qgF%BNOrEa*A;_a-MX9Rk9Noz;sn3QGQ1^VoVyGM(ZbgG_Fe z9Jkw$XhEe7nS5-8!?1EfmFwbhEGZlLO(QlW*SG=N* zbxsf{TDvvd<8ha7q&olNdd#$lW6p_`2-0m@-_jPufydY3=PxwC>yl_qF!v_E@4(5Q z0C{!u>iJLC+=i@{uPDhjlSO1JZUKt`bw7`an)kb~_o21;>GN;G z*fNhxF{D`W&?PVA$+$aS8o<8fn=%_(S@mbetvJeZA9DAnVJCFzu&ZcJ^} zk|89`Mmcd)CKqUek(xk)2cm`u7r9%oW!IKu;<-0I#9#JqqY8q?5WZ>15q} zTs$1=ZaCZ43!fs)q6#bmnkZvlrWbYfC-B#O+vx^mK-aD7SxQ-Akwy*pTzenJLzf#^ zHxmd4{_*nR=C-TkQczc$*$eD5jeHyvDf5s06G!%w^0+>uh0XkB)e{tz}Z1oZdi5)jvZ;j(Q3Aw{K%IT2-C~hkm<|} zYCA_xc0iAgbqh%o2)oGEN$=&a-Ao0XD5$NRm`Fx^*|4 zZX74VM}|cxK@S`~kIuIaK60Zk5FoK}=RTm*!kE9TvgE6ny7-=D^URvojp<47I^PE- zuH`c+Hxp09oHPN?{<#^~dIHDWj{oj861&c+G(mv>={?(cA-?dw2lMA8e zsVTP}yHKs~ff+!abkm&9@Ctab@e*1-4-R~M;Nc&UXdlOa@|BFQ&3f=;?b|(B>+dhj z$@DHR@|$YRHa!bBC*7P#xrb(5x)(Uu(294@c7&RLy=@B}(?b}xjZPxK{*3aRxpJ!Z zonY4bZT-V>&o>v%BP$Z`gSdI`n{MP%Xk65;)2N!p!Ww>g_#Do(b`O&Bt^8R*807Ms z?o#T6BEm$1r)rzVvX|$d>KG}@O!uJTYd&ktCe^hC$(|8R)Z;Se4URQ;;$mZyjnF8@R%C-cR7$@7V2rnkDWlHjy+!Iw6DLNw`rbhHsoO zWGC6EtvL4oewPcJdE4r6-{OF literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stack16.png b/src/com/jpexs/decompiler/flash/gui/graphics/stack16.png new file mode 100644 index 0000000000000000000000000000000000000000..6d659e1775edc4549305947db8fc50b53d659feb GIT binary patch literal 1444 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHmFXG>Q{BU1xMb7L1nLsvsfXIB$fXG0@L zLlaXcV;5tXUYGpj(%jU%5}4i;gkD3OdO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#INf66 ziqkx(-V~f}F>%AGS0CsYeNesF7t(ud<9`KA z$vb7qfB&;zcI#ue`k1bCqCb}Be=(UEl5p2sR!MBCSjLtW3$h&> zX6Ys)n7if{f+tUQigSpws5UYcsP42+n$tz&!eCFvoNTyS;GYZvu>5%GlFyfzJ1{>DS9hlouTH}#B1{u zxhC1)-^a(5`}jB8tNZgd6xFYvzSZu@krgJgzxaR3nfF&I`u^~5U}QMIR^!rlL%GGE Oa?{h*&t;ucLK6VVXc)Et literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stack32.png b/src/com/jpexs/decompiler/flash/gui/graphics/stack32.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae41eff207a33bfb1476eed7863c2079f256f78 GIT binary patch literal 1984 zcmaJ?dr%X19!~&)hN6f_BT}*kZcu?dFc=aE5Rz~N8Xf@#YJ-x;#)Ob;Og1Dzt%Md& zk5=Qz38#YPs!}L&R4BAX%hULv7DNY81mVO4TLnZBEmm%0#rBWVo!R|8=JWY{U!R%X zmz?-_cZ?4Pg+jS=%jYLZ4vtwV!LQV|442IQoB2ll`6Z9JhkY*c^Orz0=q)=jLXb6G`(Hd2-&=8{1 z`Y$N3L9JLLSHp5h1=tmZB1i`_@JOb=m7r9=kyUA5w+U$&(I8Y4$pn(Uqy-?4_t#LR z@(o%G^TFTq{ZnCWno$iB`JfikX~f9jr2h6$YC1~;3Smf-20^(CT}+liFr<}1YJim* zMj!(ja+L(qYhU4cJUUmUg@r0H$YnF|hyp<_m(VHUG!}Xof1^R3tY+XT=t?|yA_mbBr+S+$n!u+tOim7uS%xN7te*csNQR? zWbs^L7UdF=WQg{`{$bDySBQJ;+c&mF4sVPPst~tp5L*Y#`r=S1CkmI%Of%eSEbT7# z%J8!ERM+Iiay*?~4yKT$m1Z>aojt)z-Wl4k_el1|j-t25aOx`O?T`U*k%QK zx$vU@tq;duJ{;JSy00lZwLRwRk60XZo9jBL+n9^T_27nWxJRo_vH3kzCEZPs4ITZ=K6m9ru3U^3QdoCq1Qs z+eV+6h}qp;7XnUXA131|E6&t6TG%lNStX2BU*h2zDH~g-PROW za!BbOD<5sy>wf*fl{^D=e~*=JzA)FK6rZ?sB`)(UNA@?@0bAR=rG@hh?-{jg=H2V& z72eq?zT+!Nmj{QpN8WYs7{q>1-Dxxi=^su|6~bSpS8Mjw1?B-Ry;yhZvK!}L?y8cG z^k0>qNy*6Zj2sSGf79nzrNHQdE+sF?MmwgrwI~nWE^hsi8BIMO-+mxz-sExl_{u&v z8J7rY08G~0y@XHNf(lw?{Qjv^#@kkDXEA`8Is3oP#^wfX3 zl}%Vjs85r;@Xvm_wR-vJz0=2rHs=Ps-MA(X+ zB}V?1E@6j9+){JadToKFFaLhS3Dn;fm*>^iUHTai{ zUufLsf33eiv8uf_-RZjQY~k*vbmu6;RM7pH3{P)AoD&w+aKS40a!fm9|EF>}iR`+V H?85&8P`fR_ literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stepinto16.png b/src/com/jpexs/decompiler/flash/gui/graphics/stepinto16.png new file mode 100644 index 0000000000000000000000000000000000000000..691f6e0c7c86f88608e3a712044d0bf2b15d854a GIT binary patch literal 381 zcmV-@0fPRCP)EKoEw%ZLQCtk5Hm0 z@!kq57WxpPS1&$7QF_<6Q1GA+(1K`g9))_*g9kC-!K7rz*)&S9Zj^fPhhhHA%>Mkd zVU37ThA}43n|)5l8QYFG>YSbL({cRkd|oKW2U>^7Sgn?c~51DT;)X%j_2UZC8I$c`LE}~tl;rOoBTyJXCZ{9-C?s2oS z42uhs+UOpxuHo{4C7q9c5^yP4SCOzVI~>4;9#$It`Y}0?jU&W`Fi@?Avqg~g4kHtrLh!IM6eO8{2>^`($>yK1kGV_>K1nC(xeEeg%B(h4T-luH@-JF zx3_oEb635&!hy%~&ENax{mi}*QcBcnLWn4|2UoD|149K~#zMm>5*ygvo5cwA_|XNA z?QbJlYhmSUqciY)t({mj*#eVWUxs*`h;#RP^{HuFJn)uObE*`_whCgx@yZ4;IPJG~UpV`w|3NZvP;c`H24aT}1*He}7cC zfbr)sV%iLxoB{`j$mtUOQ39zrF5jQWbaofc&tC*M`0f$z=W(9L^HpfXXmJSqBRM}> z##Al~=j4pcMs`c-s+hlwxu3^*9?#e7;?()Eo@T7>ElFqJEWTz2(Z}xKxL|)Pv+u!i zR+Mt0f=iX1F`i~>LM@3jCh?Bs1Ccmda3D9&A^FRg`}Me$WPg$HaT;18Gl%tbJ9=-g zaD1?ciRzQbeVisG5GBz;(nfNveg2>FdJ!n4FQ-`(iKhe3f5^qP+MNIc0MZdULgJQl Q=>Px#07*qoM6N<$f-X=wQ~&?~ literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stepout16.png b/src/com/jpexs/decompiler/flash/gui/graphics/stepout16.png new file mode 100644 index 0000000000000000000000000000000000000000..6a7c9bc187c64885de4405631bb82261e8a687b5 GIT binary patch literal 565 zcmV-50?Pe~P)aOuL=d!aA+B;|n^5p;69l7CLK~5oZK6b*J`BGSYJ`b!5JgI@87!q3 zsIam|n~&SM^WF?EX)(=#d(XXx^Z%d!x#yy_#%sab=nEq}qy)=jy##?_^v3o*ef}o8 zR05UXlp-*M9%&1+{H~Mu7g$VyrJO|LBn8{zzU|}6lWuRB4XG{=rE%JXoUDdpry01| zPw3Immdjggp`~@0rE9@XKBvMYK0##NX`xa|oTz~_jZj?$%_lpEzD+W_Iy3sTM_;vE z0kQc${CB3q)Kp#OTcoMssA;v!0Bz5s#^!qQSNa|- zvCj*0H^JABc_VJ-Y!`Z^j=|d61og+yQ5c?mXfm;>9{l2WJ+WW;m1Axv$)G_TXc>Y_ zVEtpfrgHpnFgnI7^Csq@GwNG0Zc)0W3Yrh(8>lh}9N9idm#M%pA^6Sr@)THZ_RmbR zc((tCAd}+RhZX;T(DIT00000NkvXXu0mjf DEL97l literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stepout32.png b/src/com/jpexs/decompiler/flash/gui/graphics/stepout32.png new file mode 100644 index 0000000000000000000000000000000000000000..c03843653e17c8b64f6c9121dc06cf72eefee8c5 GIT binary patch literal 1184 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 literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/stop32.png b/src/com/jpexs/decompiler/flash/gui/graphics/stop32.png new file mode 100644 index 0000000000000000000000000000000000000000..f15bf69219729772bdbdfad3c7c7b1ee7c157674 GIT binary patch literal 1930 zcmV;52X**~P)lpr!KK`L)ri>}onyH!Ulp=zTL0b`zNQcu$;r|Iuj~H4YkNNK7>Hi>qUX~#e3!$;CLJ{yjbj#0%7n=|$uMP9 z5*T^Cs3<9L^sVpn~2)Crc01!&HRNS93 zDkZJ#ok<9v!S#n;Xl(bZu4YjLl_24toCE>Jr8ECWF(#gn2=_MQ3*Wk|E&S`pQ~@VRJL$r zBnZRvCqL1&X3pr;WoW#rS%fCH4=CIM|KfxR9w`W`9_m5bg`(m8gb>EhOf zBf>%O;W01y`SX2bn4iO%7`oVzKc|1DDDANZ<#LIC3>gbW-nW(`0aVc=~ z{?k}v(fsu03qMr^6Eg^ajayNcAD^E6?ao!xG09|%w+{^HMqYC}r+yD9?vohn4HJco zh(MSyCUc5X;b_f+iSe2FKR&v7-W47KAttN%@S4|0qa+9Qu5L8WRAE}A*nkRnLO}-l z$pP}cB+KB(q>(8Z2n_zKbBQo*xCK_emIwPp@i20Zr|MM!WKJzjvRKT8^RdorANy1T zg611?serEd`P|=dtWq zEd+qiC|SB{_Sg*Q!Af;`{Jm}m&5Z({z8a11SUsb6FIpkWTDw`luM(Ec9jBI|99C{l z)Sa6oKuKXLc->1^A%HIkfRQ)bmQTz{LE~~D&SARA{p5Obyw|V5=Hs_jK+*bu4-J-; z7OK1?L$curC=_I4LUuCze#5pLcefJ&vtlq7j>}F0M~9>)n;t-*rpY57p8__kS#86S zk)X1pc1%3Y#Y>lt$Q&R>UJRj+8#1_F-J@$qgo-+LcqxZ9^wtkg)^!) zF%Gs^Avm3wAzTA(^1NPopacW$ty^MX5{!Y6L;=9d0Ur7hY+x*sM`60zXb693z@tk{ z(F0(ioDgLMfFa;mbO7W<;?c=5JrBdpHn-TjZ3xzSR}Z>Z;M6?O0|-?`53;KO`e*^N z#uEa-o&#V;8(lp;y?JF&_kGZA)(Du5ra;m}?SxF_p>KUv zfkj|Yc^kVh+9XB-;P*P4%CFY7Y%Iu(2X{nz2P>Z3>*q{hvGV;kLO*BdZAhwYxH{Aw zBLGy_w?en`emSud0I&Vmy$7ob#&2BxW+7Oy9KAjzOh!@felvpVo_12u}MQLhB3)GAjTP&@$ zizdRlwe{>G$iwa)!= zprZv02Ku~&osRbXQvW0&4>g*gJW;HP$BU{A+m2j=#*@3=d)8{VQ*R3fRK^XDEw3c| zsn1w2YwR%aW4+1|N(OW#3gcIaqr~H2Xbgi*-&et-X8W=EY=M#z;A67w9%heOt z{kikrPD>nO&C9T1JUP{+Y!J609ib=91|H(A40fNm1vPgZuFKoreIISLQv4&YWOQwo z9TyIrYEGEGI3sz8wII``9!a}b=uh?nqAqB`t9qOjU{`r9oVnWItonS(B2?2%Gf6wN z4glqXNb}-B<)PD#gy~D#I{cQG^M~On!tQ$sBlwK>4+Nu1aT}ngE41qW*4^?=Qiqk3^I`f9aS)gcmEGh@RQSBbcYx9DDT1<^KiwV+Dq|}r#GsomCSoc{di>zsRb2)QtwyfyeF?mGkd3Lv}wf>C#jBky8xq}qJ%fEU3x6(XKw^;M zkm9MOtDW}w@O2}(wIu7(4Ez4?%V{)^7-^tsLoC`v_G{%O_I2XO^`8I(0B7{%1Lh;d Qvj6}907*qoM6N<$f(mk(X8-^I literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/watch16.png b/src/com/jpexs/decompiler/flash/gui/graphics/watch16.png new file mode 100644 index 0000000000000000000000000000000000000000..b81b18de127fdd1d5fb09b2250b89c5f2fbf4a2d GIT binary patch literal 783 zcmV+q1MvKbP)@y&1<*$6qAU z%F4*BkTTTFG)uxoyV|rU+Vx{)B)N$s!)@rK7St-FMNkB3kb{v{sMt6V6%wYP)HqY> zq>j&-c{AU;-N}C5R0LgkeBZm=bM85p`$;fF`;D7Tx)2u#6c1X?Ns<(l73J!gniCE9 zEr{sXkG-|s?da~NNKhqXL;@-~9(R-dTD$vi1XA?UY;Se%EicR3vaJyIUM~hG{4mEU zFqtImUZ0HPB^h|_a-r|Vz*OD&+Uytw&GxpY&dx4UHJuLMeor0F85)}j(JRjq^^7mj z^`RN6b9g8uh&ms3QncPkAcr-reot8m+Il@Wur&=;8*P}=1g3)m^ARqvD6l4&aCc-L z6}w8HX`y^Gu8*LB1akbsB?n9T~N7^!l>Vze`ZSaw($bFdTZsGd7D!V3 zYn5?Zcy%?bRvXH5=8?BK6@zzLPm literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/watch32.png b/src/com/jpexs/decompiler/flash/gui/graphics/watch32.png new file mode 100644 index 0000000000000000000000000000000000000000..9cbc3618f5ad94df90ca1cc1d726a76c87687874 GIT binary patch literal 1912 zcmV-;2Z#8HP)RhC_%=of2~iV`G2#OyRH72DiQe4g{&Ce1iA4XnF?W*F$L##h`JC_X{LY!>48y?x^Wv`d z+4}Yk3+d(?}b7ky!ZZQjEx2F{nw_A+cSlj0Jv-U-9^nUt^OxhuR?x) z0m9=kJiB=h&W1JQ7nQ)BTLeMmV6$-q!b1*?;Ns9Z%y4q}@9L#+=VT!m9K{Elx1hJ@ zTTkcCFGn%~5Uk%~!@T)DOIn-F;A0UP5B~crIP%KSx}Y3OYFwx)ln{z*7*FV?4F;V! zQ!yQ92G8MvcXr~lHFuh8nGac(dkCPO{3fRYurU=LeeCf%uh;wf1NYy@1jaKT_90;} z!gI@R#636VL8PolV=BUmhDd@Sk~+ZCLY{}1;|3?#(RJuF+7?uzq@)zzA3f$NEb@GI z;)mn@sQ`GULU~2Srp1dEQfv*okDbK@nZwOB<(OOQ#E6{4sG^!dqnd#j#a2u+pinK? z?Hnq+r5H6tbR9iw`e448&q)ej6~H0bY`0aEmC<4qT|fHa%JraimK#BqHD#=*6pVt$ zsjL#rs2Jm9y1)|vnaHEkTZXQal(43P`C>kq?@RzBs%poy;$ni=aB^6IBP$zK1#Hh% zL@9WTg0rmSlY+;o5VIs30oWiCK=JefS{oxDDokJGllji12zf)-q0vJ60ZDS0l^&*o zlM|`nEU+0IDS#xM9fyNY9ZA{>UDKgz9KkrC(H1ZW=F>`W>QlhxfzB4tVo|h{e4JTq zvZ|Yzr)5uPFG)Ojo7EEtP*pjW2CWrM6?INWrZZ-uNZ1067TYKb>hqMnj+mN~J{6eG z6y+n4+#<;?2q}Q1s$1{2#c@M%mg$4}Vm>nk(4*tyeZDh;AT_b5R0L-e2tdK`coG4U zAWVC}Up6%iOEpHz6dMjCu(-@l0KmZDAms7LK2w$q01~H8{j{aO{}2q$h6ay;>28Vk z-v+;|(h<~2U?Wv*X2BUqQcp-wZ%9y~YV`T<7Ztb&VxEU0(&^Z@?*P8-?tU8?sK5Y} zu5Z5HAMghT4jwuT)!^}XO`Igoh6<7DLN}{iqrfZ}3!bFA<$`ASvdx`#9?S8fX~0^KwH}i?#9{m&wstE^DSDTO$ER%Eh@{&Y-je6 z-ygW$J98%T2x6`)3>QtnsP4pY+>K}=3z3)uLD`OcL&XAj7nCWK zdoymmbt$r(E>zbwtlzzB`=+Zwq>mw+T7g}=IyBx|}HLoMFmZ zpETmBDrm1cUVtG;IDF(gba(gQ`s-_{jk_R6W2mmFg$IYx^zP#LEo%<2j+mJ8g@i1d zYivE{emi#_M~)nU5>M!*Wu-iOi4m!j z@`4k~TIL|n{u^*=E&BEXO)qp`5rVtI|Ez}>lFgVktG2eWspTn`%Qc_%^~nIN!XuH$ z;qE=V-}CtfMqgRGuCu(V3WAi2o227dZ2uT&`4rSF2;v2T(60#bXK%%#r3QO1D?412jAkAq!fyblr<;--8$!r z_3SjVs%>xF)?4d7kBU5#P0d-Y2V#^JY0?8u!2}jOX<|JlAfSH>i&bqRtbe}`~LK(=5g(=35bWn;Om`>=suej!G989GDHbk yPWo#l*?CK)#6Jy?hRC*hOS0a=M00RJDa7Sg}Qvxjj0000