diff --git a/build_common.xml b/build_common.xml index e97fccec0..a6ea1a799 100644 --- a/build_common.xml +++ b/build_common.xml @@ -17,6 +17,7 @@ + diff --git a/lib/JavactiveX.jar b/lib/JavactiveX.jar index 9e4a6b28a..d3143e889 100644 Binary files a/lib/JavactiveX.jar and b/lib/JavactiveX.jar differ diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as new file mode 100644 index 000000000..4d0008532 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugConnection.as @@ -0,0 +1,67 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.net.Socket; + import flash.utils.ByteArray; + import flash.events.Event; + import flash.display.Sprite; + + public class DebugConnection { + + private static var s:Socket; + private static var q = []; + private static var first:Boolean = true; + private static var inited:Boolean = false; + private static var name:String; + + + + private static function sendQueue(){ + var qo = q; + q = []; + for each(var m in qo){ + writeMsg(m); + } + } + + private static function writeString(msg){ + var b:ByteArray = new ByteArray(); + b.writeUTFBytes(msg); + s.writeByte(b.length); + s.writeBytes(b,0,b.length); + } + + public static function initClient(sname){ + if(inited){ + return; + } + name = sname; + inited = true; + s = new Socket(); + s.addEventListener(Event.CONNECT, function(){ + sendQueue(); + }); + var port:int = 0; + port = 123456; + s.connect("localhost",port); + inited = true; + } + + public static function writeMsg(msg){ + if(!inited){ + initClient(""); + } + if(s.connected){ + if(first){ + s.writeByte(0); + writeString(name); + first = false; + } + writeString(msg); + }else{ + q.push(msg); + } + } + + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as new file mode 100644 index 000000000..0ac6bac75 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/DebugMain.as @@ -0,0 +1,17 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.display.MovieClip; + + + public class DebugMain extends MovieClip { + + + public function DebugMain() { + debugAlert("test alert"); + debugConsole("test console"); + debugSocket("test proxy"); + debugTrace("test trace"); + } + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as new file mode 100644 index 000000000..7a35251ec --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugAlert.as @@ -0,0 +1,11 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.external.ExternalInterface; + + public function debugAlert(msg):*{ + if(ExternalInterface.available) + ExternalInterface.call("alert",""+msg); + return msg; + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as new file mode 100644 index 000000000..121ab0867 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugConsole.as @@ -0,0 +1,11 @@ +package com.jpexs.decompiler.flash.debugger { + + import flash.external.ExternalInterface; + + public function debugConsole(msg):*{ + if(ExternalInterface.available) + ExternalInterface.call("console.log",""+msg); + return msg; + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugInit.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugInit.as new file mode 100644 index 000000000..699f8e7c9 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugInit.as @@ -0,0 +1,8 @@ +package com.jpexs.decompiler.flash.debugger { + + + public function debugInit(name){ + DebugConnection.iniClient(name); + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as new file mode 100644 index 000000000..0f93d6137 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugSocket.as @@ -0,0 +1,13 @@ +package com.jpexs.decompiler.flash.debugger { + import flash.system.Capabilities; + + public function debugSocket(msg):*{ + //only on webpages or activex + if(Capabilities.playerType == 'PlugIn' + || Capabilities.playerType == 'ActiveX'){ + DebugConnection.writeMsg(msg); + } + return msg; + } + +} diff --git a/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as new file mode 100644 index 000000000..58ee09b11 --- /dev/null +++ b/libsrc/debugswf/com/jpexs/decompiler/flash/debugger/debugTrace.as @@ -0,0 +1,9 @@ +package com.jpexs.decompiler.flash.debugger { + + + public function debugTrace(name){ + debugConsole(name); + debugSocket(name); + } + +} diff --git a/libsrc/debugswf/debug/DOMDocument.xml b/libsrc/debugswf/debug/DOMDocument.xml new file mode 100644 index 000000000..607f86475 --- /dev/null +++ b/libsrc/debugswf/debug/DOMDocument.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/debugswf/debug/META-INF/metadata.xml b/libsrc/debugswf/debug/META-INF/metadata.xml new file mode 100644 index 000000000..1bd11073f --- /dev/null +++ b/libsrc/debugswf/debug/META-INF/metadata.xml @@ -0,0 +1,73 @@ + + + + + Adobe Flash Professional CS6 - build 537 + 2014-10-26T15:59:21+01:00 + 2014-10-27T08:16:09+01:00 + 2014-10-27T08:16:09+01:00 + + + application/vnd.adobe.fla + + + xmp.iid:A3850720A95DE411873EA2B016962F64 + xmp.did:1476A545885CE411B13FACEEFCD7D43C + xmp.did:1476A545885CE411B13FACEEFCD7D43C + + + + created + xmp.iid:1476A545885CE411B13FACEEFCD7D43C + 2014-10-26T15:59:21+01:00 + Adobe Flash Professional CS6 - build 537 + + + created + xmp.iid:8C96C4B4325DE411B13FACEEFCD7D43C + 2014-10-26T15:59:21+01:00 + Adobe Flash Professional CS6 - build 537 + + + created + xmp.iid:8E96C4B4325DE411B13FACEEFCD7D43C + 2014-10-26T15:59:21+01:00 + Adobe Flash Professional CS6 - build 537 + + + created + xmp.iid:A3850720A95DE411873EA2B016962F64 + 2014-10-26T15:59:21+01:00 + Adobe Flash Professional CS6 - build 537 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libsrc/debugswf/debug/MobileSettings.xml b/libsrc/debugswf/debug/MobileSettings.xml new file mode 100644 index 000000000..e69de29bb diff --git a/libsrc/debugswf/debug/PublishSettings.xml b/libsrc/debugswf/debug/PublishSettings.xml new file mode 100644 index 000000000..dce804882 --- /dev/null +++ b/libsrc/debugswf/debug/PublishSettings.xml @@ -0,0 +1,206 @@ + + + + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + ../../src/com/jpexs/decompiler/flash/gui/debugger/debug.swf + debug.exe + debug.app + debug.html + debug.gif + debug.jpg + debug.png + debug.mov + debug.smil + debug.swc + + + 0 + 11,4,0,0;11,3,0,0;11,2,0,0;11,1,0,0;10,3,0,0;10,2,153,0;10,1,52,0;9,0,124,0;8,0,24,0;7,0,14,0;6,0,79,0;5,0,58,0;4,0,32,0;3,0,8,0;2,0,1,12;1,0,0,1; + 1 + 1 + debug_content.html + debug_alternate.html + 0 + + 550 + 400 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 4 + 0 + 0 + 1 + 0 + C:\Users\Jindra\AppData\Local\Adobe\Flash CS6\en_US\Configuration\HTML\Default.html + 1 + + + + + 0 + 0 + 0 + 80 + 0 + 0 + 7 + 0 + 7 + 0 + 17 + FlashPlayer11.4 + 3 + 1 + + . + CONFIG::FLASH_AUTHORING="true"; + 0 + + 1 + 0 + 1 + 0 + 0 + 0 + 0 + com.jpexs.decompiler.flash.debugger.DebugMain + 2 + 4 + 4096 + AS3 + 1 + 1 + 0 + 15 + 1 + 0 + 4102 + rsl + wrap + $(AppConfig)/ActionScript 3.0/rsls/loader_animation.swf + + + $(AppConfig)/ActionScript 3.0/libs + merge + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + rsl + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + $(AppConfig)/ActionScript 3.0/libs/11.0/textLayout.swc + + http://fpdownload.adobe.com/pub/swz/tlf/2.0.0.232/textLayout_2.0.0.232.swz + http://fpdownload.adobe.com/pub/swz/crossdomain.xml + textLayout_2.0.0.232.swz + + + + + 550 + 400 + 0 + 4718592 + 0 + 80 + 1 + + + 1 + 0 + 1 + 0 + 0 + 100000 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + + + 550 + 400 + 0 + 1 + 1 + 0 + 1 + 0 + 1 + 0 + 0 + + 128 + + + 255 + + + + 550 + 400 + 1 + 0 + 0 + 1 + 0 + 0 + 1 + + + + 24-bit with Alpha + 255 + + + + 550 + 400 + 1 + 0 + + + 00000000 + 0 + 0 + 0 + 0 + 1 + + + \ No newline at end of file diff --git a/libsrc/debugswf/debug/bin/SymDepend.cache b/libsrc/debugswf/debug/bin/SymDepend.cache new file mode 100644 index 000000000..fa0e29a10 Binary files /dev/null and b/libsrc/debugswf/debug/bin/SymDepend.cache differ diff --git a/libsrc/debugswf/debug/debug.xfl b/libsrc/debugswf/debug/debug.xfl new file mode 100644 index 000000000..860a820ec --- /dev/null +++ b/libsrc/debugswf/debug/debug.xfl @@ -0,0 +1 @@ +PROXY-CS5 \ No newline at end of file diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java index 4f48a317a..be86d89ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ScriptPack.java @@ -34,6 +34,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -197,4 +198,35 @@ public class ScriptPack implements TreeElementItem { } return file; } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + Objects.hashCode(this.abc); + hash = 79 * hash + this.scriptIndex; + hash = 79 * hash + Objects.hashCode(this.path); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ScriptPack other = (ScriptPack) obj; + if (!Objects.equals(this.abc, other.abc)) { + return false; + } + if (this.scriptIndex != other.scriptIndex) { + return false; + } + if (!Objects.equals(this.path, other.path)) { + return false; + } + return true; + } + } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index ab2edc50b..9580c3200 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -340,6 +340,14 @@ public class Configuration { public static final ConfigurationItem pluginPath = null; + + @ConfigurationDefaultInt(55556) + @ConfigurationCategory("script") + public static final ConfigurationItem debuggerPort = null; + + @ConfigurationDefaultBoolean(true) + public static final ConfigurationItem displayDebuggerInfo = null; + private enum OSId { WINDOWS, OSX, UNIX diff --git a/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java new file mode 100644 index 000000000..789ae59c6 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/DebugLogDialog.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2014 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 . + */ + +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.Debugger; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.ListModel; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +/** + * + * @author JPEXS + */ +public class DebugLogDialog extends AppDialog implements ActionListener { + + private JTextArea logTextArea = new JTextArea(); + private final String ACTION_CLOSE = "CLOSE"; + private final String ACTION_CLEAR = "CLEAR"; + private Debugger debug; + + public DebugLogDialog(Debugger debug) { + setSize(800, 600); + this.debug = debug; + setTitle(translate("dialog.title")); + logTextArea.setBackground(Color.white); + logTextArea.setEditable(false); + JScrollPane spane = new JScrollPane(logTextArea); + spane.setPreferredSize(new Dimension(800,500)); + + debug.addMessageListener(new DebugListener() { + + @Override + public void onMessage(String clientId, String msg) { + log(translate("msg.header").replace("%clientid%", clientId)+msg); + } + + @Override + public void onFinish(String clientId) { + + } + }); + Container cnt = getContentPane(); + cnt.setLayout(new BorderLayout()); + cnt.add(spane,BorderLayout.CENTER); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton clearButton = new JButton(translate("button.clear")); + clearButton.setActionCommand(ACTION_CLEAR); + clearButton.addActionListener(this); + + JButton closeButton = new JButton(translate("button.close")); + closeButton.setActionCommand(ACTION_CLOSE); + closeButton.addActionListener(this); + + buttonsPanel.add(clearButton); + buttonsPanel.add(closeButton); + cnt.add(buttonsPanel,BorderLayout.SOUTH); + View.setWindowIcon(this); + View.centerScreen(this); + } + + public void log(String msg){ + Document d = logTextArea.getDocument(); + try { + d.insertString(d.getLength(), msg+"\r\n", null); + } catch (BadLocationException ex) { + //ignore + } + } + + @Override + public void actionPerformed(ActionEvent e) { + switch(e.getActionCommand()){ + case ACTION_CLEAR: + logTextArea.setText(""); + break; + case ACTION_CLOSE: + setVisible(false); + break; + } + } + +} diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 6788d89d2..13b4b0888 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -23,12 +23,22 @@ import com.jpexs.decompiler.flash.SWFBundle; import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.SearchMode; import com.jpexs.decompiler.flash.Version; +import com.jpexs.decompiler.flash.abc.ABC; +import com.jpexs.decompiler.flash.abc.ClassPath; +import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; +import com.jpexs.decompiler.flash.abc.types.Multiname; +import com.jpexs.decompiler.flash.abc.types.Namespace; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.console.CommandLineArgumentParser; import com.jpexs.decompiler.flash.console.ContextMenuTools; +import com.jpexs.decompiler.flash.gui.debugger.DebugListener; +import com.jpexs.decompiler.flash.gui.debugger.Debugger; import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; +import com.jpexs.decompiler.flash.helpers.collections.MyEntry; +import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.helpers.Cache; @@ -70,6 +80,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Map.Entry; +import java.util.Random; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; import java.util.logging.Formatter; @@ -106,6 +117,39 @@ public class Main { public static LoadFromMemoryFrame loadFromMemoryFrame; public static LoadFromCacheFrame loadFromCacheFrame; private static final Logger logger = Logger.getLogger(Main.class.getName()); + private static Debugger debugger; + public static DebugLogDialog debugDialog; + public static final String DEBUGGER_PACKAGE = "com.jpexs.decompiler.flash.debugger"; + + private static ABCContainerTag getDebuggerABCTag(SWF swf) { + for (ABCContainerTag ac : swf.abcList) { + ABC a = ac.getABC(); + for (MyEntry m : a.getScriptPacks()) { + if (isDebuggerClass(m.getKey().packageStr, null)) { + return ac; + } + } + } + return null; + } + + private static String getDebuggerPackage(SWF swf) { + ABCContainerTag ac = getDebuggerABCTag(swf); + if (ac == null) { + return null; + } + ABC a = ac.getABC(); + for (MyEntry m : a.getScriptPacks()) { + if (isDebuggerClass(m.getKey().packageStr, null)) { + return m.getKey().packageStr; + } + } + return null; + } + + public static boolean hasDebugger(SWF swf) { + return getDebuggerABCTag(swf) != null; + } public static void ensureMainFrame() { if (mainFrame == null) { @@ -448,6 +492,10 @@ public class Main { } public static void reloadApp() { + if (debugDialog != null) { + debugDialog.setVisible(false); + debugDialog = null; + } if (loadingDialog != null) { loadingDialog.setVisible(false); loadingDialog = null; @@ -878,7 +926,7 @@ public class Main { * @throws IOException */ public static void main(String[] args) throws IOException { - + String pluginPath = Configuration.pluginPath.get(); if (pluginPath != null && !pluginPath.isEmpty()) { try { @@ -1030,6 +1078,124 @@ public class Main { (new AdvancedSettingsDialog()).setVisible(true); } + private static boolean isDebuggerClass(String tested, String cls) { + if (tested == null) { + return false; + } + if (cls == null) { + cls = ""; + } else { + cls = "\\." + Pattern.quote(cls); + } + return tested.matches(Pattern.quote(DEBUGGER_PACKAGE) + "\\.pkg[a-f0-9]+" + cls); + } + + private static String byteArrayToHex(byte[] a) { + StringBuilder sb = new StringBuilder(a.length * 2); + for (byte b : a) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } + + public static void replaceTraceCalls(String fname) { + SWF swf = getMainFrame().getPanel().getCurrentSwf(); + if (hasDebugger(swf)) { + String debuggerPkg = getDebuggerPackage(swf); + //change trace to fname + for (ABCContainerTag ct : swf.abcList) { + ABC a = ct.getABC(); + for (int i = 1; i < a.constants.constant_multiname.size(); i++) { + Multiname m = a.constants.constant_multiname.get(i); + if ("trace".equals(m.getNameWithNamespace(a.constants, true))) { + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId(debuggerPkg, true)), 0, true); + m.name_index = a.constants.getStringId(fname, true); + ((Tag) ct).setModified(true); + } + } + } + } + } + + public static void switchDebugger() { + int port = Configuration.debuggerPort.get(); + SWF swf = getMainFrame().getPanel().getCurrentSwf(); + ABCContainerTag found = getDebuggerABCTag(swf); + if (found != null) { + swf.tags.remove((Tag) found); + swf.abcList.remove(found); + + //Change all debugger calls to normal trace + for (ABCContainerTag ct : swf.abcList) { + ABC a = ct.getABC(); + for (int i = 1; i < a.constants.constant_multiname.size(); i++) { + Multiname m = a.constants.constant_multiname.get(i); + if (isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugTrace") + || isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugAlert") + || isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugSocket") + || isDebuggerClass(m.getNameWithNamespace(a.constants, true), "debugConsole")) { + m.name_index = a.constants.getStringId("trace", true); + m.namespace_index = a.constants.getNamespaceId(new Namespace(Namespace.KIND_PACKAGE, a.constants.getStringId("", true)), 0, true); + ((Tag) ct).setModified(true); + } + } + } + } else { + Random rnd = new Random(); + byte rb[] = new byte[16]; + rnd.nextBytes(rb); + String rhex = byteArrayToHex(rb); + try { + //load debug swf + SWF debugSWF = new SWF(Main.class.getClassLoader().getResourceAsStream("com/jpexs/decompiler/flash/gui/debugger/debug.swf"), false); + + ABCContainerTag firstAbc = swf.abcList.get(0); + String newdebuggerpkg = DEBUGGER_PACKAGE + ".pkg" + rhex; + //add debug ABC tags to main SWF + for (ABCContainerTag ds : debugSWF.abcList) { + ABC a = ds.getABC(); + //Append random hex to Debugger package name + for (int i = 1; i < a.constants.constant_namespace.size(); i++) { + if (a.constants.constant_namespace.get(i).hasName(DEBUGGER_PACKAGE, a.constants)) { + a.constants.constant_namespace.get(i).name_index = a.constants.getStringId(newdebuggerpkg, true); + } + } + //Set debugger port to actually set port + for (int i = 0; i < a.constants.constant_int.size(); i++) { + if (a.constants.constant_int.get(i) == 123456L) { + a.constants.constant_int.set(i, (long) port); + } + } + //Add to target SWF + ((Tag) ds).setSwf(swf); + swf.tags.add(swf.tags.indexOf(firstAbc), (Tag) ds); + swf.abcList.add(swf.abcList.indexOf(firstAbc), ds); + ((Tag) ds).setModified(true); + } + + } catch (Exception ex) { + //ignore + } + + } + initDebugger(); + } + + private static void initDebugger() { + if (debugger == null) { + debugger = new Debugger(Configuration.debuggerPort.get()); + debugger.start(); + } + } + + public static void debuggerShowLog() { + initDebugger(); + if (debugDialog == null) { + debugDialog = new DebugLogDialog(debugger); + } + debugDialog.setVisible(true); + } + public static void autoCheckForUpdates() { if (Configuration.checkForUpdatesAuto.get()) { Calendar lastUpdatesCheckDate = Configuration.lastUpdatesCheckDate.get(); diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java index 72eefe499..6b0a4e7fe 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java @@ -93,6 +93,9 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { static final String ACTION_TIMELINE = "TIMELINE"; static final String ACTION_AUTO_DEOBFUSCATE = "AUTODEOBFUSCATE"; static final String ACTION_EXIT = "EXIT"; + static final String ACTION_DEBUGGER_SWITCH = "DEBUGGER_SWITCH"; + static final String ACTION_DEBUGGER_REPLACE_TRACE = "DEBUGGER_REPLACE_TRACE"; + static final String ACTION_DEBUGGER_LOG = "DEBUGGER_LOG"; static final String ACTION_RENAME_ONE_IDENTIFIER = "RENAMEONEIDENTIFIER"; static final String ACTION_ABOUT = "ABOUT"; @@ -158,6 +161,10 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { private CommandToggleButtonGroup timeLineToggleGroup; private JCommandButton gotoDocumentClassCommandButton; private JCommandButton clearRecentFilesCommandButton; + private JCommandToggleButton debuggerSwitchCommandButton; + private CommandToggleButtonGroup debuggerSwitchGroup; + private JCommandButton debuggerReplaceTraceCommandButton; + private JCommandButton debuggerLogCommandButton; private CommandToggleButtonGroup viewModeToggleGroup; @@ -385,13 +392,43 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { } private RibbonTask createToolsRibbonTask() { + + + JRibbonBand debuggerBand = new JRibbonBand(translate("menu.debugger"), null); + debuggerBand.setResizePolicies(getResizePolicies(debuggerBand)); + + debuggerSwitchCommandButton = new JCommandToggleButton(translate("menu.debugger.switch"),View.getResizableIcon("debugger32")); + assignListener(debuggerSwitchCommandButton, ACTION_DEBUGGER_SWITCH); + + //debuggerDetachCommandButton = new JCommandButton("Detach debugger",View.getResizableIcon("debuggerremove16")); + //assignListener(debuggerDetachCommandButton, ACTION_DEBUGGER_DETACH); + + debuggerReplaceTraceCommandButton = new JCommandButton(translate("menu.debugger.replacetrace"), View.getResizableIcon("debuggerreplace16")); + assignListener(debuggerReplaceTraceCommandButton, ACTION_DEBUGGER_REPLACE_TRACE); + + debuggerLogCommandButton = new JCommandButton(translate("menu.debugger.showlog"), View.getResizableIcon("debuggerlog16")); + assignListener(debuggerLogCommandButton, ACTION_DEBUGGER_LOG); + + debuggerSwitchGroup = new CommandToggleButtonGroup(); + debuggerSwitchGroup.add(debuggerSwitchCommandButton); + + debuggerSwitchCommandButton.setEnabled(false); + + debuggerReplaceTraceCommandButton.setEnabled(false); + + debuggerBand.addCommandButton(debuggerSwitchCommandButton, RibbonElementPriority.TOP); + debuggerBand.addCommandButton(debuggerReplaceTraceCommandButton, RibbonElementPriority.MEDIUM); + debuggerBand.addCommandButton(debuggerLogCommandButton, RibbonElementPriority.MEDIUM); + + + //----------------------------------------- TOOLS ----------------------------------- JRibbonBand toolsBand = new JRibbonBand(translate("menu.tools"), null); toolsBand.setResizePolicies(getResizePolicies(toolsBand)); searchCommandButton = new JCommandButton(fixCommandTitle(translate("menu.tools.search")), View.getResizableIcon("search32")); - assignListener(searchCommandButton, ACTION_SEARCH); + assignListener(searchCommandButton, ACTION_SEARCH); timeLineToggleButton = new JCommandToggleButton(fixCommandTitle(translate("menu.tools.timeline")), View.getResizableIcon("timeline32")); assignListener(timeLineToggleButton, ACTION_TIMELINE); @@ -436,7 +473,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { //JRibbonBand otherToolsBand = new JRibbonBand(translate("menu.tools.otherTools"), null); //otherToolsBand.setResizePolicies(getResizePolicies(otherToolsBand)); - return new RibbonTask(translate("menu.tools"), toolsBand, deobfuscationBand/*, otherToolsBand*/); + return new RibbonTask(translate("menu.tools"), toolsBand, deobfuscationBand, debuggerBand /*, otherToolsBand*/); } private RibbonTask createSettingsRibbonTask(boolean externalFlashPlayerUnavailable) { @@ -598,7 +635,8 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { public void updateComponents(SWF swf, List abcList) { boolean swfLoaded = swf != null; boolean hasAbc = swfLoaded && abcList != null && !abcList.isEmpty(); - + boolean hasDebugger = hasAbc && Main.hasDebugger(swf); + exportAllMenu.setEnabled(swfLoaded); exportFlaMenu.setEnabled(swfLoaded); exportSelMenu.setEnabled(swfLoaded); @@ -625,6 +663,12 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { gotoDocumentClassCommandButton.setEnabled(hasAbc); deobfuscationCommandButton.setEnabled(hasAbc); + debuggerSwitchCommandButton.setEnabled(hasAbc); + debuggerSwitchGroup.setSelected(debuggerSwitchCommandButton, hasDebugger); + //debuggerSwitchCommandButton. + //debuggerDetachCommandButton.setEnabled(hasDebugger); + debuggerReplaceTraceCommandButton.setEnabled(hasAbc && hasDebugger); + } private boolean saveAs(SWF swf, SaveFileMode mode) { @@ -640,6 +684,28 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { @Override public void actionPerformed(ActionEvent e) { switch (e.getActionCommand()) { + case ACTION_DEBUGGER_SWITCH: + if(debuggerSwitchGroup.getSelected()==null || View.showConfirmDialog(mainFrame, translate("message.debugger"), translate("dialog.message.title"),JOptionPane.OK_CANCEL_OPTION,JOptionPane.INFORMATION_MESSAGE, Configuration.displayDebuggerInfo,JOptionPane.OK_OPTION)==JOptionPane.OK_OPTION){ + Main.switchDebugger(); + mainFrame.panel.refreshDecompiled(); + }else{ + if(debuggerSwitchGroup.getSelected()==debuggerSwitchCommandButton){ + debuggerSwitchGroup.setSelected(debuggerSwitchCommandButton, false); + } + } + debuggerReplaceTraceCommandButton.setEnabled(debuggerSwitchGroup.getSelected()==debuggerSwitchCommandButton); + break; + case ACTION_DEBUGGER_LOG: + Main.debuggerShowLog(); + break; + case ACTION_DEBUGGER_REPLACE_TRACE: + ReplaceTraceDialog rtd = new ReplaceTraceDialog(mainFrame); + rtd.setVisible(true); + if(rtd.getResult()!=null){ + Main.replaceTraceCalls(rtd.getResult()); + mainFrame.panel.refreshDecompiled(); + } + break; case ACTION_RELOAD: if (View.showConfirmDialog(null, translate("message.confirm.reload"), translate("message.warning"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { Main.reloadApp(); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 069fb6993..cb85f49fd 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1892,12 +1892,12 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } - public void refreshDecompiled() { + public void refreshDecompiled() { clearCache(); if (abcPanel != null) { abcPanel.reload(); } - reload(true); + reload(true); updateClassesList(); } diff --git a/src/com/jpexs/decompiler/flash/gui/ReplaceTraceDialog.java b/src/com/jpexs/decompiler/flash/gui/ReplaceTraceDialog.java new file mode 100644 index 000000000..2de8e0471 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/ReplaceTraceDialog.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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 . + */ + +package com.jpexs.decompiler.flash.gui; + +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JRadioButton; + +/** + * + * @author JPEXS + */ +public class ReplaceTraceDialog extends AppDialog { + + private JRadioButton debugAlertRadio; + private JRadioButton debugConsoleRadio; + private JRadioButton debugProxyRadio; + + private String result = null; + + public String getResult() { + return result; + } + + public ReplaceTraceDialog(Window owner) { + super(owner); + setTitle(translate("dialog.title")); + Container cnt=getContentPane(); + cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS)); + debugAlertRadio = new JRadioButton(translate("function.debugAlert")); + debugAlertRadio.setAlignmentX(0); + debugConsoleRadio = new JRadioButton(translate("function.debugConsole")); + debugConsoleRadio.setAlignmentX(0); + debugProxyRadio = new JRadioButton(translate("function.debugSocket")); + debugProxyRadio.setAlignmentX(0); + + debugAlertRadio.setSelected(true); + + ButtonGroup bg = new ButtonGroup(); + bg.add(debugAlertRadio); + bg.add(debugConsoleRadio); + bg.add(debugProxyRadio); + + + + cnt.add(debugAlertRadio); + cnt.add(debugConsoleRadio); + cnt.add(debugProxyRadio); + + JPanel buttonsPanel = new JPanel(new FlowLayout()); + JButton okButton=new JButton(AppStrings.translate("button.ok")); + okButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if(debugAlertRadio.isSelected()){ + result = "debugAlert"; + } + if(debugConsoleRadio.isSelected()){ + result = "debugConsole"; + } + if(debugProxyRadio.isSelected()){ + result = "debugSocket"; + } + setVisible(false); + } + }); + JButton cancelButton=new JButton(AppStrings.translate("button.cancel")); + cancelButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + result = null; + setVisible(false); + } + }); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + buttonsPanel.setAlignmentX(0); + add(buttonsPanel); + setModalityType(DEFAULT_MODALITY_TYPE); + pack(); + View.setWindowIcon(this); + View.centerScreen(this); + } + +} diff --git a/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java index 482dab457..425a083c5 100644 --- a/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java @@ -333,7 +333,7 @@ public class TagTreeModel implements TreeModel { if (n instanceof TreeElement) { TreeElement te = (TreeElement) n; TreeElementItem it = te.getItem(); - if (obj == it) { + if (obj.equals(it)) { return newPath; } } @@ -346,7 +346,7 @@ public class TagTreeModel implements TreeModel { return newPath; } } else { - if (n.getItem() == obj) { + if (obj.equals(n.getItem())) { return newPath; } } diff --git a/src/com/jpexs/decompiler/flash/gui/View.java b/src/com/jpexs/decompiler/flash/gui/View.java index 1b921ac91..13ec09128 100644 --- a/src/com/jpexs/decompiler/flash/gui/View.java +++ b/src/com/jpexs/decompiler/flash/gui/View.java @@ -376,7 +376,7 @@ public class View { public static int showConfirmDialog(final Component parentComponent, String message, final String title, final int optionType, final int messageTyp, ConfigurationItem showAgainConfig, int defaultOption) { - JLabel warLabel = new JLabel(message); + JLabel warLabel = new JLabel(""+message.replace("\r\n", "
")+""); final JPanel warPanel = new JPanel(new BorderLayout()); warPanel.add(warLabel, BorderLayout.CENTER); JCheckBox donotShowAgainCheckBox = new JCheckBox(AppStrings.translate("message.confirm.donotshowagain")); @@ -398,13 +398,37 @@ public class View { return ret[0]; } - public static void showMessageDialog(final Component parentComponent, final Object message, final String title, final int messageType) { + public static void showMessageDialog(final Component parentComponent, final String message, final String title, final int messageType) { + showMessageDialog(parentComponent, message, title, messageType, null); + } + + public static void showMessageDialog(final Component parentComponent, final String message, final String title, final int messageType, ConfigurationItem showAgainConfig) { + + Object msg = message; + JCheckBox donotShowAgainCheckBox = new JCheckBox(AppStrings.translate("message.confirm.donotshowagain")); + + if (showAgainConfig != null) { + JLabel warLabel = new JLabel(""+message.replace("\r\n", "
")+""); + final JPanel warPanel = new JPanel(new BorderLayout()); + warPanel.add(warLabel, BorderLayout.CENTER); + donotShowAgainCheckBox.setSelected(!showAgainConfig.get()); + warPanel.add(donotShowAgainCheckBox, BorderLayout.SOUTH); + msg = warPanel; + if (donotShowAgainCheckBox.isSelected()) { + return; + } + } + final Object fmsg=msg; + execInEventDispatch(new Runnable() { @Override public void run() { - JOptionPane.showMessageDialog(parentComponent, message, title, messageType); + JOptionPane.showMessageDialog(parentComponent, fmsg, title, messageType); } }); + if (showAgainConfig != null) { + showAgainConfig.set(!donotShowAgainCheckBox.isSelected()); + } } public static void showMessageDialog(final Component parentComponent, final Object message) { diff --git a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 8cea28f0a..a0ea3503a 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -119,7 +119,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se public ABC abc; public SWF swf; public JComboBox abcComboBox; - public int listIndex = -1; + public ABCContainerTag listIndex = null; public DecompiledEditorPane decompiledTextArea; public JScrollPane decompiledScrollPane; public JSplitPane splitPane; @@ -318,8 +318,8 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se public void setSwf(SWF swf) { if (this.swf != swf) { this.swf = swf; - listIndex = -1; - switchAbc(0); // todo honika: do we need this? + listIndex = null; + switchAbc(swf.abcList.get(0)); // todo honika: do we need this? abcComboBox.setModel(new ABCComboBoxModel(swf.abcList)); if (swf.abcList.size() > 0) { this.abc = swf.abcList.get(0).getABC(); @@ -329,11 +329,11 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se } } - public void switchAbc(int index) { + public void switchAbc(ABCContainerTag index) { listIndex = index; - if (index != -1) { - this.abc = swf.abcList.get(index).getABC(); + if (index != null) { + this.abc = index.getABC(); } updateConstList(); } @@ -643,7 +643,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se if (index == -1) { return; } - switchAbc(index - 1); + switchAbc(swf.abcList.get(index - 1)); } if (e.getSource() == constantTypeList) { int index = ((JComboBox) e.getSource()).getSelectedIndex(); @@ -775,15 +775,23 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se case ACTION_SAVE_DECOMPILED: ScriptPack pack = decompiledTextArea.getScriptLeaf(); int oldIndex = pack.scriptIndex; - + decompiledTextArea.uncache(pack); + + try { + String oldSp = null; + List> packs = abc.script_info.get(oldIndex).getPacks(abc, oldIndex); + if (!packs.isEmpty()) { + oldSp = packs.get(0).getKey().toString(); + } + String as = decompiledTextArea.getText(); abc.replaceSciptPack(pack, as); lastDecompiled = as; mainPanel.updateClassesList(); - List> packs = abc.script_info.get(oldIndex).getPacks(abc, oldIndex); - if (!packs.isEmpty()) { - hilightScript(swf, packs.get(0).getKey().toString()); + + if(oldSp!=null){ + hilightScript(swf, oldSp); } //decompiledTextArea.setClassIndex(-1); //navigator.setClassIndex(-1, oldIndex); diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java index d536889e8..ef8579f3c 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DecompiledEditorPane.java @@ -385,7 +385,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL } } - private void uncache(ScriptPack pack) { + public void uncache(ScriptPack pack) { cache.remove(pack); } diff --git a/src/com/jpexs/decompiler/flash/gui/abc/DetailPanel.java b/src/com/jpexs/decompiler/flash/gui/abc/DetailPanel.java index 01939b0a7..77d566c3a 100644 --- a/src/com/jpexs/decompiler/flash/gui/abc/DetailPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/abc/DetailPanel.java @@ -169,7 +169,9 @@ public class DetailPanel extends JPanel implements ActionListener { if (trait == null) { traitNameLabel.setText("-"); } else { - traitNameLabel.setText(trait.getName(abcPanel.abc).getName(abcPanel.abc.constants, new ArrayList(), false)); + if(abcPanel!=null && trait.getName(abcPanel.abc)!=null && abcPanel.abc != null){ + traitNameLabel.setText(trait.getName(abcPanel.abc).getName(abcPanel.abc.constants, new ArrayList(), false)); + } } } }); diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java new file mode 100644 index 000000000..0627a7b58 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/debugger/DebugListener.java @@ -0,0 +1,10 @@ +package com.jpexs.decompiler.flash.gui.debugger; + +/** + * + * @author JPEXS + */ +public interface DebugListener { + public void onMessage(String clientId,String msg); + public void onFinish(String clientId); +} diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java new file mode 100644 index 000000000..752b40dc1 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/debugger/Debugger.java @@ -0,0 +1,181 @@ +package com.jpexs.decompiler.flash.gui.debugger; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +/** + * + * @author JPEXS + */ +public class Debugger { + + private static Set listeners = new HashSet<>(); + + public synchronized void addMessageListener(DebugListener l) { + listeners.add(l); + } + + public synchronized void removeMessageListener(DebugListener l) { + listeners.remove(l); + } + + private static class DebugHandler extends Thread { + + Socket s; + int serverPort; + static int maxid = 0; + int id; + public boolean finished = false; + + public DebugHandler(int serverPort, Socket s) { + this.s = s; + id = maxid++; + this.serverPort = serverPort; + } + + public void cancel() { + try { + s.close(); + } catch (IOException ex) { + //ignore + } + } + + private String readString(InputStream is) throws IOException + { + int len = is.read(); + if (len == -1) { + return ""; + } + byte buf[] = new byte[len]; + is.read(buf); + return new String(buf, "UTF-8"); + + } + @Override + public void run() { + String clientName = ""+id; + try (InputStream is = s.getInputStream()) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + int c; + do { + c = is.read(); + if (c != 0) { + baos.write(c); + } + + } while (c > 0); + String ret = baos.toString("UTF-8"); + + if (ret.equals("")) { + try (OutputStream os = s.getOutputStream()) { + os.write(("").getBytes("UTF-8")); + } + } else { + String name = readString(is); + if(!name.equals("")){ + clientName = name; + } + while (true) { + ret = readString(is); + for (DebugListener l : listeners) { + l.onMessage(clientName, ret); + } + } + } + + } catch (IOException ex) { + //ignore + } + try { + s.close(); + } catch (IOException ex) { + //ignore + } + finished = true; + for (DebugListener l : listeners) { + l.onFinish(clientName); + } + } + + } + + private static class DebugServerThread extends Thread { + + private final int port; + private ServerSocket ss; + private final Map handlers = new WeakHashMap<>(); + + public DebugServerThread(int port) { + this.port = port; + } + + @Override + public void run() { + try { + ss = new ServerSocket(port,50,InetAddress.getByName("localhost")); + ss.setReuseAddress(true); + while (true) { + Socket s = ss.accept(); + if (s != null) { + DebugHandler h = new DebugHandler(port, s); + handlers.put(h.id, h); + h.start(); + } + } + } catch (IOException ex) { + //ignore + } + } + + } + + private int port; + + public Debugger(int port) { + this.port = port; + } + + private DebugServerThread server = null; + + public synchronized void start() { + if (server == null) { + server = new DebugServerThread(port); + server.start(); + } + } + + public synchronized boolean isRunning() { + return server != null; + } + + public int getPort() { + return port; + } + + public synchronized void stop() { + if (server != null) { + try { + server.ss.close(); + } catch (IOException ex) { + //ignore + } + for (DebugHandler h : server.handlers.values()) { + h.cancel(); + } + server.handlers.clear(); + server = null; + } + } + +} diff --git a/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf new file mode 100644 index 000000000..f6851e435 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/debugger/debug.swf differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debugger16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debugger16.png new file mode 100644 index 000000000..c7299fd7d Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debugger16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debugger32.png b/src/com/jpexs/decompiler/flash/gui/graphics/debugger32.png new file mode 100644 index 000000000..563c364c7 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debugger32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach16.png new file mode 100644 index 000000000..e8d9959f9 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach32.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach32.png new file mode 100644 index 000000000..8bfe4a44e Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerattach32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerlog16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerlog16.png new file mode 100644 index 000000000..8a08b5224 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerlog16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove16.png new file mode 100644 index 000000000..06a9049e5 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove32.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove32.png new file mode 100644 index 000000000..5e1faac49 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerremove32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace16.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace16.png new file mode 100644 index 000000000..808773ece Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace32.png b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace32.png new file mode 100644 index 000000000..285c58279 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/debuggerreplace32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties index e3132bb2c..e9026d582 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog.properties @@ -272,3 +272,9 @@ config.description.showMethodBodyId = Shows the id of the methodbody for command config.name.export.zoom = (Internal) Export zoom config.description.export.zoom = Last used export zoom + +config.name.debuggerPort = Debugger port +config.description.debuggerPort = Port used for socket debugging + +config.name.displayDebuggerInfo = (Internal) Display debugger info +config.description.displayDebuggerInfo = Display info about debugger before switching it \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties index 53031c72d..4889952a6 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/AdvancedSettingsDialog_cs.properties @@ -253,5 +253,21 @@ config.description.packJavaScripts = Spou\u0161t\u011bt komprim\u00e1tor JavaScr config.name.textExportExportFontFace = Pou\u017e\u00edvat font-face v SVG exportu config.description.textExportExportFontFace = Vkl\u00e1dat soubory p\u00edsem do SVG pou\u017eit\u00edm font-face m\u00edsto tvar\u016f -config.name.dumpView = Dump zobrazen\u00ed -config.description.dumpView = Zobrazit dump raw dat +config.name.lzmaFastBytes = LZMA fast bytes (platn\u00e9 hodnoty: 5-255) +config.description.lzmaFastBytes = Parametr fast bytes LZMA enkoderu + +#temporary setting, do not translate it +config.name.pluginPath = Plugin Path +config.description.pluginPath = - + +config.name.deobfuscationMode = M\u00f3d deobfuskace +config.description.deobfuscationMode = Typ deobfuskace + +config.name.showMethodBodyId = Zobrazovat id body metod +config.description.showMethodBodyId = Zobrazuje id body metody pro import p\u0159es p\u0159\u00edkazovou \u0159\u00e1dku + +config.name.export.zoom = (Internal) P\u0159ibl\u00ed\u017een\u00ed exportu +config.description.export.zoom = Naposledy pou\u017eit\u00e9 nastaven\u00ed p\u0159ibl\u00ed\u017een\u00ed + +config.name.debuggerPort = Port Debuggeru +config.description.debuggerPort = Port pou\u017e\u00edvan\u00fd pro lad\u011bn\u00ed p\u0159es sockety diff --git a/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog.properties new file mode 100644 index 000000000..db2c4c63d --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog.properties @@ -0,0 +1,19 @@ +# Copyright (C) 2014 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 . + +dialog.title = Debugger Log +button.clear = Clear +button.close = Close +msg.header = connection %clientid%: \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog_cs.properties new file mode 100644 index 000000000..7cbef99b8 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/DebugLogDialog_cs.properties @@ -0,0 +1,19 @@ +# Copyright (C) 2014 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 . + +dialog.title = Log Debuggeru +button.clear = Vypr\u00e1zdnit +button.close = Zav\u0159\u00edt +msg.header = spojen\u00ed %clientid%: \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_cs.properties index 4781e9f57..3d7753e0c 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog_cs.properties @@ -66,3 +66,7 @@ frames.pdf = PDF fonts = P\u00edsma fonts.ttf = TTF fonts.woff = WOFF + +zoom = P\u0159ibl\u00ed\u017een\u00ed +zoom.percent = % +zoom.invalid = Neplatn\u00e1 hodnota velikost. \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 0f075d0dc..2c9435d43 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -514,4 +514,11 @@ button.snapshot.hint = Take snapshot into clipboard editorTruncateWarning = Text truncated at position %chars% in debug mode. -font.name.intag = Font name in tag: \ No newline at end of file +font.name.intag = Font name in tag: + +menu.debugger = Debugger +menu.debugger.switch = Debugger +menu.debugger.replacetrace = Replace trace calls +menu.debugger.showlog = Show Log + +message.debugger = This SWF Debugger can only be used to print messages to log window, browser console or alerts.\r\nIt is NOT designed for features like step code, breakpoints etc. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 056b19c00..55e0333ec 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -513,4 +513,11 @@ button.snapshot.hint = Sn\u00edmek do schr\u00e1nky editorTruncateWarning = Text je o\u0159\u00edznut na pozici %chars% v lad\u00edc\u00edm m\u00f3du. -font.name.intag = N\u00e1zev p\u00edsma v tagu: \ No newline at end of file +font.name.intag = N\u00e1zev p\u00edsma v tagu: + +menu.debugger = Debugger +menu.debugger.switch = Debugger +menu.debugger.replacetrace = Nahradit vol\u00e1n\u00ed trace +menu.debugger.showlog = Zobrazit Log + +message.debugger = Tento SWF Debugger slou\u017e\u00ed jen k pos\u00edl\u00e1n\u00ed zpr\u00e1v do okna logu, konzole prohl\u00ed\u017ee\u010de nebo alert oken.\r\nNEN\u00cd ur\u010den pro krokov\u00e1n\u00ed k\u00f3du, breakpointy atd. diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog.properties new file mode 100644 index 000000000..2408c3fa2 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog.properties @@ -0,0 +1,20 @@ +# Copyright (C) 2014 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 . + +dialog.title = Replace Trace function calls + +function.debugAlert = debugAlert - web browser javascript alert +function.debugConsole = debugConsole - web browser javascript console.log +function.debugSocket = debugSocket - socket connection to the decompiler \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog_cs.properties new file mode 100644 index 000000000..6c4dce006 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/locales/ReplaceTraceDialog_cs.properties @@ -0,0 +1,20 @@ +# Copyright (C) 2014 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 . + +dialog.title = Nahrazen\u00ed vol\u00e1n\u00ed funkce Trace + +function.debugAlert = debugAlert - javascriptov\u00e1 funkce alert webov\u00e9ho prohl\u00ed\u017ee\u010de +function.debugConsole = debugConsole - javascriptov\u00e1 funkce console.log webov\u00e9ho prohl\u00ed\u017ee\u010de +function.debugSocket = debugSocket - p\u0159ipojen\u00ed sockety k dekompil\u00e1toru \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java index badf20b02..3896b82de 100644 --- a/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/player/FlashPlayerPanel.java @@ -17,7 +17,10 @@ package com.jpexs.decompiler.flash.gui.player; import com.jpexs.decompiler.flash.gui.FlashUnsupportedException; +import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.javactivex.ActiveX; +import com.jpexs.javactivex.ActiveXEvent; +import com.jpexs.javactivex.ActiveXEventListener; import com.jpexs.javactivex.example.controls.flash.ShockwaveFlash; import com.sun.jna.Platform; import java.awt.AWTException; @@ -30,6 +33,8 @@ import java.awt.Robot; import java.awt.image.BufferedImage; import java.io.Closeable; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -107,6 +112,35 @@ public class FlashPlayerPanel extends Panel implements Closeable, MediaDisplay { throw new FlashUnsupportedException(); } flash = ActiveX.createObject(ShockwaveFlash.class, this); + flash.setAllowScriptAccess("always"); + flash.setAllowNetworking("all"); + flash.addFlashCallListener(new ActiveXEventListener() { + + @Override + public void onEvent(ActiveXEvent axe) { + String req = (String) axe.args.get("request"); + Matcher m = Pattern.compile("(.*)").matcher(req); + if (m.matches()) { + String funname = m.group(1); + String msg = m.group(2); + if (funname.equals("alert") || funname.equals("console.log")) { + if (Main.debugDialog != null) { + Main.debugDialog.log(funname + ":" + msg); + } + } + } + } + }); + flash.addFSCommandListener(new ActiveXEventListener() { + + @Override + public void onEvent(ActiveXEvent axe) { + System.out.println("Event:" + axe.name); + for (String k : axe.args.keySet()) { + System.out.println(k + "=" + axe.args.get(k)); + } + } + }); } public synchronized void stopSWF() {