Files
jpexs-decompiler/src/com/jpexs/decompiler/flash/gui/MainPanel.java
2022-12-31 23:58:51 +01:00

5817 lines
235 KiB
Java

/*
* Copyright (C) 2010-2022 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.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.ApplicationInfo;
import com.jpexs.decompiler.flash.Bundle;
import com.jpexs.decompiler.flash.DecompilerPool;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.OpenableSourceInfo;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.SWF;
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.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.AbcMultiNameCollisionFixer;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationLevel;
import com.jpexs.decompiler.flash.abc.avm2.deobfuscation.DeobfuscationScope;
import com.jpexs.decompiler.flash.abc.types.ClassInfo;
import com.jpexs.decompiler.flash.abc.types.InstanceInfo;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.abc.types.traits.Trait;
import com.jpexs.decompiler.flash.abc.types.traits.TraitClass;
import com.jpexs.decompiler.flash.abc.types.traits.TraitFunction;
import com.jpexs.decompiler.flash.abc.types.traits.TraitMethodGetterSetter;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.configuration.ConfigurationItem;
import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener;
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
import com.jpexs.decompiler.flash.dumpview.DumpInfo;
import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode;
import com.jpexs.decompiler.flash.exporters.BinaryDataExporter;
import com.jpexs.decompiler.flash.exporters.FontExporter;
import com.jpexs.decompiler.flash.exporters.FrameExporter;
import com.jpexs.decompiler.flash.exporters.ImageExporter;
import com.jpexs.decompiler.flash.exporters.MorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.MovieExporter;
import com.jpexs.decompiler.flash.exporters.PreviewExporter;
import com.jpexs.decompiler.flash.exporters.ShapeExporter;
import com.jpexs.decompiler.flash.exporters.SoundExporter;
import com.jpexs.decompiler.flash.exporters.SymbolClassExporter;
import com.jpexs.decompiler.flash.exporters.TextExporter;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SpriteExportMode;
import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode;
import com.jpexs.decompiler.flash.exporters.modes.TextExportMode;
import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter;
import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter;
import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ScriptExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.SymbolClassExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings;
import com.jpexs.decompiler.flash.exporters.swf.SwfJavaExporter;
import com.jpexs.decompiler.flash.exporters.swf.SwfXmlExporter;
import com.jpexs.decompiler.flash.flexsdk.MxmlcAs3ScriptReplacer;
import com.jpexs.decompiler.flash.flv.FLVInputStream;
import com.jpexs.decompiler.flash.flv.FLVTAG;
import com.jpexs.decompiler.flash.flv.VIDEODATA;
import com.jpexs.decompiler.flash.gui.abc.ABCPanel;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.gui.abc.DecompiledEditorPane;
import com.jpexs.decompiler.flash.gui.abc.DeobfuscationDialog;
import com.jpexs.decompiler.flash.gui.action.ActionPanel;
import com.jpexs.decompiler.flash.gui.controls.JPersistentSplitPane;
import com.jpexs.decompiler.flash.gui.dumpview.DumpTree;
import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel;
import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel;
import com.jpexs.decompiler.flash.gui.editor.LineMarkedEditorPane;
import com.jpexs.decompiler.flash.gui.helpers.CollectionChangedAction;
import com.jpexs.decompiler.flash.gui.helpers.ObservableList;
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.gui.taglistview.TagListTree;
import com.jpexs.decompiler.flash.gui.taglistview.TagListTreeModel;
import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTree;
import com.jpexs.decompiler.flash.gui.tagtree.AbstractTagTreeModel;
import com.jpexs.decompiler.flash.gui.tagtree.FilteredTreeModel;
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeContextMenu;
import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel;
import com.jpexs.decompiler.flash.gui.tagtree.TreeRoot;
import com.jpexs.decompiler.flash.gui.timeline.TimelineViewPanel;
import com.jpexs.decompiler.flash.helpers.FileTextWriter;
import com.jpexs.decompiler.flash.helpers.Freed;
import com.jpexs.decompiler.flash.importers.AS2ScriptImporter;
import com.jpexs.decompiler.flash.importers.AS3ScriptImporter;
import com.jpexs.decompiler.flash.importers.As3ScriptReplacerFactory;
import com.jpexs.decompiler.flash.importers.As3ScriptReplacerInterface;
import com.jpexs.decompiler.flash.importers.BinaryDataImporter;
import com.jpexs.decompiler.flash.importers.FFDecAs3ScriptReplacer;
import com.jpexs.decompiler.flash.importers.ImageImporter;
import com.jpexs.decompiler.flash.importers.MovieImporter;
import com.jpexs.decompiler.flash.importers.ScriptImporterProgressListener;
import com.jpexs.decompiler.flash.importers.ShapeImporter;
import com.jpexs.decompiler.flash.importers.SoundImporter;
import com.jpexs.decompiler.flash.importers.SwfXmlImporter;
import com.jpexs.decompiler.flash.importers.SymbolClassImporter;
import com.jpexs.decompiler.flash.importers.TextImporter;
import com.jpexs.decompiler.flash.importers.svg.SvgImporter;
import com.jpexs.decompiler.flash.search.ABCSearchResult;
import com.jpexs.decompiler.flash.search.ActionSearchResult;
import com.jpexs.decompiler.flash.search.ScriptSearchResult;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG3Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsJPEG4Tag;
import com.jpexs.decompiler.flash.tags.DefineBitsTag;
import com.jpexs.decompiler.flash.tags.DefineButtonCxformTag;
import com.jpexs.decompiler.flash.tags.DefineButtonTag;
import com.jpexs.decompiler.flash.tags.DefineShape2Tag;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag;
import com.jpexs.decompiler.flash.tags.DoActionTag;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.EndTag;
import com.jpexs.decompiler.flash.tags.FileAttributesTag;
import com.jpexs.decompiler.flash.tags.JPEGTablesTag;
import com.jpexs.decompiler.flash.tags.MetadataTag;
import com.jpexs.decompiler.flash.tags.PlaceObject2Tag;
import com.jpexs.decompiler.flash.tags.PlaceObject3Tag;
import com.jpexs.decompiler.flash.tags.PlaceObjectTag;
import com.jpexs.decompiler.flash.tags.ProductInfoTag;
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.Tag;
import com.jpexs.decompiler.flash.tags.TagInfo;
import com.jpexs.decompiler.flash.tags.UnknownTag;
import com.jpexs.decompiler.flash.tags.VideoFrameTag;
import com.jpexs.decompiler.flash.tags.base.ASMSource;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
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.MissingCharacterHandler;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
import com.jpexs.decompiler.flash.tags.base.ShapeTag;
import com.jpexs.decompiler.flash.tags.base.SoundImportException;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag;
import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler;
import com.jpexs.decompiler.flash.tags.base.TextTag;
import com.jpexs.decompiler.flash.tags.base.UnsupportedSamplingRateException;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
import com.jpexs.decompiler.flash.tags.text.TextParseException;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Frame;
import com.jpexs.decompiler.flash.timeline.TagScript;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.decompiler.flash.treeitems.FolderItem;
import com.jpexs.decompiler.flash.treeitems.HeaderItem;
import com.jpexs.decompiler.flash.treeitems.Openable;
import com.jpexs.decompiler.flash.treeitems.OpenableList;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import com.jpexs.decompiler.flash.types.BUTTONRECORD;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.FILLSTYLE;
import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.decompiler.flash.types.sound.SoundFormat;
import com.jpexs.decompiler.flash.xfl.FLAVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.CancellableWorker;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.Path;
import com.jpexs.helpers.ProgressListener;
import com.jpexs.helpers.Reference;
import com.jpexs.helpers.SerializableImage;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
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.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JColorChooser;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import jsyntaxpane.DefaultSyntaxKit;
/**
*
* @author JPEXS
*/
public final class MainPanel extends JPanel implements TreeSelectionListener, SearchListener<TextTag>, Freed {
private final MainFrame mainFrame;
private final ObservableList<OpenableList> openables;
private final JPanel welcomePanel;
private final TimelineViewPanel timelineViewPanel;
private final MainFrameStatusPanel statusPanel;
private Thread taskThread;
private final MainFrameMenu mainMenu;
private final JProgressBar progressBar = new JProgressBar(0, 100);
public TagTree tagTree;
public FasterScrollPane tagTreeScrollPanel;
public DumpTree dumpTree;
public TagListTree tagListTree;
private ClipboardPanel resourcesClipboardPanel;
private ClipboardPanel tagListClipboardPanel;
private final FlashPlayerPanel flashPanel;
private final FlashPlayerPanel flashPanel2;
private final JPanel contentPanel;
private final JPanel displayPanel;
public FolderPreviewPanel folderPreviewPanel;
public FolderListPanel folderListPanel;
private boolean isWelcomeScreen = true;
private static final String CARDPREVIEWPANEL = "Preview card";
private static final String CARDFOLDERPREVIEWPANEL = "Folder preview card";
private static final String CARDFOLDERLISTPANEL = "Folder list card";
private static final String CARDEMPTYPANEL = "Empty card";
private static final String CARDDUMPVIEW = "Dump view";
private static final String CARDACTIONSCRIPTPANEL = "ActionScript card";
private static final String CARDACTIONSCRIPT3PANEL = "ActionScript3 card";
private static final String CARDHEADER = "Header card";
private static final String DETAILCARDAS3NAVIGATOR = "Traits list";
private static final String DETAILCARDTAGINFO = "Tag information";
private static final String DETAILCARDEMPTYPANEL = "Empty card";
private static final String SPLIT_PANE1 = "SPLITPANE1";
private static final String WELCOME_PANEL = "WELCOMEPANEL";
private static final String TIMELINE_PANEL = "TIMELINEPANEL";
private static final String RESOURCES_VIEW = "RESOURCES";
private static final String DUMP_VIEW = "DUMP";
private static final String TAGLIST_VIEW = "TAGLIST";
private static final String TIMELINE_VIEW = "TIMELINE";
private final JPersistentSplitPane splitPane1;
private final JPersistentSplitPane splitPane2;
private JPanel detailPanel;
private QuickTreeFindPanel quickTreeFindPanel;
private QuickTreeFindPanel quickTagListFindPanel;
private ABCPanel abcPanel;
private ActionPanel actionPanel;
private final PreviewPanel previewPanel;
private final HeaderInfoPanel headerPanel;
private DumpViewPanel dumpViewPanel;
private final JPanel treePanel;
private final PreviewPanel dumpPreviewPanel;
private final TagInfoPanel tagInfoPanel;
private TreePanelMode treePanelMode;
public TreeItem oldItem;
private int currentView = VIEW_RESOURCES;
public List<SearchResultsDialog> searchResultsDialogs = new ArrayList<>();
private TagTreeContextMenu contextPopupMenu;
private static final Logger logger = Logger.getLogger(MainPanel.class.getName());
private Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
private Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
private CalculateMissingNeededThread calculateMissingNeededThread;
private List<WeakReference<TreeItem>> orderedClipboard = new ArrayList<>();
private Map<TreeItem, Boolean> clipboard = new WeakHashMap<>();
private boolean clipboardCut = false;
private PinsPanel pinsPanel;
private List<List<String>> unfilteredTreeExpandedNodes = new ArrayList<>();
private List<List<String>> unfilteredTagListExpandedNodes = new ArrayList<>();
public void savePins() {
pinsPanel.save();
}
public void clearPins() {
pinsPanel.clear();
}
public void refreshPins() {
pinsPanel.refresh();
}
public void destroyPins() {
pinsPanel.destroy();
}
public void unpinItem(TreeItem item) {
pinsPanel.removeItem(item);
}
public void unpinOthers(TreeItem item) {
pinsPanel.removeOthers(item);
}
public void pinItem(TreeItem item) {
pinsPanel.pin(item);
}
public int getPinCount() {
return pinsPanel.getPinCount();
}
public boolean isPinned(TreeItem item) {
return pinsPanel.isPinned(item);
}
public void replaceItemPin(TreeItem oldItem, TreeItem newItem) {
pinsPanel.replaceItem(oldItem, newItem);
}
private void handleKeyReleased(KeyEvent e) {
if (checkEdited()) {
return;
}
Object source = e.getSource();
List<TreeItem> items = new ArrayList<>();
if (source == folderPreviewPanel) {
items.addAll(folderPreviewPanel.selectedItems.values());
} else if (source == folderListPanel) {
items.addAll(folderListPanel.selectedItems.values());
} else {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
TreePath[] paths = tree.getSelectionPaths();
if (paths != null) {
for (TreePath treePath : paths) {
TreeItem item = (TreeItem) treePath.getLastPathComponent();
items.add(item);
}
}
}
if (items.isEmpty()) {
return;
}
if ((e.getKeyCode() == KeyEvent.VK_UP
|| e.getKeyCode() == KeyEvent.VK_DOWN)
&& e.isAltDown() && !e.isControlDown() && !e.isShiftDown()) {
TreeItem item = items.get(0);
if (item instanceof Tag) {
if (((Tag) item).isReadOnly()) {
return;
}
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
contextPopupMenu.moveUpDown(item, true);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
contextPopupMenu.moveUpDown(item, false);
}
}
}
public void moveSwfListUpDown(TreeItem item, boolean up) {
OpenableList openableList = null;
if (item instanceof Openable) {
Openable openable = (Openable) item;
if (openable.getOpenableList() != null && !openable.getOpenableList().isBundle() && openable.getOpenableList().size() == 1) {
openableList = openable.getOpenableList();
} else {
return;
}
} else if (item instanceof OpenableList) {
openableList = (OpenableList) item;
} else {
return;
}
int index = openables.indexOf(openableList);
List<List<String>> expandedTagTree = View.getExpandedNodes(tagTree);
List<List<String>> expandedTagListTree = View.getExpandedNodes(tagListTree);
if (up) {
if (index <= 0) {
return;
}
openables.move(index, index - 1);
} else {
if (index < 0 || index >= openables.size() - 1) {
return;
}
openables.move(index, index + 2);
}
View.expandTreeNodes(tagTree, expandedTagTree);
View.expandTreeNodes(tagListTree, expandedTagListTree);
TreePath path = getCurrentTree().getFullModel().getTreePath(item);
getCurrentTree().setSelectionPath(path);
getCurrentTree().scrollPathToVisible(path);
repaintTree();
}
public void hideQuickTreeFind() {
quickTreeFindPanel.setVisible(false);
quickTagListFindPanel.setVisible(false);
}
private void handleKeyPressed(KeyEvent e) {
if (checkEdited()) {
return;
}
Object source = e.getSource();
List<TreeItem> items = new ArrayList<>();
if (source == folderPreviewPanel) {
items.addAll(folderPreviewPanel.selectedItems.values());
} else if (source == folderListPanel) {
items.addAll(folderListPanel.selectedItems.values());
} else {
AbstractTagTree tree = (AbstractTagTree) e.getSource();
TreePath[] paths = tree.getSelectionPaths();
if (paths != null) {
for (TreePath treePath : paths) {
TreeItem item = (TreeItem) treePath.getLastPathComponent();
items.add(item);
}
}
}
if (items.isEmpty()) {
return;
}
if ((e.getKeyCode() == 'G') && (e.isControlDown())) {
Openable openable = items.get(0).getOpenable();
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
}
if (swf != null) {
String val = "";
boolean valid;
int characterId = -1;
do {
val = ViewMessages.showInputDialog(MainPanel.this, translate("message.input.gotoCharacter"), translate("message.input.gotoCharacter.title"), val);
if (val == null) {
break;
}
try {
characterId = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
characterId = -1;
}
} while (characterId <= 0);
if (characterId > 0) {
CharacterTag tag = swf.getCharacter(characterId);
if (tag == null) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.character.notfound").replace("%characterid%", "" + characterId), translate("error"), JOptionPane.ERROR_MESSAGE);
} else {
setTagTreeSelectedNode(getCurrentTree(), tag);
}
}
}
return;
}
if ((e.getKeyCode() == 'F') && (e.isControlDown())) {
AbstractTagTree tree = getCurrentTree();
if (tree == tagTree) {
quickTreeFindPanel.setVisible(true);
}
if (tree == tagListTree) {
quickTagListFindPanel.setVisible(true);
}
}
if ((e.getKeyCode() == KeyEvent.VK_DELETE) && !e.isControlDown() && !e.isAltDown()) {
if (contextPopupMenu.canRemove(items)) {
contextPopupMenu.update(items);
contextPopupMenu.removeItemActionPerformed(null, e.isShiftDown());
}
}
if ((e.getKeyCode() == 'C' || e.getKeyCode() == 'X') && (e.isControlDown())) {
List<TreeItem> tagItems = new ArrayList<>();
for (TreeItem item:items) {
if (item instanceof TagScript) {
tagItems.add(((TagScript) item).getTag());
} else if (item instanceof Tag) {
tagItems.add((Tag) item);
}
}
boolean allWritable = true;
for (TreeItem item : tagItems) {
if (((Tag) item).isReadOnly()) {
allWritable = false;
break;
}
}
if (e.getKeyCode() == 'C') {
if (e.isShiftDown()) {
contextPopupMenu.copyTagToClipboardWithDependenciesActionPerformed(null, tagItems);
} else {
contextPopupMenu.copyTagToClipboardActionPerformed(null, tagItems);
}
}
if (e.getKeyCode() == 'X' && allWritable) {
contextPopupMenu.update(tagItems);
if (e.isShiftDown()) {
contextPopupMenu.cutTagToClipboardWithDependenciesActionPerformed(null);
} else {
contextPopupMenu.cutTagToClipboardActionPerformed(null);
}
}
repaintTree();
}
if (e.getKeyCode() == 'V' && e.isControlDown()) {
if (items.size() > 1) {
return;
}
TreeItem firstItem = items.get(0);
if (!((firstItem instanceof Tag) || (firstItem instanceof Frame))) {
return;
}
contextPopupMenu.update(items);
if (e.isShiftDown()) {
contextPopupMenu.pasteAfterActionPerformed(null);
} else {
contextPopupMenu.pasteBeforeActionPerformed(null);
}
}
}
public void gcClipboard() {
for (int i = orderedClipboard.size() - 1; i >= 0; i--) {
WeakReference<TreeItem> ref = orderedClipboard.get(i);
TreeItem item = ref.get();
if (item != null) {
if (item.getOpenable() == null) {
orderedClipboard.remove(i);
clipboard.remove(item);
}
}
}
resourcesClipboardPanel.update();
tagListClipboardPanel.update();
}
public void emptyClipboard() {
copyToClipboard(new ArrayList<>());
}
public void copyToClipboard(Collection<TreeItem> items) {
orderedClipboard.clear();
clipboard.clear();
for (TreeItem item : items) {
orderedClipboard.add(new WeakReference<>(item));
clipboard.put(item, true);
}
clipboardCut = false;
resourcesClipboardPanel.update();
tagListClipboardPanel.update();
resourcesClipboardPanel.flash();
tagListClipboardPanel.flash();
folderPreviewPanel.repaint();
}
public void cutToClipboard(Collection<TreeItem> items) {
copyToClipboard(items);
clipboardCut = true;
}
public boolean clipboardContains(TreeItem item) {
return clipboard.containsKey(item);
}
public boolean clipboardEmpty() {
return clipboard.isEmpty();
}
public int getClipboardSize() {
return clipboard.size();
}
public Set<TreeItem> getClipboardContents() {
Set<TreeItem> ret = new LinkedHashSet<>();
for (WeakReference<TreeItem> ref : orderedClipboard) {
TreeItem item = ref.get();
if (item != null) {
ret.add(item);
}
}
return ret;
}
public boolean isClipboardCut() {
return clipboardCut;
}
public boolean checkEdited() {
if (abcPanel != null && abcPanel.isEditing()) {
abcPanel.tryAutoSave();
}
if (actionPanel != null && actionPanel.isEditing()) {
actionPanel.tryAutoSave();
}
if (previewPanel.isEditing()) {
previewPanel.tryAutoSave();
}
if (headerPanel.isEditing()) {
headerPanel.tryAutoSave();
}
return (abcPanel != null && abcPanel.isEditing())
|| (actionPanel != null && actionPanel.isEditing())
|| previewPanel.isEditing() || headerPanel.isEditing();
}
private class MyTreeSelectionModel extends DefaultTreeSelectionModel {
@Override
public void addSelectionPath(TreePath path) {
if (checkEdited()) {
return;
}
super.addSelectionPath(path);
}
@Override
public void addSelectionPaths(TreePath[] paths) {
if (checkEdited()) {
return;
}
super.addSelectionPaths(paths);
}
@Override
public void setSelectionPath(TreePath path) {
if (checkEdited()) {
return;
}
super.setSelectionPath(path);
}
@Override
public void setSelectionPaths(TreePath[] pPaths) {
if (checkEdited()) {
return;
}
super.setSelectionPaths(pPaths);
}
@Override
public void clearSelection() {
if (checkEdited()) {
return;
}
super.clearSelection();
}
public void setSelection(TreePath[] selection) {
if (checkEdited()) {
return;
}
this.selection = selection;
}
@Override
public void removeSelectionPath(TreePath path) {
if (checkEdited()) {
return;
}
super.removeSelectionPath(path);
}
@Override
public void removeSelectionPaths(TreePath[] paths) {
if (checkEdited()) {
return;
}
super.removeSelectionPaths(paths);
}
}
public TagTreeContextMenu getContextPopupMenu() {
return contextPopupMenu;
}
public void setPercent(int percent) {
View.checkAccess();
progressBar.setValue(percent);
progressBar.setVisible(true);
}
public void hidePercent() {
View.checkAccess();
if (progressBar.isVisible()) {
progressBar.setVisible(false);
}
}
public MainFrame getMainFrame() {
return mainFrame;
}
static {
try {
File.createTempFile("temp", ".swf").delete(); //First call to this is slow, so make it first
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
public void updateMenu() {
mainMenu.updateComponents();
}
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) {
statusPanel.setStatus(s);
}
public void setEditingStatus() {
statusPanel.setStatus(translate(Configuration.autoSaveTagModifications.get() ? "status.editing.autosave" : "status.editing"));
}
public void clearEditingStatus() {
statusPanel.setStatus("");
}
public void setWorkStatus(String s, CancellableWorker worker) {
statusPanel.setWorkStatus(s, worker);
mainMenu.updateComponents();
}
public CancellableWorker getCurrentWorker() {
return statusPanel.getCurrentWorker();
}
private JPanel createWelcomePanel() {
JPanel welcomePanel = new JPanel();
welcomePanel.setLayout(new BoxLayout(welcomePanel, BoxLayout.Y_AXIS));
JLabel welcomeToLabel = new JLabel(translate("startup.welcometo"));
welcomeToLabel.setFont(welcomeToLabel.getFont().deriveFont(40));
welcomeToLabel.setAlignmentX(0.5f);
JPanel appNamePanel = new JPanel(new FlowLayout());
JLabel jpLabel = new JLabel("JPEXS ");
jpLabel.setAlignmentX(0.5f);
jpLabel.setForeground(new Color(0, 0, 160));
jpLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
jpLabel.setHorizontalAlignment(SwingConstants.CENTER);
appNamePanel.add(jpLabel);
JLabel ffLabel = new JLabel("Free Flash ");
ffLabel.setAlignmentX(0.5f);
ffLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
ffLabel.setHorizontalAlignment(SwingConstants.CENTER);
appNamePanel.add(ffLabel);
JLabel decLabel = new JLabel("Decompiler");
decLabel.setAlignmentX(0.5f);
decLabel.setForeground(Color.red);
decLabel.setFont(new Font("Tahoma", Font.BOLD, 50));
decLabel.setHorizontalAlignment(SwingConstants.CENTER);
appNamePanel.add(decLabel);
appNamePanel.setAlignmentX(0.5f);
welcomePanel.add(Box.createGlue());
welcomePanel.add(welcomeToLabel);
welcomePanel.add(appNamePanel);
JLabel startLabel = new JLabel(translate("startup.selectopen"));
startLabel.setAlignmentX(0.5f);
startLabel.setFont(startLabel.getFont().deriveFont(30));
welcomePanel.add(startLabel);
welcomePanel.add(Box.createGlue());
return welcomePanel;
}
private JPanel createFolderPreviewCard() {
JPanel folderPreviewCard = new JPanel(new BorderLayout());
folderPreviewPanel = new FolderPreviewPanel(this, new ArrayList<>());
FasterScrollPane folderPreviewScrollPane = new FasterScrollPane(folderPreviewPanel);
folderPreviewCard.add(folderPreviewScrollPane, BorderLayout.CENTER);
folderPreviewPanel.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
return folderPreviewCard;
}
private JPanel createFolderListCard() {
JPanel folderListCard = new JPanel(new BorderLayout());
folderListPanel = new FolderListPanel(this, new ArrayList<>());
folderListCard.add(new FasterScrollPane(folderListPanel), BorderLayout.CENTER);
folderListPanel.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
return folderListCard;
}
private JPanel createDumpPreviewCard() {
JPanel dumpViewCard = new JPanel(new BorderLayout());
dumpViewPanel = new DumpViewPanel(dumpTree);
dumpViewCard.add(new FasterScrollPane(dumpViewPanel), BorderLayout.CENTER);
return dumpViewCard;
}
public String translate(String key) {
return mainFrame.translate(key);
}
public MainPanel(MainFrame mainFrame, MainFrameMenu mainMenu, FlashPlayerPanel flashPanel, FlashPlayerPanel previewFlashPanel) {
super();
this.mainFrame = mainFrame;
this.mainMenu = mainMenu;
this.flashPanel = flashPanel;
this.flashPanel2 = previewFlashPanel;
mainFrame.setTitle(ApplicationInfo.applicationVerName);
setLayout(new BorderLayout());
openables = new ObservableList<>();
detailPanel = new JPanel();
detailPanel.setLayout(new CardLayout());
JPanel whitePanel = new JPanel();
if (View.isOceanic()) {
whitePanel.setBackground(Color.white);
}
detailPanel.add(whitePanel, DETAILCARDEMPTYPANEL);
tagInfoPanel = new TagInfoPanel(this);
detailPanel.add(tagInfoPanel, DETAILCARDTAGINFO);
UIManager.getDefaults().put("TreeUI", BasicTreeUI.class.getName());
tagTree = new TagTree(null, this);
tagTree.addTreeSelectionListener(this);
tagTree.setSelectionModel(new MyTreeSelectionModel());
tagListTree = new TagListTree(null, this);
tagListTree.addTreeSelectionListener(this);
tagListTree.setSelectionModel(new MyTreeSelectionModel());
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(tagTree, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() {
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
dge.startDrag(DragSource.DefaultCopyDrop, new Transferable() {
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DataFlavor.javaFileListFlavor};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DataFlavor.javaFileListFlavor);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (flavor.equals(DataFlavor.javaFileListFlavor)) {
List<File> files;
String tempDir = System.getProperty("java.io.tmpdir");
if (!tempDir.endsWith(File.separator)) {
tempDir += File.separator;
}
Random rnd = new Random();
tempDir += "ffdec" + File.separator + "export" + File.separator + System.currentTimeMillis() + "_" + rnd.nextInt(1000);
File fTempDir = new File(tempDir);
Path.createDirectorySafe(fTempDir);
File ftemp = new File(tempDir);
ExportDialog exd = new ExportDialog(Main.getDefaultDialogsOwner(), null);
try {
files = exportSelection(null, new GuiAbortRetryIgnoreHandler(), tempDir, exd);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
return null;
}
files.clear();
File[] fs = ftemp.listFiles();
files.addAll(Arrays.asList(fs));
Main.stopWork();
for (File f : files) {
f.deleteOnExit();
}
new File(tempDir).deleteOnExit();
return files;
}
return null;
}
}, new DragSourceListener() {
@Override
public void dragEnter(DragSourceDragEvent dsde) {
enableDrop(false);
}
@Override
public void dragOver(DragSourceDragEvent dsde) {
}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {
}
@Override
public void dragExit(DragSourceEvent dse) {
}
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {
enableDrop(true);
}
});
}
});
List<AbstractTagTree> trees = new ArrayList<>();
trees.add(tagTree);
trees.add(tagListTree);
contextPopupMenu = new TagTreeContextMenu(trees, this);
dumpTree = new DumpTree(null, this);
dumpTree.addTreeSelectionListener(this);
dumpTree.createContextMenu();
currentView = Configuration.lastView.get();
statusPanel = new MainFrameStatusPanel(this);
add(statusPanel, BorderLayout.SOUTH);
displayPanel = new JPanel(new CardLayout());
DefaultSyntaxKit.initKit();
previewPanel = new PreviewPanel(this, flashPanel);
dumpPreviewPanel = new PreviewPanel(this, previewFlashPanel);
dumpPreviewPanel.setReadOnly(true);
displayPanel.add(previewPanel, CARDPREVIEWPANEL);
displayPanel.add(createFolderPreviewCard(), CARDFOLDERPREVIEWPANEL);
displayPanel.add(createFolderListCard(), CARDFOLDERLISTPANEL);
displayPanel.add(createDumpPreviewCard(), CARDDUMPVIEW);
headerPanel = new HeaderInfoPanel(this);
displayPanel.add(headerPanel, CARDHEADER);
displayPanel.add(new JPanel(), CARDEMPTYPANEL);
showCard(CARDEMPTYPANEL);
LazyCardLayout treePanelLayout = new LazyCardLayout();
treePanelLayout.registerLayout(createResourcesViewCard(), RESOURCES_VIEW);
treePanelLayout.registerLayout(createDumpViewCard(), DUMP_VIEW);
treePanelLayout.registerLayout(createTagListViewCard(), TAGLIST_VIEW);
treePanel = new JPanel(treePanelLayout);
//treePanel.add(searchPanel, BorderLayout.SOUTH);
//searchPanel.setVisible(false);
JPanel rightPanel = new JPanel(new BorderLayout());
rightPanel.add(displayPanel, BorderLayout.CENTER);
pinsPanel = new PinsPanel(this);
pinsPanel.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
TreeItem item = pinsPanel.getCurrent();
if ((getCurrentTree() == tagListTree) && (item instanceof TagScript)) {
item = ((TagScript) item).getTag();
}
setTagTreeSelectedNode(getCurrentTree(), item);
}
});
rightPanel.add(pinsPanel, BorderLayout.NORTH);
//displayPanel.setBorder(BorderFactory.createLineBorder(Color.black));
splitPane2 = new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, treePanel, detailPanel, Configuration.guiSplitPane2DividerLocationPercent);
splitPane1 = new JPersistentSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitPane2, rightPanel, Configuration.guiSplitPane1DividerLocationPercent);
welcomePanel = createWelcomePanel();
add(welcomePanel, BorderLayout.CENTER);
timelineViewPanel = new TimelineViewPanel();
contentPanel = new JPanel(new CardLayout());
contentPanel.add(welcomePanel, WELCOME_PANEL);
contentPanel.add(splitPane1, SPLIT_PANE1);
contentPanel.add(timelineViewPanel, TIMELINE_PANEL);
add(contentPanel);
showContentPanelCard(WELCOME_PANEL);
tagTree.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
tagListTree.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
handleKeyReleased(e);
}
@Override
public void keyPressed(KeyEvent e) {
handleKeyPressed(e);
}
});
detailPanel.setVisible(false);
updateUi();
this.openables.addCollectionChangedListener((e) -> {
AbstractTagTreeModel ttm = tagTree.getFullModel();
if (ttm != null) {
if (getCurrentSwf() == null) {
tagTree.clearSelection();
}
ttm.updateSwfs(e);
tagTree.expandRoot();
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
if (e.getAction() == CollectionChangedAction.RESET) {
tagTree.expandFirstLevelNodes();
} else if (e.getAction() == CollectionChangedAction.ADD) {
OpenableList list = e.getNewItem();
if (!list.isBundle() && list.items.size() == 1) {
tagTree.expandPath(tagTree.getFullModel().getTreePath(list.get(0)));
} else {
tagTree.expandPath(tagTree.getFullModel().getTreePath(list));
}
}
}
}
ttm = tagListTree.getFullModel();
if (ttm != null) {
if (getCurrentSwf() == null) {
tagListTree.clearSelection();
}
ttm.updateSwfs(e);
tagListTree.expandRoot();
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
if (e.getAction() == CollectionChangedAction.RESET) {
tagListTree.expandFirstLevelNodes();
} else if (e.getAction() == CollectionChangedAction.ADD) {
OpenableList list = e.getNewItem();
if (!list.isBundle() && list.items.size() == 1) {
tagListTree.expandPath(tagListTree.getFullModel().getTreePath(list.get(0)));
} else {
tagListTree.expandPath(tagListTree.getFullModel().getTreePath(list));
}
}
}
}
DumpTreeModel dtm = dumpTree.getModel();
if (dtm != null) {
List<List<String>> expandedNodes = View.getExpandedNodes(dumpTree);
dtm.updateSwfs();
View.expandTreeNodes(dumpTree, expandedNodes);
dumpTree.expandRoot();
if (Configuration.expandFirstLevelOfTreeOnLoad.get()) {
if (e.getAction() == CollectionChangedAction.RESET) {
dumpTree.expandFirstLevelNodes();
} else if (e.getAction() == CollectionChangedAction.ADD) {
OpenableList list = e.getNewItem();
for (Openable dopenable : list) {
if (dopenable instanceof SWF) {
dumpTree.expandSwfNode((SWF) dopenable);
}
}
}
}
}
if (openables.isEmpty()) {
tagTree.setUI(new BasicTreeUI() {
{
setHashColor(Color.gray);
}
});
dumpTree.setUI(new BasicTreeUI() {
{
setHashColor(Color.gray);
}
});
tagListTree.setUI(new BasicTreeUI() {
{
setHashColor(Color.gray);
}
});
}
});
//Opening files with drag&drop to main window
enableDrop(true);
calculateMissingNeededThread = new CalculateMissingNeededThread();
calculateMissingNeededThread.start();
pinsPanel.load();
Configuration.flattenASPackages.addListener(new ConfigurationItemChangeListener<Boolean>() {
@Override
public void configurationItemChanged(Boolean newValue) {
resetAllTimelines();
refreshTree();
}
});
}
public void resetAllTimelines() {
List<OpenableList> openableLists = new ArrayList<>(openables);
List<SWF> allSwfs = new ArrayList<>();
for (OpenableList openableList : openableLists) {
for (Openable openable : openableList) {
if (openable instanceof SWF) {
allSwfs.add((SWF) openable);
}
}
for (Openable openable : openableList) {
if (openable instanceof SWF) {
Main.populateSwfs((SWF) openable, allSwfs);
}
}
}
for (SWF swf : allSwfs) {
swf.resetTimeline();
}
}
public void loadSwfAtPos(OpenableList newSwfs, int index) {
View.checkAccess();
OpenableList oldSwfList = openables.get(index);
List<SWF> allSwfs = new ArrayList<>();
for (Openable o : oldSwfList.items) {
if (o instanceof SWF) {
allSwfs.add((SWF) o);
Main.populateSwfs((SWF) o, allSwfs);
}
}
List<List<String>> expandedNodes = View.getExpandedNodes(tagTree);
previewPanel.clear();
openables.set(index, newSwfs);
for (SWF s : allSwfs) {
s.clearTagSwfs();
Main.searchResultsStorage.destroySwf(s);
}
Openable openable = newSwfs.size() > 0 ? newSwfs.get(0) : null;
if (openable != null) {
updateUi(openable);
}
gcClipboard();
reload(false);
View.expandTreeNodes(tagTree, expandedNodes);
doFilter();
pinsPanel.load();
}
public void load(OpenableList newOpenables, boolean first) {
View.checkAccess();
List<List<String>> expandedNodes = View.getExpandedNodes(getCurrentTree());
previewPanel.clear();
openables.add(newOpenables);
Openable openable = newOpenables.size() > 0 ? newOpenables.get(0) : null;
if (openable != null) {
updateUi(openable);
}
gcClipboard();
reload(false);
View.expandTreeNodes(getCurrentTree(), expandedNodes);
doFilter();
pinsPanel.load();
}
public ABCPanel getABCPanel() {
if (abcPanel == null) {
abcPanel = new ABCPanel(this);
displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL);
detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR);
}
return abcPanel;
}
public ActionPanel getActionPanel() {
if (actionPanel == null) {
actionPanel = new ActionPanel(MainPanel.this);
displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL);
}
return actionPanel;
}
private void updateUi(final Openable openable) {
View.checkAccess();
if (isWelcomeScreen) {
showContentPanelCard(SPLIT_PANE1);
isWelcomeScreen = false;
}
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
List<ABCContainerTag> abcList = swf.getAbcList();
boolean hasAbc = !abcList.isEmpty();
if (hasAbc) {
getABCPanel().setAbc(abcList.get(0).getABC());
}
}
mainMenu.updateComponents(openable);
if (taskThread != null) {
taskThread.interrupt();
}
if (Configuration._debugMode.get() && swf != null) {
final SWF fSwf = swf;
Thread t = new Thread() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
DecompilerPool d = fSwf.getDecompilerPool();
statusPanel.setStatus(fSwf.getFileTitle() + " " + d.getStat());
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
break;
}
}
}
};
t.start();
taskThread = t;
}
}
private void updateUi() {
View.checkAccess();
if (!isWelcomeScreen && openables.isEmpty()) {
showContentPanelCard(WELCOME_PANEL);
isWelcomeScreen = true;
quickTagListFindPanel.setVisible(false);
quickTreeFindPanel.setVisible(false);
doFilter();
}
mainFrame.setTitle(ApplicationInfo.applicationVerName);
mainMenu.updateComponents(null);
showView(getCurrentView());
}
private boolean closeConfirmation(OpenableList swfList) {
View.checkAccess();
String message = swfList == null
? translate("message.confirm.closeAll")
: translate("message.confirm.close").replace("{swfName}", swfList.toString());
return ViewMessages.showConfirmDialog(this, message, translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, Configuration.showCloseConfirmation, JOptionPane.OK_OPTION) == JOptionPane.OK_OPTION;
}
public boolean isModified() {
for (OpenableList openableList : openables) {
for (Openable openable : openableList) {
if (openable.isModified()) {
return true;
}
}
}
return false;
}
public boolean closeAll(boolean showCloseConfirmation, boolean onExit) {
View.checkAccess();
if (showCloseConfirmation && isModified()) {
boolean closeConfirmResult = closeConfirmation(openables.size() == 1 ? openables.get(0) : null);
if (!closeConfirmResult) {
return false;
}
}
clearPins();
List<OpenableList> swfsLists = new ArrayList<>(openables);
for (SearchResultsDialog sr : searchResultsDialogs) {
sr.setVisible(false);
}
searchResultsDialogs.clear();
openables.clear();
oldItem = null;
clear();
updateUi();
List<SWF> swfsToClose = new ArrayList<>();
for (OpenableList openableList : swfsLists) {
for (Openable openable : openableList) {
if (openable instanceof SWF) {
swfsToClose.add((SWF) openable);
}
}
for (Openable openable : openableList) {
if (openable instanceof SWF) {
Main.populateSwfs((SWF) openable, swfsToClose);
}
}
}
for (SWF swf : swfsToClose) {
swf.clearTagSwfs();
if (!onExit) {
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(swf.getShortPathTitle());
if (cc != null) {
cc.setCustomData(CustomConfigurationKeys.KEY_LOADED_IMPORT_ASSETS, "");
}
}
}
refreshTree();
gcClipboard();
mainMenu.updateComponents(null);
previewPanel.clear();
return true;
}
public boolean close(OpenableList openableList) {
View.checkAccess();
boolean modified = false;
for (Openable openable : openableList) {
if (openable.isModified()) {
modified = true;
}
}
if (modified) {
boolean closeConfirmResult = closeConfirmation(openableList);
if (!closeConfirmResult) {
return false;
}
}
List<SWF> swfsToClose = new ArrayList<>();
for (Openable openable : openableList) {
if (openable instanceof SWF) {
swfsToClose.add((SWF) openable);
}
}
for (Openable openable : openableList) {
if (openable instanceof SWF) {
Main.populateSwfs((SWF) openable, swfsToClose);
}
}
for (int i = 0; i < searchResultsDialogs.size(); i++) {
SearchResultsDialog sr = searchResultsDialogs.get(i);
for (SWF swf : swfsToClose) {
sr.removeSwf(swf);
}
if (sr.isEmpty()) {
sr.setVisible(false);
searchResultsDialogs.remove(i);
i--;
}
}
for (SWF swf : swfsToClose) {
Main.searchResultsStorage.destroySwf(swf);
pinsPanel.removeOpenable(swf);
SwfSpecificCustomConfiguration cc = Configuration.getSwfSpecificCustomConfiguration(swf.getShortPathTitle());
if (cc != null) {
cc.setCustomData(CustomConfigurationKeys.KEY_LOADED_IMPORT_ASSETS, "");
}
}
openables.remove(openableList);
oldItem = null;
clear();
updateUi();
for (SWF swf : swfsToClose) {
swf.clearTagSwfs();
}
refreshTree();
gcClipboard();
mainMenu.updateComponents(null);
previewPanel.clear();
dumpPreviewPanel.clear();
return true;
}
private void enableDrop(boolean value) {
if (value) {
setDropTarget(new DropTarget() {
@Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
@SuppressWarnings("unchecked")
List<File> droppedFiles = (List<File>) dtde.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
if (!droppedFiles.isEmpty()) {
OpenableSourceInfo[] sourceInfos = new OpenableSourceInfo[droppedFiles.size()];
for (int i = 0; i < droppedFiles.size(); i++) {
sourceInfos[i] = new OpenableSourceInfo(null, droppedFiles.get(i).getAbsolutePath(), null);
}
Main.openFile(sourceInfos, null);
}
} catch (UnsupportedFlavorException | IOException ex) {
}
}
});
} else {
setDropTarget(null);
}
}
public void updateClassesList() {
String selectionPath = getCurrentTree().getSelectionPathString();
List<TreeItem> nodes = getASTreeNodes(tagTree);
boolean updateNeeded = false;
for (TreeItem n : nodes) {
if (n instanceof ClassesListTreeModel) {
((ClassesListTreeModel) n).update();
updateNeeded = true;
}
}
refreshTree();
if (updateNeeded) {
tagTree.updateUI();
}
TreePath tp = getCurrentTree().getTreePathFromString(selectionPath);
if (tp != null) {
getCurrentTree().setSelectionPath(tp);
}
}
private boolean isFilterEmpty(String filter) {
return filter.trim().length() < 3;
}
private void doFilter(AbstractTagTree tree, QuickTreeFindPanel findPanel, List<List<String>> unfilteredExpandedNodes) {
TreeModel model = tree.getModel();
String oldFilter = "";
if (model instanceof FilteredTreeModel) {
oldFilter = ((FilteredTreeModel) model).getFilter();
}
String newFilter = findPanel.getFilter();
if (isFilterEmpty(oldFilter)) {
unfilteredExpandedNodes.clear();;
unfilteredExpandedNodes.addAll(View.getExpandedNodes(tree));
}
if (oldFilter.trim().equals(newFilter.trim())) {
return;
}
TreePath selectionPaths[] = tree.getSelectionPaths();
tree.setModel(new FilteredTreeModel(newFilter, tree.getFullModel(), tree));
if (!isFilterEmpty(newFilter)) {
for (int i = 0; i < tree.getRowCount(); i++) {
tree.expandRow(i);
}
} else {
tree.setModel(tree.getFullModel());
View.expandTreeNodes(tree, unfilteredExpandedNodes);
}
tree.setSelectionPaths(selectionPaths);
}
public void doFilter() {
View.checkAccess();
doFilter(tagTree, quickTreeFindPanel, unfilteredTreeExpandedNodes);
doFilter(tagListTree, quickTagListFindPanel, unfilteredTagListExpandedNodes);
}
public void renameIdentifier(SWF swf, String identifier) throws InterruptedException {
String oldName = identifier;
String newName = ViewMessages.showInputDialog(this, translate("rename.enternew"), oldName);
if (newName != null) {
if (!oldName.equals(newName)) {
swf.renameAS2Identifier(oldName, newName);
ViewMessages.showMessageDialog(this, translate("rename.finished.identifier"));
updateClassesList();
reload(true);
}
}
}
public void renameMultiname(List<ABCContainerTag> abcList, int multiNameIndex) {
String oldName = "";
AVM2ConstantPool constants = getABCPanel().abc.constants;
if (constants.getMultiname(multiNameIndex).name_index > 0) {
oldName = constants.getString(constants.getMultiname(multiNameIndex).name_index);
}
String newName = ViewMessages.showInputDialog(this, translate("rename.enternew"), oldName);
if (newName != null) {
if (!oldName.equals(newName)) {
int mulCount = 0;
for (ABCContainerTag cnt : abcList) {
ABC abc = cnt.getABC();
for (int m = 1; m < abc.constants.getMultinameCount(); m++) {
int ni = abc.constants.getMultiname(m).name_index;
String n = "";
if (ni > 0) {
n = abc.constants.getString(ni);
}
if (n.equals(oldName)) {
abc.renameMultiname(m, newName);
mulCount++;
}
}
}
int fmulCount = mulCount;
View.execInEventDispatch(() -> {
ViewMessages.showMessageDialog(this, translate("rename.finished.multiname").replace("%count%", Integer.toString(fmulCount)));
if (abcPanel != null) {
abcPanel.reload();
}
updateClassesList();
reload(true);
ABCPanel abcPanel = getABCPanel();
abcPanel.hilightScript(abcPanel.getSwf(), abcPanel.decompiledTextArea.getScriptLeaf().getClassPath().toRawString());
});
}
}
}
public List<TreeItem> getASTreeNodes(TagTree tree) {
List<TreeItem> result = new ArrayList<>();
TagTreeModel tm = (TagTreeModel) tree.getModel();
if (tm == null) {
return result;
}
TreeItem root = tm.getRoot();
for (int i = 0; i < tm.getChildCount(root); i++) {
// first level node can be SWF and SWFBundle
TreeItem node = tm.getChild(root, i);
if (node instanceof Bundle) {
for (int j = 0; j < tm.getChildCount(node); j++) {
// child of SWFBundle should be SWF
SWF swfNode = (SWF) tm.getChild(node, j);
result.add(tm.getScriptsNode(swfNode));
}
} else if (node instanceof SWF) {
SWF swfNode = (SWF) tm.getChild(root, i);
result.add(tm.getScriptsNode(swfNode));
}
}
return result;
}
public boolean confirmExperimental() {
View.checkAccess();
return ViewMessages.showConfirmDialog(this, translate("message.confirm.experimental"), translate("message.warning"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION;
}
private List<TreeItem> getSelection(Openable openable, List<TreeItem> selection) {
if (currentView == MainPanel.VIEW_RESOURCES) {
return selection == null ? tagTree.getSelection(openable) : tagTree.getSelectionAndAllSubs(openable, selection);
} else if (currentView == MainPanel.VIEW_TAGLIST) {
return selection == null ? tagListTree.getSelection(openable) : tagListTree.getSelectionAndAllSubs(openable, selection);
}
return new ArrayList<>();
}
public List<File> exportSelection(List<TreeItem> selection, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
List<File> ret = new ArrayList<>();
List<TreeItem> sel = getSelection(null, selection);
Set<Openable> usedOpenables = new HashSet<>();
for (TreeItem d : sel) {
Openable selectedNodeOpenable = d.getOpenable();
if (!usedOpenables.contains(selectedNodeOpenable)) {
usedOpenables.add(selectedNodeOpenable);
}
}
Map<String, Integer> usedSwfsIds = new HashMap<>();
for (Openable openable : usedOpenables) {
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
} else {
swf = ((ABC) openable).getSwf();
}
List<ScriptPack> as3scripts = new ArrayList<>();
List<Tag> images = new ArrayList<>();
List<Tag> shapes = new ArrayList<>();
List<Tag> morphshapes = new ArrayList<>();
List<Tag> sprites = new ArrayList<>();
List<Tag> buttons = new ArrayList<>();
List<Tag> movies = new ArrayList<>();
List<Tag> sounds = new ArrayList<>();
List<Tag> texts = new ArrayList<>();
List<TreeItem> as12scripts = new ArrayList<>();
List<Tag> binaryData = new ArrayList<>();
Map<Integer, List<Integer>> frames = new HashMap<>();
List<Tag> fonts = new ArrayList<>();
List<Tag> symbolNames = new ArrayList<>();
for (TreeItem d : sel) {
Openable selectedNodeSwf = d.getOpenable();
if (selectedNodeSwf != openable) {
continue;
}
if (d instanceof TagScript) {
Tag tag = ((TagScript) d).getTag();
if (tag instanceof DoActionTag || tag instanceof DoInitActionTag) {
as12scripts.add(d);
}
}
if (d instanceof Tag || d instanceof ASMSource) {
TreeNodeType nodeType = TagTree.getTreeNodeType(d);
if (nodeType == TreeNodeType.IMAGE) {
images.add((Tag) d);
}
if (nodeType == TreeNodeType.SHAPE) {
shapes.add((Tag) d);
}
if (nodeType == TreeNodeType.BUTTON) {
buttons.add((Tag) d);
}
if (nodeType == TreeNodeType.MORPH_SHAPE) {
morphshapes.add((Tag) d);
}
if (nodeType == TreeNodeType.SPRITE) {
sprites.add((Tag) d);
}
if ((nodeType == TreeNodeType.AS)
|| (nodeType == TreeNodeType.AS_FRAME)
|| (nodeType == TreeNodeType.AS_BUTTON)
|| (nodeType == TreeNodeType.AS_CLIP)
|| (nodeType == TreeNodeType.AS_INIT)
|| (nodeType == TreeNodeType.AS_CLASS)) {
as12scripts.add(d);
}
if (nodeType == TreeNodeType.MOVIE) {
movies.add((Tag) d);
}
if (nodeType == TreeNodeType.SOUND) {
sounds.add((Tag) d);
}
if (nodeType == TreeNodeType.BINARY_DATA) {
binaryData.add((Tag) d);
}
if (nodeType == TreeNodeType.TEXT) {
texts.add((Tag) d);
}
if (nodeType == TreeNodeType.FONT) {
fonts.add((Tag) d);
}
if (nodeType == TreeNodeType.OTHER_TAG) {
if (d instanceof SymbolClassTypeTag) {
symbolNames.add((Tag) d);
}
}
}
if (d instanceof Frame) {
Frame fn = (Frame) d;
Timelined parent = fn.timeline.timelined;
int frame = fn.frame;
int parentId = 0;
if (parent instanceof CharacterTag) {
parentId = ((CharacterTag) parent).getCharacterId();
}
if (!frames.containsKey(parentId)) {
frames.put(parentId, new ArrayList<>());
}
frames.get(parentId).add(frame);
}
if (d instanceof ScriptPack) {
as3scripts.add((ScriptPack) d);
}
}
for (Tag sprite : sprites) {
frames.put(((DefineSpriteTag) sprite).getCharacterId(), null);
}
String selFile2;
if (usedOpenables.size() > 1) {
selFile2 = selFile + File.separator + Helper.getNextId(openable.getTitleOrShortFileName(), usedSwfsIds);
} else {
selFile2 = selFile;
}
EventListener evl = swf.getExportEventListener();
if (export.isOptionEnabled(ImageExportMode.class)) {
ret.addAll(new ImageExporter().exportImages(handler, selFile2 + File.separator + ImageExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(images),
new ImageExportSettings(export.getValue(ImageExportMode.class)), evl));
}
if (export.isOptionEnabled(ShapeExportMode.class)) {
ret.addAll(new ShapeExporter().exportShapes(handler, selFile2 + File.separator + ShapeExportSettings.EXPORT_FOLDER_NAME, swf, new ReadOnlyTagList(shapes),
new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl, export.getZoom()));
}
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile2 + File.separator + MorphShapeExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(morphshapes),
new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl));
}
if (export.isOptionEnabled(TextExportMode.class)) {
ret.addAll(new TextExporter().exportTexts(handler, selFile2 + File.separator + TextExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(texts),
new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl));
}
if (export.isOptionEnabled(MovieExportMode.class)) {
ret.addAll(new MovieExporter().exportMovies(handler, selFile2 + File.separator + MovieExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(movies),
new MovieExportSettings(export.getValue(MovieExportMode.class)), evl));
}
if (export.isOptionEnabled(SoundExportMode.class)) {
ret.addAll(new SoundExporter().exportSounds(handler, selFile2 + File.separator + SoundExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(sounds),
new SoundExportSettings(export.getValue(SoundExportMode.class)), evl));
}
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile2 + File.separator + BinaryDataExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(binaryData),
new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl));
}
if (export.isOptionEnabled(FontExportMode.class)) {
ret.addAll(new FontExporter().exportFonts(handler, selFile2 + File.separator + FontExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts),
new FontExportSettings(export.getValue(FontExportMode.class)), evl));
}
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
ret.addAll(new SymbolClassExporter().exportNames(handler, selFile2 + File.separator + SymbolClassExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(symbolNames),
new SymbolClassExportSettings(export.getValue(SymbolClassExportMode.class)), evl));
}
FrameExporter frameExporter = new FrameExporter();
if (export.isOptionEnabled(FrameExportMode.class)) {
FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom());
if (frames.containsKey(0)) {
String subFolder = FrameExportSettings.EXPORT_FOLDER_NAME;
ret.addAll(frameExporter.exportFrames(handler, selFile2 + File.separator + subFolder, swf, 0, frames.get(0), fes, evl));
}
}
if (export.isOptionEnabled(SpriteExportMode.class)) {
SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom());
for (Entry<Integer, List<Integer>> entry : frames.entrySet()) {
int containerId = entry.getKey();
if (containerId != 0) {
String subFolder = SpriteExportSettings.EXPORT_FOLDER_NAME;
ret.addAll(frameExporter.exportSpriteFrames(handler, selFile2 + File.separator + subFolder, swf, containerId, entry.getValue(), ses, evl));
}
}
}
if (export.isOptionEnabled(ButtonExportMode.class)) {
ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom());
for (Tag tag : buttons) {
ButtonTag button = (ButtonTag) tag;
String subFolder = ButtonExportSettings.EXPORT_FOLDER_NAME;
ret.addAll(frameExporter.exportButtonFrames(handler, selFile2 + File.separator + subFolder, swf, button.getCharacterId(), null, bes, evl));
}
}
if (export.isOptionEnabled(ScriptExportMode.class)) {
if (as3scripts.size() > 0 || as12scripts.size() > 0) {
boolean parallel = Configuration.parallelSpeedUp.get();
String scriptsFolder = Path.combine(selFile2, ScriptExportSettings.EXPORT_FOLDER_NAME);
Path.createDirectorySafe(new File(scriptsFolder));
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
if (parallel && singleScriptFile) {
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
singleScriptFile = false;
}
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile, false);
String singleFileName = Path.combine(scriptsFolder, openable.getShortFileName() + scriptExportSettings.getFileExtension());
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
scriptExportSettings.singleFileWriter = writer;
if (swf.isAS3()) {
ret.addAll(new AS3ScriptExporter().exportActionScript3(swf, handler, scriptsFolder, as3scripts, scriptExportSettings, parallel, evl));
} else {
Map<String, ASMSource> asmsToExport = swf.getASMs(true, as12scripts, false);
ret.addAll(new AS2ScriptExporter().exportAS2Scripts(handler, scriptsFolder, asmsToExport, scriptExportSettings, parallel, evl));
}
}
}
}
}
return ret;
}
public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
boolean exportAll = false;
if (exportAll) {
exportAllDebug(swf, handler, selFile, export);
return;
}
EventListener evl = swf.getExportEventListener();
if (export.isOptionEnabled(ImageExportMode.class)) {
new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new ImageExportSettings(export.getValue(ImageExportMode.class)), evl);
}
if (export.isOptionEnabled(ShapeExportMode.class)) {
new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME), swf, swf.getTags(),
new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl, export.getZoom());
}
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl);
}
if (export.isOptionEnabled(TextExportMode.class)) {
new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl);
}
if (export.isOptionEnabled(MovieExportMode.class)) {
new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new MovieExportSettings(export.getValue(MovieExportMode.class)), evl);
}
if (export.isOptionEnabled(SoundExportMode.class)) {
new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new SoundExportSettings(export.getValue(SoundExportMode.class)), evl);
}
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl);
}
if (export.isOptionEnabled(FontExportMode.class)) {
new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new FontExportSettings(export.getValue(FontExportMode.class)), evl);
}
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
new SymbolClassExporter().exportNames(handler, Path.combine(selFile, SymbolClassExportSettings.EXPORT_FOLDER_NAME), swf.getTags(),
new SymbolClassExportSettings(export.getValue(SymbolClassExportMode.class)), evl);
}
FrameExporter frameExporter = new FrameExporter();
if (export.isOptionEnabled(FrameExportMode.class)) {
FrameExportSettings fes = new FrameExportSettings(export.getValue(FrameExportMode.class), export.getZoom());
frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME), swf, 0, null, fes, evl);
}
if (export.isOptionEnabled(SpriteExportMode.class)) {
SpriteExportSettings ses = new SpriteExportSettings(export.getValue(SpriteExportMode.class), export.getZoom());
for (CharacterTag c : swf.getCharacters().values()) {
if (c instanceof DefineSpriteTag) {
frameExporter.exportSpriteFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, ses, evl);
}
}
}
if (export.isOptionEnabled(ButtonExportMode.class)) {
ButtonExportSettings bes = new ButtonExportSettings(export.getValue(ButtonExportMode.class), export.getZoom());
for (CharacterTag c : swf.getCharacters().values()) {
if (c instanceof ButtonTag) {
frameExporter.exportButtonFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME), swf, c.getCharacterId(), null, bes, evl);
}
}
}
if (export.isOptionEnabled(ScriptExportMode.class)) {
boolean parallel = Configuration.parallelSpeedUp.get();
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME);
Path.createDirectorySafe(new File(scriptsFolder));
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
if (parallel && singleScriptFile) {
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
singleScriptFile = false;
}
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), singleScriptFile, false);
String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension());
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
scriptExportSettings.singleFileWriter = writer;
swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl);
}
}
}
public void exportAllDebug(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException, InterruptedException {
EventListener evl = swf.getExportEventListener();
if (export.isOptionEnabled(ImageExportMode.class)) {
for (ImageExportMode exportMode : ImageExportMode.values()) {
new ImageExporter().exportImages(handler, Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new ImageExportSettings(exportMode), evl);
}
}
if (export.isOptionEnabled(ShapeExportMode.class)) {
for (ShapeExportMode exportMode : ShapeExportMode.values()) {
new ShapeExporter().exportShapes(handler, Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, swf.getTags(),
new ShapeExportSettings(exportMode, export.getZoom()), evl, export.getZoom());
}
}
if (export.isOptionEnabled(MorphShapeExportMode.class)) {
for (MorphShapeExportMode exportMode : MorphShapeExportMode.values()) {
new MorphShapeExporter().exportMorphShapes(handler, Path.combine(selFile, MorphShapeExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new MorphShapeExportSettings(exportMode, export.getZoom()), evl);
}
}
if (export.isOptionEnabled(TextExportMode.class)) {
for (TextExportMode exportMode : TextExportMode.values()) {
new TextExporter().exportTexts(handler, Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new TextExportSettings(exportMode, Configuration.textExportSingleFile.get(), export.getZoom()), evl);
}
}
if (export.isOptionEnabled(MovieExportMode.class)) {
for (MovieExportMode exportMode : MovieExportMode.values()) {
new MovieExporter().exportMovies(handler, Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new MovieExportSettings(exportMode), evl);
}
}
if (export.isOptionEnabled(SoundExportMode.class)) {
for (SoundExportMode exportMode : SoundExportMode.values()) {
new SoundExporter().exportSounds(handler, Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new SoundExportSettings(exportMode), evl);
}
}
if (export.isOptionEnabled(BinaryDataExportMode.class)) {
for (BinaryDataExportMode exportMode : BinaryDataExportMode.values()) {
new BinaryDataExporter().exportBinaryData(handler, Path.combine(selFile, BinaryDataExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new BinaryDataExportSettings(exportMode), evl);
}
}
if (export.isOptionEnabled(FontExportMode.class)) {
for (FontExportMode exportMode : FontExportMode.values()) {
new FontExporter().exportFonts(handler, Path.combine(selFile, FontExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new FontExportSettings(exportMode), evl);
}
}
if (export.isOptionEnabled(SymbolClassExportMode.class)) {
for (SymbolClassExportMode exportMode : SymbolClassExportMode.values()) {
new SymbolClassExporter().exportNames(handler, Path.combine(selFile, SymbolClassExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf.getTags(),
new SymbolClassExportSettings(exportMode), evl);
}
}
FrameExporter frameExporter = new FrameExporter();
if (export.isOptionEnabled(FrameExportMode.class)) {
for (FrameExportMode exportMode : FrameExportMode.values()) {
FrameExportSettings fes = new FrameExportSettings(exportMode, export.getZoom());
frameExporter.exportFrames(handler, Path.combine(selFile, FrameExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, 0, null, fes, evl);
}
}
if (export.isOptionEnabled(SpriteExportMode.class)) {
for (SpriteExportMode exportMode : SpriteExportMode.values()) {
SpriteExportSettings ses = new SpriteExportSettings(exportMode, export.getZoom());
for (CharacterTag c : swf.getCharacters().values()) {
if (c instanceof DefineSpriteTag) {
frameExporter.exportSpriteFrames(handler, Path.combine(selFile, SpriteExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, ses, evl);
}
}
}
}
if (export.isOptionEnabled(ButtonExportMode.class)) {
for (ButtonExportMode exportMode : ButtonExportMode.values()) {
ButtonExportSettings bes = new ButtonExportSettings(exportMode, export.getZoom());
for (CharacterTag c : swf.getCharacters().values()) {
if (c instanceof ButtonTag) {
frameExporter.exportButtonFrames(handler, Path.combine(selFile, ButtonExportSettings.EXPORT_FOLDER_NAME, exportMode.name()), swf, c.getCharacterId(), null, bes, evl);
}
}
}
}
if (export.isOptionEnabled(ScriptExportMode.class)) {
boolean parallel = Configuration.parallelSpeedUp.get();
for (ScriptExportMode exportMode : ScriptExportMode.values()) {
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME, exportMode.name());
Path.createDirectorySafe(new File(scriptsFolder));
boolean singleScriptFile = Configuration.scriptExportSingleFile.get();
if (parallel && singleScriptFile) {
logger.log(Level.WARNING, AppStrings.translate("export.script.singleFilePallelModeWarning"));
singleScriptFile = false;
}
ScriptExportSettings scriptExportSettings = new ScriptExportSettings(exportMode, singleScriptFile, false);
String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension());
try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) {
scriptExportSettings.singleFileWriter = writer;
swf.exportActionScript(handler, scriptsFolder, scriptExportSettings, parallel, evl);
}
}
}
}
public List<OpenableList> getSwfs() {
return openables;
}
public OpenableList getCurrentSwfList() {
SWF swf = getCurrentSwf();
if (swf == null) {
return null;
}
return swf.openableList;
}
public Openable getCurrentOpenable() {
if (openables == null || openables.isEmpty()) {
return null;
}
if (treePanelMode == TreePanelMode.TAG_TREE) {
TreeItem treeNode = (TreeItem) tagTree.getLastSelectedPathComponent();
if (treeNode == null || treeNode instanceof OpenableList) {
return null;
}
return treeNode.getOpenable();
} else if (treePanelMode == TreePanelMode.DUMP_TREE) {
DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent();
if (dumpInfo == null) {
return null;
}
return DumpInfoSwfNode.getSwfNode(dumpInfo).getOpenable();
} else if (treePanelMode == TreePanelMode.TAGLIST_TREE) {
TreeItem treeNode = (TreeItem) tagListTree.getLastSelectedPathComponent();
if (treeNode == null || treeNode instanceof OpenableList) {
return null;
}
return treeNode.getOpenable();
}
return null;
}
public SWF getCurrentSwf() {
Openable openable = getCurrentOpenable();
if (openable instanceof SWF) {
return (SWF) openable;
}
return null;
}
public AbstractTagTree getCurrentTree() {
if (currentView == VIEW_RESOURCES) {
return tagTree;
}
if (currentView == VIEW_TAGLIST) {
return tagListTree;
}
return tagTree; //???
}
public void gotoFrame(int frame) {
View.checkAccess();
TreeItem treeItem = (TreeItem) getCurrentTree().getLastSelectedPathComponent();
if (treeItem == null) {
return;
}
if (treeItem instanceof Timelined) {
Timelined t = (Timelined) treeItem;
Frame f = tagTree.getFullModel().getFrame((SWF) treeItem.getOpenable(), t, frame);
if (f != null) {
setTagTreeSelectedNode(getCurrentTree(), f);
}
}
}
public void gotoScriptLine(SWF swf, String scriptName, int line, int classIndex, int traitIndex, int methodIndex) {
View.checkAccess();
gotoScriptName(swf, scriptName);
if (abcPanel != null) {
if (Main.isDebugPCode()) {
if (classIndex != -1) {
boolean classChanged = false;
if (abcPanel.decompiledTextArea.getClassIndex() != classIndex) {
abcPanel.decompiledTextArea.setClassIndex(classIndex);
classChanged = true;
}
if (traitIndex != -10 && (classChanged || abcPanel.decompiledTextArea.lastTraitIndex != traitIndex)) {
abcPanel.decompiledTextArea.gotoTrait(traitIndex);
}
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.gotoInstrLine(line);
} else {
abcPanel.decompiledTextArea.gotoLine(line);
}
} else if (actionPanel != null) {
if (Main.isDebugPCode()) {
actionPanel.editor.gotoLine(line);
} else {
actionPanel.decompiledEditor.gotoLine(line);
}
}
refreshBreakPoints();
}
public void refreshBreakPoints() {
if (abcPanel != null) {
abcPanel.decompiledTextArea.refreshMarkers();
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.refreshMarkers();
}
if (actionPanel != null) {
actionPanel.decompiledEditor.refreshMarkers();
actionPanel.editor.refreshMarkers();
}
}
/*
public void debuggerBreakAt(SWF swf, String cls, int line) {
View.execInEventDispatchLater(new Runnable() {
@Override
public void run() {
gotoClassLine(swf, cls, line);
if (abcPanel != null) {
abcPanel.decompiledTextArea.addColorMarker(line, DecompiledEditorPane.FG_IP_COLOR, DecompiledEditorPane.BG_IP_COLOR, DecompiledEditorPane.PRIORITY_IP);
}
}
});
}*/
public void gotoScriptName(SWF swf, String scriptName) {
View.checkAccess();
if (swf == null) {
return;
}
if (swf.isAS3()) {
String rawScriptName = scriptName;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring(rawScriptName.indexOf(';') + 1);
}
List<ABCContainerTag> abcList = swf.getAbcList();
if (!abcList.isEmpty()) {
ABCPanel abcPanel = getABCPanel();
abcPanel.setAbc(abcList.get(0).getABC());
abcPanel.hilightScript(swf, rawScriptName);
}
} else {
String rawScriptName = scriptName;
if (rawScriptName.startsWith("#PCODE ")) {
rawScriptName = rawScriptName.substring("#PCODE ".length());
}
Map<String, ASMSource> asms = swf.getASMs(true);
if (actionPanel != null && asms.containsKey(rawScriptName)) {
actionPanel.setSource(asms.get(rawScriptName), true);
}
}
}
public void gotoDocumentClass(SWF swf) {
View.checkAccess();
if (swf == null) {
return;
}
String documentClass = swf.getDocumentClass();
if (documentClass != null && currentView != VIEW_DUMP) {
List<ABCContainerTag> abcList = swf.getAbcList();
if (!abcList.isEmpty()) {
ABCPanel abcPanel = getABCPanel();
for (ABCContainerTag c : abcList) {
if (c.getABC().findClassByName(documentClass) > -1) {
abcPanel.setAbc(c.getABC());
abcPanel.hilightScript(swf, documentClass);
break;
}
}
}
}
}
public void disableDecompilationChanged() {
View.checkAccess();
clearAllScriptCache();
if (abcPanel != null) {
abcPanel.reload();
}
updateClassesList();
}
private void clearAllScriptCache() {
for (OpenableList openableList : openables) {
for (Openable openable : openableList) {
if (openable instanceof SWF) {
((SWF) openable).clearScriptCache();
}
}
}
}
public Set<SWF> getAllSwfs() {
List<SWF> allSwfs = new ArrayList<>();
for (OpenableList slist : getSwfs()) {
for (Openable o : slist.items) {
if (o instanceof SWF) {
allSwfs.add((SWF) o);
Main.populateSwfs((SWF) o, allSwfs);
}
}
}
return new LinkedHashSet<>(allSwfs);
}
public Set<Openable> getAllOpenablesAndSwfs() {
List<Openable> allOpenables = new ArrayList<>();
for (OpenableList slist : getSwfs()) {
for (Openable o : slist.items) {
allOpenables.add(o);
if (o instanceof SWF) {
List<SWF> subSwfs = new ArrayList<>();
Main.populateSwfs((SWF) o, subSwfs);
for (SWF swf : subSwfs) {
allOpenables.add(swf);
}
}
}
}
return new LinkedHashSet<>(allOpenables);
}
private List<TreeItem> getAllSelected() {
if (currentView == VIEW_RESOURCES) {
return tagTree.getAllSelected();
}
if (currentView == VIEW_TAGLIST) {
return tagListTree.getAllSelected();
}
return new ArrayList<>();
}
private List<TreeItem> getSelected() {
if (currentView == VIEW_RESOURCES) {
return tagTree.getSelected();
}
if (currentView == VIEW_TAGLIST) {
return tagListTree.getSelected();
}
return new ArrayList<>();
}
public void searchInActionScriptOrText(Boolean searchInText, Openable openable, boolean useSelection) {
View.checkAccess();
/*if (!(openable instanceof SWF)) { //FIXME for ABCs
return;
}*/
SWF swf = (openable instanceof SWF) ? (SWF) openable : ((ABC) openable).getSwf();
Map<Openable, List<ScriptPack>> scopeAs3 = new LinkedHashMap<>();
Map<SWF, Map<String, ASMSource>> swfToAllASMSourceMap = new HashMap<>();
Map<SWF, Map<String, ASMSource>> scopeAs12 = new LinkedHashMap<>();
Set<Openable> openablesUsed = new LinkedHashSet<>();
List<TreeItem> allItems = getAllSelected();
for (TreeItem t : allItems) {
if (t instanceof ScriptPack) {
ScriptPack sp = (ScriptPack) t;
Openable s = sp.getOpenable(); //Fixme for ABCs
if (!scopeAs3.containsKey(s)) {
scopeAs3.put(s, new ArrayList<>());
}
scopeAs3.get(s).add(sp);
openablesUsed.add(s);
}
ASMSource as = null;
if (t instanceof ASMSource) {
as = (ASMSource) t;
} else if (t instanceof TagScript) {
TagScript ts = (TagScript) t;
if (ts.getTag() instanceof ASMSource) {
as = (ASMSource) ts.getTag();
}
}
if (as != null) {
SWF s = as.getSourceTag().getSwf();
String asId = null;
Map<String, ASMSource> allSources;
if (swfToAllASMSourceMap.containsKey(s)) {
allSources = swfToAllASMSourceMap.get(s);
} else {
allSources = s.getASMs(false);
swfToAllASMSourceMap.put(s, allSources);
}
for (String path : allSources.keySet()) {
if (allSources.get(path) == as) {
asId = path;
break;
}
}
if (!scopeAs12.containsKey(s)) {
scopeAs12.put(s, new LinkedHashMap<>());
}
scopeAs12.get(s).put(asId, as);
openablesUsed.add(s);
}
}
List<TreeItem> items = getSelected();
String selected;
if (scopeAs12.isEmpty() && scopeAs3.isEmpty()) {
selected = null;
} else if (items.size() == 1) {
selected = items.get(0).toString();
} else if (items.isEmpty()) {
selected = null;
} else {
selected = AppDialog.translateForDialog("scope.selection.items", SearchDialog.class).replace("%count%", "" + items.size());
}
SearchDialog searchDialog = new SearchDialog(getMainFrame().getWindow(), false, selected, useSelection, openable instanceof ABC);
if (searchInText != null) {
if (searchInText) {
searchDialog.searchInTextsRadioButton.setSelected(true);
} else {
searchDialog.searchInASRadioButton.setSelected(true);
}
}
if (searchDialog.showDialog() == AppDialog.OK_OPTION) {
final String txt = searchDialog.searchField.getText();
if (!txt.isEmpty()) {
if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_CURRENT_FILE) {
scopeAs3.clear();
scopeAs12.clear();
if (swf.isAS3()) {
List<ScriptPack> packs = new ArrayList<>();
if (openable instanceof SWF) {
packs = ((SWF) openable).getAS3Packs();
} else {
ABC abc = (ABC) openable;
List<ABC> allAbcs = new ArrayList<>();
allAbcs.add(abc);
packs = abc.getScriptPacks(null, allAbcs);
}
scopeAs3.put(openable, packs);
} else {
scopeAs12.put((SWF) openable, swf.getASMs(false));
}
openablesUsed.clear();
openablesUsed.add(openable);
}
if (searchDialog.getCurrentScope() == SearchDialog.SCOPE_ALL_FILES) {
Set<Openable> allOpenables = getAllOpenablesAndSwfs();
for (Openable s : allOpenables) {
SWF ss = (s instanceof SWF) ? (SWF) s : ((ABC) s).getSwf();
if (ss.isAS3()) {
List<ScriptPack> packs = new ArrayList<>();
if (s instanceof SWF) {
packs = ((SWF) s).getAS3Packs();
} else {
ABC abc = (ABC) s;
List<ABC> allAbcs = new ArrayList<>();
allAbcs.add(abc);
packs = abc.getScriptPacks(null, allAbcs);
}
scopeAs3.put(s, packs);
} else {
scopeAs12.put(ss, ss.getASMs(false));
}
}
openablesUsed.clear();
openablesUsed.addAll(allOpenables);
}
if (!scopeAs3.isEmpty()) {
getABCPanel();
}
if (!scopeAs12.isEmpty()) {
getActionPanel();
}
boolean ignoreCase = searchDialog.ignoreCaseCheckBox.isSelected();
boolean regexp = searchDialog.regexpCheckBox.isSelected();
boolean scriptSearch = searchDialog.searchInASRadioButton.isSelected()
|| searchDialog.searchInPCodeRadioButton.isSelected();
if (scriptSearch) {
boolean pCodeSearch = searchDialog.searchInPCodeRadioButton.isSelected();
new CancellableWorker<Void>() {
@Override
protected Void doInBackground() throws Exception {
List<ScriptSearchResult> fResult = new ArrayList<>();
for (Openable s : openablesUsed) {
if (scopeAs3.containsKey(s)) {
List<ABCSearchResult> abcResult = getABCPanel().search(s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs3.get(s));
fResult.addAll(abcResult);
if (!abcResult.isEmpty()) {
Main.searchResultsStorage.addABCResults(s, txt, ignoreCase, regexp, abcResult);
}
}
if (scopeAs12.containsKey(s)) {
List<ActionSearchResult> actionResult = getActionPanel().search((SWF) s, txt, ignoreCase, regexp, pCodeSearch, this, scopeAs12.get(s));
fResult.addAll(actionResult);
if (!actionResult.isEmpty()) {
Main.searchResultsStorage.addActionResults((SWF) s, txt, ignoreCase, regexp, actionResult);
}
}
}
Main.searchResultsStorage.finishGroup();
View.execInEventDispatch(() -> {
boolean found = false;
found = true;
List<SearchListener<ScriptSearchResult>> listeners = new ArrayList<>();
listeners.add(getABCPanel());
listeners.add(getActionPanel());
SearchResultsDialog<ScriptSearchResult> sr = new SearchResultsDialog<>(getMainFrame().getWindow(), txt, ignoreCase, regexp, listeners);
sr.setResults(fResult);
sr.setVisible(true);
searchResultsDialogs.add(sr);
if (!found) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
Main.stopWork();
});
return null;
}
@Override
protected void done() {
View.execInEventDispatch(() -> {
Main.stopWork();
});
}
}.execute();
} else if (searchDialog.searchInTextsRadioButton.isSelected()) {
new CancellableWorker<Void>() {
@Override
protected Void doInBackground() throws Exception {
List<TextTag> textResult;
SearchPanel<TextTag> textSearchPanel = previewPanel.getTextPanel().getSearchPanel();
textSearchPanel.setOptions(ignoreCase, regexp);
textResult = searchText(txt, ignoreCase, regexp, swf);
List<TextTag> fTextResult = textResult;
View.execInEventDispatch(() -> {
textSearchPanel.setSearchText(txt);
boolean found = textSearchPanel.setResults(fTextResult);
if (!found) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.search.notfound").replace("%searchtext%", txt), translate("message.search.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
Main.stopWork();
});
return null;
}
@Override
protected void done() {
View.execInEventDispatch(() -> {
Main.stopWork();
});
}
}.execute();
}
}
}
}
public void replaceText() {
SearchDialog replaceDialog = new SearchDialog(getMainFrame().getWindow(), true, null, false, false);
if (replaceDialog.showDialog() == AppDialog.OK_OPTION) {
final String txt = replaceDialog.searchField.getText();
if (!txt.isEmpty()) {
final SWF swf = getCurrentSwf();
new CancellableWorker() {
@Override
protected Void doInBackground() throws Exception {
int findCount = 0;
boolean ignoreCase = replaceDialog.ignoreCaseCheckBox.isSelected();
boolean regexp = replaceDialog.regexpCheckBox.isSelected();
String replacement = replaceDialog.replaceField.getText();
if (!regexp) {
replacement = Matcher.quoteReplacement(replacement);
}
Pattern pat;
if (regexp) {
pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
} else {
pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
}
List<TextTag> textTags = new ArrayList<>();
for (Tag tag : swf.getTags()) {
if (tag instanceof TextTag) {
textTags.add((TextTag) tag);
}
}
for (TextTag textTag : textTags) {
if (!replaceDialog.replaceInParametersCheckBox.isSelected()) {
List<String> texts = textTag.getTexts();
boolean found = false;
for (int i = 0; i < texts.size(); i++) {
String text = texts.get(i);
if (pat.matcher(text).find()) {
texts.set(i, text.replaceAll(txt, replacement));
found = true;
findCount++;
}
}
if (found) {
String[] textArray = texts.toArray(new String[texts.size()]);
textTag.setFormattedText(getMissingCharacterHandler(), textTag.getFormattedText(false).text, textArray);
}
} else {
String text = textTag.getFormattedText(false).text;
if (pat.matcher(text).find()) {
textTag.setFormattedText(getMissingCharacterHandler(), text.replaceAll(txt, replacement), null);
findCount++;
}
}
}
if (findCount > 0) {
swf.clearImageCache();
repaintTree();
}
return null;
}
}.execute();
}
}
}
private List<TextTag> searchText(String txt, boolean ignoreCase, boolean regexp, SWF swf) {
if (txt != null && !txt.isEmpty()) {
List<TextTag> found = new ArrayList<>();
Pattern pat;
if (regexp) {
pat = Pattern.compile(txt, ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
} else {
pat = Pattern.compile(Pattern.quote(txt), ignoreCase ? (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE) : 0);
}
for (Tag tag : swf.getTags()) {
if (tag instanceof TextTag) {
TextTag textTag = (TextTag) tag;
if (pat.matcher(textTag.getFormattedText(false).text).find()) {
found.add(textTag);
}
}
}
return found;
}
return null;
}
@Override
public void updateSearchPos(String searchedText, boolean ignoreCase, boolean regExp, TextTag item) {
View.checkAccess();
setTagTreeSelectedNode(getCurrentTree(), item);
previewPanel.getTextPanel().updateSearchPos();
}
private void setDumpTreeSelectedNode(DumpInfo dumpInfo) {
DumpTreeModel dtm = (DumpTreeModel) dumpTree.getModel();
TreePath tp = dtm.getDumpInfoPath(dumpInfo);
if (tp != null) {
dumpTree.setSelectionPath(tp);
dumpTree.scrollPathToVisible(tp);
} else {
showCard(CARDEMPTYPANEL);
}
}
public void setTagTreeSelectedNode(AbstractTagTree tree, TreeItem treeItem) {
AbstractTagTreeModel ttm = tree.getFullModel();
TreePath tp = ttm.getTreePath(treeItem);
if (tp != null) {
tree.setSelectionPath(tp);
tree.scrollPathToVisible(tp);
} else {
showCard(CARDEMPTYPANEL);
}
}
public void autoDeobfuscateChanged() {
Helper.decompilationErrorAdd = AppStrings.translate(Configuration.autoDeobfuscate.get() ? "deobfuscation.comment.failed" : "deobfuscation.comment.tryenable");
clearAllScriptCache();
if (abcPanel != null) {
abcPanel.reload();
}
reload(true);
updateClassesList();
}
public void renameColliding(final Openable openable) {
View.checkAccess();
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
}
//FIXME for ABCs
if (swf == null) {
return;
}
final SWF fswf = swf;
if (confirmExperimental()) {
new CancellableWorker<Integer>() {
@Override
protected Integer doInBackground() throws Exception {
AbcMultiNameCollisionFixer fixer = new AbcMultiNameCollisionFixer();
return fixer.fixCollisions(fswf);
}
@Override
protected void onStart() {
Main.startWork(translate("work.renaming.identifiers") + "...", this);
}
@Override
protected void done() {
View.execInEventDispatch(() -> {
try {
int cnt = get();
Main.stopWork();
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt)));
fswf.assignClassesToSymbols();
fswf.clearScriptCache();
if (abcPanel != null) {
abcPanel.reload();
}
updateClassesList();
reload(true);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during renaming identifiers", ex);
Main.stopWork();
ViewMessages.showMessageDialog(MainPanel.this, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
}
});
}
}.execute();
}
}
public void renameOneIdentifier(final SWF swf) {
View.checkAccess();
if (swf == null) {
return;
}
FileAttributesTag fileAttributes = swf.getFileAttributes();
if (fileAttributes != null && fileAttributes.actionScript3) {
final int multiName = getABCPanel().decompiledTextArea.getMultinameUnderCaret(new Reference<ABC>(null));
final List<ABCContainerTag> abcList = swf.getAbcList();
if (multiName > 0) {
new CancellableWorker() {
@Override
public Void doInBackground() throws Exception {
renameMultiname(abcList, multiName);
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.renaming") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
}
}.execute();
} else {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.notfound.multiname"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
} else {
final String identifier = getActionPanel().getStringUnderCursor();
if (identifier != null) {
new CancellableWorker() {
@Override
public Void doInBackground() throws Exception {
try {
renameIdentifier(swf, identifier);
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, null, ex);
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.renaming") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
}
}.execute();
} else {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.notfound.identifier"), translate("message.rename.notfound.title"), JOptionPane.INFORMATION_MESSAGE);
}
}
}
public void exportFla(final SWF swf) {
if (swf == null) {
return;
}
JFileChooser fc = new JFileChooser();
String selDir = Configuration.lastOpenDir.get();
fc.setCurrentDirectory(new File(selDir));
if (!selDir.endsWith(File.separator)) {
selDir += File.separator;
}
String swfShortName = swf.getShortFileName();
if ("".equals(swfShortName)) {
swfShortName = "untitled.swf";
}
String fileName;
if (swfShortName.contains(".")) {
fileName = swfShortName.substring(0, swfShortName.lastIndexOf(".")) + ".fla";
} else {
fileName = swfShortName + ".fla";
}
final String fSwfShortName = swfShortName;
fc.setSelectedFile(new File(selDir + fileName));
List<FileFilter> flaFilters = new ArrayList<>();
List<FileFilter> xflFilters = new ArrayList<>();
List<FLAVersion> versions = new ArrayList<>();
boolean isAS3 = swf.isAS3();
for (int i = FLAVersion.values().length - 1; i >= 0; i--) {
final FLAVersion v = FLAVersion.values()[i];
if (!isAS3 && v.minASVersion() > 2) {
// This version does not support AS1/2
} else {
versions.add(v);
FileFilter f = new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".fla"));
}
@Override
public String getDescription() {
return translate("filter.fla").replace("%version%", v.applicationName());
}
};
if (v == FLAVersion.CS6) {
fc.setFileFilter(f);
} else {
fc.addChoosableFileFilter(f);
}
flaFilters.add(f);
f = new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory() || (f.getName().toLowerCase(Locale.ENGLISH).endsWith(".xfl"));
}
@Override
public String getDescription() {
return translate("filter.xfl").replace("%version%", v.applicationName());
}
};
fc.addChoosableFileFilter(f);
xflFilters.add(f);
}
}
fc.setAcceptAllFileFilterUsed(false);
if (fc.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
Configuration.lastOpenDir.set(Helper.fixDialogFile(fc.getSelectedFile()).getParentFile().getAbsolutePath());
File sf = Helper.fixDialogFile(fc.getSelectedFile());
FileFilter selectedFilter = fc.getFileFilter();
final boolean compressed = flaFilters.contains(selectedFilter);
String path = sf.getAbsolutePath();
if (path.endsWith(".fla") || path.endsWith(".xfl")) {
path = path.substring(0, path.length() - 4);
}
path += compressed ? ".fla" : ".xfl";
final FLAVersion selectedVersion = versions.get(compressed ? flaFilters.indexOf(selectedFilter) : xflFilters.indexOf(selectedFilter));
final File selfile = new File(path);
new CancellableWorker() {
@Override
protected Void doInBackground() throws Exception {
Helper.freeMem();
try {
AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler();
if (compressed) {
swf.exportFla(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion);
} else {
swf.exportXfl(errorHandler, selfile.getAbsolutePath(), fSwfShortName, ApplicationInfo.APPLICATION_NAME, ApplicationInfo.applicationVerName, ApplicationInfo.version, Configuration.parallelSpeedUp.get(), selectedVersion);
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "FLA export error", ex);
ViewMessages.showMessageDialog(MainPanel.this, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);
}
Helper.freeMem();
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.exporting.fla") + "...", this);
}
@Override
protected void done() {
if (Configuration.openFolderAfterFlaExport.get()) {
try {
Desktop.getDesktop().open(selfile.getAbsoluteFile().getParentFile());
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
Main.stopWork();
}
}.execute();
}
}
public void importMovie(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importMovies2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportMovieInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
previewPanel.clear();
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File moviesDir = new File(Path.combine(selFile, MovieExportSettings.EXPORT_FOLDER_NAME));
if (!moviesDir.exists()) {
moviesDir = new File(selFile);
}
final File fMoviesDir = moviesDir;
MovieImporter movieImporter = new MovieImporter();
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int count = 0;
@Override
public Void doInBackground() throws Exception {
try {
count = movieImporter.bulkImport(fMoviesDir, swf, false);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during import", ex);
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.importing") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
refreshTree(swf);
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.movie.result").replace("%count%", Integer.toString(count)));
if (count != 0) {
reload(true);
}
});
}
}.execute();
}
}
public void importSound(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSounds2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSoundInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
previewPanel.clear();
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File soundsDir = new File(Path.combine(selFile, SoundExportSettings.EXPORT_FOLDER_NAME));
if (!soundsDir.exists()) {
soundsDir = new File(selFile);
}
final File fSoundsDir = soundsDir;
SoundImporter soundImporter = new SoundImporter();
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int count = 0;
@Override
public Void doInBackground() throws Exception {
try {
count = soundImporter.bulkImport(fSoundsDir, swf, false);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during import", ex);
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.importing") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
refreshTree(swf);
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.sound.result").replace("%count%", Integer.toString(count)));
if (count != 0) {
reload(true);
}
});
}
}.execute();
}
}
public void importShape(final SWF swf, boolean noFill) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importShapes2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportShapeInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File shapesDir = new File(Path.combine(selFile, ShapeExportSettings.EXPORT_FOLDER_NAME));
if (!shapesDir.exists()) {
shapesDir = new File(selFile);
}
final File fShapesDir = shapesDir;
ShapeImporter shapeImporter = new ShapeImporter();
SvgImporter svgImporter = new SvgImporter();
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int count = 0;
@Override
public Void doInBackground() throws Exception {
try {
count = shapeImporter.bulkImport(fShapesDir, swf, noFill, false);
swf.clearImageCache();
swf.clearShapeCache();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during import", ex);
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.importing") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
refreshTree(swf);
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.shape.result").replace("%count%", Integer.toString(count)));
if (count != 0) {
reload(true);
}
});
}
}.execute();
}
}
public void importImage(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importImages2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportImageInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File imagesDir = new File(Path.combine(selFile, ImageExportSettings.EXPORT_FOLDER_NAME));
if (!imagesDir.exists()) {
imagesDir = new File(selFile);
}
final File fImagesDir = imagesDir;
ImageImporter imageImporter = new ImageImporter();
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int count = 0;
@Override
public Void doInBackground() throws Exception {
try {
count = imageImporter.bulkImport(fImagesDir, swf, false);
swf.clearImageCache();
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during import", ex);
ViewMessages.showMessageDialog(null, translate("error.import") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.importing") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
refreshTree(swf);
setStatus(translate("import.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.image.result").replace("%count%", Integer.toString(count)));
if (count != 0) {
reload(true);
}
});
}
}.execute();
}
}
public void importText(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importTexts2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportTextInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
boolean textsFolderExists = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME)).exists();
File textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED));
if (!textsFolderExists) {
textsFile = new File(Path.combine(selFile, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED));
}
TextImporter textImporter = new TextImporter(getMissingCharacterHandler(), new TextImportErrorHandler() {
// "configuration items" for the current replace only
private final ConfigurationItem<Boolean> showAgainImportError = new ConfigurationItem<>("showAgainImportError", true, true);
private final ConfigurationItem<Boolean> showAgainInvalidText = new ConfigurationItem<>("showAgainInvalidText", true, true);
private String getTextTagInfo(TextTag textTag) {
StringBuilder ret = new StringBuilder();
if (textTag != null) {
ret.append(" TextId: ").append(textTag.getCharacterId()).append(" (").append(String.join(", ", textTag.getTexts())).append(")");
}
return ret.toString();
}
@Override
public boolean handle(TextTag textTag) {
String msg = translate("error.text.import");
logger.log(Level.SEVERE, "{0}{1}", new Object[]{msg, getTextTagInfo(textTag)});
return ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION;
}
@Override
public boolean handle(TextTag textTag, String message, long line) {
String msg = translate("error.text.invalid.continue").replace("%text%", message).replace("%line%", Long.toString(line));
logger.log(Level.SEVERE, "{0}{1}", new Object[]{msg, getTextTagInfo(textTag)});
return ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION;
}
});
// try to import formatted texts
if (textsFile.exists()) {
textImporter.importTextsSingleFileFormatted(textsFile, swf);
} else {
textsFile = new File(Path.combine(selFile, TextExportSettings.EXPORT_FOLDER_NAME, TextExporter.TEXT_EXPORT_FILENAME_PLAIN));
if (!textsFolderExists) {
textsFile = new File(Path.combine(selFile, TextExporter.TEXT_EXPORT_FILENAME_PLAIN));
}
// try to import plain texts
if (textsFile.exists()) {
textImporter.importTextsSingleFile(textsFile, swf);
} else {
textImporter.importTextsMultipleFiles(selFile, swf);
}
}
swf.clearImageCache();
reload(true);
updateMissingNeededCharacters();
}
}
public As3ScriptReplacerInterface getAs3ScriptReplacer(boolean air) {
As3ScriptReplacerInterface r = As3ScriptReplacerFactory.createByConfig(air);
if (!r.isAvailable()) {
if (r instanceof MxmlcAs3ScriptReplacer) {
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.flexpath.notset"), AppStrings.translate("error"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
Main.advancedSettings("paths");
}
} else if (r instanceof FFDecAs3ScriptReplacer) {
FFDecAs3ScriptReplacer fr = (FFDecAs3ScriptReplacer) r;
if (fr.isAir()) {
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.airpath.lib.notset"), AppStrings.translate("message.action.airglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
Main.advancedSettings("paths");
}
} else {
if (ViewMessages.showConfirmDialog(this, AppStrings.translate("message.playerpath.lib.notset"), AppStrings.translate("message.action.playerglobal.title"), JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
Main.advancedSettings("paths");
}
}
} else {
//Not translated yet - just in case there are more Script replacers in the future. Unused now.
ViewMessages.showConfirmDialog(this, "Current script replacer is not available", "Script replacer not available", JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
}
return null;
}
return r;
}
public void importScript(final Openable openable) {
As3ScriptReplacerInterface as3ScriptReplacer = getAs3ScriptReplacer(Main.isSwfAir(openable));
if (as3ScriptReplacer == null) {
return;
}
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importScripts2"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportScriptsInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME);
if (!new File(scriptsFolder).exists()) {
scriptsFolder = selFile;
}
final String fScriptsFolder = scriptsFolder;
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
private int countAs2 = 0;
private int countAs3 = 0;
@Override
public Void doInBackground() throws Exception {
SWF swf = (openable instanceof SWF) ? (SWF) openable : ((ABC) openable).getSwf();
new AS2ScriptImporter().importScripts(fScriptsFolder, swf.getASMs(true), new ScriptImporterProgressListener() {
@Override
public void scriptImported() {
countAs2++;
}
});
List<ScriptPack> packs;
if (openable instanceof SWF) {
packs = swf.getAS3Packs();
} else {
List<ABC> allAbcs = new ArrayList<>();
ABC abc = (ABC) openable;
allAbcs.add(abc);
packs = abc.getScriptPacks(null, allAbcs);
}
new AS3ScriptImporter().importScripts(as3ScriptReplacer, fScriptsFolder, packs, new ScriptImporterProgressListener() {
@Override
public void scriptImported() {
countAs3++;
}
}
);
if (countAs3 > 0) {
updateClassesList();
}
return null;
}
@Override
protected void onStart() {
Main.importWorker = this;
Main.startWork(translate("work.importing_as") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
Main.importWorker = null;
View.execInEventDispatch(() -> {
setStatus(translate("importing_as.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
ViewMessages.showMessageDialog(MainPanel.this, translate("import.script.result").replace("%count%", Integer.toString(countAs2 + countAs3)));
if (countAs2 != 0 || countAs3 != 0) {
reload(true);
updateMissingNeededCharacters();
}
});
}
}.execute();
}
}
public void importSymbolClass(final SWF swf) {
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importSymbolClass").replace("%file%", SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportSymbolClassInfo);
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("import.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
File importFile = new File(Path.combine(selFile, SymbolClassExporter.SYMBOL_CLASS_EXPORT_FILENAME));
SymbolClassImporter importer = new SymbolClassImporter();
if (importFile.exists()) {
importer.importSymbolClasses(importFile, swf);
}
}
}
private String selectExportDir() {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File(Configuration.lastExportDir.get()));
chooser.setDialogTitle(translate("export.select.directory"));
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
final String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath();
Configuration.lastExportDir.set(Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath());
return selFile;
}
return null;
}
public void export(final boolean onlySel, List<TreeItem> selected) {
View.checkAccess();
final SWF swf = getCurrentSwf();
List<TreeItem> sel = getCurrentTree().getAllSubsForItems(selected);
if (!onlySel) {
sel = null;
} else if (sel.isEmpty()) {
return;
}
final ExportDialog export = new ExportDialog(Main.getDefaultDialogsOwner(), sel);
if (export.showExportDialog() == AppDialog.OK_OPTION) {
final String selFile = selectExportDir();
if (selFile != null) {
final long timeBefore = System.currentTimeMillis();
new CancellableWorker<Void>() {
@Override
public Void doInBackground() throws Exception {
try {
AbortRetryIgnoreHandler errorHandler = new GuiAbortRetryIgnoreHandler();
if (onlySel) {
exportSelection(selected, errorHandler, selFile, export);
} else {
exportAll(swf, errorHandler, selFile, export);
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during export", ex);
ViewMessages.showMessageDialog(null, translate("error.export") + ": " + ex.getClass().getName() + " " + ex.getLocalizedMessage());
}
return null;
}
@Override
protected void onStart() {
Main.startWork(translate("work.exporting") + "...", this);
}
@Override
protected void done() {
Main.stopWork();
long timeAfter = System.currentTimeMillis();
final long timeMs = timeAfter - timeBefore;
View.execInEventDispatch(() -> {
setStatus(translate("export.finishedin").replace("%time%", Helper.formatTimeSec(timeMs)));
});
}
}.execute();
}
}
}
public void exportJavaSource(List<TreeItem> items) {
Set<SWF> swfs = new LinkedHashSet<>();
for (TreeItem item : items) {
if (item instanceof OpenableList) {
OpenableList list = (OpenableList) item;
for (Openable openable : list) {
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
} else {
Openable openable = item.getOpenable();
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
}
for (SWF item : swfs) {
SWF swf = (SWF) item;
final String selFile = selectExportDir();
if (selFile != null) {
Main.startWork(translate("work.exporting") + "...", null);
try {
new SwfJavaExporter().exportJavaCode(swf, selFile);
Main.stopWork();
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
}
public void exportSwfXml(List<TreeItem> items) {
View.checkAccess();
Set<SWF> swfs = new LinkedHashSet<>();
for (TreeItem item : items) {
if (item instanceof OpenableList) {
OpenableList list = (OpenableList) item;
for (Openable openable : list) {
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
} else {
Openable openable = item.getOpenable();
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
}
for (SWF swf : swfs) {
final String selFile = selectExportDir();
if (selFile != null) {
Main.startWork(translate("work.exporting") + "...", null);
try {
File outFile = new File(selFile + File.separator + Helper.makeFileName("swf.xml"));
new SwfXmlExporter().exportXml(swf, outFile);
Main.stopWork();
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
}
public void importSwfXml(List<TreeItem> items) {
View.checkAccess();
ViewMessages.showMessageDialog(MainPanel.this, translate("message.info.importXml"), translate("message.info"), JOptionPane.INFORMATION_MESSAGE, Configuration.showImportXmlInfo);
Set<SWF> swfs = new LinkedHashSet<>();
for (TreeItem item : items) {
if (item instanceof OpenableList) {
OpenableList list = (OpenableList) item;
for (Openable openable : list) {
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
} else {
Openable openable = item.getOpenable();
if (openable instanceof SWF) {
swfs.add((SWF) openable);
}
}
}
if (swfs.size() > 1) {
return;
}
for (SWF swf : swfs) {
File selectedFile = showImportFileChooser("filter.xml|*.xml", false);
if (selectedFile != null) {
File selfile = Helper.fixDialogFile(selectedFile);
try {
try (FileInputStream fis = new FileInputStream(selfile)) {
new SwfXmlImporter().importSwf(swf, fis);
}
swf.clearAllCache();
swf.assignExportNamesToSymbols();
swf.assignClassesToSymbols();
refreshTree(swf);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
}
public void renameIdentifiers(final Openable openable) {
View.checkAccess();
SWF swf = null;
if (openable instanceof SWF) {
swf = (SWF) openable;
}
//FIXME for ABCs
if (swf == null) {
return;
}
final SWF fswf = swf;
if (confirmExperimental()) {
RenameDialog renameDialog = new RenameDialog(Main.getDefaultDialogsOwner());
if (renameDialog.showRenameDialog() == AppDialog.OK_OPTION) {
final RenameType renameType = renameDialog.getRenameType();
new CancellableWorker<Integer>() {
@Override
protected Integer doInBackground() throws Exception {
int cnt = fswf.deobfuscateIdentifiers(renameType);
return cnt;
}
@Override
protected void onStart() {
Main.startWork(translate("work.renaming.identifiers") + "...", this);
}
@Override
protected void done() {
View.execInEventDispatch(() -> {
try {
int cnt = get();
Main.stopWork();
ViewMessages.showMessageDialog(MainPanel.this, translate("message.rename.renamed").replace("%count%", Integer.toString(cnt)));
fswf.assignClassesToSymbols();
fswf.clearScriptCache();
if (abcPanel != null) {
abcPanel.reload();
}
updateClassesList();
reload(true);
} catch (Exception ex) {
logger.log(Level.SEVERE, "Error during renaming identifiers", ex);
Main.stopWork();
ViewMessages.showMessageDialog(MainPanel.this, translate("error.occured").replace("%error%", ex.getClass().getSimpleName()));
}
});
}
}.execute();
}
}
}
private void deobfuscateMethod(Trait t, int scriptIndex, DeobfuscationLevel level, boolean isStatic, int methodIndex, ABC abc) throws InterruptedException {
if (methodIndex == -1) {
return;
}
MethodBody body = abc.findBody(methodIndex);
if (body != null) {
body.deobfuscate(level, t, scriptIndex, methodIndex, isStatic, "");
}
}
private void deobfuscateTraits(int scriptIndex, DeobfuscationLevel level, List<Trait> traits, ABC abc, boolean isStatic) throws InterruptedException {
for (Trait t : traits) {
int methodIndex = -1;
if (t instanceof TraitMethodGetterSetter) {
methodIndex = ((TraitMethodGetterSetter) t).method_info;
}
if (t instanceof TraitFunction) {
methodIndex = ((TraitFunction) t).method_info;
}
if (methodIndex != -1) {
deobfuscateMethod(t, scriptIndex, level, isStatic, methodIndex, abc);
}
if (t instanceof TraitClass) {
TraitClass tc = (TraitClass) t;
ClassInfo ci = abc.class_info.get(tc.class_info);
deobfuscateMethod(t, scriptIndex, level, true, ci.cinit_index, abc);
deobfuscateTraits(scriptIndex, level, ci.static_traits.traits, abc, true);
InstanceInfo ii = abc.instance_info.get(tc.class_info);
deobfuscateMethod(t, scriptIndex, level, false, ii.iinit_index, abc);
deobfuscateTraits(scriptIndex, level, ii.instance_traits.traits, abc, false);
}
}
}
public void deobfuscate() {
View.checkAccess();
DeobfuscationDialog deobfuscationDialog = new DeobfuscationDialog(Main.getDefaultDialogsOwner());
if (deobfuscationDialog.showDialog() == AppDialog.OK_OPTION) {
DeobfuscationLevel level = deobfuscationDialog.getDeobfuscationLevel();
new CancellableWorker() {
@Override
protected Void doInBackground() throws Exception {
try {
ABCPanel abcPanel = getABCPanel();
DeobfuscationScope scope = deobfuscationDialog.getDeobfuscationScope();
if (scope == DeobfuscationScope.SWF) {
SWF swf = abcPanel.getSwf();
swf.deobfuscate(level);
} else if (scope == DeobfuscationScope.CLASS) {
ScriptPack pack = abcPanel.getPack();
if (pack == null) {
return null;
}
List<Trait> traits = pack.abc.script_info.get(pack.scriptIndex).traits.traits;
deobfuscateMethod(null, pack.scriptIndex, level, true, pack.abc.script_info.get(pack.scriptIndex).init_index, pack.abc);
deobfuscateTraits(pack.scriptIndex, level, traits, pack.abc, true);
} else {
int mi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getMethodIndex();
int bi = abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getBodyIndex();
DecompiledEditorPane decompiledTextArea = abcPanel.decompiledTextArea;
Trait t = abcPanel.decompiledTextArea.getCurrentTrait();
ABC abc = abcPanel.abc;
if (bi != -1) {
int scriptIndex = decompiledTextArea.getScriptLeaf().scriptIndex;
int classIndex = decompiledTextArea.getClassIndex();
boolean isStatic = decompiledTextArea.getIsStatic();
abc.bodies.get(bi).deobfuscate(level, t, scriptIndex, classIndex, isStatic, ""/*FIXME*/);
}
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.setMethod(decompiledTextArea.getScriptLeaf().getPathScriptName(), mi, bi, abc, t, abcPanel.detailPanel.methodTraitPanel.methodCodePanel.getScriptIndex());
}
} catch (Exception ex) {
logger.log(Level.SEVERE, "Deobfuscation error", ex);
ViewMessages.showMessageDialog(MainPanel.this, translate("error.deobfuscation"), translate("error"), JOptionPane.ERROR_MESSAGE);
}
return null;
}
@Override
protected void onStart() {
Main.deobfuscatePCodeWorker = this;
Main.startWork(translate("work.deobfuscating") + "...", this);
}
@Override
protected void done() {
Main.deobfuscatePCodeWorker = null;
View.execInEventDispatch(() -> {
Main.stopWork();
ViewMessages.showMessageDialog(MainPanel.this, translate("work.deobfuscating.complete"));
clearAllScriptCache();
getABCPanel().reload();
updateClassesList();
});
}
}.execute();
}
}
public void removeNonScripts(SWF swf) {
if (swf == null) {
return;
}
List<Tag> tags = swf.getTags().toArrayList();
List<Tag> toRemove = new ArrayList<>();
for (Tag tag : tags) {
System.out.println(tag.getClass());
if (!(tag instanceof ABCContainerTag || tag instanceof ASMSource)) {
toRemove.add(tag);
}
}
swf.removeTags(toRemove, true, null);
refreshTree(swf);
}
public void removeExceptSelected(SWF swf) {
if (swf == null) {
return;
}
List<TreeItem> sel = getAllSelected();
Set<Integer> needed = new HashSet<>();
for (TreeItem item : sel) {
if (item instanceof CharacterTag) {
CharacterTag characterTag = (CharacterTag) item;
characterTag.getNeededCharactersDeep(needed);
needed.add(characterTag.getCharacterId());
}
}
List<Tag> tagsToRemove = new ArrayList<>();
for (Tag tag : swf.getTags()) {
if (tag instanceof CharacterTag) {
CharacterTag characterTag = (CharacterTag) tag;
if (!needed.contains(characterTag.getCharacterId())) {
tagsToRemove.add(tag);
}
}
}
swf.removeTags(tagsToRemove, true, null);
refreshTree(swf);
}
private void clear() {
dumpViewPanel.clear();
previewPanel.clear();
headerPanel.clear();
folderPreviewPanel.clear();
folderListPanel.clear();
if (abcPanel != null) {
abcPanel.clearSwf();
}
if (actionPanel != null) {
actionPanel.clearSource();
}
}
public void refreshTree() {
refreshTree(new SWF[0]);
}
public void treeOperation(Runnable runnable) {
TreeItem treeItem = getCurrentTree().getCurrentTreeItem();
tagTree.clearSelection();
tagListTree.clearSelection();
runnable.run();
clear();
showCard(CARDEMPTYPANEL);
tagTree.updateSwfs(new SWF[0]);
tagListTree.updateSwfs(new SWF[0]);
if (treeItem != null) {
Openable openable = treeItem.getOpenable();
if (openable != null) {
if (openable instanceof SWF) {
SWF treeItemSwf = ((SWF) openable).getRootSwf();
if (this.openables.contains(treeItemSwf.openableList)) {
setTagTreeSelectedNode(getCurrentTree(), treeItem);
}
} else {
if (this.openables.contains(openable.getOpenableList())) {
setTagTreeSelectedNode(getCurrentTree(), treeItem);
}
}
}
}
reload(true);
pinsPanel.refresh();
}
public void refreshTree(Openable openable) {
refreshTree(new Openable[]{openable});
}
public void refreshTree(Openable[] openables) {
TreeItem treeItem = null;
if (currentView == VIEW_RESOURCES || currentView == VIEW_TAGLIST) {
treeItem = getCurrentTree().getCurrentTreeItem();
}
clear();
showCard(CARDEMPTYPANEL);
tagTree.updateSwfs(openables);
tagListTree.updateSwfs(openables);
if (treeItem != null) {
Openable openable = treeItem.getOpenable();
if (openable instanceof SWF) {
SWF swf = (SWF) openable;
SWF treeItemSwf = swf.getRootSwf();
if (this.openables.contains(treeItemSwf.openableList)) {
setTagTreeSelectedNode(getCurrentTree(), treeItem);
}
} else if (openable != null) {
if (this.openables.contains(openable.getOpenableList())) {
setTagTreeSelectedNode(getCurrentTree(), treeItem);
}
}
}
reload(true);
updateMissingNeededCharacters();
pinsPanel.refresh();
}
public void refreshDecompiled() {
clearAllScriptCache();
if (abcPanel != null) {
abcPanel.reload();
}
reload(true);
updateClassesList();
}
private MissingCharacterHandler getMissingCharacterHandler() {
return new MissingCharacterHandler() {
// "configuration items" for the current replace only
private final ConfigurationItem<Boolean> showAgainIgnoreMissingCharacters = new ConfigurationItem<>("showAgainIgnoreMissingCharacters", true, true);
private boolean ignoreMissingCharacters = false;
@Override
public boolean getIgnoreMissingCharacters() {
return ignoreMissingCharacters;
}
@Override
public boolean handle(TextTag textTag, final FontTag font, final char character) {
String fontName = font.getSwf().sourceFontNamesMap.get(font.getFontId());
if (fontName == null) {
fontName = font.getFontName();
}
final Font f = FontTag.getInstalledFontsByName().get(fontName);
if (f == null || !f.canDisplay(character)) {
String msg = translate("error.font.nocharacter").replace("%char%", "" + character);
logger.log(Level.SEVERE, "{0} FontId: {1} TextId: {2}", new Object[]{msg, font.getCharacterId(), textTag.getCharacterId()});
ignoreMissingCharacters = ViewMessages.showConfirmDialog(MainPanel.this, msg, translate("error"),
JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE,
showAgainIgnoreMissingCharacters,
ignoreMissingCharacters ? JOptionPane.OK_OPTION : JOptionPane.CANCEL_OPTION) == JOptionPane.OK_OPTION;
return false;
}
font.addCharacter(character, f);
return true;
}
};
}
public boolean saveText(TextTag textTag, String formattedText, String[] texts, LineMarkedEditorPane editor) {
try {
if (textTag.setFormattedText(getMissingCharacterHandler(), formattedText, texts)) {
return true;
}
} catch (TextParseException ex) {
if (editor != null) {
editor.gotoLine((int) ex.line);
editor.markError();
}
ViewMessages.showMessageDialog(MainPanel.this, translate("error.text.invalid").replace("%text%", ex.text).replace("%line%", Long.toString(ex.line)), translate("error"), JOptionPane.ERROR_MESSAGE);
}
return false;
}
public boolean previousTag() {
JTree tree = getCurrentTree();
if (tree != null) {
if (tree.getSelectionRows().length > 0) {
int row = tree.getSelectionRows()[0];
if (row > 0) {
tree.setSelectionRow(row - 1);
tree.scrollRowToVisible(row - 1);
previewPanel.focusTextPanel();
}
}
return true;
}
return false;
}
public boolean nextTag() {
JTree tree = getCurrentTree();
if (tree != null) {
if (tree.getSelectionRows().length > 0) {
int row = tree.getSelectionRows()[0];
if (row < tree.getRowCount() - 1) {
tree.setSelectionRow(row + 1);
tree.scrollRowToVisible(row + 1);
previewPanel.focusTextPanel();
}
}
return true;
}
return false;
}
public void selectBkColorButtonActionPerformed(ActionEvent evt) {
Color newColor = JColorChooser.showDialog(null, AppStrings.translate("dialog.selectbkcolor.title"), View.getSwfBackgroundColor());
if (newColor != null) {
View.setSwfBackgroundColor(newColor);
reload(true);
}
}
public void replaceButtonActionPerformed(List<TreeItem> items) {
if (items.size() == 0) {
return;
}
TreeItem ti0 = items.get(0);
File file = null;
if (ti0 instanceof SoundTag) {
file = showImportFileChooser("filter.sounds|*.mp3;*.wav|filter.sounds.mp3|*.mp3|filter.sounds.wav|*.wav", false);
}
if (ti0 instanceof ImageTag) {
file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp", true);
}
if (ti0 instanceof ShapeTag) {
file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg", true);
}
if (ti0 instanceof DefineVideoStreamTag) {
file = showImportFileChooser("filter.movies|*.flv", false);
}
if (ti0 instanceof DefineBinaryDataTag) {
file = showImportFileChooser("", false);
}
if (ti0 instanceof UnknownTag) {
file = showImportFileChooser("", false);
}
for (TreeItem ti : items) {
doReplaceAction(ti, file);
}
}
private void doReplaceAction(TreeItem item, File selectedFile) {
if (selectedFile == null) {
return;
}
if (item instanceof SoundTag) {
File selfile = Helper.fixDialogFile(selectedFile);
SoundTag st = (SoundTag) item;
int soundFormat = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN;
if (selfile.getName().toLowerCase(Locale.ENGLISH).endsWith(".mp3")) {
soundFormat = SoundFormat.FORMAT_MP3;
}
SoundImporter soundImporter = new SoundImporter();
boolean ok = false;
try {
ok = soundImporter.importSound(st, new FileInputStream(selfile), soundFormat);
((Tag)st).getSwf().clearSoundCache();
} catch (IOException ex) {
//ignore
} catch (UnsupportedSamplingRateException ex) {
String samplingRateKhz = "" + (ex.getSoundRate() / 1000.0) + " kHz";
List<String> supportedRatesKhz = new ArrayList<>();
for (int rate : ex.getSupportedRates()) {
supportedRatesKhz.add("" + (rate / 1000.0) + " kHz");
}
ViewMessages.showMessageDialog(this, translate("error.sound.rate").replace("%saplingRate%", samplingRateKhz).replace("%supportedRates%", String.join(", ", supportedRatesKhz)), translate("error"), JOptionPane.ERROR_MESSAGE);
return;
} catch (SoundImportException ex) {
//ignore
}
if (!ok) {
ViewMessages.showMessageDialog(this, translate("error.sound.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
} else {
refreshTree(((Tag)st).getSwf());
reload(true);
}
}
if (item instanceof ImageTag) {
ImageTag it = (ImageTag) item;
if (it.importSupported()) {
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = Helper.readFile(selfile.getAbsolutePath());
try {
Tag newTag = new ImageImporter().importImage(it, data);
SWF swf = it.getSwf();
if (newTag != null) {
refreshTree(swf);
setTagTreeSelectedNode(getCurrentTree(), newTag);
}
swf.clearImageCache();
swf.clearShapeCache();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Invalid image", ex);
ViewMessages.showMessageDialog(this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
}
reload(true);
}
}
if (item instanceof ShapeTag) {
ShapeTag st = (ShapeTag) item;
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = null;
String svgText = null;
if (".svg".equals(Path.getExtension(selfile))) {
svgText = Helper.readTextFile(selfile.getAbsolutePath());
showSvgImportWarning();
} else {
data = Helper.readFile(selfile.getAbsolutePath());
}
try {
Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText) : new ShapeImporter().importImage(st, data);
SWF swf = st.getSwf();
if (newTag != null) {
refreshTree(swf);
setTagTreeSelectedNode(getCurrentTree(), newTag);
}
swf.clearImageCache();
swf.clearShapeCache();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Invalid image", ex);
ViewMessages.showMessageDialog(MainPanel.this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
}
reload(true);
}
if (item instanceof DefineBinaryDataTag) {
DefineBinaryDataTag bt = (DefineBinaryDataTag) item;
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = Helper.readFile(selfile.getAbsolutePath());
new BinaryDataImporter().importData(bt, data);
refreshTree(bt.getSwf());
reload(true);
}
if (item instanceof UnknownTag) {
UnknownTag ut = (UnknownTag) item;
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = Helper.readFile(selfile.getAbsolutePath());
ut.unknownData = new ByteArrayRange(data);
ut.setModified(true);
refreshTree(ut.getSwf());
reload(true);
}
if (item instanceof DefineVideoStreamTag) {
previewPanel.clear();
DefineVideoStreamTag movie = (DefineVideoStreamTag) item;
File selfile = Helper.fixDialogFile(selectedFile);
try {
new MovieImporter().importMovie(movie, Helper.readFile(selfile.getAbsolutePath()));
refreshTree();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Invalid movie", ex);
ViewMessages.showMessageDialog(MainPanel.this, translate("error.movie.invalid") + ": "+ex.getMessage(), translate("error"), JOptionPane.ERROR_MESSAGE);
}
}
}
public void replaceNoFillButtonActionPerformed(TreeItem item) {
if (item == null) {
return;
}
if (item instanceof ShapeTag) {
ShapeTag st = (ShapeTag) item;
String filter = "filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg";
File selectedFile = showImportFileChooser(filter, true);
if (selectedFile != null) {
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = null;
String svgText = null;
if (".svg".equals(Path.getExtension(selfile))) {
svgText = Helper.readTextFile(selfile.getAbsolutePath());
showSvgImportWarning();
} else {
data = Helper.readFile(selfile.getAbsolutePath());
}
try {
Tag newTag = svgText != null ? new SvgImporter().importSvg(st, svgText, false) : new ShapeImporter().importImage(st, data, 0, false);
SWF swf = st.getSwf();
if (newTag != null) {
refreshTree(swf);
setTagTreeSelectedNode(getCurrentTree(), newTag);
}
swf.clearImageCache();
swf.clearShapeCache();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Invalid image", ex);
ViewMessages.showMessageDialog(this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
}
reload(true);
}
}
}
private void showSvgImportWarning() {
ViewMessages.showMessageDialog(this, AppStrings.translate("message.warning.svgImportExperimental"), AppStrings.translate("message.warning"), JOptionPane.WARNING_MESSAGE, Configuration.warningSvgImport);
}
public void replaceAlphaButtonActionPerformed(ActionEvent evt) {
TreeItem item = getCurrentTree().getCurrentTreeItem();
if (item == null) {
return;
}
if (item instanceof DefineBitsJPEG3Tag || item instanceof DefineBitsJPEG4Tag) {
ImageTag it = (ImageTag) item;
if (it.importSupported()) {
File selectedFile = showImportFileChooser("", false);
if (selectedFile != null) {
File selfile = Helper.fixDialogFile(selectedFile);
byte[] data = Helper.readFile(selfile.getAbsolutePath());
try {
new ImageImporter().importImageAlpha(it, data);
SWF swf = it.getSwf();
swf.clearImageCache();
swf.clearShapeCache();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Invalid alpha channel data", ex);
ViewMessages.showMessageDialog(this, translate("error.image.alpha.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE);
}
reload(true);
}
}
}
}
public void exportJavaSourceActionPerformed(List<TreeItem> items) {
if (Main.isWorking()) {
return;
}
exportJavaSource(items);
}
public void exportSwfXmlActionPerformed(List<TreeItem> items) {
if (Main.isWorking()) {
return;
}
exportSwfXml(items);
}
public void importSwfXmlActionPerformed(List<TreeItem> items) {
if (Main.isWorking()) {
return;
}
importSwfXml(items);
}
public void exportSelectionActionPerformed(List<TreeItem> selected) {
if (Main.isWorking()) {
return;
}
export(true, selected);
}
public File showImportFileChooser(String filter, boolean imagePreview) {
String[] filterArray = filter.length() > 0 ? filter.split("\\|") : new String[0];
JFileChooser fc = new JFileChooser();
fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get()));
if (imagePreview) {
fc.setAccessory(new FileChooserImagePreview(fc));
Dimension prefferedSize = new Dimension(fc.getPreferredSize());
prefferedSize.width += FileChooserImagePreview.PREVIEW_SIZE;
fc.setPreferredSize(prefferedSize);
}
boolean first = true;
for (int i = 0; i < filterArray.length; i += 2) {
final String filterName = filterArray[i];
final String[] extensions = filterArray[i + 1].split(";");
for (int j = 0; j < extensions.length; j++) {
if (extensions[j].startsWith("*.")) {
extensions[j] = extensions[j].substring(1);
}
}
FileFilter ff = new FileFilter() {
@Override
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
String fileName = f.getName().toLowerCase(Locale.ENGLISH);
for (String ext : extensions) {
if (fileName.endsWith(ext)) {
return true;
}
}
return false;
}
@Override
public String getDescription() {
StringBuilder extStr = new StringBuilder();
boolean first = true;
for (String ext : extensions) {
if (first) {
first = false;
} else {
extStr.append(",");
}
extStr.append("*").append(ext);
}
return translate(filterName).replace("%extensions%", extStr);
}
};
if (first) {
fc.setFileFilter(ff);
} else {
fc.addChoosableFileFilter(ff);
}
first = false;
}
if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File result = fc.getSelectedFile();
Configuration.lastOpenDir.set(Helper.fixDialogFile(result).getParentFile().getAbsolutePath());
return result;
}
return null;
}
private void showDetail(String card) {
CardLayout cl = (CardLayout) (detailPanel.getLayout());
cl.show(detailPanel, card);
if (card.equals(DETAILCARDEMPTYPANEL)) {
if (detailPanel.isVisible()) {
detailPanel.setVisible(false);
}
} else if (!detailPanel.isVisible()) {
detailPanel.setVisible(true);
}
}
private void showCard(String card) {
CardLayout cl = (CardLayout) (displayPanel.getLayout());
cl.show(displayPanel, card);
}
private void valueChanged(Object source, TreePath selectedPath) {
TreeItem treeItem = (TreeItem) selectedPath.getLastPathComponent();
if (treeItem == null) {
return;
}
if (!(treeItem instanceof OpenableList)) {
Openable openable = treeItem.getOpenable();
if (openables.isEmpty()) {
// show welcome panel after closing swfs
updateUi();
} else {
if (openable == null && openables.get(0) != null) {
openable = openables.get(0).get(0);
}
if (openable != null) {
updateUi(openable);
}
}
} else {
updateUi();
}
reload(false);
if (source == dumpTree) {
TreeItem t = null;
if (treeItem instanceof DumpInfo) {
DumpInfo di = (DumpInfo) treeItem;
t = di.getTag();
if ("BUTTONRECORD".equals(di.type)) {
DumpInfo recList = di.parent;
int index = recList.getChildInfos().indexOf(di);
ButtonTag buttonTag = (ButtonTag) di.parent.parent.getTag();
if (index < buttonTag.getRecords().size()) { //last is empty, not displayed in resource/taglist views
t = buttonTag.getRecords().get(index);
}
}
}
if (t instanceof Tag) {
t = dumpTree.getOriginalTag(t);
}
showPreview(t, dumpPreviewPanel, getFrameForTreeItem(t), getTimelinedForTreeItem(t));
}
}
@Override
public void valueChanged(TreeSelectionEvent e) {
Object source = e.getSource();
valueChanged(source, e.getPath());
}
private int getFrameForTreeItem(TreeItem treeItem) {
if (treeItem == null) {
return -1;
}
if (currentView == VIEW_DUMP) {
if (treeItem instanceof Tag) {
return dumpTree.getFrameForItem(treeItem);
}
return -1;
}
if (currentView == VIEW_TIMELINE) {
return -1;
}
TreePath path = getCurrentTree().getFullModel().getTreePath(treeItem);
if (path == null) {
return -1;
}
for (int i = path.getPathCount() - 1; i >= 0; i--) {
if (path.getPathComponent(i) instanceof Frame) {
Frame frame = (Frame) path.getPathComponent(i);
return frame.frame;
}
}
return -1;
}
private Timelined getTimelinedForTreeItem(TreeItem treeItem) {
if (treeItem == null) {
return null;
}
if (currentView == VIEW_DUMP) {
if (treeItem instanceof Tag) {
return dumpTree.getTimelinedForItem(treeItem);
}
return null;
}
if (currentView == VIEW_TIMELINE) {
return null;
}
TreePath path = getCurrentTree().getFullModel().getTreePath(treeItem);
if (path == null) {
return null;
}
for (int i = path.getPathCount() - 1; i >= 0; i--) {
if (path.getPathComponent(i) instanceof Timelined) {
return (Timelined) path.getPathComponent(i);
}
}
return null;
}
public void unloadFlashPlayer() {
if (flashPanel != null) {
try {
flashPanel.close();
} catch (IOException ex) {
// ignore
}
}
if (flashPanel2 != null) {
try {
flashPanel2.close();
} catch (IOException ex) {
// ignore
}
}
}
public void clearDebuggerColors() {
if (abcPanel != null) {
abcPanel.decompiledTextArea.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clearDebuggerColors();
}
if (actionPanel != null) {
actionPanel.decompiledEditor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
actionPanel.editor.removeColorMarkerOnAllLines(DecompiledEditorPane.IP_MARKER);
}
}
private void stopFlashPlayer() {
if (flashPanel != null) {
if (!flashPanel.isStopped()) {
flashPanel.stopSWF();
}
}
if (flashPanel2 != null) {
if (!flashPanel2.isStopped()) {
flashPanel2.stopSWF();
}
}
}
public static boolean isAdobeFlashPlayerEnabled() {
return Configuration.useAdobeFlashPlayerForPreviews.get();
}
public static final int VIEW_RESOURCES = 0;
public static final int VIEW_DUMP = 1;
public static final int VIEW_TIMELINE = 2;
public static final int VIEW_TAGLIST = 3;
public int getCurrentView() {
return currentView;
}
public void setTreeModel(int view) {
switch (view) {
case VIEW_DUMP:
if (dumpTree.getModel() == null) {
DumpTreeModel dtm = new DumpTreeModel(openables);
dumpTree.setModel(dtm);
dumpTree.expandFirstLevelNodes();
}
break;
case VIEW_RESOURCES:
case VIEW_TAGLIST:
if (tagTree.getModel() == null) {
TagTreeModel ttm = new TagTreeModel(openables, Configuration.tagTreeShowEmptyFolders.get());
tagTree.setModel(ttm);
//tagTree.expandFirstLevelNodes();
}
if (tagListTree.getModel() == null) {
TagListTreeModel ttm = new TagListTreeModel(openables);
tagListTree.setModel(ttm);
//tagListTree.expandFirstLevelNodes();
}
break;
}
}
private JPanel createDumpViewCard() {
JPanel r = new JPanel(new BorderLayout());
r.add(new JPersistentSplitPane(JSplitPane.VERTICAL_SPLIT, new FasterScrollPane(dumpTree), dumpPreviewPanel, Configuration.guiDumpSplitPaneDividerLocationPercent), BorderLayout.CENTER);
return r;
}
private JPanel createTagListViewCard() {
tagListClipboardPanel = new ClipboardPanel(this);
JPanel r = new JPanel(new BorderLayout());
r.add(tagListClipboardPanel, BorderLayout.NORTH);
r.add(new FasterScrollPane(tagListTree), BorderLayout.CENTER);
quickTagListFindPanel = new QuickTreeFindPanel();
quickTagListFindPanel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doFilter();
}
});
r.add(quickTagListFindPanel, BorderLayout.SOUTH);
return r;
}
private JPanel createResourcesViewCard() {
resourcesClipboardPanel = new ClipboardPanel(this);
JPanel r = new JPanel(new BorderLayout());
r.add(resourcesClipboardPanel, BorderLayout.NORTH);
r.add(tagTreeScrollPanel = new FasterScrollPane(tagTree), BorderLayout.CENTER);
quickTreeFindPanel = new QuickTreeFindPanel();
quickTreeFindPanel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
doFilter();
}
});
r.add(quickTreeFindPanel, BorderLayout.SOUTH);
return r;
}
private void showContentPanelCard(String card) {
CardLayout cl = (CardLayout) (contentPanel.getLayout());
cl.show(contentPanel, card);
}
private void showTreePanelCard(String card) {
CardLayout cl = (CardLayout) (treePanel.getLayout());
cl.show(treePanel, card);
}
public boolean showView(int view) {
View.checkAccess();
setTreeModel(view);
switch (view) {
case VIEW_DUMP:
pinsPanel.setVisible(false);
currentView = view;
Configuration.lastView.set(currentView);
if (!isWelcomeScreen) {
showContentPanelCard(SPLIT_PANE1);
}
showTreePanelCard(DUMP_VIEW);
treePanelMode = TreePanelMode.DUMP_TREE;
showDetail(DETAILCARDEMPTYPANEL);
reload(true);
return true;
case VIEW_RESOURCES:
pinsPanel.setVisible(true);
currentView = view;
Configuration.lastView.set(currentView);
if (!isWelcomeScreen) {
showContentPanelCard(SPLIT_PANE1);
}
showTreePanelCard(RESOURCES_VIEW);
treePanelMode = TreePanelMode.TAG_TREE;
treePanel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
tagTree.scrollPathToVisible(tagTree.getSelectionPath());
}
});
refreshPins();
reload(true);
return true;
case VIEW_TIMELINE:
pinsPanel.setVisible(false);
currentView = view;
Configuration.lastView.set(currentView);
final SWF swf = getCurrentSwf();
if (swf != null) {
TreeItem item = tagTree.getCurrentTreeItem();
if (item instanceof TagScript) {
item = ((TagScript) item).getTag();
}
if (item instanceof Timelined) {
timelineViewPanel.setTimelined((Timelined) item);
} else if (item instanceof Frame) {
timelineViewPanel.setTimelined(((Frame) item).timeline.timelined);
} else {
timelineViewPanel.setTimelined(swf);
}
showContentPanelCard(TIMELINE_PANEL);
return true;
} else {
showView(VIEW_RESOURCES);
}
return false;
case VIEW_TAGLIST:
pinsPanel.setVisible(true);
currentView = view;
Configuration.lastView.set(currentView);
if (!isWelcomeScreen) {
showContentPanelCard(SPLIT_PANE1);
}
showTreePanelCard(TAGLIST_VIEW);
treePanelMode = TreePanelMode.TAGLIST_TREE;
refreshPins();
reload(true);
return true;
}
return false;
}
private void dumpViewReload(boolean forceReload) {
showDetail(DETAILCARDEMPTYPANEL);
DumpInfo dumpInfo = (DumpInfo) dumpTree.getLastSelectedPathComponent();
if (dumpInfo == null) {
showCard(CARDEMPTYPANEL);
return;
}
dumpViewPanel.revalidate();
dumpViewPanel.setSelectedNode(dumpInfo);
showCard(CARDDUMPVIEW);
}
public void loadFromBinaryTag(final DefineBinaryDataTag binaryDataTag) {
loadFromBinaryTag(Arrays.asList(binaryDataTag));
}
public void loadFromBinaryTag(final List<DefineBinaryDataTag> binaryDataTags) {
Main.loadingDialog.setVisible(true);
new CancellableWorker<Void>() {
@Override
protected Void doInBackground() throws Exception {
try {
for (DefineBinaryDataTag binaryDataTag : binaryDataTags) {
String path = binaryDataTag.getSwf().getShortPathTitle() + "/DefineBinaryData (" + binaryDataTag.getCharacterId() + ")";
try {
SwfSpecificCustomConfiguration conf = Configuration.getSwfSpecificCustomConfiguration(path);
String charset = conf == null ? Charset.defaultCharset().name() : conf.getCustomData(CustomConfigurationKeys.KEY_CHARSET, Charset.defaultCharset().name());
InputStream is = new ByteArrayInputStream(binaryDataTag.binaryData.getRangeData());
SWF bswf = new SWF(is, null, "(SWF Data)", new ProgressListener() {
@Override
public void progress(int p) {
Main.loadingDialog.setPercent(p);
}
}, Configuration.parallelSpeedUp.get(), charset);
binaryDataTag.innerSwf = bswf;
bswf.binaryData = binaryDataTag;
} catch (IOException ex) {
//ignore
}
}
} catch (InterruptedException ex) {
//ignore
}
return null;
}
@Override
protected void onStart() {
Main.startWork(AppStrings.translate("work.reading.swf") + "...", this);
}
@Override
protected void done() {
View.execInEventDispatch(() -> {
Main.loadingDialog.setVisible(false);
refreshTree();
Main.stopWork();
});
}
}.execute();
}
private void closeTag() {
View.checkAccess();
previewPanel.closeTag();
}
public static void showPreview(TreeItem treeItem, PreviewPanel previewPanel, int frame, Timelined timelinedContainer) {
previewPanel.clear();
if (treeItem == null) {
previewPanel.showEmpty();
return;
}
boolean internalViewer = !isAdobeFlashPlayerEnabled();
boolean isVideoButNotDrawable = (treeItem instanceof DefineVideoStreamTag) && (!DefineVideoStreamTag.displayAvailable());
if (treeItem instanceof SWF) {
SWF swf = (SWF) treeItem;
if (internalViewer) {
previewPanel.showImagePanel(swf, swf, -1, true, Configuration.autoPlaySwfs.get() && Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
} else {
previewPanel.setParametersPanelVisible(false);
//if (flashPanel != null) { //same for flashPanel2
previewPanel.showFlashViewerPanel();
previewPanel.showSwf(swf);
//}
}
} else if ((treeItem instanceof PlaceObjectTypeTag)) {// && (previewPanel != dumpPreviewPanel)) {
previewPanel.showDisplayEditTagPanel((PlaceObjectTypeTag) treeItem, frame);
} else if (treeItem instanceof ShapeTag) {
previewPanel.showDisplayEditTagPanel((ShapeTag)treeItem, 0);
previewPanel.setImageReplaceButtonVisible(false, false, !((Tag) treeItem).isReadOnly(), false, false);
} else if (treeItem instanceof MetadataTag) {
MetadataTag metadataTag = (MetadataTag) treeItem;
previewPanel.showMetaDataPanel(metadataTag);
} else if (treeItem instanceof DefineBinaryDataTag) {
DefineBinaryDataTag binaryTag = (DefineBinaryDataTag) treeItem;
previewPanel.showBinaryPanel(binaryTag);
} else if (treeItem instanceof ProductInfoTag) {
ProductInfoTag productInfoTag = (ProductInfoTag) treeItem;
previewPanel.showProductInfoPanel(productInfoTag);
} else if (treeItem instanceof UnknownTag) {
UnknownTag unknownTag = (UnknownTag) treeItem;
previewPanel.showUnknownPanel(unknownTag);
} else if (treeItem instanceof ImageTag) {
ImageTag imageTag = (ImageTag) treeItem;
previewPanel.setImageReplaceButtonVisible(!((Tag) imageTag).isReadOnly() && imageTag.importSupported(), imageTag instanceof DefineBitsJPEG3Tag || imageTag instanceof DefineBitsJPEG4Tag, false, false, false);
SWF imageSWF = makeTimelinedImage(imageTag);
previewPanel.showImagePanel(imageSWF, imageSWF, 0, false, true, true, true, true, false, false);
} else if (!isVideoButNotDrawable && (treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) {
final Tag tag = (Tag) treeItem;
DrawableTag d = (DrawableTag) tag;
Timelined timelined;
if (treeItem instanceof Timelined && !(treeItem instanceof ButtonTag)) {
timelined = (Timelined) tag;
} else {
timelined = makeTimelined(tag);
}
previewPanel.setParametersPanelVisible(false);
if (treeItem instanceof ShapeTag) {
previewPanel.setImageReplaceButtonVisible(false, false, !((Tag) treeItem).isReadOnly(), false, false);
}
if (treeItem instanceof DefineVideoStreamTag) {
previewPanel.setImageReplaceButtonVisible(false, false, false, false, !((Tag) treeItem).isReadOnly());
}
previewPanel.showImagePanel(timelined, tag.getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), treeItem instanceof ShapeTag, !Configuration.playFrameSounds.get(), (treeItem instanceof DefineSpriteTag) || (treeItem instanceof ButtonTag), (treeItem instanceof DefineSpriteTag) || (treeItem instanceof ButtonTag) || (treeItem instanceof ShapeTag));
} else if (treeItem instanceof Frame && internalViewer) {
Frame fn = (Frame) treeItem;
SWF swf = (SWF) fn.getOpenable();
previewPanel.showImagePanel(fn.timeline.timelined, swf, fn.frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
} else if (treeItem instanceof ShowFrameTag) {
SWF swf;
if (timelinedContainer instanceof DefineSpriteTag) {
swf = ((DefineSpriteTag) timelinedContainer).getSwf();
} else {
swf = (SWF) timelinedContainer;
}
previewPanel.showImagePanel(timelinedContainer, swf, frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
} else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) {
previewPanel.showImagePanel(new SerializableImage(View.loadImage("sound32")));
previewPanel.setImageReplaceButtonVisible(false, false, false, !((Tag) treeItem).isReadOnly() && (treeItem instanceof SoundTag), false);
try {
SoundTagPlayer soundThread = new SoundTagPlayer(null, (SoundTag) treeItem, Configuration.loopMedia.get() ? Integer.MAX_VALUE : 1, true);
if (!Configuration.autoPlaySounds.get()) {
soundThread.pause();
}
previewPanel.setMedia(soundThread);
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException ex) {
logger.log(Level.SEVERE, null, ex);
}
} else if ((treeItem instanceof FontTag) && internalViewer) {
previewPanel.showFontPanel((FontTag) treeItem);
} else if ((treeItem instanceof TextTag) && internalViewer) {
previewPanel.showTextPanel((TextTag) treeItem);
} else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) {
previewPanel.createAndShowTempSwf(treeItem);
if (treeItem instanceof TextTag) {
previewPanel.showTextPanel((TextTag) treeItem);
} else if (treeItem instanceof FontTag) {
previewPanel.showFontPanel((FontTag) treeItem);
} else {
previewPanel.setParametersPanelVisible(false);
}
} else if (treeItem instanceof BUTTONRECORD) {
BUTTONRECORD buttonRecord = (BUTTONRECORD) treeItem;
previewPanel.setParametersPanelVisible(false);
SWF swf = new SWF(buttonRecord.getSwf().getCharset());
swf.frameCount = 1;
swf.frameRate = buttonRecord.getSwf().frameRate;
swf.displayRect = buttonRecord.getTag().getRect();
if (swf.getBackgroundColor() != null) {
SetBackgroundColorTag setBackgroundColorTag = new SetBackgroundColorTag(swf, swf.getBackgroundColor().backgroundColor);
swf.addTag(setBackgroundColorTag);
setBackgroundColorTag.setTimelined(swf);
}
CharacterTag character = buttonRecord.getSwf().getCharacter(buttonRecord.characterId);
Set<Integer> needed = new LinkedHashSet<>();
character.getNeededCharactersDeep(needed);
needed.remove(buttonRecord.characterId);
needed.add(buttonRecord.characterId);
for (int n : needed) {
CharacterTag neededCharacter;
try {
neededCharacter = (CharacterTag) buttonRecord.getSwf().getCharacter(n).cloneTag();
} catch (InterruptedException | IOException ex) {
Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex);
return;
}
neededCharacter.setSwf(swf);
neededCharacter.setTimelined(swf);
swf.addTag(neededCharacter);
}
PlaceObject3Tag placeTag = buttonRecord.toPlaceObject();
placeTag.setSwf(swf);
swf.addTag(placeTag);
placeTag.setTimelined(swf);
ShowFrameTag showFrameTag = new ShowFrameTag(swf);
swf.addTag(showFrameTag);
showFrameTag.setTimelined(swf);
previewPanel.showImagePanel(swf, swf, 0, true, true, !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false);
} else {
previewPanel.showEmpty();
}
}
private void tagListViewReload(boolean forceReload) {
showDetail(DETAILCARDEMPTYPANEL);
showCard(CARDEMPTYPANEL);
}
public void reload(boolean forceReload) {
View.checkAccess();
JScrollBar folderPreviewScrollBar = ((JScrollPane)folderPreviewPanel.getParent().getParent()).getVerticalScrollBar();
int scrollValue = folderPreviewScrollBar.getValue();
Map<Integer, TreeItem> folderItems = new HashMap<>(folderPreviewPanel.selectedItems);
tagTree.scrollPathToVisible(tagTree.getSelectionPath());
if (currentView == VIEW_DUMP) {
dumpViewReload(forceReload);
return;
}
/*else if (currentView == VIEW_TAGLIST) {
tagListViewReload(forceReload);
return;
}*/
AbstractTagTree tree = getCurrentTree();
TreeItem treeItem = null;
TreePath treePath = tree.getSelectionPath();
if (treePath != null && tree.getFullModel().treePathExists(treePath)) {
treeItem = (TreeItem) treePath.getLastPathComponent();
}
// save last selected node to config
if (treeItem != null && !(treeItem instanceof OpenableList)) {
Openable openable = treeItem.getOpenable();
if (openable != null && (openable instanceof SWF)) {
openable = ((SWF) openable).getRootSwf();
}
if (openable != null) {
SwfSpecificCustomConfiguration swfCustomConf = Configuration.getOrCreateSwfSpecificCustomConfiguration(openable.getShortPathTitle());
swfCustomConf.setCustomData(CustomConfigurationKeys.KEY_LAST_SELECTED_PATH_RESOURCES, tagTree.getSelectionPathString());
swfCustomConf.setCustomData(CustomConfigurationKeys.KEY_LAST_SELECTED_PATH_TAGLIST, tagListTree.getSelectionPathString());
}
}
if (!forceReload && (treeItem == oldItem)) {
return;
}
if (oldItem != treeItem) {
closeTag();
}
oldItem = treeItem;
// show the preview of the tag when the user clicks to the tagname inside the scripts node, too
// this is a little bit inconsistent, beacuse the frames (FrameScript) are not shown
boolean preferScript = false;
if (treeItem instanceof TagScript) {
treeItem = ((TagScript) treeItem).getTag();
preferScript = true;
}
folderPreviewPanel.clear();
folderListPanel.clear();
previewPanel.clear();
stopFlashPlayer();
previewPanel.setImageReplaceButtonVisible(false, false, false, false, false);
boolean internalViewer = !isAdobeFlashPlayerEnabled();
if (treeItem instanceof ScriptPack) {
final ScriptPack scriptLeaf = (ScriptPack) treeItem;
if (!Main.isInited() || !Main.isWorking() || Main.isDebugging()) {
ABCPanel abcPanel = getABCPanel();
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear();
abcPanel.setAbc(scriptLeaf.abc);
abcPanel.decompiledTextArea.setScript(scriptLeaf, true);
abcPanel.decompiledTextArea.setNoTrait();
}
if (Configuration.displayAs3TraitsListAndConstantsPanel.get()) {
showDetail(DETAILCARDAS3NAVIGATOR);
} else {
showDetail(DETAILCARDEMPTYPANEL);
}
showCard(CARDACTIONSCRIPT3PANEL);
} else if (treeItem instanceof Tag) {
Tag tag = (Tag) treeItem;
TagInfo tagInfo = new TagInfo((SWF) treeItem.getOpenable());
tag.getTagInfo(tagInfo);
Set<Integer> needed;
if (neededCharacters.containsKey(treeItem)) {
needed = neededCharacters.get(treeItem);
} else {
needed = new LinkedHashSet<>();
tag.getNeededCharactersDeep(needed);
neededCharacters.put(treeItem, needed);
}
if (needed.size() > 0) {
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
}
if (tag instanceof CharacterTag) {
int characterId = ((CharacterTag) tag).getCharacterId();
Set<Integer> dependent = tag.getSwf().getDependentCharacters(characterId);
if (dependent != null) {
if (dependent.size() > 0) {
tagInfo.addInfo("general", "dependentCharacters", Helper.joinStrings(dependent, ", "));
}
}
Set<Integer> dependent2 = tag.getSwf().getDependentFrames(characterId);
if (dependent2 != null && dependent2.size() > 0) {
tagInfo.addInfo("general", "dependentFrames", Helper.joinStrings(dependent2, ", "));
}
}
if (!tagInfo.isEmpty()) {
tagInfoPanel.setTagInfos(tagInfo);
showDetail(DETAILCARDTAGINFO);
} else {
showDetail(DETAILCARDEMPTYPANEL);
}
} else if (treeItem instanceof Frame) {
Frame frame = (Frame) treeItem;
Set<Integer> needed = new LinkedHashSet<>();
frame.getNeededCharacters(needed);
if (!needed.isEmpty()) {
TagInfo tagInfo = new TagInfo((SWF) treeItem.getOpenable());
tagInfo.addInfo("general", "neededCharacters", Helper.joinStrings(needed, ", "));
tagInfoPanel.setTagInfos(tagInfo);
showDetail(DETAILCARDTAGINFO);
} else {
showDetail(DETAILCARDEMPTYPANEL);
}
} else {
showDetail(DETAILCARDEMPTYPANEL);
}
/*if (treeItem instanceof SoundStreamBlockTag) {
SoundStreamBlockTag block = (SoundStreamBlockTag)treeItem;
byte[] data = block.streamSoundData.getRangeData();
try{
SWFInputStream sis = new SWFInputStream(block.getSwf(), data);
int sampleCount = sis.readUI16("sampleCount");
int seekSamples = sis.readSI16("seekSamples");
System.out.println("sampleCount = "+sampleCount);
System.out.println("seekSamples = "+seekSamples);
System.out.println("============");
}catch(Exception ex){
}
}*/
if (treeItem instanceof HeaderItem) {
headerPanel.load((SWF) ((HeaderItem) treeItem).getOpenable());
showCard(CARDHEADER);
} else if (treeItem instanceof FolderItem) {
showFolderPreview((FolderItem) treeItem);
} else if (treeItem instanceof SWF) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof MetadataTag) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof DefineBinaryDataTag) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof UnknownTag) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof ASMSource && (!(treeItem instanceof DrawableTag) || preferScript)) {
getActionPanel().setSource((ASMSource) treeItem, !forceReload);
showCard(CARDACTIONSCRIPTPANEL);
} else if (treeItem instanceof ImageTag) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if ((treeItem instanceof DrawableTag) && (!(treeItem instanceof TextTag)) && (!(treeItem instanceof FontTag)) && internalViewer) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if ((treeItem instanceof FontTag) && internalViewer) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if ((treeItem instanceof TextTag) && internalViewer) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof Frame && internalViewer) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof ShowFrameTag && internalViewer) {
showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), getTimelinedForTreeItem(treeItem));
showCard(CARDPREVIEWPANEL);
} else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof PlaceObjectTypeTag) {
showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof ProductInfoTag) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (treeItem instanceof Tag) {
showGenericTag((Tag) treeItem);
} else if (treeItem instanceof BUTTONRECORD) {
showPreview(treeItem, previewPanel, -1, null);
showCard(CARDPREVIEWPANEL);
} else if (!(treeItem instanceof ScriptPack)) {
if (treePath == null) {
showCard(CARDEMPTYPANEL);
} else {
showFolderList(treePath);
}
}
if (oldItem instanceof TreeRoot) {
pinsPanel.setCurrent(null);
} else {
pinsPanel.setCurrent(oldItem);
}
folderPreviewPanel.selectedItems = folderItems;
folderPreviewScrollBar.setValue(scrollValue);
}
public void repaintTree() {
tagTree.repaint();
tagListTree.repaint();
reload(true);
}
public void showGenericTag(Tag tag) {
previewPanel.showGenericTagPanel(tag);
showCard(CARDPREVIEWPANEL);
}
public void showTextTagWithNewValue(TextTag textTag, TextTag newTextTag) {
previewPanel.showTextComparePanel(textTag, newTextTag);
}
private void addFolderPreviewItems(List<TreeItem> folderPreviewItems, String folderName, Timelined timelined) {
switch (folderName) {
case TagTreeModel.FOLDER_SHAPES:
for (Tag tag : timelined.getTags()) {
if (tag instanceof ShapeTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_MORPHSHAPES:
for (Tag tag : timelined.getTags()) {
if (tag instanceof MorphShapeTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_SPRITES:
for (Tag tag : timelined.getTags()) {
if (tag instanceof DefineSpriteTag) {
folderPreviewItems.add(tag);
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_MOVIES:
for (Tag tag : timelined.getTags()) {
if (tag instanceof DefineVideoStreamTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_BUTTONS:
for (Tag tag : timelined.getTags()) {
if (tag instanceof ButtonTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_FONTS:
for (Tag tag : timelined.getTags()) {
if (tag instanceof FontTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_FRAMES:
for (Frame frame : timelined.getTimeline().getFrames()) {
folderPreviewItems.add(frame);
}
break;
case TagTreeModel.FOLDER_IMAGES:
for (Tag tag : timelined.getTags()) {
if (tag instanceof ImageTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
case TagTreeModel.FOLDER_TEXTS:
for (Tag tag : timelined.getTags()) {
if (tag instanceof TextTag) {
folderPreviewItems.add(tag);
}
if (tag instanceof DefineSpriteTag) {
addFolderPreviewItems(folderPreviewItems, folderName, (DefineSpriteTag) tag);
}
}
break;
}
}
private void showFolderPreview(FolderItem item) {
String folderName = item.getName();
if (TagTreeModel.FOLDER_OTHERS.equals(folderName) || TagTreeModel.FOLDER_SCRIPTS.equals(folderName)) {
showFolderList(tagTree.getFullModel().getTreePath(item));
return;
}
List<TreeItem> folderPreviewItems = new ArrayList<>();
SWF swf = item.swf;
addFolderPreviewItems(folderPreviewItems, folderName, swf);
folderPreviewPanel.setItems(folderPreviewItems);
showCard(CARDFOLDERPREVIEWPANEL);
}
private void showFolderList(TreePath path) {
List<TreeItem> items = new ArrayList<>(getCurrentTree().getFullModel().getAllChildren((TreeItem) path.getLastPathComponent()));
folderListPanel.setItems(path, items);
showCard(CARDFOLDERLISTPANEL);
}
private boolean isFreeing;
@Override
public boolean isFreeing() {
return isFreeing;
}
@Override
public void free() {
isFreeing = true;
}
public void setErrorState(ErrorState errorState) {
statusPanel.setErrorState(errorState);
}
public static Timelined makeTimelined(final Tag tag) {
return makeTimelined(tag, -1);
}
public static SWF makeTimelinedImage(ImageTag imageTag) {
SWF swf = new SWF();
swf.gfx = imageTag.getSwf().gfx;
swf.version = imageTag.getSwf().version;
int w = (int) (imageTag.getImageDimension().getWidth() * SWF.unitDivisor);
int h = (int) (imageTag.getImageDimension().getHeight() * SWF.unitDivisor);
swf.displayRect = new RECT(0, w, 0, h);
swf.frameCount = 1;
swf.frameRate = 1;
swf.setFile(imageTag.getSwf().getFile()); //DefineSubImage calculates relative paths from it
try {
JPEGTablesTag jpegTablesTag = null;
if (imageTag instanceof DefineBitsTag) {
jpegTablesTag = imageTag.getSwf().getJtt();
}
Set<Integer> needed = new LinkedHashSet<>();
imageTag.getNeededCharacters(needed);
List<CharacterTag> neededCopies = new ArrayList<>();
for (int n : needed) {
CharacterTag ct = imageTag.getSwf().getCharacter(n);
if (ct != null) {
ct = (CharacterTag) ct.cloneTag();
ct.setSwf(swf);
neededCopies.add(ct);
}
}
if (imageTag instanceof DefineSubImage) {
DefineExternalImage2 dei2 = (DefineExternalImage2) imageTag.getSwf().getExternalImage2(((DefineSubImage) imageTag).imageId);
if (dei2 != null) {
dei2 = (DefineExternalImage2) dei2.cloneTag();
dei2.setSwf(swf);
neededCopies.add(dei2);
}
}
ImageTag imageTagCopy = (ImageTag) imageTag.cloneTag();
imageTagCopy.setSwf(swf);
int imageCharId = imageTag.getCharacterId();
DefineShape2Tag shapeTag = new DefineShape2Tag(swf);
int shapeCharId = imageCharId + 1;
shapeTag.shapeId = shapeCharId;
shapeTag.shapeBounds = new RECT(swf.displayRect);
SHAPEWITHSTYLE shapeData = new SHAPEWITHSTYLE();
FILLSTYLEARRAY fillStyleArray = new FILLSTYLEARRAY();
FILLSTYLE fillStyles[] = new FILLSTYLE[1];
FILLSTYLE fillStyle = new FILLSTYLE();
fillStyle.bitmapId = imageCharId;
fillStyle.inShape3 = false;
fillStyle.fillStyleType = FILLSTYLE.CLIPPED_BITMAP;
fillStyle.bitmapMatrix = Matrix.getScaleInstance(SWF.unitDivisor).toMATRIX();
fillStyles[0] = fillStyle;
fillStyleArray.fillStyles = fillStyles;
shapeData.fillStyles = fillStyleArray;
shapeData.lineStyles = new LINESTYLEARRAY();
List<SHAPERECORD> shapeRecords = new ArrayList<>();
StyleChangeRecord scr = new StyleChangeRecord();
scr.stateFillStyle0 = true;
scr.fillStyle0 = 1;
shapeRecords.add(scr);
StyleChangeRecord scr2 = new StyleChangeRecord();
scr2.stateMoveTo = true;
scr2.moveDeltaX = 0;
scr2.moveDeltaY = 0;
scr2.calculateBits();
shapeRecords.add(scr2);
StraightEdgeRecord ser1 = new StraightEdgeRecord();
ser1.vertLineFlag = true;
ser1.deltaY = h;
ser1.calculateBits();
shapeRecords.add(ser1);
StraightEdgeRecord ser2 = new StraightEdgeRecord();
ser2.deltaX = w;
shapeRecords.add(ser2);
StraightEdgeRecord ser3 = new StraightEdgeRecord();
ser3.vertLineFlag = true;
ser3.deltaY = -h;
shapeRecords.add(ser3);
StraightEdgeRecord ser4 = new StraightEdgeRecord();
ser4.deltaX = -w;
shapeRecords.add(ser4);
shapeRecords.add(new EndShapeRecord());
shapeData.shapeRecords = shapeRecords;
shapeData.numFillBits = 1;
shapeData.numLineBits = 0;
shapeTag.shapes = shapeData;
PlaceObjectTag placeTag = new PlaceObjectTag(swf, shapeCharId, 1, new Matrix().toMATRIX(), null);
ShowFrameTag showFrameTag = new ShowFrameTag(swf);
EndTag endTag = new EndTag(swf);
if (jpegTablesTag != null) {
swf.addTag(jpegTablesTag);
}
for (CharacterTag neededCopy : neededCopies) {
swf.addTag(neededCopy);
}
swf.addTag(imageTagCopy);
swf.addTag(shapeTag);
swf.addTag(placeTag);
swf.addTag(showFrameTag);
swf.addTag(endTag);
} catch (InterruptedException | IOException ex) {
//ignore
}
return swf;
}
public static Timelined makeTimelined(final Tag tag, final int fontFrameNum) {
return new Timelined() {
private Timeline tim;
@Override
public Timeline getTimeline() {
if (tim == null) {
Timeline timeline = new Timeline(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect());
initTimeline(timeline);
tim = timeline;
}
return tim;
}
@Override
public void resetTimeline() {
if (tim != null) {
tim.reset(tag.getSwf(), this, ((CharacterTag) tag).getCharacterId(), getRect());
initTimeline(tim);
}
}
private void initTimeline(Timeline timeline) {
if (tag instanceof MorphShapeTag) {
timeline.frameRate = PreviewExporter.MORPH_SHAPE_ANIMATION_FRAME_RATE;
int framesCnt = (int) (timeline.frameRate * PreviewExporter.MORPH_SHAPE_ANIMATION_LENGTH);
for (int i = 0; i < framesCnt; i++) {
Frame f = new Frame(timeline, i);
DepthState ds = new DepthState(tag.getSwf(), f);
ds.characterId = ((CharacterTag) tag).getCharacterId();
ds.matrix = new MATRIX();
ds.ratio = i * 65535 / framesCnt;
f.layers.put(1, ds);
f.layersChanged = true;
timeline.addFrame(f);
}
} else if (tag instanceof FontTag) {
int pageCount = PreviewPanel.getFontPageCount((FontTag) tag);
int frame = fontFrameNum;
if (frame < 0 || frame >= pageCount) {
frame = 0;
}
Frame f = new Frame(timeline, 0);
DepthState ds = new DepthState(tag.getSwf(), f);
ds.characterId = ((CharacterTag) tag).getCharacterId();
ds.matrix = new MATRIX();
f.layers.put(1, ds);
f.layersChanged = true;
timeline.addFrame(f);
timeline.fontFrameNum = frame;
} else {
Frame f = new Frame(timeline, 0);
DepthState ds = new DepthState(tag.getSwf(), f);
ds.characterId = ((CharacterTag) tag).getCharacterId();
ds.matrix = new MATRIX();
f.layers.put(1, ds);
timeline.addFrame(f);
}
timeline.displayRect = getRect();
}
@Override
public RECT getRect() {
return getRect(new HashSet<>());
}
@Override
public RECT getRect(Set<BoundedTag> added) {
BoundedTag bt = (BoundedTag) tag;
if (!added.contains(bt)) {
return bt.getRect(added);
}
return new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
@Override
public int hashCode() {
return tag.hashCode();
}
@Override
public void setModified(boolean value) {
}
@Override
public ReadOnlyTagList getTags() {
return ReadOnlyTagList.EMPTY;
}
@Override
public void removeTag(int index) {
}
@Override
public void removeTag(Tag tag) {
}
@Override
public void addTag(Tag tag) {
}
@Override
public void addTag(int index, Tag tag) {
}
@Override
public void replaceTag(int index, Tag newTag) {
}
@Override
public void replaceTag(Tag oldTag, Tag newTag) {
}
@Override
public int indexOfTag(Tag tag) {
return -1;
}
@Override
public RECT getRectWithStrokes() {
return getRect();
}
@Override
public void setFrameCount(int frameCount) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getFrameCount() {
return getTimeline().getFrameCount();
}
};
}
private void disposeInner(Container container) {
for (Component c : container.getComponents()) {
if (c instanceof Container) {
Container c2 = (Container) c;
disposeInner(c2);
}
}
container.removeAll();
container.setLayout(null);
if (container instanceof TagEditorPanel) {
Helper.emptyObject(container);
}
}
public void dispose() {
if (calculateMissingNeededThread != null) {
calculateMissingNeededThread.interrupt();
}
setDropTarget(null);
disposeInner(this);
Helper.emptyObject(this);
}
private static void calculateMissingNeededCharacters(Map<TreeItem, Set<Integer>> neededMap, Map<TreeItem, Set<Integer>> missingNeededCharacters, Timelined tim) {
List<Tag> tags = tim.getTags().toArrayList();
Map<Integer, List<CharacterIdTag>> nestedTags = new HashMap<>();
for (Tag t : tags) {
if ((t instanceof CharacterIdTag) && !(t instanceof CharacterTag) && !(t instanceof SoundStreamHeadTypeTag)) {
int characterId = ((CharacterIdTag) t).getCharacterId();
if (!nestedTags.containsKey(characterId)) {
nestedTags.put(characterId, new ArrayList<>());
}
nestedTags.get(characterId).add((CharacterIdTag) t);
}
if (!(t instanceof CharacterTag) && !(t instanceof SoundStreamHeadTypeTag)) {
int characterId = -1;
if (t instanceof CharacterIdTag) {
characterId = ((CharacterIdTag) t).getCharacterId();
}
Set<Integer> needed = new LinkedHashSet<>();
t.getNeededCharactersDeep(needed);
neededMap.put(t, needed);
if ((t instanceof CharacterIdTag) && !(t instanceof PlaceObjectTypeTag)) {
needed = new HashSet<>();
needed.add(characterId);
}
if ((t instanceof PlaceObjectTypeTag) && (characterId != -1) && nestedTags.containsKey(characterId)) {
for (CharacterIdTag n : nestedTags.get(characterId)) {
((Tag) n).getNeededCharactersDeep(needed);
}
}
missingNeededCharacters.put(t, t.getMissingNeededCharacters(needed));
if (characterId != -1 && tim.getTimeline().swf.getCharacter(characterId) == null) {
missingNeededCharacters.get(t).add(characterId);
}
}
/*if (t instanceof DefineSpriteTag) {
calculateMissingNeededCharacters(neededMap, missingNeededCharacters, (DefineSpriteTag) t);
}*/
}
}
public void updateMissingNeededCharacters() {
if (calculateMissingNeededThread != null) {
calculateMissingNeededThread.recalculate();
}
}
private void calculateMissingNeededCharacters() {
Map<TreeItem, Set<Integer>> missingNeededCharacters = new WeakHashMap<>();
Map<TreeItem, Set<Integer>> neededCharacters = new WeakHashMap<>();
List<OpenableList> swfsLists = new ArrayList<>(openables);
for (OpenableList swfList : swfsLists) {
for (Openable openable : swfList) {
if (openable instanceof SWF) {
calculateMissingNeededCharacters(neededCharacters, missingNeededCharacters, (SWF) openable);
//TODO: how about SubSWFs???
}
}
}
this.neededCharacters = neededCharacters;
this.missingNeededCharacters = missingNeededCharacters;
tagTree.setMissingNeededCharacters(missingNeededCharacters);
tagListTree.setMissingNeededCharacters(missingNeededCharacters);
}
class CalculateMissingNeededThread extends Thread {
public CalculateMissingNeededThread() {
super("calculateMissingNeededThread");
setPriority(Thread.MIN_PRIORITY);
}
private boolean recalculate = false;
public synchronized void recalculate() {
this.recalculate = true;
this.notify();
}
@Override
public void run() {
while (true) {
synchronized (this) {
recalculate = false;
}
try {
calculateMissingNeededCharacters();
} catch (ConcurrentModificationException cme) {
//ignore
}
synchronized (this) {
if (recalculate) {
continue;
}
try {
wait();
} catch (InterruptedException ex) {
return;
}
}
}
}
}
public String itemToString(TreeItem item) {
int index = getCurrentTree().getFullModel().getItemIndex(item);
String itemToStr = item.toString();
if (index > 1) {
return itemToStr + " [" + index + "]";
}
return itemToStr;
}
public void startEdit() {
TreeItem treeItem = getCurrentTree().getCurrentTreeItem();
if (treeItem == null) {
return;
}
if (treeItem instanceof HeaderItem) {
headerPanel.startEdit();
} else if (treeItem instanceof PlaceObjectTypeTag) {
previewPanel.startEditPlaceTag();
} else if (treeItem instanceof MetadataTag) {
previewPanel.startEditMetaDataTag();
} else if (treeItem instanceof DefineBinaryDataTag) {
//TODO
} else if (treeItem instanceof FontTag) {
previewPanel.startEditFontTag();
} else if (treeItem instanceof TextTag) {
previewPanel.startEditTextTag();
} else if (treeItem instanceof ASMSource) {
//There are two kinds of edit - Script and P-code.
} else if (treeItem instanceof Tag) {
Tag tag = (Tag) treeItem;
previewPanel.showGenericTagPanel(tag);
previewPanel.startEditGenericTag();
}
}
}