mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
hactoolnet: Use new NCA APIs
This commit is contained in:
parent
c267826dd1
commit
c73493b505
7 changed files with 47 additions and 79 deletions
|
@ -10,7 +10,7 @@ namespace LibHac.IO.NcaUtils
|
||||||
{
|
{
|
||||||
private const int HeaderSize = 0xc00;
|
private const int HeaderSize = 0xc00;
|
||||||
private const int HeaderSectorSize = 0x200;
|
private const int HeaderSectorSize = 0x200;
|
||||||
|
|
||||||
public NcaHeader Header { get; }
|
public NcaHeader Header { get; }
|
||||||
public string NcaId { get; set; }
|
public string NcaId { get; set; }
|
||||||
public string Filename { get; set; }
|
public string Filename { get; set; }
|
||||||
|
@ -91,6 +91,11 @@ namespace LibHac.IO.NcaUtils
|
||||||
return sect.Header.EncryptionType == NcaEncryptionType.None || !IsMissingTitleKey && string.IsNullOrWhiteSpace(MissingKeyName);
|
return sect.Header.EncryptionType == NcaEncryptionType.None || !IsMissingTitleKey && string.IsNullOrWhiteSpace(MissingKeyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanOpenSection(NcaSectionType type)
|
||||||
|
{
|
||||||
|
return CanOpenSection(GetSectionIndexFromType(type));
|
||||||
|
}
|
||||||
|
|
||||||
private IStorage OpenEncryptedStorage(int index)
|
private IStorage OpenEncryptedStorage(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index > 3) throw new ArgumentOutOfRangeException(nameof(index));
|
if (index < 0 || index > 3) throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
@ -275,11 +280,9 @@ namespace LibHac.IO.NcaUtils
|
||||||
return Sections[index] != null;
|
return Sections[index] != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SectionIsDecryptable(int index)
|
public bool SectionExists(NcaSectionType type)
|
||||||
{
|
{
|
||||||
if (!SectionExists(index)) return false;
|
return SectionExists(GetSectionIndexFromType(type));
|
||||||
|
|
||||||
return Sections[index].Header.EncryptionType == NcaEncryptionType.None || !IsMissingTitleKey && string.IsNullOrWhiteSpace(MissingKeyName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -363,7 +366,7 @@ namespace LibHac.IO.NcaUtils
|
||||||
{
|
{
|
||||||
if (Header != null)
|
if (Header != null)
|
||||||
{
|
{
|
||||||
return Header.Version;
|
return Header.Version;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,16 +25,27 @@ namespace LibHac.IO.NcaUtils
|
||||||
.WriteAllBytes(filename, logger);
|
.WriteAllBytes(filename, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ExportSection(this Nca nca, NcaSectionType type, string filename, bool raw = false,
|
||||||
|
IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
||||||
|
{
|
||||||
|
nca.OpenStorage(type, integrityCheckLevel, raw)
|
||||||
|
.WriteAllBytes(filename, logger);
|
||||||
|
}
|
||||||
|
|
||||||
public static void ExtractSection(this Nca nca, int index, string outputDir,
|
public static void ExtractSection(this Nca nca, int index, string outputDir,
|
||||||
IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
||||||
{
|
{
|
||||||
if (index < 0 || index > 3) throw new IndexOutOfRangeException();
|
|
||||||
if (!nca.SectionIsDecryptable(index)) return;
|
|
||||||
|
|
||||||
IFileSystem fs = nca.OpenFileSystem(index, integrityCheckLevel);
|
IFileSystem fs = nca.OpenFileSystem(index, integrityCheckLevel);
|
||||||
fs.Extract(outputDir, logger);
|
fs.Extract(outputDir, logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ExtractSection(this Nca nca, NcaSectionType type, string outputDir,
|
||||||
|
IntegrityCheckLevel integrityCheckLevel = IntegrityCheckLevel.None, IProgressReport logger = null)
|
||||||
|
{
|
||||||
|
IFileSystem fs = nca.OpenFileSystem(type, integrityCheckLevel);
|
||||||
|
fs.Extract(outputDir, logger);
|
||||||
|
}
|
||||||
|
|
||||||
public static Validity VerifyNca(this Nca nca, IProgressReport logger = null, bool quiet = false)
|
public static Validity VerifyNca(this Nca nca, IProgressReport logger = null, bool quiet = false)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
|
|
|
@ -193,13 +193,6 @@ namespace LibHac.IO.NcaUtils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ProgramPartitionType
|
|
||||||
{
|
|
||||||
Code,
|
|
||||||
Data,
|
|
||||||
Logo
|
|
||||||
};
|
|
||||||
|
|
||||||
public enum NcaSectionType
|
public enum NcaSectionType
|
||||||
{
|
{
|
||||||
Code,
|
Code,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.IO;
|
using LibHac.IO;
|
||||||
|
@ -46,13 +45,13 @@ namespace hactoolnet
|
||||||
nca.ExtractSection(i, ctx.Options.SectionOutDir[i], ctx.Options.IntegrityLevel, ctx.Logger);
|
nca.ExtractSection(i, ctx.Options.SectionOutDir[i], ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.Validate && nca.Sections[i] != null)
|
if (ctx.Options.Validate && nca.SectionExists(i))
|
||||||
{
|
{
|
||||||
nca.VerifySection(i, ctx.Logger);
|
nca.VerifySection(i, ctx.Logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ListRomFs && nca.Sections[1] != null)
|
if (ctx.Options.ListRomFs && nca.CanOpenSection(NcaSectionType.Data))
|
||||||
{
|
{
|
||||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, ctx.Options.IntegrityLevel);
|
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, ctx.Options.IntegrityLevel);
|
||||||
|
|
||||||
|
@ -64,35 +63,26 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ReadBench)
|
if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null || ctx.Options.ReadBench)
|
||||||
{
|
{
|
||||||
NcaSection section = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);
|
if (!nca.SectionExists(NcaSectionType.Data))
|
||||||
|
|
||||||
if (section == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("NCA has no RomFS section");
|
ctx.Logger.LogMessage("NCA has no RomFS section");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section.Type == SectionType.Bktr && ctx.Options.BaseNca == null)
|
|
||||||
{
|
|
||||||
ctx.Logger.LogMessage("Cannot save BKTR section without base RomFS");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.Options.RomfsOut != null)
|
if (ctx.Options.RomfsOut != null)
|
||||||
{
|
{
|
||||||
nca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
nca.ExportSection(NcaSectionType.Data, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.RomfsOutDir != null)
|
if (ctx.Options.RomfsOutDir != null)
|
||||||
{
|
{
|
||||||
IFileSystem romfs = nca.OpenFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
|
nca.ExtractSection(NcaSectionType.Data, ctx.Options.RomfsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ReadBench)
|
if (ctx.Options.ReadBench)
|
||||||
{
|
{
|
||||||
long bytesToRead = 1024L * 1024 * 1024 * 5;
|
long bytesToRead = 1024L * 1024 * 1024 * 5;
|
||||||
IStorage storage = nca.OpenStorage(section.SectionNum, ctx.Options.IntegrityLevel);
|
IStorage storage = nca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel);
|
||||||
var dest = new NullStorage(storage.Length);
|
var dest = new NullStorage(storage.Length);
|
||||||
|
|
||||||
int iterations = (int)(bytesToRead / storage.Length) + 1;
|
int iterations = (int)(bytesToRead / storage.Length) + 1;
|
||||||
|
@ -119,9 +109,7 @@ namespace hactoolnet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaSection section = nca.Sections[(int)ProgramPartitionType.Code];
|
if (!nca.SectionExists(NcaSectionType.Code))
|
||||||
|
|
||||||
if (section == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("Could not find an ExeFS section");
|
ctx.Logger.LogMessage("Could not find an ExeFS section");
|
||||||
return;
|
return;
|
||||||
|
@ -129,13 +117,12 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.ExefsOut != null)
|
if (ctx.Options.ExefsOut != null)
|
||||||
{
|
{
|
||||||
nca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
nca.ExportSection(NcaSectionType.Code, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ExefsOutDir != null)
|
if (ctx.Options.ExefsOutDir != null)
|
||||||
{
|
{
|
||||||
IFileSystem pfs = nca.OpenFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
|
nca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
pfs.Extract(ctx.Options.ExefsOutDir, ctx.Logger);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +186,7 @@ namespace hactoolnet
|
||||||
NcaSection sect = nca.Sections[i];
|
NcaSection sect = nca.Sections[i];
|
||||||
if (sect == null) continue;
|
if (sect == null) continue;
|
||||||
|
|
||||||
bool isExefs = nca.Header.ContentType == ContentType.Program && i == (int)ProgramPartitionType.Code;
|
bool isExefs = nca.Header.ContentType == ContentType.Program && i == 0;
|
||||||
|
|
||||||
sb.AppendLine($" Section {i}:");
|
sb.AppendLine($" Section {i}:");
|
||||||
PrintItem(sb, colLen, " Offset:", $"0x{sect.Offset:x12}");
|
PrintItem(sb, colLen, " Offset:", $"0x{sect.Offset:x12}");
|
||||||
|
|
|
@ -10,13 +10,14 @@ namespace hactoolnet
|
||||||
{
|
{
|
||||||
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
|
||||||
{
|
{
|
||||||
var romfs = new RomFsFileSystem(file);
|
Process(ctx, file);
|
||||||
Process(ctx, romfs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Process(Context ctx, RomFsFileSystem romfs)
|
public static void Process(Context ctx, IStorage romfsStorage)
|
||||||
{
|
{
|
||||||
|
var romfs = new RomFsFileSystem(romfsStorage);
|
||||||
|
|
||||||
if (ctx.Options.ListRomFs)
|
if (ctx.Options.ListRomFs)
|
||||||
{
|
{
|
||||||
foreach (DirectoryEntry entry in romfs.EnumerateEntries())
|
foreach (DirectoryEntry entry in romfs.EnumerateEntries())
|
||||||
|
@ -29,7 +30,6 @@ namespace hactoolnet
|
||||||
{
|
{
|
||||||
using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite))
|
using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite))
|
||||||
{
|
{
|
||||||
IStorage romfsStorage = romfs.GetBaseStorage();
|
|
||||||
romfsStorage.CopyToStream(outFile, romfsStorage.Length, ctx.Logger);
|
romfsStorage.CopyToStream(outFile, romfsStorage.Length, ctx.Logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,9 +69,7 @@ namespace hactoolnet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaSection section = title.MainNca.Sections[(int)ProgramPartitionType.Code];
|
if (!title.MainNca.SectionExists(NcaSectionType.Code))
|
||||||
|
|
||||||
if (section == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
|
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
|
||||||
return;
|
return;
|
||||||
|
@ -79,12 +77,12 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.ExefsOutDir != null)
|
if (ctx.Options.ExefsOutDir != null)
|
||||||
{
|
{
|
||||||
title.MainNca.ExtractSection(section.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
title.MainNca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ExefsOut != null)
|
if (ctx.Options.ExefsOut != null)
|
||||||
{
|
{
|
||||||
title.MainNca.ExportSection(section.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
title.MainNca.ExportSection(NcaSectionType.Code, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,24 +107,13 @@ namespace hactoolnet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaSection section = title.MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);
|
if (!title.MainNca.SectionExists(NcaSectionType.Data))
|
||||||
|
|
||||||
if (section == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
|
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.RomfsOutDir != null)
|
ProcessRomfs.Process(ctx, title.MainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false));
|
||||||
{
|
|
||||||
IFileSystem romfs = title.MainNca.OpenFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
|
|
||||||
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.Options.RomfsOut != null)
|
|
||||||
{
|
|
||||||
title.MainNca.ExportSection(section.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.OutDir != null)
|
if (ctx.Options.OutDir != null)
|
||||||
|
|
|
@ -72,9 +72,7 @@ namespace hactoolnet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaSection exefsSection = mainNca.Sections[(int)ProgramPartitionType.Code];
|
if (!mainNca.SectionExists(NcaSectionType.Code))
|
||||||
|
|
||||||
if (exefsSection == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("NCA has no ExeFS section");
|
ctx.Logger.LogMessage("NCA has no ExeFS section");
|
||||||
return;
|
return;
|
||||||
|
@ -82,12 +80,12 @@ namespace hactoolnet
|
||||||
|
|
||||||
if (ctx.Options.ExefsOutDir != null)
|
if (ctx.Options.ExefsOutDir != null)
|
||||||
{
|
{
|
||||||
mainNca.ExtractSection(exefsSection.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
mainNca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ExefsOut != null)
|
if (ctx.Options.ExefsOut != null)
|
||||||
{
|
{
|
||||||
mainNca.ExportSection(exefsSection.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
mainNca.ExportSection(NcaSectionType.Code, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,24 +99,13 @@ namespace hactoolnet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaSection romfsSection = mainNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs);
|
if (!mainNca.SectionExists(NcaSectionType.Data))
|
||||||
|
|
||||||
if (romfsSection == null)
|
|
||||||
{
|
{
|
||||||
ctx.Logger.LogMessage("NCA has no RomFS section");
|
ctx.Logger.LogMessage("NCA has no RomFS section");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.RomfsOutDir != null)
|
ProcessRomfs.Process(ctx, mainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false));
|
||||||
{
|
|
||||||
IFileSystem romfs = mainNca.OpenFileSystem(romfsSection.SectionNum, ctx.Options.IntegrityLevel);
|
|
||||||
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.Options.RomfsOut != null)
|
|
||||||
{
|
|
||||||
mainNca.ExportSection(romfsSection.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue