From 8232ff7ed667cc2c847c9bc2b92608b67d095ecf Mon Sep 17 00:00:00 2001
From: MonsterDruide1 <5958456@gmail.com>
Date: Wed, 28 Sep 2022 14:23:24 +0200
Subject: [PATCH] hactoolnet: Add NPDM converter
---
README.md | 2 ++
src/hactoolnet/CliParser.cs | 6 +++++-
src/hactoolnet/Options.cs | 4 +++-
src/hactoolnet/ProcessNpdm.cs | 27 +++++++++++++++++++++++++++
src/hactoolnet/Program.cs | 3 +++
5 files changed, 40 insertions(+), 2 deletions(-)
create mode 100644 src/hactoolnet/ProcessNpdm.cs
diff --git a/README.md b/README.md
index 2fd499c0..e819f89a 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,8 @@ NCA options:
--romfsdir
Specify RomFS directory path.
--listromfs List files in RomFS.
--basenca Set Base NCA to use with update partitions.
+NPDM options:
+ --json Specify file path for saving JSON representation of program permissions to.
KIP1 options:
--uncompressed Specify file path for saving uncompressed KIP1.
RomFS options:
diff --git a/src/hactoolnet/CliParser.cs b/src/hactoolnet/CliParser.cs
index f8ae51c6..a6a249dc 100644
--- a/src/hactoolnet/CliParser.cs
+++ b/src/hactoolnet/CliParser.cs
@@ -68,6 +68,7 @@ internal static class CliParser
new CliOption("title", 1, (o, a) => o.TitleId = ParseTitleId(o, a[0])),
new CliOption("bench", 1, (o, a) => o.BenchType = a[0]),
new CliOption("cpufreq", 1, (o, a) => o.CpuFrequencyGhz = ParseDouble(o, a[0])),
+ new CliOption("json", 1, (o, a) => o.JsonFile = a[0]),
new CliOption("replacefile", 2, (o, a) =>
{
@@ -190,6 +191,7 @@ internal static class CliParser
case "ini1": return FileType.Ini1;
case "ndv0": return FileType.Ndv0;
case "bench": return FileType.Bench;
+ case "npdm": return FileType.Npdm;
}
options.ParseErrorMessage ??= "Specified type is invalid.";
@@ -274,6 +276,8 @@ internal static class CliParser
sb.AppendLine(" --romfsdir Specify RomFS directory path.");
sb.AppendLine(" --listromfs List files in RomFS.");
sb.AppendLine(" --basenca Set Base NCA to use with update partitions.");
+ sb.AppendLine("NPDM options:");
+ sb.AppendLine(" --json Specify file path for saving JSON representation of program permissions to.");
sb.AppendLine("KIP1 options:");
sb.AppendLine(" --uncompressed Specify file path for saving uncompressed KIP1.");
sb.AppendLine("RomFS options:");
@@ -370,4 +374,4 @@ internal static class CliParser
public int ArgsNeeded { get; }
public Action Assigner { get; }
}
-}
\ No newline at end of file
+}
diff --git a/src/hactoolnet/Options.cs b/src/hactoolnet/Options.cs
index a0ab9032..420eb1ff 100644
--- a/src/hactoolnet/Options.cs
+++ b/src/hactoolnet/Options.cs
@@ -63,6 +63,7 @@ internal class Options
public ulong TitleId;
public string BenchType;
public double CpuFrequencyGhz;
+ public string JsonFile;
public string ParseErrorMessage;
public bool IsParseSuccessful;
@@ -99,7 +100,8 @@ internal enum FileType
Kip1,
Ini1,
Ndv0,
- Bench
+ Bench,
+ Npdm
}
internal class Context
diff --git a/src/hactoolnet/ProcessNpdm.cs b/src/hactoolnet/ProcessNpdm.cs
new file mode 100644
index 00000000..d5b411c9
--- /dev/null
+++ b/src/hactoolnet/ProcessNpdm.cs
@@ -0,0 +1,27 @@
+using System.IO;
+using System.Text.Json;
+using LibHac.FsSystem;
+using LibHac.Tools.FsSystem;
+using LibHac.Tools.Npdm;
+
+namespace hactoolnet;
+
+internal static class ProcessNpdm
+{
+ public static void Process(Context ctx)
+ {
+ using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
+ {
+ var npdm = new NpdmBinary(file.AsStream(), ctx.KeySet);
+
+ if(ctx.Options.JsonFile != null)
+ {
+ string json = JsonSerializer.Serialize(npdm, new JsonSerializerOptions
+ {
+ WriteIndented = true
+ });
+ File.WriteAllText(ctx.Options.JsonFile, json);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/hactoolnet/Program.cs b/src/hactoolnet/Program.cs
index 9a540320..2be33d1e 100644
--- a/src/hactoolnet/Program.cs
+++ b/src/hactoolnet/Program.cs
@@ -182,6 +182,9 @@ public static class Program
case FileType.Bench:
ProcessBench.Process(ctx);
break;
+ case FileType.Npdm:
+ ProcessNpdm.Process(ctx);
+ break;
default:
throw new ArgumentOutOfRangeException();
}