global using System; using System.Collections.Generic; using System.IO; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; using DTLib.Console; using DTLib.Demystifier; using DTLib.Filesystem; using ParadoxSaveParser.Lib; using File = DTLib.Filesystem.File; using Directory = DTLib.Filesystem.Directory; namespace ParadoxSaveParser.CLI; [JsonSourceGenerationOptions(MaxDepth = 1024, WriteIndented = true)] [JsonSerializable(typeof(Dictionary>))] [JsonSerializable(typeof(List))] [JsonSerializable(typeof(string))] [JsonSerializable(typeof(long))] [JsonSerializable(typeof(double))] public partial class ParsedValueJsonContext : JsonSerializerContext { } class Program { private static IOPath? _inputPath; private static IOPath? _outputPath; private static string? _searchQuery; static void Main(string[] args) { try { new LaunchArgumentParser( new LaunchArgument(["-i", "--input"], "Set input file path", s => _inputPath = s, "gamestate or zip file"), new LaunchArgument(["-o", "--output"], "Set output file path", s => _outputPath = s, "json file [default=stdout]"), new LaunchArgument(["-s", "--search"], "Search expression", Search), new LaunchArgument(["-e", "--search-expression"], "Set search expression", s => _searchQuery = s, "expression in my custom format" ) ) .WithNoExit() .ParseAndHandle(args); Console.Clear(); Console.ResetColor(); ColoredConsole.WriteTitle("interactive mode", fg: ConsoleColor.Cyan); ColoredConsole.WriteLine($"working directory: '{Environment.CurrentDirectory}'", ConsoleColor.Gray); string? input = null; for (int i = 0; i < 10 && string.IsNullOrEmpty(input); i++) input = ColoredConsole.ReadLine("input file", ConsoleColor.Blue); _inputPath = input ?? throw new NullReferenceException(); input = ColoredConsole.ReadLine("output file [default=stdout]", ConsoleColor.Blue); if (!string.IsNullOrEmpty(input)) _outputPath = input; _searchQuery = ColoredConsole.ReadLine("search expression", ConsoleColor.Blue); ColoredConsole.WriteHLine('-', ConsoleColor.Cyan); Console.ResetColor(); Search(); } catch (Exception ex) { ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red); Console.ResetColor(); Environment.Exit(1); } Console.ResetColor(); } private static void Search() { if(_inputPath == null) throw new ArgumentException("Input file path is required"); using var inputStream = File.OpenRead(_inputPath.Value); using var outputStream = _outputPath is null ? Console.OpenStandardOutput() : File.OpenWrite(_outputPath.Value); var searchExpression = string.IsNullOrEmpty(_searchQuery) ? null : SearchExpressionCompiler.Compile(_searchQuery); var parser = new SaveParserEU4(inputStream, searchExpression); var parsedValue = parser.Parse(); JsonSerializer.Serialize(outputStream, parsedValue, ParsedValueJsonContext.Default.DictionaryStringListObject); } }