mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Begin command line tool
This commit is contained in:
parent
ca815312d3
commit
79b09267e6
4 changed files with 230 additions and 2 deletions
128
hactoolnet/CliParser.cs
Normal file
128
hactoolnet/CliParser.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace hactoolnet
|
||||
{
|
||||
internal static class CliParser
|
||||
{
|
||||
private static readonly CliOption[] CliOptions =
|
||||
{
|
||||
new CliOption("intype", 't', 1, (o, a) => o.InFileType = ParseFileType(a[0])),
|
||||
new CliOption("raw", 'r', 0, (o, a) => o.Raw = true),
|
||||
new CliOption("keyset", 'k', 1, (o, a) => o.Keyfile = a[0]),
|
||||
new CliOption("titlekeys", 1, (o, a) => o.TitleKeyFile = a[0]),
|
||||
new CliOption("section0", 1, (o, a) => o.SectionOut[0] = a[0]),
|
||||
new CliOption("section1", 1, (o, a) => o.SectionOut[1] = a[0]),
|
||||
new CliOption("section2", 1, (o, a) => o.SectionOut[2] = a[0]),
|
||||
new CliOption("section3", 1, (o, a) => o.SectionOut[3] = a[0]),
|
||||
new CliOption("section0dir", 1, (o, a) => o.SectionOutDir[0] = a[0]),
|
||||
new CliOption("section1dir", 1, (o, a) => o.SectionOutDir[1] = a[0]),
|
||||
new CliOption("section2dir", 1, (o, a) => o.SectionOutDir[2] = a[0]),
|
||||
new CliOption("section3dir", 1, (o, a) => o.SectionOutDir[3] = a[0]),
|
||||
new CliOption("exefs", 1, (o, a) => o.ExefsOut = a[0]),
|
||||
new CliOption("exefsdir", 1, (o, a) => o.ExefsOutDir = a[0]),
|
||||
new CliOption("romfs", 1, (o, a) => o.RomfsOut = a[0]),
|
||||
new CliOption("romfsdir", 1, (o, a) => o.RomfsOutDir = a[0]),
|
||||
new CliOption("outdir", 1, (o, a) => o.OutDir = a[0]),
|
||||
new CliOption("sdseed", 1, (o, a) => o.SdSeed = a[0]),
|
||||
new CliOption("sdpath", 1, (o, a) => o.SdPath = a[0]),
|
||||
};
|
||||
|
||||
public static Options Parse(string[] args)
|
||||
{
|
||||
var options = new Options();
|
||||
var inputSpecified = false;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string arg;
|
||||
|
||||
if (args[i].Length == 2 && (args[i][0] == '-' || args[i][0] == '/'))
|
||||
{
|
||||
arg = args[i][1].ToString().ToLower();
|
||||
}
|
||||
else if (args[i].Length > 2 && args[i].Substring(0, 2) == "--")
|
||||
{
|
||||
arg = args[i].Substring(2).ToLower();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputSpecified)
|
||||
{
|
||||
Console.WriteLine($"Unable to parse option {args[i]}");
|
||||
return null;
|
||||
}
|
||||
|
||||
options.InFile = args[i];
|
||||
inputSpecified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
var option = CliOptions.FirstOrDefault(x => x.Long == arg || x.Short == arg);
|
||||
if (option == null)
|
||||
{
|
||||
Console.WriteLine($"Unknown option {args[i]}");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (i + option.ArgsNeeded >= args.Length)
|
||||
{
|
||||
Console.WriteLine($"Need {option.ArgsNeeded} parameter{(option.ArgsNeeded == 1 ? "" : "s")} after {args[i]}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var optionArgs = new string[option.ArgsNeeded];
|
||||
Array.Copy(args, i + 1, optionArgs, 0, option.ArgsNeeded);
|
||||
|
||||
option.Assigner(options, optionArgs);
|
||||
i += option.ArgsNeeded;
|
||||
}
|
||||
|
||||
if (!inputSpecified)
|
||||
{
|
||||
Console.WriteLine("Input file must be specified");
|
||||
return null;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static FileType ParseFileType(string input)
|
||||
{
|
||||
if (!Enum.TryParse(input, true, out FileType type))
|
||||
{
|
||||
PrintWithUsage("Specified type is invalid.");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void PrintWithUsage(string toPrint)
|
||||
{
|
||||
Console.WriteLine(toPrint);
|
||||
// PrintUsage();
|
||||
}
|
||||
|
||||
private class CliOption
|
||||
{
|
||||
public CliOption(string longName, char shortName, int argsNeeded, Action<Options, string[]> assigner)
|
||||
{
|
||||
Long = longName;
|
||||
Short = shortName.ToString();
|
||||
ArgsNeeded = argsNeeded;
|
||||
Assigner = assigner;
|
||||
}
|
||||
public CliOption(string longName, int argsNeeded, Action<Options, string[]> assigner)
|
||||
{
|
||||
Long = longName;
|
||||
ArgsNeeded = argsNeeded;
|
||||
Assigner = assigner;
|
||||
}
|
||||
|
||||
public string Long { get; }
|
||||
public string Short { get; }
|
||||
public int ArgsNeeded { get; }
|
||||
public Action<Options, string[]> Assigner { get; }
|
||||
}
|
||||
}
|
||||
}
|
38
hactoolnet/Options.cs
Normal file
38
hactoolnet/Options.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using libhac;
|
||||
|
||||
namespace hactoolnet
|
||||
{
|
||||
internal class Options
|
||||
{
|
||||
public string InFile;
|
||||
public FileType InFileType = FileType.Nca;
|
||||
public bool Raw = false;
|
||||
public string Keyfile;
|
||||
public string TitleKeyFile;
|
||||
public string[] SectionOut = new string[4];
|
||||
public string[] SectionOutDir = new string[4];
|
||||
public string ExefsOut;
|
||||
public string ExefsOutDir;
|
||||
public string RomfsOut;
|
||||
public string RomfsOutDir;
|
||||
public string OutDir;
|
||||
public string SdSeed;
|
||||
public string SdPath;
|
||||
}
|
||||
|
||||
internal enum FileType
|
||||
{
|
||||
Nca,
|
||||
Pfs0,
|
||||
Romfs,
|
||||
Nax0,
|
||||
SwitchFs
|
||||
}
|
||||
|
||||
internal class Context
|
||||
{
|
||||
public Options Options;
|
||||
public Keyset Keyset;
|
||||
public IProgressReport Logger;
|
||||
}
|
||||
}
|
|
@ -10,13 +10,73 @@ namespace hactoolnet
|
|||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ListSdfs(args);
|
||||
var ctx = new Context();
|
||||
ctx.Options = CliParser.Parse(args);
|
||||
if (ctx.Options == null) return;
|
||||
|
||||
using (var logger = new ProgressBar())
|
||||
{
|
||||
ctx.Logger = logger;
|
||||
OpenKeyset(ctx);
|
||||
|
||||
switch (ctx.Options.InFileType)
|
||||
{
|
||||
case FileType.Nca:
|
||||
ProcessNca(ctx);
|
||||
break;
|
||||
case FileType.Pfs0:
|
||||
break;
|
||||
case FileType.Romfs:
|
||||
break;
|
||||
case FileType.Nax0:
|
||||
break;
|
||||
case FileType.SwitchFs:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
//ListSdfs(args);
|
||||
//FileReadTest(args);
|
||||
//ReadNca();
|
||||
//ListSdfs(args);
|
||||
//ReadNcaSdfs(args);
|
||||
}
|
||||
|
||||
private static void ProcessNca(Context ctx)
|
||||
{
|
||||
using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
var nca = new Nca(ctx.Keyset, file, false);
|
||||
|
||||
if (ctx.Options.RomfsOut != null && nca.Sections[1] != null)
|
||||
{
|
||||
var romfs = nca.OpenSection(1, false);
|
||||
|
||||
using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
romfs.CopyStream(outFile, romfs.Length, ctx.Logger);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.Options.SectionOut[0] != null && nca.Sections[0] != null)
|
||||
{
|
||||
var romfs = nca.OpenSection(0, false);
|
||||
|
||||
using (var outFile = new FileStream(ctx.Options.SectionOut[0], FileMode.Create, FileAccess.ReadWrite))
|
||||
{
|
||||
romfs.CopyStream(outFile, romfs.Length, ctx.Logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OpenKeyset(Context ctx)
|
||||
{
|
||||
ctx.Keyset = ExternalKeys.ReadKeyFile(ctx.Options.Keyfile, ctx.Options.TitleKeyFile, ctx.Logger);
|
||||
}
|
||||
|
||||
private static void ListSdfs(string[] args)
|
||||
{
|
||||
var sdfs = LoadSdFs(args);
|
||||
|
@ -161,7 +221,6 @@ namespace hactoolnet
|
|||
{
|
||||
Console.WriteLine($"{app.Name} v{app.DisplayVersion}");
|
||||
|
||||
long totalSize = 0;
|
||||
if (app.Main != null)
|
||||
{
|
||||
Console.WriteLine($"Software: {Util.GetBytesReadable(app.Main.GetSize())}");
|
||||
|
@ -189,3 +248,4 @@ namespace hactoolnet
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,8 @@ namespace libhac
|
|||
public static Keyset ReadKeyFile(string filename, string titleKeysFilename, IProgressReport progress = null)
|
||||
{
|
||||
var keyset = ReadKeyFile(filename, progress);
|
||||
if (titleKeysFilename == null) return keyset;
|
||||
|
||||
using (var reader = new StreamReader(new FileStream(titleKeysFilename, FileMode.Open, FileAccess.Read)))
|
||||
{
|
||||
string line;
|
||||
|
|
Loading…
Reference in a new issue