Issue #350 (Allow to open multiple SWF files into the same ffdec instance)

This commit is contained in:
Honfika
2013-12-22 19:56:08 +01:00
parent e1f4ca362b
commit f811ca2d27
7 changed files with 130 additions and 96 deletions
@@ -56,6 +56,7 @@ import com.jpexs.decompiler.flash.flv.FLVOutputStream;
import com.jpexs.decompiler.flash.flv.FLVTAG;
import com.jpexs.decompiler.flash.flv.VIDEODATA;
import com.jpexs.decompiler.flash.gui.SWFSourceInfo;
import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel;
import com.jpexs.decompiler.flash.helpers.collections.MyEntry;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
@@ -212,6 +213,7 @@ public final class SWF {
public HashMap<Integer, CharacterTag> characters;
public List<ABCContainerTag> abcList;
public JPEGTablesTag jtt;
public ClassesListTreeModel classTreeModel;
/**
* Gets all tags with specified id
@@ -40,6 +40,7 @@ import java.awt.event.MouseEvent;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
@@ -191,13 +192,35 @@ public class Main {
public static SWF parseSWF(SWFSourceInfo sourceInfo) throws Exception {
SWF locswf;
InputStream fis = sourceInfo.getInputStream();
locswf = new SWF(fis, new ProgressListener() {
InputStream inputStream = sourceInfo.getInputStream();
if (inputStream == null) {
inputStream = new FileInputStream(sourceInfo.getFile());
} else if (inputStream instanceof SeekableInputStream) {
try {
((SeekableInputStream) inputStream).seek(0);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (inputStream instanceof BufferedInputStream) {
try {
((BufferedInputStream) inputStream).reset();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
locswf = new SWF(inputStream, new ProgressListener() {
@Override
public void progress(int p) {
startWork(AppStrings.translate("work.reading.swf"), p);
}
}, Configuration.parallelSpeedUp.get());
if (inputStream instanceof FileInputStream) {
inputStream.close();
}
locswf.sourceInfo = sourceInfo;
locswf.file = sourceInfo.getFile();
locswf.fileTitle = sourceInfo.getFileTitle();
@@ -242,51 +265,52 @@ public class Main {
private static class OpenFileWorker extends SwingWorker {
private SWFSourceInfo sourceInfo;
private SWFSourceInfo[] sourceInfos;
public OpenFileWorker(SWFSourceInfo sourceInfo) {
this.sourceInfo = sourceInfo;
this.sourceInfos = new SWFSourceInfo[] { sourceInfo };
}
public OpenFileWorker(SWFSourceInfo[] sourceInfos) {
this.sourceInfos = sourceInfos;
}
@Override
protected Object doInBackground() throws Exception {
SWF swf = null;
try {
Main.startWork(AppStrings.translate("work.reading.swf") + "...");
InputStream inputStream = sourceInfo.getInputStream();
swf = parseSWF(sourceInfo);
if (inputStream instanceof FileInputStream) {
inputStream.close();
for (SWFSourceInfo sourceInfo : sourceInfos) {
SWF swf = null;
try {
Main.startWork(AppStrings.translate("work.reading.swf") + "...");
swf = parseSWF(sourceInfo);
} catch (OutOfMemoryError ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file. Out of memory.");
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file.");
}
final SWF swf1 = swf;
try {
Main.startWork(AppStrings.translate("work.creatingwindow") + "...");
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
if (mainFrame == null) {
mainFrame = new MainFrame();
}
mainFrame.load(swf1);
if (errorState) {
mainFrame.setErrorState();
}
}
});
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (OutOfMemoryError ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file. Out of memory.");
loadingDialog.setVisible(false);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
View.showMessageDialog(null, "Cannot load SWF file.");
loadingDialog.setVisible(false);
}
final SWF swf1 = swf;
try {
Main.startWork(AppStrings.translate("work.creatingwindow") + "...");
View.execInEventDispatch(new Runnable() {
@Override
public void run() {
if (mainFrame == null) {
mainFrame = new MainFrame();
}
mainFrame.load(swf1);
if (errorState) {
mainFrame.setErrorState();
}
}
});
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
loadingDialog.setVisible(false);
View.execInEventDispatch(new Runnable() {
@Override
@@ -304,6 +328,7 @@ public class Main {
public static boolean reloadSWFs() {
CancellableWorker.cancelBackgroundThreads();
mainFrame.closeAll();
if (Main.sourceInfos.isEmpty()) {
Cache.clearAll();
System.gc();
@@ -312,27 +337,9 @@ public class Main {
} else {
SWFSourceInfo[] sourceInfosCopy = new SWFSourceInfo[sourceInfos.size()];
sourceInfos.toArray(sourceInfosCopy);
for (SWFSourceInfo sourceInfo : sourceInfosCopy) {
InputStream inputStream = sourceInfo.getInputStream();
if (inputStream instanceof FileInputStream) {
openFile(sourceInfo.getFile(), null);
} else if (inputStream instanceof SeekableInputStream) {
try {
((SeekableInputStream) inputStream).seek(0);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return openFile(inputStream, sourceInfo.getFileTitle()) == OpenFileResult.OK;
} else if (inputStream instanceof BufferedInputStream) {
try {
((BufferedInputStream) inputStream).reset();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
return openFile(inputStream, sourceInfo.getFileTitle()) == OpenFileResult.OK;
}
}
return false;
sourceInfos.clear();
openFile(sourceInfosCopy);
return true;
}
}
@@ -363,14 +370,15 @@ public class Main {
public static OpenFileResult openFile(String swfFile, String fileTitle) {
try {
File file = new File(swfFile);
if (!file.exists()) {
View.showMessageDialog(null, "File not found", "Error", JOptionPane.ERROR_MESSAGE);
return OpenFileResult.NOT_FOUND;
}
swfFile = file.getCanonicalPath();
Configuration.addRecentFile(swfFile);
SWFSourceInfo sourceInfo = new SWFSourceInfo(new FileInputStream(swfFile), swfFile, fileTitle);
SWFSourceInfo sourceInfo = new SWFSourceInfo(null, swfFile, fileTitle);
OpenFileResult openResult = openFile(sourceInfo);
return openResult;
} catch (FileNotFoundException ex) {
View.showMessageDialog(null, "File not found", "Error", JOptionPane.ERROR_MESSAGE);
return OpenFileResult.NOT_FOUND;
} catch (IOException ex) {
View.showMessageDialog(null, "Cannot open file", "Error", JOptionPane.ERROR_MESSAGE);
return OpenFileResult.ERROR;
@@ -378,6 +386,10 @@ public class Main {
}
public static OpenFileResult openFile(SWFSourceInfo sourceInfo) {
return openFile(new SWFSourceInfo[] { sourceInfo });
}
public static OpenFileResult openFile(SWFSourceInfo[] newSourceInfos) {
if (mainFrame != null && !Configuration.openMultiple.get()) {
sourceInfos.clear();
mainFrame.closeAll();
@@ -396,9 +408,9 @@ public class Main {
});
Main.loadingDialog.setVisible(true);
OpenFileWorker wrk = new OpenFileWorker(sourceInfo);
OpenFileWorker wrk = new OpenFileWorker(newSourceInfos);
wrk.execute();
sourceInfos.add(sourceInfo);
sourceInfos.addAll(Arrays.asList(newSourceInfos));
return OpenFileResult.OK;
}
@@ -1009,6 +1009,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
actionPanel.clearSource();
}
updateUi();
updateTagTree();
}
public void close(SWF swf) {
@@ -1019,6 +1020,12 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
actionPanel.clearSource();
oldValue = null;
updateUi();
updateTagTree();
}
private void updateTagTree() {
tagTree.setModel(new TagTreeModel(this, swfs, null));
expandSwfRoots();
}
public void enableDrop(boolean value) {
@@ -1048,7 +1055,7 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
boolean updateNeeded = false;
for (TagNode n : nodes) {
if (n.tag instanceof ClassesListTreeModel) {
n.tag = new ClassesListTreeModel(abcPanel.classTree.treeList, n.getSwf(), filterField.getText());
((ClassesListTreeModel) n.tag).setFilter(filterField.getText());
updateNeeded = true;
}
}
@@ -1473,19 +1480,21 @@ public final class MainFrame extends AppRibbonFrame implements ActionListener, T
public List<TagNode> getASTagNode(JTree tree) {
List<TagNode> result = new ArrayList<>();
TreeModel tm = tree.getModel();
TagTreeModel tm = (TagTreeModel) tree.getModel();
if (tm == null) {
return result;
}
Object root = tm.getRoot();
for (int i = 0; i < tm.getChildCount(root); i++) {
Object node = tm.getChild(root, i);
if (node instanceof TagNode) {
Object tag = ((TagNode) tm.getChild(root, i)).tag;
if (tag != null) {
if ("scripts".equals(((TagNode) node).mark)) {
TreeNode root = tm.getRoot();
for (int j = 0; j < tm.getChildCount(root); j++) {
SWFRoot swfRoot = (SWFRoot) tm.getChild(root, j);
for (int i = 0; i < tm.getChildCount(swfRoot); i++) {
TreeNode node = tm.getChild(swfRoot, i);
if (node instanceof TagNode) {
TagNode tagNode = (TagNode) node;
TreeElementItem tag = tagNode.tag;
if (tag != null && "scripts".equals(tagNode.mark)) {
result.add((TagNode) node);
}
}
}
}
}
@@ -49,7 +49,7 @@ public class TagTreeModel implements TreeModel {
for (SWF swf : swfs) {
List<ContainerItem> objs = new ArrayList<>();
objs.addAll(swf.tags);
List<TagNode> list = createTagList(objs, null, abcPanel, swf);
List<TagNode> list = createTagList(objs, null, swf);
SWFRoot swfRoot = new SWFRoot(swf, new File(swf.file).getName(), list);
this.swfs.add(swfRoot);
@@ -75,7 +75,7 @@ public class TagTreeModel implements TreeModel {
return ret;
}
private List<TagNode> createTagList(List<ContainerItem> list, Object parent, ABCPanel abcPanel, SWF swf) {
private List<TagNode> createTagList(List<ContainerItem> list, Object parent, SWF swf) {
List<TagNode> ret = new ArrayList<>();
List<TagNode> frames = getTagNodesWithType(list, TagType.FRAME, parent, true);
List<TagNode> shapes = getTagNodesWithType(list, TagType.SHAPE, parent, true);
@@ -88,7 +88,6 @@ public class TagTreeModel implements TreeModel {
List<TagNode> movies = getTagNodesWithType(list, TagType.MOVIE, parent, true);
List<TagNode> sounds = getTagNodesWithType(list, TagType.SOUND, parent, true);
List<TagNode> binaryData = getTagNodesWithType(list, TagType.BINARY_DATA, parent, true);
List<TagNode> actionScript = new ArrayList<>();
for (int i = 0; i < sounds.size(); i++) {
if (sounds.get(i).tag instanceof SoundStreamHeadTypeTag) {
@@ -118,13 +117,13 @@ public class TagTreeModel implements TreeModel {
TagNode tti = new TagNode(t, t.getSwf());
if (((Container) t).getItemCount() > 0) {
List<ContainerItem> subItems = ((Container) t).getSubItems();
tti.subItems = createTagList(subItems, t, abcPanel, t.getSwf());
tti.subItems = createTagList(subItems, t, swf);
}
//ret.add(tti);
}
}
actionScript = SWF.createASTagList(list, null);
List<TagNode> actionScript = SWF.createASTagList(list, null);
TagNode textsNode = new TagNode(new StringNode(translate("node.texts")), swf);
textsNode.subItems.addAll(texts);
@@ -198,11 +197,13 @@ public class TagTreeModel implements TreeModel {
ret.add(framesNode);
}
if (abcPanel != null) {
boolean hasAbc = swf.abcList != null && !swf.abcList.isEmpty();
if (hasAbc) {
actionScriptNode.subItems.clear();
actionScriptNode.tag = abcPanel.classTree.getModel();
actionScriptNode.tag = swf.classTreeModel;
}
if ((!actionScriptNode.subItems.isEmpty()) || (abcPanel != null)) {
if ((!actionScriptNode.subItems.isEmpty()) || hasAbc) {
ret.add(actionScriptNode);
}
@@ -248,7 +249,7 @@ public class TagTreeModel implements TreeModel {
}
@Override
public Object getRoot() {
public TreeNode getRoot() {
return root;
}
@@ -16,14 +16,21 @@
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
/**
*
* @author JPEXS
*/
public class TagTreeRoot {
public class TagTreeRoot implements TreeNode {
@Override
public String toString() {
return "root";
}
@Override
public SWF getSwf() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
@@ -38,7 +38,6 @@ import javax.swing.tree.TreeSelectionModel;
public final class ClassesListTree extends JTree implements TreeSelectionListener {
private List<ABCContainerTag> abcList;
public List<MyEntry<ClassPath, ScriptPack>> treeList;
private ABCPanel abcPanel;
private SWF swf;
@@ -55,7 +54,6 @@ public final class ClassesListTree extends JTree implements TreeSelectionListene
this.abcPanel = abcPanel;
addTreeSelectionListener(this);
DefaultTreeCellRenderer treeRenderer = new DefaultTreeCellRenderer();
ClassLoader cldr = this.getClass().getClassLoader();
treeRenderer.setLeafIcon(View.getIcon("as16"));
setCellRenderer(treeRenderer);
}
@@ -96,21 +94,21 @@ public final class ClassesListTree extends JTree implements TreeSelectionListene
}
public void clearDoABCTags() {
this.abcList = null;
this.treeList = null;
this.swf = null;
setModel(null);
}
public void setDoABCTags(List<ABCContainerTag> list, SWF swf) {
this.abcList = list;
this.treeList = swf.getAS3Packs();
this.swf = swf;
setModel(new ClassesListTreeModel(this.treeList, swf));
ClassesListTreeModel model = new ClassesListTreeModel(this.treeList, swf);
this.swf.classTreeModel = model;
setModel(model);
}
public void applyFilter(String filter) {
setModel(new ClassesListTreeModel(this.treeList, swf, filter));
getModel().setFilter(filter);
}
@Override
@@ -142,10 +140,10 @@ public final class ClassesListTree extends JTree implements TreeSelectionListene
break;
}
}
abcPanel.navigator.setABC(abcList, scriptLeaf.abc);
abcPanel.navigator.setABC(swf.abcList, scriptLeaf.abc);
abcPanel.navigator.setClassIndex(classIndex, scriptLeaf.scriptIndex);
abcPanel.setAbc(scriptLeaf.abc);
abcPanel.decompiledTextArea.setScript(scriptLeaf, abcList);
abcPanel.decompiledTextArea.setScript(scriptLeaf, swf.abcList);
abcPanel.decompiledTextArea.setClassIndex(classIndex);
abcPanel.decompiledTextArea.setNoTrait();
abcPanel.detailPanel.methodTraitPanel.methodCodePanel.clear();
@@ -79,6 +79,7 @@ class ClassIndexVisitor implements TreeVisitor {
public class ClassesListTreeModel implements TreeModel, TreeElementItem {
private SWF swf;
private Tree classTree;
private List<MyEntry<ClassPath, ScriptPack>> list;
@@ -89,8 +90,14 @@ public class ClassesListTreeModel implements TreeModel, TreeElementItem {
public ClassesListTreeModel(List<MyEntry<ClassPath, ScriptPack>> list, SWF swf) {
this(list, swf, null);
}
public ClassesListTreeModel(List<MyEntry<ClassPath, ScriptPack>> list, SWF swf, String filter) {
this.swf = swf;
this.list = list;
setFilter(filter);
}
public final void setFilter(String filter) {
classTree = new Tree(swf);
for (MyEntry<ClassPath, ScriptPack> item : list) {
if (filter != null) {
@@ -104,8 +111,6 @@ public class ClassesListTreeModel implements TreeModel, TreeElementItem {
//String packageName = path.contains(".") ? path.substring(0, path.lastIndexOf(".")) : "";
classTree.add(item.key.className, item.key.packageStr, item.value);
}
this.list = list;
}
public Object getItemByPath(String fullPath) {