Bump version to 0.17.0 and add version output to hactoolnet

This commit is contained in:
Alex Barney 2022-11-15 22:09:05 -07:00
parent 766e0d6461
commit 2b31368030
8 changed files with 98 additions and 29 deletions

View file

@ -35,6 +35,8 @@ Options:
--titlekeys <file> Load title keys from an external file. --titlekeys <file> Load title keys from an external file.
--accesslog <file> Specify the access log file path. --accesslog <file> Specify the access log file path.
--disablekeywarns Disables warning output when loading external keys. --disablekeywarns Disables warning output when loading external keys.
--version Display version information and exit.
--help Display this help and exit.
NCA options: NCA options:
--plaintext <file> Specify file path for saving a decrypted copy of the NCA. --plaintext <file> Specify file path for saving a decrypted copy of the NCA.
--ciphertext <file> Specify file path for saving an encrypted copy of the NCA. --ciphertext <file> Specify file path for saving an encrypted copy of the NCA.

View file

@ -812,11 +812,11 @@ namespace LibHac.Fs.Impl
public static ReadOnlySpan<byte> FsModuleName => // "$fs" public static ReadOnlySpan<byte> FsModuleName => // "$fs"
new[] { (byte)'$', (byte)'f', (byte)'s' }; new[] { (byte)'$', (byte)'f', (byte)'s' };
/// <summary>"<c>0.16.1</c>"</summary> /// <summary>"<c>0.17.0</c>"</summary>
public static ReadOnlySpan<byte> LogLibHacVersion => // "0.16.1" public static ReadOnlySpan<byte> LogLibHacVersion => // "0.17.0"
new[] new[]
{ {
(byte)'0', (byte)'.', (byte)'1', (byte)'6', (byte)'.', (byte)'1' (byte)'0', (byte)'.', (byte)'1', (byte)'7', (byte)'.', (byte)'0'
}; };
/// <summary>"<c>"</c>"</summary> /// <summary>"<c>"</c>"</summary>

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<VersionPrefix>0.16.1</VersionPrefix> <VersionPrefix>0.17.0</VersionPrefix>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>

View file

