diff --git a/ParadoxSaveParser.CLI/Modes.cs b/ParadoxSaveParser.CLI/Modes.cs new file mode 100644 index 0000000..6ede7cb --- /dev/null +++ b/ParadoxSaveParser.CLI/Modes.cs @@ -0,0 +1,156 @@ +using System.Text.Json; +using ParadoxSaveParser.Lib; + +namespace ParadoxSaveParser.CLI; + +internal enum Mode +{ + Unset, Search, Interactive +} + +internal static class Modes +{ + internal static void Search(string searchQuery, IOPath inputPath, IOPath? outputPath) + { + using var inputStream = File.OpenRead(inputPath); + + using var outputStream = outputPath is null + ? Console.OpenStandardOutput() + : File.OpenWrite(outputPath.Value); + + var searchExpression = SearchExpressionCompiler.Compile(searchQuery); + + var parser = new SaveParserEU4(inputStream, searchExpression); + var parsedValue = parser.Parse(); + JsonSerializer.Serialize(outputStream, parsedValue, ParsedValueJsonContext.Default.DictionaryStringListObject); + } + + internal static void Interactive() + { + Console.Clear(); + Console.ResetColor(); + ColoredConsole.WriteTitle("interactive mode", fg: ConsoleColor.Cyan); + ColoredConsole.WriteLine($"working directory: '{Environment.CurrentDirectory}'", ConsoleColor.Gray); + IOPath? inputPath = null; + IOPath? outputPath = null; + + while (true) + { + try + { + ColoredConsole.Write("> ", ConsoleColor.Blue); + Console.ForegroundColor = ConsoleColor.Gray; + string? input = Console.ReadLine(); + if (string.IsNullOrEmpty(input)) + continue; + + const string helpMessage = + """ + Commands dont have arguments. Just write command name ant it will ask you for more information. + Avaliable commands: + h, help - show this message + q, quit, exit - close the program + pwd - show working directory + cd - change working directory + ls - show list of files in working directory + i, input - set input file path + o, output - set output file path + s, search - perform search in input file using expression + """; + + if (input.Contains(' ')) + { + ColoredConsole.WriteLine("Commands dont have arguments." + + " Just write command name ant it will ask you for more information.", + ConsoleColor.Red); + continue; + } + + switch (input) + { + default: + ColoredConsole.WriteLine("Unknown command, use 'help' for a list of commands.", + ConsoleColor.Red); + continue; + + case "q": + case "quit": + case "exit": + return; + + case "h": + case "help": + ColoredConsole.WriteLine(helpMessage, fg: ConsoleColor.White); + break; + + case "i": + case "input": + input = ColoredConsole.ReadLine("Input file path", + ConsoleColor.Blue); + if (string.IsNullOrEmpty(input)) + throw new NullReferenceException(); + inputPath = input; + break; + + case "o": + case "output": + input = ColoredConsole.ReadLine("Output file path [default=stdout]", + ConsoleColor.Blue); + if (string.IsNullOrEmpty(input)) + throw new ArgumentException("Input file path is required"); + inputPath = input; + break; + + case "s": + case "search": + if (inputPath is null) + throw new ArgumentException("Input file path is required"); + + var searchQuery = ColoredConsole.ReadLine("search expression", + ConsoleColor.Blue); + if (string.IsNullOrEmpty(searchQuery)) + throw new ArgumentException("Search expression is required"); + + ColoredConsole.WriteHLine('-', ConsoleColor.Cyan); + Console.ResetColor(); + Search(searchQuery, inputPath.Value, outputPath); + ColoredConsole.WriteHLine('-', ConsoleColor.Green); + break; + + case "pwd": + ColoredConsole.WriteLine(Environment.CurrentDirectory, ConsoleColor.White); + break; + + case "cd": + input = ColoredConsole.ReadLine("Change working directory to", + ConsoleColor.Blue); + if (!string.IsNullOrEmpty(input)) + { + Environment.CurrentDirectory = new IOPath(input).Str; + ColoredConsole.WriteLine(Environment.CurrentDirectory, ConsoleColor.Green); + } + + break; + + case "ls": + IOPath curdir = Directory.GetCurrent(); + foreach (var dir in Directory.GetDirectories(curdir)) + { + ColoredConsole.WriteLine(dir.RemoveBase(curdir).Str + Path.Sep, ConsoleColor.Cyan); + } + + foreach (var file in Directory.GetFiles(curdir)) + { + ColoredConsole.WriteLine(file.RemoveBase(curdir).Str, ConsoleColor.White); + } + + break; + } + } + catch (Exception ex) + { + ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red); + } + } + } +} \ No newline at end of file diff --git a/ParadoxSaveParser.CLI/Program.cs b/ParadoxSaveParser.CLI/Program.cs index 918313a..c18e8b3 100644 --- a/ParadoxSaveParser.CLI/Program.cs +++ b/ParadoxSaveParser.CLI/Program.cs @@ -1,108 +1,66 @@ 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; +global using DTLib.Console; +global using DTLib.Demystifier; +global using DTLib.Filesystem; +global using Directory = DTLib.Filesystem.Directory; +global using File = DTLib.Filesystem.File; +using ParadoxSaveParser.CLI; -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 +try { + Mode mode = Mode.Unset; + IOPath? inputPath = null; + IOPath? outputPath = null; + string? searchQuery = null; + + 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 in input file", + s => + { + searchQuery = s; + mode = Mode.Search; + }, + "search expression") + ) + .WithNoExit() + .ParseAndHandle(args); + + if (args.Length == 0) + mode = Mode.Interactive; + + switch (mode) + { + default: + throw new ArgumentOutOfRangeException(nameof(mode)); + case Mode.Unset: + throw new Exception("No action specified"); + case Mode.Search: + if (string.IsNullOrEmpty(searchQuery)) + throw new ArgumentException("Search expression is required"); + if (inputPath is null) + throw new ArgumentException("Input file path is required"); + Modes.Search(searchQuery, inputPath.Value, outputPath); + break; + case Mode.Interactive: + Modes.Interactive(); + break; + } } - -class Program +catch (Exception ex) { - 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); - } -} \ No newline at end of file + ColoredConsole.WriteLine(ex.ToStringDemystified(), ConsoleColor.Red); + Console.ResetColor(); + Environment.Exit(1); +} +Console.ResetColor(); \ No newline at end of file diff --git a/ParadoxSaveParser.Lib/ParsedValueJsonContext.cs b/ParadoxSaveParser.Lib/ParsedValueJsonContext.cs new file mode 100644 index 0000000..6ba94c2 --- /dev/null +++ b/ParadoxSaveParser.Lib/ParsedValueJsonContext.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace ParadoxSaveParser.Lib; + +[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 +{ +} \ No newline at end of file