diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7605a292c..2dde4aee9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,10 +4,14 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
### Added
- Debugger - Debugged SWF file name in the session title
+- Debugger - Remove watch
+- Debugger - List of watches
+- Debugger - Show flag of watch type (read/write)
### Fixed
- [#2639] Export to FLA - missing sound streams
- Debugger - Threading issues with multiple SWFs
+- Debugger - Reading variables on 64bit flash players (like in browsers)
## [25.1.1] - 2026-02-19
### Fixed
diff --git a/lib/flashdebugger.jar b/lib/flashdebugger.jar
index 9e5d8b116..b0477c274 100644
Binary files a/lib/flashdebugger.jar and b/lib/flashdebugger.jar differ
diff --git a/libsrc/ffdec_lib/lib/flashdebugger.jar b/libsrc/ffdec_lib/lib/flashdebugger.jar
index 9e5d8b116..b0477c274 100644
Binary files a/libsrc/ffdec_lib/lib/flashdebugger.jar and b/libsrc/ffdec_lib/lib/flashdebugger.jar differ
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swd b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swd
new file mode 100644
index 000000000..87c1bc7e0
Binary files /dev/null and b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swd differ
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swf b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swf
index da5f1d2ae..5f3f0af37 100644
Binary files a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swf and b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/DOMDocument.xml b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/DOMDocument.xml
index 9c14de71b..4fa7a414d 100644
--- a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/DOMDocument.xml
+++ b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/DOMDocument.xml
@@ -6,6 +6,8 @@
+
+
@@ -43,6 +45,7 @@ stop();]]>
var score = parseInt(_root.inpScore.text);
score = score + 5;
_root.inpScore.text = score;
+ trace("plus 5");
}]]>
@@ -58,6 +61,7 @@ stop();]]>
var score = parseInt(_root.inpScore.text);
score = score * 2;
_root.inpScore.text = score;
+ trace("multiply 2");
}]]>
@@ -100,7 +104,7 @@ stop();]]>
-
+
@@ -110,6 +114,48 @@ stop();]]>
+
+
+
+
+
+
+
+
+ Speed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -122,6 +168,10 @@ stop();]]>
+
+
+
+
@@ -138,6 +188,5 @@ stop();]]>
-
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonDown.xml b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonDown.xml
new file mode 100644
index 000000000..3d0048d06
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonDown.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonUp.xml b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonUp.xml
new file mode 100644
index 000000000..d2e081df9
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/LIBRARY/ButtonUp.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/META-INF/metadata.xml b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/META-INF/metadata.xml
index 0ac4224b3..e4344c771 100644
--- a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/META-INF/metadata.xml
+++ b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/META-INF/metadata.xml
@@ -5,8 +5,8 @@
xmlns:xmp="http://ns.adobe.com/xap/1.0/">
Adobe Flash Professional CS6 - build 481
2026-02-16T10:31:42-08:00
- 2026-02-16T11:18:35-08:00
- 2026-02-16T11:18:35-08:00
+ 2026-02-21T09:35:10-08:00
+ 2026-02-21T09:35:10-08:00
@@ -17,7 +17,7 @@
xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
xmp.did:7FE581FA660BF11197008EF33C376745
- xmp.iid:9BDF39F36B0BF11197008EF33C376745
+ xmp.iid:377DE8AB4B0FF111A0D3B09FD2F43FD4
xmp.did:7FE581FA660BF11197008EF33C376745
@@ -39,6 +39,12 @@
2026-02-16T10:31:42-08:00
Adobe Flash Professional CS6 - build 481
+
+ created
+ xmp.iid:377DE8AB4B0FF111A0D3B09FD2F43FD4
+ 2026-02-16T10:31:42-08:00
+ Adobe Flash Professional CS6 - build 481
+
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/bin/SymDepend.cache b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/bin/SymDepend.cache
index ce963c485..62634e4c3 100644
Binary files a/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/bin/SymDepend.cache and b/libsrc/ffdec_lib/testdata/debug_game/as2_scoring/bin/SymDepend.cache differ
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring.swf b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring.swf
index 4280165d6..d5bb3532b 100644
Binary files a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring.swf and b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring.swf differ
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/DOMDocument.xml b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/DOMDocument.xml
index 2397a0329..c16c0879e 100644
--- a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/DOMDocument.xml
+++ b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/DOMDocument.xml
@@ -6,6 +6,8 @@
+
+
@@ -42,7 +44,8 @@ setTimeout(decreaseScore, delay);
function onPlus5(e:MouseEvent):void {
var score:int = getScore();
score = score + 5;
- setScore(score);
+ setScore(score);
+ trace("plus 5");
}
butPlus5.addEventListener(MouseEvent.CLICK, onPlus5);
@@ -51,15 +54,32 @@ function onMultiply2(e:MouseEvent):void {
var score:int = getScore();
score = score * 2;
setScore(score);
+ trace("multiply 2");
}
butMultiply2.addEventListener(MouseEvent.CLICK, onMultiply2);
function onReset(e:MouseEvent):void {
setScore(0);
+ trace("reset");
}
-butReset.addEventListener(MouseEvent.CLICK, onReset);]]>
+butReset.addEventListener(MouseEvent.CLICK, onReset);
+
+function onSpeedUp(e:MouseEvent): void {
+ delay = Math.round(delay / 1.1);
+ trace("speed up");
+}
+
+btnSpeedUp.addEventListener(MouseEvent.CLICK, onSpeedUp);
+
+function onSpeedDown(e:MouseEvent): void {
+ delay = Math.round(delay * 1.1);
+ trace("speed down");
+}
+
+btnSpeedDown.addEventListener(MouseEvent.CLICK, onSpeedDown);
+]]>
@@ -125,6 +145,35 @@ butReset.addEventListener(MouseEvent.CLICK, onReset);]]>
+
+
+
+
+
+
+ Speed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -134,6 +183,8 @@ butReset.addEventListener(MouseEvent.CLICK, onReset);]]>
+
+
@@ -152,7 +203,5 @@ butReset.addEventListener(MouseEvent.CLICK, onReset);]]>
-
-
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonDown.xml b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonDown.xml
new file mode 100644
index 000000000..3d0048d06
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonDown.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonUp.xml b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonUp.xml
new file mode 100644
index 000000000..d2e081df9
--- /dev/null
+++ b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/LIBRARY/ButtonUp.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/META-INF/metadata.xml b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/META-INF/metadata.xml
index 445a6caa0..fe30b6721 100644
--- a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/META-INF/metadata.xml
+++ b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/META-INF/metadata.xml
@@ -5,8 +5,8 @@
xmlns:xmp="http://ns.adobe.com/xap/1.0/">
Adobe Flash Professional CS6 - build 481
2026-02-16T10:31:42-08:00
- 2026-02-16T11:18:44-08:00
- 2026-02-16T11:18:44-08:00
+ 2026-02-21T09:45:46-08:00
+ 2026-02-21T09:45:46-08:00
@@ -22,7 +22,7 @@
xmp.did:7FE581FA660BF11197008EF33C376745
xmp.did:EDF1CDD4690BF11197008EF33C376745
- xmp.iid:9DDF39F36B0BF11197008EF33C376745
+ xmp.iid:3B7DE8AB4B0FF111A0D3B09FD2F43FD4
xmp.did:7FE581FA660BF11197008EF33C376745
@@ -45,6 +45,12 @@
2026-02-16T10:31:42-08:00
Adobe Flash Professional CS6 - build 481
+
+ created
+ xmp.iid:3B7DE8AB4B0FF111A0D3B09FD2F43FD4
+ 2026-02-16T10:31:42-08:00
+ Adobe Flash Professional CS6 - build 481
+
diff --git a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/bin/SymDepend.cache b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/bin/SymDepend.cache
index dbecb1715..2debd5f6d 100644
Binary files a/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/bin/SymDepend.cache and b/libsrc/ffdec_lib/testdata/debug_game/as3_scoring/bin/SymDepend.cache differ
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
index 7c5b7703c..7a5e9b9c9 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebugPanel.java
@@ -16,6 +16,8 @@
*/
package com.jpexs.decompiler.flash.gui;
+import com.jpexs.debugger.flash.Debugger;
+import com.jpexs.debugger.flash.DebuggerCommands;
import com.jpexs.debugger.flash.Variable;
import com.jpexs.debugger.flash.messages.in.InConstantPool;
import com.jpexs.debugger.flash.messages.in.InFrame;
@@ -70,7 +72,9 @@ public class DebugPanel extends JPanel {
private MyTreeTable debugRegistersTable;
- private MyTreeTable debugLocalsTable; //JTable debugLocalsTable;
+ private MyTreeTable debugLocalsTable;
+
+ private MyTreeTable debugWatchesTable;
private MyTreeTable debugScopeTable;
@@ -91,14 +95,14 @@ public class DebugPanel extends JPanel {
private boolean loading = false;
public ABCPanel.VariablesTableModel localsTable;
-
+
private WeakReference currentSessionRef = null;
private boolean as3;
-
+
public static enum SelectedTab {
- LOG, STACK, SCOPECHAIN, LOCALS, REGISTERS, CALLSTACK, CONSTANTPOOL
+ LOG, STACK, SCOPECHAIN, LOCALS, WATCHES, REGISTERS, CALLSTACK, CONSTANTPOOL
}
public synchronized boolean isLoading() {
@@ -107,6 +111,7 @@ public class DebugPanel extends JPanel {
public synchronized void setLoading(boolean loading) {
this.loading = loading;
+ //varTabs.setVisible(!loading);
}
private SelectedTab selectedTab = null;
@@ -157,15 +162,16 @@ public class DebugPanel extends JPanel {
//ignore
}
if (wasEmpty) {
- refresh(session);
+ refresh();
}
}
public DebugPanel(boolean as3) {
super(new BorderLayout());
this.as3 = as3;
- debugRegistersTable = new MyTreeTable(new ABCPanel.VariablesTableModel(as3, debugRegistersTable, new ArrayList<>()), false);
- debugLocalsTable = new MyTreeTable(new ABCPanel.VariablesTableModel(as3, debugLocalsTable, new ArrayList<>()), false);
+ debugRegistersTable = new MyTreeTable(new ABCPanel.VariablesTableModel(null, as3, debugRegistersTable, new ArrayList<>(), new ArrayList<>()), false);
+ debugLocalsTable = new MyTreeTable(new ABCPanel.VariablesTableModel(null, as3, debugLocalsTable, new ArrayList<>(), new ArrayList<>()), false);
+ debugWatchesTable = new MyTreeTable(new ABCPanel.VariablesTableModel(null, as3, debugWatchesTable, new ArrayList<>(), new ArrayList<>()), false);
MouseAdapter watchHandler = new MouseAdapter() {
@@ -184,7 +190,7 @@ public class DebugPanel extends JPanel {
}
private void dopop(MouseEvent e) {
-
+
if (currentSessionRef == null) {
return;
}
@@ -192,11 +198,13 @@ public class DebugPanel extends JPanel {
if (session == null) {
return;
}
-
- if (debugLocalsTable.getSelectedRow() == -1) {
+
+ MyTreeTable src = (MyTreeTable) e.getSource();
+
+ if (src.getSelectedRow() == -1) {
return;
}
- Object node = debugLocalsTable.getTree().getPathForRow(debugLocalsTable.getSelectedRow()).getLastPathComponent();
+ Object node = src.getTree().getPathForRow(src.getSelectedRow()).getLastPathComponent();
Variable v;
ABCPanel.VariableNode vn;
if (node instanceof ABCPanel.VariableNode) {
@@ -261,7 +269,7 @@ public class DebugPanel extends JPanel {
if (igv == null) {
return;
}
- Variable debugConnectionClass = igv.parent;
+ Variable debugConnectionClass = igv.parent;
String dataStr = (String) session.callMethod(debugConnectionClass, "readCommaSeparatedFromByteArray", Arrays.asList(v)).variables.get(0).value;
String[] parts = dataStr.split(",");
byte[] data = new byte[parts.length];
@@ -356,35 +364,63 @@ public class DebugPanel extends JPanel {
watchReadMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(session, v, watchParentId, true, false)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ return;
}
+ refresh();
});
JMenuItem watchWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.write"));
watchWriteMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(session, v, watchParentId, false, true)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ return;
}
+ refresh();
});
JMenuItem watchReadWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.readwrite"));
watchReadWriteMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(session, v, watchParentId, true, true)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ return;
}
+ refresh();
});
addWatchMenu.add(watchReadMenuItem);
addWatchMenu.add(watchWriteMenuItem);
addWatchMenu.add(watchReadWriteMenuItem);
pm.add(addWatchMenu);
+
+ JMenuItem removeWatcheMenuItem = new JMenuItem(AppStrings.translate("debug.watch.remove"));
+ removeWatcheMenuItem.addActionListener((ActionEvent e1) -> {
+ if (!Main.removeWatch(session, v, watchParentId)) {
+ ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.remove"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ refresh();
+ });
+ if (session.getWatch(v.name, watchParentId) != null) {
+ pm.add(removeWatcheMenuItem);
+ }
pm.show(e.getComponent(), e.getX(), e.getY());
}
};
debugLocalsTable.addMouseListener(watchHandler);
+ debugWatchesTable.addMouseListener(watchHandler);
//debugScopeTable.addMouseListener(watchHandler);
- debugScopeTable = new MyTreeTable(new ABCPanel.VariablesTableModel(as3, debugScopeTable, new ArrayList<>()), false);
+ debugScopeTable = new MyTreeTable(new ABCPanel.VariablesTableModel(null, as3, debugScopeTable, new ArrayList<>(), new ArrayList<>()), false);
- constantPoolTable = new JTable();
+ constantPoolTable = new JTable(new DefaultTableModel(new Object[2][0], new Object[]{
+ AppStrings.translate("constantpool.header.id"),
+ AppStrings.translate("constantpool.header.value")
+ }) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+
+ });
traceLogTextarea = new JTextArea();
traceLogTextarea.setEditable(false);
traceLogTextarea.setOpaque(false);
@@ -408,7 +444,7 @@ public class DebugPanel extends JPanel {
public void errorException(DebuggerSession session, String message, Variable thrownVar) {
logAdd(session, "unhandled exception: " + message);
selectedTab = tabTypes.get(tabTypes.size() - 1);
- refresh(session);
+ refresh();
}
});
@@ -420,19 +456,26 @@ public class DebugPanel extends JPanel {
@Override
public void disconnected(DebuggerSession session) {
- refresh(session);
+ refresh();
+ }
+ });
+
+ Main.getDebugHandler().addSelectionListener(new DebuggerHandler.SessionSelectionListener() {
+ @Override
+ public void sessionSelected(DebuggerSession newSession, int oldSessionId) {
+ refresh();
}
});
Main.getDebugHandler().addFrameChangeListener(frameChangeListener = new DebuggerHandler.FrameChangeListener() {
@Override
public void frameChanged(DebuggerSession session) {
- View.execInEventDispatchLater(new Runnable() {
- @Override
- public void run() {
- refresh(session);
- }
- });
+ /*DebuggerSession currentSession = Main.getCurrentDebugSession();
+ if (session != currentSession) {
+ return;
+ } */
+
+ refresh();
}
});
@@ -440,22 +483,18 @@ public class DebugPanel extends JPanel {
@Override
public void doContinue(DebuggerSession session) {
- View.execInEventDispatch(new Runnable() {
- @Override
- public void run() {
- refresh(Main.getCurrentDebugSession());
- }
- });
+ refresh();
}
@Override
public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
- View.execInEventDispatch(new Runnable() {
+ /*View.execInEventDispatch(new Runnable() {
@Override
public void run() {
refresh(Main.getCurrentDebugSession());
}
- });
+ });*/
+ //reacts to frameChanged instead
}
});
@@ -479,7 +518,7 @@ public class DebugPanel extends JPanel {
});
add(new HeaderLabel(AppStrings.translate("debugpanel.header")), BorderLayout.NORTH);
- add(varTabs, BorderLayout.CENTER);
+ add(varTabs, BorderLayout.CENTER);
}
/* private void getVariableList() {
@@ -509,190 +548,269 @@ public class DebugPanel extends JPanel {
}
return v.getMembers(this);
}*/
- public void refresh(DebuggerSession session) {
-
- if (session != null && !session.isPaused()) {
- return;
+ private final Object refreshLock = new Object();
+
+ public void refresh() {
+ DebuggerSession session = Main.getCurrentDebugSession();
+
+ if (session != null) {
+ SWF swf = session.getCurrentSwf();
+ if (swf != null) {
+ if (swf.isAS3() != as3) {
+ return;
+ }
+ }
}
-
+
currentSessionRef = session == null ? null : new WeakReference<>(session);
- View.execInEventDispatch(new Runnable() {
+ Runnable r = new Runnable() {
@Override
public void run() {
- if (session != null && !session.isPaused()) {
- return;
- }
- setLoading(true);
- synchronized (DebugPanel.this) {
+ synchronized (refreshLock) {
+ try {
+ setLoading(true);
- SelectedTab oldSel = selectedTab;
- localsTable = null;
- InFrame f = session == null ? null : session.getFrame();
- if (f != null) {
-
-
- List locals = new ArrayList<>();
-
-
- Map placedObjects = session.getPlacedObjects();
- for (String poName : placedObjects.keySet()) {
- String realName = poName;
- if ("/".equals(realName)) {
- realName = "_root";
- } else if (realName.startsWith("/")) {
- continue;
- }
- InGetVariable igv = session.getVariable(0, realName, false, false);
- if (igv != null) {
- Variable placedVar = igv.parent;
- if (placedVar != null) {
- locals.add(placedVar);
+ int sessionId = -1;
+
+ if (session != null) {
+ sessionId = session.getId();
+ ABCPanel.VariableNode.stopLoading(sessionId); //stop any previous loading
+ }
+
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Refreshing debug panel", new Object[]{sessionId});
+
+ localsTable = null;
+ InFrame f = session == null ? null : session.getFrame();
+
+ ABCPanel.VariablesTableModel registersTableModel = new ABCPanel.VariablesTableModel(session, as3, debugRegistersTable, new ArrayList<>(), new ArrayList<>());
+ ABCPanel.VariablesTableModel localsTableModel = new ABCPanel.VariablesTableModel(session, as3, debugLocalsTable, new ArrayList<>(), new ArrayList<>());
+ ABCPanel.VariablesTableModel scopeTableModel = new ABCPanel.VariablesTableModel(session, as3, debugScopeTable, new ArrayList<>(), new ArrayList<>());
+ ABCPanel.VariablesTableModel watchesTableModel = new ABCPanel.VariablesTableModel(session, as3, debugWatchesTable, new ArrayList<>(), new ArrayList<>());
+ ABCPanel.VariablesTableModel fRegistersTableModel;
+ ABCPanel.VariablesTableModel fLocalsTableModel;
+ ABCPanel.VariablesTableModel fScopeTableModel;
+ ABCPanel.VariablesTableModel fWatchesTableModel;
+ Object[][] fCpoolData;
+
+ if (f != null) {
+
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Debug panel - has frame", new Object[]{sessionId});
+
+ List locals = new ArrayList<>();
+
+ Map placedObjects = session.getPlacedObjects();
+ for (String poName : placedObjects.keySet()) {
+ String realName = poName;
+ if ("/".equals(realName)) {
+ realName = "_root";
+ } else if (realName.startsWith("/")) {
+ continue;
+ }
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Getting placedObject {1}", new Object[]{sessionId, realName});
+ InGetVariable igv = session.getVariable(0, realName, false, false);
+ if (igv != null) {
+ Variable placedVar = igv.parent;
+ if (placedVar != null) {
+ locals.add(placedVar);
+ }
+ } else {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Cannot get placedObject {1}", new Object[]{sessionId, realName});
}
}
+
+ locals.addAll(f.arguments);
+ locals.addAll(f.variables);
+
+ localsTable = new ABCPanel.VariablesTableModel(session, as3, debugLocalsTable, locals, null);
+
+ List watchedVars = new ArrayList<>();
+ List watchedParentIds = new ArrayList<>();
+ for (DebuggerCommands.Watch w : session.getWatches().values()) {
+ InGetVariable igv = session.getVariable(w.varId, w.varName, false, false);
+ if (igv != null) {
+ Variable wVar = igv.parent;
+ if (wVar != null) {
+ watchedVars.add(wVar);
+ watchedParentIds.add(w.varId);
+ }
+ }
+ }
+
+ TreeModelListener refreshListener = new TreeModelListener() {
+ @Override
+ public void treeNodesChanged(TreeModelEvent e) {
+ synchronized (DebugPanel.this) {
+ if (loading) {
+ return;
+ }
+ }
+ session.refreshFrame();
+ }
+
+ @Override
+ public void treeNodesInserted(TreeModelEvent e) {
+ }
+
+ @Override
+ public void treeNodesRemoved(TreeModelEvent e) {
+
+ }
+
+ @Override
+ public void treeStructureChanged(TreeModelEvent e) {
+
+ }
+ };
+
+ registersTableModel = new ABCPanel.VariablesTableModel(session, as3, debugRegistersTable, f.registers, null);
+ localsTableModel = localsTable;
+ scopeTableModel = new ABCPanel.VariablesTableModel(session, as3, debugScopeTable, f.scopeChain, null);
+ watchesTableModel = new ABCPanel.VariablesTableModel(session, as3, debugWatchesTable, watchedVars, watchedParentIds);
+
+ localsTableModel.addTreeModelListener(refreshListener);
+ scopeTableModel.addTreeModelListener(refreshListener);
+ watchesTableModel.addTreeModelListener(refreshListener);
}
-
- safeSetTreeModel(debugRegistersTable, new ABCPanel.VariablesTableModel(as3, debugRegistersTable, f.registers));
-
- locals.addAll(f.arguments);
- locals.addAll(f.variables);
-
- localsTable = new ABCPanel.VariablesTableModel(as3, debugLocalsTable, locals);
- safeSetTreeModel(debugLocalsTable, localsTable);
- safeSetTreeModel(debugScopeTable, new ABCPanel.VariablesTableModel(as3, debugScopeTable, f.scopeChain));
-
- /*TableModelListener refreshListener = new TableModelListener() {
- @Override
- public void tableChanged(TableModelEvent e) {
- Main.getDebugHandler().refreshFrame();
- refresh();
- }
- };*/
- TreeModelListener refreshListener = new TreeModelListener() {
- @Override
- public void treeNodesChanged(TreeModelEvent e) {
- session.refreshFrame();
- refresh(session);
+ InConstantPool cpool = session == null ? null : session.getConstantPool();
+ Object[][] cpoolData = new Object[0][2];
+ if (cpool != null) {
+ cpoolData = new Object[cpool.vars.size()][2];
+ for (int i = 0; i < cpool.vars.size(); i++) {
+ cpoolData[i][0] = cpool.ids.get(i);
+ cpoolData[i][1] = cpool.vars.get(i).value;
}
-
- @Override
- public void treeNodesInserted(TreeModelEvent e) {
- session.refreshFrame();
- refresh(session);
- }
-
- @Override
- public void treeNodesRemoved(TreeModelEvent e) {
- session.refreshFrame();
- refresh(session);
- }
-
- @Override
- public void treeStructureChanged(TreeModelEvent e) {
- session.refreshFrame();
- refresh(session);
- }
- };
- debugLocalsTable.getTreeTableModel().addTreeModelListener(refreshListener);
- debugScopeTable.getTreeTableModel().addTreeModelListener(refreshListener);
- } else {
- debugRegistersTable.setTreeModel(new ABCPanel.VariablesTableModel(as3, debugRegistersTable, new ArrayList<>()));
- debugLocalsTable.setTreeModel(new ABCPanel.VariablesTableModel(as3, debugLocalsTable, new ArrayList<>()));
- debugScopeTable.setTreeModel(new ABCPanel.VariablesTableModel(as3, debugScopeTable, new ArrayList<>()));
- }
- InConstantPool cpool = session == null ? null : session.getConstantPool();
- if (cpool != null) {
- Object[][] data2 = new Object[cpool.vars.size()][2];
- for (int i = 0; i < cpool.vars.size(); i++) {
- data2[i][0] = cpool.ids.get(i);
- data2[i][1] = cpool.vars.get(i).value;
}
- constantPoolTable.setModel(new DefaultTableModel(data2, new Object[]{
- AppStrings.translate("constantpool.header.id"),
- AppStrings.translate("constantpool.header.value")
- }) {
+
+ fRegistersTableModel = registersTableModel;
+ fLocalsTableModel = localsTableModel;
+ fScopeTableModel = scopeTableModel;
+ fWatchesTableModel = watchesTableModel;
+ fCpoolData = cpoolData;
+
+ View.execInEventDispatch(new Runnable() {
@Override
- public boolean isCellEditable(int row, int column) {
- return false;
- }
+ public void run() {
+ try {
+ if (f != null) {
+ safeSetTreeModel(debugRegistersTable, fRegistersTableModel);
+ safeSetTreeModel(debugLocalsTable, fLocalsTableModel);
+ safeSetTreeModel(debugScopeTable, fScopeTableModel);
+ safeSetTreeModel(debugWatchesTable, fWatchesTableModel);
+ } else {
+ debugRegistersTable.setTreeModel(fRegistersTableModel);
+ debugLocalsTable.setTreeModel(fLocalsTableModel);
+ debugScopeTable.setTreeModel(fScopeTableModel);
+ debugWatchesTable.setTreeModel(fWatchesTableModel);
+ }
- });
- } else {
- constantPoolTable.setModel(new DefaultTableModel());
- }
+ constantPoolTable.setModel(new DefaultTableModel(fCpoolData, new Object[]{
+ AppStrings.translate("constantpool.header.id"),
+ AppStrings.translate("constantpool.header.value")
+ }) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
- varTabs.removeAll();
- tabTypes.clear();
- JPanel pa;
- if (debugRegistersTable.getRowCount() > 0) {
- tabTypes.add(SelectedTab.REGISTERS);
- pa = new JPanel(new BorderLayout());
- pa.add(new FasterScrollPane(debugRegistersTable), BorderLayout.CENTER);
- varTabs.addTab(AppStrings.translate("variables.header.registers"), pa);
- }
- if (debugLocalsTable.getRowCount() > 0) {
- tabTypes.add(SelectedTab.LOCALS);
+ });
- pa = new JPanel(new BorderLayout());
- pa.add(new FasterScrollPane(debugLocalsTable), BorderLayout.CENTER);
- varTabs.addTab(AppStrings.translate("variables.header.locals"), pa);
- }
+ varTabs.removeAll();
+ tabTypes.clear();
+ JPanel pa;
+ if (debugRegistersTable.getRowCount() > 0) {
+ tabTypes.add(SelectedTab.REGISTERS);
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(debugRegistersTable), BorderLayout.CENTER);
+ varTabs.addTab(AppStrings.translate("variables.header.registers"), pa);
+ }
+ if (debugLocalsTable.getRowCount() > 0) {
+ tabTypes.add(SelectedTab.LOCALS);
- if (debugScopeTable.getRowCount() > 0) {
- tabTypes.add(SelectedTab.SCOPECHAIN);
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(debugLocalsTable), BorderLayout.CENTER);
+ varTabs.addTab(AppStrings.translate("variables.header.locals"), pa);
+ }
- pa = new JPanel(new BorderLayout());
- pa.add(new FasterScrollPane(debugScopeTable), BorderLayout.CENTER);
- varTabs.addTab(AppStrings.translate("variables.header.scopeChain"), pa);
- }
+ if (debugWatchesTable.getRowCount() > 0) {
+ tabTypes.add(SelectedTab.WATCHES);
- if (constantPoolTable.getRowCount() > 0) {
- tabTypes.add(SelectedTab.CONSTANTPOOL);
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(debugWatchesTable), BorderLayout.CENTER);
+ varTabs.addTab(AppStrings.translate("variables.header.watches"), pa);
+ }
- pa = new JPanel(new BorderLayout());
- pa.add(new FasterScrollPane(constantPoolTable), BorderLayout.CENTER);
- varTabs.addTab(AppStrings.translate("constantpool.header"), pa);
- }
+ if (debugScopeTable.getRowCount() > 0) {
+ tabTypes.add(SelectedTab.SCOPECHAIN);
- if (logLength > 0) {
- tabTypes.add(SelectedTab.LOG);
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(debugScopeTable), BorderLayout.CENTER);
+ varTabs.addTab(AppStrings.translate("variables.header.scopeChain"), pa);
+ }
- pa = new JPanel(new BorderLayout());
- pa.add(new FasterScrollPane(traceLogTextarea), BorderLayout.CENTER);
- JButton clearButton = new JButton(AppStrings.translate("debuglog.button.clear"));
- clearButton.addActionListener(new ActionListener() {
+ if (constantPoolTable.getRowCount() > 0) {
+ tabTypes.add(SelectedTab.CONSTANTPOOL);
+
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(constantPoolTable), BorderLayout.CENTER);
+ varTabs.addTab(AppStrings.translate("constantpool.header"), pa);
+ }
+
+ if (logLength > 0) {
+ tabTypes.add(SelectedTab.LOG);
+
+ pa = new JPanel(new BorderLayout());
+ pa.add(new FasterScrollPane(traceLogTextarea), BorderLayout.CENTER);
+ JButton clearButton = new JButton(AppStrings.translate("debuglog.button.clear"));
+ clearButton.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ traceLogTextarea.setText("");
+ logLength = 0;
+ refresh();
+ }
+ });
+ JPanel butPanel = new JPanel(new FlowLayout());
+ butPanel.add(clearButton);
+ pa.add(butPanel, BorderLayout.SOUTH);
+ varTabs.addTab(AppStrings.translate("debuglog.header"), pa);
+ }
+ boolean newVisible = !tabTypes.isEmpty();
+ if (newVisible != isVisible()) {
+ setVisible(newVisible);
+ }
+
+ SelectedTab oldSel = selectedTab;
+
+ if (!tabTypes.isEmpty()) {
+ if (oldSel != null && !tabTypes.contains(oldSel)) {
+ oldSel = null;
+ }
+ }
+ if (oldSel != null) {
+ selectedTab = oldSel;
+ varTabs.setSelectedIndex(tabTypes.indexOf(selectedTab));
+ }
+ } catch (Throwable t) {
+ int sessionId = session == null ? -1 : session.getId();
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session" + sessionId + ": Error refeshing debug panel in UI thread", t);
+ }
+
+ setLoading(false);
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Refreshed debug panel", new Object[]{session == null ? -1 : session.getId()});
- @Override
- public void actionPerformed(ActionEvent e) {
- traceLogTextarea.setText("");
- logLength = 0;
- refresh(session);
}
});
- JPanel butPanel = new JPanel(new FlowLayout());
- butPanel.add(clearButton);
- pa.add(butPanel, BorderLayout.SOUTH);
- varTabs.addTab(AppStrings.translate("debuglog.header"), pa);
+ } catch (Throwable t) {
+ int sessionId = session == null ? -1 : session.getId();
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session" + sessionId + ": Error refeshing debug panel", t);
}
- boolean newVisible = !tabTypes.isEmpty();
- if (newVisible != isVisible()) {
- setVisible(newVisible);
- }
- if (!tabTypes.isEmpty()) {
- if (oldSel != null && !tabTypes.contains(oldSel)) {
- oldSel = null;
- }
- }
- if (oldSel != null) {
- selectedTab = oldSel;
- varTabs.setSelectedIndex(tabTypes.indexOf(selectedTab));
- }
- setLoading(false);
}
-
}
- });
+ };
+ DebuggerHandler.getPool().submit(r);
}
public void dispose() {
diff --git a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
index 294e5662a..8b3508a6a 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebugStackPanel.java
@@ -45,6 +45,7 @@ import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableModel;
/**
* @author JPEXS
@@ -67,8 +68,23 @@ public class DebugStackPanel extends JPanel {
private int[] traitIndices = new int[0];
private WeakReference currentSessionRef = null;
+ private DefaultTableModel getStackTableModel(Object[][] data) {
+ return 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")
+ }) {
+ @Override
+ public boolean isCellEditable(int row, int column) {
+ return false;
+ }
+
+ };
+ }
+
public DebugStackPanel() {
- stackTable = new JTable();
+ stackTable = new JTable(getStackTableModel(new Object[0][4]));
Main.getDebugHandler().addFrameChangeListener(new DebuggerHandler.FrameChangeListener() {
@Override
public void frameChanged(DebuggerSession session) {
@@ -160,8 +176,10 @@ public class DebugStackPanel extends JPanel {
sessionComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- if (sessionComboBoxCreating) {
- return;
+ synchronized (DebugStackPanel.this) {
+ if (sessionComboBoxCreating) {
+ return;
+ }
}
SessionItem selection = (SessionItem) sessionComboBox.getSelectedItem();
if (selection != null) {
@@ -174,12 +192,13 @@ public class DebugStackPanel extends JPanel {
lastSessionComboBoxIndex = sessionComboBox.getSelectedIndex();
Main.getDebugHandler().setSelectedSessionId(session.getId());
+ //session.refreshFrame();
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
refresh(session);
}
- });
+ });
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
@@ -210,7 +229,7 @@ public class DebugStackPanel extends JPanel {
SessionItem item = (SessionItem) value;
if (item != null) {
DebuggerSession session = Main.getDebugHandler().getSessionById(item.id);
- if (!session.isPaused()) {
+ if (session == null || !session.isPaused()) {
c.setForeground(Color.GRAY);
c.setBackground(list.getBackground());
} else {
@@ -279,8 +298,8 @@ public class DebugStackPanel extends JPanel {
}
}
- public void clear() {
- stackTable.setModel(new DefaultTableModel());
+ public void clear() {
+ stackTable.setModel(getStackTableModel(new Object[0][4]));
if (Main.getDebugHandler().getActiveSessions().isEmpty()) {
active = false;
}
@@ -304,7 +323,10 @@ public class DebugStackPanel extends JPanel {
model.addElement(new SessionItem(id));
j++;
}
- sessionComboBoxCreating = true;
+ synchronized (this) {
+ sessionComboBoxCreating = true;
+ }
+
if (itemIndex > -1) {
final int fItemIndex = itemIndex;
View.execInEventDispatchLater(new Runnable() {
@@ -315,7 +337,9 @@ public class DebugStackPanel extends JPanel {
sessionComboBox.setSelectedIndex(fItemIndex);
}
lastSessionComboBoxIndex = fItemIndex;
- sessionComboBoxCreating = false;
+ synchronized (DebugStackPanel.this) {
+ sessionComboBoxCreating = false;
+ }
}
});
}
@@ -378,19 +402,7 @@ public class DebugStackPanel extends JPanel {
newTraitIndices[i] = newTraitIndex == null ? -1 : newTraitIndex;
}
- 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")
- }) {
- @Override
- public boolean isCellEditable(int row, int column) {
- return false;
- }
-
- };
- stackTable.setModel(tm);
+ stackTable.setModel(getStackTableModel(data));
this.swfHashes = newSwfHashes;
this.classIndices = newClassIndices;
this.methodIndices = newMethodIndices;
@@ -410,11 +422,12 @@ public class DebugStackPanel extends JPanel {
}
};
- if (stackTable.getColumnModel().getColumnCount() >= 3) {
+ stackTable.setDefaultRenderer(String.class, renderer);
+ /*if (stackTable.getColumnModel().getColumnCount() >= 3) {
stackTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
- }
+ }*/
repaint();
}
});
diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
index 019ebfc81..9c2560f5c 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebuggerHandler.java
@@ -31,6 +31,10 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.WeakHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* @author JPEXS
@@ -46,6 +50,8 @@ public class DebuggerHandler implements DebugConnectionListener {
private boolean terminating = false;
private Map>> allBreakPoints = new WeakHashMap<>();
+
+ private static ExecutorService pool = null;
public static class ActionScriptException extends Exception {
@@ -263,6 +269,11 @@ public class DebuggerHandler implements DebugConnectionListener {
synchronized (this) {
terminating = false;
}
+
+ if (pool != null) {
+ pool.shutdownNow();
+ pool = null;
+ }
}
public synchronized Map> getAllSessionsBreakPoints(SWF swf) {
@@ -423,4 +434,20 @@ public class DebuggerHandler implements DebugConnectionListener {
}
return true;
}
+
+
+
+ public static synchronized ExecutorService getPool() {
+ if (pool == null) {
+ AtomicInteger counter = new AtomicInteger(1);
+
+ ThreadFactory namedThreadFactory = runnable -> {
+ Thread t = new Thread(runnable);
+ t.setName("debugger-handler-thread-" + counter.getAndIncrement());
+ return t;
+ };
+ pool = Executors.newCachedThreadPool(namedThreadFactory);
+ }
+ return pool;
+ }
}
diff --git a/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java b/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java
index 4df57d67c..5647bc689 100644
--- a/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java
+++ b/src/com/jpexs/decompiler/flash/gui/DebuggerSession.java
@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.gui;
import com.jpexs.debugger.flash.DebugMessageListener;
+import com.jpexs.debugger.flash.Debugger;
import com.jpexs.debugger.flash.DebuggerCommands;
import com.jpexs.debugger.flash.DebuggerConnection;
import com.jpexs.debugger.flash.Variable;
@@ -34,6 +35,7 @@ import com.jpexs.debugger.flash.messages.in.InFrame;
import com.jpexs.debugger.flash.messages.in.InGetSwf;
import com.jpexs.debugger.flash.messages.in.InGetVariable;
import com.jpexs.debugger.flash.messages.in.InNumScript;
+import com.jpexs.debugger.flash.messages.in.InOption;
import com.jpexs.debugger.flash.messages.in.InPlaceObject;
import com.jpexs.debugger.flash.messages.in.InProcessTag;
import com.jpexs.debugger.flash.messages.in.InScript;
@@ -47,6 +49,7 @@ import com.jpexs.debugger.flash.messages.out.OutGetSwf;
import com.jpexs.debugger.flash.messages.out.OutPlay;
import com.jpexs.debugger.flash.messages.out.OutProcessedTag;
import com.jpexs.debugger.flash.messages.out.OutRewind;
+import com.jpexs.debugger.flash.messages.out.OutSetOption;
import com.jpexs.debugger.flash.messages.out.OutSwfInfo;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
@@ -56,6 +59,7 @@ import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -136,14 +140,17 @@ public class DebuggerSession {
private InSetBreakpoint inSetBreakpoint;
private int id;
-
+
private String title = "";
-
+ private static final int DEFAULT_TIMEOUT = 1000;
+
private List getSwfThreadList = Collections.synchronizedList(new ArrayList<>());
+ private Map watches = new LinkedHashMap<>();
+
public DebuggerSession(DebuggerHandler handler, DebuggerConnection con, Map>> breakpoints) {
- id = con.getId();
+ id = con.getId();
toAddBPointMap = breakpoints;
this.handler = handler;
@@ -157,10 +164,8 @@ public class DebuggerSession {
@Override
public void run() {
Main.getMainFrame().getPanel().updateMenu();
- }
+ }
});
-
-
//enlog(DebuggerConnection.class);
//enlog(DebuggerCommands.class);
@@ -291,6 +296,10 @@ public class DebuggerSession {
commands.setGetterTimeout(1500);
commands.setSetterTimeout(5000);
+ if (commands.playerConcurrency()) {
+ commands.debuggerSetConcurrency();
+ }
+
commands.squelch(true);
con.addMessageListener(new DebugMessageListener() {
@@ -340,16 +349,16 @@ public class DebuggerSession {
if (inGetSwf == null) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: Cannot read SWF", id);
continue;
- }
+ }
String sha256 = Helper.byteArrayToHex(MessageDigest.getInstance("SHA-256").digest(inGetSwf.swfData));
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: Received SWF hash = {1}", new Object[]{id, sha256});
-
+
String originalHash = Main.getHashFromMetadataFromSwfBytes(inGetSwf.swfData);
if (originalHash != null) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: Received SWF original hash = {1}", new Object[]{id, originalHash});
sha256 = originalHash;
}
-
+
SWF debuggedSwf = Main.findOpenedSwfByHash(sha256);
if (debuggedSwf == null) {
con.disconnect();
@@ -379,9 +388,9 @@ public class DebuggerSession {
}
try {
-
+
Set hashes = new LinkedHashSet<>();
-
+
for (int file : modulePaths.keySet()) {
String path = modulePaths.get(file);
if (!path.contains(":")) {
@@ -391,22 +400,22 @@ public class DebuggerSession {
String hash = path.substring(0, path.indexOf(":"));
hashes.add(hash);
}
- for (String hash : hashes) {
+ for (String hash : hashes) {
if (Main.findOpenedSwfByHash(hash) == null) {
//This is probably SWF file instrumented by another software
throw new IOException("SWF with hash " + hash + " not found");
}
- }
-
+ }
+
if (!debuggedSwfs.isEmpty() && modulesEmptyBefore) {
if (title.isEmpty()) {
title = debuggedSwfs.values().iterator().next().toString();
}
if (con.isAS3) {
- //Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines
- con.wideLines = commands.getOption("wide_line_player", "false").equals("true");
+ //Widelines - only AS3, it hangs in AS1/2 and SWD does not support UI32 lines
+ con.wideLines = commands.playerIsWideLine();
if (con.wideLines) {
- commands.setOption("wide_line_debugger", "on");
+ commands.debuggerSetWideLine();;
}
} else {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINER, "session{0}: End of connect - sending continue", id);
@@ -461,7 +470,19 @@ public class DebuggerSession {
con.addMessageListener(new DebugMessageListener() {
@Override
public void message(InPlaceObject t) {
- placedObjects.put(t.path, t.objId);
+ //Sometimes the player sends _global variable with 4 byte PTR instead of 8 byte
+ byte[] globalVar = new byte[]{(byte) 0xfe, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x5f, (byte) 0x67, (byte) 0x6c, (byte) 0x6f, (byte) 0x62, (byte) 0x61, (byte) 0x6c, (byte) 0x00};
+ String placeName = t.path;
+ long placeId = t.objId;
+ if (Arrays.equals(t.data, globalVar)) {
+ Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINER, "session{0}: Received mangled placeobject _global", new Object[]{id});
+ placeName = "_global";
+ placeId = -2;
+ } else {
+ Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINER, "session{0}: Received placeobject {1}", new Object[]{id, t.path});
+ }
+ Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINEST, "session{0}: Placeobject hex data: {1}", new Object[]{id, Helper.byteArrayToHex(t.data)});
+ placedObjects.put(placeName, placeId);
con.dropMessage(t);
}
});
@@ -474,10 +495,10 @@ public class DebuggerSession {
synchronized (DebuggerSession.this) {
paused = false;
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: continued", id);
- }
+ }
for (DebuggerHandler.BreakListener bl : handler.getBreakListeners()) {
bl.doContinue(DebuggerSession.this);
- }
+ }
}
});
@@ -491,14 +512,13 @@ public class DebuggerSession {
@Override
public void run() {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: In break at start", id);
-
+
synchronized (DebuggerSession.this) {
if (!connected) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: Received break while not connected", id);
return;
}
-
-
+
paused = true;
Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: paused", id);
}
@@ -543,7 +563,7 @@ public class DebuggerSession {
sendBreakPoints();
} catch (IOException ex) {
//ignore
- Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: send breakpoints exception: {1}", new Object[] {id, ex.getMessage()});
+ Logger.getLogger(DebuggerSession.class.getName()).log(Level.FINE, "session{0}: send breakpoints exception: {1}", new Object[]{id, ex.getMessage()});
}
synchronized (DebuggerSession.this) {
@@ -574,14 +594,15 @@ public class DebuggerSession {
} else {
Main.startWork(AppStrings.translate("debug.session").replace("%id%", "" + id) + " - " + AppStrings.translate("work.breakat") + userBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null, true);
}
- depth = 0;
- refreshFrame();
-
+
//If there is single one left paused, switch to it
if (Main.getDebugHandler().getNumberOfPausedSessions() == 1) {
Main.getDebugHandler().setSelectedSessionId(getId());
}
-
+
+ depth = 0;
+ refreshFrame();
+
for (DebuggerHandler.BreakListener l : handler.getBreakListeners()) {
l.breakAt(DebuggerSession.this, newBreakScriptName, message.line,
moduleToClassIndex.containsKey(message.file) ? moduleToClassIndex.get(message.file) : -1,
@@ -631,7 +652,7 @@ public class DebuggerSession {
} catch (IOException ex) {
Logger.getLogger(DebuggerSession.class.getName()).log(Level.SEVERE, null, ex);
}
- }*/
+ }*/
con.addMessageListener(new DebugMessageListener() {
@Override
@@ -657,8 +678,6 @@ public class DebuggerSession {
public int getId() {
return id;
}
-
-
public boolean containsSwf(SWF swf) {
return debuggedSwfs.containsValue(swf);
@@ -705,9 +724,9 @@ public class DebuggerSession {
return stackLines;
}
- public InGetVariable getVariable(long parentId, String varName, boolean children, boolean useGetter) {
+ public synchronized InGetVariable getVariable(long parentId, String varName, boolean children, boolean useGetter) {
try {
- return commands.getVariableWithTimeout(parentId, varName, useGetter, children, 100);
+ return commands.getVariableWithTimeout(parentId, varName, useGetter, children, DEFAULT_TIMEOUT);
} catch (IOException ex) {
return null;
}
@@ -740,7 +759,7 @@ public class DebuggerSession {
}
public void removeBreakPoint(SWF swf, String scriptName, int line) {
- synchronized (this) {
+ synchronized (this) {
if (isBreakpointInvalid(swf, scriptName, line)) {
invalidBreakPointMap.get(swf).get(scriptName).remove(line);
if (invalidBreakPointMap.get(swf).get(scriptName).isEmpty()) {
@@ -772,10 +791,19 @@ public class DebuggerSession {
private int watchTag = 1;
- public synchronized com.jpexs.debugger.flash.DebuggerCommands.Watch addWatch(Variable v, long v_id, boolean watchRead, boolean watchWrite) {
+ public synchronized DebuggerCommands.Watch addWatch(String varName, long varId, boolean watchRead, boolean watchWrite) {
+ if (getWatch(varName, varId) != null) {
+ if (!removeWatch(varName, varId)) {
+ return null;
+ }
+ }
int tag = watchTag++;
try {
- return commands.addWatch(v_id, v.name, (watchRead ? OutAddWatch2.FLAG_READ : 0) | (watchWrite ? OutAddWatch2.FLAG_WRITE : 0), tag);
+ com.jpexs.debugger.flash.DebuggerCommands.Watch w = commands.addWatch(varId, varName, (watchRead ? OutAddWatch2.FLAG_READ : 0) | (watchWrite ? OutAddWatch2.FLAG_WRITE : 0), tag);
+ if (w != null) {
+ watches.put("" + w.varId + ":" + w.varName, w);
+ }
+ return w;
} catch (IOException ex) {
return null;
}
@@ -953,8 +981,11 @@ public class DebuggerSession {
}
public void setDepth(int depth) {
+ boolean depthChanged = depth != this.depth;
this.depth = depth;
- refreshFrame();
+ if (depthChanged) {
+ refreshFrame();
+ }
}
public String moduleToString(int file) {
@@ -991,20 +1022,42 @@ public class DebuggerSession {
}
public void refreshFrame() {
- synchronized (this) {
+ synchronized (DebuggerSession.this) {
if (!paused) {
return;
}
- try {
- frame = commands.getFrameWithTimeout(depth, 100);
- pool = commands.getConstantPoolWithTimeout(0, 100);
- } catch (IOException ex) {
- //ignore
+ }
+
+ DebuggerHandler.getPool().submit(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (DebuggerSession.this) {
+ if (!paused) {
+ return;
+ }
+ }
+ try {
+ frame = commands.getFrameWithTimeout(depth, DEFAULT_TIMEOUT);
+ pool = commands.getConstantPoolWithTimeout(0, DEFAULT_TIMEOUT);
+ } catch (IOException ex) {
+ //ignore
+ }
+
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Frame loaded", new Object[]{getId()});
+
+ if (frame == null) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: Frame is null!", new Object[]{getId()});
+ }
+
+ if (pool == null) {
+ Logger.getLogger(DebugPanel.class.getName()).log(Level.FINE, "session{0}: CPool is null!", new Object[]{getId()});
+ }
+
+ for (DebuggerHandler.FrameChangeListener l : handler.getFrameChangeListeners()) {
+ l.frameChanged(DebuggerSession.this);
+ }
}
- }
- for (DebuggerHandler.FrameChangeListener l : handler.getFrameChangeListeners()) {
- l.frameChanged(DebuggerSession.this);
- }
+ });
}
public synchronized InFrame getFrame() {
@@ -1066,17 +1119,17 @@ public class DebuggerSession {
}
}
}
-
+
//If there is single one left paused, switch to it
if (Main.getDebugHandler().getNumberOfPausedSessions() == 1) {
- for (DebuggerSession session : Main.getDebugHandler().getActiveSessions().values()) {
+ for (DebuggerSession session : Main.getDebugHandler().getActiveSessions().values()) {
if (session.isPaused()) {
Main.getDebugHandler().setSelectedSessionId(session.getId());
break;
}
}
}
-
+
for (DebuggerHandler.ConnectionListener l : handler.getConnectionListeners()) {
l.disconnected(DebuggerSession.this);
}
@@ -1282,5 +1335,45 @@ public class DebuggerSession {
public String getTitle() {
return title;
- }
+ }
+
+ public Map getWatches() {
+ return new LinkedHashMap<>(watches);
+ }
+
+ public DebuggerCommands.Watch getWatch(String varName, long varId) {
+ return watches.get("" + varId + ":" + varName);
+ }
+
+ public boolean removeWatch(String varName, long variId) {
+ String key = "" + variId + ":" + varName;
+ if (!watches.containsKey(key)) {
+ return false;
+ }
+ try {
+ if (commands.removeWatch(variId, varName)) {
+ watches.remove(key);
+ return true;
+ }
+ } catch (IOException ex) {
+ //false
+ }
+ return false;
+ }
+
+ public SWF getCurrentSwf() {
+ InBreakAtExt info = getBreakInfo();
+ if (info == null) {
+ return null;
+ }
+ //Object[][] data = new Object[info.files.size()][4];
+ String moduleName = moduleToString(info.file);
+ if (moduleName.contains(":")) {
+ String swfHash = moduleName.substring(0, moduleName.indexOf(":"));
+ return Main.findOpenedSwfByHash(swfHash);
+ } else {
+ List debuggedSwfs = new ArrayList<>(getDebuggedSwfs().values());
+ return debuggedSwfs.get(debuggedSwfs.size() - 1);
+ }
+ }
}
diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java
index 964054641..09fb9fd9e 100644
--- a/src/com/jpexs/decompiler/flash/gui/Main.java
+++ b/src/com/jpexs/decompiler/flash/gui/Main.java
@@ -441,9 +441,13 @@ public class Main {
}
public static synchronized boolean addWatch(DebuggerSession session, Variable v, long v_id, boolean watchRead, boolean watchWrite) {
- DebuggerCommands.Watch w = session.addWatch(v, v_id, watchRead, watchWrite);
+ DebuggerCommands.Watch w = session.addWatch(v.name, v_id, watchRead, watchWrite);
return w != null;
}
+
+ public static synchronized boolean removeWatch(DebuggerSession session, Variable v, long v_id) {
+ return session.removeWatch(v.name, v_id);
+ }
public static void runPlayer(String title, final String exePath, String file, String flashVars) {
if (!new File(file).exists()) {
@@ -1137,7 +1141,7 @@ public class Main {
}
public static void updateSession() {
- DebuggerSession session = getCurrentDebugSession();
+ /*DebuggerSession session = getCurrentDebugSession();
for (DebuggerHandler.FrameChangeListener l : getDebugHandler().getFrameChangeListeners()) {
l.frameChanged(session);
}
@@ -1145,6 +1149,7 @@ public class Main {
if (getDebugHandler().getNumberOfPausedSessions() > 0) {
mainFrame.getPanel().showDebugStackFrame();
}
+ */
}
public static void ensureMainFrame() {
@@ -3197,7 +3202,7 @@ public class Main {
@Override
public void disconnected(DebuggerSession session) {
- Main.updateSession();
+ //Main.updateSession();
if (Main.mainFrame != null) {
Main.mainFrame.getMenu().updateComponents();
}
diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java
index 3ede7ad82..6c0973547 100644
--- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java
@@ -1636,7 +1636,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private void updateUi(final Openable openable) {
View.checkAccess();
- Main.updateSession();
+ //Main.updateSession();
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
@@ -5785,7 +5785,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
return;
}
- Main.updateSession();
+ //Main.updateSession();
if (!(treeItem instanceof OpenableList)) {
Openable openable = treeItem.getOpenable();
diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
index 4201d1175..6e6bcc54b 100644
--- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
+++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java
@@ -16,10 +16,13 @@
*/
package com.jpexs.decompiler.flash.gui.abc;
+import com.jpexs.debugger.flash.DebuggerCommands;
+import com.jpexs.debugger.flash.DebuggerMessage;
import com.jpexs.debugger.flash.Variable;
import com.jpexs.debugger.flash.VariableFlags;
import com.jpexs.debugger.flash.VariableType;
import com.jpexs.debugger.flash.messages.in.InGetVariable;
+import com.jpexs.debugger.flash.messages.out.OutAddWatch2;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.ClassPath;
@@ -266,7 +269,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener loaderList = Collections.synchronizedList(new ArrayList<>());
- private static final Object loaderLock = new Object();
-
+ private static Map sessionIdToVariableLoaderThread = new HashMap<>();
+ private static Map> sessionIdToLoaderList = new HashMap<>();
+ private static Map> sessionIdToLoadedVariableNode = new HashMap<>();
+ private static Map sessionIdToLoaderLock = new HashMap<>();
+
public List path = new ArrayList<>();
public Variable var;
@@ -322,8 +326,25 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener childs;
public List traits = new ArrayList<>();
+ private DebuggerSession session;
+ private MyTreeTable treeTable;
private boolean as3;
-
+
+ public static void stopLoading(int sessionId) {
+ if (!sessionIdToLoadedVariableNode.containsKey(sessionId)) {
+ return;
+ }
+ sessionIdToLoaderList.get(sessionId).clear();
+ for (VariableNode node : sessionIdToLoadedVariableNode.get(sessionId)) {
+ synchronized (node) {
+ node.childs = new ArrayList<>();
+ node.loading = false;
+ node.loaded = true;
+ }
+ }
+ sessionIdToLoadedVariableNode.get(sessionId).clear();
+ }
+
@Override
public int hashCode() {
int hash = 3;
@@ -361,6 +382,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 0) {
varInsideGetter = igv.parent;
@@ -416,10 +444,10 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 0) {
continue;
}
-
+
if (!isTraits(igv.childs.get(i))) {
Long parentObjectId = varToObjectId(varInsideGetter);
- childs.add(new VariableNode(as3, path, level + 1, igv.childs.get(i), parentObjectId, curTrait));
+ childs.add(new VariableNode(currentSession, treeTable, as3, path, level + 1, igv.childs.get(i), parentObjectId, curTrait));
} else {
curTrait = igv.childs.get(i);
traits.add(curTrait);
@@ -427,62 +455,130 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener());
+ sessionIdToLoaderLock.put(sessionId, new Object());
+ Thread t = new Thread(r, "Variable loader for session " + sessionId);
+ sessionIdToVariableLoaderThread.put(sessionId, t);
+ t.setDaemon(true);
+ t.start();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ //ignore
+ }
}
+
+ sessionIdToLoaderList.get(sessionId).add(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (VariableNode.this) {
+ if (!loading) {
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Already loaded {1}, skipping", new Object[]{session.getId(), var.name});
+ return;
+ }
+ }
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Loading children of {1}", new Object[]{session.getId(), var.name});
+
+ reloadChildren();
+
+ synchronized (VariableNode.this) {
+ if (!loading) {
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Already loaded {1}, not firing", new Object[]{session.getId(), var.name});
+ return;
+ }
+ loaded = true;
+ loading = false;
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Children of {1} loaded", new Object[]{session.getId(), var.name});
+ }
+
+ DebuggerSession currentSession = Main.getCurrentDebugSession();
+ if (currentSession == null || currentSession.getId() != sessionId) {
+ return;
+ }
+
+ VariablesTableModel variableModel = (VariablesTableModel) treeTable.getTreeTableModel();
+ Object[] changedPath = new Object[path.size()];
+ for (int i = 0; i < path.size(); i++) {
+ changedPath[i] = path.get(i);
+ }
+ View.execInEventDispatch(new Runnable() {
+ @Override
+ public void run() {
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Firing change of {1} - {2} childs", new Object[]{session.getId(), var.name, childs.size()});
+ int[] childIds = new int[childs.size()];
+ Object[] childObjs = new Object[childs.size()];
+
+ for (int i = 0; i < childIds.length; i++) {
+ childIds[i] = i;
+ childObjs[i] = childs.get(i);
+ }
+
+ //variableModel.fireTreeStructureChanged(treeTable.getTree(), changedPath, new int[0], null);
+ variableModel.fireTreeNodesInserted(treeTable.getTree(), changedPath, childIds, childObjs);
+ treeTable.repaint();
+ }
+ });
+ }
+ });
+ if (!sessionIdToLoadedVariableNode.containsKey(sessionId)) {
+ sessionIdToLoadedVariableNode.put(sessionId, new ArrayList<>());
+ }
+ sessionIdToLoadedVariableNode.get(sessionId).add(this);
+ Object lock = sessionIdToLoaderLock.get(sessionId);
+ Logger.getLogger(VariableNode.class.getName()).log(Level.FINE, "session{0}: Scheduling loading children of {1}", new Object[]{session.getId(), var.name});
+ synchronized (lock) {
+ lock.notify();
+ }
+ /*reloadChildren();
+ loaded = true;*/
}
public VariableNode getChildAt(int index) {
ensureLoaded();
+ if (!loaded) {
+ return null;
+ }
return childs.get(index);
}
public int getChildCount() {
ensureLoaded();
+ if (!loaded) {
+ return 0;
+ }
return childs.size();
}
- public VariableNode(boolean as3, List parentPath, int level, Variable var, Long parentObjectId, Variable trait) {
+ public VariableNode(DebuggerSession session, MyTreeTable treeTable, boolean as3, List parentPath, int level, Variable var, Long parentObjectId, Variable trait) {
this.var = var;
this.varInsideGetter = var;
this.parentObjectId = parentObjectId;
@@ -491,10 +587,12 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener parentPath, int level, Variable var, Long parentObjectId, Variable trait, List subvars) {
+ public VariableNode(DebuggerSession session, MyTreeTable treeTable, boolean as3, List parentPath, int level, Variable var, Long parentObjectId, Variable trait, List subvars) {
this.var = var;
this.varInsideGetter = var;
this.parentObjectId = parentObjectId;
@@ -510,6 +608,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener vars) {
- this.ttable = ttable;
+ public VariablesTableModel(DebuggerSession session, boolean as3, MyTreeTable treeTable, List vars, List parentIds) {
+ this.treeTable = treeTable;
List childs = new ArrayList<>();
for (int i = 0; i < vars.size(); i++) {
- childs.add(new VariableNode(as3, new ArrayList<>(), 1, vars.get(i), 0L, null));
+ childs.add(new VariableNode(session, treeTable, as3, new ArrayList<>(), 1, vars.get(i), parentIds == null ? 0L : parentIds.get(i), null));
}
- root = new VariableNode(as3, new ArrayList<>(), 0, null, 0L, null, childs);
+ root = new VariableNode(session, treeTable, as3, new ArrayList<>(), 0, null, 0L, null, childs);
+ root.loaded = true;
}
@Override
@@ -767,7 +868,26 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener 0) {
+ if (!flags.isEmpty()) {
+ flags += ", ";
+ }
+
+ flags += "watch:read";
+ }
+ if ((w.flags & OutAddWatch2.FLAG_WRITE) > 0) {
+ if (!flags.isEmpty()) {
+ flags += ", ";
+ }
+
+ flags += "watch:write";
+ }
+ }
+ return flags;
case COLUMN_TYPE:
String typeStr = val.getTypeAsStr();
if ("Object".equals(typeStr)) {
@@ -782,7 +902,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener(), ci.abc.getSwf(), true);
-
- if (swfRef.getVal() == abc.getSwf()) {
+
+ if (swfRef.getVal() == abc.getSwf()) {
hilightScript(getOpenable(), scriptNamePrintable);
return;
}
@@ -1131,12 +1251,12 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener foundStatic = new Reference<>(null);
@@ -1212,7 +1332,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener