Compare commits

..

No commits in common. "master" and "1.0.0.1" have entirely different histories.

9 changed files with 814 additions and 1161 deletions

View file

@ -1,4 +0,0 @@
[*.cs]
# CA1822: Member als statisch markieren
dotnet_diagnostic.CA1822.severity = none

View file

@ -1,14 +1,9 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio 15
VisualStudioVersion = 17.3.32929.385 VisualStudioVersion = 15.0.28010.2036
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExeToBat", "ExeToBat\ExeToBat.csproj", "{97ED5369-CCC1-4EAD-B316-97FB983E0A62}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExeToBat", "ExeToBat\ExeToBat.csproj", "{04F45237-23C8-4EE6-B61C-6C47B9979A4B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1E4294A3-12F4-4F45-93B3-05D31958042B}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -16,15 +11,15 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{97ED5369-CCC1-4EAD-B316-97FB983E0A62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {04F45237-23C8-4EE6-B61C-6C47B9979A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97ED5369-CCC1-4EAD-B316-97FB983E0A62}.Debug|Any CPU.Build.0 = Debug|Any CPU {04F45237-23C8-4EE6-B61C-6C47B9979A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97ED5369-CCC1-4EAD-B316-97FB983E0A62}.Release|Any CPU.ActiveCfg = Release|Any CPU {04F45237-23C8-4EE6-B61C-6C47B9979A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97ED5369-CCC1-4EAD-B316-97FB983E0A62}.Release|Any CPU.Build.0 = Release|Any CPU {04F45237-23C8-4EE6-B61C-6C47B9979A4B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F9811F2-7CC0-4D74-8D4A-51D126D13ECD} SolutionGuid = {4AA99DAC-6B37-42AF-8FB7-8394329BD79A}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

6
ExeToBat/App.config Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>

720
ExeToBat/BatGen.cs Normal file
View file

@ -0,0 +1,720 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
namespace ExeToBat
{
static class Generator
{
public const int chunk = 8000;
public static List<SourceFile> Sources = new List<SourceFile>();
static void Main() => MainMenu();
static void MainMenu()
{
Dictionary<string, Action> options = new Dictionary<string, Action> {
{ "Files", ChooseSource },
{ "Generate", () => BuildBat(Sources, "output.bat") }
};
new ListMenu<string>(options.Keys.ToList())
{
DisplayTitle = (List<string> Options) => Console.WriteLine("ExeToBat > Main"),
DisplayEntry = (List<string> Options, int index, int i) =>
{
Console.WriteLine("[{0}] {1}", i, Options[index]);
},
HandleEntry = (List<string> Options, int index) =>
{
if (options.ContainsKey(Options[index]))
{
options[Options[index]]();
}
else
{
ResetInput();
}
return false;
},
ExitEntry = "Exit",
}.Show();
}
static void ChooseSource()
{
new ListMenu<SourceFile>(Sources)
{
DisplayTitle = (List<SourceFile> sources) =>
{
Console.WriteLine("ExeToBat > Main > Files");
Console.WriteLine("[{0}] ({1})", Convert.ToString(0).PadLeft(Convert.ToString(sources.Count).Length, ' '), "Add Files");
},
DisplayEntry = (List<SourceFile> sources, int index, int i) =>
Console.WriteLine("[{0}] {1}",
Convert.ToString(i).PadLeft(
Convert.ToString(sources.Count).Length, ' '),
Path.GetFileName(sources[index].File)),
ZeroEntry = (List<SourceFile> sources) =>
{
AddSource();
return false;
},
HandleEntry = (List<SourceFile> sources, int index) =>
{
ManageSource(sources[index]);
return false;
},
RefreshEntries = (List<SourceFile> sources) => Sources,
}.Show();
}
static void AddSource()
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Clear();
Console.WriteLine("ExeToBat > Main > Files > Add");
Console.Write("\n");
Console.Write("{0}> ", "File/Folder");
string input = Console.ReadLine();
input.Trim();
input = input.Replace("\"", "");
if (!string.IsNullOrEmpty(input))
{
switch (input)
{
case var i when Directory.Exists(i):
IsInputValid = true;
foreach (string file in Directory.GetFiles(input))
{
Sources.Add(new SourceFile(file));
}
break;
case var i when File.Exists(i):
IsInputValid = true;
Sources.Add(new SourceFile(input));
break;
default:
ResetInput();
break;
}
}
else
{
IsInputValid = true;
}
}
}
static void ManageSource(SourceFile source)
{
Dictionary<string, Func<bool>> options = new Dictionary<string, Func<bool>>
{
{"Edit", () => {
ModifySource(source);
return false;
}
},
{ "Position", () => {
EditPosition(source);
return false;
}
},
{ "Delete", () => {
Sources.Remove(source);
return true;
}
},
};
new ListMenu<string>(options.Keys.ToList())
{
DisplayTitle = (List<string> Options) => Console.WriteLine("ExeToBat > Main > Files > {0}", Path.GetFileName(source.File)),
DisplayEntry = (List<string> Options, int index, int i) => Console.WriteLine("[{0}] {1}", i, Options[index]),
HandleEntry = (List<string> Options, int index) =>
{
if (options.ContainsKey(Options[index]))
{
return options[Options[index]]();
}
else
{
ResetInput();
}
return false;
},
}.Show();
}
static void ModifySource(SourceFile source)
{
// this could be solved better with an enum
Dictionary<string, Action> options()
{
Dictionary<string, Action> opts = new Dictionary<string, Action> {
{"File", () => { } },
{"Extraction directory", () => EditExtraction(source)},
{"Execute after extraction", () => source.Execute = !source.Execute },
};
if (source.Execute)
{
opts.Add("Parameters", () => EditParameters(source));
opts.Add("Wait for exit", () => source.Wait = !source.Wait);
}
if (source.Execute && source.Wait) { opts.Add("Delete after execution", () => source.Delete = !source.Delete); }
return opts;
}
Dictionary<string, string> ValueMap = new Dictionary<string, string>
{
{ "File", "File" },
{ "Extraction directory", "Directory" },
{ "Execute after extraction", "Execute" },
{ "Parameters", "Parameters" },
{ "Wait for exit", "Wait"},
{ "Delete after execution", "Delete"},
};
new ListMenu<string>(options().Keys.ToList())
{
DisplayTitle = (List<string> Options) => Console.WriteLine("ExeToBat > Main > Files > {0} > Edit", Path.GetFileName(source.File)),
DisplayEntry = (List<string> Options, int index, int i) =>
{
int MaxLength = options().Keys.Select(x => x.Length).Max();
Console.WriteLine("[{0}] {1} | {2}", i, Options[index].PadRight(MaxLength, ' '), source.GetType().GetProperty(ValueMap[Options[index]]).GetValue(source).ToString());
},
HandleEntry = (List<string> Options, int index) =>
{
if (options().ContainsKey(Options[index]))
{
options()[Options[index]]();
}
else
{
ResetInput();
}
return false;
},
RefreshEntries = (List<string> Options) => options().Keys.ToList(),
}.Show();
}
static void EditExtraction(SourceFile source)
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Clear();
Console.WriteLine("ExeToBat > Main > Files > {0} > Edit > Extraction", Path.GetFileName(source.File));
Console.Write("\n");
Console.WriteLine("Documentation: ");
Console.WriteLine("https://ss64.com/nt/syntax-variables.html");
Console.WriteLine("https://ss64.com/nt/syntax-args.html");
Console.Write("\n");
Console.Write("{0}> ", "Directory");
string input = Console.ReadLine();
input.Trim();
if (!string.IsNullOrEmpty(input))
{
source.Directory = input;
IsInputValid = true;
}
else
{
IsInputValid = true;
}
}
}
static void EditParameters(SourceFile source)
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Clear();
Console.WriteLine("ExeToBat > Main > Files > {0} > Edit > Parameters", Path.GetFileName(source.File));
Console.Write("\n");
Console.Write("{0}> ", "Parameters");
string input = Console.ReadLine();
input.Trim();
if (!string.IsNullOrEmpty(input))
{
source.Parameters = input;
IsInputValid = true;
}
else
{
IsInputValid = true;
}
}
}
static void EditPosition(SourceFile source)
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Clear();
Console.WriteLine("ExeToBat > Main > Files > {0} > Position : {1}", Path.GetFileName(source.File), Sources.IndexOf(source));
Console.Write("\n");
Console.Write("{0}> ", "New index");
string input = Console.ReadLine();
if (int.TryParse(input, out int index))
{
if (index < Sources.Count)
{
Sources.Remove(source);
Sources.Insert(index, source);
IsInputValid = true;
}
else
{
ResetInput();
}
}
else
{
if (string.IsNullOrEmpty(input))
{
IsInputValid = true;
}
else
{
ResetInput();
}
}
}
}
static void BuildBat(List<SourceFile> sources, string outputFile)
{
Console.Clear();
Console.WriteLine("ExeToBat > Main > Generate");
if (Sources.Any())
{
using (StreamWriter writer = new StreamWriter(outputFile))
{
Console.WriteLine("[Preparing] basic batch structure...");
writer.WriteLine("@echo off");
writer.WriteLine(":: Auto-generated batch file by ExeToBat ::");
writer.WriteLine("");
foreach (SourceFile source in sources)
{
Console.WriteLine("[ Reading ] {0}", source.File);
List<string> fileChunks = Convert.ToBase64String(File.ReadAllBytes(source.File)).Chunks(chunk).ToList();
string tempFile = Path.Combine("%temp%", source.Resource);
writer.WriteLine("(");
int pos = 0;
foreach (string part in fileChunks)
{
pos++;
Console.Write("[ Writing ] {0} part {1}/{2}\r", Path.GetFileName(source.File), pos.ToString().PadLeft(fileChunks.Count.ToString().Length, '0'), fileChunks.Count);
writer.WriteLine(string.Format("echo {0}", part));
}
Console.WriteLine();
writer.WriteLine(string.Format(") >> \"{0}\"", tempFile));
writer.WriteLine("");
Console.WriteLine("[ Writing ] decode mechanism");
writer.WriteLine(string.Format("certutil -decode \"{0}\" \"{1}\" >nul 2>&1", tempFile, Path.Combine(source.Directory, Path.GetFileName(source.File))));
writer.WriteLine(string.Format("del /f /q \"{0}\" >nul 2>&1", tempFile));
writer.WriteLine("");
if (source.Execute)
{
string wait;
if (source.Wait) { wait = " /wait"; } else { wait = " "; }
Console.WriteLine("[ Writing ] execute mechanism");
writer.WriteLine(string.Format("start{0} \"\" \"cmd /c {1}\" {2}", wait, Path.Combine(source.Directory, Path.GetFileName(source.File)), source.Parameters));
if (source.Wait)
{
Console.WriteLine("[ Writing ] wait mechanism");
if (source.Delete)
{
Console.WriteLine("[ Writing ] delete mechanism");
writer.WriteLine(string.Format("del /f /q \"{0}\" >nul 2>&1", Path.Combine(source.Directory, Path.GetFileName(source.File))));
writer.WriteLine("");
}
}
writer.WriteLine("");
}
writer.Flush();
Console.WriteLine("[Generated] {0}", Path.GetFileName(source.File));
}
Console.WriteLine("[Generated] All done");
Console.WriteLine("Press anything...");
Console.ReadKey();
}
}
else
{
Console.WriteLine("No files specified");
Wait(500);
}
}
public class SourceFile
{
public string File { get; set; }
public bool Execute { get; set; } = false;
public bool Wait { get; set; } = false;
public bool Delete { get; set; } = false;
public string Resource { get; set; } = GenTemp();
public string Directory { get; set; } = "%~dp0";
public string Parameters { get; set; } = "";
public SourceFile(string file)
{
File = file;
}
static public string GenTemp()
{
return string.Format($"res_{new Random().Next(1000, 10000)}.b64");
}
}
static string[] Chunks(this string toSplit, int chunkSize)
{
int stringLength = toSplit.Length;
int chunksRequired = (int)Math.Ceiling(stringLength / (decimal)chunkSize);
var stringArray = new string[chunksRequired];
int lengthRemaining = stringLength;
for (int i = 0; i < chunksRequired; i++)
{
int lengthToUse = Math.Min(lengthRemaining, chunkSize);
int startIndex = chunkSize * i;
stringArray[i] = toSplit.Substring(startIndex, lengthToUse);
lengthRemaining -= lengthToUse;
}
return stringArray;
}
public static void Wait(int ms)
{
using (System.Threading.ManualResetEvent wait = new System.Threading.ManualResetEvent(false))
{
wait.WaitOne(ms);
}
}
public class ListMenu<T>
{
/// <summary>
/// CLOE (Command-line List Options Enumerator).
/// <para>Turns a List<T> into a menu of options. Each list item is asigned a number. Provides several callbacks to customise the menu.</para>
/// </summary>
/// <param name="entries">List of objects you want to display</param>
public ListMenu(List<T> entries)
{
Entries = entries;
}
/// <summary>
/// The prompt that is displayed to the user.
/// </summary>
public string Prompt = "Choose";
/// <summary>
/// The string to be displayed for the option to exit the menu.
/// </summary>
public string ExitEntry = "Back";
/// <summary>
/// The key the user has to press to exit the menu.
/// </summary>
public char ExitKey = 'q';
/// <summary>
/// Wether or not the user can exit the menu.
/// </summary>
public bool UserCanExit = true;
private List<T> Entries;
/// <summary>
/// The function that processes the chosen menu entries.
/// </summary>
public Func<List<T>, int, bool> HandleEntry = (entries, index) =>
{
Console.Clear();
Console.WriteLine(entries[index]);
Wait(200);
return false;
};
/// <summary>
/// The function that displays the menu title.
/// </summary>
public Action<List<T>> DisplayTitle = (entries) => { };
/// <summary>
/// The function that displays the entry to the user.
/// </summary>
public Action<List<T>, int, int> DisplayEntry = (entries, index, num) =>
{
Console.WriteLine("[{0}] {1}", Convert.ToString(num).PadLeft(Convert.ToString(entries.Count).Length, ' '), entries[index]);
};
/// <summary>
/// The function to update the list of entries.
/// </summary>
public Func<List<T>, List<T>> RefreshEntries = (entries) =>
{
return entries;
};
/// <summary>
/// The function that is called when 0th entry in the list is chosen.
/// <para>Display this entry with the title function.</para>
/// </summary>
public Func<List<T>, bool> ZeroEntry = (entries) =>
{
ResetInput();
return false;
};
/// <summary>
/// Display the menu.
/// </summary>
/// <returns></returns>
public ListMenu<T> Show()
{
string readInput = string.Empty;
bool MenuExitIsPending = false;
while (!MenuExitIsPending)
{
Console.Clear();
int printedEntries = 0;
Entries = RefreshEntries(Entries);
DisplayTitle(Entries);
if (Entries.Any())
{
int num = 0;
foreach (T entry in Entries)
{
num++;
if (string.IsNullOrEmpty(readInput) || Convert.ToString(num).StartsWith(readInput))
{
DisplayEntry(Entries, Entries.IndexOf(entry), num);
printedEntries++;
}
if (Entries.Count > Console.WindowHeight - 5)
{
if (printedEntries >= Console.WindowHeight - (5 + 1))
{
Console.WriteLine("[{0}] +{1}", ".".PadLeft(Convert.ToString(Entries.Count).Length, '.'), Entries.Count);
break;
}
}
else
{
if (printedEntries == Console.WindowHeight - 5)
{
break;
}
}
}
}
if (UserCanExit)
{
Console.WriteLine("[{0}] {1}", Convert.ToString(ExitKey).PadLeft(Convert.ToString(Entries.Count).Length, ' '), ExitEntry);
}
Console.WriteLine();
bool InputIsValid = false;
while (!InputIsValid)
{
Console.Write("{0}> {1}", Prompt, readInput);
ConsoleKeyInfo input = Console.ReadKey();
Wait(20);
int choiceNum = -1;
switch (input)
{
case var key when key.KeyChar.Equals(ExitKey):
if (UserCanExit)
{
Console.WriteLine();
InputIsValid = true;
MenuExitIsPending = true;
}
else
{
Console.WriteLine();
ResetInput();
}
break;
case var key when key.Key.Equals(ConsoleKey.Backspace):
if (!string.IsNullOrEmpty(readInput))
{
Console.Write("\b");
readInput = readInput.Remove(readInput.Length - 1);
}
InputIsValid = true;
break;
case var key when key.Key.Equals(ConsoleKey.Enter):
if (!string.IsNullOrEmpty(readInput))
{
if (HandleEntry(Entries, (Convert.ToInt32(readInput) - 1)))
{
MenuExitIsPending = true;
}
readInput = string.Empty;
}
InputIsValid = true;
break;
case var key when int.TryParse(key.KeyChar.ToString(), out choiceNum):
Console.WriteLine();
if (string.IsNullOrEmpty(readInput) && choiceNum.Equals(0))
{
InputIsValid = true;
if (ZeroEntry(Entries))
{
MenuExitIsPending = true;
}
}
else
{
if (Convert.ToInt32(readInput + Convert.ToString(choiceNum)) <= Entries.Count)
{
InputIsValid = true;
int matchingEntries = 0;
readInput = new System.Text.StringBuilder().Append(readInput).Append(Convert.ToString(choiceNum)).ToString();
for (int i = 0; i < Entries.Count; i++)
{
if (Convert.ToString(i + 1).StartsWith(readInput) || Convert.ToString(i + 1) == readInput) { matchingEntries++; }
}
if ((readInput.Length == Convert.ToString(Entries.Count).Length) || (matchingEntries == 1))
{
if (HandleEntry(Entries, (Convert.ToInt32(readInput) - 1)))
{
MenuExitIsPending = true;
}
readInput = string.Empty;
}
}
else
{
ResetInput();
}
}
break;
default:
Console.WriteLine();
ResetInput();
break;
}
}
}
return this;
}
}
/// <summary>
/// A simple template to create Yes or No menus.
/// </summary>
/// <param name="title">The title of the menu.</param>
/// <param name="Yes">The function to be called upon Yes</param>
/// <param name="No">The function to be called upon No</param>
public static void YesNoMenu(string title, Action Yes, Action No)
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Write("{0}? [{1}]> ", title, "Y/N");
string Input = Console.ReadKey().KeyChar.ToString();
Wait(20);
Console.Write("\n");
if (string.Equals(Input, "Y", StringComparison.OrdinalIgnoreCase))
{
IsInputValid = true;
Yes();
}
else if (string.Equals(Input, "N", StringComparison.OrdinalIgnoreCase))
{
IsInputValid = true;
No();
}
else
{
ResetInput();
}
}
}
public static void ResetInput(string error = "Input Invalid")
{
Console.Write(string.Format("[{0}] {1}", "Error", error));
Wait(150);
ClearCurrentConsoleLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
ClearCurrentConsoleLine();
}
public static void ClearCurrentConsoleLine()
{
int currentLineCursor = Console.CursorTop;
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write(new string(' ', Console.BufferWidth));
Console.SetCursorPosition(0, currentLineCursor);
}
}
}

