From 4639e61c8e3a83c21ab7fbdf2cf6f28687da1cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Mon, 9 Oct 2023 18:25:25 +0200 Subject: [PATCH] Added #2097 Commandline command `-header` to modify SWF header values --- CHANGELOG.md | 4 +- .../console/CommandLineArgumentParser.java | 242 +++++++++++++++++- 2 files changed, 244 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71c4d02e0..424612add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. - [#2090] Support for Mochicrypt packed binarydata tags - loading SWF as subtree - [#2079] Replace DefineSprite with GIF, Bulk import sprites from GIFs, also from commandline - [#116] Show invalid utf-8 bytes in Strings as `{invalid_utf8:xxx}` +- [#2097] Commandline command `-header` to modify SWF header values ### Fixed - Close action on SWF inside DefineBinaryData @@ -3145,12 +3146,13 @@ Major version of SWF to XML export changed to 2. [alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7 [#2090]: https://www.free-decompiler.com/flash/issues/2090 [#2079]: https://www.free-decompiler.com/flash/issues/2079 +[#116]: https://www.free-decompiler.com/flash/issues/116 +[#2097]: https://www.free-decompiler.com/flash/issues/2097 [#2093]: https://www.free-decompiler.com/flash/issues/2093 [#1678]: https://www.free-decompiler.com/flash/issues/1678 [#2094]: https://www.free-decompiler.com/flash/issues/2094 [#2095]: https://www.free-decompiler.com/flash/issues/2095 [#223]: https://www.free-decompiler.com/flash/issues/223 -[#116]: https://www.free-decompiler.com/flash/issues/116 [#1449]: https://www.free-decompiler.com/flash/issues/1449 [#2070]: https://www.free-decompiler.com/flash/issues/2070 [#2073]: https://www.free-decompiler.com/flash/issues/2073 diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index ea3040a88..caf2ad427 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -235,6 +235,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * @@ -747,6 +749,19 @@ public class CommandLineArgumentParser { out.println(" ...use AIR (airglobal.swc) for AS3 compilation instead of playerglobal.swc"); out.println(" (use in combination with other commands)"); } + + if (filter == null || filter.equals("header")) { + out.println(" " + (cnt++) + ") -header -set [-set ...] []"); + out.println(" ...prints header or sets SWF header values (with -set arguments) in and saves it to "); + out.println(" Available keys: version"); + out.println(" gfx (true/false)"); + out.println(" displayrect ([x1,y1,x2,y2])"); + out.println(" width"); + out.println(" height"); + out.println(" framecount"); + out.println(" framerate"); + out.println(" For width, height and displayrect subvalues you can use suffix px for pixel values. Otherwise its twips."); + } printCmdLineUsageExamples(out, filter); @@ -844,6 +859,13 @@ public class CommandLineArgumentParser { if (filter == null || filter.equals("swf2exe")) { out.println(PREFIX + "-swf2exe wrapper result.exe myfile.swf"); } + + if (filter == null || filter.equals("header")) { + out.println(PREFIX + "-header myfile.swf"); + out.println(PREFIX + "-header -set version 10 -set width 800px -set framerate 23.5 myfile.swf outfile.swf"); + out.println(PREFIX + "-header -set displayrect [0,0,800px,600px] myfile.swf outfile.swf"); + out.println(PREFIX + "-header -set gfx true myfile.swf outfile.swf"); + } if (!exampleFound) { out.println("Sorry, no example found for command " + filter + ", Let us know in issue tracker when you need it."); @@ -983,7 +1005,10 @@ public class CommandLineArgumentParser { command = nextParam.substring(1); } - if (command.equals("translator")) { + if (command.equals("header")) { + parseHeader(args); + System.exit(0); + } else if (command.equals("translator")) { Translator.main(new String[]{}); } else if (command.equals("swf2exe")) { parseSwf2Exe(args, charset); @@ -4686,6 +4711,221 @@ public class CommandLineArgumentParser { System.exit(2); } } + + private static void parseHeader(Stack args) { + if (args.isEmpty()) { + badArguments("header"); + } + Float frameRate = null; + Integer frameCount = null; + Integer width = null; + Integer height = null; + Integer x = null; + Integer y = null; + Boolean gfx = null; + Integer version = null; + + Pattern displayRectPattern = Pattern.compile("\\[(?[0-9.]+)(?px)?,(?[0-9.]+)(?px)?,(?[0-9.]+)(?px)?,(?[0-9.]+)(?px)?\\]"); + + boolean printOnly = args.size() == 1; + + while (!args.isEmpty()) { + String arg = args.pop(); + if (arg.equals("-set")) { + if (args.size() < 3) { + badArguments("header"); + } + String key = args.pop(); + String value = args.pop(); + switch(key.toLowerCase()) { + case "version": + try { + version = Integer.valueOf(value); + } catch (NumberFormatException nfe) { + badArguments("header"); + } + break; + case "gfx": + gfx = parseBooleanConfigValue(value); + if (gfx == null) { + badArguments("header"); + } + break; + case "displayrect": + Matcher displayRectMatcher = displayRectPattern.matcher(value); + if (!displayRectMatcher.matches()) { + badArguments("header"); + } + if (displayRectMatcher.group("x1px") != null) { + x = (int) Math.round(Float.parseFloat(displayRectMatcher.group("x1")) * SWF.unitDivisor); + } else { + try { + x = Integer.valueOf(displayRectMatcher.group("x1")); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + if (displayRectMatcher.group("y1px") != null) { + y = (int) Math.round(Float.parseFloat(displayRectMatcher.group("y1")) * SWF.unitDivisor); + } else { + try { + y = Integer.valueOf(displayRectMatcher.group("y1")); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + + int x2 = 0; + int y2 = 0; + + if (displayRectMatcher.group("x2px") != null) { + x2 = (int) Math.round(Float.parseFloat(displayRectMatcher.group("x2")) * SWF.unitDivisor); + } else { + try { + x2 = Integer.parseInt(displayRectMatcher.group("x2")); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + if (displayRectMatcher.group("y2px") != null) { + y2 = (int) Math.round(Float.parseFloat(displayRectMatcher.group("y2")) * SWF.unitDivisor); + } else { + try { + y2 = Integer.parseInt(displayRectMatcher.group("y2")); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + + width = x2 - x; + height = y2 - y; + break; + case "width": + if (value.endsWith("px")) { + value = value.substring(0, value.length() - 2).trim(); + try { + width = (int)Math.round(Float.parseFloat(value) * SWF.unitDivisor); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } else { + try { + width = Integer.valueOf(value); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + break; + case "height": + if (value.endsWith("px")) { + value = value.substring(0, value.length() - 2).trim(); + try { + height = (int)Math.round(Float.parseFloat(value) * SWF.unitDivisor); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } else { + try { + height = Integer.valueOf(value); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + } + break; + case "framecount": + try { + frameCount = Integer.valueOf(value); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + break; + case "framerate": + try { + frameRate = Float.valueOf(value); + } catch(NumberFormatException nfe) { + badArguments("header"); + } + break; + default: + badArguments("header"); + } + } else { + args.push(arg); + break; + } + } + + if (!printOnly && args.size() != 2) { + badArguments("header"); + } + + File file = new File(args.pop()); + File outfile = printOnly ? null : new File(args.pop()); + PrintWriter pw = new PrintWriter(System.out); + try { + try (StdInAwareFileInputStream is = new StdInAwareFileInputStream(file)) { + SWF swf = new SWF(is, Configuration.parallelSpeedUp.get(), true); + + if (printOnly) { + pw.println("[header]"); + pw.println("fileSize=" + swf.fileSize); + pw.println("version=" + swf.version); + pw.println("compression=" + swf.compression); + pw.println("gfx=" + swf.gfx); + pw.println("displayRect=[" + swf.displayRect.Xmin + ", " +swf.displayRect.Ymin + ", " + swf.displayRect.Xmax + ", " + swf.displayRect.Ymax + "]"); + pw.println("width=" + swf.displayRect.getWidth()); + pw.println("widthPx=" + doubleToString(swf.displayRect.getWidth() / SWF.unitDivisor)); + pw.println("height=" + swf.displayRect.getHeight()); + pw.println("heightPx=" + doubleToString(swf.displayRect.getHeight() / SWF.unitDivisor)); + pw.println("frameCount=" + swf.frameCount); + pw.println("frameRate=" + doubleToString(swf.frameRate)); + pw.flush(); + return; + } + if (version != null) { + swf.version = version; + pw.println("version set to " + version); + } + if (gfx != null) { + swf.gfx = gfx; + pw.println("gfx set to " + gfx); + } + if (x != null) { + swf.displayRect.Xmin = x; + pw.println("displayrect.x1 set to " + x); + } + if (y != null) { + swf.displayRect.Ymin = y; + pw.println("displayrect.y1 set to " + y); + } + if (width != null) { + swf.displayRect.Xmax = swf.displayRect.Xmin + width; + pw.println("displayrect.x2 set to " + swf.displayRect.Xmax); + } + if (height != null) { + swf.displayRect.Ymax = swf.displayRect.Ymin + height; + pw.println("displayrect.y2 set to " + swf.displayRect.Ymax); + } + if (frameCount != null) { + swf.frameCount = frameCount; + pw.println("framecount set to " + frameCount); + } + if (frameRate != null) { + swf.frameRate = frameRate; + pw.println("framerate set to " + frameRate); + } + + try (FileOutputStream fos = new FileOutputStream(outfile)) { + swf.saveTo(fos); + } + pw.println("Successfully saved"); + } + } catch (IOException | InterruptedException e) { + System.err.println("I/O error during reading"); + System.exit(2); + } + pw.flush(); + } private static FilenameFilter getSwfFilter() { return (File dir, String name) -> name.toLowerCase(Locale.ENGLISH).endsWith(".swf");