Merge branch 'debug-browser' into dev

This commit is contained in:
Jindra Petřík
2026-02-15 14:50:54 +01:00
21 changed files with 2084 additions and 1295 deletions
Binary file not shown.
Binary file not shown.
@@ -181,6 +181,7 @@ import com.jpexs.helpers.Helper;
import com.jpexs.helpers.ImageResizer;
import com.jpexs.helpers.ImmediateFuture;
import com.jpexs.helpers.NulStream;
import com.jpexs.helpers.PosMarkedInputStream;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.Reference;
import com.jpexs.helpers.SerializableImage;
@@ -204,6 +205,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -695,6 +697,15 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* Lock for characters synchronization
*/
private final Object charactersLock = new Object();
/**
* SHA 256 hash of original data
*/
private String hashSha256 = null;
public String getHashSha256() {
return hashSha256;
}
public UninitializedClassFieldsDetector getUninitializedClassFieldsDetector() {
return uninitializedClassFieldsDetector;
@@ -1818,9 +1829,16 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
* @param includeImported Include imported characters
* @throws IOException On I/O error
*/
public void saveTo(OutputStream os, boolean gfx, boolean includeImported) throws IOException {
public void saveTo(OutputStream os, boolean gfx, boolean includeImported) throws IOException {
checkCharset();
byte[] newUncompressedData = saveToByteArray(gfx, includeImported);
try {
hashSha256 = Helper.byteArrayToHex(MessageDigest.getInstance("SHA-256").digest(newUncompressedData));
} catch (NoSuchAlgorithmException ex) {
//ignore
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
compress(new ByteArrayInputStream(newUncompressedData), baos, compression, lzmaProperties);
byte[] newCompressedData = baos.toByteArray();
@@ -1828,7 +1846,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
encrypt(new ByteArrayInputStream(newCompressedData), os);
} else {
os.write(newCompressedData);
}
}
}
/**
@@ -2298,7 +2316,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
public SWF(InputStream is, String file, String fileTitle, ProgressListener listener, boolean parallelRead, boolean checkOnly, boolean lazy, UrlResolver resolver, String charset, boolean allowRenameIdentifiers) throws IOException, InterruptedException {
this.file = file;
this.fileTitle = fileTitle;
this.charset = charset;
this.charset = charset;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
SWFHeader header = decompress(is, baos, true);
gfx = header.gfx;
@@ -2307,6 +2325,12 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
lzmaProperties = header.lzmaProperties;
uncompressedData = baos.toByteArray();
originalUncompressedData = uncompressedData;
try {
hashSha256 = Helper.byteArrayToHex(MessageDigest.getInstance("SHA-256").digest(uncompressedData));
} catch (NoSuchAlgorithmException ex) {
//ignore
}
SWFInputStream sis = new SWFInputStream(this, uncompressedData);
dumpInfo = new DumpInfoSwfNode(this, "rootswf", "", null, 0, 0);
@@ -6445,5 +6469,5 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
@Override
public RECT getRectWithFilters() {
return getRect();
}
}
}
@@ -583,7 +583,8 @@ public final class AbcIndexing {
*/
public void rebuildPkgToObjectsNameMap() {
pkgToObjectsName.clear();
for (ClassDef cd : classes.keySet()) {
Set<ClassDef> cs = new LinkedHashSet<>(classes.keySet());
for (ClassDef cd : cs) {
if (!(cd.type instanceof TypeItem)) {
continue;
}
@@ -592,7 +593,8 @@ public final class AbcIndexing {
}
pkgToObjectsName.get(cd.pkg).add(((TypeItem) cd.type).fullTypeName.getLast());
}
for (PropertyNsDef nsdef : scriptProperties.keySet()) {
Set<PropertyNsDef> nss = new LinkedHashSet<>(scriptProperties.keySet());
for (PropertyNsDef nsdef : nss) {
if (!pkgToObjectsName.containsKey(nsdef.ns)) {
pkgToObjectsName.put(nsdef.ns, new LinkedHashSet<>());
}
@@ -197,16 +197,16 @@ public class BreakpointListDialog extends AppDialog {
defaultTableModel.addColumn(translate("breakpoint.line"));
defaultTableModel.addColumn(translate("breakpoint.status"));
Map<String, Set<Integer>> breakpoints = Main.getDebugHandler().getAllBreakPoints(swf, false);
Map<String, Set<Integer>> breakpoints = Main.getDebugHandler().getAllSessionsBreakPoints(swf);
List<Breakpoint> newBreakpointList = new ArrayList<>();
for (String scriptName : breakpoints.keySet()) {
for (int line : breakpoints.get(scriptName)) {
newBreakpointList.add(new Breakpoint(scriptName, line));
String status = "unknown";
if (Main.getDebugHandler().isBreakpointInvalid(swf, scriptName, line)) {
if (Main.getCurrentDebugSession().isBreakpointInvalid(swf, scriptName, line)) {
status = "invalid";
} else if (Main.getDebugHandler().isBreakpointConfirmed(swf, scriptName, line)) {
} else if (Main.getCurrentDebugSession().isBreakpointConfirmed(swf, scriptName, line)) {
status = "confirmed";
}
defaultTableModel.addRow(new Object[]{scriptName, line, translate("breakpoint.status." + status)});
@@ -36,6 +36,7 @@ import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -89,6 +90,8 @@ public class DebugPanel extends JPanel {
private boolean loading = false;
public ABCPanel.VariablesTableModel localsTable;
private WeakReference<DebuggerSession> currentSessionRef = null;
public static enum SelectedTab {
@@ -140,7 +143,7 @@ public class DebugPanel extends JPanel {
}
private void logAdd(String message) {
private void logAdd(DebuggerSession session, String message) {
boolean wasEmpty = logLength == 0;
String add = message + "\r\n";
logLength += add.length();
@@ -151,7 +154,7 @@ public class DebugPanel extends JPanel {
//ignore
}
if (wasEmpty) {
refresh();
refresh(session);
}
}
@@ -177,6 +180,15 @@ public class DebugPanel extends JPanel {
}
private void dopop(MouseEvent e) {
if (currentSessionRef == null) {
return;
}
DebuggerSession session = currentSessionRef.get();
if (session == null) {
return;
}
if (debugLocalsTable.getSelectedRow() == -1) {
return;
}
@@ -241,8 +253,8 @@ public class DebugPanel extends JPanel {
}*/
//Variant using comma separated bytes, pretty fast
try {
Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
String dataStr = (String) Main.getDebugHandler().callMethod(debugConnectionClass, "readCommaSeparatedFromByteArray", Arrays.asList(v)).variables.get(0).value;
Variable debugConnectionClass = session.getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).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];
for (int i = 0; i < parts.length; i++) {
@@ -313,9 +325,9 @@ public class DebugPanel extends JPanel {
splitter = ",";
}
String dataStr = sb.toString();
Variable debugConnectionClass = Main.getDebugHandler().getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
Variable debugConnectionClass = session.getVariable(0, Main.currentDebuggerPackage + "::DebugConnection", false, false).parent;
try {
Main.getDebugHandler().callMethod(debugConnectionClass, "writeCommaSeparatedToByteArray", Arrays.asList(dataStr, v));
session.callMethod(debugConnectionClass, "writeCommaSeparatedToByteArray", Arrays.asList(dataStr, v));
} catch (DebuggerHandler.ActionScriptException ex) {
Logger.getLogger(DebugPanel.class.getName()).log(Level.SEVERE, "Error exporting ByteArray", ex);
}
@@ -334,19 +346,19 @@ public class DebugPanel extends JPanel {
JMenu addWatchMenu = new JMenu(AppStrings.translate("debug.watch.add").replace("%name%", v.name));
JMenuItem watchReadMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.read"));
watchReadMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(v, watchParentId, true, false)) {
if (!Main.addWatch(session, v, watchParentId, true, false)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
});
JMenuItem watchWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.write"));
watchWriteMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(v, watchParentId, false, true)) {
if (!Main.addWatch(session, v, watchParentId, false, true)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
});
JMenuItem watchReadWriteMenuItem = new JMenuItem(AppStrings.translate("debug.watch.add.readwrite"));
watchReadWriteMenuItem.addActionListener((ActionEvent e1) -> {
if (!Main.addWatch(v, watchParentId, true, true)) {
if (!Main.addWatch(session, v, watchParentId, true, true)) {
ViewMessages.showMessageDialog(DebugPanel.this, AppStrings.translate("error.debug.watch.add"), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
});
@@ -376,41 +388,41 @@ public class DebugPanel extends JPanel {
Main.getDebugHandler().addTraceListener(new DebuggerHandler.TraceListener() {
@Override
public void trace(String... val) {
public void trace(DebuggerSession session, String... val) {
for (String s : val) {
logAdd("trace: " + s);
logAdd(session, "trace: " + s);
}
}
});
Main.getDebugHandler().addErrorListener(new DebuggerHandler.ErrorListener() {
@Override
public void errorException(String message, Variable thrownVar) {
logAdd("unhandled exception: " + message);
public void errorException(DebuggerSession session, String message, Variable thrownVar) {
logAdd(session, "unhandled exception: " + message);
selectedTab = tabTypes.get(tabTypes.size() - 1);
refresh();
refresh(session);
}
});
Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
}
@Override
public void disconnected() {
refresh();
public void disconnected(DebuggerSession session) {
refresh(session);
}
});
Main.getDebugHandler().addFrameChangeListener(frameChangeListener = new DebuggerHandler.FrameChangeListener() {
@Override
public void frameChanged() {
public void frameChanged(DebuggerSession session) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
refresh();
refresh(session);
}
});
}
@@ -419,17 +431,17 @@ public class DebugPanel extends JPanel {
Main.getDebugHandler().addBreakListener(breakListener = new DebuggerHandler.BreakListener() {
@Override
public void doContinue() {
public void doContinue(DebuggerSession session) {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
refresh();
refresh(session);
}
});
}
@Override
public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
}
});
@@ -484,8 +496,9 @@ public class DebugPanel extends JPanel {
}
return v.getMembers(this);
}*/
public void refresh() {
public void refresh(DebuggerSession session) {
currentSessionRef = session == null ? null : new WeakReference<>(session);
View.execInEventDispatch(new Runnable() {
@Override
@@ -495,19 +508,14 @@ public class DebugPanel extends JPanel {
SelectedTab oldSel = selectedTab;
localsTable = null;
SWF swf = Main.getMainFrame().getPanel().getCurrentSwf();
if (swf == null) {
return;
}
boolean as3 = swf.isAS3();
InFrame f = Main.getDebugHandler().getFrame();
InFrame f = session == null ? null : session.getFrame();
if (f != null) {
List<Variable> locals = new ArrayList<>();
Map<String, Long> placedObjects = Main.getDebugHandler().getPlacedObjects();
Map<String, Long> placedObjects = session.getPlacedObjects();
for (String poName : placedObjects.keySet()) {
String realName = poName;
if ("/".equals(realName)) {
@@ -515,7 +523,7 @@ public class DebugPanel extends JPanel {
} else if (realName.startsWith("/")) {
continue;
}
Variable placedVar = Main.getDebugHandler().getVariable(0, realName, false, false).parent;
Variable placedVar = session.getVariable(0, realName, false, false).parent;
if (placedVar != null) {
locals.add(placedVar);
}
@@ -540,26 +548,26 @@ public class DebugPanel extends JPanel {
TreeModelListener refreshListener = new TreeModelListener() {
@Override
public void treeNodesChanged(TreeModelEvent e) {
Main.getDebugHandler().refreshFrame();
refresh();
session.refreshFrame();
refresh(session);
}
@Override
public void treeNodesInserted(TreeModelEvent e) {
Main.getDebugHandler().refreshFrame();
refresh();
session.refreshFrame();
refresh(session);
}
@Override
public void treeNodesRemoved(TreeModelEvent e) {
Main.getDebugHandler().refreshFrame();
refresh();
session.refreshFrame();
refresh(session);
}
@Override
public void treeStructureChanged(TreeModelEvent e) {
Main.getDebugHandler().refreshFrame();
refresh();
session.refreshFrame();
refresh(session);
}
};
debugLocalsTable.getTreeTableModel().addTreeModelListener(refreshListener);
@@ -569,7 +577,7 @@ public class DebugPanel extends JPanel {
debugLocalsTable.setTreeModel(new ABCPanel.VariablesTableModel(debugLocalsTable, new ArrayList<>()));
debugScopeTable.setTreeModel(new ABCPanel.VariablesTableModel(debugScopeTable, new ArrayList<>()));
}
InConstantPool cpool = Main.getDebugHandler().getConstantPool();
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++) {
@@ -635,7 +643,7 @@ public class DebugPanel extends JPanel {
public void actionPerformed(ActionEvent e) {
traceLogTextarea.setText("");
logLength = 0;
refresh();
refresh(session);
}
});
JPanel butPanel = new JPanel(new FlowLayout());
@@ -23,6 +23,7 @@ import java.awt.Component;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.ref.WeakReference;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
@@ -46,35 +47,40 @@ public class DebugStackPanel extends JPanel {
private int[] classIndices = new int[0];
private int[] methodIndices = new int[0];
private int[] traitIndices = new int[0];
private WeakReference<DebuggerSession> currentSessionRef = null;
public DebugStackPanel() {
stackTable = new JTable();
Main.getDebugHandler().addFrameChangeListener(new DebuggerHandler.FrameChangeListener() {
@Override
public void frameChanged() {
depth = Main.getDebugHandler().getDepth();
refresh();
public void frameChanged(DebuggerSession session) {
if (session == null) {
refresh(null);
return;
}
depth = session.getDepth();
refresh(session);
}
});
Main.getDebugHandler().addBreakListener(new DebuggerHandler.BreakListener() {
@Override
public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
}
@Override
public void doContinue() {
public void doContinue(DebuggerSession session) {
clear();
}
});
Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
}
@Override
public void disconnected() {
public void disconnected(DebuggerSession session) {
clear();
}
});
@@ -93,10 +99,16 @@ public class DebugStackPanel extends JPanel {
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);
SWF swf = swfHash == null ? Main.getRunningSWF() : Main.findOpenedSwfByHash(swfHash);
Main.getMainFrame().getPanel().gotoScriptLine(swf,
scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode());
Main.getDebugHandler().setDepth(row);
DebuggerSession session = null;
if (currentSessionRef != null) {
session = currentSessionRef.get();
}
if (session != null) {
session.setDepth(row);
}
}
}
}
@@ -112,8 +124,12 @@ public class DebugStackPanel extends JPanel {
return active;
}
public void refresh() {
InBreakAtExt info = Main.getDebugHandler().getBreakInfo();
public void refresh(DebuggerSession session) {
if (session == null) {
clear();
return;
}
InBreakAtExt info = session.getBreakInfo();
if (info == null) {
clear();
return;
@@ -126,22 +142,22 @@ public class DebugStackPanel extends JPanel {
int[] newTraitIndices = new int[info.files.size()];
for (int i = 0; i < info.files.size(); i++) {
int f = info.files.get(i);
String moduleName = Main.getDebugHandler().moduleToString(f);
String moduleName = session.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][0] = swfHash == null ? "unknown" : Main.findOpenedSwfByHash(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);
Integer newClassIndex = session.moduleToClassIndex(f);
newClassIndices[i] = newClassIndex == null ? -1 : newClassIndex;
Integer newMethodIndex = Main.getDebugHandler().moduleToMethodIndex(f);
Integer newMethodIndex = session.moduleToMethodIndex(f);
newMethodIndices[i] = newMethodIndex == null ? -1 : newMethodIndex;
Integer newTraitIndex = Main.getDebugHandler().moduleToTraitIndex(f);
Integer newTraitIndex = session.moduleToTraitIndex(f);
;
newTraitIndices[i] = newTraitIndex == null ? -1 : newTraitIndex;
}
@@ -178,12 +194,15 @@ public class DebugStackPanel extends JPanel {
}
};
stackTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
stackTable.getColumnModel().getColumn(2).setCellRenderer(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();
}
});
currentSessionRef = new WeakReference<>(session);
}
public int getDepth() {
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1175,6 +1175,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
setMenuEnabled("/file/start/run", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/debug", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/debugpcode", swfSelected && !isRunningOrDebugging);
setMenuEnabled("/file/start/debuglisten", !isDebugRunning);
setMenuEnabled("/file/start/stop", isRunningOrDebugging);
setMenuEnabled("/debugging/debug/stop", isRunningOrDebugging); //same as previous
@@ -1298,6 +1299,7 @@ public abstract class MainFrameMenu implements MenuBuilder {
addMenuItem("/file/start/stop", translate("menu.file.start.stop"), "stop32", this::stopActionPerformed, PRIORITY_TOP, null, true, null, false);
addMenuItem("/file/start/debug", translate("menu.file.start.debug"), "debug32", this::debugActionPerformed, PRIORITY_MEDIUM, null, true, new HotKey("CTRL+F5"), false);
addMenuItem("/file/start/debugpcode", translate("menu.file.start.debugpcode"), "debug32", this::debugPCodeActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
addMenuItem("/file/start/debuglisten", translate("menu.file.start.debuglisten"), "listen32", this::debugListenActionPerformed, PRIORITY_MEDIUM, null, true, null, false);
finishMenu("/file/start");
addMenuItem("/file/view", translate("menu.view"), null, null, 0, null, false, null, false);
@@ -1736,6 +1738,11 @@ public abstract class MainFrameMenu implements MenuBuilder {
Main.runDebug((SWF) openable, false);
return true;
}
public boolean debugListenActionPerformed(ActionEvent evt) {
Main.startDebugListening();
return true;
}
public boolean debugPCodeActionPerformed(ActionEvent evt) {
Main.runDebug((SWF) openable, true);
@@ -1749,11 +1756,11 @@ public abstract class MainFrameMenu implements MenuBuilder {
public boolean pauseActionPerformed(ActionEvent evt) {
try {
DebuggerCommands cmd = Main.getDebugHandler().getCommands();
DebuggerCommands cmd = Main.getCurrentDebugSession().getCommands();
//TODO
} catch (IOException ex) {
Main.getDebugHandler().disconnect();
Main.getCurrentDebugSession().disconnect();
//ignore
}
return true;
@@ -1763,13 +1770,13 @@ public abstract class MainFrameMenu implements MenuBuilder {
try {
DebuggerCommands cmd = Main.getDebugHandler().getCommands();
DebuggerCommands cmd = Main.getCurrentDebugSession().getCommands();
mainFrame.getPanel().clearDebuggerColors();
Main.startWork(AppStrings.translate("work.debugging") + "...", null);
cmd.stepOver();
} catch (IOException ex) {
Main.getDebugHandler().disconnect();
Main.getCurrentDebugSession().disconnect();
//ignore
}
return true;
@@ -1777,13 +1784,13 @@ public abstract class MainFrameMenu implements MenuBuilder {
public boolean stepIntoActionPerformed(ActionEvent evt) {
try {
DebuggerCommands cmd = Main.getDebugHandler().getCommands();
DebuggerCommands cmd = Main.getCurrentDebugSession().getCommands();
mainFrame.getPanel().clearDebuggerColors();
Main.startWork(AppStrings.translate("work.debugging") + "...", null);
cmd.stepInto();
} catch (IOException ex) {
Main.getDebugHandler().disconnect();
Main.getCurrentDebugSession().disconnect();
//ignore
}
@@ -1792,12 +1799,12 @@ public abstract class MainFrameMenu implements MenuBuilder {
public boolean stepOutActionPerformed(ActionEvent evt) {
try {
DebuggerCommands cmd = Main.getDebugHandler().getCommands();
DebuggerCommands cmd = Main.getCurrentDebugSession().getCommands();
mainFrame.getPanel().clearDebuggerColors();
Main.startWork(AppStrings.translate("work.debugging") + "...", null);
cmd.stepOut();
} catch (IOException ex) {
Main.getDebugHandler().disconnect();
Main.getCurrentDebugSession().disconnect();
//ignore
}
@@ -1806,12 +1813,12 @@ public abstract class MainFrameMenu implements MenuBuilder {
public boolean continueActionPerformed(ActionEvent evt) {
try {
DebuggerCommands cmd = Main.getDebugHandler().getCommands();
DebuggerCommands cmd = Main.getCurrentDebugSession().getCommands();
mainFrame.getPanel().clearDebuggerColors();
Main.startWork(AppStrings.translate("work.debugging") + "...", null);
cmd.sendContinue();
} catch (IOException ex) {
Main.getDebugHandler().disconnect();
Main.getCurrentDebugSession().disconnect();
//ignore
}
@@ -143,16 +143,16 @@ public final class MainFrameRibbon extends AppRibbonFrame {
boolean first = true;
for (OpenableList swf : panel.getSwfs()) {
if (!first) {
sb.append(File.pathSeparator);
sbt.append(File.pathSeparator);
}
first = false;
String file = swf.sourceInfo.getFile();
if (file != null) {
if (!first) {
sb.append(File.pathSeparator);
sbt.append(File.pathSeparator);
}
sb.append(file);
String t = swf.sourceInfo.getFileTitle();
sbt.append(t == null ? "" : t);
first = false;
}
}
@@ -451,6 +451,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private boolean loadingScrollPosEnabled = true;
private static final DataFlavor TREE_FILE_FLAVOR = new DataFlavor(TreeFileFlavor.class, "TreeFile");
private boolean editingStatusSet = false;
public synchronized void setLoadingScrollPosEnabled(boolean loadingScrollPosEnabled) {
this.loadingScrollPosEnabled = loadingScrollPosEnabled;
@@ -972,11 +974,15 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
public void setEditingStatus() {
editingStatusSet = true;
statusPanel.setStatus(translate(Configuration.autoSaveTagModifications.get() ? "status.editing.autosave" : "status.editing"));
}
public void clearEditingStatus() {
statusPanel.setStatus("");
if (editingStatusSet) {
statusPanel.setStatus("");
editingStatusSet = false;
}
}
public void setWorkStatus(String s, CancellableWorker worker) {
@@ -1116,7 +1122,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
debugStackPanel = new DebugStackPanel();
Main.getDebugHandler().addBreakListener(new DebuggerHandler.BreakListener() {
@Override
public void breakAt(String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
public void breakAt(DebuggerSession session, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
@@ -1126,23 +1132,25 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
}
@Override
public void doContinue() {
public void doContinue(DebuggerSession session) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
showDetail(DETAILCARDEMPTYPANEL);
if (Main.getDebugHandler().getNumberOfPausedSessions() == 0) {
showDetail(DETAILCARDEMPTYPANEL);
}
}
});
}
});
Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
}
@Override
public void disconnected() {
public void disconnected(DebuggerSession session) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
@@ -1628,6 +1636,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private void updateUi(final Openable openable) {
View.checkAccess();
Main.updateSession();
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
@@ -1646,7 +1655,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
if (!abcFound) {
getABCPanel().setAbc(abcList.get(0).getABC());
}
}
}
}
mainMenu.updateComponents(openable);
@@ -5766,7 +5775,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
private void valueChanged(Object source, TreePath selectedPath) {
TreeItem treeItem = selectedPath == null ? null : (TreeItem) selectedPath.getLastPathComponent();
Main.updateSession();
if (treeItem == null) {
updateUi(null);
reload(false);
@@ -6360,7 +6370,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
if (openable instanceof SWF) {
SwfSpecificCustomConfiguration swfCustomConf = Configuration.getOrCreateSwfSpecificCustomConfiguration(openable.getShortPathTitle());
SWF swf = (SWF) openable;
Map<String, Set<Integer>> breakpoints = Main.getDebugHandler().getAllBreakPoints(swf, false);
Map<String, Set<Integer>> breakpoints = Main.getDebugHandler().getAllSessionsBreakPoints(swf);
List<String> breakpointList = new ArrayList<>();
for (String scriptName : breakpoints.keySet()) {
for (int line : breakpoints.get(scriptName)) {
@@ -7053,4 +7063,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
public EasyPanel getEasyPanel() {
return easyPanel;
}
public void showDebugStackFrame() {
showDetail(DETAILCARDDEBUGSTACKFRAME);
}
}
@@ -56,6 +56,7 @@ import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.DebugPanel;
import com.jpexs.decompiler.flash.gui.DebuggerHandler;
import com.jpexs.decompiler.flash.gui.DebuggerSession;
import com.jpexs.decompiler.flash.gui.FasterScrollPane;
import com.jpexs.decompiler.flash.gui.HeaderLabel;
import com.jpexs.decompiler.flash.gui.Main;
@@ -387,10 +388,13 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
boolean isAS3 = (Main.getMainFrame().getPanel().getCurrentSwf().isAS3());
if (Main.getCurrentDebugSession() == null) {
return;
}
if (parentObjectId == 0 && objectId != 0L && isAS3) {
igv = Main.getDebugHandler().getVariable(objectId, "", true, useGetter);
igv = Main.getCurrentDebugSession().getVariable(objectId, "", true, useGetter);
} else {
igv = Main.getDebugHandler().getVariable(parentObjectId, var.name, true, useGetter);
igv = Main.getCurrentDebugSession().getVariable(parentObjectId, var.name, true, useGetter);
}
//current var is getter function - set it to value really got
@@ -782,7 +786,7 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
default:
return;
}
Main.getDebugHandler().setVariable(((VariableNode) node).parentObjectId, ((VariableNode) node).var.name, valType, symb.value);
Main.getCurrentDebugSession().setVariable(((VariableNode) node).parentObjectId, ((VariableNode) node).var.name, valType, symb.value);
//((VariableNode) node).refresh();
Object[] path = new Object[((VariableNode) node).path.size()];
for (int i = 0; i < path.length; i++) {
@@ -1422,13 +1426,15 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
decButtonsPan.setVisible(false);
}
@Override
public void disconnected() {
decButtonsPan.setVisible(true);
public void disconnected(DebuggerSession session) {
if (!Main.getDebugHandler().isAnySessionConnected()) {
decButtonsPan.setVisible(true);
}
}
});
@@ -1755,27 +1761,8 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
}
String swfHash = nameIncludingSwfHash.substring(nameIncludingSwfHash.indexOf(":"));
String name = nameIncludingSwfHash.substring(nameIncludingSwfHash.indexOf(":") + 1);
Openable openable = null;
if (swfHash.equals("main")) {
openable = Main.getRunningSWF();
} else if (swfHash.startsWith("loaded_")) {
String hashToSearch = swfHash.substring("loaded_".length());
loop:
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
Openable op = sl.get(s);
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hashToSearch)) { //this one is already opened
openable = op;
break loop;
}
}
}
}
Openable openable = Main.findOpenedSwfByHash(swfHash);
if (openable != null) {
hilightScript(openable, name);
}
@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.DebuggerHandler;
import com.jpexs.decompiler.flash.gui.DebuggerSession;
import com.jpexs.decompiler.flash.gui.HeaderLabel;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainPanel;
@@ -146,7 +147,7 @@ public class DetailPanel extends JPanel implements TagEditorPanel {
conListener = new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
synchronized (DetailPanel.this) {
debugRunning = true;
if (buttonsPanel != null) {
@@ -156,7 +157,10 @@ public class DetailPanel extends JPanel implements TagEditorPanel {
}
@Override
public void disconnected() {
public void disconnected(DebuggerSession session) {
if (Main.getDebugHandler().isAnySessionConnected()) {
return;
}
synchronized (DetailPanel.this) {
debugRunning = false;
@@ -43,6 +43,7 @@ import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.DebugPanel;
import com.jpexs.decompiler.flash.gui.DebuggerHandler;
import com.jpexs.decompiler.flash.gui.DebuggerSession;
import com.jpexs.decompiler.flash.gui.DocsPanel;
import com.jpexs.decompiler.flash.gui.FasterScrollPane;
import com.jpexs.decompiler.flash.gui.GraphDialog;
@@ -1065,12 +1066,15 @@ public class ActionPanel extends JPanel implements SearchListener<ScriptSearchRe
//decPanel.add(searchPanel, BorderLayout.NORTH);
Main.getDebugHandler().addConnectionListener(new DebuggerHandler.ConnectionListener() {
@Override
public void connected() {
public void connected(DebuggerSession session) {
decButtonsPan.setVisible(false);
}
@Override
public void disconnected() {
public void disconnected(DebuggerSession session) {
if (Main.getDebugHandler().isAnySessionConnected()) {
return;
}
decButtonsPan.setVisible(true);
}
});
@@ -126,7 +126,7 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
return;
}
Set<Integer> bkptLines = Main.getScriptBreakPoints(breakPointScriptName, false);
Set<Integer> bkptLines = Main.getScriptBreakPoints(breakPointScriptName);
for (int line : bkptLines) {
if (Main.isBreakPointValid(breakPointScriptName, line)) {
@@ -137,7 +137,7 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
}
int ip = Main.getIp(breakPointScriptName);
String ipPath = Main.getIpClass();
String ipHash = "main";
String ipHash = "unknown";
if (ipPath != null && ipPath.contains(":")) {
ipHash = ipPath.substring(0, ipPath.indexOf(":"));
ipPath = ipPath.substring(ipPath.indexOf(":") + 1);
@@ -150,7 +150,7 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
List<String> stackClasses = Main.getStackClasses();
for (int i = 1; i < stackClasses.size(); i++) {
String cls = stackClasses.get(i);
String clsHash = "main";
String clsHash = "unknown";
if (cls.contains(":")) {
clsHash = cls.substring(0, cls.indexOf(":"));
cls = cls.substring(cls.indexOf(":") + 1);
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1105,4 +1105,12 @@ contextmenu.normalizeFonts = Normalize fonts
#after 24.1.1
contextmenu.saveSwc = Save as Swc...
work.generating.swc = Generating Swc...
work.generating.swc = Generating Swc...
#after 25.0.0
menu.file.start.debuglisten = Debug listen...
work.debugging.listening = Listening for incoming connections...
contextmenu.prepareDebug.injectDebug = Prepare file for debugging (+ inject debug info)
contextmenu.prepareDebug.generateSwd = Prepare file for debugging (+ generate SWD)
prepareDebug.title = Hit Save to overwrite current file or select another file.
work.halted.with = Debugging of %file% started, execution halted. Add breakpoints and click Continue (F5) to resume running.
@@ -381,7 +381,11 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenuItem convertPlaceObjectTypeMenuItem;
private JMenuItem normalizeFontsMenuItem;
private JMenuItem prepareDebugInject;
private JMenuItem prepareDebugSwd;
private List<TreeItem> items = new ArrayList<>();
private static final int KIND_TAG_MOVETO = 0;
@@ -653,6 +657,17 @@ public class TagTreeContextMenu extends JPopupMenu {
addSeparator();
prepareDebugInject = new JMenuItem(mainPanel.translate("contextmenu.prepareDebug.injectDebug"));
prepareDebugInject.addActionListener(this::prepareDebugActionPerformed);
prepareDebugInject.setIcon(View.getIcon("debug16"));
add(prepareDebugInject);
prepareDebugSwd = new JMenuItem(mainPanel.translate("contextmenu.prepareDebug.generateSwd"));
prepareDebugSwd.addActionListener(this::prepareDebugActionPerformed);
prepareDebugSwd.setIcon(View.getIcon("debug16"));
add(prepareDebugSwd);
gotoDocumentClassMenuItem = new JMenuItem(mainPanel.translate("menu.tools.gotoDocumentClass"));
gotoDocumentClassMenuItem.addActionListener(this::gotoDocumentClassActionPerformed);
gotoDocumentClassMenuItem.setIcon(View.getIcon("gotomainclass16"));
@@ -1354,6 +1369,8 @@ public class TagTreeContextMenu extends JPopupMenu {
boolean hasExportableNodes = tree.hasExportableNodes();
prepareDebugInject.setVisible(false);
prepareDebugSwd.setVisible(false);
gotoDocumentClassMenuItem.setVisible(false);
setAsLinkageMenuItem.setVisible(false);
setAs3ClassLinkageMenuItem.setVisible(false);
@@ -1549,7 +1566,7 @@ public class TagTreeContextMenu extends JPopupMenu {
if ("__Packages".equals(firstPkg)) {
addAs12ClassMenuItem.setVisible(true);
}
}
}
if (firstItem instanceof ClassesListTreeModel) {
addAs3ClassMenuItem.setVisible(true);
if (firstItem.getOpenable() instanceof SWF) {
@@ -1586,6 +1603,9 @@ public class TagTreeContextMenu extends JPopupMenu {
if (firstItem instanceof SWF) {
if (((SWF) firstItem).isAS3()) {
gotoDocumentClassMenuItem.setVisible(true);
prepareDebugInject.setVisible(true);
} else {
prepareDebugSwd.setVisible(true);
}
}
@@ -3055,6 +3075,42 @@ public class TagTreeContextMenu extends JPopupMenu {
mainPanel.showGenericTag((Tag) itemr);
}
private void prepareDebugActionPerformed(ActionEvent evt) {
TreeItem item = getCurrentItem();
SWF swf = (SWF) item.getOpenable();
JFileChooser chooser = View.getFileChooserWithIcon("debug");
if (swf.getFile() != null) {
File dir = new File(swf.getFile()).getParentFile();
chooser.setCurrentDirectory(dir);
chooser.setSelectedFile(new File(swf.getFile()));
chooser.setDialogTitle(AppStrings.translate("prepareDebug.title"));
}
chooser.setFileFilter(new FileFilter() {
@Override
public boolean accept(File f) {
return f.getAbsolutePath().toLowerCase().endsWith(".swf") || f.isDirectory();
}
@Override
public String getDescription() {
return AppStrings.translate("filter.swf");
}
});
if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) {
return;
}
File selFile = Helper.fixDialogFile(chooser.getSelectedFile());
boolean doPCode = false;
List<File> tempFiles = new ArrayList<>();
try {
Main.prepareForDebug(swf, selFile, selFile.getParentFile(), tempFiles, doPCode);
} catch (IOException | InterruptedException ex) {
ViewMessages.showMessageDialog(mainPanel, ex.toString(), AppStrings.translate("error"), JOptionPane.ERROR_MESSAGE);
}
Main.stopWork();
}
private void gotoDocumentClassActionPerformed(ActionEvent evt) {
TreeItem item = getCurrentItem();
item.getOpenable();