@ -9,8 +9,10 @@ internal static class CliParser
{ {
private static CliOption[] GetCliOptions() => new[] private static CliOption[] GetCliOptions() => new[]
{ {
new CliOption("help", 0, (o, _) => o.PrintHelp = true),
new CliOption("version", 0, (o, _) => o.PrintVersion = true),
new CliOption("custom", 0, (o, _) => o.RunCustom = true), new CliOption("custom", 0, (o, _) => o.RunCustom = true),
new CliOption("intype", 't', 1, (o, a) => o.InFileType = ParseFileType(a[0])), new CliOption("intype", 't', 1, (o, a) => o.InFileType = ParseFileType(o, a[0])),
new CliOption("raw", 'r', 0, (o, _) => o.Raw = true), new CliOption("raw", 'r', 0, (o, _) => o.Raw = true),
new CliOption("verify", 'y', 0, (o, _) => o.Validate = true), new CliOption("verify", 'y', 0, (o, _) => o.Validate = true),
new CliOption("dev", 'd', 0, (o, _) => o.UseDevKeys = true), new CliOption("dev", 'd', 0, (o, _) => o.UseDevKeys = true),
@ -63,9 +65,9 @@ internal static class CliParser
new CliOption("readbench", 0, (o, _) => o.ReadBench = true), new CliOption("readbench", 0, (o, _) => o.ReadBench = true),
new CliOption("hashedfs", 0, (o, _) => o.BuildHfs = true), new CliOption("hashedfs", 0, (o, _) => o.BuildHfs = true),
new CliOption("extractini1", 0, (o, _) => o.ExtractIni1 = true), new CliOption("extractini1", 0, (o, _) => o.ExtractIni1 = true),
new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(a[0])), new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(o, a[0])),
new CliOption("bench", 1, (o, a) => o.BenchType = a[0]), new CliOption("bench", 1, (o, a) => o.BenchType = a[0]),
new CliOption("cpufreq", 1, (o, a) => o.CpuFrequencyGhz = ParseDouble(a[0])), new CliOption("cpufreq", 1, (o, a) => o.CpuFrequencyGhz = ParseDouble(o, a[0])),
new CliOption("replacefile", 2, (o, a) => new CliOption("replacefile", 2, (o, a) =>
{ {
@ -75,6 +77,38 @@ internal static class CliParser
}; };
public static Options Parse(string[] args) public static Options Parse(string[] args)
{
Options options = ParseAllOptions(args);
if (options.PrintVersion)
{
Console.WriteLine(GetLongVersion());
return options;
}
if (options.PrintHelp)
{
Console.WriteLine(GetShortVersion());
Console.WriteLine(GetUsage());
return options;
}
if (!options.IsParseSuccessful)
{
Console.WriteLine($"hactoolnet: {options.ParseErrorMessage}");
Console.WriteLine("Usage: hactoolnet [options...] <path>");
Console.WriteLine("Use 'hactoolnet --help' for full usage information.");
return options;
}
options.ContinueRunning = true;
return options;
}
public static Options ParseAllOptions(string[] args)
{ {
var options = new Options(); var options = new Options();
bool inputSpecified = false; bool inputSpecified = false;
@ -89,7 +123,7 @@ internal static class CliParser
{ {
arg = args[i][1].ToString().ToLower(); arg = args[i][1].ToString().ToLower();
} }
else if (args[i].Length > 2 && args[i].Substring(0, 2) == "--") else if (args[i].Length > 2 && (args[i][0] == '-' && args[i][1] == '-'))
{ {
arg = args[i].Substring(2).ToLower(); arg = args[i].Substring(2).ToLower();
} }
@ -97,8 +131,8 @@ internal static class CliParser
{ {
if (inputSpecified) if (inputSpecified)
{ {
PrintWithUsage($"Unable to parse option {args[i]}"); options.ParseErrorMessage ??= $"Unable to parse option {args[i]}";
return null; continue;
} }
options.InFile = args[i]; options.InFile = args[i];
@ -109,14 +143,14 @@ internal static class CliParser
CliOption option = cliOptions.FirstOrDefault(x => x.Long == arg || x.Short == arg); CliOption option = cliOptions.FirstOrDefault(x => x.Long == arg || x.Short == arg);
if (option == null) if (option == null)
{ {
PrintWithUsage($"Unknown option {args[i]}"); options.ParseErrorMessage ??= $"Unknown option {args[i]}";
return null; continue;
} }
if (i + option.ArgsNeeded >= args.Length) if (i + option.ArgsNeeded >= args.Length)
{ {
PrintWithUsage($"Need {option.ArgsNeeded} parameter{(option.ArgsNeeded == 1 ? "" : "s")} after {args[i]}"); options.ParseErrorMessage ??= $"Need {option.ArgsNeeded} parameter{(option.ArgsNeeded == 1 ? "" : "s")} after {args[i]}";
return null; continue;
} }
string[] optionArgs = new string[option.ArgsNeeded]; string[] optionArgs = new string[option.ArgsNeeded];
@ -128,14 +162,14 @@ internal static class CliParser
if (!inputSpecified && options.InFileType != FileType.Keygen && options.InFileType != FileType.Bench && !options.RunCustom) if (!inputSpecified && options.InFileType != FileType.Keygen && options.InFileType != FileType.Bench && !options.RunCustom)
{ {
PrintWithUsage("Input file must be specified"); options.ParseErrorMessage ??= "Input file must be specified";
return null;
} }
options.IsParseSuccessful = options.ParseErrorMessage is null;
return options; return options;
} }
private static FileType ParseFileType(string input) private static FileType ParseFileType(Options options, string input)
{ {
switch (input.ToLower()) switch (input.ToLower())
{ {
@ -158,41 +192,51 @@ internal static class CliParser
case "bench": return FileType.Bench; case "bench": return FileType.Bench;
} }
PrintWithUsage("Specified type is invalid."); options.ParseErrorMessage ??= "Specified type is invalid.";
return default; return default;
} }
private static ulong ParseTitleId(string input) private static ulong ParseTitleId(Options options, string input)
{ {
if (input.Length != 16) if (input.Length != 16)
{ {
PrintWithUsage("Title ID must be 16 hex characters long"); options.ParseErrorMessage ??= "Title ID must be 16 hex characters long";
return default;
} }
if (!ulong.TryParse(input, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong id)) if (!ulong.TryParse(input, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong id))
{ {
PrintWithUsage("Could not parse title ID"); options.ParseErrorMessage ??= "Could not parse title ID";
} }
return id; return id;
} }
private static double ParseDouble(string input) private static double ParseDouble(Options options, string input)
{ {
if (!double.TryParse(input, out double value)) if (!double.TryParse(input, out double value))
{ {
PrintWithUsage($"Could not parse value \"{input}\""); options.ParseErrorMessage ??= $"Could not parse value \"{input}\"";
} }
return value; return value;
} }
private static void PrintWithUsage(string toPrint) private static string GetShortVersion()
{ {
Console.WriteLine(toPrint); return $"hactoolnet {VersionInfo.Version}";
Console.WriteLine(GetUsage()); }
// PrintUsage();
private static string GetLongVersion()
{
var sb = new StringBuilder();
sb.AppendLine($"hactoolnet {VersionInfo.Version}");
//sb.AppendLine($"Commit time: {VersionInfo.CommitTime}");
//sb.Append($"Commit hash: {VersionInfo.CommitHash}");
return sb.ToString();
} }
private static string GetUsage() private static string GetUsage()
@ -210,6 +254,8 @@ internal static class CliParser
sb.AppendLine(" --titlekeys <file> Load title keys from an external file."); sb.AppendLine(" --titlekeys <file> Load title keys from an external file.");
sb.AppendLine(" --accesslog <file> Specify the access log file path."); sb.AppendLine(" --accesslog <file> Specify the access log file path.");
sb.AppendLine(" --disablekeywarns Disables warning output when loading external keys."); sb.AppendLine(" --disablekeywarns Disables warning output when loading external keys.");
sb.AppendLine(" --version Display version information and exit.");
sb.AppendLine(" --help Display this help and exit.");
sb.AppendLine("NCA options:"); sb.AppendLine("NCA options:");
sb.AppendLine(" --plaintext <file> Specify file path for saving a decrypted copy of the NCA."); sb.AppendLine(" --plaintext <file> Specify file path for saving a decrypted copy of the NCA.");
sb.AppendLine(" --ciphertext <file> Specify file path for saving an encrypted copy of the NCA."); sb.AppendLine(" --ciphertext <file> Specify file path for saving an encrypted copy of the NCA.");

View file

@ -7,6 +7,8 @@ namespace hactoolnet;
internal class Options internal class Options
{ {
public bool PrintHelp;
public bool PrintVersion;
public bool RunCustom; public bool RunCustom;
public string InFile; public string InFile;
public FileType InFileType = FileType.Nca; public FileType InFileType = FileType.Nca;
@ -62,6 +64,10 @@ internal class Options
public string BenchType; public string BenchType;
public double CpuFrequencyGhz; public double CpuFrequencyGhz;
public string ParseErrorMessage;
public bool IsParseSuccessful;
public bool ContinueRunning;
public IntegrityCheckLevel IntegrityLevel public IntegrityCheckLevel IntegrityLevel
{ {
get get

View file

@ -60,7 +60,9 @@ public static class Program
Console.OutputEncoding = Encoding.UTF8; Console.OutputEncoding = Encoding.UTF8;
var ctx = new Context(); var ctx = new Context();
ctx.Options = CliParser.Parse(args); ctx.Options = CliParser.Parse(args);
if (ctx.Options == null) return false; if (!ctx.Options.IsParseSuccessful) return false;
if (!ctx.Options.ContinueRunning) return true;
StreamWriter logWriter = null; StreamWriter logWriter = null;
ResultLogger resultLogger = null; ResultLogger resultLogger = null;

View file

@ -0,0 +1,9 @@
namespace hactoolnet
{
internal static class VersionInfo
{
public static string Version => "0.17.0";
public static string CommitTime => "";
public static string CommitHash => "";
}
}

View file

@ -6,7 +6,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<VersionPrefix>0.16.1</VersionPrefix> <VersionPrefix>0.17.0</VersionPrefix>
<PathMap Condition=" '$(BuildType)' == 'Release' ">$(MSBuildProjectDirectory)=C:/hactoolnet/</PathMap> <PathMap Condition=" '$(BuildType)' == 'Release' ">$(MSBuildProjectDirectory)=C:/hactoolnet/</PathMap>
</PropertyGroup> </PropertyGroup>
@ -15,6 +15,10 @@
<EmbeddedResource Include="CA00000003_XS00000020" /> <EmbeddedResource Include="CA00000003_XS00000020" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Condition="Exists('VersionInfo.Generated.cs')" Remove="VersionInfo.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LibHac\LibHac.csproj" /> <ProjectReference Include="..\LibHac\LibHac.csproj" />
</ItemGroup> </ItemGroup>