From f04fc33b07241b120116e58d0a4fd8ee7cc72dfe Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Mon, 17 Sep 2018 19:52:22 -0500 Subject: [PATCH] Read INI1 --- LibHac/Kip.cs | 43 ++++++++++++++++++++++++++++++++++++++++ hactoolnet/CliParser.cs | 4 +++- hactoolnet/Options.cs | 3 ++- hactoolnet/ProcessKip.cs | 20 +++++++++++++++++++ hactoolnet/Program.cs | 3 +++ 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/LibHac/Kip.cs b/LibHac/Kip.cs index 9b06b3d7..f09b0a1f 100644 --- a/LibHac/Kip.cs +++ b/LibHac/Kip.cs @@ -49,6 +49,8 @@ namespace LibHac return DecompressBlz(compressed); } + public Stream OpenRawFile() => StreamSource.CreateStream(); + private static byte[] DecompressBlz(byte[] compressed) { int additionalSize = BitConverter.ToInt32(compressed, compressed.Length - 4); @@ -161,4 +163,45 @@ namespace LibHac Attribute = reader.ReadInt32(); } } + + public class Ini1 + { + public Kip[] Kips { get; } + + public string Magic { get; } + public int Size { get; } + public int KipCount { get; } + + private SharedStreamSource StreamSource { get; } + + public Ini1(Stream stream) + { + StreamSource = new SharedStreamSource(stream); + Stream initStream = StreamSource.CreateStream(); + + var reader = new BinaryReader(initStream); + + Magic = reader.ReadAscii(4); + if (Magic != "INI1") + { + throw new InvalidDataException("Invalid INI1 file!"); + } + + Size = reader.ReadInt32(); + KipCount = reader.ReadInt32(); + + Kips = new Kip[KipCount]; + int offset = 0x10; + + for (int i = 0; i < KipCount; i++) + { + // How to get the KIP's size the lazy way + var kip = new Kip(StreamSource.CreateStream(offset)); + + Kips[i] = new Kip(StreamSource.CreateStream(offset, kip.Size)); + + offset += kip.Size; + } + } + } } diff --git a/hactoolnet/CliParser.cs b/hactoolnet/CliParser.cs index 11e62bef..62bf0dde 100644 --- a/hactoolnet/CliParser.cs +++ b/hactoolnet/CliParser.cs @@ -147,7 +147,7 @@ namespace hactoolnet sb.AppendLine(" -r, --raw Keep raw data, don\'t unpack."); sb.AppendLine(" -y, --verify Verify hashes."); sb.AppendLine(" -k, --keyset Load keys from an external file."); - sb.AppendLine(" -t, --intype=type Specify input file type [nca, xci, romfs, pk11, pk21, switchfs, save, keygen]"); + sb.AppendLine(" -t, --intype=type Specify input file type [nca, xci, romfs, pk11, pk21, ini1, kip1, switchfs, save, keygen]"); sb.AppendLine(" --titlekeys Load title keys from an external file."); sb.AppendLine("NCA options:"); sb.AppendLine(" --section0 Specify Section 0 file path."); @@ -183,6 +183,8 @@ namespace hactoolnet sb.AppendLine(" --outdir Specify Package1 directory path."); sb.AppendLine("Package2 options:"); sb.AppendLine(" --outdir Specify Package2 directory path."); + sb.AppendLine("INI1 options:"); + sb.AppendLine(" --outdir Specify INI1 directory path."); sb.AppendLine("Switch FS options:"); sb.AppendLine(" --sdseed Set console unique seed for SD card NAX0 encryption."); sb.AppendLine(" --listapps List application info."); diff --git a/hactoolnet/Options.cs b/hactoolnet/Options.cs index ad791779..44d1845a 100644 --- a/hactoolnet/Options.cs +++ b/hactoolnet/Options.cs @@ -49,7 +49,8 @@ namespace hactoolnet Keygen, Pk11, Pk21, - Kip1 + Kip1, + Ini1 } internal class Context diff --git a/hactoolnet/ProcessKip.cs b/hactoolnet/ProcessKip.cs index 448851f4..7051b138 100644 --- a/hactoolnet/ProcessKip.cs +++ b/hactoolnet/ProcessKip.cs @@ -12,5 +12,25 @@ namespace hactoolnet var kip = new Kip(file); } } + + public static void ProcessIni1(Context ctx) + { + using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) + { + var ini1 = new Ini1(file); + + string outDir = ctx.Options.OutDir; + + if (outDir != null) + { + Directory.CreateDirectory(outDir); + + foreach (Kip kip in ini1.Kips) + { + kip.OpenRawFile().WriteAllBytes(Path.Combine(outDir, $"{kip.Header.Name}.kip1")); + } + } + } + } } } diff --git a/hactoolnet/Program.cs b/hactoolnet/Program.cs index e18f30ef..8a01d1b3 100644 --- a/hactoolnet/Program.cs +++ b/hactoolnet/Program.cs @@ -59,6 +59,9 @@ namespace hactoolnet case FileType.Kip1: ProcessKip.ProcessKip1(ctx); break; + case FileType.Ini1: + ProcessKip.ProcessIni1(ctx); + break; default: throw new ArgumentOutOfRangeException(); }