Issue #707 Debugger for logging messages

This commit is contained in:
Jindra Petřík
2014-10-28 15:57:31 +01:00
parent 9a5361e8e3
commit 2746f3bc32
49 changed files with 1351 additions and 28 deletions
@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}
}
+167 -1
View File
@@ -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<ClassPath, ScriptPack> 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<ClassPath, ScriptPack> 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();
@@ -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<ABCContainerTag> 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();
@@ -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();
}
@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}
@@ -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;
}
}
+27 -3
View File
@@ -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<Boolean> showAgainConfig, int defaultOption) {
JLabel warLabel = new JLabel(message);
JLabel warLabel = new JLabel("<html>"+message.replace("\r\n", "<br>")+"</html>");
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<Boolean> showAgainConfig) {
Object msg = message;
JCheckBox donotShowAgainCheckBox = new JCheckBox(AppStrings.translate("message.confirm.donotshowagain"));
if (showAgainConfig != null) {
JLabel warLabel = new JLabel("<html>"+message.replace("\r\n", "<br>")+"</html>");
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) {
@@ -119,7 +119,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se
public ABC abc;
public SWF swf;
public JComboBox<ABCContainerTag> 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<MyEntry<ClassPath, ScriptPack>> 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<MyEntry<ClassPath, ScriptPack>> 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);
@@ -385,7 +385,7 @@ public class DecompiledEditorPane extends LineMarkedEditorPane implements CaretL
}
}
private void uncache(ScriptPack pack) {
public void uncache(ScriptPack pack) {
cache.remove(pack);
}
@@ -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<String>(), false));
if(abcPanel!=null && trait.getName(abcPanel.abc)!=null && abcPanel.abc != null){
traitNameLabel.setText(trait.getName(abcPanel.abc).getName(abcPanel.abc.constants, new ArrayList<String>(), false));
}
}
}
});
@@ -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);
}
@@ -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<DebugListener> 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("<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"));
}
} 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<Integer, DebugHandler> 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;
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 984 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -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
@@ -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
@@ -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 <http://www.gnu.org/licenses/>.
dialog.title = Debugger Log
button.clear = Clear
button.close = Close
msg.header = connection %clientid%:
@@ -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 <http://www.gnu.org/licenses/>.
dialog.title = Log Debuggeru
button.clear = Vypr\u00e1zdnit
button.close = Zav\u0159\u00edt
msg.header = spojen\u00ed %clientid%:
@@ -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.
@@ -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:
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.
@@ -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:
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.
@@ -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 <http://www.gnu.org/licenses/>.
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
@@ -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 <http://www.gnu.org/licenses/>.
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
@@ -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("<invoke name=\"([^\"]+)\" returntype=\"xml\"><arguments><string>(.*)</string></arguments></invoke>").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() {