mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 06:21:16 +00:00
Added: #1383 AS Debugger - debugging nested SWFs
This commit is contained in:
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
Reference in New Issue
Block a user