From c8c482c8c0b84306baf54a9695b5295c28a9e65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 18 May 2025 17:38:45 +0200 Subject: [PATCH] Added: -configFile and -storeConfigFile commandline parameters for loading/storing configuration file --- CHANGELOG.md | 1 + .../flash/configuration/Configuration.java | 169 +++++++++++------- .../TomlConfigurationStorage.java | 21 ++- .../flash/locales/AppResources.properties | 2 +- .../console/CommandLineArgumentParser.java | 55 +++++- .../jpexs/decompiler/flash/console/help.txt | 10 ++ 6 files changed, 182 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 188ecf6c1..08371bdc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Configuration is now stored in easily readable/editable textual format (TOML) (saved also to older binary format, but loading is preffered from the new TOML file, when exists) +- `-configFile` and `-storeConfigFile` commandline parameters for loading/storing configuration file ### Fixed - [#2456] FLA export - NullPointer exception while exporting to CS4 or lower via commandline diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index f193934e6..310b8e43b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -53,7 +53,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.JOptionPane; /** * Configuration of FFDec. @@ -1030,125 +1029,123 @@ public final class Configuration { @ConfigurationDefaultBoolean(true) @ConfigurationCategory("script") public static ConfigurationItem warningAddFunction = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("export") public static ConfigurationItem linkAllClasses = null; - + @ConfigurationDefaultString("") @ConfigurationInternal public static ConfigurationItem recentColors = null; - - + @ConfigurationDefaultDouble(0.7) @ConfigurationName("gui.splitPaneEasyVertical.dividerLocationPercent") @ConfigurationInternal public static ConfigurationItem guiSplitPaneEasyVerticalDividerLocationPercent = null; - + @ConfigurationDefaultDouble(0.7) @ConfigurationName("gui.splitPaneEasyHorizontal.dividerLocationPercent") @ConfigurationInternal public static ConfigurationItem guiSplitPaneEasyHorizontalDividerLocationPercent = null; - + public static ConfigurationItem lastSessionEasySwf = null; - + @ConfigurationDefaultInt(1000) @ConfigurationCategory("limit") public static ConfigurationItem maxScriptLineLength = null; - + @ConfigurationDefaultString(".") @ConfigurationDirectory public static ConfigurationItem lastSolEditorDirectory = null; - + @ConfigurationDefaultBoolean(true) @ConfigurationCategory("display") public static ConfigurationItem halfTransparentParentLayersEasy = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem showRuler = null; - + @ConfigurationDefaultBoolean(true) @ConfigurationCategory("display") public static ConfigurationItem snapToGuides = null; - + @ConfigurationDefaultBoolean(true) @ConfigurationCategory("display") public static ConfigurationItem snapToObjects = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem snapToPixels = null; - + @ConfigurationDefaultBoolean(true) @ConfigurationCategory("display") public static ConfigurationItem snapAlign = null; - + @ConfigurationDefaultBoolean(true) @ConfigurationCategory("display") public static ConfigurationItem showGuides = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem lockGuides = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") - public static ConfigurationItem showGrid = null; - + public static ConfigurationItem showGrid = null; + @ConfigurationDefaultInt(10) @ConfigurationCategory("display") public static ConfigurationItem gridVerticalSpace = null; - + @ConfigurationDefaultInt(10) @ConfigurationCategory("display") public static ConfigurationItem gridHorizontalSpace = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem snapToGrid = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem gridOverObjects = null; - + @ConfigurationDefaultColor("#949494") @ConfigurationCategory("display") - public static ConfigurationItem gridColor = null; - + public static ConfigurationItem gridColor = null; + @ConfigurationDefaultColor("#00FF00") @ConfigurationCategory("display") public static ConfigurationItem guidesColor = null; - + @ConfigurationCategory("display") @ConfigurationDefaultString("NORMAL") public static ConfigurationItem gridSnapAccuracy = null; - + @ConfigurationCategory("display") @ConfigurationDefaultString("NORMAL") public static ConfigurationItem guidesSnapAccuracy = null; - + @ConfigurationDefaultInt(0) @ConfigurationCategory("display") public static ConfigurationItem snapAlignObjectHorizontalSpace = null; - + @ConfigurationDefaultInt(0) @ConfigurationCategory("display") public static ConfigurationItem snapAlignObjectVerticalSpace = null; - + @ConfigurationDefaultInt(0) @ConfigurationCategory("display") public static ConfigurationItem snapAlignStageBorder = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem snapAlignCenterAlignmentHorizontal = null; - + @ConfigurationDefaultBoolean(false) @ConfigurationCategory("display") public static ConfigurationItem snapAlignCenterAlignmentVertical = null; - - + private static Map configurationDescriptions = new LinkedHashMap<>(); private static Map configurationTitles = new LinkedHashMap<>(); @@ -1156,7 +1153,6 @@ public final class Configuration { WINDOWS, OSX, UNIX } - public static void setConfigurationDescriptions(Map configurationDescriptions) { Configuration.configurationDescriptions = configurationDescriptions; } @@ -1164,12 +1160,11 @@ public final class Configuration { public static void setConfigurationTitles(Map configurationTitles) { Configuration.configurationTitles = configurationTitles; } - - + public static String getConfigurationTitle(String confirationName) { return configurationTitles.get(confirationName); } - + public static String getConfigurationDescription(String confirationName) { return configurationDescriptions.get(confirationName); } @@ -1275,6 +1270,7 @@ public final class Configuration { /** * Get recent files + * * @return List of recent files */ public static List getRecentFiles() { @@ -1287,6 +1283,7 @@ public final class Configuration { /** * Add recent file + * * @param path Path to file */ public static void addRecentFile(String path) { @@ -1304,6 +1301,7 @@ public final class Configuration { /** * Remove recent file + * * @param path Path to file */ public static void removeRecentFile(String path) { @@ -1317,6 +1315,7 @@ public final class Configuration { /** * Get font to name map + * * @return Font to name map */ public static Map getFontToNameMap() { @@ -1331,6 +1330,7 @@ public final class Configuration { /** * Add font pair + * * @param fileName File name * @param fontId Font ID * @param fontName Font name @@ -1346,6 +1346,7 @@ public final class Configuration { /** * Get per-swf configuration. + * * @param fileName SWF File name * @return SWF specific configuration, null if not found */ @@ -1361,6 +1362,7 @@ public final class Configuration { /** * Get or create per-swf configuration. + * * @param fileName SWF File name * @return SWF specific configuration */ @@ -1376,6 +1378,7 @@ public final class Configuration { /** * Get per-swf custom configuration. + * * @param fileName SWF File name * @return SWF specific custom configuration, null if not found */ @@ -1391,6 +1394,7 @@ public final class Configuration { /** * Get or create per-swf custom configuration. + * * @param fileName SWF File name * @return SWF specific custom configuration */ @@ -1407,17 +1411,17 @@ public final class Configuration { private static String getConfigFile() throws IOException { return getFFDecHome() + storage.getConfigName(); } - + private static String getLegacyConfigFile() throws IOException { return getFFDecHome() + legacyStorage.getConfigName(); } - + /** * Save configuration to file */ public static void saveConfig() { try { - storage.saveToFile(getConfigFile()); + storage.saveToFile(getConfigFile()); } catch (IOException ex) { // ignore } @@ -1441,20 +1445,9 @@ public final class Configuration { //int processorCount = Runtime.getRuntime().availableProcessors(); } - /** - * Set configuration fields. - */ @SuppressWarnings("unchecked") - public static void setConfigurationFields() { + private static void loadFromMap(Map config) { try { - Map config; - - if (new File(getConfigFile()).exists()) { - config = storage.loadFromFile(getConfigFile()); - } else { - config = legacyStorage.loadFromFile(getLegacyConfigFile()); - } - for (Entry entry : getConfigurationFields(false, true).entrySet()) { String name = entry.getKey(); Field field = entry.getValue(); @@ -1469,7 +1462,7 @@ public final class Configuration { Object value = null; if (config.containsKey(name)) { value = config.get(name); - + Class type = ConfigurationItem.getConfigurationFieldType(field); if (value != null && !type.isAssignableFrom(value.getClass())) { System.out.println("Configuration item has a wrong type: " + name + " expected: " + type.getSimpleName() + " actual: " + value.getClass().getSimpleName()); @@ -1486,9 +1479,8 @@ public final class Configuration { } catch (IllegalArgumentException | IllegalAccessException | SecurityException ex) { // Reflection exceptions. This should never happen throw new Error(ex.getMessage()); - } catch (IOException ex) { - Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); } + if (playerLibLocation.get("").isEmpty()) { File swcFile = getPlayerSwcOld(); if (swcFile != null) { @@ -1503,13 +1495,46 @@ public final class Configuration { } } + /** + * Loads configuration from specific file. If it has .bin extension, + * it uses legacy storage, else it uses TOML storage. + * @param file File to load from + */ + public static void loadFromFile(String file) { + Map config; + if (file.toLowerCase(Locale.ENGLISH).endsWith(".bin")) { + config = legacyStorage.loadFromFile(file); + } else { + config = storage.loadFromFile(file); + } + loadFromMap(config); + } + + /** + * Set configuration fields. + */ + public static void setConfigurationFields() { + try { + Map config; + if (new File(getConfigFile()).exists()) { + config = storage.loadFromFile(getConfigFile()); + } else { + config = legacyStorage.loadFromFile(getLegacyConfigFile()); + } + loadFromMap(config); + } catch (IOException ex) { + Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex); + } + } + /** * Get default value for field + * * @param field Field * @return Default value */ @SuppressWarnings("unchecked") - public static Object getDefaultValue(Field field) { + public static Object getDefaultValue(Field field) { Object defaultValue = null; ConfigurationDefaultBoolean aBool = field.getAnnotation(ConfigurationDefaultBoolean.class); if (aBool != null) { @@ -1522,11 +1547,11 @@ public final class Configuration { ConfigurationDefaultString aString = field.getAnnotation(ConfigurationDefaultString.class); if (aString != null) { defaultValue = aString.value(); - + Class type = ConfigurationItem.getConfigurationFieldType(field); if (type.isEnum()) { return Enum.valueOf(type.asSubclass(Enum.class), (String) defaultValue); - } + } } ConfigurationDefaultDouble aDouble = field.getAnnotation(ConfigurationDefaultDouble.class); if (aDouble != null) { @@ -1538,7 +1563,7 @@ public final class Configuration { mingc.setTime(new Date(aCalendar.value())); defaultValue = mingc; } - + ConfigurationDefaultColor aColor = field.getAnnotation(ConfigurationDefaultColor.class); if (aColor != null) { Pattern p = Pattern.compile("#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$"); @@ -1549,7 +1574,7 @@ public final class Configuration { defaultValue = Color.black; } } - + if (defaultValue == null) { Class type = ConfigurationItem.getConfigurationFieldType(field); if (type.isEnum()) { @@ -1568,12 +1593,12 @@ public final class Configuration { * Get configuration fields * @return Configuration fields */ - /*public static Map getConfigurationFields(boolean alsoRemoved) { + /*public static Map getConfigurationFields(boolean alsoRemoved) { return getConfigurationFields(false, alsoRemoved); }*/ - /** * Get configuration fields + * * @param lowerCaseNames Lower case names * @return Configuration fields */ @@ -1601,6 +1626,7 @@ public final class Configuration { /** * Get code formatting + * * @return Code formatting */ public static CodeFormatting getCodeFormatting() { @@ -1616,26 +1642,28 @@ public final class Configuration { /** * Get number of parallel threads + * * @return Number of parallel threads */ public static int getParallelThreadCount() { int processorCount = Runtime.getRuntime().availableProcessors(); - + int threadCount = parallelSpeedUpThreadCount.get(); - + if (threadCount <= 0) { threadCount = processorCount - 1; } - + if (threadCount < 2) { threadCount = 2; } - + return threadCount; } /** * Get folder in FFDec home + * * @param folder Folder * @return Folder */ @@ -1650,6 +1678,7 @@ public final class Configuration { /** * Get flashlib path + * * @return Flashlib path */ public static File getFlashLibPath() { @@ -1658,6 +1687,7 @@ public final class Configuration { /** * Get projector path + * * @return Projector path */ public static File getProjectorPath() { @@ -1730,6 +1760,7 @@ public final class Configuration { /** * Get player SWC + * * @return Player SWC */ public static File getPlayerSWC() { @@ -1752,6 +1783,7 @@ public final class Configuration { /** * Get AIR SWC + * * @return AIR SWC */ public static File getAirSWC() { @@ -1809,6 +1841,7 @@ public final class Configuration { /** * Get projector file + * * @param exportMode Export mode * @return Projector file */ diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/TomlConfigurationStorage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/TomlConfigurationStorage.java index 2dd7d5a26..c5293825f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/TomlConfigurationStorage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/TomlConfigurationStorage.java @@ -241,22 +241,33 @@ public class TomlConfigurationStorage implements ConfigurationStorage { @Override public void saveToFile(String file) { - boolean showComments = false; - boolean modifiedOnly = true; - if (new File(file).exists()) { + saveToFile(file, null, null); + } + public void saveToFile(String file, Boolean showComments, Boolean modifiedOnly) { + if (new File(file).exists() && (showComments == null || modifiedOnly == null)) { TomlParseResult tomlResult; try { tomlResult = Toml.parse(Paths.get(file)); TomlTable metaTable = tomlResult.getTable("meta"); if (metaTable != null) { - showComments = metaTable.getBoolean("showComments") == Boolean.TRUE; - modifiedOnly = metaTable.getBoolean("modifiedOnly") == Boolean.TRUE; + if (showComments == null) { + showComments = metaTable.getBoolean("showComments") == Boolean.TRUE; + } + if (modifiedOnly == null) { + modifiedOnly = metaTable.getBoolean("modifiedOnly") == Boolean.TRUE; + } } } catch (IOException ex) { //ignore } } + if (showComments == null) { + showComments = false; + } + if (modifiedOnly == null) { + modifiedOnly = true; + } try ( Writer w = new FileWriter(file); PrintWriter pw = new PrintWriter(w)) { String header = AppResources.translate("configurationFile").replace("%app%", ApplicationInfo.APPLICATION_NAME); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties index 3329e3f66..510337574 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/AppResources.properties @@ -53,7 +53,7 @@ valueType.Integer = Integer valueType.String = String configurationFile = Configuration file of %app% configurationFile.comment = Line starting with hash is a comment -configurationFile.modify = WARNING: This file is overwritten on every application exit. If you make changes to values, make sure FFDec is not running. +configurationFile.modify = WARNING: This file is overwritten on every application exit. If you make changes to values, make sure the application is not running. configurationFile.meta = Section - Meta info of how configuration is stored configurationFile.meta.saveDate = When this file was last modified by the app configurationFile.meta.appVersion = Last version of tha app that modified this file diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index e2ad31db5..652c7d310 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -54,6 +54,7 @@ import com.jpexs.decompiler.flash.amf.amf3.Traits; import com.jpexs.decompiler.flash.amf.amf3.types.ObjectType; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; +import com.jpexs.decompiler.flash.configuration.TomlConfigurationStorage; import com.jpexs.decompiler.flash.docs.As12PCodeDocs; import com.jpexs.decompiler.flash.docs.As3PCodeDocs; import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; @@ -282,7 +283,7 @@ public class CommandLineArgumentParser { if (ConfigurationItem.isInternal(field)) { continue; } - + ConfigurationItem item = ConfigurationItem.getItem(field); Object value = item.get(); Class type = ConfigurationItem.getConfigurationFieldType(field); @@ -562,6 +563,9 @@ public class CommandLineArgumentParser { return null; } break; + case "-configfile": + parseConfigFile(args); + break; case "-onerror": handler = parseOnError(args); break; @@ -779,6 +783,9 @@ public class CommandLineArgumentParser { printHeader(); printConfigurationSettings(); System.exit(0); + } else if (nextParam.equals("-storeconfigfile")) { + parseStoreConfigFile(args); + System.exit(0); } else if (nextParam.equals("-help") || nextParam.equals("--help") || nextParam.equals("/?") || nextParam.equals("\\_") /* /? translates as this on windows */) { parseHelp(args); System.exit(0); @@ -859,7 +866,8 @@ public class CommandLineArgumentParser { cp = new String[]{cp[0], "1"}; } - Field field = fields.get(cp[0].toLowerCase(Locale.ENGLISH)); + String nameLowerCase = cp[0].toLowerCase(Locale.ENGLISH); + Field field = fields.get(nameLowerCase); ConfigurationItem item = ConfigurationItem.getItem(field); String stringValue = cp[1]; Class type = ConfigurationItem.getConfigurationFieldType(field); @@ -903,6 +911,9 @@ public class CommandLineArgumentParser { ConfigurationItem uncheckedItem = (ConfigurationItem) item; uncheckedItem.set(enumValue); } + if ("locale".equals(nameLowerCase)) { + Main.initLang(); + } } } @@ -932,6 +943,46 @@ public class CommandLineArgumentParser { setConfigurations(args.pop()); } + + private static void parseStoreConfigFile(Stack args) { + boolean comments = false; + boolean all = false; + String configFile; + while(true) { + if (args.isEmpty()) { + System.err.println("Configuration file expected"); + badArguments("configfile"); + } + configFile = args.pop(); + if (configFile.equals("-comments")) { + comments = true; + } else if (configFile.equals("-all")) { + all = true; + } else { + if (!args.isEmpty()) { + badArguments("configfile"); + } + break; + } + } + TomlConfigurationStorage storage = new TomlConfigurationStorage(); + storage.saveToFile(configFile, comments, !all); + System.out.println("Configuration saved to \"" + configFile + "\""); + } + + private static void parseConfigFile(Stack args) { + if (args.isEmpty()) { + System.err.println("Configuration file expected"); + badArguments("configfile"); + } + String configFile = args.pop(); + if (!new File(configFile).exists()) { + System.err.println("Configuration file \"" + configFile + "\" does not exist!"); + badArguments("configfile"); + } + Configuration.loadFromFile(configFile); + System.out.println("Configuration loaded from the file \"" + configFile + "\""); + } private static void parseSwf2Exe(Stack args, String charset) { if (args.size() != 3) { diff --git a/src/com/jpexs/decompiler/flash/console/help.txt b/src/com/jpexs/decompiler/flash/console/help.txt index d966d641e..735c5af3e 100644 --- a/src/com/jpexs/decompiler/flash/console/help.txt +++ b/src/com/jpexs/decompiler/flash/console/help.txt @@ -295,6 +295,11 @@ alias /? List all available configuration keys and current values. These keys can be used in -config pre-option. +-storeConfigFile [-comments] [-all] + Stores current configuration to a file . + With -comments argument it adds titles and descriptions. + With -all argument it exports all configs, not even modified. + -translator Runs the Translator app for FFDec localization @@ -394,6 +399,11 @@ Pre-options: Otherwise it is used only once. DO NOT PUT space between comma (,) and next value. +-configFile + Applies to: * + Use configuration from a file . TOML file format is expected. + When it has .bin extension, legacy storage is used. + -onerror (abort|retry |ignore) Applies to: -export, -importScript Error handling mode.