mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 07:20:46 +00:00
Faster AS3 Debugging - export/import ByteArray variable data
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2023 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 class DebugAdapter implements DebugListener {
|
||||
|
||||
@Override
|
||||
public void onMessage(String clientId, String msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderURL(String clientId, String url) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderBytes(String clientId, byte[] data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDumpByteArray(String clientId, byte[] data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(String clientId) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] onRequestBytes(String clientId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,6 +27,10 @@ public interface DebugListener {
|
||||
public void onLoaderURL(String clientId, String url);
|
||||
|
||||
public void onLoaderBytes(String clientId, byte[] data);
|
||||
|
||||
public void onDumpByteArray(String clientId, byte[] data);
|
||||
|
||||
public void onFinish(String clientId);
|
||||
|
||||
public byte[] onRequestBytes(String clientId);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -37,8 +39,29 @@ import java.util.WeakHashMap;
|
||||
*/
|
||||
public class Debugger {
|
||||
|
||||
public static final int MSG_STRING = 0;
|
||||
|
||||
public static final int MSG_LOADER_URL = 1;
|
||||
|
||||
public static final int MSG_LOADER_BYTES = 2;
|
||||
|
||||
public static final int MSG_DUMP_BYTEARRAY = 3;
|
||||
|
||||
public static final int MSG_REQUEST_BYTEARRAY = 4;
|
||||
|
||||
|
||||
private static final Set<DebugListener> listeners = new HashSet<>();
|
||||
|
||||
private static Logger logger = Logger.getLogger(Debugger.class.getName());
|
||||
|
||||
private static boolean active = false;
|
||||
|
||||
public static boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public synchronized void addMessageListener(DebugListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
@@ -61,12 +84,7 @@ public class Debugger {
|
||||
|
||||
private final Map<String, String> parameters = new HashMap<>();
|
||||
|
||||
public static final int MSG_STRING = 0;
|
||||
|
||||
public static final int MSG_LOADER_URL = 1;
|
||||
|
||||
public static final int MSG_LOADER_BYTES = 2;
|
||||
|
||||
|
||||
public String getParameter(String name, String defValue) {
|
||||
if (parameters.containsKey(name)) {
|
||||
return parameters.get(name);
|
||||
@@ -108,6 +126,14 @@ public class Debugger {
|
||||
return type;
|
||||
}
|
||||
|
||||
private void writeBytes(OutputStream os, byte[] data) throws IOException {
|
||||
os.write((data.length >> 24) & 0xff);
|
||||
os.write((data.length >> 16) & 0xff);
|
||||
os.write((data.length >> 8) & 0xff);
|
||||
os.write(data.length & 0xff);
|
||||
os.write(data);
|
||||
}
|
||||
|
||||
private byte[] readBytes(InputStream is) throws IOException {
|
||||
int len = is.read();
|
||||
if (len == -1) {
|
||||
@@ -161,7 +187,8 @@ public class Debugger {
|
||||
@Override
|
||||
public void run() {
|
||||
String clientName = Integer.toString(id);
|
||||
try (InputStream is = s.getInputStream()) {
|
||||
try (InputStream is = s.getInputStream();
|
||||
OutputStream os = s.getOutputStream()) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
int c;
|
||||
@@ -175,11 +202,10 @@ public class Debugger {
|
||||
String ret = baos.toString("UTF-8");
|
||||
|
||||
if (ret.equals("<policy-file-request/>")) {
|
||||
try (OutputStream os = s.getOutputStream()) {
|
||||
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"" + serverPort + "\" /></cross-domain-policy>").getBytes("UTF-8"));
|
||||
}
|
||||
os.write(("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" secure=\"false\" /></cross-domain-policy>").getBytes("UTF-8"));
|
||||
} else {
|
||||
if (!ret.isEmpty()) {
|
||||
logger.log(Level.FINER, "Connected. Header: {0}", ret);
|
||||
String[] param = (ret.contains(";") ? ret.split(";") : new String[]{ret});
|
||||
for (String p : param) {
|
||||
if (p.contains("=")) {
|
||||
@@ -190,35 +216,79 @@ public class Debugger {
|
||||
parameters.put(p, "true");
|
||||
}
|
||||
}
|
||||
active = true;
|
||||
}
|
||||
boolean hasType = hasMsgType();
|
||||
logger.log(Level.FINER, "reading name...");
|
||||
String name = readString(is);
|
||||
logger.log(Level.FINER, "name = {0}", name);
|
||||
if (!name.isEmpty()) {
|
||||
clientName = name;
|
||||
}
|
||||
while (true) {
|
||||
int type = 0;
|
||||
logger.finer("reading type...");
|
||||
if (hasType) {
|
||||
type = readType(is);
|
||||
}
|
||||
logger.log(Level.FINE, "received type {0}", type);
|
||||
switch (type) {
|
||||
case MSG_STRING:
|
||||
logger.finer("reading string...");
|
||||
ret = readString(is);
|
||||
logger.finer("informing listeners...");
|
||||
for (DebugListener l : listeners) {
|
||||
l.onMessage(clientName, ret);
|
||||
}
|
||||
logger.finer("listeners informed");
|
||||
break;
|
||||
case MSG_LOADER_URL:
|
||||
logger.finer("reading string...");
|
||||
ret = readString(is);
|
||||
logger.finer("informing listeners...");
|
||||
for (DebugListener l : listeners) {
|
||||
l.onLoaderURL(clientName, ret);
|
||||
}
|
||||
logger.finer("listeners informed");
|
||||
break;
|
||||
case MSG_LOADER_BYTES:
|
||||
logger.finer("reading bytes...");
|
||||
byte[] retB = readBytes(is);
|
||||
logger.finer("informing listeners...");
|
||||
for (DebugListener l : listeners) {
|
||||
l.onLoaderBytes(clientName, retB);
|
||||
}
|
||||
logger.finer("listeners informed");
|
||||
break;
|
||||
case MSG_DUMP_BYTEARRAY:
|
||||
logger.finer("reading bytes...");
|
||||
byte[] retBa = readBytes(is);
|
||||
logger.finer("informing listeners...");
|
||||
for (DebugListener l : listeners) {
|
||||
l.onDumpByteArray(clientName, retBa);
|
||||
}
|
||||
logger.finer("listeners informed");
|
||||
break;
|
||||
case MSG_REQUEST_BYTEARRAY:
|
||||
logger.finer("checking listeners for data...");
|
||||
boolean dataFound = false;
|
||||
for (DebugListener l : listeners) {
|
||||
byte[] data = l.onRequestBytes(clientName);
|
||||
if (data != null) {
|
||||
logger.finer("found listener with data");
|
||||
logger.log(Level.FINER, "writing data.length = {0}", data.length);
|
||||
writeBytes(os, data);
|
||||
logger.finer("data written");
|
||||
dataFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dataFound) {
|
||||
logger.finer("listener not found, writing empty array");
|
||||
writeBytes(os, new byte[0]);
|
||||
}
|
||||
os.flush();
|
||||
logger.finer("listeners checked");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -233,6 +303,7 @@ public class Debugger {
|
||||
//ignore
|
||||
}
|
||||
finished = true;
|
||||
active = false;
|
||||
for (DebugListener l : listeners) {
|
||||
l.onFinish(clientName);
|
||||
}
|
||||
|
||||
@@ -46,8 +46,8 @@ public class DebuggerTools {
|
||||
|
||||
public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger";
|
||||
|
||||
private static volatile Debugger debugger;
|
||||
|
||||
private static volatile Debugger debugger;
|
||||
|
||||
private static ScriptPack getDebuggerScriptPack(SWF swf) {
|
||||
List<ABC> allAbcList = new ArrayList<>();
|
||||
for (ABCContainerTag ac : swf.getAbcList()) {
|
||||
@@ -234,6 +234,7 @@ public class DebuggerTools {
|
||||
if (Configuration.randomDebuggerPackage.get()) {
|
||||
newdebuggerpkg += ".pkg" + rhex;
|
||||
}
|
||||
swf.debuggerPackage = newdebuggerpkg;
|
||||
|
||||
//add debug ABC tags to main SWF
|
||||
for (ABCContainerTag ds : debugSWF.getAbcList()) {
|
||||
@@ -261,6 +262,46 @@ public class DebuggerTools {
|
||||
ft.useNetwork = true;
|
||||
ft.setModified(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Add call to DebugConnection.initClient("") to the document class
|
||||
/*String documentClass = swf.getDocumentClass();
|
||||
if (documentClass != null) {
|
||||
List<String> searchClassNames = new ArrayList<>();
|
||||
searchClassNames.add(documentClass);
|
||||
List<ScriptPack> documentClassPacks = swf.getScriptPacksByClassNames(searchClassNames);
|
||||
if (!documentClassPacks.isEmpty()) {
|
||||
ScriptPack documentClassPack = documentClassPacks.get(0);
|
||||
Trait publicTrait = documentClassPack.getPublicTrait();
|
||||
if (publicTrait != null) {
|
||||
if (publicTrait instanceof TraitClass) {
|
||||
TraitClass classTrait = (TraitClass) publicTrait;
|
||||
int classIndex = classTrait.class_info;
|
||||
ABC a = documentClassPack.abc;
|
||||
int cinitMethodInfo = a.class_info.get(classIndex).cinit_index;
|
||||
MethodBody body = a.findBody(cinitMethodInfo);
|
||||
AVM2Code code = body.getCode();
|
||||
int debugConnectionMultiname = a.constants.getMultinameId(
|
||||
Multiname.createQName(false, a.constants.getStringId("DebugConnection", true),
|
||||
a.constants.getNamespaceId(Namespace.KIND_PACKAGE, newdebuggerpkg, 0, true)
|
||||
), true);
|
||||
int initClientMultiname = a.constants.getMultinameId(
|
||||
Multiname.createQName(false, a.constants.getStringId("initClient", true),
|
||||
a.constants.getNamespaceId(Namespace.KIND_PACKAGE, "", 0, true)
|
||||
), true);
|
||||
code.insertInstruction(0, new AVM2Instruction(0, AVM2Instructions.GetLex, new int[] {debugConnectionMultiname}), true, body);
|
||||
code.insertInstruction(1, new AVM2Instruction(0, AVM2Instructions.PushString, new int[] {a.constants.getStringId("", true)}), true, body);
|
||||
code.insertInstruction(2, new AVM2Instruction(0, AVM2Instructions.CallPropVoid, new int[] {initClientMultiname, 1}), true, body);
|
||||
if (body.max_stack < 2) {
|
||||
body.max_stack = 2;
|
||||
}
|
||||
body.setModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Error while attaching debugger", ex);
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user