diff --git a/CHANGELOG.md b/CHANGELOG.md index 770b0c793..188473224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Show in Taglist command from dump view for tags - Create new empty SWF file - Checking missing needed character tags and their proper position (Marking them as red - with tooltip) +- [#1432] Save as EXE from commandline ### Fixed - Flash viewer - subtract blend mode @@ -2500,6 +2501,7 @@ All notable changes to this project will be documented in this file. [#1459]: https://www.free-decompiler.com/flash/issues/1459 [#1832]: https://www.free-decompiler.com/flash/issues/1832 [#1849]: https://www.free-decompiler.com/flash/issues/1849 +[#1432]: https://www.free-decompiler.com/flash/issues/1432 [#1712]: https://www.free-decompiler.com/flash/issues/1712 [#1857]: https://www.free-decompiler.com/flash/issues/1857 [#1455]: https://www.free-decompiler.com/flash/issues/1455 diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 022484b62..3d21104b1 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -67,6 +67,7 @@ import com.jpexs.decompiler.flash.exporters.amf.amf3.Amf3Exporter; 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.ExeExportMode; import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; @@ -316,7 +317,7 @@ public class CommandLineArgumentParser { out.println(" " + (cnt++) + ") [ ...]"); out.println(" ...opens SWF file(s) with the decompiler GUI"); } - + if (filter == null || filter.equals("proxy")) { out.println(" " + (cnt++) + ") -proxy [-P]"); out.println(" ...auto start proxy in the tray. Optional parameter -P specifies port for proxy. Defaults to 55555. "); @@ -658,6 +659,12 @@ public class CommandLineArgumentParser { out.println(" ...: Where to save merged file"); out.println(" ...: Input SWF file"); } + + if (filter == null || filter.equals("swf2exe")) { + out.println(" " + (cnt++) + ") -swf2exe "); + out.println(" ...export SWF to executable file"); + out.println(" ...: wrapper|projector_win||projector_mac|projector_linux"); + } printCmdLineUsageExamples(out, filter); } @@ -874,7 +881,9 @@ public class CommandLineArgumentParser { command = nextParam.substring(1); } - if (command.equals("abcmerge")) { + if (command.equals("swf2exe")) { + parseSwf2Exe(args); + } else if (command.equals("abcmerge")) { parseAbcMerge(args); } else if (command.equals("swf2swc")) { parseSwf2Swc(args); @@ -1112,6 +1121,19 @@ public class CommandLineArgumentParser { setConfigurations(args.pop()); } + private static void parseSwf2Exe(Stack args) { + if (args.size() != 3) { + badArguments("swf2exe"); + } + final String type = args.pop(); + final File outFile = new File(args.pop()); + final File swfFile = new File(args.pop()); + ExeExportMode exportMode = enumFromStr(type, ExeExportMode.class); + processReadSWF(swfFile, null, (SWF swf, OutputStream stdout) -> { + Main.saveFileToExe(swf, exportMode, outFile); + }); + } + private static void parseAbcMerge(Stack args) { if (args.size() < 2) { badArguments("abcmerge"); diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index 53c88105f..3831243fe 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -1119,6 +1119,62 @@ public class Main { saveFile(swf, outfile, SaveFileMode.SAVE, null); } + public static void saveFileToExe(SWF swf, ExeExportMode exeExportMode, File tmpFile) throws IOException { + try (FileOutputStream fos = new FileOutputStream(tmpFile); BufferedOutputStream bos = new BufferedOutputStream(fos)) { + switch (exeExportMode) { + case WRAPPER: + InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); + Helper.copyStream(exeStream, bos); + int width = swf.displayRect.Xmax - swf.displayRect.Xmin; + int height = swf.displayRect.Ymax - swf.displayRect.Ymin; + bos.write(width & 0xff); + bos.write((width >> 8) & 0xff); + bos.write((width >> 16) & 0xff); + bos.write((width >> 24) & 0xff); + bos.write(height & 0xff); + bos.write((height >> 8) & 0xff); + bos.write((height >> 16) & 0xff); + bos.write((height >> 24) & 0xff); + bos.write(Configuration.saveAsExeScaleMode.get()); + break; + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + File projectorFile = Configuration.getProjectorFile(exeExportMode); + if (projectorFile == null) { + String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); + logger.log(Level.SEVERE, message); + throw new IOException(message); + } + Helper.copyStream(new FileInputStream(projectorFile), bos); + bos.flush(); + break; + } + + long pos = fos.getChannel().position(); + swf.saveTo(bos); + + switch (exeExportMode) { + case PROJECTOR_WIN: + case PROJECTOR_MAC: + case PROJECTOR_LINUX: + bos.flush(); + int swfSize = (int) (fos.getChannel().position() - pos); + + // write magic number + bos.write(0x56); + bos.write(0x34); + bos.write(0x12); + bos.write(0xfa); + + bos.write(swfSize & 0xff); + bos.write((swfSize >> 8) & 0xff); + bos.write((swfSize >> 16) & 0xff); + bos.write((swfSize >> 24) & 0xff); + } + } + } + public static void saveFile(SWF swf, String outfile, SaveFileMode mode, ExeExportMode exeExportMode) throws IOException { File savedFile = new File(outfile); startSaving(savedFile); @@ -1128,60 +1184,13 @@ public class Main { } File outfileF = new File(outfile); File tmpFile = new File(outfile + ".tmp"); - try (FileOutputStream fos = new FileOutputStream(tmpFile); BufferedOutputStream bos = new BufferedOutputStream(fos)) { + + try { if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case WRAPPER: - InputStream exeStream = View.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/Swf2Exe.bin"); - Helper.copyStream(exeStream, bos); - int width = swf.displayRect.Xmax - swf.displayRect.Xmin; - int height = swf.displayRect.Ymax - swf.displayRect.Ymin; - bos.write(width & 0xff); - bos.write((width >> 8) & 0xff); - bos.write((width >> 16) & 0xff); - bos.write((width >> 24) & 0xff); - bos.write(height & 0xff); - bos.write((height >> 8) & 0xff); - bos.write((height >> 16) & 0xff); - bos.write((height >> 24) & 0xff); - bos.write(Configuration.saveAsExeScaleMode.get()); - break; - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - File projectorFile = Configuration.getProjectorFile(exeExportMode); - if (projectorFile == null) { - String message = "Projector not found, please place it to " + Configuration.getProjectorPath(); - logger.log(Level.SEVERE, message); - throw new IOException(message); - } - Helper.copyStream(new FileInputStream(projectorFile), bos); - bos.flush(); - break; - } - } - - long pos = fos.getChannel().position(); - swf.saveTo(bos); - - if (mode == SaveFileMode.EXE) { - switch (exeExportMode) { - case PROJECTOR_WIN: - case PROJECTOR_MAC: - case PROJECTOR_LINUX: - bos.flush(); - int swfSize = (int) (fos.getChannel().position() - pos); - - // write magic number - bos.write(0x56); - bos.write(0x34); - bos.write(0x12); - bos.write(0xfa); - - bos.write(swfSize & 0xff); - bos.write((swfSize >> 8) & 0xff); - bos.write((swfSize >> 16) & 0xff); - bos.write((swfSize >> 24) & 0xff); + saveFileToExe(swf, exeExportMode, tmpFile); + } else { + try (FileOutputStream fos = new FileOutputStream(tmpFile); BufferedOutputStream bos = new BufferedOutputStream(fos)) { + swf.saveTo(bos); } } } catch (Throwable t) { @@ -1359,7 +1368,7 @@ public class Main { Helper.freeMem(); showModeFrame(); return true; - } else { + } else { for (int i = sourceInfos.size() - 1; i >= 0; i--) { if (sourceInfos.get(i).isEmpty()) { sourceInfos.remove(i); @@ -1492,8 +1501,8 @@ public class Main { swf.setFileTitle(fileTitle); swf.displayRect = new RECT( - newFileDialog.getXMin(), - newFileDialog.getXMax(), + newFileDialog.getXMin(), + newFileDialog.getXMax(), newFileDialog.getYMin(), newFileDialog.getYmax() ); @@ -1506,23 +1515,23 @@ public class Main { if (newFileDialog.isAs3()) { f.actionScript3 = true; } - Tag t = f; + Tag t = f; t.setTimelined(swf); - swf.addTag(t); + swf.addTag(t); t = new SetBackgroundColorTag(swf, new RGB(newFileDialog.getBackgroundColor())); t.setTimelined(swf); swf.addTag(t); t = new ShowFrameTag(swf); t.setTimelined(swf); - swf.addTag(t); + swf.addTag(t); swf.frameCount = 1; swf.hasEndTag = true; list.add(swf); swf.swfList = list; mainFrame.getPanel().load(list, true); - + //select first frame - mainFrame.getPanel().setTagTreeSelectedNode(mainFrame.getPanel().getCurrentTree(), swf.getTimeline().getFrame(0)); + mainFrame.getPanel().setTagTreeSelectedNode(mainFrame.getPanel().getCurrentTree(), swf.getTimeline().getFrame(0)); } }