mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Read NCA header
This commit is contained in:
parent
8054d38f5a
commit
e3d8e60b0e
6 changed files with 327 additions and 47 deletions
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using libhac;
|
using libhac;
|
||||||
|
|
||||||
namespace hactoolnet
|
namespace hactoolnet
|
||||||
|
@ -22,7 +23,7 @@ namespace hactoolnet
|
||||||
using (var output = new FileStream(args[4], FileMode.Create))
|
using (var output = new FileStream(args[4], FileMode.Create))
|
||||||
using (var progress = new ProgressBar())
|
using (var progress = new ProgressBar())
|
||||||
{
|
{
|
||||||
progress.LogMessage($"Title ID: {nca.TitleId:X8}");
|
progress.LogMessage($"Title ID: {nca.Header.TitleId:X16}");
|
||||||
progress.LogMessage($"Writing {args[4]}");
|
progress.LogMessage($"Writing {args[4]}");
|
||||||
nax0.Stream.CopyStream(output, nax0.Stream.Length, progress);
|
nax0.Stream.CopyStream(output, nax0.Stream.Length, progress);
|
||||||
}
|
}
|
||||||
|
@ -33,11 +34,11 @@ namespace hactoolnet
|
||||||
var keyset = ExternalKeys.ReadKeyFile(args[0]);
|
var keyset = ExternalKeys.ReadKeyFile(args[0]);
|
||||||
keyset.SetSdSeed(args[1].ToBytes());
|
keyset.SetSdSeed(args[1].ToBytes());
|
||||||
var sdfs = new SdFs(keyset, args[2]);
|
var sdfs = new SdFs(keyset, args[2]);
|
||||||
var ncas = sdfs.ReadAllNca();
|
var ncas = sdfs.ReadAllNca().ToArray();
|
||||||
|
|
||||||
foreach (var nca in ncas)
|
foreach (var nca in ncas)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{nca.TitleId:X8} {nca.ContentType} {nca.Name}");
|
Console.WriteLine($"{nca.Header.TitleId:X16} {nca.Header.ContentType} {nca.Name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace libhac
|
||||||
public byte[] header_kek_source { get; set; } = new byte[0x10];
|
public byte[] header_kek_source { get; set; } = new byte[0x10];
|
||||||
public byte[] sd_card_kek_source { get; set; } = new byte[0x10];
|
public byte[] sd_card_kek_source { get; set; } = new byte[0x10];
|
||||||
public byte[][] sd_card_key_sources { get; set; } = Util.CreateJaggedArray<byte[][]>(2, 0x20);
|
public byte[][] sd_card_key_sources { get; set; } = Util.CreateJaggedArray<byte[][]>(2, 0x20);
|
||||||
|
public byte[][] sd_card_key_sources_specific { get; set; } = Util.CreateJaggedArray<byte[][]>(2, 0x20);
|
||||||
public byte[] encrypted_header_key { get; set; } = new byte[0x20];
|
public byte[] encrypted_header_key { get; set; } = new byte[0x20];
|
||||||
public byte[] header_key { get; set; } = new byte[0x20];
|
public byte[] header_key { get; set; } = new byte[0x20];
|
||||||
public byte[][] titlekeks { get; set; } = Util.CreateJaggedArray<byte[][]>(0x20, 0x10);
|
public byte[][] titlekeks { get; set; } = Util.CreateJaggedArray<byte[][]>(0x20, 0x10);
|
||||||
|
@ -42,13 +43,14 @@ namespace libhac
|
||||||
|
|
||||||
public void SetSdSeed(byte[] sdseed)
|
public void SetSdSeed(byte[] sdseed)
|
||||||
{
|
{
|
||||||
foreach (byte[] key in sd_card_key_sources)
|
for (int k = 0; k < sd_card_key_sources.Length; k++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 0x20; i++)
|
for (int i = 0; i < 0x20; i++)
|
||||||
{
|
{
|
||||||
key[i] ^= sdseed[i & 0xF];
|
sd_card_key_sources_specific[k][i] = (byte)(sd_card_key_sources[k][i] ^ sdseed[i & 0xF]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeriveKeys();
|
DeriveKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +67,9 @@ namespace libhac
|
||||||
var sdKek = new byte[0x10];
|
var sdKek = new byte[0x10];
|
||||||
Crypto.GenerateKek(sdKek, sd_card_kek_source, master_keys[0], aes_kek_generation_source, aes_key_generation_source);
|
Crypto.GenerateKek(sdKek, sd_card_kek_source, master_keys[0], aes_kek_generation_source, aes_key_generation_source);
|
||||||
|
|
||||||
for (int k = 0; k < sd_card_key_sources.Length; k++)
|
for (int k = 0; k < sd_card_key_sources_specific.Length; k++)
|
||||||
{
|
{
|
||||||
Crypto.DecryptEcb(sdKek, sd_card_key_sources[k], sd_card_keys[k], 0x20);
|
Crypto.DecryptEcb(sdKek, sd_card_key_sources_specific[k], sd_card_keys[k], 0x20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +78,7 @@ namespace libhac
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, KeyValue> KeyDict = CreateKeyDict();
|
private static readonly Dictionary<string, KeyValue> KeyDict = CreateKeyDict();
|
||||||
|
|
||||||
public static Keyset ReadKeyFile(string filename)
|
public static Keyset ReadKeyFile(string filename, IProgressReport progress = null)
|
||||||
{
|
{
|
||||||
var keyset = new Keyset();
|
var keyset = new Keyset();
|
||||||
using (var reader = new StreamReader(new FileStream(filename, FileMode.Open)))
|
using (var reader = new StreamReader(new FileStream(filename, FileMode.Open)))
|
||||||
|
@ -92,14 +94,14 @@ namespace libhac
|
||||||
|
|
||||||
if (!KeyDict.TryGetValue(key, out var kv))
|
if (!KeyDict.TryGetValue(key, out var kv))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to match key {key}");
|
progress?.LogMessage($"Failed to match key {key}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = valueStr.ToBytes();
|
var value = valueStr.ToBytes();
|
||||||
if (value.Length != kv.Size)
|
if (value.Length != kv.Size)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Key {key} had incorrect size {value.Length}. (Expected {kv.Size})");
|
progress?.LogMessage($"Key {key} had incorrect size {value.Length}. (Expected {kv.Size})");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
333
libhac/Nca.cs
333
libhac/Nca.cs
|
@ -1,54 +1,325 @@
|
||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using libhac.XTSSharp;
|
using libhac.XTSSharp;
|
||||||
|
|
||||||
namespace libhac
|
namespace libhac
|
||||||
{
|
{
|
||||||
public class Nca
|
public class Nca
|
||||||
{
|
{
|
||||||
public byte[] Signature1 { get; set; } // RSA-PSS signature over header with fixed key.
|
public NcaHeader Header { get; private set; }
|
||||||
public byte[] Signature2 { get; set; } // RSA-PSS signature over header with key in NPDM.
|
|
||||||
public string Magic { get; set; }
|
|
||||||
public byte Distribution { get; set; } // System vs gamecard.
|
|
||||||
public byte ContentType { get; set; }
|
|
||||||
public byte CryptoType { get; set; } // Which keyblob (field 1)
|
|
||||||
public byte KaekInd { get; set; } // Which kaek index?
|
|
||||||
public ulong NcaSize { get; set; } // Entire archive size.
|
|
||||||
public ulong TitleId { get; set; }
|
|
||||||
public uint SdkVersion { get; set; } // What SDK was this built with?
|
|
||||||
public byte CryptoType2 { get; set; } // Which keyblob (field 2)
|
|
||||||
public byte[] RightsId { get; set; }
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public bool HasRightsId { get; private set; }
|
||||||
|
public int CryptoType { get; private set; }
|
||||||
|
public byte[][] DecryptedKeys { get; } = Util.CreateJaggedArray<byte[][]>(4, 0x10);
|
||||||
|
|
||||||
public Nca(Keyset keyset, Stream stream)
|
public Nca(Keyset keyset, Stream stream)
|
||||||
{
|
{
|
||||||
ReadHeader(keyset, stream);
|
ReadHeader(keyset, stream);
|
||||||
|
|
||||||
|
CryptoType = Math.Max(Header.CryptoType, Header.CryptoType2);
|
||||||
|
if (CryptoType > 0) CryptoType--;
|
||||||
|
|
||||||
|
HasRightsId = !Header.RightsId.IsEmpty();
|
||||||
|
|
||||||
|
if (!HasRightsId)
|
||||||
|
{
|
||||||
|
DecryptKeyArea(keyset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReadHeader(Keyset keyset, Stream stream)
|
private void ReadHeader(Keyset keyset, Stream stream)
|
||||||
{
|
{
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
var xts = XtsAes128.Create(keyset.header_key);
|
var xts = XtsAes128.Create(keyset.header_key);
|
||||||
var header = new RandomAccessSectorStream(new XtsSectorStream(stream, xts, 0x200));
|
var headerDec = new RandomAccessSectorStream(new XtsSectorStream(stream, xts, 0x200));
|
||||||
var reader = new BinaryReader(header);
|
var reader = new BinaryReader(headerDec);
|
||||||
|
|
||||||
Signature1 = reader.ReadBytes(0x100);
|
Header = NcaHeader.Read(reader);
|
||||||
Signature2 = reader.ReadBytes(0x100);
|
|
||||||
Magic = reader.ReadAscii(4);
|
|
||||||
if (Magic != "NCA3") throw new InvalidDataException("Not an NCA3 file");
|
|
||||||
Distribution = reader.ReadByte();
|
|
||||||
ContentType = reader.ReadByte();
|
|
||||||
CryptoType = reader.ReadByte();
|
|
||||||
KaekInd = reader.ReadByte();
|
|
||||||
NcaSize = reader.ReadUInt64();
|
|
||||||
TitleId = reader.ReadUInt64();
|
|
||||||
header.Position += 4;
|
|
||||||
|
|
||||||
SdkVersion = reader.ReadUInt32();
|
headerDec.Close();
|
||||||
CryptoType2 = reader.ReadByte();
|
}
|
||||||
header.Position += 0xF;
|
|
||||||
|
|
||||||
RightsId = reader.ReadBytes(0x10);
|
private void DecryptKeyArea(Keyset keyset)
|
||||||
header.Close();
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
Crypto.DecryptEcb(keyset.key_area_keys[CryptoType][Header.KaekInd], Header.EncryptedKeys[i],
|
||||||
|
DecryptedKeys[i], 0x10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NcaHeader
|
||||||
|
{
|
||||||
|
public byte[] Signature1; // RSA-PSS signature over header with fixed key.
|
||||||
|
public byte[] Signature2; // RSA-PSS signature over header with key in NPDM.
|
||||||
|
public string Magic;
|
||||||
|
public byte Distribution; // System vs gamecard.
|
||||||
|
public ContentType ContentType;
|
||||||
|
public byte CryptoType; // Which keyblob (field 1)
|
||||||
|
public byte KaekInd; // Which kaek index?
|
||||||
|
public ulong NcaSize; // Entire archive size.
|
||||||
|
public ulong TitleId;
|
||||||
|
public uint SdkVersion; // What SDK was this built with?
|
||||||
|
public byte CryptoType2; // Which keyblob (field 2)
|
||||||
|
public byte[] RightsId;
|
||||||
|
public string Name;
|
||||||
|
|
||||||
|
public NcaSectionEntry[] SectionEntries = new NcaSectionEntry[4];
|
||||||
|
public byte[][] SectionHashes = new byte[4][];
|
||||||
|
public byte[][] EncryptedKeys = new byte[4][];
|
||||||
|
|
||||||
|
public NcaFsHeader[] FsHeaders = new NcaFsHeader[4];
|
||||||
|
|
||||||
|
public static NcaHeader Read(BinaryReader reader)
|
||||||
|
{
|
||||||
|
var head = new NcaHeader();
|
||||||
|
|
||||||
|
head.Signature1 = reader.ReadBytes(0x100);
|
||||||
|
head.Signature2 = reader.ReadBytes(0x100);
|
||||||
|
head.Magic = reader.ReadAscii(4);
|
||||||
|
head.Distribution = reader.ReadByte();
|
||||||
|
head.ContentType = (ContentType)reader.ReadByte();
|
||||||
|
head.CryptoType = reader.ReadByte();
|
||||||
|
head.KaekInd = reader.ReadByte();
|
||||||
|
head.NcaSize = reader.ReadUInt64();
|
||||||
|
head.TitleId = reader.ReadUInt64();
|
||||||
|
reader.BaseStream.Position += 4;
|
||||||
|
|
||||||
|
head.SdkVersion = reader.ReadUInt32();
|
||||||
|
head.CryptoType2 = reader.ReadByte();
|
||||||
|
reader.BaseStream.Position += 0xF;
|
||||||
|
|
||||||
|
head.RightsId = reader.ReadBytes(0x10);
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
head.SectionEntries[i] = new NcaSectionEntry(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
head.SectionHashes[i] = reader.ReadBytes(0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
head.EncryptedKeys[i] = reader.ReadBytes(0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.BaseStream.Position += 0xC0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
head.FsHeaders[i] = new NcaFsHeader(reader);
|
||||||
|
}
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NcaSectionEntry
|
||||||
|
{
|
||||||
|
public uint MediaStartOffset;
|
||||||
|
public uint MediaEndOffset;
|
||||||
|
|
||||||
|
public NcaSectionEntry(BinaryReader reader)
|
||||||
|
{
|
||||||
|
MediaStartOffset = reader.ReadUInt32();
|
||||||
|
MediaEndOffset = reader.ReadUInt32();
|
||||||
|
reader.BaseStream.Position += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NcaFsHeader
|
||||||
|
{
|
||||||
|
public byte Field0;
|
||||||
|
public byte Field1;
|
||||||
|
public SectionPartitionType PartitionType;
|
||||||
|
public SectionFsType FsType;
|
||||||
|
public SectionCryptType CryptType;
|
||||||
|
public SectionType Type;
|
||||||
|
|
||||||
|
public Pfs0Superblock Pfs0;
|
||||||
|
public RomfsSuperblock Romfs;
|
||||||
|
public BktrSuperblock Bktr;
|
||||||
|
|
||||||
|
public NcaFsHeader(BinaryReader reader)
|
||||||
|
{
|
||||||
|
Field0 = reader.ReadByte();
|
||||||
|
Field1 = reader.ReadByte();
|
||||||
|
PartitionType = (SectionPartitionType)reader.ReadByte();
|
||||||
|
FsType = (SectionFsType)reader.ReadByte();
|
||||||
|
CryptType = (SectionCryptType)reader.ReadByte();
|
||||||
|
reader.BaseStream.Position += 3;
|
||||||
|
|
||||||
|
if (PartitionType == SectionPartitionType.Pfs0 && FsType == SectionFsType.Pfs0)
|
||||||
|
{
|
||||||
|
Type = SectionType.Pfs0;
|
||||||
|
Pfs0 = new Pfs0Superblock(reader);
|
||||||
|
}
|
||||||
|
else if (PartitionType == SectionPartitionType.Romfs && FsType == SectionFsType.Romfs)
|
||||||
|
{
|
||||||
|
if (CryptType == SectionCryptType.BKTR)
|
||||||
|
{
|
||||||
|
Type = SectionType.Bktr;
|
||||||
|
Bktr = new BktrSuperblock(reader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type = SectionType.Romfs;
|
||||||
|
Romfs = new RomfsSuperblock(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Pfs0Superblock
|
||||||
|
{
|
||||||
|
public byte[] MasterHash; /* SHA-256 hash of the hash table. */
|
||||||
|
public uint BlockSize; /* In bytes. */
|
||||||
|
public uint Always2;
|
||||||
|
public ulong HashTableOffset; /* Normally zero. */
|
||||||
|
public ulong HashTableSize;
|
||||||
|
public ulong Pfs0Offset;
|
||||||
|
public ulong Pfs0Size;
|
||||||
|
|
||||||
|
public Pfs0Superblock(BinaryReader reader)
|
||||||
|
{
|
||||||
|
MasterHash = reader.ReadBytes(0x20);
|
||||||
|
BlockSize = reader.ReadUInt32();
|
||||||
|
Always2 = reader.ReadUInt32();
|
||||||
|
HashTableOffset = reader.ReadUInt64();
|
||||||
|
HashTableSize = reader.ReadUInt64();
|
||||||
|
Pfs0Offset = reader.ReadUInt64();
|
||||||
|
Pfs0Size = reader.ReadUInt64();
|
||||||
|
reader.BaseStream.Position += 0xF0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RomfsSuperblock
|
||||||
|
{
|
||||||
|
public IvfcHeader IvfcHeader;
|
||||||
|
|
||||||
|
public RomfsSuperblock(BinaryReader reader)
|
||||||
|
{
|
||||||
|
IvfcHeader = new IvfcHeader(reader);
|
||||||
|
reader.BaseStream.Position += 0x58;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BktrSuperblock
|
||||||
|
{
|
||||||
|
public IvfcHeader IvfcHeader;
|
||||||
|
public BktrHeader RelocationHeader;
|
||||||
|
public BktrHeader SubsectionHeader;
|
||||||
|
|
||||||
|
public BktrSuperblock(BinaryReader reader)
|
||||||
|
{
|
||||||
|
IvfcHeader = new IvfcHeader(reader);
|
||||||
|
reader.BaseStream.Position += 0x18;
|
||||||
|
RelocationHeader = new BktrHeader(reader);
|
||||||
|
SubsectionHeader = new BktrHeader(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IvfcHeader
|
||||||
|
{
|
||||||
|
public string Magic;
|
||||||
|
public uint Id;
|
||||||
|
public uint MasterHashSize;
|
||||||
|
public uint NumLevels;
|
||||||
|
public IvfcLevelHeader[] LevelHeaders = new IvfcLevelHeader[6];
|
||||||
|
public byte[] MasterHash;
|
||||||
|
|
||||||
|
|
||||||
|
public IvfcHeader(BinaryReader reader)
|
||||||
|
{
|
||||||
|
Magic = reader.ReadAscii(4);
|
||||||
|
Id = reader.ReadUInt32();
|
||||||
|
MasterHashSize = reader.ReadUInt32();
|
||||||
|
NumLevels = reader.ReadUInt32();
|
||||||
|
|
||||||
|
for (int i = 0; i < LevelHeaders.Length; i++)
|
||||||
|
{
|
||||||
|
LevelHeaders[i] = new IvfcLevelHeader(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.BaseStream.Position += 0x20;
|
||||||
|
MasterHash = reader.ReadBytes(0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IvfcLevelHeader
|
||||||
|
{
|
||||||
|
public ulong LogicalOffset;
|
||||||
|
public ulong HashDataSize;
|
||||||
|
public uint BlockSize;
|
||||||
|
public uint Reserved;
|
||||||
|
|
||||||
|
public IvfcLevelHeader(BinaryReader reader)
|
||||||
|
{
|
||||||
|
LogicalOffset = reader.ReadUInt64();
|
||||||
|
HashDataSize = reader.ReadUInt64();
|
||||||
|
BlockSize = reader.ReadUInt32();
|
||||||
|
Reserved = reader.ReadUInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BktrHeader
|
||||||
|
{
|
||||||
|
public ulong Offset;
|
||||||
|
public ulong Size;
|
||||||
|
public uint Magic;
|
||||||
|
public uint Field14;
|
||||||
|
public uint NumEntries;
|
||||||
|
public uint Field1C;
|
||||||
|
|
||||||
|
public BktrHeader(BinaryReader reader)
|
||||||
|
{
|
||||||
|
Offset = reader.ReadUInt64();
|
||||||
|
Size = reader.ReadUInt64();
|
||||||
|
Magic = reader.ReadUInt32();
|
||||||
|
Field14 = reader.ReadUInt32();
|
||||||
|
NumEntries = reader.ReadUInt32();
|
||||||
|
Field1C = reader.ReadUInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ContentType
|
||||||
|
{
|
||||||
|
Program,
|
||||||
|
Meta,
|
||||||
|
Control,
|
||||||
|
Manual,
|
||||||
|
Data,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionCryptType
|
||||||
|
{
|
||||||
|
None = 1,
|
||||||
|
XTS,
|
||||||
|
CTR,
|
||||||
|
BKTR
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionFsType
|
||||||
|
{
|
||||||
|
Pfs0 = 2,
|
||||||
|
Romfs
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionPartitionType
|
||||||
|
{
|
||||||
|
Romfs,
|
||||||
|
Pfs0
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SectionType
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
Pfs0,
|
||||||
|
Romfs,
|
||||||
|
Bktr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,17 @@ namespace libhac
|
||||||
Files = Directory.GetFiles(ContentsDir, "00", SearchOption.AllDirectories).Select(Path.GetDirectoryName).ToArray();
|
Files = Directory.GetFiles(ContentsDir, "00", SearchOption.AllDirectories).Select(Path.GetDirectoryName).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Nca> ReadAllNca()
|
public IEnumerable<Nca> ReadAllNca()
|
||||||
{
|
{
|
||||||
List<Nca> ncas = new List<Nca>();
|
|
||||||
foreach (var file in Files)
|
foreach (var file in Files)
|
||||||
{
|
{
|
||||||
var sdPath = "/" + Util.GetRelativePath(file, ContentsDir).Replace('\\', '/');
|
var sdPath = "/" + Util.GetRelativePath(file, ContentsDir).Replace('\\', '/');
|
||||||
var nax0 = new Nax0(Keyset, file, sdPath);
|
var nax0 = new Nax0(Keyset, file, sdPath);
|
||||||
var nca = new Nca(Keyset, nax0.Stream);
|
var nca = new Nca(Keyset, nax0.Stream);
|
||||||
ncas.Add(nca);
|
|
||||||
nca.Name = Path.GetFileName(file);
|
nca.Name = Path.GetFileName(file);
|
||||||
|
yield return nca;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ncas;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ namespace libhac
|
||||||
{
|
{
|
||||||
public static class Util
|
public static class Util
|
||||||
{
|
{
|
||||||
|
private const int MediaSize = 0x200;
|
||||||
|
|
||||||
public static T CreateJaggedArray<T>(params int[] lengths)
|
public static T CreateJaggedArray<T>(params int[] lengths)
|
||||||
{
|
{
|
||||||
return (T)InitializeJaggedArray(typeof(T).GetElementType(), 0, lengths);
|
return (T)InitializeJaggedArray(typeof(T).GetElementType(), 0, lengths);
|
||||||
|
@ -49,7 +51,7 @@ namespace libhac
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; i++)
|
for (int i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
if (i != 0)
|
if (array[i] != 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -159,5 +161,10 @@ namespace libhac
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static ulong MediaToReal(ulong media)
|
||||||
|
{
|
||||||
|
return MediaSize * media;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue