hactoolnet: Use new NCA APIs

This commit is contained in:
Alex Barney 2019-03-15 21:12:43 -05:00
parent c267826dd1
commit c73493b505
7 changed files with 47 additions and 79 deletions

View file

@ -91,6 +91,11 @@ namespace LibHac.IO.NcaUtils
return sect.Header.EncryptionType == NcaEncryptionType.None || !IsMissingTitleKey && string.IsNullOrWhiteSpace(MissingKeyName);
}
public bool CanOpenSection(NcaSectionType type)
{
return CanOpenSection(GetSectionIndexFromType(type));
}
private IStorage OpenEncryptedStorage(int index)
{
if (index < 0 || index > 3) throw new ArgumentOutOfRangeException(nameof(index));
@ -275,11 +280,9 @@ namespace LibHac.IO.NcaUtils
return Sections[index] != null;
}
public bool SectionIsDecryptable(int index)
public bool SectionExists(NcaSectionType type)
{
if (!SectionExists(index)) return false;
return Sections[index].Header.EncryptionType == NcaEncryptionType.None || !IsMissingTitleKey && string.IsNullOrWhiteSpace(MissingKeyName);
return SectionExists(GetSectionIndexFromType(type));
}
/// <summary>

View file

@ -25,16 +25,27 @@ namespace LibHac.IO.NcaUtils
.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,
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);
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)
{
for (int i = 0; i < 3; i++)

View file

@ -193,13 +193,6 @@ namespace LibHac.IO.NcaUtils
}
}
public enum ProgramPartitionType
{
Code,
Data,
Logo
};
public enum NcaSectionType
{
Code,

View file

@ -1,5 +1,4 @@
using System.IO;
using System.Linq;
using System.Text;
using LibHac;
using LibHac.IO;
@ -46,13 +45,13 @@ namespace hactoolnet
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);
}
}
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);
@ -64,35 +63,26 @@ namespace hactoolnet
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 (section == null)
if (!nca.SectionExists(NcaSectionType.Data))
{
ctx.Logger.LogMessage("NCA has no RomFS section");
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)
{
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)
{
IFileSystem romfs = nca.OpenFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger);
nca.ExtractSection(NcaSectionType.Data, ctx.Options.RomfsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
}
if (ctx.Options.ReadBench)
{
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);
int iterations = (int)(bytesToRead / storage.Length) + 1;
@ -119,9 +109,7 @@ namespace hactoolnet
return;
}
NcaSection section = nca.Sections[(int)ProgramPartitionType.Code];
if (section == null)
if (!nca.SectionExists(NcaSectionType.Code))
{
ctx.Logger.LogMessage("Could not find an ExeFS section");
return;
@ -129,13 +117,12 @@ namespace hactoolnet
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)
{
IFileSystem pfs = nca.OpenFileSystem(section.SectionNum, ctx.Options.IntegrityLevel);
pfs.Extract(ctx.Options.ExefsOutDir, ctx.Logger);
nca.ExtractSection(NcaSectionType.Code, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger);
}
}
@ -199,7 +186,7 @@ namespace hactoolnet
NcaSection sect = nca.Sections[i];
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}:");
PrintItem(sb, colLen, " Offset:", $"0x{sect.Offset:x12}");

View file

@ -10,13 +10,14 @@ namespace hactoolnet
{
using (var file = new LocalStorage(ctx.Options.InFile, FileAccess.Read))
{
var romfs = new RomFsFileSystem(file);
Process(ctx, romfs);
Process(ctx, file);
}
}
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)
{
foreach (DirectoryEntry entry in romfs.EnumerateEntries())
@ -29,7 +30,6 @@ namespace hactoolnet
{
using (var outFile = new FileStream(ctx.Options.RomfsOut, FileMode.Create, FileAccess.ReadWrite))
{
IStorage romfsStorage = romfs.GetBaseStorage();
romfsStorage.CopyToStream(outFile, romfsStorage.Length, ctx.Logger);
}
}

View file

@ -69,9 +69,7 @@ namespace hactoolnet
return;
}
NcaSection section = title.MainNca.Sections[(int)ProgramPartitionType.Code];
if (section == null)
if (!title.MainNca.SectionExists(NcaSectionType.Code))
{
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no ExeFS section");
return;
@ -79,12 +77,12 @@ namespace hactoolnet
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)
{
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;
}
NcaSection section = title.MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);
if (section == null)
if (!title.MainNca.SectionExists(NcaSectionType.Data))
{
ctx.Logger.LogMessage($"Main NCA for title {id:X16} has no RomFS section");
return;
}
if (ctx.Options.RomfsOutDir != null)
{
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);
}
ProcessRomfs.Process(ctx, title.MainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false));
}
if (ctx.Options.OutDir != null)

View file

@ -72,9 +72,7 @@ namespace hactoolnet
return;
}
NcaSection exefsSection = mainNca.Sections[(int)ProgramPartitionType.Code];
if (exefsSection == null)
if (!mainNca.SectionExists(NcaSectionType.Code))
{
ctx.Logger.LogMessage("NCA has no ExeFS section");
return;
@ -82,12 +80,12 @@ namespace hactoolnet
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)
{
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;
}
NcaSection romfsSection = mainNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs);
if (romfsSection == null)
if (!mainNca.SectionExists(NcaSectionType.Data))
{
ctx.Logger.LogMessage("NCA has no RomFS section");
return;
}
if (ctx.Options.RomfsOutDir != null)
{
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);
}
ProcessRomfs.Process(ctx, mainNca.OpenStorage(NcaSectionType.Data, ctx.Options.IntegrityLevel, false));
}
}
}