diff --git a/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java b/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java index 4f671e268..6b7792102 100644 --- a/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java +++ b/trunk/src/com/jpexs/decompiler/flash/BinarySWFBundle.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash; +import com.jpexs.helpers.ReReadableInputStream; import com.jpexs.helpers.StreamSearch; import java.io.IOException; import java.io.InputStream; @@ -32,7 +33,7 @@ import java.util.Set; public class BinarySWFBundle implements SWFBundle { private final SWFSearch search; public BinarySWFBundle(InputStream is){ - search=new SWFSearch(new StreamSearch(is)); + search = new SWFSearch(new StreamSearch(is)); } @Override @@ -50,7 +51,7 @@ public class BinarySWFBundle implements SWFBundle { } @Override - public SWF getSWF(String key) { + public ReReadableInputStream getSWF(String key) { if(!key.startsWith("[")){ return null; } @@ -59,7 +60,7 @@ public class BinarySWFBundle implements SWFBundle { } key = key.substring(1,key.length()-1); try{ - int index=Integer.parseInt(key); + int index = Integer.parseInt(key); if(index<0 || index>=length()){ return null; } @@ -72,8 +73,8 @@ public class BinarySWFBundle implements SWFBundle { } @Override - public Map getAll() { - Map ret=new HashMap<>(); + public Map getAll() { + Map ret = new HashMap<>(); for(String key:getKeys()){ ret.put(key, getSWF(key)); } @@ -84,5 +85,4 @@ public class BinarySWFBundle implements SWFBundle { public String getExtension() { return "bin"; } - } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWC.java b/trunk/src/com/jpexs/decompiler/flash/SWC.java index 5a132edd8..17ed20ea1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWC.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWC.java @@ -34,9 +34,10 @@ import org.xml.sax.helpers.DefaultHandler; */ public class SWC extends ZippedSWFBundle { - public SWC(InputStream is) { + public SWC(InputStream is) throws IOException { super(is); keySet.clear(); + this.is.reset(); ZipInputStream zip = new ZipInputStream(this.is); ZipEntry entry; try { diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 103252f9c..2fc020908 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -56,6 +56,7 @@ import com.jpexs.decompiler.flash.flv.AUDIODATA; 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.SWFList; import com.jpexs.decompiler.flash.helpers.collections.MyEntry; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; @@ -216,7 +217,7 @@ public final class SWF implements TreeItem { */ public boolean gfx = false; - public SWFSourceInfo sourceInfo; + public SWFList swfList; public String file; public String fileTitle; public boolean isAS3; diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFBundle.java b/trunk/src/com/jpexs/decompiler/flash/SWFBundle.java index 5d4b374c4..225d4971a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFBundle.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFBundle.java @@ -17,6 +17,9 @@ package com.jpexs.decompiler.flash; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.helpers.ReReadableInputStream; +import java.io.IOException; import java.util.Map; import java.util.Set; @@ -25,9 +28,10 @@ import java.util.Set; * @author JPEXS */ public interface SWFBundle { + public int length(); public Set getKeys(); - public SWF getSWF(String key); - public Map getAll(); + public ReReadableInputStream getSWF(String key) throws IOException; + public Map getAll() throws IOException; public String getExtension(); } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java b/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java index 39cf26798..c55dd12fa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFSearch.java @@ -29,8 +29,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; /** * @@ -42,7 +40,7 @@ public class SWFSearch { private boolean processed = false; private final Set listeners = new HashSet<>(); private final List swfStreams = new ArrayList<>(); - private final Map cachedSWFs = new HashMap<>(); + private final Map cachedSWFs = new HashMap<>(); public SWFSearch(Searchable s) { this.s = s; @@ -100,7 +98,7 @@ public class SWFSearch { processed = true; } - public SWF get(ProgressListener listener,int index) throws IOException { + public ReReadableInputStream get(ProgressListener listener, int index) throws IOException { if(!processed){ return null; } @@ -108,12 +106,7 @@ public class SWFSearch { return null; } if(!cachedSWFs.containsKey(index)){ - try { - cachedSWFs.put(index, new SWF(swfStreams.get(index), listener, false)); - } catch (InterruptedException ex) { - Logger.getLogger(SWFSearch.class.getName()).log(Level.SEVERE, null, ex); - return null; - } + cachedSWFs.put(index, swfStreams.get(index)); } return cachedSWFs.get(index); } diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFSourceInfo.java b/trunk/src/com/jpexs/decompiler/flash/SWFSourceInfo.java index 56b48a3bf..bd801d2d2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFSourceInfo.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFSourceInfo.java @@ -16,6 +16,13 @@ */ package com.jpexs.decompiler.flash; +import com.jpexs.helpers.Helper; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilterInputStream; +import java.io.IOException; import java.io.InputStream; /** @@ -46,4 +53,40 @@ public class SWFSourceInfo { return fileTitle; } + /** + * Get title of the file + * + * @return file title + */ + public String getFileTitleOrName() { + if (fileTitle != null) { + return fileTitle; + } + return file; + } + + public boolean isBundle() { + if (inputStream == null) { + String extension = Helper.getExtension(new File(file)); + return !(extension.equals(".swf") || extension.equals(".gfx")); + } + return false; + } + + public SWFBundle getBundle() throws IOException { + if (!isBundle()) { + return null; + } + + String extension = Helper.getExtension(new File(file)); + InputStream is = new BufferedInputStream(new FileInputStream(file)); + switch (extension) { + case ".swc": + return new SWC(is); + case ".zip": + return new ZippedSWFBundle(is); + default: + return new BinarySWFBundle(is); + } + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/ZippedSWFBundle.java b/trunk/src/com/jpexs/decompiler/flash/ZippedSWFBundle.java index 2a99dad27..7c3fe33ff 100644 --- a/trunk/src/com/jpexs/decompiler/flash/ZippedSWFBundle.java +++ b/trunk/src/com/jpexs/decompiler/flash/ZippedSWFBundle.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash; +import com.jpexs.helpers.LimitedInputStream; import com.jpexs.helpers.ReReadableInputStream; import java.io.IOException; import java.io.InputStream; @@ -34,17 +35,17 @@ import java.util.zip.ZipInputStream; * @author JPEXS */ public class ZippedSWFBundle implements SWFBundle { - protected Set keySet=new HashSet<>(); - private final Map cachedSWFs=new HashMap<>(); + protected Set keySet = new HashSet<>(); + private final Map cachedSWFs = new HashMap<>(); protected ReReadableInputStream is; public ZippedSWFBundle(InputStream is){ this.is = new ReReadableInputStream(is); - ZipInputStream zip=new ZipInputStream(this.is); - ZipEntry entry; + ZipInputStream zip = new ZipInputStream(this.is); + ZipEntry entry; try { - while((entry = zip.getNextEntry())!=null) + while((entry = zip.getNextEntry()) != null) { if(entry.getName().toLowerCase().endsWith(".swf") || entry.getName().toLowerCase().endsWith(".gfx")){ @@ -68,27 +69,24 @@ public class ZippedSWFBundle implements SWFBundle { } @Override - public SWF getSWF(String key) { + public ReReadableInputStream getSWF(String key) throws IOException { if(!keySet.contains(key)){ return null; } if(!cachedSWFs.containsKey(key)){ - ZipInputStream zip=new ZipInputStream(this.is); + this.is.reset(); + ZipInputStream zip = new ZipInputStream(this.is); ZipEntry entry; try { - while((entry = zip.getNextEntry())!=null) + while((entry = zip.getNextEntry()) != null) { if(entry.getName().equals(key)){ - try { - cachedSWFs.put(key, new SWF(zip, null,false)); - } catch (IOException ex) { - Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex); - } catch (InterruptedException ex) { - Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex); - } + ReReadableInputStream ris = new ReReadableInputStream(zip); + cachedSWFs.put(key, ris); break; } + zip.closeEntry(); } } catch (IOException ex) { Logger.getLogger(ZippedSWFBundle.class.getName()).log(Level.SEVERE, null, ex); @@ -100,8 +98,8 @@ public class ZippedSWFBundle implements SWFBundle { } @Override - public Map getAll() { - for(String key:getKeys()){ //cache everything first + public Map getAll() throws IOException { + for(String key : getKeys()){ //cache everything first getSWF(key); } return cachedSWFs; @@ -111,5 +109,4 @@ public class ZippedSWFBundle implements SWFBundle { public String getExtension() { return "zip"; } - } diff --git a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index bdfec8212..f4ee1df91 100644 --- a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.abc.RenameType; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; @@ -28,6 +29,8 @@ import com.jpexs.decompiler.graph.ExportMode; import com.jpexs.helpers.Helper; import com.sun.jna.Platform; import com.sun.jna.platform.win32.Kernel32; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -580,17 +583,22 @@ public class CommandLineArgumentParser { if (args.size() < 2) { badArguments(); } + try { - InputStream fis = new FileInputStream(args.remove()); - OutputStream fos = new FileOutputStream(args.remove()); - if (SWF.fws2cws(fis, fos)) { - System.out.println("OK"); - } else { - System.err.println("FAIL"); + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.remove())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.remove()))) { + if (SWF.fws2cws(fis, fos)) { + System.out.println("OK"); + } else { + System.err.println("FAIL"); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); } + System.exit(0); } @@ -600,18 +608,22 @@ public class CommandLineArgumentParser { } try { - InputStream fis = new FileInputStream(args.remove()); - OutputStream fos = new FileOutputStream(args.remove()); - if (SWF.decompress(fis, fos)) { - System.out.println("OK"); - System.exit(0); - } else { - System.err.println("FAIL"); - System.exit(1); + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.remove())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.remove()))) { + if (SWF.decompress(fis, fos)) { + System.out.println("OK"); + System.exit(0); + } else { + System.err.println("FAIL"); + System.exit(1); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); } + System.exit(0); } @@ -634,19 +646,24 @@ public class CommandLineArgumentParser { badArguments(); return; } + try { - InputStream fis = new FileInputStream(args.remove()); - OutputStream fos = new FileOutputStream(args.remove()); - if (SWF.renameInvalidIdentifiers(renameType, fis, fos)) { - System.out.println("OK"); - System.exit(0); - } else { - System.err.println("FAIL"); - System.exit(1); + try (InputStream fis = new BufferedInputStream(new FileInputStream(args.remove())); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(args.remove()))) { + if (SWF.renameInvalidIdentifiers(renameType, fis, fos)) { + System.out.println("OK"); + System.exit(0); + } else { + System.err.println("FAIL"); + System.exit(1); + } + } catch (FileNotFoundException ex) { + System.err.println("File not found."); } - } catch (FileNotFoundException ex) { - System.err.println("File not found."); + } catch (IOException ex) { + Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); } + System.exit(0); } @@ -657,7 +674,8 @@ public class CommandLineArgumentParser { try { Configuration.dumpTags.set(true); Configuration.parallelSpeedUp.set(false); - SWF swf = Main.parseSWF(args.remove()); + SWFSourceInfo sourceInfo = new SWFSourceInfo(null, args.remove(), null); + Main.parseSWF(sourceInfo); } catch (Exception ex) { Logger.getLogger(CommandLineArgumentParser.class.getName()).log(Level.SEVERE, null, ex); System.exit(1); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java index d30ba1158..0a744bd37 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromCacheFrame.java @@ -20,6 +20,7 @@ import com.jpexs.browsers.cache.CacheEntry; import com.jpexs.browsers.cache.CacheImplementation; import com.jpexs.browsers.cache.CacheReader; import com.jpexs.decompiler.flash.AppStrings; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.helpers.Helper; import com.jpexs.helpers.ReReadableInputStream; @@ -225,7 +226,8 @@ public class LoadFromCacheFrame extends AppFrame implements ActionListener { CacheEntry en = list.getSelectedValue(); if (en != null) { ReReadableInputStream str = new ReReadableInputStream(en.getResponseDataStream()); - Main.openFile(str, entryToFileName(en)); + SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, entryToFileName(en)); + Main.openFile(sourceInfo); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java index 165367c9b..e8116ee69 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/LoadFromMemoryFrame.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AppStrings; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.helpers.Helper; import com.jpexs.helpers.LimitedInputStream; @@ -195,7 +196,8 @@ public class LoadFromMemoryFrame extends AppFrame implements ActionListener { return; } str.mark(Integer.MAX_VALUE); - Main.openFile(str, swf.process + " [" + (index + 1) + "]"); + SWFSourceInfo sourceInfo = new SWFSourceInfo(str, null, swf.process + " [" + (index + 1) + "]"); + Main.openFile(sourceInfo); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java index d8b389d45..1004bb5e5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/Main.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AppStrings; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFBundle; import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.Version; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; @@ -33,6 +34,7 @@ import com.jpexs.helpers.Cache; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; import com.jpexs.helpers.ProgressListener; +import com.jpexs.helpers.ReReadableInputStream; import com.jpexs.helpers.Stopwatch; import com.jpexs.helpers.streams.SeekableInputStream; import com.sun.jna.Platform; @@ -207,28 +209,19 @@ public class Main { }); } - public static SWF parseSWF(String file) throws Exception { - SWFSourceInfo sourceInfo = new SWFSourceInfo(null, file, null); - return parseSWF(sourceInfo); - } - - public static SWF parseSWF(SWFSourceInfo sourceInfo) throws Exception { - SWF locswf; + public static SWFList parseSWF(SWFSourceInfo sourceInfo) throws Exception { + SWFList result = new SWFList(); InputStream inputStream = sourceInfo.getInputStream(); + SWFBundle bundle = null; if (inputStream == null) { - inputStream = new FileInputStream(sourceInfo.getFile()); + inputStream = new BufferedInputStream(new FileInputStream(sourceInfo.getFile())); + bundle = sourceInfo.getBundle(); logger.log(Level.INFO, "Load file: {0}", sourceInfo.getFile()); - } else if (inputStream instanceof SeekableInputStream) { + } else if (inputStream instanceof SeekableInputStream + || inputStream instanceof BufferedInputStream) { try { - ((SeekableInputStream) inputStream).seek(0); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - logger.log(Level.INFO, "Load stream: {0}", sourceInfo.getFileTitle()); - } else if (inputStream instanceof BufferedInputStream) { - try { - ((BufferedInputStream) inputStream).reset(); + inputStream.reset(); } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } @@ -236,12 +229,28 @@ public class Main { } Stopwatch sw = Stopwatch.startNew(); - locswf = new SWF(inputStream, new ProgressListener() { - @Override - public void progress(int p) { - startWork(AppStrings.translate("work.reading.swf"), p); + if (bundle != null) { + result.isBundle = true; + result.name = sourceInfo.getFileTitleOrName(); + for (ReReadableInputStream stream : bundle.getAll().values()) { + stream.reset(); + SWF swf = new SWF(stream, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p); + } + }, Configuration.parallelSpeedUp.get()); + result.add(swf); } - }, Configuration.parallelSpeedUp.get()); + } else { + SWF swf = new SWF(inputStream, new ProgressListener() { + @Override + public void progress(int p) { + startWork(AppStrings.translate("work.reading.swf"), p); + } + }, Configuration.parallelSpeedUp.get()); + result.add(swf); + } if (inputStream instanceof FileInputStream) { logger.log(Level.INFO, "File loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); @@ -250,37 +259,40 @@ public class Main { logger.log(Level.INFO, "Stream loaded in {0} seconds.", (sw.getElapsedMilliseconds() / 1000)); } - logger.log(Level.INFO, ""); - logger.log(Level.INFO, "== File information =="); - logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(locswf.fileSize)); - logger.log(Level.INFO, "Flash version: {0}", locswf.version); - int width = (locswf.displayRect.Xmax - locswf.displayRect.Xmin) / 20; - int height = (locswf.displayRect.Ymax - locswf.displayRect.Ymin) / 20; - logger.log(Level.INFO, "Width: {0}", width); - logger.log(Level.INFO, "Height: {0}", height); + result.sourceInfo = sourceInfo; + for (SWF swf : result) { + logger.log(Level.INFO, ""); + logger.log(Level.INFO, "== File information =="); + logger.log(Level.INFO, "Size: {0}", Helper.formatFileSize(swf.fileSize)); + logger.log(Level.INFO, "Flash version: {0}", swf.version); + int width = (swf.displayRect.Xmax - swf.displayRect.Xmin) / 20; + int height = (swf.displayRect.Ymax - swf.displayRect.Ymin) / 20; + logger.log(Level.INFO, "Width: {0}", width); + logger.log(Level.INFO, "Height: {0}", height); + + swf.swfList = result; + swf.file = sourceInfo.getFile(); + swf.fileTitle = sourceInfo.getFileTitle(); + swf.addEventListener(new EventListener() { + @Override + public void handleEvent(String event, Object data) { + if (event.equals("exporting")) { + startWork((String) data); + } + if (event.equals("getVariables")) { + startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data); + } + if (event.equals("deobfuscate")) { + startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data); + } + if (event.equals("rename")) { + startWork(AppStrings.translate("work.renaming") + "..." + (String) data); + } + } + }); + } - locswf.sourceInfo = sourceInfo; - locswf.file = sourceInfo.getFile(); - locswf.fileTitle = sourceInfo.getFileTitle(); - locswf.addEventListener(new EventListener() { - @Override - public void handleEvent(String event, Object data) { - if (event.equals("exporting")) { - startWork((String) data); - } - if (event.equals("getVariables")) { - startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data); - } - if (event.equals("deobfuscate")) { - startWork(AppStrings.translate("work.deobfuscating") + "..." + (String) data); - } - if (event.equals("rename")) { - startWork(AppStrings.translate("work.renaming") + "..." + (String) data); - } - } - }); - //} - return locswf; + return result; } public static void saveFile(SWF swf, String outfile) throws IOException { @@ -342,12 +354,11 @@ public class Main { @Override protected Object doInBackground() throws Exception { boolean first = true; - for (SWFSourceInfo sourceInfo : sourceInfos) { - //TODO: Handle non SWF filetypes (SWC,ZIP,Binary search) - SWF swf = null; + for (final SWFSourceInfo sourceInfo : sourceInfos) { + SWFList swfs = null; try { Main.startWork(AppStrings.translate("work.reading.swf") + "..."); - swf = parseSWF(sourceInfo); + swfs = parseSWF(sourceInfo); } catch (OutOfMemoryError ex) { logger.log(Level.SEVERE, null, ex); View.showMessageDialog(null, "Cannot load SWF file. Out of memory."); @@ -356,7 +367,7 @@ public class Main { View.showMessageDialog(null, "Cannot load SWF file."); } - final SWF swf1 = swf; + final SWFList swfs1 = swfs; final boolean first1 = first; first = false; try { @@ -365,7 +376,7 @@ public class Main { @Override public void run() { ensureMainFrame(); - mainFrame.getPanel().load(swf1, first1); + mainFrame.getPanel().load(swfs1, first1); } }); @@ -482,12 +493,7 @@ public class Main { return OpenFileResult.OK; } - public static OpenFileResult openFile(InputStream is, String fileTitle) { - SWFSourceInfo sourceInfo = new SWFSourceInfo(is, null, fileTitle); - return openFile(sourceInfo); - } - - public static void closeFile(SWF swf) { + public static void closeFile(SWFList swf) { sourceInfos.remove(swf.sourceInfo); mainFrame.getPanel().close(swf); } @@ -571,9 +577,7 @@ public class Main { JFileChooser fc = new JFileChooser(); fc.setCurrentDirectory(new File(Configuration.lastOpenDir.get())); FileFilter allSupportedFilter = new FileFilter() { - // todo: honfika: enalbe again after swf bundle imlpmented - //private String[] supportedExtensions = new String[] { ".swf", ".gfx", ".swc", ".zip" }; - private String[] supportedExtensions = new String[] { ".swf", ".gfx" }; + private final String[] supportedExtensions = new String[] { ".swf", ".gfx", ".swc", ".zip" }; @Override public boolean accept(File f) { @@ -617,7 +621,7 @@ public class Main { return AppStrings.translate("filter.swc"); } }; - // todo: honfika: enalbe again after swf bundle imlpmented fc.addChoosableFileFilter(swcFilter); + fc.addChoosableFileFilter(swcFilter); FileFilter gfxFilter = new FileFilter() { @Override @@ -644,7 +648,7 @@ public class Main { return AppStrings.translate("filter.zip"); } }; - // todo: honfika: enalbe again after swf bundle imlpmented fc.addChoosableFileFilter(zipFilter); + fc.addChoosableFileFilter(zipFilter); FileFilter binaryFilter = new FileFilter() { @Override @@ -657,7 +661,7 @@ public class Main { return AppStrings.translate("filter.binary"); } }; - // todo: honfika: enalbe again after swf bundle imlpmented fc.addChoosableFileFilter(binaryFilter); + fc.addChoosableFileFilter(binaryFilter); fc.setAcceptAllFileFilterUsed(false); JFrame f = new JFrame(); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java index 8cc8da28e..57a598c54 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrameRibbonMenu.java @@ -646,7 +646,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener { Main.openFileDialog(); break; case ACTION_CLOSE: - Main.closeFile(mainFrame.panel.getCurrentSwf()); + Main.closeFile(mainFrame.panel.getCurrentSwfList()); break; case ACTION_CLOSE_ALL: Main.closeAll(); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 1fcb58da1..9f72c97e9 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.AppStrings; import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.SWFSourceInfo; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.RenameType; import com.jpexs.decompiler.flash.abc.ScriptPack; @@ -37,7 +38,8 @@ import com.jpexs.decompiler.flash.gui.abc.treenodes.TreeElement; import com.jpexs.decompiler.flash.gui.action.ActionPanel; import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel; import com.jpexs.decompiler.flash.gui.player.PlayerControls; -import com.jpexs.decompiler.flash.gui.treenodes.SWFRoot; +import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode; +import com.jpexs.decompiler.flash.gui.treenodes.SWFNode; import com.jpexs.decompiler.flash.helpers.Freed; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; @@ -191,7 +193,7 @@ import javax.swing.tree.TreeSelectionModel; public final class MainPanel extends JPanel implements ActionListener, TreeSelectionListener, SearchListener, Freed { private final MainFrame mainFrame; - private final List swfs; + private final List swfs; private ABCPanel abcPanel; private ActionPanel actionPanel; private final JPanel welcomePanel; @@ -380,27 +382,29 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec replaceBinarySelectionMenuItem.setVisible(true); } - if (treeNode instanceof SWFRoot) { + if (treeNode instanceof SWFNode) { closeSelectionMenuItem.setVisible(true); } if (item instanceof Tag && swfs.size() > 1) { final Tag tag = (Tag) item; moveTagMenu.removeAll(); - for (final SWF targetSwf : swfs) { - if (targetSwf != tag.getSwf()) { - JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName()); - swfItem.addActionListener(new ActionListener() { + for (SWFList targetSwfList : swfs) { + for (final SWF targetSwf : targetSwfList) { + if (targetSwf != tag.getSwf()) { + JMenuItem swfItem = new JMenuItem(targetSwf.getShortFileName()); + swfItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ae) { - tag.getSwf().tags.remove(tag); - tag.setSwf(targetSwf); - targetSwf.tags.add(tag); - refreshTree(); - } - }); - moveTagMenu.add(swfItem); + @Override + public void actionPerformed(ActionEvent ae) { + tag.getSwf().tags.remove(tag); + tag.setSwf(targetSwf); + targetSwf.tags.add(tag); + refreshTree(); + } + }); + moveTagMenu.add(swfItem); + } } } moveTagMenu.setVisible(true); @@ -850,68 +854,72 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec enableDrop(true); } - public void load(SWF swf, boolean first) { - List objs = new ArrayList<>(); - objs.addAll(swf.tags); + public void load(SWFList newSwfs, boolean first) { + swfs.add(newSwfs); - ArrayList abcList = new ArrayList<>(); - getActionScript3(objs, abcList); + for (SWF swf : newSwfs) { + List objs = new ArrayList<>(); + objs.addAll(swf.tags); - swfs.add(swf); - swf.abcList = abcList; + ArrayList abcList = new ArrayList<>(); + getActionScript3(objs, abcList); - boolean hasAbc = !abcList.isEmpty(); - swf.isAS3 = hasAbc; - - tagTree.setModel(new TagTreeModel(mainFrame, swfs)); + swf.abcList = abcList; - if (hasAbc) { - if (abcPanel == null) { - abcPanel = new ABCPanel(this); - displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); - detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR); - } - abcPanel.setSwf(swf); - } else { - if (actionPanel == null) { - actionPanel = new ActionPanel(this); - displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); - } - } + boolean hasAbc = !abcList.isEmpty(); + swf.isAS3 = hasAbc; - expandSwfRoots(); + tagTree.setModel(new TagTreeModel(mainFrame, swfs)); - for (Tag t : swf.tags) { - if (t instanceof JPEGTablesTag) { - swf.jtt = (JPEGTablesTag) t; - } - } - - List list2 = new ArrayList<>(); - list2.addAll(swf.tags); - swf.characters = new HashMap<>(); - parseCharacters(swf, list2); - - if (Configuration.autoRenameIdentifiers.get()) { - try { - swf.deobfuscateIdentifiers(RenameType.TYPENUMBER); - swf.assignClassesToSymbols(); - clearCache(); - if (abcPanel != null) { - abcPanel.reload(); + if (hasAbc) { + if (abcPanel == null) { + abcPanel = new ABCPanel(this); + displayPanel.add(abcPanel, CARDACTIONSCRIPT3PANEL); + detailPanel.add(abcPanel.tabbedPane, DETAILCARDAS3NAVIGATOR); + } + abcPanel.setSwf(swf); + } else { + if (actionPanel == null) { + actionPanel = new ActionPanel(this); + displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); } - updateClassesList(); - } catch (InterruptedException ex) { - Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex); } - } - showDetail(DETAILCARDEMPTYPANEL); - showCard(CARDEMPTYPANEL); - updateUi(swf); + expandSwfNodes(); - if (first && Configuration.gotoMainClassOnStartup.get()) { - gotoDocumentClass(swf); + for (Tag t : swf.tags) { + if (t instanceof JPEGTablesTag) { + swf.jtt = (JPEGTablesTag) t; + } + } + + List list2 = new ArrayList<>(); + list2.addAll(swf.tags); + swf.characters = new HashMap<>(); + parseCharacters(swf, list2); + + if (Configuration.autoRenameIdentifiers.get()) { + try { + swf.deobfuscateIdentifiers(RenameType.TYPENUMBER); + swf.assignClassesToSymbols(); + clearCache(); + if (abcPanel != null) { + abcPanel.reload(); + } + updateClassesList(); + } catch (InterruptedException ex) { + Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex); + } + } + + showDetail(DETAILCARDEMPTYPANEL); + showCard(CARDEMPTYPANEL); + updateUi(swf); + + if (first && Configuration.gotoMainClassOnStartup.get()) { + gotoDocumentClass(swf); + } + first = false; } } @@ -946,8 +954,8 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (swfs.isEmpty()) { mainMenu.updateComponets(null, null); } else { - SWF swf = swfs.get(0); - updateUi(swf); + SWFList swfList = swfs.get(0); + updateUi(swfList.get(0)); } } @@ -965,10 +973,14 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec updateTagTree(); } - public void close(SWF swf) { - swfs.remove(swf); - if (abcPanel != null && abcPanel.swf == swf) { - abcPanel.clearSwf(); + public void close(SWFList swfList) { + swfs.remove(swfList); + if (abcPanel != null) { + for (SWF swf : swfList) { + if (abcPanel.swf == swf) { + abcPanel.clearSwf(); + } + } } if (actionPanel != null) { actionPanel.clearSource(); @@ -981,7 +993,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec private void updateTagTree() { tagTree.setModel(new TagTreeModel(mainFrame, swfs)); - expandSwfRoots(); + expandSwfNodes(); } public void enableDrop(boolean value) { @@ -1007,7 +1019,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } public void updateClassesList() { - List nodes = getASTagNode(tagTree); + List nodes = getASTreeNodes(tagTree); boolean updateNeeded = false; for (TreeNode n : nodes) { if (n.getItem() instanceof ClassesListTreeModel) { @@ -1029,7 +1041,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } public void doFilter() { - List nodes = getASTagNode(tagTree); + List nodes = getASTreeNodes(tagTree); boolean updateNeeded = false; for (TreeNode n : nodes) { if (n.getItem() instanceof ClassesListTreeModel) { @@ -1295,16 +1307,26 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec return ret; } - public List getASTagNode(TagTree tree) { + public List getASTreeNodes(TagTree tree) { List result = new ArrayList<>(); TagTreeModel tm = (TagTreeModel) tree.getModel(); if (tm == null) { return result; } TreeNode root = tm.getRoot(); - for (int j = 0; j < tm.getChildCount(root); j++) { - SWFRoot swfRoot = (SWFRoot) tm.getChild(root, j); - result.add(swfRoot.scriptsNode); + for (int i = 0; i < tm.getChildCount(root); i++) { + // first level node can be SWFNode and SWFBundleNode + TreeNode node = tm.getChild(root, i); + if (node instanceof SWFBundleNode) { + for (int j = 0; j < tm.getChildCount(node); j++) { + // child of SWFBundleNode should be SWFNode + SWFNode swfNode = (SWFNode) tm.getChild(node, j); + result.add(swfNode.scriptsNode); + } + } else if (node instanceof SWFNode) { + SWFNode swfNode = (SWFNode) tm.getChild(root, i); + result.add(swfNode.scriptsNode); + } } return result; } @@ -1348,78 +1370,89 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec List ret = new ArrayList<>(); List sel = getAllSelected(tagTree); - for (SWF swf : swfs) { - List tlsList = new ArrayList<>(); - List images = new ArrayList<>(); - List shapes = new ArrayList<>(); - List movies = new ArrayList<>(); - List sounds = new ArrayList<>(); - List texts = new ArrayList<>(); - List actionNodes = new ArrayList<>(); - List binaryData = new ArrayList<>(); - for (TreeNode d : sel) { - if (d.getItem().getSwf() != swf) { - continue; - } - if (d instanceof ContainerNode) { - ContainerNode n = (ContainerNode) d; - TreeNodeType nodeType = TagTree.getTreeNodeType(n.getItem()); - if (nodeType == TreeNodeType.IMAGE) { - images.add((Tag) n.getItem()); + for (SWFList swfList : swfs) { + for (SWF swf : swfList) { + List tlsList = new ArrayList<>(); + List images = new ArrayList<>(); + List shapes = new ArrayList<>(); + List movies = new ArrayList<>(); + List sounds = new ArrayList<>(); + List texts = new ArrayList<>(); + List actionNodes = new ArrayList<>(); + List binaryData = new ArrayList<>(); + for (TreeNode d : sel) { + if (d.getItem().getSwf() != swf) { + continue; } - if (nodeType == TreeNodeType.SHAPE) { - shapes.add((Tag) n.getItem()); + if (d instanceof ContainerNode) { + ContainerNode n = (ContainerNode) d; + TreeNodeType nodeType = TagTree.getTreeNodeType(n.getItem()); + if (nodeType == TreeNodeType.IMAGE) { + images.add((Tag) n.getItem()); + } + if (nodeType == TreeNodeType.SHAPE) { + shapes.add((Tag) n.getItem()); + } + if (nodeType == TreeNodeType.AS) { + actionNodes.add(n); + } + if (nodeType == TreeNodeType.MOVIE) { + movies.add((Tag) n.getItem()); + } + if (nodeType == TreeNodeType.SOUND) { + sounds.add((Tag) n.getItem()); + } + if (nodeType == TreeNodeType.BINARY_DATA) { + binaryData.add((Tag) n.getItem()); + } + if (nodeType == TreeNodeType.TEXT) { + texts.add((Tag) n.getItem()); + } } - if (nodeType == TreeNodeType.AS) { - actionNodes.add(n); - } - if (nodeType == TreeNodeType.MOVIE) { - movies.add((Tag) n.getItem()); - } - if (nodeType == TreeNodeType.SOUND) { - sounds.add((Tag) n.getItem()); - } - if (nodeType == TreeNodeType.BINARY_DATA) { - binaryData.add((Tag) n.getItem()); - } - if (nodeType == TreeNodeType.TEXT) { - texts.add((Tag) n.getItem()); + if (d instanceof TreeElement) { + if (((TreeElement) d).isLeaf()) { + TreeElement treeElement = (TreeElement) d; + tlsList.add((ScriptPack) treeElement.getItem()); + } } } - if (d instanceof TreeElement) { - if (((TreeElement) d).isLeaf()) { - TreeElement treeElement = (TreeElement) d; - tlsList.add((ScriptPack) treeElement.getItem()); + ret.addAll(swf.exportImages(handler, selFile + File.separator + "images", images)); + ret.addAll(SWF.exportShapes(handler, selFile + File.separator + "shapes", shapes)); + ret.addAll(swf.exportTexts(handler, selFile + File.separator + "texts", texts, isFormatted)); + ret.addAll(swf.exportMovies(handler, selFile + File.separator + "movies", movies)); + ret.addAll(swf.exportSounds(handler, selFile + File.separator + "sounds", sounds, isMp3OrWav, isMp3OrWav)); + ret.addAll(SWF.exportBinaryData(handler, selFile + File.separator + "binaryData", binaryData)); + List abcList = swf.abcList; + if (abcPanel != null) { + for (int i = 0; i < tlsList.size(); i++) { + ScriptPack tls = tlsList.get(i); + Main.startWork(translate("work.exporting") + " " + (i + 1) + "/" + tlsList.size() + " " + tls.getPath() + " ..."); + ret.add(tls.export(selFile, abcList, exportMode, Configuration.parallelSpeedUp.get())); + } + } else { + List allNodes = new ArrayList<>(); + List asNodes = getASTreeNodes(tagTree); + for (TreeNode asn : asNodes) { + allNodes.add(asn); + TagNode.setExport(allNodes, false); + TagNode.setExport(actionNodes, true); + ret.addAll(TagNode.exportNodeAS(handler, allNodes, selFile, exportMode, null)); } - } - } - ret.addAll(swf.exportImages(handler, selFile + File.separator + "images", images)); - ret.addAll(SWF.exportShapes(handler, selFile + File.separator + "shapes", shapes)); - ret.addAll(swf.exportTexts(handler, selFile + File.separator + "texts", texts, isFormatted)); - ret.addAll(swf.exportMovies(handler, selFile + File.separator + "movies", movies)); - ret.addAll(swf.exportSounds(handler, selFile + File.separator + "sounds", sounds, isMp3OrWav, isMp3OrWav)); - ret.addAll(SWF.exportBinaryData(handler, selFile + File.separator + "binaryData", binaryData)); - List abcList = swf.abcList; - if (abcPanel != null) { - for (int i = 0; i < tlsList.size(); i++) { - ScriptPack tls = tlsList.get(i); - Main.startWork(translate("work.exporting") + " " + (i + 1) + "/" + tlsList.size() + " " + tls.getPath() + " ..."); - ret.add(tls.export(selFile, abcList, exportMode, Configuration.parallelSpeedUp.get())); - } - } else { - List allNodes = new ArrayList<>(); - List asNodes = getASTagNode(tagTree); - for (TreeNode asn : asNodes) { - allNodes.add(asn); - TagNode.setExport(allNodes, false); - TagNode.setExport(actionNodes, true); - ret.addAll(TagNode.exportNodeAS(handler, allNodes, selFile, exportMode, null)); } } } return ret; } + public SWFList getCurrentSwfList() { + SWF swf = getCurrentSwf(); + if (swf == null) { + return null; + } + + return swf.swfList; + } + public SWF getCurrentSwf() { if (swfs == null || swfs.isEmpty()) { return null; @@ -1427,7 +1460,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec TreeNode treeNode = (TreeNode) tagTree.getLastSelectedPathComponent(); if (treeNode == null) { - return swfs.get(0); + return swfs.get(0).get(0); } return treeNode.getItem().getSwf(); @@ -2089,7 +2122,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec break; case ACTION_CLOSE_SWF: { - Main.closeFile(getCurrentSwf()); + Main.closeFile(getCurrentSwfList()); } } if (Main.isWorking()) { @@ -2136,9 +2169,14 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec @Override public void valueChanged(TreeSelectionEvent e) { TreeNode treeNode = (TreeNode) e.getPath().getLastPathComponent(); - SWF swf = treeNode.getItem().getSwf(); - if (swfs.contains(swf)) { - updateUi(swf); + TreeItem treeItem = treeNode.getItem(); + if (!(treeItem instanceof SWFList)) { + SWF swf = treeItem.getSwf(); + if (swfs.contains(swf.swfList)) { + updateUi(swf); + } else { + updateUi(); + } } else { updateUi(); } @@ -2244,9 +2282,9 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } - if (treeNode instanceof SWFRoot) { - SWFRoot swfRoot = (SWFRoot) treeNode; - SWF swf = swfRoot.getItem(); + if (treeNode instanceof SWFNode) { + SWFNode swfNode = (SWFNode) treeNode; + SWF swf = swfNode.getItem(); if (mainMenu.isInternalFlashViewerSelected()) { showCard(CARDSWFPREVIEWPANEL); swfPreviewPanel.load(swf); @@ -2373,9 +2411,8 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec int frameCount = 1; int frameRate = swf.frameRate; HashMap videoFrames = new HashMap<>(); - DefineVideoStreamTag vs = null; if (tagObj instanceof DefineVideoStreamTag) { - vs = (DefineVideoStreamTag) tagObj; + DefineVideoStreamTag vs = (DefineVideoStreamTag) tagObj; swf.populateVideoFrames(vs.getCharacterId(), swf.tags, videoFrames); frameCount = videoFrames.size(); } @@ -2736,11 +2773,11 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec tagTree.setModel(new TagTreeModel(mainFrame, swfs)); - expandSwfRoots(); + expandSwfNodes(); expandTreeNodes(tagTree, expandedNodes); } - public void expandSwfRoots() { + public void expandSwfNodes() { TreeModel model = tagTree.getModel(); Object node = model.getRoot(); int childCount = model.getChildCount(node); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/SWFList.java b/trunk/src/com/jpexs/decompiler/flash/gui/SWFList.java new file mode 100644 index 000000000..fc2386354 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/gui/SWFList.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010-2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.jpexs.decompiler.flash.gui; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFSourceInfo; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * + * @author JPEXS + */ +public class SWFList implements List, TreeItem { + + public String name; + public boolean isBundle; + public SWFSourceInfo sourceInfo; + public List swfs = new ArrayList<>(); + + @Override + public SWF getSwf() { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public Iterator iterator() { + return swfs.iterator(); + } + + @Override + public int size() { + return swfs.size(); + } + + @Override + public boolean isEmpty() { + return swfs.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return swfs.contains(o); + } + + @Override + public Object[] toArray() { + return swfs.toArray(); + } + + @Override + public T[] toArray(T[] ts) { + return swfs.toArray(ts); + } + + @Override + public boolean add(SWF e) { + return swfs.add(e); + } + + @Override + public boolean remove(Object o) { + return swfs.remove(o); + } + + @Override + public boolean containsAll(Collection clctn) { + return swfs.containsAll(clctn); + } + + @Override + public boolean addAll(Collection clctn) { + return swfs.addAll(clctn); + } + + @Override + public boolean removeAll(Collection clctn) { + return swfs.removeAll(clctn); + } + + @Override + public boolean retainAll(Collection clctn) { + return swfs.retainAll(clctn); + } + + @Override + public void clear() { + swfs.clear(); + } + + @Override + public boolean addAll(int i, Collection clctn) { + return swfs.addAll(i, clctn); + } + + @Override + public SWF get(int i) { + return swfs.get(i); + } + + @Override + public SWF set(int i, SWF e) { + return swfs.set(i, e); + } + + @Override + public void add(int i, SWF e) { + swfs.add(i, e); + } + + @Override + public SWF remove(int i) { + return swfs.remove(i); + } + + @Override + public int indexOf(Object o) { + return swfs.indexOf(0); + } + + @Override + public int lastIndexOf(Object o) { + return swfs.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return swfs.listIterator(); + } + + @Override + public ListIterator listIterator(int i) { + return swfs.listIterator(i); + } + + @Override + public List subList(int i, int i1) { + return swfs.subList(i, i1); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java b/trunk/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java index 68078a35f..98d051d8d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/TagTreeModel.java @@ -20,7 +20,9 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.gui.abc.ClassesListTreeModel; import com.jpexs.decompiler.flash.gui.abc.treenodes.ClassesListNode; import com.jpexs.decompiler.flash.gui.abc.treenodes.TreeElement; -import com.jpexs.decompiler.flash.gui.treenodes.SWFRoot; +import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode; +import com.jpexs.decompiler.flash.gui.treenodes.SWFContainerNode; +import com.jpexs.decompiler.flash.gui.treenodes.SWFNode; import com.jpexs.decompiler.flash.gui.treenodes.StringNode; import com.jpexs.decompiler.flash.gui.treenodes.TagTreeRoot; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; @@ -48,25 +50,38 @@ import javax.swing.tree.TreePath; public class TagTreeModel implements TreeModel { private final TagTreeRoot root = new TagTreeRoot(); - private final List swfs; - private final Map swfToSwfRoot; + private final List swfs; + private final Map swfToSwfNode; private final MainFrame mainFrame; - public TagTreeModel(MainFrame mainFrame, List swfs) { + public TagTreeModel(MainFrame mainFrame, List swfs) { this.mainFrame = mainFrame; this.swfs = new ArrayList<>(); - swfToSwfRoot = new HashMap<>(); - for (SWF swf : swfs) { - List objs = new ArrayList<>(); - objs.addAll(swf.tags); - ClassesListTreeModel classTreeModel = new ClassesListTreeModel(swf); - SWFRoot swfRoot = new SWFRoot(swf, new File(swf.getFileTitle()).getName()); - swfRoot.list = createTagList(objs, null, swf, swfRoot, classTreeModel); - this.swfs.add(swfRoot); - swfToSwfRoot.put(swf, swfRoot); + swfToSwfNode = new HashMap<>(); + for (SWFList swfList : swfs) { + if (swfList.isBundle) { + SWFBundleNode bundleNode = new SWFBundleNode(swfList, swfList.name); + for (SWF swf : swfList) { + bundleNode.swfs.add(createSwfNode(swf)); + } + this.swfs.add(bundleNode); + } else { + SWF swf = swfList.get(0); + this.swfs.add(createSwfNode(swf)); + } } } + private SWFNode createSwfNode(SWF swf) { + List objs = new ArrayList<>(); + objs.addAll(swf.tags); + ClassesListTreeModel classTreeModel = new ClassesListTreeModel(swf); + SWFNode swfNode = new SWFNode(swf, new File(swf.getFileTitle()).getName()); + swfNode.list = createTagList(objs, null, swf, swfNode, classTreeModel); + swfToSwfNode.put(swf, swfNode); + return swfNode; + } + private String translate(String key) { return mainFrame.translate(key); } @@ -86,7 +101,7 @@ public class TagTreeModel implements TreeModel { return ret; } - private List createTagList(List list, Tag parent, SWF swf, SWFRoot swfRoot, ClassesListTreeModel classTreeModel) { + private List createTagList(List list, Tag parent, SWF swf, SWFNode swfNode, ClassesListTreeModel classTreeModel) { boolean hasAbc = swf.abcList != null && !swf.abcList.isEmpty(); List ret = new ArrayList<>(); @@ -168,7 +183,7 @@ public class TagTreeModel implements TreeModel { actionScriptNode = new StringNode(new StringItem(translate("node.scripts"), swf)); actionScriptNode.subNodes.addAll(actionScript); } - swfRoot.scriptsNode = actionScriptNode; + swfNode.scriptsNode = actionScriptNode; if (!shapesNode.subNodes.isEmpty()) { ret.add(shapesNode); @@ -241,8 +256,8 @@ public class TagTreeModel implements TreeModel { return ret; } - public SWFRoot getSwfRoot(SWF swf) { - return swfToSwfRoot.get(swf); + public SWFNode getSwfNode(SWF swf) { + return swfToSwfNode.get(swf); } public TreePath getTagPath(TreeItem obj) { @@ -271,8 +286,10 @@ public class TagTreeModel implements TreeModel { } if (parent == root) { return swfs.get(index); - } else if (parent instanceof SWFRoot) { - return ((SWFRoot) parent).list.get(index); + } else if (parent instanceof SWFBundleNode) { + return ((SWFBundleNode) parent).swfs.get(index); + } else if (parent instanceof SWFNode) { + return ((SWFNode) parent).list.get(index); } return parentNode.subNodes.get(index); } @@ -284,8 +301,10 @@ public class TagTreeModel implements TreeModel { return swfs.size(); } else if (parent instanceof TreeElement) { return ((TreeElement) parent).getChildCount(); - } else if (parent instanceof SWFRoot) { - return ((SWFRoot) parent).list.size(); + } else if (parent instanceof SWFBundleNode) { + return ((SWFBundleNode) parent).swfs.size(); + } else if (parent instanceof SWFNode) { + return ((SWFNode) parent).list.size(); } else { if (parentNode.getItem() instanceof ClassesListTreeModel) { ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem(); @@ -311,8 +330,10 @@ public class TagTreeModel implements TreeModel { return swfs.indexOf(child); } else if (parent instanceof TreeElement) { return ((TreeElement) parent).getIndexOfChild((TreeElement) child); - } else if (parent instanceof SWFRoot) { - return ((SWFRoot) parent).list.indexOf(child); + } else if (parent instanceof SWFBundleNode) { + return ((SWFBundleNode) parent).swfs.indexOf(child); + } else if (parent instanceof SWFNode) { + return ((SWFNode) parent).list.indexOf(child); } else { if (parentNode.getItem() instanceof ClassesListTreeModel) { ClassesListTreeModel clt = (ClassesListTreeModel) parentNode.getItem(); diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java index 2c34c3164..386f0ae39 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/abc/ABCPanel.java @@ -107,7 +107,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se if ((txt != null) && (!txt.isEmpty())) { searchPanel.setOptions(ignoreCase, regexp); TagTreeModel ttm = (TagTreeModel) mainPanel.tagTree.getModel(); - TreeNode scriptsNode = ttm.getSwfRoot(mainPanel.getCurrentSwf()).scriptsNode; + TreeNode scriptsNode = ttm.getSwfNode(mainPanel.getCurrentSwf()).scriptsNode; final List found = new ArrayList<>(); if (scriptsNode.getItem() instanceof ClassesListTreeModel) { ClassesListTreeModel clModel = (ClassesListTreeModel) scriptsNode.getItem(); @@ -486,7 +486,7 @@ public class ABCPanel extends JPanel implements ItemListener, ActionListener, Se public void hilightScript(SWF swf, String name) { TagTreeModel ttm = (TagTreeModel) mainPanel.tagTree.getModel(); - TreeNode scriptsNode = ttm.getSwfRoot(swf).scriptsNode; + TreeNode scriptsNode = ttm.getSwfNode(swf).scriptsNode; if (scriptsNode.getItem() instanceof ClassesListTreeModel) { ClassesListTreeModel clModel = (ClassesListTreeModel) scriptsNode.getItem(); ScriptPack pack = null; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFBundleNode.java b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFBundleNode.java new file mode 100644 index 000000000..0c5abf639 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFBundleNode.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.jpexs.decompiler.flash.gui.treenodes; + +import com.jpexs.decompiler.flash.gui.SWFList; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class SWFBundleNode extends SWFContainerNode { + + private final String name; + public List swfs = new ArrayList<>(); + + public SWFBundleNode(SWFList swfList, String name) { + super(swfList); + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFContainerNode.java b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFContainerNode.java new file mode 100644 index 000000000..7e12486c7 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFContainerNode.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.jpexs.decompiler.flash.gui.treenodes; + +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.treenodes.TreeNode; + +/** + * + * @author JPEXS + */ +public abstract class SWFContainerNode extends TreeNode { + + public SWFContainerNode(TreeItem item) { + super(item); + } + +} diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFRoot.java b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFNode.java similarity index 89% rename from trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFRoot.java rename to trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFNode.java index e0c3a398c..881ac62f1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFRoot.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/treenodes/SWFNode.java @@ -24,13 +24,13 @@ import java.util.List; * * @author JPEXS */ -public class SWFRoot extends TreeNode { +public class SWFNode extends SWFContainerNode { private final String name; public List list; public TreeNode scriptsNode; - public SWFRoot(SWF swf, String name) { + public SWFNode(SWF swf, String name) { super(swf); this.name = name; } diff --git a/trunk/src/com/jpexs/helpers/Helper.java b/trunk/src/com/jpexs/helpers/Helper.java index 49144aa2a..1d2fda43c 100644 --- a/trunk/src/com/jpexs/helpers/Helper.java +++ b/trunk/src/com/jpexs/helpers/Helper.java @@ -738,6 +738,20 @@ public class Helper { } } + /* + * Get the extension of a file. + */ + public static String getExtension(File f) { + String ext = null; + String s = f.getName(); + int i = s.lastIndexOf('.'); + + if (i > 0 && i < s.length() - 1) { + ext = s.substring(i).toLowerCase(); + } + return ext; + } + public static void appendTimeoutComment(GraphTextWriter writer, int timeout) { writer.appendNoHilight("/*").newLine(); writer.appendNoHilight(" * ").appendNoHilight(AppStrings.translate("decompilationError")).newLine(); diff --git a/trunk/src/com/jpexs/helpers/MemoryInputStream.java b/trunk/src/com/jpexs/helpers/MemoryInputStream.java index b5fa101ca..63a5715c2 100644 --- a/trunk/src/com/jpexs/helpers/MemoryInputStream.java +++ b/trunk/src/com/jpexs/helpers/MemoryInputStream.java @@ -50,6 +50,11 @@ public class MemoryInputStream extends SeekableInputStream { this.pos = pos; } + @Override + public synchronized void reset() throws IOException { + seek(0); + } + @Override public int read() throws IOException { if (pos > count) { diff --git a/trunk/src/com/jpexs/helpers/ReReadableInputStream.java b/trunk/src/com/jpexs/helpers/ReReadableInputStream.java index dc582a3c0..a4781859c 100644 --- a/trunk/src/com/jpexs/helpers/ReReadableInputStream.java +++ b/trunk/src/com/jpexs/helpers/ReReadableInputStream.java @@ -58,6 +58,11 @@ public class ReReadableInputStream extends SeekableInputStream { this.pos = pos; } + @Override + public synchronized void reset() throws IOException { + seek(0); + } + @Override public int read() throws IOException { if (pos < count) { diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java index cd4d40831..a0e85f773 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript2AssemblerTest.java @@ -7,6 +7,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.HilightedTextWriter; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.graph.ExportMode; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.List; @@ -23,7 +24,7 @@ public class ActionScript2AssemblerTest extends ActionStript2TestBase { @BeforeClass public void init() throws IOException, InterruptedException { Configuration.autoDeobfuscate.set(false); - swf = new SWF(new FileInputStream("testdata/as2/as2.swf"), false); + swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2/as2.swf")), false); } @Test diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java index 42b1ee89e..e514963e5 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript2DeobfuscatorTest.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.helpers.HilightedTextWriter; import com.jpexs.decompiler.flash.tags.DoActionTag; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.List; @@ -38,7 +39,7 @@ public class ActionScript2DeobfuscatorTest extends ActionStript2TestBase { @BeforeClass public void init() throws IOException, InterruptedException { Configuration.autoDeobfuscate.set(true); - swf = new SWF(new FileInputStream("testdata/as2/as2.swf"), false); + swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2/as2.swf")), false); } @Test diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript2Test.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript2Test.java index d52eca5d7..288493e08 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript2Test.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript2Test.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.helpers.HilightedTextWriter; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import static org.testng.Assert.*; @@ -39,7 +40,7 @@ public class ActionScript2Test extends ActionStript2TestBase { Configuration.autoDeobfuscate.set(false); Configuration.decompile.set(true); Configuration.registerNameFormat.set("_loc%d_"); - swf = new SWF(new FileInputStream("testdata/as2/as2.swf"), false); + swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2/as2.swf")), false); } private void compareSrc(int frame, String expectedResult) { diff --git a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java index e62aa124e..ed1047583 100644 --- a/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java +++ b/trunk/test/com/jpexs/decompiler/flash/ActionScript3Test.java @@ -8,6 +8,7 @@ import com.jpexs.decompiler.flash.tags.DoABCDefineTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.graph.ExportMode; import com.jpexs.decompiler.graph.GraphTargetItem; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; @@ -28,7 +29,7 @@ public class ActionScript3Test { @BeforeClass public void init() throws IOException, InterruptedException { - swf = new SWF(new FileInputStream("testdata/as3/as3.swf"), false); + swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as3/as3.swf")), false); DoABCDefineTag tag = null; for (Tag t : swf.tags) { if (t instanceof DoABCDefineTag) { diff --git a/trunk/test/com/jpexs/decompiler/flash/RecompileTest.java b/trunk/test/com/jpexs/decompiler/flash/RecompileTest.java index 4f710d8f1..0e2efcfb5 100644 --- a/trunk/test/com/jpexs/decompiler/flash/RecompileTest.java +++ b/trunk/test/com/jpexs/decompiler/flash/RecompileTest.java @@ -16,7 +16,7 @@ public class RecompileTest { private void testRecompileOne(String filename) { try { - SWF swf = new SWF(new FileInputStream(TESTDATADIR + File.separator + filename), false); + SWF swf = new SWF(new BufferedInputStream(new FileInputStream(TESTDATADIR + File.separator + filename)), false); Configuration.debugCopy.set(true); swf.saveTo(new ByteArrayOutputStream()); } catch (IOException | InterruptedException ex) { diff --git a/trunk/test/com/jpexs/decompiler/flash/generators/AS2Generator.java b/trunk/test/com/jpexs/decompiler/flash/generators/AS2Generator.java index 42cba7338..8c196a01f 100644 --- a/trunk/test/com/jpexs/decompiler/flash/generators/AS2Generator.java +++ b/trunk/test/com/jpexs/decompiler/flash/generators/AS2Generator.java @@ -9,6 +9,7 @@ import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -22,7 +23,7 @@ public class AS2Generator { public static void main(String[] args) throws Exception { Configuration.autoDeobfuscate.set(false); - SWF swf = new SWF(new FileInputStream("testdata/as2/as2.swf"), false); + SWF swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as2/as2.swf")), false); DoABCDefineTag tag = null; DoActionTag doa = null; int frame = 0; diff --git a/trunk/test/com/jpexs/decompiler/flash/generators/AS3Generator.java b/trunk/test/com/jpexs/decompiler/flash/generators/AS3Generator.java index c49ad16ac..f7713dca1 100644 --- a/trunk/test/com/jpexs/decompiler/flash/generators/AS3Generator.java +++ b/trunk/test/com/jpexs/decompiler/flash/generators/AS3Generator.java @@ -10,6 +10,7 @@ import com.jpexs.decompiler.flash.tags.DoABCDefineTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.graph.ExportMode; import com.jpexs.decompiler.graph.GraphTargetItem; +import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.PrintWriter; import java.util.ArrayList; @@ -25,7 +26,7 @@ public class AS3Generator { public static void main(String[] args) throws Exception { Configuration.autoDeobfuscate.set(false); - SWF swf = new SWF(new FileInputStream("testdata/as3/as3.swf"),false); + SWF swf = new SWF(new BufferedInputStream(new FileInputStream("testdata/as3/as3.swf")),false); DoABCDefineTag tag = null; for (Tag t : swf.tags) { if (t instanceof DoABCDefineTag) {