diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
index 05c9ca248..8cad454b0 100644
--- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
+++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
@@ -4,7 +4,9 @@
import flash.utils.ByteArray;
import flash.events.Event;
import flash.display.Sprite;
-
+ import flash.utils.getTimer;
+ import flash.events.ProgressEvent;
+
public class DebugConnection {
private static var s:Socket;
@@ -12,21 +14,30 @@
private static var first:Boolean = true;
private static var inited:Boolean = false;
private static var name:String;
+ private static var failed:Boolean = false;
+ private static var fillByteArrays = [];
+ private static var lenBytes:Array = [
+ -1, -1, -1, -1
+ ];
+ private static var lenBytePos:int = 0;
+ private static var len:int = 0;
+ private static var readBa:ByteArray;
+
+
public static const DEBUG_VERSION_MAJOR = 1;
- public static const DEBUG_VERSION_MINOR = 2;
+ public static const DEBUG_VERSION_MINOR = 3;
public static const MSG_STRING = 0;
public static const MSG_LOADER_URL = 1;
public static const MSG_LOADER_BYTES = 2;
- public static const MSG_LONGSTRING = 3;
- public static const MSG_LOADER_URL_GETBYTES = 4;
- public static const MSG_LOADER_BYTES_GETBYTES = 5;
-
-
+ public static const MSG_DUMP_BYTEARRAY = 3;
+ public static const MSG_REQUEST_BYTEARRAY = 4;
+
private static function sendQueue(){
var qo = q;
q = [];
+ sendHeader();
for each(var m in qo){
writeMsg(m.data,m.type);
}
@@ -68,8 +79,7 @@
var a3 = s.readUnsignedByte();
var a4 = s.readUnsignedByte();
var len = (a1<<24)+(a2<<16)+(a3<<8)+a4;
-
- s.readBytes(b,0,len);
+ s.readBytes(b,0,len);
return b;
}
@@ -85,24 +95,65 @@
private static function readLongString():String {
var b:ByteArray = readBytes();
return b.readUTFBytes(b.length);
- }
-
+ }
+
public static function initClient(sname){
if(inited){
return;
}
name = sname;
inited = true;
- s = new Socket();
- s.addEventListener(Event.CONNECT, function(){
- sendQueue();
- });
- var port:int = 0;
- port = 123456;
- s.connect("localhost",port);
- inited = true;
+ try {
+ s = new Socket();
+ s.addEventListener(Event.CONNECT, onSocketConnect);
+ s.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
+ var port:int = 0;
+ port = 123456;
+ s.connect("localhost",port);
+
+ inited = true;
+ } catch (e:SecurityError) {
+ trace("Debugger helper failed to connect to localhost");
+ failed = true;
+ }
}
+ private static function onSocketConnect(event:Event):void {
+ sendQueue();
+ }
+
+
+ private static function onSocketData(event:ProgressEvent):void {
+ while (s.bytesAvailable > 0) {
+ if (lenBytePos < 4) {
+ lenBytes[lenBytePos] = s.readUnsignedByte();
+ lenBytePos++;
+ if (lenBytePos == 4) {
+ len = (lenBytes[0]<<24)+(lenBytes[1]<<16)+(lenBytes[2]<<8)+lenBytes[3];
+ readBa = new ByteArray();
+ }
+ } else {
+ var readLen:int = s.bytesAvailable <= len ? s.bytesAvailable : len;
+ s.readBytes(readBa, readBa.length, readLen);
+ len -= readLen;
+
+ if (len == 0) {
+ lenBytePos = 0;
+ var ba:ByteArray = fillByteArrays.pop();
+ var pos = ba.position;
+ ba.position = 0;
+ ba.length = 0;
+ ba.writeBytes(readBa);
+ if (pos > ba.length) {
+ ba.position = ba.length;
+ } else {
+ ba.position = pos;
+ }
+ }
+ }
+ }
+ }
+
public static function writeLoaderURL(url){
writeMsg(url,MSG_LOADER_URL);
@@ -113,19 +164,59 @@
writeMsg(data,MSG_LOADER_BYTES);
}
+ public static function writeCommaSeparatedToByteArray(s:String, ba:ByteArray) {
+ var bytes:Array = s.split(",");
+ var pos:uint = ba.position;
+ ba.position = 0;
+ ba.length = 0;
+ for (var i:int = 0; i < bytes.length; i++) {
+ ba.writeByte(bytes[i]);
+ }
+ if (pos > ba.length) {
+ ba.position = ba.length;
+ } else {
+ ba.position = pos;
+ }
+ }
+ public static function readCommaSeparatedFromByteArray(ba:ByteArray): String {
+ var s:String = "";
+ var splitter = "";
+ for (var i:int = 0; i < ba.length; i++) {
+ s += splitter;
+ s += ba[i];
+ splitter = ",";
+ }
+ return s;
+ }
+
+ private static function sendHeader() {
+ if (!first) {
+ return;
+ }
+ if (!s.connected) {
+ return;
+ }
+ writeStringNull("debug.version.major="+DEBUG_VERSION_MAJOR+";debug.version.minor="+DEBUG_VERSION_MINOR);
+ writeString(name);
+ first = false;
+ }
public static function writeMsg(msg,msgType=0){
- if(!inited){
+ if (failed) {
+ return;
+ }
+ if(!inited) {
initClient("");
}
- if(s.connected){
- if(first){
- //s.writeByte(0);
- writeStringNull("debug.version.major="+DEBUG_VERSION_MAJOR+";debug.version.minor="+DEBUG_VERSION_MINOR);
- writeString(name);
- first = false;
- }
+ if ((msg is ByteArray) && msgType == MSG_DUMP_BYTEARRAY) {
+ var ba2:ByteArray = new ByteArray();
+ ba2.writeBytes(msg);
+ msg = ba2;
+ }
+
+ if(s.connected){
+ sendHeader();
s.writeByte(msgType);
switch(msgType){
case MSG_STRING:
@@ -137,11 +228,11 @@
case MSG_LOADER_BYTES:
writeBytes(msg);
break;
- case MSG_LOADER_URL_GETBYTES:
- writeString(msg);
+ case MSG_DUMP_BYTEARRAY:
+ writeBytes(msg);
break;
- case MSG_LOADER_BYTES_GETBYTES:
- writeBytes(msg);
+ case MSG_REQUEST_BYTEARRAY:
+ fillByteArrays.push(msg);
break;
}
s.flush();
diff --git a/libsrc/debugswf/debug/DOMDocument.xml b/libsrc/debugswf/debug/DOMDocument.xml
index 2a2022b3c..dcadb265f 100644
--- a/libsrc/debugswf/debug/DOMDocument.xml
+++ b/libsrc/debugswf/debug/DOMDocument.xml
@@ -14,6 +14,13 @@
+
+
+
+
+
+
+
@@ -27,12 +34,5 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libsrc/debugswf/debug/META-INF/metadata.xml b/libsrc/debugswf/debug/META-INF/metadata.xml
index ed05677a5..d682531f2 100644
--- a/libsrc/debugswf/debug/META-INF/metadata.xml
+++ b/libsrc/debugswf/debug/META-INF/metadata.xml
@@ -5,8 +5,8 @@
xmlns:xmp="http://ns.adobe.com/xap/1.0/">
Adobe Flash Professional CS6 - build 537
2014-10-26T15:59:21+01:00
- 2023-11-18T12:05:50-08:00
- 2023-11-18T12:05:50-08:00
+ 2023-11-19T08:32:38-08:00
+ 2023-11-19T08:32:38-08:00
@@ -15,7 +15,7 @@
- xmp.iid:CDA31DDF4D86EE11B43B9B2E6D6D7C97
+ xmp.iid:D4132A45B886EE11B43B9B2E6D6D7C97
xmp.did:1476A545885CE411B13FACEEFCD7D43C
xmp.did:1476A545885CE411B13FACEEFCD7D43C
@@ -50,6 +50,12 @@
2014-10-26T15:59:21+01:00
Adobe Flash Professional CS6 - build 481
+
+ created
+ xmp.iid:D4132A45B886EE11B43B9B2E6D6D7C97
+ 2014-10-26T15:59:21+01:00
+ Adobe Flash Professional CS6 - build 481
+
diff --git a/libsrc/debugswf/debug/PublishSettings.xml b/libsrc/debugswf/debug/PublishSettings.xml
index e317964e7..618fc2897 100644
--- a/libsrc/debugswf/debug/PublishSettings.xml
+++ b/libsrc/debugswf/debug/PublishSettings.xml
@@ -79,7 +79,7 @@
.
CONFIG::FLASH_AUTHORING="true";
- 0
+ 1
1
0
diff --git a/libsrc/debugswf/debug/bin/SymDepend.cache b/libsrc/debugswf/debug/bin/SymDepend.cache
index ea8830d75..8ece03aba 100644
Binary files a/libsrc/debugswf/debug/bin/SymDepend.cache and b/libsrc/debugswf/debug/bin/SymDepend.cache differ
diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
index 195d2e5e4..4a19035be 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
@@ -421,6 +421,9 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
@Internal
private ExporterInfo exporterInfo = null;
+
+ @Internal
+ public String debuggerPackage = null;
private static AbcIndexing playerGlobalAbcIndex;
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java
index 83669ea77..3e1665947 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.gui.debugger.DebugAdapter;
import com.jpexs.decompiler.flash.gui.debugger.DebugListener;
import com.jpexs.decompiler.flash.gui.debugger.Debugger;
import java.awt.BorderLayout;
@@ -54,18 +55,13 @@ public class DebugLogDialog extends AppDialog {
JScrollPane spane = new FasterScrollPane(logTextArea);
spane.setPreferredSize(new Dimension(800, 500));
- debug.addMessageListener(new DebugListener() {
+ debug.addMessageListener(new DebugAdapter() {
@Override
public void onMessage(String clientId, String msg) {
log(translate("msg.header").replace("%clientid%", clientId) + msg);
}
-
- @Override
- public void onFinish(String clientId) {
-
- }
-
+
@Override
public void onLoaderURL(String clientId, String url) {
log(translate("msg.header").replace("%clientid%", clientId) + " LOADURL:" + url);
@@ -75,6 +71,11 @@ public class DebugLogDialog extends AppDialog {
public void onLoaderBytes(String clientId, byte[] data) {
log(translate("msg.header").replace("%clientid%", clientId) + " LOADBYTES: " + data.length + "B");
}
+
+ @Override
+ public void onDumpByteArray(String clientId, byte[] data) {
+ log(translate("msg.header").replace("%clientid%", clientId) + " DUMPBYTEARRAY: " + data.length + "B");
+ }
});
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
index 710546cc8..a2323e1dc 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
@@ -20,9 +20,14 @@ import com.jpexs.debugger.flash.Variable;
import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
import com.jpexs.debugger.flash.messages.in.InConstantPool;
import com.jpexs.debugger.flash.messages.in.InFrame;
+import com.jpexs.debugger.flash.messages.in.InGetVariable;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.DebuggerHandler.BreakListener;
import com.jpexs.decompiler.flash.gui.abc.ABCPanel;
+import com.jpexs.decompiler.flash.gui.debugger.DebugAdapter;
+import com.jpexs.decompiler.flash.gui.debugger.DebugListener;
+import com.jpexs.decompiler.flash.gui.debugger.Debugger;
+import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools;
import com.jpexs.helpers.Helper;
import de.hameister.treetable.MyTreeTable;
import de.hameister.treetable.MyTreeTableModel;
@@ -38,6 +43,7 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -201,19 +207,66 @@ public class DebugPanel extends JPanel {
if (isByteArray) {
JMenu exportMenu = new JMenu(AppStrings.translate("debug.export").replace("%name%", v.name));
JMenuItem exportByteArrayMenuItem = new JMenuItem(AppStrings.translate("debug.export.bytearray"));
- exportByteArrayMenuItem.addActionListener((ActionEvent e1) -> {
+ exportByteArrayMenuItem.addActionListener((ActionEvent e1) -> {
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
if (fc.showSaveDialog(Main.getDefaultMessagesComponent()) == JFileChooser.APPROVE_OPTION) {
File file = Helper.fixDialogFile(fc.getSelectedFile());
+
+ //Variant with direct calling readByte - SLOW
+ /*
try (FileOutputStream fos = new FileOutputStream(file)) {
Main.debugExportByteArray(v, fos);
+ fos.write(data);
Configuration.lastExportDir.set(file.getParentFile().getAbsolutePath());
} catch (IOException ex) {
Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
- ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
- }
+ */
+ //Asynchronous variant
+ /*DebuggerTools.initDebugger().addMessageListener(new DebugAdapter() {
+
+ @Override
+ public void onDumpByteArray(String clientId, byte[] data) {
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(data);
+ Configuration.lastExportDir.set(file.getParentFile().getAbsolutePath());
+ } catch (IOException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
+ ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ }
+ DebuggerTools.initDebugger().removeMessageListener(this);
+ }
+ });
+ Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
+ try {
+ Main.getDebugHandler().callMethod(debugConnectionClass, "writeMsg", Arrays.asList(v, (Double) (double) Debugger.MSG_DUMP_BYTEARRAY));
+ } catch (DebuggerHandler.ActionScriptException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex);
+ }*/
+
+ //Variant using comma separated bytes, pretty fast
+ try {
+ Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
+ String dataStr = (String) Main.getDebugHandler().callMethod(debugConnectionClass, "readCommaSeparatedFromByteArray", Arrays.asList(v)).variables.get(0).value;
+ String[] parts = dataStr.split(",");
+ byte[] data = new byte[parts.length];
+ for (int i = 0; i < parts.length; i++) {
+ data[i] = (byte) Integer.parseInt(parts[i]);
+ }
+
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(data);
+ Configuration.lastExportDir.set(file.getParentFile().getAbsolutePath());
+ } catch (IOException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
+ ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ }
+ } catch (DebuggerHandler.ActionScriptException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex);
+ }
+ }
});
exportMenu.add(exportByteArrayMenuItem);
@@ -227,11 +280,57 @@ public class DebugPanel extends JPanel {
if (fc.showOpenDialog(Main.getDefaultMessagesComponent()) == JFileChooser.APPROVE_OPTION) {
File file = Helper.fixDialogFile(fc.getSelectedFile());
Configuration.lastOpenDir.set(file.getParentFile().getAbsolutePath());
- try (FileInputStream fis = new FileInputStream(file)) {
+
+ //Variant with asynchronous connection
+ /*DebuggerTools.initDebugger().addMessageListener(new DebugAdapter() {
+ @Override
+ public byte[] onRequestBytes(String clientId) {
+ byte[] data = null;
+ try {
+ data = Helper.readFileEx(file.getAbsolutePath());
+ } catch (IOException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
+ ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ }
+ DebuggerTools.initDebugger().removeMessageListener(this);
+ return data;
+ }
+ });
+ Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
+ try {
+ Main.getDebugHandler().callMethod(debugConnectionClass, "writeMsg", Arrays.asList(v, (Double) (double) Debugger.MSG_REQUEST_BYTEARRAY));
+ } catch (DebuggerHandler.ActionScriptException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex);
+ }*/
+
+ //Variant with direct writeByte calls - SLOW
+ /*try (FileInputStream fis = new FileInputStream(file)) {
Main.debugImportByteArray(v, fis);
} catch (IOException ex) {
Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ }*/
+
+ //Variant with using comma separated bytes, pretty fast
+ try {
+ byte[] data = Helper.readFileEx(file.getAbsolutePath());
+ String splitter = "";
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < data.length; i++) {
+ sb.append(splitter);
+ sb.append(data[i] & 0xff);
+ splitter = ",";
+ }
+ String dataStr = sb.toString();
+ Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
+ try {
+ Main.getDebugHandler().callMethod(debugConnectionClass, "writeCommaSeparatedToByteArray", Arrays.asList(dataStr, v));
+ } catch (DebuggerHandler.ActionScriptException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex);
+ }
+ } catch (IOException ex) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, null, ex);
+ ViewMessages.showMessageDialog(Main.getDefaultMessagesComponent(), AppStrings.translate("error.file.save") + ": " + ex.getLocalizedMessage(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
});
@@ -264,8 +363,8 @@ public class DebugPanel extends JPanel {
addWatchMenu.add(watchReadMenuItem);
addWatchMenu.add(watchWriteMenuItem);
addWatchMenu.add(watchReadWriteMenuItem);
- pm.add(addWatchMenu);
- pm.show(e.getComponent(), e.getX(), e.getY());
+ pm.add(addWatchMenu);
+ pm.show(e.getComponent(), e.getX(), e.getY());
}
};
diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java
index 5d2c0b5fd..19c01a215 100644
--- a/src/com/jpexs/decompiler/flash/gui/Main.java
+++ b/src/com/jpexs/decompiler/flash/gui/Main.java
@@ -46,6 +46,7 @@ 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.gfx.GfxConvertor;
+import com.jpexs.decompiler.flash.gui.debugger.DebugAdapter;
import com.jpexs.decompiler.flash.gui.debugger.DebugListener;
import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools;
import com.jpexs.decompiler.flash.gui.pipes.FirstInstance;
@@ -217,6 +218,8 @@ public class Main {
public static CancellableWorker importWorker = null;
public static CancellableWorker deobfuscatePCodeWorker = null;
public static CancellableWorker swfPrepareWorker = null;
+
+ public static String currentDebuggerPackage = null;
public static boolean isSwfAir(Openable openable) {
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(openable.getShortPathTitle());
@@ -524,7 +527,13 @@ public class Main {
}
instrSWF.removeEventListener(prepEventListner);
- instrSWF = super.prepare(instrSWF);
+ //instrSWF = super.prepare(instrSWF);
+
+ if (!DebuggerTools.hasDebugger(instrSWF)) {
+ DebuggerTools.switchDebugger(instrSWF);
+ }
+ DebuggerTools.injectDebugLoader(instrSWF);
+ currentDebuggerPackage = instrSWF.debuggerPackage;
return instrSWF;
}
@@ -2399,15 +2408,8 @@ public class Main {
watcherWorker.execute();
}
- DebuggerTools.initDebugger().addMessageListener(new DebugListener() {
- @Override
- public void onMessage(String clientId, String msg) {
- }
-
- @Override
- public void onLoaderURL(String clientId, String url) {
- }
-
+ DebuggerTools.initDebugger().addMessageListener(new DebugAdapter() {
+
@Override
public void onLoaderBytes(String clientId, byte[] data) {
String hash = md5(data);
@@ -2438,11 +2440,7 @@ public class Main {
} catch (IOException ex) {
logger.log(Level.SEVERE, "Cannot create tempfile");
}
- }
-
- @Override
- public void onFinish(String clientId) {
- }
+ }
});
try {
diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebugAdapter.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebugAdapter.java
new file mode 100644
index 000000000..90d418a4b
--- /dev/null
+++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebugAdapter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010-2023 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.gui.debugger;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class DebugAdapter implements 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) {
+ }
+
+ @Override
+ public void onDumpByteArray(String clientId, byte[] data) {
+ }
+
+ @Override
+ public void onFinish(String clientId) {
+ }
+
+ @Override
+ public byte[] onRequestBytes(String clientId) {
+ return null;
+ }
+
+}
diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java
index 6bfa1729f..2818da1fa 100644
--- a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java
+++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java
@@ -27,6 +27,10 @@ public interface DebugListener {
public void onLoaderURL(String clientId, String url);
public void onLoaderBytes(String clientId, byte[] data);
+
+ public void onDumpByteArray(String clientId, byte[] data);
public void onFinish(String clientId);
+
+ public byte[] onRequestBytes(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 8e7bc3185..ca03f383a 100644
--- a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java
+++ b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java
@@ -30,6 +30,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
*
@@ -37,8 +39,29 @@ import java.util.WeakHashMap;
*/
public class Debugger {
+ public static final int MSG_STRING = 0;
+
+ public static final int MSG_LOADER_URL = 1;
+
+ public static final int MSG_LOADER_BYTES = 2;
+
+ public static final int MSG_DUMP_BYTEARRAY = 3;
+
+ public static final int MSG_REQUEST_BYTEARRAY = 4;
+
+
private static final Set listeners = new HashSet<>();
+ private static Logger logger = Logger.getLogger(Debugger.class.getName());
+
+ private static boolean active = false;
+
+ public static boolean isActive() {
+ return active;
+ }
+
+
+
public synchronized void addMessageListener(DebugListener l) {
listeners.add(l);
}
@@ -61,12 +84,7 @@ public class Debugger {
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);
@@ -108,6 +126,14 @@ public class Debugger {
return type;
}
+ private void writeBytes(OutputStream os, byte[] data) throws IOException {
+ os.write((data.length >> 24) & 0xff);
+ os.write((data.length >> 16) & 0xff);
+ os.write((data.length >> 8) & 0xff);
+ os.write(data.length & 0xff);
+ os.write(data);
+ }
+
private byte[] readBytes(InputStream is) throws IOException {
int len = is.read();
if (len == -1) {
@@ -161,7 +187,8 @@ public class Debugger {
@Override
public void run() {
String clientName = Integer.toString(id);
- try (InputStream is = s.getInputStream()) {
+ try (InputStream is = s.getInputStream();
+ OutputStream os = s.getOutputStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
@@ -175,11 +202,10 @@ public class Debugger {
String ret = baos.toString("UTF-8");
if (ret.equals("")) {
- try (OutputStream os = s.getOutputStream()) {
- os.write(("").getBytes("UTF-8"));
- }
+ os.write(("").getBytes("UTF-8"));
} else {
if (!ret.isEmpty()) {
+ logger.log(Level.FINER, "Connected. Header: {0}", ret);
String[] param = (ret.contains(";") ? ret.split(";") : new String[]{ret});
for (String p : param) {
if (p.contains("=")) {
@@ -190,35 +216,79 @@ public class Debugger {
parameters.put(p, "true");
}
}
+ active = true;
}
boolean hasType = hasMsgType();
+ logger.log(Level.FINER, "reading name...");
String name = readString(is);
+ logger.log(Level.FINER, "name = {0}", name);
if (!name.isEmpty()) {
clientName = name;
}
while (true) {
int type = 0;
+ logger.finer("reading type...");
if (hasType) {
type = readType(is);
}
+ logger.log(Level.FINE, "received type {0}", type);
switch (type) {
case MSG_STRING:
+ logger.finer("reading string...");
ret = readString(is);
+ logger.finer("informing listeners...");
for (DebugListener l : listeners) {
l.onMessage(clientName, ret);
}
+ logger.finer("listeners informed");
break;
case MSG_LOADER_URL:
+ logger.finer("reading string...");
ret = readString(is);
+ logger.finer("informing listeners...");
for (DebugListener l : listeners) {
l.onLoaderURL(clientName, ret);
}
+ logger.finer("listeners informed");
break;
case MSG_LOADER_BYTES:
+ logger.finer("reading bytes...");
byte[] retB = readBytes(is);
+ logger.finer("informing listeners...");
for (DebugListener l : listeners) {
l.onLoaderBytes(clientName, retB);
}
+ logger.finer("listeners informed");
+ break;
+ case MSG_DUMP_BYTEARRAY:
+ logger.finer("reading bytes...");
+ byte[] retBa = readBytes(is);
+ logger.finer("informing listeners...");
+ for (DebugListener l : listeners) {
+ l.onDumpByteArray(clientName, retBa);
+ }
+ logger.finer("listeners informed");
+ break;
+ case MSG_REQUEST_BYTEARRAY:
+ logger.finer("checking listeners for data...");
+ boolean dataFound = false;
+ for (DebugListener l : listeners) {
+ byte[] data = l.onRequestBytes(clientName);
+ if (data != null) {
+ logger.finer("found listener with data");
+ logger.log(Level.FINER, "writing data.length = {0}", data.length);
+ writeBytes(os, data);
+ logger.finer("data written");
+ dataFound = true;
+ break;
+ }
+ }
+ if (!dataFound) {
+ logger.finer("listener not found, writing empty array");
+ writeBytes(os, new byte[0]);
+ }
+ os.flush();
+ logger.finer("listeners checked");
break;
}
}
@@ -233,6 +303,7 @@ public class Debugger {
//ignore
}
finished = true;
+ active = false;
for (DebugListener l : listeners) {
l.onFinish(clientName);
}
diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java
index d92078b54..a19f0c5ff 100644
--- a/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java
+++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebuggerTools.java
@@ -46,8 +46,8 @@ public class DebuggerTools {
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
- private static volatile Debugger debugger;
-
+ private static volatile Debugger debugger;
+
private static ScriptPack getDebuggerScriptPack(SWF swf) {
List allAbcList = new ArrayList<>();
for (ABCContainerTag ac : swf.getAbcList()) {
@@ -234,6 +234,7 @@ public class DebuggerTools {
if (Configuration.randomDebuggerPackage.get()) {
newdebuggerpkg += ".pkg" + rhex;
}
+ swf.debuggerPackage = newdebuggerpkg;
//add debug ABC tags to main SWF
for (ABCContainerTag ds : debugSWF.getAbcList()) {
@@ -261,6 +262,46 @@ public class DebuggerTools {
ft.useNetwork = true;
ft.setModified(true);
}
+
+
+
+ //Add call to DebugConnection.initClient("") to the document class
+ /*String documentClass = swf.getDocumentClass();
+ if (documentClass != null) {
+ List searchClassNames = new ArrayList<>();
+ searchClassNames.add(documentClass);
+ List documentClassPacks = swf.getScriptPacksByClassNames(searchClassNames);
+ if (!documentClassPacks.isEmpty()) {
+ ScriptPack documentClassPack = documentClassPacks.get(0);
+ Trait publicTrait = documentClassPack.getPublicTrait();
+ if (publicTrait != null) {
+ if (publicTrait instanceof TraitClass) {
+ TraitClass classTrait = (TraitClass) publicTrait;
+ int classIndex = classTrait.class_info;
+ ABC a = documentClassPack.abc;
+ int cinitMethodInfo = a.class_info.get(classIndex).cinit_index;
+ MethodBody body = a.findBody(cinitMethodInfo);
+ AVM2Code code = body.getCode();
+ int debugConnectionMultiname = a.constants.getMultinameId(
+ Multiname.createQName(false, a.constants.getStringId("DebugConnection", true),
+ a.constants.getNamespaceId(Namespace.KIND_PACKAGE, newdebuggerpkg, 0, true)
+ ), true);
+ int initClientMultiname = a.constants.getMultinameId(
+ Multiname.createQName(false, a.constants.getStringId("initClient", true),
+ a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true)
+ ), true);
+ code.insertInstruction(0, new AVM2Instruction(0, AVM2Instructions.GetLex, new int[] {debugConnectionMultiname}), true, body);
+ code.insertInstruction(1, new AVM2Instruction(0, AVM2Instructions.PushString, new int[] {a.constants.getStringId("", true)}), true, body);
+ code.insertInstruction(2, new AVM2Instruction(0, AVM2Instructions.CallPropVoid, new int[] {initClientMultiname, 1}), true, body);
+ if (body.max_stack < 2) {
+ body.max_stack = 2;
+ }
+ body.setModified();
+ }
+ }
+ }
+ }
+ */
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf
index bc35da002..cc36bc0ef 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