Added: #1383 AS Debugger - debugging nested SWFs

This commit is contained in:
Jindra Petřík
2024-08-05 11:17:25 +02:00
parent c3389dbfd1
commit 84d6ad8591
45 changed files with 1409 additions and 192 deletions
@@ -176,7 +176,7 @@ public class BreakpointListDialog extends AppDialog {
}
}*/
Pattern abcPcodePattern = Pattern.compile("^#PCODE abc:(?<abc>[0-9]+),body:(?<body>[0-9]+);.*");
Matcher m = abcPcodePattern.matcher(breakpoint.scriptName);
Matcher m = abcPcodePattern.matcher(breakpoint.scriptName);
if (m.matches()) {
int abcIndex = Integer.parseInt(m.group("abc"));
int bodyIndex = Integer.parseInt(m.group("body"));
@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.gui;
import com.jpexs.debugger.flash.messages.in.InBreakAtExt;
import com.jpexs.decompiler.flash.SWF;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -43,6 +44,7 @@ public class DebugStackPanel extends JPanel {
private int depth = 0;
private String[] swfHashes = new String[0];
private int[] classIndices = new int[0];
private int[] methodIndices = new int[0];
private int[] traitIndices = new int[0];
@@ -90,9 +92,11 @@ public class DebugStackPanel extends JPanel {
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
int row = stackTable.rowAtPoint(e.getPoint());
if (row >= 0) {
String scriptName = (String) stackTable.getModel().getValueAt(row, 0);
int line = (int) (Integer) stackTable.getModel().getValueAt(row, 1);
Main.getMainFrame().getPanel().gotoScriptLine(Main.getMainFrame().getPanel().getCurrentSwf(),
String swfHash = swfHashes[row];
String scriptName = (String) stackTable.getModel().getValueAt(row, 1);
int line = (int) (Integer) stackTable.getModel().getValueAt(row, 2);
SWF swf = swfHash == null ? Main.getRunningSWF() : Main.getSwfByHash(swfHash);
Main.getMainFrame().getPanel().gotoScriptLine(swf,
scriptName, line, classIndices[row], traitIndices[row], methodIndices[row], Main.isDebugPCode());
Main.getDebugHandler().setDepth(row);
}
@@ -117,15 +121,24 @@ public class DebugStackPanel extends JPanel {
return;
}
active = true;
Object[][] data = new Object[info.files.size()][3];
Object[][] data = new Object[info.files.size()][4];
String[] newSwfHashes = new String[info.files.size()];
int[] newClassIndices = new int[info.files.size()];
int[] newMethodIndices = new int[info.files.size()];
int[] newTraitIndices = new int[info.files.size()];
for (int i = 0; i < info.files.size(); i++) {
int f = info.files.get(i);
data[i][0] = Main.getDebugHandler().moduleToString(f);
data[i][1] = info.lines.get(i);
data[i][2] = info.stacks.get(i);
String moduleName = Main.getDebugHandler().moduleToString(f);
String swfHash = null;
if (moduleName.contains(":")) {
swfHash = moduleName.substring(0, moduleName.indexOf(":"));
moduleName = moduleName.substring(moduleName.indexOf(":") + 1);
}
newSwfHashes[i] = swfHash;
data[i][0] = swfHash == null ? "unknown" : Main.getSwfByHash(swfHash).toString();
data[i][1] = moduleName;
data[i][2] = info.lines.get(i);
data[i][3] = info.stacks.get(i);
Integer newClassIndex = Main.getDebugHandler().moduleToClassIndex(f);
newClassIndices[i] = newClassIndex == null ? -1 : newClassIndex;
Integer newMethodIndex = Main.getDebugHandler().moduleToMethodIndex(f);
@@ -135,6 +148,7 @@ public class DebugStackPanel extends JPanel {
}
DefaultTableModel tm = new DefaultTableModel(data, new Object[]{
AppStrings.translate("callStack.header.swf"),
AppStrings.translate("callStack.header.file"),
AppStrings.translate("callStack.header.line"),
AppStrings.translate("stack.header.item")
@@ -146,6 +160,7 @@ public class DebugStackPanel extends JPanel {
};
stackTable.setModel(tm);
this.swfHashes = newSwfHashes;
this.classIndices = newClassIndices;
this.methodIndices = newMethodIndices;
this.traitIndices = newTraitIndices;
@@ -57,6 +57,7 @@ import com.jpexs.decompiler.graph.DottedChain;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -85,7 +86,13 @@ public class DebuggerHandler implements DebugConnectionListener {
private Map<Integer, String> modulePaths = new HashMap<>();
private Map<Integer, Integer> moduleToSwfIndex = new HashMap<>();
//Marks swfIndices that are fully loaded - at least one break was on it (including onloaded break)
private Set<Integer> swfIndicesCommited = new HashSet<>();
private Map<Integer,String> swfIndicesNewToSwfHash = new HashMap<>();
private Map<String, Integer> scriptToModule = new HashMap<>();
private Map<Integer, Integer> moduleToTraitIndex = new HashMap<>();
@@ -110,7 +117,7 @@ public class DebuggerHandler implements DebugConnectionListener {
private List<Integer> stackLines = new ArrayList<>();
private SWF debuggedSwf = null;
private List<SWF> debuggedSwfs = new ArrayList<>();
public static class ActionScriptException extends Exception {
@@ -130,12 +137,13 @@ public class DebuggerHandler implements DebugConnectionListener {
}
}
public void setDebuggedSwf(SWF debuggedSwf) {
this.debuggedSwf = debuggedSwf;
public void setMainDebuggedSwf(SWF debuggedSwf) {
debuggedSwfs.clear();
//debuggedSwfs.add(debuggedSwf);
}
public SWF getDebuggedSwf() {
return debuggedSwf;
public List<SWF> getDebuggedSwfs() {
return debuggedSwfs;
}
public int getBreakIp() {
@@ -538,11 +546,11 @@ public class DebuggerHandler implements DebugConnectionListener {
return frame;
}
public synchronized int moduleIdOf(String pack) {
if (scriptToModule.containsKey(pack)) {
return scriptToModule.get(pack);
public synchronized int moduleIdOf(String packWithHash) {
if (!scriptToModule.containsKey(packWithHash)) {
return -1;
}
return -1;
return scriptToModule.get(packWithHash);
}
public boolean isPaused() {
@@ -569,35 +577,38 @@ public class DebuggerHandler implements DebugConnectionListener {
}
commands = null;
synchronized (this) {
if (confirmedPointMap.containsKey(debuggedSwf)) {
for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) {
if (!toAddBPointMap.containsKey(debuggedSwf)) {
toAddBPointMap.put(debuggedSwf, new HashMap<>());
for (SWF debuggedSwf : debuggedSwfs) {
if (confirmedPointMap.containsKey(debuggedSwf)) {
for (String scriptName : confirmedPointMap.get(debuggedSwf).keySet()) {
if (!toAddBPointMap.containsKey(debuggedSwf)) {
toAddBPointMap.put(debuggedSwf, new HashMap<>());
}
if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(confirmedPointMap.get(debuggedSwf).get(scriptName));
}
if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(confirmedPointMap.get(debuggedSwf).get(scriptName));
confirmedPointMap.get(debuggedSwf).clear();
}
confirmedPointMap.get(debuggedSwf).clear();
}
if (invalidBreakPointMap.containsKey(debuggedSwf)) {
for (String scriptName : invalidBreakPointMap.get(debuggedSwf).keySet()) {
if (!toAddBPointMap.containsKey(debuggedSwf)) {
toAddBPointMap.put(debuggedSwf, new HashMap<>());
if (invalidBreakPointMap.containsKey(debuggedSwf)) {
for (String scriptName : invalidBreakPointMap.get(debuggedSwf).keySet()) {
if (!toAddBPointMap.containsKey(debuggedSwf)) {
toAddBPointMap.put(debuggedSwf, new HashMap<>());
}
if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(invalidBreakPointMap.get(debuggedSwf).get(scriptName));
}
if (!toAddBPointMap.get(debuggedSwf).containsKey(scriptName)) {
toAddBPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
toAddBPointMap.get(debuggedSwf).get(scriptName).addAll(invalidBreakPointMap.get(debuggedSwf).get(scriptName));
invalidBreakPointMap.get(debuggedSwf).clear();
}
invalidBreakPointMap.get(debuggedSwf).clear();
}
}
for (ConnectionListener l : clisteners) {
l.disconnected();
}
debuggedSwfs.clear();
}
public synchronized boolean isConnected() {
@@ -628,7 +639,9 @@ public class DebuggerHandler implements DebugConnectionListener {
@Override
public void connected(DebuggerConnection con) {
makeBreakPointsUnconfirmed(debuggedSwf);
/*for (SWF debuggedSwf : debuggedSwfs) {
makeBreakPointsUnconfirmed(debuggedSwf);
}*/
Main.startWork(AppStrings.translate("work.debugging"), null);
@@ -661,13 +674,15 @@ public class DebuggerHandler implements DebugConnectionListener {
});
swfs.clear();
swfIndicesCommited.clear();
swfIndicesNewToSwfHash.clear();
Map<Integer, String> moduleNames = new HashMap<>();
final Pattern patAS3 = Pattern.compile("^(.*);(.*);(.*)\\.as$");
final Pattern patAS3PCode = Pattern.compile("^#PCODE abc:([0-9]+),script:([0-9]+),class:(-?[0-9]+),trait:(-?[0-9]+),method:([0-9]+),body:([0-9]+);(.*)$");
final Pattern patAS3PCode = Pattern.compile("^(?<hash>[0-9a-z_]+):#PCODE abc:(?<abc>[0-9]+),script:(?<script>[0-9]+),class:(?<class>-?[0-9]+),trait:(?<trait>-?[0-9]+),method:(?<method>[0-9]+),body:(?<body>[0-9]+);(.*)$");
boolean isAS3 = (Main.getMainFrame().getPanel().getCurrentSwf().isAS3());
boolean isAS3 = Main.getRunningSWF().isAS3();
try {
con.addMessageListener(new DebugMessageListener<InErrorException>() {
@@ -687,39 +702,69 @@ public class DebuggerHandler implements DebugConnectionListener {
}
});
modulePaths = new HashMap<>();
scriptToModule = new HashMap<>();
modulePaths.clear();
scriptToModule.clear();
moduleNames.clear();
moduleToClassIndex.clear();
moduleToTraitIndex.clear();
moduleToMethodIndex.clear();
moduleToSwfIndex.clear();
con.addMessageListener(new DebugMessageListener<InScript>() {
@Override
public void message(InScript sc) {
moduleNames.put(sc.module, sc.name);
moduleToSwfIndex.put(sc.module, sc.swfIndex);
int file = sc.module;
String name = sc.name;
synchronized (DebuggerHandler.this) {
moduleNames.put(sc.module, sc.name);
int file = sc.module;
String name = sc.name;
int swfIndex = sc.swfIndex;
name = name.replaceAll("\\[(invalid_utf8=[0-9]+)\\]", "{$1}");
name = name.replaceAll("\\[(invalid_utf8=[0-9]+)\\]", "{$1}");
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Received script added - index {0} name: {1}", new Object[]{file, name});
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Received script added - index {0} name: {1}", new Object[]{file, name});
Matcher m;
if ((m = patAS3.matcher(name)).matches()) {
String clsNameWithSuffix = m.group(3).replace("{{semicolon}}", ";");
String pkg = m.group(2).replace("{{semicolon}}", ";").replace("\\", ".");
m = patAS3PCode.matcher(name);
if (m.matches()) {
moduleToClassIndex.put(file, Integer.parseInt(m.group(3)));
moduleToTraitIndex.put(file, Integer.parseInt(m.group(4)));
moduleToMethodIndex.put(file, Integer.parseInt(m.group(5)));
name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString();
name = "#PCODE abc:" + m.group(1) + ",body:" + m.group(6) + ";" + name;
String swfHash = "main";
Matcher m;
if ((m = patAS3.matcher(name)).matches()) {
String clsNameWithSuffix = m.group(3).replace("{{semicolon}}", ";");
String pkg = m.group(2).replace("{{semicolon}}", ";").replace("\\", ".");
m = patAS3PCode.matcher(name);
if (m.matches()) {
moduleToClassIndex.put(file, Integer.parseInt(m.group("class")));
moduleToTraitIndex.put(file, Integer.parseInt(m.group("trait")));
moduleToMethodIndex.put(file, Integer.parseInt(m.group("method")));
name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toString();
swfHash = m.group("hash");
name = swfHash + ":" + "#PCODE abc:" + m.group("abc") + ",body:" + m.group("body") + ";" + name;
} else {
if (pkg.contains(":")) {
swfHash = pkg.substring(0, pkg.indexOf(":"));
pkg = pkg.substring(pkg.indexOf(":") + 1);
}
name = swfHash + ":" + DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toPrintableString(con.isAS3);
}
} else {
name = DottedChain.parseWithSuffix(pkg).addWithSuffix(clsNameWithSuffix).toPrintableString(con.isAS3);
if (name.contains(":")) {
swfHash = name.substring(0, name.indexOf(":"));
}
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Script added - index {0} name: {1}", new Object[]{file, name});
modulePaths.put(file, name);
scriptToModule.put(name, file);
moduleToSwfIndex.put(file, swfIndex);
if (swfIndex > debuggedSwfs.size() - 1) {
SWF swf = Main.getSwfByHash(swfHash);
if (swf == null) {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.WARNING, "SWF with hash {0} not found", swfHash);
} else {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "adding {0} to debugSwfs", swfIndex);
debuggedSwfs.add(swf);
}
} else {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Swf index already commited");
}
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "Script added - index {0} name: {1}", new Object[]{file, name});
modulePaths.put(file, name);
scriptToModule.put(name, file);
con.dropMessage(sc);
}
});
@@ -781,6 +826,7 @@ public class DebuggerHandler implements DebugConnectionListener {
synchronized (this) {
for (int i = 0; i < isb.files.size(); i++) {
String sname = moduleNames.get(isb.files.get(i));
SWF debuggedSwf = debuggedSwfs.get(moduleToSwfIndex.get(isb.files.get(i)));
if (!confirmedPointMap.containsKey(debuggedSwf)) {
confirmedPointMap.put(debuggedSwf, new HashMap<>());
}
@@ -826,22 +872,37 @@ public class DebuggerHandler implements DebugConnectionListener {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINE, "paused");
}
try {
//ignore single InSetBreakpoint, otherwise setting breakpoints later won't work
con.getMessage(InSetBreakpoint.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
breakInfo = con.getMessage(InBreakAtExt.class, DebuggerConnection.PREF_RESPONSE_TIMEOUT);
breakReason = con.sendMessageWithTimeout(new OutGetBreakReason(con), InBreakReason.class);
int reasonInt = breakReason == null ? 0 : breakReason.reason;
String newBreakScriptName = "unknown";
String userBreakScriptName = "unknown";
if (modulePaths.containsKey(message.file)) {
newBreakScriptName = modulePaths.get(message.file);
userBreakScriptName = newBreakScriptName;
if (newBreakScriptName.contains(":")) {
String swfHash = newBreakScriptName.substring(0, newBreakScriptName.indexOf(":"));
SWF swf = Main.getSwfByHash(swfHash);
userBreakScriptName = swf.toString() + ": " + newBreakScriptName.substring(newBreakScriptName.indexOf(":") + 1);
}
} else if (reasonInt != InBreakReason.REASON_SCRIPT_LOADED) {
Logger.getLogger(DebuggerCommands.class.getName()).log(Level.SEVERE, "Invalid file: {0}", message.file);
//return;
}
for (int i = 0; i < debuggedSwfs.size(); i++) {
swfIndicesCommited.add(i);
}
final String[] reasonNames = new String[]{"unknown", "breakpoint", "watch", "fault", "stopRequest", "step", "halt", "scriptLoaded"};
String reason = reasonInt < reasonNames.length ? reasonNames[reasonInt] : reasonNames[0];
@@ -869,8 +930,8 @@ public class DebuggerHandler implements DebugConnectionListener {
return;
}
Main.startWork(AppStrings.translate("work.halted"), null);
} else {
Main.startWork(AppStrings.translate("work.breakat") + newBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null);
} else {
Main.startWork(AppStrings.translate("work.breakat") + userBreakScriptName + ":" + message.line + " " + AppStrings.translate("debug.break.reason." + reason), null);
}
depth = 0;
refreshFrame();
@@ -933,53 +994,79 @@ public class DebuggerHandler implements DebugConnectionListener {
return;
}
synchronized (this) {
if (toRemoveBPointMap.containsKey(debuggedSwf)) {
for (String scriptName : toRemoveBPointMap.get(debuggedSwf).keySet()) {
int file = moduleIdOf(scriptName);
if (file > -1) {
for (int line : toRemoveBPointMap.get(debuggedSwf).get(scriptName)) {
if (isBreakpointConfirmed(debuggedSwf, scriptName, line)) {
commands.removeBreakPoint(file, line);
confirmedPointMap.get(debuggedSwf).get(scriptName).remove(line);
if (confirmedPointMap.get(debuggedSwf).get(scriptName).isEmpty()) {
confirmedPointMap.get(debuggedSwf).remove(scriptName);
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending breakpoints of {0} swfs", debuggedSwfs.size());
for (int swfIndex = 0; swfIndex < debuggedSwfs.size(); swfIndex++) {
if (!swfIndicesCommited.contains(swfIndex)) {
continue;
}
SWF debuggedSwf = debuggedSwfs.get(swfIndex);
String hash = Main.getSwfHash(debuggedSwf);
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending breakpoints of ", hash);
if (toRemoveBPointMap.containsKey(debuggedSwf)) {
for (String scriptName : toRemoveBPointMap.get(debuggedSwf).keySet()) {
if (scriptName.startsWith("#PCODE") != Main.isDebugPCode()) {
continue;
}
int file = moduleIdOf(hash + ":" + scriptName);
if (file > -1) {
for (int line : toRemoveBPointMap.get(debuggedSwf).get(scriptName)) {
if (isBreakpointConfirmed(debuggedSwf, scriptName, line)) {
commands.removeBreakPoint(file, line);
confirmedPointMap.get(debuggedSwf).get(scriptName).remove(line);
if (confirmedPointMap.get(debuggedSwf).get(scriptName).isEmpty()) {
confirmedPointMap.get(debuggedSwf).remove(scriptName);
}
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} removed", new Object[]{scriptName, line});
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} removed", new Object[]{scriptName, line});
}
}
toRemoveBPointMap.get(debuggedSwf).clear();
if (toRemoveBPointMap.get(debuggedSwf).isEmpty()) {
toRemoveBPointMap.remove(debuggedSwf);
}
}
toRemoveBPointMap.clear();
}
if (toAddBPointMap.containsKey(debuggedSwf)) {
for (String scriptName : toAddBPointMap.get(debuggedSwf).keySet()) {
int file = moduleIdOf(scriptName);
if (file > -1) {
for (int line : toAddBPointMap.get(debuggedSwf).get(scriptName)) {
if (commands.addBreakPoint(file, line)) {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{scriptName, line});
if (!confirmedPointMap.containsKey(debuggedSwf)) {
confirmedPointMap.put(debuggedSwf, new HashMap<>());
if (toAddBPointMap.containsKey(debuggedSwf)) {
for (String scriptName : toAddBPointMap.get(debuggedSwf).keySet()) {
if (scriptName.startsWith("#PCODE") != Main.isDebugPCode()) {
continue;
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "searching for module of {0}:{1}", new Object[]{hash, scriptName});
int file = moduleIdOf(hash + ":" + scriptName);
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "module = {0}", file);
if (file > -1) {
for (int line : toAddBPointMap.get(debuggedSwf).get(scriptName)) {
if (commands.addBreakPoint(file, line)) {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} submitted successfully", new Object[]{scriptName, line});
if (!confirmedPointMap.containsKey(debuggedSwf)) {
confirmedPointMap.put(debuggedSwf, new HashMap<>());
}
if (!confirmedPointMap.get(debuggedSwf).containsKey(scriptName)) {
confirmedPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
confirmedPointMap.get(debuggedSwf).get(scriptName).add(line);
} else {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} unable to submit", new Object[]{scriptName, line});
markBreakPointInvalid(debuggedSwf, scriptName, line);
}
if (!confirmedPointMap.get(debuggedSwf).containsKey(scriptName)) {
confirmedPointMap.get(debuggedSwf).put(scriptName, new TreeSet<>());
}
confirmedPointMap.get(debuggedSwf).get(scriptName).add(line);
} else {
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.INFO, "Breakpoint {0}:{1} unable to submit", new Object[]{scriptName, line});
}
} else {
for (int line : toAddBPointMap.get(debuggedSwf).get(scriptName)) {
markBreakPointInvalid(debuggedSwf, scriptName, line);
}
}
} else {
for (int line : toAddBPointMap.get(debuggedSwf).get(scriptName)) {
markBreakPointInvalid(debuggedSwf, scriptName, line);
}
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "clearing toAddBps of {0}", hash);
toAddBPointMap.get(debuggedSwf).clear();
if (toAddBPointMap.get(debuggedSwf).isEmpty()) {
toAddBPointMap.remove(debuggedSwf);
}
}
toAddBPointMap.clear();
}
}
Logger.getLogger(DebuggerHandler.class.getName()).log(Level.FINEST, "sending bps finished");
+131 -38
View File
@@ -47,6 +47,7 @@ import com.jpexs.decompiler.flash.console.ContextMenuTools;
import com.jpexs.decompiler.flash.exporters.modes.ExeExportMode;
import com.jpexs.decompiler.flash.gfx.GfxConvertor;
import com.jpexs.decompiler.flash.gui.debugger.DebugAdapter;
import com.jpexs.decompiler.flash.gui.debugger.DebugLoaderDataModified;
import com.jpexs.decompiler.flash.gui.debugger.DebuggerTools;
import com.jpexs.decompiler.flash.gui.pipes.FirstInstance;
import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin;
@@ -207,7 +208,15 @@ public class Main {
public static CancellableWorker swfPrepareWorker = null;
public static String currentDebuggerPackage = null;
private static SWF runningSWF = null;
private static SwfPreparation runningPreparation = null;
public static SWF getRunningSWF() {
return runningSWF;
}
public static boolean isSwfAir(Openable openable) {
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(openable.getShortPathTitle());
if (conf != null) {
@@ -250,6 +259,8 @@ public class Main {
runTempFiles.clear();
runProcess = null;
runningSWF = null;
runningPreparation = null;
}
if (mainFrame != null && mainFrame.getPanel() != null) {
mainFrame.getPanel().clearDebuggerColors();
@@ -418,13 +429,13 @@ public class Main {
private static interface SwfPreparation {
public SWF prepare(SWF swf) throws InterruptedException;
public SWF prepare(SWF swf, String swfHash) throws InterruptedException;
}
private static class SwfRunPrepare implements SwfPreparation {
@Override
public SWF prepare(SWF swf) throws InterruptedException {
public SWF prepare(SWF swf, String swfHash) throws InterruptedException {
if (Configuration.autoOpenLoadedSWFs.get()) {
if (!DebuggerTools.hasDebugger(swf)) {
DebuggerTools.switchDebugger(swf);
@@ -444,7 +455,7 @@ public class Main {
}
@Override
public SWF prepare(SWF instrSWF) throws InterruptedException {
public SWF prepare(SWF instrSWF, String swfHash) throws InterruptedException {
EventListener prepEventListner = new EventListener() {
@Override
public void handleExportingEvent(String type, int index, int count, Object data) {
@@ -464,7 +475,7 @@ public class Main {
instrSWF.addEventListener(prepEventListner);
try {
File fTempFile = new File(instrSWF.getFile());
instrSWF.enableDebugging(true, new File("."), true, doPCode);
instrSWF.enableDebugging(true, new File("."), true, doPCode, swfHash);
FileOutputStream fos = new FileOutputStream(fTempFile);
instrSWF.saveTo(fos);
fos.close();
@@ -502,9 +513,9 @@ public class Main {
}
});
if (doPCode) {
instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true));
instrSWF.generatePCodeSwdFile(swdFile, getPackBreakPoints(true, swfHash), swfHash);
} else {
instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true));
instrSWF.generateSwdFile(swdFile, getPackBreakPoints(true, swfHash), swfHash);
}
}
}
@@ -524,7 +535,7 @@ public class Main {
}
}
private static void prepareSwf(SwfPreparation prep, File toPrepareFile, File origFile, File tempFilesDir, List<File> tempFiles) throws IOException, InterruptedException {
private static void prepareSwf(String swfHash, SwfPreparation prep, File toPrepareFile, File origFile, File tempFilesDir, List<File> tempFiles) throws IOException, InterruptedException {
SWF instrSWF = null;
try (FileInputStream fis = new FileInputStream(toPrepareFile)) {
instrSWF = new SWF(fis, toPrepareFile.getAbsolutePath(), origFile == null ? "unknown.swf" : origFile.getName(), false);
@@ -539,18 +550,18 @@ public class Main {
String url = it.getUrl();
File importedFile = new File(origFile.getParentFile(), url);
if (importedFile.exists()) {
File newTempFile = createTempFileInDir(tempFilesDir, "~ffdec_run_import_", ".swf");
File newTempFile = createTempFileInDir(tempFilesDir, "~ffdec_run_import_", ".swf");
it.setUrl("./" + newTempFile.getName());
byte[] impData = Helper.readFile(importedFile.getAbsolutePath());
byte[] impData = Helper.readFile(importedFile.getAbsolutePath());
Helper.writeFile(newTempFile.getAbsolutePath(), impData);
tempFiles.add(newTempFile);
prepareSwf(prep, newTempFile, importedFile, tempFilesDir, tempFiles);
prepareSwf("imported_" + md5(impData),prep, newTempFile, importedFile, tempFilesDir, tempFiles);
}
}
}
}
if (prep != null) {
instrSWF = prep.prepare(instrSWF);
instrSWF = prep.prepare(instrSWF, swfHash);
}
try (FileOutputStream fos = new FileOutputStream(toPrepareFile)) {
instrSWF.saveTo(fos);
@@ -605,7 +616,7 @@ public class Main {
File tempRunDir = swf.getFile() == null ? null : new File(swf.getFile()).getParentFile();
File tempFile;
List<File> tempFiles = new ArrayList<>();
List<File> tempFiles = new ArrayList<>();
try {
tempFile = createTempFileInDir(tempRunDir, "~ffdec_run_", ".swf");
@@ -617,7 +628,7 @@ public class Main {
swfToSave.saveTo(fos, false, swf.gfx);
}
prepareSwf(new SwfRunPrepare(), tempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
prepareSwf("main",new SwfRunPrepare(), tempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
} catch (IOException ex) {
return;
@@ -629,6 +640,8 @@ public class Main {
runTempFile = tempFile;
runTempFiles = tempFiles;
runProcessDebug = false;
runningSWF = swf;
runningPreparation = new SwfRunPrepare();
}
runPlayer(AppStrings.translate("work.running"), playerLocation, tempFile.getAbsolutePath(), flashVars);
}
@@ -645,7 +658,7 @@ public class Main {
if (swf == null) {
return;
}
debugHandler.setDebuggedSwf(swf);
debugHandler.setMainDebuggedSwf(swf);
File tempRunDir = swf.getFile() == null ? null : new File(swf.getFile()).getParentFile();
File tempFile = null;
@@ -669,7 +682,7 @@ public class Main {
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fTempFile))) {
swfToSave.saveTo(fos, false, swf.gfx);
}
prepareSwf(new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
prepareSwf("main", new SwfDebugPrepare(doPCode), fTempFile, swf.getFile() == null ? null : new File(swf.getFile()), tempRunDir, tempFiles);
return null;
}
@@ -690,6 +703,8 @@ public class Main {
runProcessDebug = true;
runProcessDebugPCode = doPCode;
runTempFiles = tempFiles;
runningSWF = swf;
runningPreparation = new SwfDebugPrepare(doPCode);
}
Main.stopWork();
Main.startDebugger();
@@ -751,8 +766,8 @@ public class Main {
}
}
public static synchronized Map<String, Set<Integer>> getPackBreakPoints(boolean validOnly) {
SWF swf = getMainFrame().getPanel().getCurrentSwf();
public static synchronized Map<String, Set<Integer>> getPackBreakPoints(boolean validOnly, String swfHash) {
SWF swf = Main.getSwfByHash(swfHash);
return getDebugHandler().getAllBreakPoints(swf, validOnly);
}
@@ -1515,7 +1530,7 @@ public class Main {
private final OpenableSourceInfo[] sourceInfos;
private final Runnable executeAfterOpen;
private final OpenableOpened executeAfterOpen;
private final int[] reloadIndices;
@@ -1527,11 +1542,11 @@ public class Main {
this(sourceInfo, null, reloadIndex);
}
public OpenFileWorker(OpenableSourceInfo sourceInfo, Runnable executeAfterOpen) {
public OpenFileWorker(OpenableSourceInfo sourceInfo, OpenableOpened executeAfterOpen) {
this(sourceInfo, executeAfterOpen, -1);
}
public OpenFileWorker(OpenableSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) {
public OpenFileWorker(OpenableSourceInfo sourceInfo, OpenableOpened executeAfterOpen, int reloadIndex) {
this.sourceInfos = new OpenableSourceInfo[]{sourceInfo};
this.executeAfterOpen = executeAfterOpen;
this.reloadIndices = new int[]{reloadIndex};
@@ -1541,11 +1556,11 @@ public class Main {
this(sourceInfos, null, null);
}
public OpenFileWorker(OpenableSourceInfo[] sourceInfos, Runnable executeAfterOpen) {
public OpenFileWorker(OpenableSourceInfo[] sourceInfos, OpenableOpened executeAfterOpen) {
this(sourceInfos, executeAfterOpen, null);
}
public OpenFileWorker(OpenableSourceInfo[] sourceInfos, Runnable executeAfterOpen, int[] reloadIndices) {
public OpenFileWorker(OpenableSourceInfo[] sourceInfos, OpenableOpened executeAfterOpen, int[] reloadIndices) {
this.sourceInfos = sourceInfos;
this.executeAfterOpen = executeAfterOpen;
int[] indices = new int[sourceInfos.length];
@@ -1693,8 +1708,8 @@ public class Main {
mainFrame.getPanel().updateMissingNeededCharacters();
}
if (executeAfterOpen != null) {
executeAfterOpen.run();
if (executeAfterOpen != null && fopenable != null) {
executeAfterOpen.opened(fopenable);
}
});
@@ -1841,13 +1856,13 @@ public class Main {
return openFile(new OpenableSourceInfo[]{sourceInfo});
}
public static OpenFileResult openFile(OpenableSourceInfo sourceInfo, Runnable executeAfterOpen) {
public static OpenFileResult openFile(OpenableSourceInfo sourceInfo, OpenableOpened executeAfterOpen) {
View.checkAccess();
return openFile(new OpenableSourceInfo[]{sourceInfo}, executeAfterOpen);
}
public static OpenFileResult openFile(OpenableSourceInfo sourceInfo, Runnable executeAfterOpen, int reloadIndex) {
public static OpenFileResult openFile(OpenableSourceInfo sourceInfo, OpenableOpened executeAfterOpen, int reloadIndex) {
View.checkAccess();
return openFile(new OpenableSourceInfo[]{sourceInfo}, executeAfterOpen, new int[]{reloadIndex});
@@ -1859,13 +1874,13 @@ public class Main {
return openFile(newSourceInfos, null);
}
public static OpenFileResult openFile(OpenableSourceInfo[] newSourceInfos, Runnable executeAfterOpen) {
public static OpenFileResult openFile(OpenableSourceInfo[] newSourceInfos, OpenableOpened executeAfterOpen) {
View.checkAccess();
return openFile(newSourceInfos, executeAfterOpen, null);
}
public static OpenFileResult openFile(OpenableSourceInfo[] newSourceInfos, Runnable executeAfterOpen, int[] reloadIndices) {
public static OpenFileResult openFile(OpenableSourceInfo[] newSourceInfos, OpenableOpened executeAfterOpen, int[] reloadIndices) {
View.checkAccess();
if (mainFrame != null && !Configuration.openMultipleFiles.get()) {
@@ -2467,31 +2482,61 @@ public class Main {
watcherWorker.execute();
}
DebuggerTools.initDebugger().addMessageListener(new DebugAdapter() {
DebuggerTools.initDebugger().addMessageListener(new DebugAdapter() {
@Override
public void onLoaderBytes(String clientId, byte[] data) {
String hash = md5(data);
public boolean isModifyBytesSupported() {
return true;
}
@Override
public void onLoaderModifyBytes(String clientId, byte[] inputData, String url, DebugLoaderDataModified modifiedListener) {
final String hash = md5(inputData);
OpenableOpened afterLoad = new OpenableOpened() {
@Override
public void opened(Openable openable) {
try {
SWF mainSWF = getRunningSWF();
File tempRunDir = mainSWF.getFile() == null ? null : new File(mainSWF.getFile()).getParentFile();
File tempFile = createTempFileInDir(tempRunDir, "~ffdec_loader_", ".swf");
try(FileOutputStream fos = new FileOutputStream(tempFile)) {
fos.write(inputData);
}
prepareSwf("loaded_" + hash, runningPreparation, tempFile, mainSWF.getFile() == null ? null : new File(mainSWF.getFile()), tempRunDir, runTempFiles);
byte outputData[] = Helper.readFileEx(tempFile.getAbsolutePath());
tempFile.delete();
modifiedListener.dataModified(outputData);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
String t = sl.get(s).getTitleOrShortFileName();
Openable op = sl.get(s);
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hash)) { //this one is already opened
afterLoad.opened(op);
return;
}
}
}
SWF swf = Main.getMainFrame().getPanel().getCurrentSwf();
SWF swf = Main.getRunningSWF();
String title = swf == null ? "?" : swf.getTitleOrShortFileName();
final String titleWithHash = title + ":" + hash;
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
OpenableSourceInfo osi = new OpenableSourceInfo(new ReReadableInputStream(new ByteArrayInputStream(data)), null, titleWithHash);
openFile(osi);
OpenableSourceInfo osi = new OpenableSourceInfo(new ReReadableInputStream(new ByteArrayInputStream(inputData)), null, titleWithHash);
openFile(osi, afterLoad);
}
});
}
@@ -2511,7 +2556,14 @@ public class Main {
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
mainFrame.getPanel().gotoScriptLine(getMainFrame().getPanel().getCurrentSwf(), scriptName, line, classIndex, traitIndex, methodIndex, Main.isDebugPCode());
String hash = "main";
String scriptNameNoHash = scriptName;
if (scriptName.contains(":")) {
hash = scriptName.substring(0, scriptName.indexOf(":"));
scriptNameNoHash = scriptName.substring(scriptName.indexOf(":") + 1);
}
SWF swf = Main.getSwfByHash(hash);
mainFrame.getPanel().gotoScriptLine(swf, scriptNameNoHash, line, classIndex, traitIndex, methodIndex, Main.isDebugPCode());
}
});
}
@@ -2944,7 +2996,7 @@ public class Main {
}
if (sourceInfos.length > 0) {
openingFiles = true;
openFile(sourceInfos, () -> {
openFile(sourceInfos, (Openable openable) -> {
mainFrame.getPanel().tagTree.setSelectionPathString(Configuration.lastSessionSelection.get());
mainFrame.getPanel().tagListTree.setSelectionPathString(Configuration.lastSessionTagListSelection.get());
setSessionLoaded(true);
@@ -3307,4 +3359,45 @@ public class Main {
SWF swf = getMainFrame().getPanel().getCurrentSwf();
getMainFrame().getPanel().showBreakpointlistDialog(swf);
}
public static String getSwfHash(SWF swf) {
if (swf == getRunningSWF()) {
return "main";
}
String tit = swf.getTitleOrShortFileName();
if (tit != null && tit.contains(":")) {
return "loaded_" + tit.substring(tit.lastIndexOf(":") + 1);
}
return "";
}
public static SWF getSwfByHash(String hash) {
if ("main".equals(hash)) {
SWF runningSwf = getRunningSWF();
if (runningSwf == null) {
return mainFrame.getPanel().getCurrentSwf();
}
return runningSwf;
}
if (!hash.startsWith("loaded_")) {
return null;
}
hash = hash.substring("loaded_".length());
for (OpenableList sl : Main.getMainFrame().getPanel().getSwfs()) {
for (int s = 0; s < sl.size(); s++) {
Openable op = sl.get(s);
if (!(op instanceof SWF)) {
continue;
}
String t = op.getTitleOrShortFileName();
if (t == null) {
t = "";
}
if (t.endsWith(":" + hash)) { //this one is already opened
return (SWF) op;
}
}
}
return null;
}
}
@@ -2680,7 +2680,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
});
}
});
}
}
gotoScriptName(swf, scriptName);
}
@@ -2709,30 +2709,33 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se
});
}*/
public void gotoScriptName(SWF swf, String scriptName) {
public void gotoScriptName(SWF mainSwf, String scriptNameWithSwfHash) {
View.checkAccess();
if (swf == null) {
if (mainSwf == null) {
return;
}
if (swf.isAS3()) {
String rawScriptName = scriptName;
if (mainSwf.isAS3()) {
String rawScriptName = scriptNameWithSwfHash;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring(rawScriptName.indexOf(';') + 1);
}
List<ABCContainerTag> abcList = swf.getAbcList();
if (!abcList.isEmpty()) {
ABCPanel abcPanel = getABCPanel();
abcPanel.setAbc(abcList.get(0).getABC());
abcPanel.hilightScript(swf, rawScriptName);
}
//List<ABCContainerTag> abcList = swf.getAbcList();
//abcPanel.setAbc(abcList.get(0).getABC());
//if (!abcList.isEmpty()) {
ABCPanel abcPanel = getABCPanel();
abcPanel.hilightScript(mainSwf, rawScriptName);
//}
} else {
String rawScriptName = scriptName;
String rawScriptName = scriptNameWithSwfHash;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring("#PCODE ".length());
}
Map<String, ASMSource> asms = swf.getASMs(true);
Map<String, ASMSource> asms = mainSwf.getASMs(true);
if (asms.containsKey(rawScriptName)) {
oldItem = null;
getCurrentTree().setSelectionPath(null);
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2010-2024 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.treeitems.Openable;
/**
*
* @author JPEXS
*/
public interface OpenableOpened {
public void opened(Openable openable);
}
@@ -81,6 +81,7 @@ import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.timeline.AS3Package;
import com.jpexs.decompiler.flash.treeitems.AS3ClassTreeItem;
import com.jpexs.decompiler.flash.treeitems.Openable;
import com.jpexs.decompiler.flash.treeitems.OpenableList;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
@@ -1432,6 +1433,37 @@ public class ABCPanel extends JPanel implements ItemListener, SearchListener<Scr
setVisible(true);
}
public void hilightScript(String nameIncludingSwfHash) {
if (!nameIncludingSwfHash.contains(":")) {
throw new RuntimeException("Script name should conatin swfHash");
}
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;
}
}
}
}
if (openable != null) {
hilightScript(openable, name);
}
}
/**
* Hilights specific script.
*
@@ -47,4 +47,18 @@ public class DebugAdapter implements DebugListener {
return null;
}
@Override
public void onLoaderURLInfo(String clientId, String url) {
}
@Override
public void onLoaderModifyBytes(String clientId, byte[] inputData, String url, DebugLoaderDataModified modifiedListener) {
modifiedListener.dataModified(inputData);
}
@Override
public boolean isModifyBytesSupported() {
return false;
}
}
@@ -25,6 +25,8 @@ public interface DebugListener {
public void onMessage(String clientId, String msg);
public void onLoaderURL(String clientId, String url);
public void onLoaderURLInfo(String clientId, String url);
public void onLoaderBytes(String clientId, byte[] data);
@@ -33,4 +35,8 @@ public interface DebugListener {
public void onFinish(String clientId);
public byte[] onRequestBytes(String clientId);
public void onLoaderModifyBytes(String clientId, byte[] inputData, String url, DebugLoaderDataModified modifiedListener);
public boolean isModifyBytesSupported();
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2010-2024 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui.debugger;
/**
*
* @author JPEXS
*/
public interface DebugLoaderDataModified {
public void dataModified(byte[] data);
}
@@ -48,6 +48,10 @@ public class Debugger {
public static final int MSG_DUMP_BYTEARRAY = 3;
public static final int MSG_REQUEST_BYTEARRAY = 4;
public static final int MSG_LOADER_URL_INFO = 5;
public static final int MSG_LOADER_MODIFY_BYTES = 6;
private static final Set<DebugListener> listeners = new HashSet<>();
@@ -285,6 +289,62 @@ public class Debugger {
os.flush();
logger.finer("listeners checked");
break;
case MSG_LOADER_URL_INFO:
logger.finer("reading string...");
ret = readString(is);
logger.finer("informing listeners...");
for (DebugListener l : listeners) {
l.onLoaderURLInfo(clientName, ret);
}
logger.finer("listeners informed");
break;
case MSG_LOADER_MODIFY_BYTES:
logger.finer("reading url(string)...");
String url = readString(is);
logger.finer("reading bytes...");
byte[] inputBytes = readBytes(is);
logger.finer("checking listeners for data...");
boolean modifyDataFound = false;
for (DebugListener l : listeners) {
if (l.isModifyBytesSupported()) {
l.onLoaderModifyBytes(clientName, inputBytes, url, new DebugLoaderDataModified() {
@Override
public void dataModified(byte[] data) {
if (data != null) {
logger.finer("got modified data");
logger.log(Level.FINER, "writing data.length = {0}", data.length);
try {
writeBytes(os, data);
os.flush();
} catch (IOException ex) {
Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
}
logger.finer("data written");
} else {
logger.finer("got empty modified data, writing original array");
try {
writeBytes(os, inputBytes);
} catch (IOException ex) {
Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
}
logger.finer("data written");
}
}
});
modifyDataFound = true;
break;
}
}
if (!modifyDataFound) {
logger.finer("listener not found, writing original array");
writeBytes(os, inputBytes);
logger.finer("data written");
}
os.flush();
logger.finer("listeners checked");
break;
}
}
}
@@ -137,15 +137,26 @@ public class DebuggableEditorPane extends LineMarkedEditorPane implements BreakP
}
int ip = Main.getIp(breakPointScriptName);
String ipPath = Main.getIpClass();
if (ip > 0 && ipPath != null && ipPath.equals(breakPointScriptName)) {
String ipHash = "main";
if (ipPath != null && ipPath.contains(":")) {
ipHash = ipPath.substring(0, ipPath.indexOf(":"));
ipPath = ipPath.substring(ipPath.indexOf(":") + 1);
}
String myhash = Main.getSwfHash(Main.getMainFrame().getPanel().getCurrentSwf());
if (ip > 0 && ipPath != null && ipHash.equals(myhash) && ipPath.equals(breakPointScriptName)) {
addColorMarker(ip + firstLineOffset(), IP_MARKER);
}
List<Integer> stackLines = Main.getStackLines();
List<String> stackClasses = Main.getStackClasses();
for (int i = 1; i < stackClasses.size(); i++) {
String cls = stackClasses.get(i);
String clsHash = "main";
if (cls.contains(":")) {
clsHash = cls.substring(0, cls.indexOf(":"));
cls = cls.substring(cls.indexOf(":") + 1);
}
int line = stackLines.get(i);
if (cls.equals(breakPointScriptName)) {
if (clsHash.equals(myhash) && cls.equals(breakPointScriptName)) {
addColorMarker(line + firstLineOffset(), STACK_MARKER);
}
}
@@ -1301,3 +1301,5 @@ filter.exe.wrapper = Wrapper executable file (*.exe)
filter.exe.projectorWin = Windows projector file (*.exe)
filter.exe.projectorMac = Mac Os projector file (*.dmg)
filter.exe.projectorLinux = Linux projector file
callStack.header.swf = SWF
@@ -1269,4 +1269,6 @@ menu.file.export.idea = Exportovat IDEA projekt
contextmenu.exportFla = Exportovat do FLA
export.project.select.directory = Vyberte um\u00edst\u011bn\u00ed nov\u00e9ho adres\u00e1\u0159e projektu
export.project.select.directory = Vyberte um\u00edst\u011bn\u00ed nov\u00e9ho adres\u00e1\u0159e projektu
callStack.header.swf = SWF