mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-29 10:24:38 +00:00
Added: #2427 Commandline export with use of imported SWFs (importAssets tag)
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- [#2427] Commandline export with use of imported SWFs (importAssets tag)
|
||||
|
||||
### Fixed
|
||||
- [#2424] DefineEditText handling of letterSpacing, font size on incorrect values
|
||||
- [#2391] Double not operator in ternar operator expression
|
||||
@@ -3691,6 +3694,7 @@ Major version of SWF to XML export changed to 2.
|
||||
[alpha 9]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha8...alpha9
|
||||
[alpha 8]: https://github.com/jindrapetrik/jpexs-decompiler/compare/alpha7...alpha8
|
||||
[alpha 7]: https://github.com/jindrapetrik/jpexs-decompiler/releases/tag/alpha7
|
||||
[#2427]: https://www.free-decompiler.com/flash/issues/2427
|
||||
[#2424]: https://www.free-decompiler.com/flash/issues/2424
|
||||
[#2391]: https://www.free-decompiler.com/flash/issues/2391
|
||||
[#2375]: https://www.free-decompiler.com/flash/issues/2375
|
||||
|
||||
@@ -2330,7 +2330,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
|
||||
if (importedSwfs.containsKey(url)) {
|
||||
iSwf = importedSwfs.get(url);
|
||||
} else {
|
||||
iSwf = resolver.resolveUrl(url);
|
||||
iSwf = resolver.resolveUrl(this.file, url);
|
||||
importedSwfs.put(url, iSwf);
|
||||
}
|
||||
if (iSwf != null) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.jpexs.decompiler.flash;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* URL resolver interface.
|
||||
*
|
||||
@@ -26,8 +28,9 @@ public interface UrlResolver {
|
||||
/**
|
||||
* Resolves URL to SWF object.
|
||||
*
|
||||
* @param basePath Base SWF path
|
||||
* @param url URL
|
||||
* @return SWF object or null if not valid
|
||||
*/
|
||||
public SWF resolveUrl(String url);
|
||||
public SWF resolveUrl(String basePath, String url);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFCompression;
|
||||
import com.jpexs.decompiler.flash.SearchMode;
|
||||
import com.jpexs.decompiler.flash.SwfOpenException;
|
||||
import com.jpexs.decompiler.flash.UrlResolver;
|
||||
import com.jpexs.decompiler.flash.ValueTooLargeException;
|
||||
import com.jpexs.decompiler.flash.abc.ABC;
|
||||
import com.jpexs.decompiler.flash.abc.ABCInputStream;
|
||||
@@ -228,6 +229,7 @@ import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -494,7 +496,9 @@ public class CommandLineArgumentParser {
|
||||
}
|
||||
|
||||
AbortRetryIgnoreHandler handler = null;
|
||||
UrlResolver urlResolver = new ConsoleUrlResolver(false, false, false, new HashMap<>());
|
||||
Map<String, String> format = new HashMap<>();
|
||||
Map<String, String> changedImports = new LinkedHashMap<>();
|
||||
double zoom = 1;
|
||||
String charset = Charset.defaultCharset().name();
|
||||
boolean cliMode = false;
|
||||
@@ -598,6 +602,12 @@ public class CommandLineArgumentParser {
|
||||
}
|
||||
Configuration._debugMode.set(true);
|
||||
break;
|
||||
case "-importassets":
|
||||
urlResolver = parseImportAssets(args, changedImports);
|
||||
break;
|
||||
case "-changeimport":
|
||||
parseChangeImport(args, changedImports);
|
||||
break;
|
||||
default:
|
||||
break OUTER;
|
||||
}
|
||||
@@ -658,7 +668,7 @@ public class CommandLineArgumentParser {
|
||||
} else if (command.equals("proxy")) {
|
||||
parseProxy(args);
|
||||
} else if (command.equals("export")) {
|
||||
parseExport(selectionClasses, selection, selectionIds, args, handler, traceLevel, format, zoom, charset, exportEmbed, resampleWav, transparentBackground);
|
||||
parseExport(selectionClasses, selection, selectionIds, args, handler, traceLevel, format, zoom, charset, exportEmbed, resampleWav, transparentBackground, urlResolver);
|
||||
System.exit(0);
|
||||
} else if (command.equals("compress")) {
|
||||
parseCompress(args);
|
||||
@@ -1731,6 +1741,43 @@ public class CommandLineArgumentParser {
|
||||
System.err.println("Process affinity setting is only available on Windows platform.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseChangeImport(Stack<String> args, Map<String, String> changedImports) {
|
||||
if (args.size() < 2) {
|
||||
System.err.println("source and target of import expected");
|
||||
badArguments("changeimport");
|
||||
}
|
||||
changedImports.put(args.pop(), args.pop());
|
||||
}
|
||||
|
||||
private static UrlResolver parseImportAssets(Stack<String> args, Map<String, String> changedImports) {
|
||||
if (args.isEmpty()) {
|
||||
System.err.println("importassets options expected");
|
||||
badArguments("importassets");
|
||||
}
|
||||
String impOptionsStr = args.pop();
|
||||
String[] impOptionsArr = impOptionsStr.split(",", -1);
|
||||
boolean doResolve = false;
|
||||
boolean doAsk = false;
|
||||
boolean localOnly = false;
|
||||
for (String impOption:impOptionsArr) {
|
||||
switch (impOption) {
|
||||
case "yes":
|
||||
doResolve = true;
|
||||
break;
|
||||
case "ask":
|
||||
doAsk = true;
|
||||
break;
|
||||
case "local":
|
||||
localOnly = true;
|
||||
break;
|
||||
default:
|
||||
System.err.println("incorrect importassets option: " + impOption);
|
||||
badArguments("importassets");
|
||||
}
|
||||
}
|
||||
return new ConsoleUrlResolver(doResolve, doAsk, localOnly, changedImports);
|
||||
}
|
||||
|
||||
private static void parsePriority(Stack<String> args) {
|
||||
if (Platform.isWindows()) {
|
||||
@@ -1930,7 +1977,7 @@ public class CommandLineArgumentParser {
|
||||
|
||||
}
|
||||
|
||||
private static void parseExport(List<String> selectionClasses, Selection selection, Selection selectionIds, Stack<String> args, AbortRetryIgnoreHandler handler, Level traceLevel, Map<String, String> formats, double zoom, String charset, boolean exportEmbed, boolean resampleWav, boolean transparentBackground) {
|
||||
private static void parseExport(List<String> selectionClasses, Selection selection, Selection selectionIds, Stack<String> args, AbortRetryIgnoreHandler handler, Level traceLevel, Map<String, String> formats, double zoom, String charset, boolean exportEmbed, boolean resampleWav, boolean transparentBackground, UrlResolver urlResolver) {
|
||||
if (args.size() < 3) {
|
||||
badArguments("export");
|
||||
}
|
||||
@@ -2021,11 +2068,11 @@ public class CommandLineArgumentParser {
|
||||
startTimeSwf = System.currentTimeMillis();
|
||||
System.out.println("Start exporting " + inFile.getName());
|
||||
}
|
||||
|
||||
|
||||
OpenableSourceInfo sourceInfo = new OpenableSourceInfo(null, inFile.getAbsolutePath(), inFile.getName());
|
||||
SWF swf;
|
||||
try {
|
||||
swf = new SWF(new BufferedInputStream(new StdInAwareFileInputStream(inFile)), sourceInfo.getFile(), sourceInfo.getFileTitle(), null, Configuration.parallelSpeedUp.get(), false, true, charset);
|
||||
swf = new SWF(new BufferedInputStream(new StdInAwareFileInputStream(inFile)), sourceInfo.getFile(), sourceInfo.getFileTitle(), null, Configuration.parallelSpeedUp.get(), false, true, urlResolver, charset);
|
||||
} catch (FileNotFoundException | SwfOpenException ex) {
|
||||
// FileNotFoundException when anti virus software blocks to open the file
|
||||
logger.log(Level.SEVERE, "Failed to open swf: " + inFile.getName(), ex);
|
||||
|
||||
191
src/com/jpexs/decompiler/flash/console/ConsoleUrlResolver.java
Normal file
191
src/com/jpexs/decompiler/flash/console/ConsoleUrlResolver.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2025 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.console;
|
||||
|
||||
import com.jpexs.decompiler.flash.OpenableSourceInfo;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.UrlResolver;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Console Url resolver
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class ConsoleUrlResolver implements UrlResolver {
|
||||
|
||||
private final boolean doResolve;
|
||||
private final boolean doAsk;
|
||||
private final boolean localOnly;
|
||||
|
||||
private boolean ignoredInfoPrinted = false;
|
||||
private Character toAll = null;
|
||||
|
||||
private Map<String, String> importSources = new HashMap<>();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param doResolve Do resolve?
|
||||
* @param doAsk Do ask?
|
||||
* @param localOnly Local only?
|
||||
* @param importSources Import sources
|
||||
*/
|
||||
public ConsoleUrlResolver(boolean doResolve, boolean doAsk, boolean localOnly, Map<String, String> importSources) {
|
||||
this.doResolve = doResolve;
|
||||
this.doAsk = doAsk;
|
||||
this.localOnly = localOnly;
|
||||
this.importSources = importSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SWF resolveUrl(String basePath, String url) {
|
||||
|
||||
Character choice = toAll;
|
||||
String currentUrl = url;
|
||||
|
||||
if (importSources.containsKey(url)) {
|
||||
currentUrl = importSources.get(url);
|
||||
if (currentUrl.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
choice = 'y';
|
||||
} else {
|
||||
if (choice == null && doResolve) {
|
||||
choice = 'y';
|
||||
}
|
||||
if (!doResolve && !doAsk) {
|
||||
if (!ignoredInfoPrinted) {
|
||||
System.out.println("WARNING: SWF tried to import assets from external SWF, the request was ignored. (See --help -importAssets for more options)");
|
||||
}
|
||||
ignoredInfoPrinted = true;
|
||||
return null;
|
||||
}
|
||||
if (choice == null && doAsk) {
|
||||
choice = ask(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while(choice != 'n') {
|
||||
if (choice == 'c') {
|
||||
System.out.println("Enter new location instead (empty to cancel):");
|
||||
Scanner sc = new Scanner(System.in);
|
||||
String newUrl = sc.nextLine();
|
||||
importSources.put(url, newUrl);
|
||||
currentUrl = newUrl;
|
||||
if (currentUrl.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUrl.startsWith("http://") || currentUrl.startsWith("https://")) {
|
||||
if (localOnly && choice != 'c') {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
URL u = new URL(currentUrl);
|
||||
SWF ret = open(u.openStream(), null, currentUrl); //?
|
||||
return ret;
|
||||
} catch (Exception ex) {
|
||||
//ignore
|
||||
}
|
||||
} else {
|
||||
File swf = new File(new File(basePath).getParentFile(), currentUrl);
|
||||
if (swf.exists()) {
|
||||
try {
|
||||
SWF ret = open(new FileInputStream(swf), swf.getAbsolutePath(), swf.getName());
|
||||
return ret;
|
||||
} catch (Exception ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
// try .gfx if .swf failed
|
||||
if (currentUrl.endsWith(".swf")) {
|
||||
File gfx = new File(new File(basePath).getParentFile(), url.substring(0, url.length() - 4) + ".gfx");
|
||||
if (gfx.exists()) {
|
||||
try {
|
||||
SWF ret = open(new FileInputStream(gfx), gfx.getAbsolutePath(), gfx.getName());
|
||||
return ret;
|
||||
} catch (Exception ex) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.err.println("Cannot load imported SWF " + currentUrl);
|
||||
if (doAsk) {
|
||||
choice = 'c';
|
||||
} else {
|
||||
choice = 'n';
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private SWF open(InputStream is, String file, String fileTitle) throws Exception {
|
||||
OpenableSourceInfo sourceInfo = new OpenableSourceInfo(is, file, fileTitle);
|
||||
return new SWF(new BufferedInputStream(is), sourceInfo.getFile(), sourceInfo.getFileTitle(), null, Configuration.parallelSpeedUp.get(), false, true, this, null /*??*/);
|
||||
}
|
||||
|
||||
private String prompt() {
|
||||
Scanner sc = new Scanner(System.in);
|
||||
String s;
|
||||
System.out.print("Select action: (Y)es, (N)o, (C)ustom, (YA) Yes to all, (NA) No to all: ");
|
||||
s = sc.nextLine();
|
||||
s = s.toLowerCase(Locale.ENGLISH);
|
||||
return s;
|
||||
}
|
||||
|
||||
private char ask(String url) {
|
||||
String s;
|
||||
if (toAll != null) {
|
||||
s = "" + toAll;
|
||||
} else {
|
||||
System.out.println("The SWF file is trying to import assets from the following location:");
|
||||
System.out.println(url);
|
||||
s = prompt();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
switch (s) {
|
||||
case "ya":
|
||||
toAll = 'y';
|
||||
return 'y';
|
||||
case "na":
|
||||
toAll = 'n';
|
||||
return 'n';
|
||||
case "y":
|
||||
return 'y';
|
||||
case "n":
|
||||
return 'n';
|
||||
case "c":
|
||||
return 'c';
|
||||
}
|
||||
System.out.println("Invalid action.");
|
||||
s = prompt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,3 +444,17 @@ Pre-options:
|
||||
Ignores SWF background color when exporting frames
|
||||
and thus make background transparent.
|
||||
|
||||
-importAssets <importOptions>
|
||||
Applies to: -export
|
||||
Specifies options for importAssets tag - using external SWFs.
|
||||
<importOptions> format: (combination of yes,ask,local)
|
||||
yes = use external SWFs when available
|
||||
ask = ask whether to use external SWFs
|
||||
yes,ask = use external SWFs, ask for alternatives when not available
|
||||
yes,local = ignores URLs - SWFs starting with http/s:// prefix
|
||||
|
||||
-changeImport <source> <target>
|
||||
Applies to: -export
|
||||
Replaces <source> URL in importAssets tag with <target>
|
||||
for purposes of export. Can be used multiple times.
|
||||
|
||||
|
||||
@@ -1235,7 +1235,7 @@ public class Main {
|
||||
}
|
||||
}, Configuration.parallelSpeedUp.get(), false, true, new UrlResolver() {
|
||||
@Override
|
||||
public SWF resolveUrl(final String url) {
|
||||
public SWF resolveUrl(String file, final String url) {
|
||||
loadedUrls.add(url);
|
||||
File selFile = null;
|
||||
int opt = -1;
|
||||
|
||||
Reference in New Issue
Block a user