View file

@ -1,485 +0,0 @@
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.Message);
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;
}
}
}
}

View file

@ -1,328 +0,0 @@
namespace System
{
public static class ConsoleUtils
{
/// <summary>
/// Pauses the thread for a duration.
/// </summary>
/// <param name="ms"></param> The duration to pause.
public static void Wait(int ms)
{
using (Threading.ManualResetEvent wait = new Threading.ManualResetEvent(false))
{
wait.WaitOne(ms);
}
}
/// <summary>
/// Clears the current line of the Console.
/// </summary>
public static void ClearCurrentConsoleLine()
{
int currentLineCursor = Console.CursorTop;
Console.SetCursorPosition(0, Console.CursorTop);
Console.Write(new string(' ', Console.BufferWidth));
Console.SetCursorPosition(0, currentLineCursor);
}
/// <summary>
/// Deletes the last line of the console and displays an error for a short duration.
/// </summary>
/// <param name="error"></param> The error to display.
public static void ResetInput(string error = "Input Invalid")
{
Console.Write(string.Format("[{0}] {1}", "Error", error));
Wait(150);
ClearCurrentConsoleLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
ClearCurrentConsoleLine();
}
/// <summary>
/// A simple template to create Yes or No menus.
/// </summary>
/// <param name="title">The title of the menu.</param>
/// <param name="Yes">The function to be called upon Yes</param>
/// <param name="No">The function to be called upon No</param>
public static void YesNoMenu(string title, Action Yes, Action No)
{
bool IsInputValid = false;
while (!IsInputValid)
{
Console.Write("{0}? [{1}]> ", title, "Y/N");
string Input = Console.ReadKey().KeyChar.ToString();
Wait(20);
Console.Write("\n");
if (string.Equals(Input, "Y", StringComparison.OrdinalIgnoreCase))
{
IsInputValid = true;
Yes();
}
else if (string.Equals(Input, "N", StringComparison.OrdinalIgnoreCase))
{
IsInputValid = true;
No();
}
else
{
ResetInput();
}
}
}
public class ListMenu<T>
{
/// <summary>
/// Command-line List Options Enumerator
/// <para>Turns a List<T> into a menu of options. Each list item is asigned a number. Provides several callbacks to customise the menu.</para>
/// </summary>
/// <param name="entries">List of objects you want to display</param>
public ListMenu(List<T> entries)
{
Entries = entries;
}
/// <summary>
/// The prompt that is displayed to the user.
/// </summary>
public string Prompt = "Choose";
/// <summary>
/// The string to be displayed for the option to exit the menu.
/// </summary>
public string ExitEntry = "Back";
/// <summary>
/// The key the user has to press to exit the menu.
/// </summary>
public char ExitKey = 'q';
/// <summary>
/// Wether or not the user can exit the menu.
/// </summary>
public bool UserCanExit = true;
private List<T> Entries;
/// <summary>
/// The function that processes the chosen menu entries.
/// </summary>
public Func<List<T>, int, bool> HandleEntry = (entries, index) =>
{
Console.Clear();
Console.WriteLine(entries[index]);
Wait(200);
return false;
};
/// <summary>
/// The function that displays the menu title.
/// </summary>
public Action<List<T>> DisplayTitle = (entries) => { };
/// <summary>
/// The function that displays the entry to the user.
/// </summary>
public Action<List<T>, int, int> DisplayEntry = (entries, index, num) =>
{
Console.WriteLine(
"[{0}] {1}",
Convert.ToString(num).PadLeft(Convert.ToString(entries.Count).Length, ' '),
entries[index]
);
};
/// <summary>
/// The function to update the list of entries.
/// </summary>
public Func<List<T>, List<T>> RefreshEntries = (entries) => entries;
/// <summary>
/// The function that is called when 0th entry in the list is chosen.
/// <para>Display this entry with the title function.</para>
/// </summary>
public Func<List<T>, bool> ZeroEntry = (entries) =>
{
ResetInput();
return false;
};
/// <summary>
/// Display the menu.
/// </summary>
/// <returns></returns>
public ListMenu<T> Show()
{
string readInput = string.Empty;
bool MenuExitIsPending = false;
while (!MenuExitIsPending)
{
Console.Clear();
int printedEntries = 0;
Entries = RefreshEntries(Entries);
DisplayTitle(Entries);
if (Entries.Any())
{
int num = 0;
foreach (T entry in Entries)
{
num++;
if (
string.IsNullOrEmpty(readInput)
|| Convert.ToString(num).StartsWith(readInput)
)
{
DisplayEntry(Entries, Entries.IndexOf(entry), num);
printedEntries++;
}
if (Entries.Count > Console.WindowHeight - 5)
{
if (printedEntries >= Console.WindowHeight - (5 + 1))
{
Console.WriteLine(
"[{0}] +{1}",
".".PadLeft(Convert.ToString(Entries.Count).Length, '.'),
Entries.Count
);
break;
}
}
else
{
if (printedEntries == Console.WindowHeight - 5)
{
break;
}
}
}
}
if (UserCanExit)
{
Console.WriteLine(
"[{0}] {1}",
Convert
.ToString(ExitKey)
.PadLeft(Convert.ToString(Entries.Count).Length, ' '),
ExitEntry
);
}
Console.WriteLine();
bool InputIsValid = false;
while (!InputIsValid)
{
Console.Write("{0}> {1}", Prompt, readInput);
ConsoleKeyInfo input = Console.ReadKey();
Wait(20);
int choiceNum = -1;
switch (input)
{
case var key when key.KeyChar.Equals(ExitKey):
if (UserCanExit)
{
Console.WriteLine();
InputIsValid = true;
MenuExitIsPending = true;
}
else
{
Console.WriteLine();
ResetInput();
}
break;
case var key when key.Key.Equals(ConsoleKey.Backspace):
if (!string.IsNullOrEmpty(readInput))
{
Console.Write("\b");
readInput = readInput.Remove(readInput.Length - 1);
}
InputIsValid = true;
break;
case var key when key.Key.Equals(ConsoleKey.Enter):
if (!string.IsNullOrEmpty(readInput))
{
if (HandleEntry(Entries, (Convert.ToInt32(readInput) - 1)))
{
MenuExitIsPending = true;
}
readInput = string.Empty;
}
InputIsValid = true;
break;
case var key when int.TryParse(key.KeyChar.ToString(), out choiceNum):
Console.WriteLine();
if (string.IsNullOrEmpty(readInput) && choiceNum.Equals(0))
{
InputIsValid = true;
if (ZeroEntry(Entries))
{
MenuExitIsPending = true;
}
}
else
{
if (
Convert.ToInt32(readInput + Convert.ToString(choiceNum))
<= Entries.Count
)
{
InputIsValid = true;
int matchingEntries = 0;
readInput = new System.Text.StringBuilder()
.Append(readInput)
.Append(Convert.ToString(choiceNum))
.ToString();
for (int i = 0; i < Entries.Count; i++)
{
if (
Convert.ToString(i + 1).StartsWith(readInput)
|| Convert.ToString(i + 1) == readInput
)
{
matchingEntries++;
}
}
if (
(
readInput.Length
== Convert.ToString(Entries.Count).Length
) || (matchingEntries == 1)
)
{
if (
HandleEntry(
Entries,
(Convert.ToInt32(readInput) - 1)
)
)
{
MenuExitIsPending = true;
}
readInput = string.Empty;
}
}
else
{
ResetInput();
}
}
break;
default:
Console.WriteLine();
ResetInput();
break;
}
}
}
return this;
}
}
}
}

