/*
* Copyright (C) 2010-2013 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.Configuration;
import com.jpexs.decompiler.flash.FrameNode;
import com.jpexs.decompiler.flash.PackageNode;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.TagNode;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.RenameType;
import com.jpexs.decompiler.flash.abc.ScriptPack;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
import static com.jpexs.decompiler.flash.gui.Main.isAddedToContextMenu;
import com.jpexs.decompiler.flash.gui.abc.ABCPanel;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog;
import com.jpexs.decompiler.flash.gui.abc.LineMarkedEditorPane;
import com.jpexs.decompiler.flash.gui.abc.TreeElement;
import com.jpexs.decompiler.flash.gui.action.ActionPanel;
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsLosslessTag;
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
import com.jpexs.decompiler.flash.tags.DefineButton2Tag;
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
import com.jpexs.decompiler.flash.tags.DefineEditTextTag;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.DefineFont3Tag;
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
import com.jpexs.decompiler.flash.tags.DefineFontTag;
import com.jpexs.decompiler.flash.tags.DefineMorphShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineShape3Tag;
import com.jpexs.decompiler.flash.tags.DefineShape4Tag;
import com.jpexs.decompiler.flash.tags.DefineShapeTag;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DefineText2Tag;
import com.jpexs.decompiler.flash.tags.DefineTextTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.EndTag;
import com.jpexs.decompiler.flash.tags.ExportAssetsTag;
import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
import com.jpexs.decompiler.flash.tags.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
import com.jpexs.decompiler.flash.tags.SoundStreamHead2Tag;
import com.jpexs.decompiler.flash.tags.SoundStreamHeadTag;
import com.jpexs.decompiler.flash.tags.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.tags.SymbolClassTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.tags.base.AloneTag;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.Container;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.tags.text.ParseException;
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.sun.jna.Platform;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.border.BevelBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
/**
*
* @author Jindra
*/
public class MainFrame extends AppFrame implements ActionListener, TreeSelectionListener {
private SWF swf;
public ABCPanel abcPanel;
public ActionPanel actionPanel;
public LoadingPanel loadingPanel = new LoadingPanel(20, 20);
public JLabel statusLabel = new JLabel("");
public JPanel statusPanel = new JPanel();
public JProgressBar progressBar = new JProgressBar(0, 100);
private DeobfuscationDialog deobfuscationDialog;
public JTree tagTree;
public FlashPlayerPanel flashPanel;
public JPanel displayPanel;
public ImagePanel imagePanel;
public ImagePanel previewImagePanel;
public SWFPreviwPanel swfPreviewPanel;
final static String CARDFLASHPANEL = "Flash card";
final static String CARDSWFPREVIEWPANEL = "SWF card";
final static String CARDDRAWPREVIEWPANEL = "Draw card";
final static String CARDIMAGEPANEL = "Image card";
final static String CARDEMPTYPANEL = "Empty card";
final static String CARDACTIONSCRIPTPANEL = "ActionScript card";
final static String DETAILCARDAS3NAVIGATOR = "Traits list";
final static String DETAILCARDEMPTYPANEL = "Empty card";
final static String CARDTEXTPANEL = "Text card";
private LineMarkedEditorPane textValue;
private JPEGTablesTag jtt;
private HashMap characters;
private List abcList;
JSplitPane splitPane1;
JSplitPane splitPane2;
private JPanel detailPanel;
private JTextField filterField = new JTextField("");
private JPanel searchPanel;
private JCheckBoxMenuItem autoDeobfuscateMenuItem;
private JPanel displayWithPreview;
private JButton textSaveButton;
private JButton textEditButton;
private JButton textCancelButton;
private JPanel parametersPanel;
private JSplitPane previewSplitPane;
private JButton imageReplaceButton;
private JPanel imageButtonsPanel;
private JCheckBoxMenuItem miInternalViewer;
private JCheckBoxMenuItem miParallelSpeedUp;
private JCheckBoxMenuItem miAssociate;
private JCheckBoxMenuItem miDecompile;
public void setPercent(int percent) {
progressBar.setValue(percent);
progressBar.setVisible(true);
}
public void hidePercent() {
if (progressBar.isVisible()) {
progressBar.setVisible(false);
}
}
static {
try {
File.createTempFile("temp", ".swf").delete(); //First call to this is slow, so make it first
} catch (IOException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void addTab(JTabbedPane tabbedPane, Component tab, String title, Icon icon) {
tabbedPane.add(tab);
JLabel lbl = new JLabel(title);
lbl.setIcon(icon);
lbl.setIconTextGap(5);
lbl.setHorizontalTextPosition(SwingConstants.RIGHT);
tabbedPane.setTabComponentAt(tabbedPane.getTabCount() - 1, lbl);
}
public void setStatus(String s) {
statusLabel.setText(s);
}
public void setWorkStatus(String s) {
if (s.equals("")) {
loadingPanel.setVisible(false);
} else {
loadingPanel.setVisible(true);
}
statusLabel.setText(s);
}
public MainFrame(SWF swf) {
int w = (Integer) Configuration.getConfig("gui.window.width", 1000);
int h = (Integer) Configuration.getConfig("gui.window.height", 700);
Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
if (w > dim.width) {
w = dim.width;
}
if (h > dim.height) {
h = dim.height;
}
setSize(w, h);
View.setWindowIcon(this);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Configuration.setConfig("gui.window.width", getWidth());
Configuration.setConfig("gui.window.height", getHeight());
}
});
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (Main.proxyFrame != null) {
if (Main.proxyFrame.isVisible()) {
return;
}
}
Main.exit();
}
});
setTitle(Main.applicationVerName + (Configuration.DISPLAY_FILENAME ? " - " + Main.getFileTitle() : ""));
JMenuBar menuBar = new JMenuBar();
try {
flashPanel = new FlashPlayerPanel(this);
} catch (FlashUnsupportedException fue) {
}
JMenu menuFile = new JMenu(translate("menu.file"));
JMenuItem miOpen = new JMenuItem(translate("menu.file.open"));
miOpen.setIcon(View.getIcon("open16"));
miOpen.setActionCommand("OPEN");
miOpen.addActionListener(this);
JMenuItem miSave = new JMenuItem(translate("menu.file.save"));
miSave.setIcon(View.getIcon("save16"));
miSave.setActionCommand("SAVE");
miSave.addActionListener(this);
JMenuItem miSaveAs = new JMenuItem(translate("menu.file.saveas"));
miSaveAs.setIcon(View.getIcon("saveas16"));
miSaveAs.setActionCommand("SAVEAS");
miSaveAs.addActionListener(this);
JMenuItem menuExportFla = new JMenuItem(translate("menu.file.export.fla"));
menuExportFla.setActionCommand("EXPORTFLA");
menuExportFla.addActionListener(this);
menuExportFla.setIcon(View.getIcon("flash16"));
JMenuItem menuExportAll = new JMenuItem(translate("menu.file.export.all"));
menuExportAll.setActionCommand("EXPORT");
menuExportAll.addActionListener(this);
JMenuItem menuExportSel = new JMenuItem(translate("menu.file.export.selection"));
menuExportSel.setActionCommand("EXPORTSEL");
menuExportSel.addActionListener(this);
menuExportAll.setIcon(View.getIcon("export16"));
menuExportSel.setIcon(View.getIcon("exportsel16"));
menuFile.add(miOpen);
menuFile.add(miSave);
menuFile.add(miSaveAs);
menuFile.add(menuExportFla);
menuFile.add(menuExportAll);
menuFile.add(menuExportSel);
menuFile.addSeparator();
JMenuItem miClose = new JMenuItem(translate("menu.file.exit"));
miClose.setIcon(View.getIcon("exit16"));
miClose.setActionCommand("EXIT");
miClose.addActionListener(this);
menuFile.add(miClose);
menuBar.add(menuFile);
JMenu menuDeobfuscation = new JMenu(translate("menu.tools.deobfuscation"));
menuDeobfuscation.setIcon(View.getIcon("deobfuscate16"));
JMenuItem miDeobfuscation = new JMenuItem(translate("menu.tools.deobfuscation.pcode"));
miDeobfuscation.setActionCommand("DEOBFUSCATE");
miDeobfuscation.addActionListener(this);
autoDeobfuscateMenuItem = new JCheckBoxMenuItem(translate("menu.settings.autodeobfuscation"));
autoDeobfuscateMenuItem.setState((Boolean) Configuration.getConfig("autoDeobfuscate", true));
autoDeobfuscateMenuItem.addActionListener(this);
autoDeobfuscateMenuItem.setActionCommand("AUTODEOBFUSCATE");
/* JCheckBoxMenuItem miSubLimiter = new JCheckBoxMenuItem("Enable sub limiter");
miSubLimiter.setActionCommand("SUBLIMITER");
miSubLimiter.addActionListener(this);
*/
JMenuItem miRenameOneIdentifier = new JMenuItem(translate("menu.tools.deobfuscation.globalrename"));
miRenameOneIdentifier.setActionCommand("RENAMEONEIDENTIFIER");
miRenameOneIdentifier.addActionListener(this);
JMenuItem miRenameIdentifiers = new JMenuItem(translate("menu.tools.deobfuscation.renameinvalid"));
miRenameIdentifiers.setActionCommand("RENAMEIDENTIFIERS");
miRenameIdentifiers.addActionListener(this);
/*JMenuItem miRemoveDeadCode = new JMenuItem("Remove dead code");
miRemoveDeadCode.setActionCommand("REMOVEDEADCODE");
miRemoveDeadCode.addActionListener(this);
JMenuItem miRemoveDeadCodeAll = new JMenuItem("Remove all dead code");
miRemoveDeadCodeAll.setActionCommand("REMOVEDEADCODEALL");
miRemoveDeadCodeAll.addActionListener(this);
JMenuItem miTraps = new JMenuItem("Remove traps");
miTraps.setActionCommand("REMOVETRAPS");
miTraps.addActionListener(this);
JMenuItem miTrapsAll = new JMenuItem("Remove all traps");
miTrapsAll.setActionCommand("REMOVETRAPSALL");
miTrapsAll.addActionListener(this);
JMenuItem miControlFlow = new JMenuItem("Restore control flow");
miControlFlow.setActionCommand("RESTORECONTROLFLOW");
miControlFlow.addActionListener(this);
JMenuItem miControlFlowAll = new JMenuItem("Restore all control flow");
miControlFlowAll.setActionCommand("RESTORECONTROLFLOWALL");
miControlFlowAll.addActionListener(this);*/
menuDeobfuscation.add(miRenameOneIdentifier);
menuDeobfuscation.add(miRenameIdentifiers);
//menuDeobfuscation.add(miSubLimiter);
menuDeobfuscation.add(miDeobfuscation);
/*menuDeobfuscation.add(miDeobfuscate);
menuDeobfuscation.addSeparator();*/
/*menuDeobfuscation.add(miRemoveDeadCode);
menuDeobfuscation.add(miRemoveDeadCodeAll);
menuDeobfuscation.add(miTraps);
menuDeobfuscation.add(miTrapsAll);
menuDeobfuscation.add(miControlFlow);
menuDeobfuscation.add(miControlFlowAll);
*/
JMenu menuTools = new JMenu(translate("menu.tools"));
JMenuItem miProxy = new JMenuItem(translate("menu.tools.proxy"));
miProxy.setActionCommand("SHOWPROXY");
miProxy.setIcon(View.getIcon("proxy16"));
miProxy.addActionListener(this);
JMenuItem miSearchScript = new JMenuItem(translate("menu.tools.searchas"));
miSearchScript.addActionListener(this);
miSearchScript.setActionCommand("SEARCHAS");
miSearchScript.setIcon(View.getIcon("search16"));
menuTools.add(miSearchScript);
miInternalViewer = new JCheckBoxMenuItem(translate("menu.settings.internalflashviewer"));
miInternalViewer.setSelected((Boolean) Configuration.getConfig("internalFlashViewer", (Boolean) (flashPanel == null)));
if (flashPanel == null) {
miInternalViewer.setSelected(true);
miInternalViewer.setEnabled(false);
}
miInternalViewer.setActionCommand("INTERNALVIEWERSWITCH");
miInternalViewer.addActionListener(this);
miParallelSpeedUp = new JCheckBoxMenuItem(translate("menu.settings.parallelspeedup"));
miParallelSpeedUp.setSelected((Boolean) Configuration.getConfig("paralelSpeedUp", Boolean.TRUE));
miParallelSpeedUp.setActionCommand("PARALLELSPEEDUP");
miParallelSpeedUp.addActionListener(this);
menuTools.add(miProxy);
//menuTools.add(menuDeobfuscation);
menuTools.add(menuDeobfuscation);
JMenuItem miGotoDocumentClass = new JMenuItem(translate("menu.tools.gotodocumentclass"));
miGotoDocumentClass.setActionCommand("GOTODOCUMENTCLASS");
miGotoDocumentClass.addActionListener(this);
menuBar.add(menuTools);
miDecompile = new JCheckBoxMenuItem(translate("menu.settings.disabledecompilation"));
miDecompile.setSelected(!(Boolean) Configuration.getConfig("decompile", Boolean.TRUE));
miDecompile.setActionCommand("DISABLEDECOMPILATION");
miDecompile.addActionListener(this);
JMenu menuSettings = new JMenu(translate("menu.settings"));
menuSettings.add(autoDeobfuscateMenuItem);
menuSettings.add(miInternalViewer);
menuSettings.add(miParallelSpeedUp);
menuSettings.add(miDecompile);
miAssociate = new JCheckBoxMenuItem(translate("menu.settings.addtocontextmenu"));
miAssociate.setActionCommand("ASSOCIATE");
miAssociate.addActionListener(this);
miAssociate.setState(isAddedToContextMenu());
JMenuItem miLanguage = new JMenuItem(translate("menu.settings.language"));
miLanguage.setActionCommand("SETLANGUAGE");
miLanguage.addActionListener(this);
if (Platform.isWindows()) {
menuSettings.add(miAssociate);
}
menuSettings.add(miLanguage);
menuBar.add(menuSettings);
JMenu menuHelp = new JMenu(translate("menu.help"));
JMenuItem miAbout = new JMenuItem(translate("menu.help.about"));
miAbout.setIcon(View.getIcon("about16"));
miAbout.setActionCommand("ABOUT");
miAbout.addActionListener(this);
JMenuItem miCheckUpdates = new JMenuItem(translate("menu.help.checkupdates"));
miCheckUpdates.setActionCommand("CHECKUPDATES");
miCheckUpdates.setIcon(View.getIcon("update16"));
miCheckUpdates.addActionListener(this);
JMenuItem miHelpUs = new JMenuItem(translate("menu.help.helpus"));
miHelpUs.setActionCommand("HELPUS");
miHelpUs.setIcon(View.getIcon("donate16"));
miHelpUs.addActionListener(this);
JMenuItem miHomepage = new JMenuItem(translate("menu.help.homepage"));
miHomepage.setActionCommand("HOMEPAGE");
miHomepage.setIcon(View.getIcon("homepage16"));
miHomepage.addActionListener(this);
menuHelp.add(miCheckUpdates);
menuHelp.add(miHelpUs);
menuHelp.add(miHomepage);
menuHelp.add(miAbout);
menuBar.add(menuHelp);
setJMenuBar(menuBar);
List