485 lines
17 KiB
C#
485 lines
17 KiB
C#
using static ExeToBat.Generator;
|
|
using static System.ConsoleUtils;
|
|
using Mono.Options;
|
|
using System.Text.Json;
|
|
using System.Reflection;
|
|
|
|
namespace ExeToBat
|
|
{
|
|
class Console
|
|
{
|
|
public static void Main(string[] args) => new Console().Show(args);
|
|
|
|
public Console() { }
|
|
|
|
private readonly Generator generator = new();
|
|
|
|
public void Show(string[] args)
|
|
{
|
|
string? config = null;
|
|
bool help = false;
|
|
|
|
OptionSet options =
|
|
new()
|
|
{
|
|
{
|
|
"c|config=",
|
|
"the config file used for automatic generation",
|
|
v => config = v
|
|
},
|
|
{ "h|help", "show this message and exit", v => help = v != null },
|
|
};
|
|
|
|
try
|
|
{
|
|
List<string> extra = options.Parse(args);
|
|
if (help)
|
|
{
|
|
Help(options);
|
|
}
|
|
else if (config != null)
|
|
{
|
|
try
|
|
{
|
|
generator.LoadConfig(GeneratorConfig.FromJson(File.ReadAllText(config)));
|
|
Generate(interactive: false);
|
|
}
|
|
catch (Exception e) when (e is IOException || e is JsonException)
|
|
{
|
|
System.Console.WriteLine("Failed to load config {0}:\n{1}", config, e.Message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MainMenu();
|
|
}
|
|
}
|
|
catch (OptionException e)
|
|
{
|
|
System.Console.WriteLine("Invalid arguments: {0}", e);
|
|
Help(options);
|
|
}
|
|
}
|
|
|
|
public void Show() => MainMenu();
|
|
|
|
private void Help(OptionSet options)
|
|
{
|
|
string version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "";
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine(string.Format("ExeToBat {0}", version));
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("From github.com/clragon/ExeToBat");
|
|
System.Console.WriteLine("Licensed under GNUPL v3");
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("Usage:");
|
|
options.WriteOptionDescriptions(System.Console.Out);
|
|
}
|
|
|
|
private void MainMenu()
|
|
{
|
|
Dictionary<string, Action> options =
|
|
new()
|
|
{
|
|
{ "Files", ChooseSource },
|
|
{ "Save config", SaveConfig },
|
|
{ "Load config", LoadConfig },
|
|
{ "Generate", Generate },
|
|
};
|
|
|
|
new ListMenu<string>(options.Keys.ToList())
|
|
{
|
|
DisplayTitle = (Options) => System.Console.WriteLine("ExeToBat"),
|
|
DisplayEntry = (Options, index, i) =>
|
|
{
|
|
System.Console.WriteLine("[{0}] {1}", i, Options[index]);
|
|
},
|
|
HandleEntry = (Options, index) =>
|
|
{
|
|
options[Options[index]]();
|
|
return false;
|
|
},
|
|
ExitEntry = "Exit",
|
|
}.Show();
|
|
}
|
|
|
|
private void SaveConfig()
|
|
{
|
|
bool IsInputValid = false;
|
|
while (!IsInputValid)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine("ExeToBat > Config > Save");
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "Output File");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
input = input?.Trim()?.Replace("\"", "");
|
|
if (!string.IsNullOrEmpty(input))
|
|
{
|
|
try
|
|
{
|
|
File.WriteAllText(input, generator.SaveConfig().ToJson());
|
|
IsInputValid = true;
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
System.Console.WriteLine("Failed to save config:\n{0}", e.Message);
|
|
ResetInput();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadConfig()
|
|
{
|
|
bool IsInputValid = false;
|
|
while (!IsInputValid)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine("ExeToBat > Config > Load");
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "Config File");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
input = input?.Trim()?.Replace("\"", "");
|
|
if (!string.IsNullOrEmpty(input))
|
|
{
|
|
try
|
|
{
|
|
generator.LoadConfig(GeneratorConfig.FromJson(File.ReadAllText(input)));
|
|
IsInputValid = true;
|
|
}
|
|
catch (Exception e) when (e is IOException || e is JsonException)
|
|
{
|
|
System.Console.WriteLine("Failed to load config {0}:\n{1}", input, e.Message);
|
|
ResetInput();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ChooseSource()
|
|
{
|
|
new ListMenu<SourceFile>(generator.Sources)
|
|
{
|
|
DisplayTitle = (sources) =>
|
|
{
|
|
System.Console.WriteLine("ExeToBat > Files");
|
|
System.Console.WriteLine(
|
|
"[{0}] ({1})",
|
|
Convert.ToString(0).PadLeft(Convert.ToString(sources.Count).Length, ' '),
|
|
"Add Files"
|
|
);
|
|
},
|
|
DisplayEntry = (sources, index, i) =>
|
|
System.Console.WriteLine(
|
|
"[{0}] {1}",
|
|
Convert.ToString(i).PadLeft(Convert.ToString(sources.Count).Length, ' '),
|
|
Path.GetFileName(sources[index].Path)
|
|
),
|
|
ZeroEntry = (sources) =>
|
|
{
|
|
AddSource();
|
|
return false;
|
|
},
|
|
HandleEntry = (sources, index) =>
|
|
{
|
|
ManageSource(sources[index]);
|
|
return false;
|
|
},
|
|
RefreshEntries = (sources) => generator.Sources,
|
|
}.Show();
|
|
}
|
|
|
|
private void AddSource()
|
|
{
|
|
bool IsInputValid = false;
|
|
while (!IsInputValid)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine("ExeToBat > Files > Add");
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "File/Folder");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
input = input?.Trim()?.Replace("\"", "");
|
|
switch (input)
|
|
{
|
|
case var i when string.IsNullOrEmpty(i):
|
|
IsInputValid = true;
|
|
break;
|
|
case var i when Directory.Exists(i):
|
|
IsInputValid = true;
|
|
foreach (string file in Directory.GetFiles(i))
|
|
{
|
|
generator.Sources.Add(new SourceFile(file));
|
|
}
|
|
break;
|
|
case var i when File.Exists(i):
|
|
IsInputValid = true;
|
|
generator.Sources.Add(new SourceFile(i));
|
|
break;
|
|
|
|
default:
|
|
ResetInput();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ManageSource(SourceFile source)
|
|
{
|
|
Dictionary<string, Func<bool>> options =
|
|
new()
|
|
{
|
|
{
|
|
"Edit",
|
|
() =>
|
|
{
|
|
ModifySource(source);
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
"Position",
|
|
() =>
|
|
{
|
|
EditPosition(source);
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
"Delete",
|
|
() =>
|
|
{
|
|
generator.Sources.Remove(source);
|
|
return true;
|
|
}
|
|
},
|
|
};
|
|
|
|
new ListMenu<string>(options.Keys.ToList())
|
|
{
|
|
DisplayTitle = (Options) =>
|
|
System.Console.WriteLine(
|
|
"ExeToBat > Files > {0}",
|
|
Path.GetFileName(source.Path)
|
|
),
|
|
DisplayEntry = (Options, index, i) =>
|
|
System.Console.WriteLine("[{0}] {1}", i, Options[index]),
|
|
HandleEntry = (Options, index) => options[Options[index]](),
|
|
}.Show();
|
|
}
|
|
|
|
private void ModifySource(SourceFile source)
|
|
{
|
|
List<(string, string, Action)> options()
|
|
{
|
|
List<(string, string, Action)> result =
|
|
new()
|
|
{
|
|
("File", source.Path, () => { }),
|
|
("Extraction directory", source.Directory, () => EditExtraction(source)),
|
|
(
|
|
"Execute after extraction",
|
|
source.Execute.ToString(),
|
|
() => source.Execute = !source.Execute
|
|
),
|
|
};
|
|
if (source.Execute)
|
|
{
|
|
result.Add(("Parameters", source.Parameters, () => EditParameters(source)));
|
|
result.Add(
|
|
("Wait for exit", source.Wait.ToString(), () => source.Wait = !source.Wait)
|
|
);
|
|
}
|
|
if (source.Execute && source.Wait)
|
|
{
|
|
result.Add(
|
|
(
|
|
"Delete after execution",
|
|
source.Delete.ToString(),
|
|
() => source.Delete = !source.Delete
|
|
)
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
new ListMenu<(string, string, Action)>(options())
|
|
{
|
|
DisplayTitle = (Options) =>
|
|
System.Console.WriteLine(
|
|
"ExeToBat > Files > {0} > Edit",
|
|
Path.GetFileName(source.Path)
|
|
),
|
|
DisplayEntry = (Options, index, i) =>
|
|
{
|
|
int MaxLength = options().ConvertAll(e => e.Item1.Length).Max();
|
|
System.Console.WriteLine(
|
|
"[{0}] {1} | {2}",
|
|
i,
|
|
Options[index].Item1.PadRight(MaxLength, ' '),
|
|
Options[index].Item2
|
|
);
|
|
},
|
|
HandleEntry = (Options, index) =>
|
|
{
|
|
Options[index].Item3();
|
|
return false;
|
|
},
|
|
RefreshEntries = (Options) => options(),
|
|
}.Show();
|
|
}
|
|
|
|
private void EditExtraction(SourceFile source)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine(
|
|
"ExeToBat > Files > {0} > Edit > Extraction",
|
|
Path.GetFileName(source.Path)
|
|
);
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("Documentation: ");
|
|
System.Console.WriteLine("https://ss64.com/nt/syntax-variables.html");
|
|
System.Console.WriteLine("https://ss64.com/nt/syntax-args.html");
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "Directory");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
if (!string.IsNullOrEmpty(input))
|
|
{
|
|
source.Directory = input;
|
|
}
|
|
}
|
|
|
|
private void EditParameters(SourceFile source)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine(
|
|
"ExeToBat > Files > {0} > Edit > Parameters",
|
|
Path.GetFileName(source.Path)
|
|
);
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "Parameters");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
input = input?.Trim();
|
|
if (!string.IsNullOrEmpty(input))
|
|
{
|
|
source.Parameters = input;
|
|
}
|
|
}
|
|
|
|
private void EditPosition(SourceFile source)
|
|
{
|
|
bool IsInputValid = false;
|
|
while (!IsInputValid)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine(
|
|
"ExeToBat > Files > {0} > Position : {1}",
|
|
Path.GetFileName(source.Path),
|
|
generator.Sources.IndexOf(source)
|
|
);
|
|
|
|
System.Console.WriteLine();
|
|
System.Console.Write("{0}> ", "New index");
|
|
string? input = System.Console.ReadLine();
|
|
|
|
if (int.TryParse(input, out int index))
|
|
{
|
|
if (index < generator.Sources.Count)
|
|
{
|
|
generator.Sources.Remove(source);
|
|
generator.Sources.Insert(index, source);
|
|
IsInputValid = true;
|
|
}
|
|
else
|
|
{
|
|
ResetInput();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(input))
|
|
{
|
|
IsInputValid = true;
|
|
}
|
|
else
|
|
{
|
|
ResetInput();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Generate() => Generate(true);
|
|
|
|
private void Generate(bool interactive)
|
|
{
|
|
System.Console.Clear();
|
|
System.Console.WriteLine("ExeToBat > Generate");
|
|
|
|
generator.Generation += OnGenerate;
|
|
|
|
generator.Generate("output.bat");
|
|
|
|
generator.Generation -= OnGenerate;
|
|
|
|
if (interactive)
|
|
{
|
|
System.Console.WriteLine("Press anything...");
|
|
System.Console.ReadKey();
|
|
}
|
|
}
|
|
|
|
private void OnGenerate(object? sender, GeneratorEvent e)
|
|
{
|
|
switch (e)
|
|
{
|
|
case GenerationStartEvent s:
|
|
System.Console.WriteLine("Starting generation...");
|
|
System.Console.WriteLine("{0} files scheduled", s.Files.Count);
|
|
break;
|
|
case ReadingFileEvent s:
|
|
System.Console.WriteLine("[{0}] Reading file", s.File.Path);
|
|
break;
|
|
case WritingFilePartEvent s:
|
|
System.Console.Write(
|
|
"[{0}] writing part {1}/{2}\r",
|
|
s.File.Path,
|
|
s.Part.ToString().PadLeft(s.Max.ToString().Length, '0'),
|
|
s.Max
|
|
);
|
|
break;
|
|
case WritingFileDecoderEvent s:
|
|
System.Console.WriteLine();
|
|
System.Console.WriteLine("[{0}] Writing decode mechanism", s.File.Path);
|
|
break;
|
|
case WritingFileExecuteEvent s:
|
|
System.Console.WriteLine("[{0}] Writing execute mechanism", s.File.Path);
|
|
break;
|
|
case WritingFileWaitEvent s:
|
|
System.Console.WriteLine("[{0}] Writing wait mechanism", s.File.Path);
|
|
break;
|
|
case WritingFileDeleteEvent s:
|
|
System.Console.WriteLine("[{0}] Writing delete mechanism", s.File.Path);
|
|
break;
|
|
case WritingFileCompleteEvent s:
|
|
System.Console.WriteLine("[{0}] Finshed generating!", s.File.Path);
|
|
break;
|
|
case GenerationCompleteEvent s:
|
|
System.Console.WriteLine("Finished generation! Result written to {0}", s.Path);
|
|
break;
|
|
case GenerationEmptyEvent _:
|
|
System.Console.WriteLine("No files specified");
|
|
break;
|
|
case GenerationFailedEvent s:
|
|
System.Console.WriteLine("Generation failed with:\n{0}", s.Error.Message);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|