View file

@ -1,29 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk"> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{04F45237-23C8-4EE6-B61C-6C47B9979A4B}</ProjectGuid>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<PublishSingleFile>true</PublishSingleFile> <RootNamespace>ExeToBat</RootNamespace>
<PublishReadyToRun>true</PublishReadyToRun> <AssemblyName>ExeToBat</AssemblyName>
<TargetFramework>net6.0</TargetFramework> <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<ImplicitUsings>enable</ImplicitUsings> <FileAlignment>512</FileAlignment>
<Nullable>enable</Nullable> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<AssemblyVersion>2.0.0.0</AssemblyVersion> <Deterministic>true</Deterministic>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PlatformTarget>AnyCPU</PlatformTarget>
<WarningsAsErrors>$(WarningsAsErrors);NU1605;CS8600;CS8601;CS8602;CS8603;CS8604;CS8613;CS8614;CS8619;CS8620;CS8622;CS8625;CS8629;CS8633;CS8767;</WarningsAsErrors> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PlatformTarget>AnyCPU</PlatformTarget>
<WarningsAsErrors>$(WarningsAsErrors);NU1605;CS8600;CS8601;CS8602;CS8603;CS8604;CS8613;CS8614;CS8619;CS8620;CS8622;CS8625;CS8629;CS8633;CS8767;</WarningsAsErrors> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" /> <Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Mono.Options" Version="6.12.0.148" /> <Compile Include="BatGen.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup>
</Project> <None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -1,311 +0,0 @@
using System.Text.Json;
namespace ExeToBat
{
public class Generator
{
public Generator() { }
public Generator(GeneratorConfig config)
{
LoadConfig(config);
}
public const int ChunkSize = 8000;
public List<SourceFile> Sources = new();
public class SourceFile
{
/// <summary>
/// Represents a file that is later embedded in a bat.
/// </summary>
/// <param name="path"></param> The path of the file.
public SourceFile(string path)
{
Path = path;
}
public string Path { get; set; }
public bool Execute { get; set; } = false;
public bool Wait { get; set; } = false;
public bool Delete { get; set; } = false;
public string Resource { get; set; } = GetTempFileName();
public string Directory { get; set; } = "%~dp0";
public string Parameters { get; set; } = "";
static public string GetTempFileName()
{
return string.Format($"res_{new Random().Next(1000, 10000)}.b64");
}
}
public class GeneratorConfig
{
/// <summary>
/// The configuration for a Generator.
/// </summary>
/// <param name="sources"></param>
public GeneratorConfig(List<SourceFile> sources)
{
Sources = sources;
}
public List<SourceFile> Sources { get; private set; }
public string ToJson()
{
return JsonSerializer.Serialize(this);
}
public static GeneratorConfig FromJson(string raw)
{
return JsonSerializer.Deserialize<GeneratorConfig>(raw)
?? new GeneratorConfig(new());
}
}
/// <summary>
/// Exports the variables of this Generator as a configuration.
/// </summary>
/// <returns></returns>
public GeneratorConfig SaveConfig()
{
return new GeneratorConfig(Sources);
}
/// <summary>
/// Loads a configuration into this Generator.
/// </summary>
/// <param name="config"></param>
public void LoadConfig(GeneratorConfig config)
{
Sources = config.Sources;
}
/// <summary>
/// Sends progress updates about ongoing generation task.
/// </summary>
public event EventHandler<GeneratorEvent>? Generation;
protected virtual void OnGeneration(GeneratorEvent e)
{
EventHandler<GeneratorEvent>? handler = Generation;
handler?.Invoke(this, e);
}
/// <summary>
/// Generates a batch file with all specified source files.
/// </summary>
/// <param name="outputFile"></param> Target output file path.
public void Generate(string outputFile)
{
if (Sources.Any())
{
using StreamWriter writer = new(outputFile);
OnGeneration(new GenerationStartEvent(Sources));
writer.WriteLine("@echo off");
writer.WriteLine(":: Auto-generated batch file by ExeToBat ::");
writer.WriteLine("");
foreach (SourceFile source in Sources)
{
OnGeneration(new ReadingFileEvent(source));
List<string> fileChunks = Convert
.ToBase64String(File.ReadAllBytes(source.Path))
.Chunks(ChunkSize)
.ToList();
string tempFile = Path.Combine("%temp%", source.Resource);
writer.WriteLine("(");
int pos = 0;
foreach (string part in fileChunks)
{
pos++;
OnGeneration(new WritingFilePartEvent(source, pos, fileChunks.Count));
writer.WriteLine(string.Format("echo {0}", part));
}
writer.WriteLine(string.Format(") >> \"{0}\"", tempFile));
writer.WriteLine("");
OnGeneration(new WritingFileDecoderEvent(source));
writer.WriteLine(
string.Format(
"certutil -decode \"{0}\" \"{1}\" >nul 2>&1",
tempFile,
Path.Combine(source.Directory, Path.GetFileName(source.Path))
)
);
writer.WriteLine(string.Format("del /f /q \"{0}\" >nul 2>&1", tempFile));
writer.WriteLine("");
if (source.Execute)
{
string wait;
if (source.Wait)
{
wait = " /wait";
}
else
{
wait = " ";
}
OnGeneration(new WritingFileExecuteEvent(source));
writer.WriteLine(
string.Format(
"start{0} \"\" \"cmd /c {1}\" {2}",
wait,
Path.Combine(source.Directory, Path.GetFileName(source.Path)),
source.Parameters
)
);
if (source.Wait)
{
OnGeneration(new WritingFileWaitEvent(source));
if (source.Delete)
{
OnGeneration(new WritingFileDeleteEvent(source));
writer.WriteLine(
string.Format(
"del /f /q \"{0}\" >nul 2>&1",
Path.Combine(
source.Directory,
Path.GetFileName(source.Path)
)
)
);
writer.WriteLine("");
}
}
writer.WriteLine("");
}
writer.Flush();
OnGeneration(new WritingFileCompleteEvent(source));
}
OnGeneration(new GenerationCompleteEvent(outputFile));
}
else
{
OnGeneration(new GenerationEmptyEvent());
}
}
public abstract class GeneratorEvent : EventArgs { }
public abstract class GeneratorFileEvent : GeneratorEvent
{
public GeneratorFileEvent(SourceFile file)
{
File = file;
}
public SourceFile File { get; private set; }
}
public class GenerationStartEvent : GeneratorEvent
{
public GenerationStartEvent(List<SourceFile> files)
{
Files = files;
}
public List<SourceFile> Files { get; private set; }
}
public class ReadingFileEvent : GeneratorFileEvent
{
public ReadingFileEvent(SourceFile file) : base(file) { }
}
public class WritingFilePartEvent : GeneratorFileEvent
{
public WritingFilePartEvent(SourceFile file, int part, int max) : base(file)
{
Part = part;
Max = max;
}
public int Part { get; private set; }
public int Max { get; private set; }
}
public class WritingFileDecoderEvent : GeneratorFileEvent
{
public WritingFileDecoderEvent(SourceFile file) : base(file) { }
}
public class WritingFileExecuteEvent : GeneratorFileEvent
{
public WritingFileExecuteEvent(SourceFile file) : base(file) { }
}
public class WritingFileWaitEvent : GeneratorFileEvent
{
public WritingFileWaitEvent(SourceFile file) : base(file) { }
}
public class WritingFileDeleteEvent : GeneratorFileEvent
{
public WritingFileDeleteEvent(SourceFile file) : base(file) { }
}
public class WritingFileCompleteEvent : GeneratorFileEvent
{
public WritingFileCompleteEvent(SourceFile file) : base(file) { }
}
public class GenerationCompleteEvent : GeneratorEvent
{
public GenerationCompleteEvent(string path)
{
Path = path;
}
public string Path { get; private set; }
}
public class GenerationEmptyEvent : GeneratorEvent
{
public GenerationEmptyEvent() { }
}
public class GenerationFailedEvent : GeneratorEvent
{
public GenerationFailedEvent(Exception error)
{
Error = error;
}
public Exception Error { get; private set; }
}
}
internal static class StringChunks
{
public static string[] Chunks(this string toSplit, int chunkSize)
{
int stringLength = toSplit.Length;
int chunksRequired = (int)Math.Ceiling(stringLength / (decimal)chunkSize);
var stringArray = new string[chunksRequired];
int lengthRemaining = stringLength;
for (int i = 0; i < chunksRequired; i++)
{
int lengthToUse = Math.Min(lengthRemaining, chunkSize);
int startIndex = chunkSize * i;
stringArray[i] = toSplit.Substring(startIndex, lengthToUse);
lengthRemaining -= lengthToUse;
}
return stringArray;
}
}
}

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("ExeToBat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ExeToBat")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("04f45237-23c8-4ee6-b61c-6c47b9979a4b")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]