diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as index 0a5e01a62..b0787dda0 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as @@ -12,17 +12,30 @@ private static var first:Boolean = true; private static var inited:Boolean = false; private static var name:String; + public static const DEBUG_VERSION_MAJOR = 1; + public static const DEBUG_VERSION_MINOR = 1; + public static const MSG_STRING = 0; + public static const MSG_LOADER_URL = 1; + public static const MSG_LOADER_BYTES = 2; + private static function sendQueue(){ var qo = q; q = []; for each(var m in qo){ - writeMsg(m); + writeMsg(m.data,m.type); } } + private static function writeStringNull(msg){ + var b:ByteArray = new ByteArray(); + b.writeUTFBytes(msg); + s.writeBytes(b,0,b.length); + s.writeByte(0); + } + private static function writeString(msg){ var b:ByteArray = new ByteArray(); b.writeUTFBytes(msg); @@ -31,6 +44,14 @@ s.writeBytes(b,0,b.length); } + private static function writeBytes(b:ByteArray){ + s.writeByte((b.length>>24) & 0xff); + s.writeByte((b.length>>16) & 0xff); + s.writeByte((b.length>>8) & 0xff); + s.writeByte(b.length & 0xff); + s.writeBytes(b,0,b.length); + } + public static function initClient(sname){ if(inited){ return; @@ -47,19 +68,43 @@ inited = true; } - public static function writeMsg(msg){ + + public static function writeLoaderURL(url){ + writeMsg(url,MSG_LOADER_URL); + } + + + public static function writeLoaderBytes(data:ByteArray){ + writeMsg(data,MSG_LOADER_BYTES); + } + + + + public static function writeMsg(msg,msgType=0){ if(!inited){ initClient(""); } if(s.connected){ if(first){ - s.writeByte(0); + //s.writeByte(0); + writeStringNull("debug.version.major="+DEBUG_VERSION_MAJOR+";debug.version.minor="+DEBUG_VERSION_MINOR); writeString(name); first = false; + } + s.writeByte(msgType); + switch(msgType){ + case MSG_STRING: + writeString(msg); + break; + case MSG_LOADER_URL: + writeString(msg); + break; + case MSG_LOADER_BYTES: + writeBytes(msg); + break; } - writeString(msg); }else{ - q.push(msg); + q.push({type:msgType,data:msg}); } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as new file mode 100644 index 000000000..cdcf3f3f4 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as @@ -0,0 +1,22 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.display.Loader; + import flash.net.URLRequest; + import flash.system.LoaderContext; + import flash.utils.ByteArray; + + public class DebugLoader extends Loader { + + + public override function load(request:URLRequest, context:LoaderContext = null):void { + DebugConnection.writeLoaderURL(request.url); + super.load(request,context); + } + + public override function loadBytes(bytes:ByteArray, context:LoaderContext = null):void { + DebugConnection.writeLoaderBytes(bytes); + super.loadBytes(bytes,context); + } + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as index 0ac6bac75..a78ed0a95 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as @@ -11,6 +11,7 @@ debugConsole("test console"); debugSocket("test proxy"); debugTrace("test trace"); + var loader:DebugLoader = new DebugLoader(); } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as index 7a35251ec..ecb897385 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as @@ -2,10 +2,11 @@ import flash.external.ExternalInterface; - public function debugAlert(msg):*{ - if(ExternalInterface.available) - ExternalInterface.call("alert",""+msg); - return msg; + public function debugAlert(...msg):void{ + for each(var n in msg){ + if(ExternalInterface.available) + ExternalInterface.call("alert",""+n); + } } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as index 121ab0867..ae40b66fc 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as @@ -2,10 +2,11 @@ import flash.external.ExternalInterface; - public function debugConsole(msg):*{ - if(ExternalInterface.available) - ExternalInterface.call("console.log",""+msg); - return msg; + public function debugConsole(...msg):*{ + for each(var n in msg){ + if(ExternalInterface.available) + ExternalInterface.call("console.log",""+n); + } } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as index 0f93d6137..6bf16b0e1 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as @@ -1,13 +1,14 @@ package com.jpexs.decompiler.flash.debugger { import flash.system.Capabilities; - public function debugSocket(msg):*{ - //only on webpages or activex - if(Capabilities.playerType == 'PlugIn' - || Capabilities.playerType == 'ActiveX'){ - DebugConnection.writeMsg(msg); + public function debugSocket(...msg):*{ + for each(var n in msg){ + //only on webpages or activex + if(Capabilities.playerType == 'PlugIn' + || Capabilities.playerType == 'ActiveX'){ + DebugConnection.writeMsg(n); + } } - return msg; } } diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as index 58ee09b11..885581190 100644 --- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as @@ -1,9 +1,11 @@ package com.jpexs.decompiler.flash.debugger { - public function debugTrace(name){ - debugConsole(name); - debugSocket(name); + public function debugTrace(...msg){ + for each(var n in msg){ + debugConsole(n); + debugSocket(n); + } } } 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 e4059bc82..f2004fbe7 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 @@ -494,6 +494,10 @@ public class Configuration { @ConfigurationCategory("script") public static final ConfigurationItem enableScriptInitializerDisplay = null; + @ConfigurationDefaultBoolean(false) + @ConfigurationCategory("ui") + public static final ConfigurationItem autoOpenLoadedSWFs = null; + private enum OSId { WINDOWS, OSX, UNIX diff --git a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java index 3f8509df6..b0a28f7cc 100644 --- a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.gui.debugger.DebugListener; import com.jpexs.decompiler.flash.gui.debugger.Debugger; import java.awt.BorderLayout; @@ -24,6 +25,7 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; +import java.io.ByteArrayInputStream; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; @@ -61,6 +63,16 @@ public class DebugLogDialog extends AppDialog { public void onFinish(String clientId) { } + + @Override + public void onLoaderURL(String clientId, String url) { + log(translate("msg.header").replace("%clientid%", clientId) + " LOADURL:" + url); + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + log(translate("msg.header").replace("%clientid%", clientId) + " LOADBYTES: " + data.length + "B"); + } }); Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 4d68cc83a..7d6459a34 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -30,6 +30,8 @@ import com.jpexs.decompiler.flash.configuration.SwfSpecificConfiguration; import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; import com.jpexs.decompiler.flash.console.ContextMenuTools; import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode; +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.pipes.FirstInstance; import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; @@ -60,6 +62,7 @@ import java.awt.event.MouseEvent; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -77,9 +80,11 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.logging.ConsoleHandler; @@ -910,6 +915,20 @@ public class Main { ErrorLogFrame.getInstance().setVisible(true); } + private static String md5(byte data[]) { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < array.length; ++i) { + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3)); + } + return sb.toString(); + } catch (java.security.NoSuchAlgorithmException e) { + } + return null; + } + private static void initGui() { if (GraphicsEnvironment.isHeadless()) { System.err.println("Error: Your system does not support Graphic User Interface"); @@ -942,6 +961,41 @@ public class Main { autoCheckForUpdates(); offerAssociation(); loadingDialog = new LoadingDialog(); + + DebuggerTools.initDebugger().addMessageListener(new DebugListener() { + + @Override + public void onMessage(String clientId, String msg) { + } + + @Override + public void onLoaderURL(String clientId, String url) { + } + + @Override + public void onLoaderBytes(String clientId, byte[] data) { + String hash = md5(data); + for (SWFList sl : Main.getMainFrame().getPanel().getSwfs()) { + for (int s = 0; s < sl.size(); s++) { + String t = sl.get(s).getFileTitle(); + if (t == null) { + t = ""; + } + if (t.endsWith(":" + hash)) { //this one is already opened + return; + } + } + } + SWF swf = Main.getMainFrame().getPanel().getCurrentSwf(); + + String title = swf == null ? "?" : swf.getFileTitle(); + openFile(new SWFSourceInfo(new ByteArrayInputStream(data), null, title + ":" + hash)); + } + + @Override + public void onFinish(String clientId) { + } + }); } public static void showModeFrame() { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index 6ade11fd5..015d6699c 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -374,6 +374,11 @@ public abstract class MainFrameMenu implements MenuBuilder { DebuggerTools.debuggerShowLog(); } + protected void debuggerInjectLoader(ActionEvent evt) { + DebuggerTools.injectDebugLoader(swf); + refreshDecompiled(); + } + protected void debuggerReplaceTraceCallsActionPerformed(ActionEvent evt) { ReplaceTraceDialog rtd = new ReplaceTraceDialog(Configuration.lastDebuggerReplaceFunction.get()); rtd.setVisible(true); @@ -518,6 +523,13 @@ public abstract class MainFrameMenu implements MenuBuilder { Configuration.gotoMainClassOnStartup.set(selected); } + protected void autoOpenLoadedSWFsActionPerformed(ActionEvent evt) { + AbstractButton button = (AbstractButton) evt.getSource(); + boolean selected = button.isSelected(); + + Configuration.autoOpenLoadedSWFs.set(selected); + } + protected void autoRenameIdentifiersActionPerformed(ActionEvent evt) { AbstractButton button = (AbstractButton) evt.getSource(); boolean selected = button.isSelected(); @@ -672,6 +684,7 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuEnabled("/tools/debugger/debuggerSwitch", hasAbc); setMenuChecked("/tools/debugger/debuggerSwitch", hasDebugger); setMenuEnabled("/tools/debugger/debuggerReplaceTrace", hasAbc && hasDebugger); + //setMenuEnabled("/tools/debugger/debuggerInjectLoader", hasAbc && hasDebugger); setMenuEnabled("_/checkUpdates", !isWorking); setMenuEnabled("/help/checkUpdates", !isWorking); @@ -780,6 +793,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/tools/debugger", translate("menu.debugger"), null, null, 0, null, false); addToggleMenuItem("/tools/debugger/debuggerSwitch", translate("menu.debugger.switch"), null, "debugger32", this::debuggerSwitchActionPerformed, PRIORITY_TOP); addMenuItem("/tools/debugger/debuggerReplaceTrace", translate("menu.debugger.replacetrace"), "debuggerreplace16", this::debuggerReplaceTraceCallsActionPerformed, PRIORITY_MEDIUM, null, true); + //addMenuItem("/tools/debugger/debuggerInjectLoader", "Inject Loader", "debuggerreplace16", this::debuggerInjectLoader, PRIORITY_MEDIUM, null, true); addMenuItem("/tools/debugger/debuggerShowLog", translate("menu.debugger.showlog"), "debuggerlog16", this::debuggerShowLogActionPerformed, PRIORITY_MEDIUM, null, true); finishMenu("/tools/debugger"); @@ -796,7 +810,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addToggleMenuItem("/settings/cacheOnDisk", translate("menu.settings.cacheOnDisk"), null, null, this::cacheOnDiskActionPerformed, 0); addToggleMenuItem("/settings/gotoMainClassOnStartup", translate("menu.settings.gotoMainClassOnStartup"), null, null, this::gotoDucumentClassOnStartupActionPerformed, 0); addToggleMenuItem("/settings/autoRenameIdentifiers", translate("menu.settings.autoRenameIdentifiers"), null, null, this::autoRenameIdentifiersActionPerformed, 0); - + addToggleMenuItem("/settings/autoOpenLoadedSWFs", translate("menu.settings.autoOpenLoadedSWFs"), null, null, this::autoOpenLoadedSWFsActionPerformed, 0); if (Platform.isWindows()) { addToggleMenuItem("/settings/associate", translate("menu.settings.addtocontextmenu"), null, null, this::associateActionPerformed, 0); } @@ -858,6 +872,7 @@ public abstract class MainFrameMenu implements MenuBuilder { if (externalFlashPlayerUnavailable) { setMenuEnabled("/settings/internalViewer", false); + setMenuEnabled("/settings/autoOpenLoadedSWFs", false); } /*int deobfuscationMode = Configuration.deobfuscationMode.get(); @@ -954,6 +969,7 @@ public abstract class MainFrameMenu implements MenuBuilder { setMenuChecked("/tools/debugger/debuggerSwitch", false); } setMenuEnabled("/tools/debugger/debuggerReplaceTrace", isMenuChecked("/tools/debugger/debuggerSwitch")); + //setMenuEnabled("/tools/debugger/debuggerInjectLoader", isMenuChecked("/tools/debugger/debuggerSwitch")); } private void timelineActionPerformed(ActionEvent evt) { diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index d534e8e54..1ae410f1a 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -24,6 +24,7 @@ import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane; +import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools; import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane; import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.player.MediaDisplay; @@ -79,6 +80,7 @@ import java.awt.event.ActionEvent; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -1072,9 +1074,25 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { swf.saveTo(fos); } + //Inject Loader + if (swf.isAS3() && Configuration.autoOpenLoadedSWFs.get() && !Configuration.internalFlashViewer.get() && !DebuggerTools.hasDebugger(swf)) { + SWF instrSWF = null; + try (FileInputStream fis = new FileInputStream(tempFile)) { + instrSWF = new SWF(fis, false, false); + } + if (instrSWF != null) { + DebuggerTools.switchDebugger(instrSWF); + DebuggerTools.injectDebugLoader(instrSWF); + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile))) { + instrSWF.saveTo(fos); + } + } + } flashPanel.displaySWF(tempFile.getAbsolutePath(), backgroundColor, swf.frameRate); } catch (IOException iex) { Logger.getLogger(PreviewPanel.class.getName()).log(Level.SEVERE, "Cannot create tempfile", iex); + } catch (InterruptedException ex) { + } } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java index 6fcae2c67..1882c30c0 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java @@ -24,5 +24,9 @@ public interface DebugListener { public void onMessage(String clientId, String msg); + public void onLoaderURL(String clientId, String url); + + public void onLoaderBytes(String clientId, byte data[]); + public void onFinish(String clientId); } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java index ee3440253..76f7da65b 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java @@ -25,10 +25,12 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.regex.Pattern; /** * @@ -57,6 +59,30 @@ public class Debugger { private final int id; public boolean finished = false; + private final Map parameters = new HashMap<>(); + + public static final int MSG_STRING = 0; + public static final int MSG_LOADER_URL = 1; + public static final int MSG_LOADER_BYTES = 2; + + public String getParameter(String name, String defValue) { + if (parameters.containsKey(name)) { + return parameters.get(name); + } + return defValue; + } + + public int getVersionMajor() { + return Integer.parseInt(getParameter("debug.version.major", "1")); + } + + public int getVersionMinor() { + return Integer.parseInt(getParameter("debug.version.major", "0")); + } + + public boolean hasMsgType() { + return getVersionMajor() > 1 || getVersionMinor() > 0; + } public DebugHandler(int serverPort, Socket s) { this.s = s; @@ -72,6 +98,42 @@ public class Debugger { } } + private int readType(InputStream is) throws IOException { + int type = is.read(); + if (type == -1) { + throw new EOFException(); + } + return type; + } + + private byte[] readBytes(InputStream is) throws IOException { + int len = is.read(); + if (len == -1) { + throw new EOFException(); + } + int len2 = is.read(); + if (len2 == -1) { + throw new EOFException(); + } + int len3 = is.read(); + if (len3 == -1) { + throw new EOFException(); + } + int len4 = is.read(); + if (len4 == -1) { + throw new EOFException(); + } + len = (len << 24) + (len2 << 16) + (len3 << 8) + len4; + byte data[] = new byte[len]; + int cnt; + int off = 0; + while (len > 0 && (cnt = is.read(data, off, len)) > 0) { + len -= cnt; + off += cnt; + } + return data; + } + private String readString(InputStream is) throws IOException { int len = is.read(); if (len == -1) { @@ -115,14 +177,47 @@ public class Debugger { os.write(("").getBytes("UTF-8")); } } else { + if (!ret.isEmpty()) { + String param[] = (ret.contains(";") ? ret.split(";") : new String[]{ret}); + for (String p : param) { + if (p.contains("=")) { + String key = p.substring(0, p.indexOf("=")); + String val = p.substring(p.indexOf("=") + 1); + parameters.put(key, val); + } else { + parameters.put(p, "true"); + } + } + } + boolean hasType = hasMsgType(); String name = readString(is); if (!name.isEmpty()) { clientName = name; } while (true) { - ret = readString(is); - for (DebugListener l : listeners) { - l.onMessage(clientName, ret); + int type = 0; + if (hasType) { + type = readType(is); + } + switch (type) { + case MSG_STRING: + ret = readString(is); + for (DebugListener l : listeners) { + l.onMessage(clientName, ret); + } + break; + case MSG_LOADER_URL: + ret = readString(is); + for (DebugListener l : listeners) { + l.onLoaderURL(clientName, ret); + } + break; + case MSG_LOADER_BYTES: + byte retB[] = readBytes(is); + for (DebugListener l : listeners) { + l.onLoaderBytes(clientName, retB); + } + break; } } } diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java index 37a354014..fc78acfa4 100644 --- a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java @@ -85,6 +85,27 @@ public class DebuggerTools { return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "(\\.pkg[a-f0-9]+)?" + cls); } + public static void injectDebugLoader(SWF swf) { + if (hasDebugger(swf)) { + ScriptPack dsp = getDebuggerScriptPack(swf); + String debuggerPkg = dsp.getClassPath().packageStr.toRawString(); + for (ABCContainerTag ct : swf.getAbcList()) { + ABC a = ct.getABC(); + if (dsp.abc == a) { //do not replace Loader in debugger itself + continue; + } + for (int i = 1; i < a.constants.constant_multiname.size(); i++) { + Multiname m = a.constants.constant_multiname.get(i); + if ("flash.display.Loader".equals(m.getNameWithNamespace(a.constants).toRawString())) { + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId(debuggerPkg, true)), 0, true); + m.name_index = a.constants.getStringId("DebugLoader", true); + ((Tag) ct).setModified(true); + } + } + } + } + } + public static void replaceTraceCalls(SWF swf, String fname) { if (hasDebugger(swf)) { String debuggerPkg = getDebuggerScriptPack(swf).getClassPath().packageStr.toRawString(); @@ -111,7 +132,7 @@ public class DebuggerTools { swf.tags.remove((Tag) tag); swf.getAbcList().remove(tag); - //Change all debugger calls to normal trace + //Change all debugger calls to normal trace / Loader for (ABCContainerTag ct : swf.getAbcList()) { ABC a = ct.getABC(); for (int i = 1; i < a.constants.constant_multiname.size(); i++) { @@ -124,6 +145,9 @@ public class DebuggerTools { m.name_index = a.constants.getStringId("trace", true); m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("", true)), 0, true); ((Tag) ct).setModified(true); + } else if (isDebuggerClass(packageStr, "DebugLoader")) { + m.name_index = a.constants.getStringId("Loader", true); + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("flash.display", true)), 0, true); } } } @@ -136,7 +160,11 @@ public class DebuggerTools { //load debug swf SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false); - ABCContainerTag firstAbc = swf.getAbcList().get(0); + List al = swf.getAbcList(); + ABCContainerTag firstAbc = al.isEmpty() ? null : al.get(0); + if (firstAbc == null) { //nothing to instrument? + return; + } String newdebuggerpkg = DEBUGGER_PACKAGE; if (Configuration.randomDebuggerPackage.get()) { @@ -174,7 +202,7 @@ public class DebuggerTools { initDebugger(); } - private static void initDebugger() { + public static Debugger initDebugger() { if (debugger == null) { synchronized (Main.class) { if (debugger == null) { @@ -184,6 +212,7 @@ public class DebuggerTools { } } } + return debugger; } public static void debuggerShowLog() { diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf index 4eeec885b..2bd76b157 100644 Binary files a/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf and b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index 6585b91cb..853c46a61 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -377,3 +377,6 @@ config.description.smartNumberFormatting = Format special numbers (for example c config.name.enableScriptInitializerDisplay = Display script initializers config.description.enableScriptInitializerDisplay = Enable script initializers display and editation. This setting may add one newline to each class file for highlighting. + +config.name.autoOpenLoadedSWFs = Open loaded SWFs during run (External viewer = WIN only) +config.description.autoOpenLoadedSWFs = Opens automatically all SWFs loaded by AS3 class Loader by running SWF when played in FFDec external player. This feature is Windows only. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 8fc025ca6..71617587b 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -357,3 +357,6 @@ config.description.cacheImages = Ke\u0161ovat dek\u00f3dovan\u00e9 objekty obr\u config.name.swfSpecificConfigs = Konfigurace specifick\u00e9 pro jednotliv\u00e1 SWF config.description.swfSpecificConfigs = Obsahuje konfigurace pro jednotliv\u00e1 SWF + +config.name.autoOpenLoadedSWFs = Otev\u00edrat na\u010d\u00edtan\u00e1 SWF b\u011bhem p\u0159ehr\u00e1v\u00e1n\u00ed (Extern\u00ed p\u0159ehr\u00e1va\u010d = jen WIN) +config.description.autoOpenLoadedSWFs = Otev\u00edr\u00e1 automaticky v\u0161echna SWF na\u010d\u00edtan\u00e1 AS3 t\u0159\u00eddou Loader b\u011bhem p\u0159ehr\u00e1v\u00e1n\u00ed v extern\u00edm p\u0159ehr\u00e1va\u010di v FFDec. Toto funguje pouze ve Windows. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 79ee78546..c6a18ea39 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -629,4 +629,5 @@ error.image.alpha.invalid = Invalid alpha channel data. #after version 6.0.2 contextmenu.saveUncompressedToFile = Save to Uncompressed File -abc.traitslist.scriptinitializer = script initializer \ No newline at end of file +abc.traitslist.scriptinitializer = script initializer +menu.settings.autoOpenLoadedSWFs = Open loaded SWFs while playing \ 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 2d53d4b1b..45b6ea8ea 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -628,4 +628,5 @@ error.image.alpha.invalid = Neplatn\u00e1 data alpha kan\u00e1lu. #after version 6.0.2 contextmenu.saveUncompressedToFile = Ulo\u017eit nekomprimovan\u011b -abc.traitslist.scriptinitializer = inicializ\u00e1tor skriptu \ No newline at end of file +abc.traitslist.scriptinitializer = inicializ\u00e1tor skriptu +menu.settings.autoOpenLoadedSWFs = Otev\u00edrat na\u010d\u00edtan\u00e1 SWF b\u011bhem p\u0159ehr\u00e1v\u00e1n\u00ed \ No newline at end of file