diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27c3e01f9..63c7e8719 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,7 @@ All notable changes to this project will be documented in this file.
- Optimized (faster) deleting items for large SWF trees
- AS debugger - More varible flags
- AS3 direct editation - edit files with native keyword
+- [#1383] AS Debugger - debugging nested SWFs (enable "Open loaded SWFs while playing")
### Fixed
- Debugger - getting children of top level variables
@@ -3480,6 +3481,7 @@ Major version of SWF to XML export changed to 2.
[#1809]: https://www.free-decompiler.com/flash/issues/1809
[#873]: https://www.free-decompiler.com/flash/issues/873
[#1644]: https://www.free-decompiler.com/flash/issues/1644
+[#1383]: https://www.free-decompiler.com/flash/issues/1383
[#2149]: https://www.free-decompiler.com/flash/issues/2149
[#2172]: https://www.free-decompiler.com/flash/issues/2172
[#2174]: https://www.free-decompiler.com/flash/issues/2174
diff --git a/lib/flashdebugger.jar b/lib/flashdebugger.jar
index 579e06cc4..5608d0a2b 100644
Binary files a/lib/flashdebugger.jar and b/lib/flashdebugger.jar differ
diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugByteArrayLoadedEvent.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugByteArrayLoadedEvent.as
new file mode 100644
index 000000000..5250d45d6
--- /dev/null
+++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugByteArrayLoadedEvent.as
@@ -0,0 +1,10 @@
+package com.jpexs.decompiler.flash.debugger {
+ import flash.events.Event;
+
+ public class DebugByteArrayLoadedEvent extends Event {
+
+ public DebugByteArrayLoadedEvent() {
+ super("DebugByteArrayLoadedEvent");
+ }
+ }
+}
diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
index 8cad454b0..46b25b6dc 100644
--- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
+++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as
@@ -16,6 +16,7 @@
private static var name:String;
private static var failed:Boolean = false;
private static var fillByteArrays = [];
+ private static var fillByteArraysEvents = [];
private static var lenBytes:Array = [
-1, -1, -1, -1
];
@@ -32,7 +33,8 @@
public static const MSG_LOADER_BYTES = 2;
public static const MSG_DUMP_BYTEARRAY = 3;
public static const MSG_REQUEST_BYTEARRAY = 4;
-
+ public static const MSG_LOADER_URL_INFO = 5;
+ public static const MSG_LOADER_MODIFY_BYTES = 6;
private static function sendQueue(){
var qo = q;
@@ -125,7 +127,7 @@
private static function onSocketData(event:ProgressEvent):void {
while (s.bytesAvailable > 0) {
- if (lenBytePos < 4) {
+ if (lenBytePos < 4) {
lenBytes[lenBytePos] = s.readUnsignedByte();
lenBytePos++;
if (lenBytePos == 4) {
@@ -136,9 +138,8 @@
var readLen:int = s.bytesAvailable <= len ? s.bytesAvailable : len;
s.readBytes(readBa, readBa.length, readLen);
len -= readLen;
-
- if (len == 0) {
- lenBytePos = 0;
+ if (len == 0) {
+ lenBytePos = 0;
var ba:ByteArray = fillByteArrays.pop();
var pos = ba.position;
ba.position = 0;
@@ -149,6 +150,10 @@
} else {
ba.position = pos;
}
+ var onComplete = fillByteArraysEvents.pop();
+ if (onComplete != null) {
+ onComplete.call(onComplete);
+ }
}
}
}
@@ -163,6 +168,10 @@
public static function writeLoaderBytes(data:ByteArray){
writeMsg(data,MSG_LOADER_BYTES);
}
+
+ public static function modifyLoaderBytesWithUrl(data:ByteArray, outputData:ByteArray, url:String, onComplete:Function){
+ writeMsg({"inputData": data, "outputData": outputData, "url" : url, "onComplete" : onComplete},MSG_LOADER_MODIFY_BYTES);
+ }
public static function writeCommaSeparatedToByteArray(s:String, ba:ByteArray) {
var bytes:Array = s.split(",");
@@ -232,8 +241,14 @@
writeBytes(msg);
break;
case MSG_REQUEST_BYTEARRAY:
- fillByteArrays.push(msg);
+ fillByteArrays.push(msg);
break;
+ case MSG_LOADER_MODIFY_BYTES:
+ writeString(msg["url"]);
+ writeBytes(msg["inputData"]);
+ fillByteArraysEvents.push(msg["onComplete"]);
+ fillByteArrays.push(msg["outputData"]);
+ break;
}
s.flush();
}else{
diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as
index 503b11ae6..2e2b235bc 100644
--- a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as
+++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugLoader.as
@@ -4,18 +4,45 @@
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
+ import flash.net.URLLoader;
+ import flash.net.URLLoaderDataFormat;
+ import flash.net.URLRequest;
+ import flash.events.Event;
- public class DebugLoader extends Loader {
-
+ public class DebugLoader extends Loader {
+
+ private var lastLoadedContext:LoaderContext = null;
+ private var urlLoader:URLLoader = null;
+ private var lastLoadedRequest:URLRequest = null;
+ private var lastModifiedByteArray:ByteArray = null;
public override function load(request:URLRequest, context:LoaderContext = null):void {
- DebugConnection.writeLoaderURL(request.url);
- super.load(request,context);
+ lastLoadedRequest = request;
+ lastLoadedContext = context;
+
+ urlLoader = new URLLoader();
+ urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
+ urlLoader.addEventListener(Event.COMPLETE, onURLLoaderComplete);
+ urlLoader.load(request);
}
+
+ private function onURLLoaderComplete(event:Event):void {
+ var dataBytes:ByteArray = urlLoader.data as ByteArray;
+ loadBytesInternal(dataBytes, lastLoadedContext, lastLoadedRequest.url);
+ }
+ private function loadBytesInternal(bytes:ByteArray, context:LoaderContext = null, url:String = "") {
+ lastModifiedByteArray = new ByteArray();
+ lastLoadedContext = context;
+ DebugConnection.modifyLoaderBytesWithUrl(bytes, lastModifiedByteArray, url, onModifiedDataLoaded);
+ }
+
+ private function onModifiedDataLoaded() {
+ super.loadBytes(lastModifiedByteArray, lastLoadedContext);
+ }
+
public override function loadBytes(bytes:ByteArray, context:LoaderContext = null):void {
- DebugConnection.writeLoaderBytes(bytes);
- super.loadBytes(bytes,context);
+ loadBytesInternal(bytes, context);
}
public override function toString():String {
diff --git a/libsrc/debugswf/debug/DOMDocument.xml b/libsrc/debugswf/debug/DOMDocument.xml
index dcadb265f..605551470 100644
--- a/libsrc/debugswf/debug/DOMDocument.xml
+++ b/libsrc/debugswf/debug/DOMDocument.xml
@@ -14,6 +14,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -24,15 +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 d682531f2..dc3d51ac8 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-19T08:32:38-08:00
- 2023-11-19T08:32:38-08:00
+ 2024-08-04T02:20:55-07:00
+ 2024-08-04T02:20:55-07:00
@@ -15,7 +15,7 @@
- xmp.iid:D4132A45B886EE11B43B9B2E6D6D7C97
+ xmp.iid:C1FFFAAC2852EF1194768CEE75293134
xmp.did:1476A545885CE411B13FACEEFCD7D43C
xmp.did:1476A545885CE411B13FACEEFCD7D43C
@@ -56,6 +56,12 @@
2014-10-26T15:59:21+01:00
Adobe Flash Professional CS6 - build 481
+
+ created
+ xmp.iid:C1FFFAAC2852EF1194768CEE75293134
+ 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 618fc2897..e317964e7 100644
--- a/libsrc/debugswf/debug/PublishSettings.xml
+++ b/libsrc/debugswf/debug/PublishSettings.xml
@@ -79,7 +79,7 @@
.
CONFIG::FLASH_AUTHORING="true";
- 1
+ 0
1
0
diff --git a/libsrc/debugswf/debug/bin/SymDepend.cache b/libsrc/debugswf/debug/bin/SymDepend.cache
index 8ece03aba..3a10c8f2e 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 1674db1f8..37690f21f 100644
--- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
+++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java
@@ -3990,6 +3990,9 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* P-code)
*/
public void injectAS3PcodeDebugInfo() throws InterruptedException {
+ injectAS3PcodeDebugInfo("main");
+ }
+ public void injectAS3PcodeDebugInfo(String swfHash) throws InterruptedException {
List packs = getAS3Packs();
int i = 0;
for (ScriptPack s : packs) {
@@ -4000,7 +4003,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
informListeners("inject_debuginfo", "" + i + "/" + packs.size() + ": " + s.getPath());
int abcIndex = s.allABCs.indexOf(s.abc);
if (s.isSimple) {
- s.injectPCodeDebugInfo(abcIndex);
+ s.injectPCodeDebugInfo(abcIndex, swfHash);
}
}
}
@@ -4011,6 +4014,10 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* @param decompileDir Directory to set file information paths
*/
public void injectAS3DebugInfo(File decompileDir) throws InterruptedException {
+ injectAS3DebugInfo(decompileDir, "main");
+ }
+
+ public void injectAS3DebugInfo(File decompileDir, String swfHash) throws InterruptedException {
List packs = getAS3Packs();
int i = 0;
for (ScriptPack s : packs) {
@@ -4021,7 +4028,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
informListeners("inject_debuginfo", "" + i + "/" + packs.size() + ": " + s.getPath());
if (s.isSimple) {
try {
- s.injectDebugInfo(decompileDir);
+ s.injectDebugInfo(decompileDir, swfHash);
} catch (Throwable t) {
Logger.getLogger(SWF.class.getName()).log(Level.SEVERE, "Errorr injecting debug info", t);
}
@@ -4072,12 +4079,17 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* @param pcodeLevel inject Pcode lines instead of decompiled lines
*/
public void enableDebugging(boolean injectAS3Code, File decompileDir, boolean telemetry, boolean pcodeLevel) throws InterruptedException {
+ enableDebugging(injectAS3Code, decompileDir, telemetry, pcodeLevel, "main");
+ }
+
+ public void enableDebugging(boolean injectAS3Code, File decompileDir, boolean telemetry, boolean pcodeLevel, String swfHash) throws InterruptedException {
+
if (injectAS3Code) {
if (pcodeLevel) {
- injectAS3PcodeDebugInfo();
+ injectAS3PcodeDebugInfo(swfHash);
} else {
- injectAS3DebugInfo(decompileDir);
+ injectAS3DebugInfo(decompileDir, swfHash);
}
}
@@ -4156,6 +4168,10 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
}
public boolean generatePCodeSwdFile(File file, Map> breakpoints) throws IOException, InterruptedException {
+ return generatePCodeSwdFile(file, breakpoints, "main");
+ }
+
+ public boolean generatePCodeSwdFile(File file, Map> breakpoints, String swfHash) throws IOException, InterruptedException {
DebugIDTag dit = getDebugId();
if (dit == null) {
return false;
@@ -4180,7 +4196,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
}
informListeners("generate_swd", name);
moduleId++;
- String sname = "#PCODE " + name;
+ String sname = swfHash + ":" + "#PCODE " + name;
int bitmap = SWD.bitmapAction;
items.add(new SWD.DebugScript(moduleId, bitmap, sname, ""));
@@ -4237,6 +4253,10 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
}
public boolean generateSwdFile(File file, Map> breakpoints) throws IOException {
+ return generateSwdFile(file, breakpoints, "main");
+ }
+
+ public boolean generateSwdFile(File file, Map> breakpoints, String swfHash) throws IOException {
DebugIDTag dit = getDebugId();
if (dit == null) {
return false;
@@ -4299,7 +4319,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
}
//final String NONAME = "[No instance name assigned]";
- String sname = name;
+ String sname = swfHash + ":" + name;
int bitmap = SWD.bitmapAction;
/* Matcher m;
int bitmap = SWD.bitmapAction;
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 455d9f3d9..37c0ca4fb 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
@@ -396,6 +396,10 @@ public class ScriptPack extends AS3ClassTreeItem {
* http://securityevaluators.com/knowledge/flash/
*/
public void injectDebugInfo(File directoryPath) {
+ injectDebugInfo(directoryPath, "main");
+ }
+
+ public void injectDebugInfo(File directoryPath, String swfHash) {
Map> bodyToPosToLine = new HashMap<>();
Map> bodyLineToPos = new HashMap<>();
Map> bodyToRegToName = new HashMap<>();
@@ -517,6 +521,7 @@ public class ScriptPack extends AS3ClassTreeItem {
String cls = path.className;
String filename = new File(directoryPath, path.packageStr.toFilePath()).getPath().replace(";", "{{semicolon}}")
+ ";"
+ + swfHash + ":"
+ pkg.replace(".", File.separator).replace(";", "{{semicolon}}")
+ ";"
+ cls.replace(";", "{{semicolon}}")
@@ -689,7 +694,7 @@ public class ScriptPack extends AS3ClassTreeItem {
((Tag) abc.parentTag).setModified(true);
}
- public void injectPCodeDebugInfo(int abcIndex) {
+ public void injectPCodeDebugInfo(int abcIndex, String swfHash) {
Map bodyToIdentifier = new HashMap<>();
@@ -765,7 +770,7 @@ public class ScriptPack extends AS3ClassTreeItem {
i -= 2;
}
}
- String filename = "#PCODE " + bodyName + ";" + pkg.replace(".", File.separator) + ";" + cls + ".as";
+ String filename = swfHash + ":" + "#PCODE " + bodyName + ";" + pkg.replace(".", File.separator) + ";" + cls + ".as";
b.insertInstruction(0, new AVM2Instruction(0, AVM2Instructions.DebugFile, new int[]{abc.constants.getStringId(filename, true)}));
b.setModified();
diff --git a/libsrc/ffdec_lib/testdata/debug/debug_as2.swf b/libsrc/ffdec_lib/testdata/debug/debug_as2.swf
new file mode 100644
index 000000000..4379aa0b7
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug/debug_as2.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug/debug_as3.swf b/libsrc/ffdec_lib/testdata/debug/debug_as3.swf
new file mode 100644
index 000000000..162f5a11e
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug/debug_as3.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner.swf b/libsrc/ffdec_lib/testdata/debug_inner/inner.swf
new file mode 100644
index 000000000..0a7bf764f
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug_inner/inner.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner/InnerSWF.as3proj b/libsrc/ffdec_lib/testdata/debug_inner/inner/InnerSWF.as3proj
new file mode 100644
index 000000000..7c7d91598
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner/InnerSWF.as3proj
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.old b/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.old
new file mode 100644
index 000000000..3fb908ad7
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.old
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\inner\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\inner\src\InnerMain.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.xml b/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.xml
new file mode 100644
index 000000000..3fb908ad7
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner/obj/InnerSWFConfig.xml
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\inner\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\inner\src\InnerMain.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner/src/InnerMain.as b/libsrc/ffdec_lib/testdata/debug_inner/inner/src/InnerMain.as
new file mode 100644
index 000000000..710cb6b23
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner/src/InnerMain.as
@@ -0,0 +1,24 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.events.Event;
+
+ public class InnerMain extends Sprite
+ {
+ MyInnerClass;
+
+ public function InnerMain()
+ {
+ if (stage) init();
+ else addEventListener(Event.ADDED_TO_STAGE, init);
+ }
+
+ private function init(e:Event = null):void
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, init);
+ // entry point
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner/src/MyInnerClass.as b/libsrc/ffdec_lib/testdata/debug_inner/inner/src/MyInnerClass.as
new file mode 100644
index 000000000..b90f7d2ad
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner/src/MyInnerClass.as
@@ -0,0 +1,59 @@
+package
+{
+ import flash.display.Loader;
+ import flash.display.LoaderInfo;
+ import flash.display.Sprite;
+ import flash.events.Event;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
+ import flash.utils.ByteArray;
+
+ public class MyInnerClass
+ {
+ [Embed(source="../../inner2.swf", mimeType="application/octet-stream")]
+ public var binaryData2Class:Class;
+
+ private var root:Sprite;
+
+ public function MyInnerClass()
+ {
+ }
+
+ public function run(s:Sprite): void {
+ var myvar:int = 1;
+ trace("hello from inner class 1");
+
+ var textField:TextField = new TextField();
+
+ textField.text = "Hello from inner1 !";
+
+ var textFormat:TextFormat = new TextFormat();
+ textFormat.size = 24;
+ textFormat.color = 0x000000;
+ textField.setTextFormat(textFormat);
+
+ textField.width = 200;
+
+ s.addChild(textField);
+
+ textField.x = 50;
+ textField.y = 50;
+
+ root = s;
+ var byteArray:ByteArray = new binaryData2Class() as ByteArray;
+ var loader:Loader = new Loader();
+ loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
+ loader.loadBytes(byteArray);
+ }
+
+ private function onLoaderComplete(event:Event):void {
+ var loaderInfo:LoaderInfo = event.target as LoaderInfo;
+ var className:String = "MyInnerClass2";
+ var LoadedClass:Class = loaderInfo.applicationDomain.getDefinition(className) as Class;
+ var instance:* = new LoadedClass();
+ instance.run(root);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2.swf b/libsrc/ffdec_lib/testdata/debug_inner/inner2.swf
new file mode 100644
index 000000000..da6ab5aef
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug_inner/inner2.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2/InnerSWF2.as3proj b/libsrc/ffdec_lib/testdata/debug_inner/inner2/InnerSWF2.as3proj
new file mode 100644
index 000000000..2bf448b4c
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner2/InnerSWF2.as3proj
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.old b/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.old
new file mode 100644
index 000000000..a1eafadb6
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.old
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\inner2\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\inner2\src\Main.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.xml b/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.xml
new file mode 100644
index 000000000..a1eafadb6
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner2/obj/InnerSWF2Config.xml
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\inner2\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\inner2\src\Main.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/Main.as b/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/Main.as
new file mode 100644
index 000000000..1e9bfa3ff
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/Main.as
@@ -0,0 +1,24 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.events.Event;
+
+ public class Main extends Sprite
+ {
+ MyInnerClass2;
+
+ public function Main()
+ {
+ if (stage) init();
+ else addEventListener(Event.ADDED_TO_STAGE, init);
+ }
+
+ private function init(e:Event = null):void
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, init);
+ // entry point
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/MyInnerClass2.as b/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/MyInnerClass2.as
new file mode 100644
index 000000000..aff712b6c
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/inner2/src/MyInnerClass2.as
@@ -0,0 +1,37 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
+
+ public class MyInnerClass2
+ {
+
+ public function MyInnerClass2()
+ {
+
+ }
+
+ public function run(s:Sprite): void {
+ var myvar:int = 2;
+ trace("hello from inner class 2");
+
+ var textField:TextField = new TextField();
+
+ textField.text = "Hello from inner2 !";
+
+ var textFormat:TextFormat = new TextFormat();
+ textFormat.size = 24;
+ textFormat.color = 0x000000;
+ textField.setTextFormat(textFormat);
+ textField.width = 200;
+
+ s.addChild(textField);
+
+ textField.x = 50;
+ textField.y = 75;
+
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/outer.swf b/libsrc/ffdec_lib/testdata/debug_inner/outer.swf
new file mode 100644
index 000000000..4902490c2
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug_inner/outer.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/outer/OuterSwf.as3proj b/libsrc/ffdec_lib/testdata/debug_inner/outer/OuterSwf.as3proj
new file mode 100644
index 000000000..f5a39481c
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/outer/OuterSwf.as3proj
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.old b/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.old
new file mode 100644
index 000000000..3c1960d44
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.old
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\outer\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\outer\src\Main.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.xml b/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.xml
new file mode 100644
index 000000000..3c1960d44
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/outer/obj/OuterSwfConfig.xml
@@ -0,0 +1,48 @@
+
+
+
+
+ 25.0
+ false
+ true
+
+
+ CONFIG::debug
+ true
+
+
+ CONFIG::release
+ false
+
+
+ CONFIG::timeStamp
+ '04.08.2024'
+
+
+ CONFIG::air
+ false
+
+
+ CONFIG::mobile
+ false
+
+
+ CONFIG::desktop
+ false
+
+ true
+
+ C:\FlashRelated\test_debugger\inner_debug\outer\src
+ C:\Program Files (x86)\FlashDevelop\Library\AS3\classes
+
+
+
+ C:\FlashRelated\test_debugger\inner_debug\outer\src\Main.as
+
+ #FFFFFF
+ 30
+
+ 800
+ 600
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_inner/outer/src/Main.as b/libsrc/ffdec_lib/testdata/debug_inner/outer/src/Main.as
new file mode 100644
index 000000000..d4bb99cfe
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_inner/outer/src/Main.as
@@ -0,0 +1,44 @@
+package
+{
+ import flash.display.Sprite;
+ import flash.events.Event;
+ import flash.display.Loader;
+ import flash.display.LoaderInfo;
+ import flash.utils.ByteArray;
+
+ /**
+ * ...
+ * @author Jindra
+ */
+ public class Main extends Sprite
+ {
+ [Embed(source="../../inner.swf", mimeType="application/octet-stream")]
+ public var binaryDataClass:Class;
+
+ public function Main()
+ {
+ if (stage) init();
+ else addEventListener(Event.ADDED_TO_STAGE, init);
+ }
+
+ private function init(e:Event = null):void
+ {
+ removeEventListener(Event.ADDED_TO_STAGE, init);
+
+ var byteArray:ByteArray = new binaryDataClass() as ByteArray;
+ var loader:Loader = new Loader();
+ loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
+ loader.loadBytes(byteArray);
+ }
+
+ private function onLoaderComplete(event:Event):void {
+ var loaderInfo:LoaderInfo = event.target as LoaderInfo;
+ var className:String = "MyInnerClass";
+ var LoadedClass:Class = loaderInfo.applicationDomain.getDefinition(className) as Class;
+ var instance:* = new LoadedClass();
+ instance.run(this);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java b/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java
index eca81d5e1..8628f7a65 100644
--- a/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java
+++ b/src/com/jpexs/decompiler/flash/gui/BreakpointListDialog.java
@@ -176,7 +176,7 @@ public class BreakpointListDialog extends AppDialog {
}
}*/
Pattern abcPcodePattern = Pattern.compile("^#PCODE abc:(?[0-9]+),body:(?[0-9]+);.*");
- Matcher m = abcPcodePattern.matcher(breakpoint.scriptName);
+ Matcher m = abcPcodePattern.matcher(breakpoint.scriptName);
if (m.matches()) {
int abcIndex = Integer.parseInt(m.group("abc"));
int bodyIndex = Integer.parseInt(m.group("body"));
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
index 7d0b8cd9e..a9220f35b 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.gui;
import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
+import com.jpexs.decompiler.flash.SWF;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -43,6 +44,7 @@ public class DebugStackPanel extends JPanel {
private int depth = 0;
+ private String[] swfHashes = new String[0];
private int[] classIndices = new int[0];
private int[] methodIndices = new int[0];
private int[] traitIndices = new int[0];
@@ -90,9 +92,11 @@ public class DebugStackPanel extends JPanel {
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
int row = stackTable.rowAtPoint(e.getPoint());
if (row >= 0) {
- String scriptName = (String) stackTable.getModel().getValueAt(row, 0);
- int line = (int) (Integer) stackTable.getModel().getValueAt(row, 1);
- Main.getMainFrame().getPanel().gotoScriptLine(Main.getMainFrame().getPanel().getCurrentSwf(),
+ String swfHash = swfHashes[row];
+ String scriptName = (String) stackTable.getModel().getValueAt(row, 1);
+ int line = (int) (Integer) stackTable.getModel().getValueAt(row, 2);
+ SWF swf = swfHash == null ? Main.getRunningSWF() : Main.getSwfByHash(swfHash);
+ Main.getMainFrame().getPanel().gotoScriptLine(swf,
scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode());
Main.getDebugHandler().setDepth(row);
}
@@ -117,15 +121,24 @@ public class DebugStackPanel extends JPanel {
return;
}
active = true;
- Object[][] data = new Object[info.files.size()][3];
+ Object[][] data = new Object[info.files.size()][4];
+ String[] newSwfHashes = new String[info.files.size()];
int[] newClassIndices = new int[info.files.size()];
int[] newMethodIndices = new int[info.files.size()];
int[] newTraitIndices = new int[info.files.size()];
for (int i = 0; i < info.files.size(); i++) {
int f = info.files.get(i);
- data[i][0] = Main.getDebugHandler().moduleToString(f);
- data[i][1] = info.lines.get(i);
- data[i][2] = info.stacks.get(i);
+ String moduleName = Main.getDebugHandler().moduleToString(f);
+ String swfHash = null;
+ if (moduleName.contains(":")) {
+ swfHash = moduleName.substring(0, moduleName.indexOf(":"));
+ moduleName = moduleName.substring(moduleName.indexOf(":") + 1);
+ }
+ newSwfHashes[i] = swfHash;
+ data[i][0] = swfHash == null ? "unknown" : Main.getSwfByHash(swfHash).toString();
+ data[i][1] = moduleName;
+ data[i][2] = info.lines.get(i);
+ data[i][3] = info.stacks.get(i);
Integer newClassIndex = Main.getDebugHandler().moduleToClassIndex(f);
newClassIndices[i] = newClassIndex == null ? -1 : newClassIndex;
Integer newMethodIndex = Main.getDebugHandler().moduleToMethodIndex(f);
@@ -135,6 +148,7 @@ public class DebugStackPanel extends JPanel {
}
DefaultTableModel tm = new DefaultTableModel(data, new Object[]{
+ AppStrings.translate("callStack.header.swf"),
AppStrings.translate("callStack.header.file"),
AppStrings.translate("callStack.header.line"),
AppStrings.translate("stack.header.item")
@@ -146,6 +160,7 @@ public class DebugStackPanel extends JPanel {
};
stackTable.setModel(tm);
+ this.swfHashes = newSwfHashes;
this.classIndices = newClassIndices;
this.methodIndices = newMethodIndices;
this.traitIndices = newTraitIndices;
diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
index 606bfd0bf..7aa0df343 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
@@ -57,6 +57,7 @@ import com.jpexs.decompiler.graph.DottedChain;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -85,7 +86,13 @@ public class DebuggerHandler implements DebugConnectionListener {
private Map modulePaths = new HashMap<>();
private Map moduleToSwfIndex = new HashMap<>();
-
+
+ //Marks swfIndices that are fully loaded - at least one break was on it (including onloaded break)
+ private Set swfIndicesCommited = new HashSet<>();
+
+ private Map swfIndicesNewToSwfHash = new HashMap<>();
+
+
private Map scriptToModule = new HashMap<>();
private Map moduleToTraitIndex = new HashMap<>();
@@ -110,7 +117,7 @@ public class DebuggerHandler implements DebugConnectionListener {
private List stackLines = new ArrayList<>();
- private SWF debuggedSwf = null;
+ private List debuggedSwfs = new ArrayList<>();
public static class ActionScriptException extends Exception {
@@ -130,12 +137,13 @@ public class DebuggerHandler implements DebugConnectionListener {
}
}
- public void setDebuggedSwf(SWF debuggedSwf) {
- this.debuggedSwf = debuggedSwf;
+ public void setMainDebuggedSwf(SWF debuggedSwf) {
+ debuggedSwfs.clear();
+ //debuggedSwfs.add(debuggedSwf);
}
- public SWF getDebuggedSwf() {
- return debuggedSwf;
+ public List getDebuggedSwfs() {
+ return debuggedSwfs;
}
public int getBreakIp() {
@@ -538,11 +546,11 @@ public class DebuggerHandler implements DebugConnectionListener {
return frame;
}
- public synchronized int moduleIdOf(String pack) {
- if (scriptToModule.containsKey(pack)) {
- return scriptToModule.get(pack);
+ public synchronized int moduleIdOf(String packWithHash) {
+ if (!scriptToModule.containsKey(packWithHash)) {
+ return -1;
}
- return -1;
+ return scriptToModule.get(packWithHash);
}
public boolean isPaused() {
@@ -569,35 +577,38 @@ public class DebuggerHandler implements DebugConnectionListener {
}
commands = null;
synchronized (this) {
- if (confirmedPointMap.containsKey(debuggedSwf)) {
- for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) {
- if (!toAddBPointMap.containsKey(debuggedSwf)) {
- toAddBPointMap.put(debuggedSwf, new HashMap<>());
+ for (SWF debuggedSwf : debuggedSwfs) {
+ if (confirmedPointMap.containsKey(debuggedSwf)) {
+ for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) {
+ if (!toAddBPointMap.containsKey(debuggedSwf)) {
+ toAddBPointMap.put(debuggedSwf, new HashMap<>());
+ }
+ if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
+ toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
+ }
+ toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(confirmedPointMap.get(debuggedSwf).get(scriptName));
}
- if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
- toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
- }
- toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(confirmedPointMap.get(debuggedSwf).get(scriptName));
+ confirmedPointMap.get(debuggedSwf).clear();
}
- confirmedPointMap.get(debuggedSwf).clear();
- }
- if (invalidBreakPointMap.containsKey(debuggedSwf)) {
- for (String scriptName : invalidBreakPointMap.get(debuggedSwf).keySet()) {
- if (!toAddBPointMap.containsKey(debuggedSwf)) {
- toAddBPointMap.put(debuggedSwf, new HashMap<>());
+ if (invalidBreakPointMap.containsKey(debuggedSwf)) {
+ for (String scriptName : invalidBreakPointMap.get(debuggedSwf).keySet()) {
+ if (!toAddBPointMap.containsKey(debuggedSwf)) {
+ toAddBPointMap.put(debuggedSwf, new HashMap<>());
+ }
+ if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
+ toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
+ }
+ toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(invalidBreakPointMap.get(debuggedSwf).get(scriptName));
}
- if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
- toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
- }
- toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(invalidBreakPointMap.get(debuggedSwf).get(scriptName));
+ invalidBreakPointMap.get(debuggedSwf).clear();
}
- invalidBreakPointMap.get(debuggedSwf).clear();
}
}
for (ConnectionListener l : clisteners) {
l.disconnected();
}
+ debuggedSwfs.clear();
}
public synchronized boolean isConnected() {
@@ -628,7 +639,9 @@ public class DebuggerHandler implements DebugConnectionListener {
@Override
public void connected(DebuggerConnection con) {
- makeBreakPointsUnconfirmed(debuggedSwf);
+ /*for (SWF debuggedSwf : debuggedSwfs) {
+ makeBreakPointsUnconfirmed(debuggedSwf);
+ }*/
Main.startWork(AppStrings.translate("work.debugging"), null);
@@ -661,13 +674,15 @@ public class DebuggerHandler implements DebugConnectionListener {
});
swfs.clear();
-
+ swfIndicesCommited.clear();
+ swfIndicesNewToSwfHash.clear();
+
Map moduleNames = new HashMap<>();
final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$");
- final Pattern patAS3PCode = Pattern.compile("^#PCODE abc:([0-9]+),script:([0-9]+),class:(-?[0-9]+),trait:(-?[0-9]+),method:([0-9]+),body:([0-9]+);(.*)$");
+ final Pattern patAS3PCode = Pattern.compile("^(?[0-9a-z_]+):#PCODE abc:(?[0-9]+),script:(?