mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Remove deprecated classes
This commit is contained in:
parent
0a8fb8a5c0
commit
2793648d37
6 changed files with 0 additions and 864 deletions
|
@ -10,32 +10,6 @@ namespace LibHac.FsSystem
|
||||||
{
|
{
|
||||||
public static class StorageExtensions
|
public static class StorageExtensions
|
||||||
{
|
{
|
||||||
[Obsolete("The standard Span-based IStorage methods should be used instead.")]
|
|
||||||
public static Result Read(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset)
|
|
||||||
{
|
|
||||||
ValidateStorageParameters(buffer, offset, count, bufferOffset);
|
|
||||||
return storage.Read(offset, buffer.AsSpan(bufferOffset, count));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Obsolete("The standard Span-based IStorage methods should be used instead.")]
|
|
||||||
public static Result Write(this IStorage storage, long offset, byte[] buffer, int count, int bufferOffset)
|
|
||||||
{
|
|
||||||
ValidateStorageParameters(buffer, offset, count, bufferOffset);
|
|
||||||
return storage.Write(offset, buffer.AsSpan(bufferOffset, count));
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: remove this method when the above Read and Write methods are removed
|
|
||||||
// (Hopefully they're still above, or else someone didn't listen)
|
|
||||||
// ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
|
|
||||||
private static void ValidateStorageParameters(byte[] buffer, long offset, int count, int bufferOffset)
|
|
||||||
// ReSharper restore ParameterOnlyUsedForPreconditionCheck.Local
|
|
||||||
{
|
|
||||||
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
|
|
||||||
if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
|
|
||||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Argument must be non-negative.");
|
|
||||||
if (bufferOffset < 0) throw new ArgumentOutOfRangeException(nameof(bufferOffset), "Argument must be non-negative.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IStorage Slice(this IStorage storage, long start)
|
public static IStorage Slice(this IStorage storage, long start)
|
||||||
{
|
{
|
||||||
storage.GetSize(out long length).ThrowIfFailure();
|
storage.GetSize(out long length).ThrowIfFailure();
|
||||||
|
|
|
@ -1,213 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using LibHac.Common;
|
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.FsSystem;
|
|
||||||
using LibHac.Kernel;
|
|
||||||
|
|
||||||
namespace LibHac
|
|
||||||
{
|
|
||||||
[Obsolete("This class has been deprecated. LibHac.Loader.KipReader should be used instead.")]
|
|
||||||
public class Kip
|
|
||||||
{
|
|
||||||
private const int HeaderSize = 0x100;
|
|
||||||
|
|
||||||
public KipHeader Header { get; }
|
|
||||||
|
|
||||||
public int[] SectionOffsets { get; } = new int[6];
|
|
||||||
public int Size { get; }
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Kip(IStorage storage)
|
|
||||||
{
|
|
||||||
Header = new KipHeader(storage);
|
|
||||||
|
|
||||||
Size = HeaderSize;
|
|
||||||
|
|
||||||
for (int index = 0; index < Header.Sections.Length; index++)
|
|
||||||
{
|
|
||||||
int sectionSize = Header.Sections[index].CompressedSize;
|
|
||||||
SectionOffsets[index] = Size;
|
|
||||||
Size += sectionSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage = storage.Slice(0, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenSection(int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index > 5)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index), "Section index must be between 0-5");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Storage.Slice(SectionOffsets[index], Header.Sections[index].CompressedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] DecompressSection(int index)
|
|
||||||
{
|
|
||||||
IStorage compStorage = OpenSection(index);
|
|
||||||
compStorage.GetSize(out long compressedSize).ThrowIfFailure();
|
|
||||||
|
|
||||||
byte[] compressed = new byte[compressedSize];
|
|
||||||
compStorage.Read(0, compressed).ThrowIfFailure();
|
|
||||||
|
|
||||||
return DecompressBlz(compressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenRawFile() => Storage;
|
|
||||||
|
|
||||||
private static byte[] DecompressBlz(byte[] compressed)
|
|
||||||
{
|
|
||||||
int additionalSize = BitConverter.ToInt32(compressed, compressed.Length - 4);
|
|
||||||
int headerSize = BitConverter.ToInt32(compressed, compressed.Length - 8);
|
|
||||||
int totalCompSize = BitConverter.ToInt32(compressed, compressed.Length - 12);
|
|
||||||
|
|
||||||
byte[] decompressed = new byte[totalCompSize + additionalSize];
|
|
||||||
|
|
||||||
int inOffset = totalCompSize - headerSize;
|
|
||||||
int outOffset = totalCompSize + additionalSize;
|
|
||||||
|
|
||||||
while (outOffset > 0)
|
|
||||||
{
|
|
||||||
byte control = compressed[--inOffset];
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if ((control & 0x80) != 0)
|
|
||||||
{
|
|
||||||
if (inOffset < 2) throw new InvalidDataException("KIP1 decompression out of bounds!");
|
|
||||||
|
|
||||||
inOffset -= 2;
|
|
||||||
|
|
||||||
ushort segmentValue = BitConverter.ToUInt16(compressed, inOffset);
|
|
||||||
int segmentSize = ((segmentValue >> 12) & 0xF) + 3;
|
|
||||||
int segmentOffset = (segmentValue & 0x0FFF) + 3;
|
|
||||||
|
|
||||||
if (outOffset < segmentSize)
|
|
||||||
{
|
|
||||||
// Kernel restricts segment copy to stay in bounds.
|
|
||||||
segmentSize = outOffset;
|
|
||||||
}
|
|
||||||
outOffset -= segmentSize;
|
|
||||||
|
|
||||||
for (int j = 0; j < segmentSize; j++)
|
|
||||||
{
|
|
||||||
decompressed[outOffset + j] = decompressed[outOffset + j + segmentOffset];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Copy directly.
|
|
||||||
if (inOffset < 1) throw new InvalidDataException("KIP1 decompression out of bounds!");
|
|
||||||
|
|
||||||
decompressed[--outOffset] = compressed[--inOffset];
|
|
||||||
}
|
|
||||||
control <<= 1;
|
|
||||||
if (outOffset == 0) return decompressed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return decompressed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class KipHeader
|
|
||||||
{
|
|
||||||
public string Magic { get; }
|
|
||||||
public string Name { get; }
|
|
||||||
public ulong TitleId { get; }
|
|
||||||
public int ProcessCategory { get; }
|
|
||||||
public byte MainThreadPriority { get; }
|
|
||||||
public byte DefaultCore { get; }
|
|
||||||
public byte Field1E { get; }
|
|
||||||
public byte Flags { get; }
|
|
||||||
public KipSectionHeader[] Sections { get; } = new KipSectionHeader[6];
|
|
||||||
public byte[] Capabilities { get; }
|
|
||||||
|
|
||||||
public KipHeader(IStorage storage)
|
|
||||||
{
|
|
||||||
var reader = new BinaryReader(storage.AsStream());
|
|
||||||
|
|
||||||
Magic = reader.ReadAscii(4);
|
|
||||||
if (Magic != "KIP1")
|
|
||||||
{
|
|
||||||
throw new InvalidDataException("Invalid KIP file!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Name = reader.ReadAsciiZ(0xC);
|
|
||||||
|
|
||||||
reader.BaseStream.Position = 0x10;
|
|
||||||
TitleId = reader.ReadUInt64();
|
|
||||||
ProcessCategory = reader.ReadInt32();
|
|
||||||
MainThreadPriority = reader.ReadByte();
|
|
||||||
DefaultCore = reader.ReadByte();
|
|
||||||
Field1E = reader.ReadByte();
|
|
||||||
Flags = reader.ReadByte();
|
|
||||||
|
|
||||||
for (int i = 0; i < Sections.Length; i++)
|
|
||||||
{
|
|
||||||
Sections[i] = new KipSectionHeader(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
Capabilities = reader.ReadBytes(0x20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class KipSectionHeader
|
|
||||||
{
|
|
||||||
public int OutOffset { get; }
|
|
||||||
public int DecompressedSize { get; }
|
|
||||||
public int CompressedSize { get; }
|
|
||||||
public int Attribute { get; }
|
|
||||||
|
|
||||||
public KipSectionHeader(BinaryReader reader)
|
|
||||||
{
|
|
||||||
OutOffset = reader.ReadInt32();
|
|
||||||
DecompressedSize = reader.ReadInt32();
|
|
||||||
CompressedSize = reader.ReadInt32();
|
|
||||||
Attribute = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Ini1
|
|
||||||
{
|
|
||||||
public KipReader[] Kips { get; }
|
|
||||||
|
|
||||||
public string Magic { get; }
|
|
||||||
public int Size { get; }
|
|
||||||
public int KipCount { get; }
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Ini1(IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
|
|
||||||
var reader = new BinaryReader(Storage.AsStream());
|
|
||||||
|
|
||||||
Magic = reader.ReadAscii(4);
|
|
||||||
if (Magic != "INI1")
|
|
||||||
{
|
|
||||||
throw new InvalidDataException("Invalid INI1 file!");
|
|
||||||
}
|
|
||||||
|
|
||||||
Size = reader.ReadInt32();
|
|
||||||
KipCount = reader.ReadInt32();
|
|
||||||
|
|
||||||
Kips = new KipReader[KipCount];
|
|
||||||
int offset = 0x10;
|
|
||||||
|
|
||||||
for (int i = 0; i < KipCount; i++)
|
|
||||||
{
|
|
||||||
using var sharedStorage = new SharedRef<IStorage>(Storage.Slice(offset));
|
|
||||||
|
|
||||||
Kips[i] = new KipReader();
|
|
||||||
Kips[i].Initialize(in sharedStorage).ThrowIfFailure();
|
|
||||||
|
|
||||||
offset += Kips[i].GetFileSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,190 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace LibHac
|
|
||||||
{
|
|
||||||
[Obsolete("This class has been deprecated. LibHac.Ns.ApplicationControlProperty should be used instead.")]
|
|
||||||
public class Nacp
|
|
||||||
{
|
|
||||||
public NacpDescription[] Descriptions { get; } = new NacpDescription[0x10];
|
|
||||||
public string Isbn { get; }
|
|
||||||
public byte StartupUserAccount { get; }
|
|
||||||
public byte UserAccountSwitchLock { get; }
|
|
||||||
public byte AocRegistrationType { get; }
|
|
||||||
public int AttributeFlag { get; }
|
|
||||||
public uint SupportedLanguageFlag { get; }
|
|
||||||
public uint ParentalControlFlag { get; }
|
|
||||||
public byte Screenshot { get; }
|
|
||||||
public byte VideoCapture { get; }
|
|
||||||
public byte DataLossConfirmation { get; }
|
|
||||||
public byte PlayLogPolicy { get; }
|
|
||||||
public ulong PresenceGroupId { get; }
|
|
||||||
public sbyte[] RatingAge { get; } = new sbyte[32];
|
|
||||||
public string DisplayVersion { get; }
|
|
||||||
public ulong AddOnContentBaseId { get; }
|
|
||||||
public ulong SaveDataOwnerId { get; }
|
|
||||||
public long UserAccountSaveDataSize { get; }
|
|
||||||
public long UserAccountSaveDataJournalSize { get; }
|
|
||||||
public long DeviceSaveDataSize { get; }
|
|
||||||
public long DeviceSaveDataJournalSize { get; }
|
|
||||||
public long BcatDeliveryCacheStorageSize { get; }
|
|
||||||
public string ApplicationErrorCodeCategory { get; }
|
|
||||||
public ulong[] LocalCommunicationId { get; } = new ulong[8];
|
|
||||||
public byte LogoType { get; }
|
|
||||||
public byte LogoHandling { get; }
|
|
||||||
public byte RuntimeAddOnContentInstall { get; }
|
|
||||||
public byte[] Reserved00 { get; }
|
|
||||||
public byte CrashReport { get; }
|
|
||||||
public byte Hdcp { get; }
|
|
||||||
public ulong SeedForPseudoDeviceId { get; }
|
|
||||||
public string BcatPassphrase { get; }
|
|
||||||
public byte Reserved01 { get; }
|
|
||||||
public byte[] Reserved02 { get; }
|
|
||||||
public long UserAccountSaveDataSizeMax { get; }
|
|
||||||
public long UserAccountSaveDataJournalSizeMax { get; }
|
|
||||||
public long DeviceSaveDataSizeMax { get; }
|
|
||||||
public long DeviceSaveDataJournalSizeMax { get; }
|
|
||||||
public long TemporaryStorageSize { get; }
|
|
||||||
public long CacheStorageSize { get; }
|
|
||||||
public long CacheStorageJournalSize { get; }
|
|
||||||
public long CacheStorageDataAndJournalSizeMax { get; }
|
|
||||||
public short CacheStorageIndex { get; }
|
|
||||||
public byte[] Reserved03 { get; }
|
|
||||||
public List<ulong> PlayLogQueryableApplicationId { get; } = new List<ulong>();
|
|
||||||
public byte PlayLogQueryCapability { get; }
|
|
||||||
public byte RepairFlag { get; }
|
|
||||||
public byte ProgramIndex { get; }
|
|
||||||
|
|
||||||
public long TotalSaveDataSize { get; }
|
|
||||||
public long UserTotalSaveDataSize { get; }
|
|
||||||
public long DeviceTotalSaveDataSize { get; }
|
|
||||||
|
|
||||||
public Nacp() { }
|
|
||||||
|
|
||||||
public Nacp(Stream file)
|
|
||||||
{
|
|
||||||
long start = file.Position;
|
|
||||||
|
|
||||||
var reader = new BinaryReader(file);
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
Descriptions[i] = new NacpDescription(reader, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
Isbn = reader.ReadUtf8Z(37);
|
|
||||||
reader.BaseStream.Position = start + 0x3025;
|
|
||||||
StartupUserAccount = reader.ReadByte();
|
|
||||||
UserAccountSwitchLock = reader.ReadByte();
|
|
||||||
AocRegistrationType = reader.ReadByte();
|
|
||||||
AttributeFlag = reader.ReadInt32();
|
|
||||||
SupportedLanguageFlag = reader.ReadUInt32();
|
|
||||||
ParentalControlFlag = reader.ReadUInt32();
|
|
||||||
Screenshot = reader.ReadByte();
|
|
||||||
VideoCapture = reader.ReadByte();
|
|
||||||
DataLossConfirmation = reader.ReadByte();
|
|
||||||
PlayLogPolicy = reader.ReadByte();
|
|
||||||
PresenceGroupId = reader.ReadUInt64();
|
|
||||||
|
|
||||||
for (int i = 0; i < RatingAge.Length; i++)
|
|
||||||
{
|
|
||||||
RatingAge[i] = reader.ReadSByte();
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayVersion = reader.ReadUtf8Z(16);
|
|
||||||
reader.BaseStream.Position = start + 0x3070;
|
|
||||||
AddOnContentBaseId = reader.ReadUInt64();
|
|
||||||
SaveDataOwnerId = reader.ReadUInt64();
|
|
||||||
UserAccountSaveDataSize = reader.ReadInt64();
|
|
||||||
UserAccountSaveDataJournalSize = reader.ReadInt64();
|
|
||||||
DeviceSaveDataSize = reader.ReadInt64();
|
|
||||||
DeviceSaveDataJournalSize = reader.ReadInt64();
|
|
||||||
BcatDeliveryCacheStorageSize = reader.ReadInt64();
|
|
||||||
ApplicationErrorCodeCategory = reader.ReadUtf8Z(8);
|
|
||||||
reader.BaseStream.Position = start + 0x30B0;
|
|
||||||
|
|
||||||
for (int i = 0; i < LocalCommunicationId.Length; i++)
|
|
||||||
{
|
|
||||||
LocalCommunicationId[i] = reader.ReadUInt64();
|
|
||||||
}
|
|
||||||
|
|
||||||
LogoType = reader.ReadByte();
|
|
||||||
LogoHandling = reader.ReadByte();
|
|
||||||
RuntimeAddOnContentInstall = reader.ReadByte();
|
|
||||||
Reserved00 = reader.ReadBytes(3);
|
|
||||||
CrashReport = reader.ReadByte();
|
|
||||||
Hdcp = reader.ReadByte();
|
|
||||||
SeedForPseudoDeviceId = reader.ReadUInt64();
|
|
||||||
BcatPassphrase = reader.ReadUtf8Z(65);
|
|
||||||
|
|
||||||
reader.BaseStream.Position = start + 0x3141;
|
|
||||||
Reserved01 = reader.ReadByte();
|
|
||||||
Reserved02 = reader.ReadBytes(6);
|
|
||||||
|
|
||||||
UserAccountSaveDataSizeMax = reader.ReadInt64();
|
|
||||||
UserAccountSaveDataJournalSizeMax = reader.ReadInt64();
|
|
||||||
DeviceSaveDataSizeMax = reader.ReadInt64();
|
|
||||||
DeviceSaveDataJournalSizeMax = reader.ReadInt64();
|
|
||||||
TemporaryStorageSize = reader.ReadInt64();
|
|
||||||
CacheStorageSize = reader.ReadInt64();
|
|
||||||
CacheStorageJournalSize = reader.ReadInt64();
|
|
||||||
CacheStorageDataAndJournalSizeMax = reader.ReadInt64();
|
|
||||||
CacheStorageIndex = reader.ReadInt16();
|
|
||||||
Reserved03 = reader.ReadBytes(6);
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
{
|
|
||||||
ulong value = reader.ReadUInt64();
|
|
||||||
if (value != 0) PlayLogQueryableApplicationId.Add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayLogQueryCapability = reader.ReadByte();
|
|
||||||
RepairFlag = reader.ReadByte();
|
|
||||||
ProgramIndex = reader.ReadByte();
|
|
||||||
|
|
||||||
UserTotalSaveDataSize = UserAccountSaveDataSize + UserAccountSaveDataJournalSize;
|
|
||||||
DeviceTotalSaveDataSize = DeviceSaveDataSize + DeviceSaveDataJournalSize;
|
|
||||||
TotalSaveDataSize = UserTotalSaveDataSize + DeviceTotalSaveDataSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NacpDescription
|
|
||||||
{
|
|
||||||
public string Title { get; }
|
|
||||||
public string Developer { get; }
|
|
||||||
|
|
||||||
public TitleLanguage Language;
|
|
||||||
|
|
||||||
public NacpDescription() { }
|
|
||||||
|
|
||||||
public NacpDescription(BinaryReader reader, int index)
|
|
||||||
{
|
|
||||||
Language = (TitleLanguage)index;
|
|
||||||
long start = reader.BaseStream.Position;
|
|
||||||
Title = reader.ReadUtf8Z();
|
|
||||||
reader.BaseStream.Position = start + 0x200;
|
|
||||||
Developer = reader.ReadUtf8Z();
|
|
||||||
reader.BaseStream.Position = start + 0x300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TitleLanguage
|
|
||||||
{
|
|
||||||
AmericanEnglish = 0,
|
|
||||||
BritishEnglish,
|
|
||||||
Japanese,
|
|
||||||
French,
|
|
||||||
German,
|
|
||||||
LatinAmericanSpanish,
|
|
||||||
Spanish,
|
|
||||||
Italian,
|
|
||||||
Dutch,
|
|
||||||
CanadianFrench,
|
|
||||||
Portuguese,
|
|
||||||
Russian,
|
|
||||||
Korean,
|
|
||||||
Taiwanese,
|
|
||||||
Chinese
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.IO;
|
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.FsSystem;
|
|
||||||
|
|
||||||
namespace LibHac
|
|
||||||
{
|
|
||||||
[Obsolete("This class has been deprecated. LibHac.Loader.NsoReader should be used instead.")]
|
|
||||||
public class Nso
|
|
||||||
{
|
|
||||||
public NsoSection[] Sections { get; }
|
|
||||||
public RodataRelativeExtent[] RodataRelativeExtents { get; }
|
|
||||||
public uint BssSize { get; }
|
|
||||||
public byte[] BuildId { get; } = new byte[0x20];
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Nso(IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
var reader = new BinaryReader(Storage.AsStream());
|
|
||||||
if (reader.ReadAscii(4) != "NSO0")
|
|
||||||
throw new InvalidDataException("NSO magic is incorrect!");
|
|
||||||
reader.ReadUInt32(); // Version
|
|
||||||
reader.ReadUInt32(); // Reserved/Unused
|
|
||||||
var flags = new BitArray(new[] { (int)reader.ReadUInt32() });
|
|
||||||
var textSection = new NsoSection(Storage);
|
|
||||||
var rodataSection = new NsoSection(Storage);
|
|
||||||
var dataSection = new NsoSection(Storage);
|
|
||||||
textSection.IsCompressed = flags[0];
|
|
||||||
rodataSection.IsCompressed = flags[1];
|
|
||||||
dataSection.IsCompressed = flags[2];
|
|
||||||
textSection.CheckHash = flags[3];
|
|
||||||
rodataSection.CheckHash = flags[4];
|
|
||||||
dataSection.CheckHash = flags[5];
|
|
||||||
|
|
||||||
textSection.ReadSegmentHeader(reader);
|
|
||||||
reader.ReadUInt32(); // Module offset (TODO)
|
|
||||||
rodataSection.ReadSegmentHeader(reader);
|
|
||||||
reader.ReadUInt32(); // Module file size
|
|
||||||
dataSection.ReadSegmentHeader(reader);
|
|
||||||
BssSize = reader.ReadUInt32();
|
|
||||||
reader.Read(BuildId, 0, 0x20);
|
|
||||||
textSection.CompressedSize = reader.ReadUInt32();
|
|
||||||
rodataSection.CompressedSize = reader.ReadUInt32();
|
|
||||||
dataSection.CompressedSize = reader.ReadUInt32();
|
|
||||||
reader.ReadBytes(0x1C); // Padding
|
|
||||||
RodataRelativeExtents = new[]
|
|
||||||
{
|
|
||||||
new RodataRelativeExtent(reader), new RodataRelativeExtent(reader), new RodataRelativeExtent(reader)
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.Read(textSection.Hash, 0, 0x20);
|
|
||||||
reader.Read(rodataSection.Hash, 0, 0x20);
|
|
||||||
reader.Read(dataSection.Hash, 0, 0x20);
|
|
||||||
|
|
||||||
Sections = new[] { textSection, rodataSection, dataSection };
|
|
||||||
reader.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NsoSection
|
|
||||||
{
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public bool IsCompressed { get; set; }
|
|
||||||
public bool CheckHash { get; set; }
|
|
||||||
public uint FileOffset { get; set; }
|
|
||||||
public uint MemoryOffset { get; set; }
|
|
||||||
public uint DecompressedSize { get; set; }
|
|
||||||
public uint CompressedSize { get; set; }
|
|
||||||
|
|
||||||
public byte[] Hash { get; } = new byte[0x20];
|
|
||||||
|
|
||||||
public NsoSection(IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenSection()
|
|
||||||
{
|
|
||||||
return Storage.Slice(FileOffset, CompressedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] DecompressSection()
|
|
||||||
{
|
|
||||||
byte[] compressed = new byte[CompressedSize];
|
|
||||||
OpenSection().Read(0, compressed).ThrowIfFailure();
|
|
||||||
|
|
||||||
if (IsCompressed)
|
|
||||||
return Lz4.Decompress(compressed, (int)DecompressedSize);
|
|
||||||
else
|
|
||||||
return compressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ReadSegmentHeader(BinaryReader reader)
|
|
||||||
{
|
|
||||||
FileOffset = reader.ReadUInt32();
|
|
||||||
MemoryOffset = reader.ReadUInt32();
|
|
||||||
DecompressedSize = reader.ReadUInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class RodataRelativeExtent
|
|
||||||
{
|
|
||||||
public uint RegionRodataOffset { get; }
|
|
||||||
public uint RegionSize { get; }
|
|
||||||
|
|
||||||
public RodataRelativeExtent(BinaryReader reader)
|
|
||||||
{
|
|
||||||
RegionRodataOffset = reader.ReadUInt32();
|
|
||||||
RegionSize = reader.ReadUInt32();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using LibHac.Common.Keys;
|
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.FsSystem;
|
|
||||||
|
|
||||||
namespace LibHac
|
|
||||||
{
|
|
||||||
[Obsolete("This class has been deprecated. LibHac.Boot.Package1 should be used instead.")]
|
|
||||||
public class Package1
|
|
||||||
{
|
|
||||||
private const uint Pk11Magic = 0x31314B50; // PK11
|
|
||||||
|
|
||||||
public byte[] BuildHash { get; }
|
|
||||||
public string BuildDate { get; }
|
|
||||||
public int Field1E { get; }
|
|
||||||
public int Pk11Size { get; }
|
|
||||||
public byte[] Counter { get; }
|
|
||||||
public int KeyRevision { get; }
|
|
||||||
public Pk11 Pk11 { get; }
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Package1(KeySet keySet, IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
var reader = new BinaryReader(storage.AsStream());
|
|
||||||
|
|
||||||
BuildHash = reader.ReadBytes(0x10);
|
|
||||||
BuildDate = reader.ReadAscii(0xE);
|
|
||||||
Field1E = reader.ReadUInt16();
|
|
||||||
|
|
||||||
reader.BaseStream.Position = 0x3FE0;
|
|
||||||
Pk11Size = reader.ReadInt32();
|
|
||||||
|
|
||||||
reader.BaseStream.Position += 0xC;
|
|
||||||
Counter = reader.ReadBytes(0x10);
|
|
||||||
|
|
||||||
// Try decrypting the PK11 blob with all known package1 keys
|
|
||||||
IStorage encStorage = Storage.Slice(0x4000, Pk11Size);
|
|
||||||
byte[] decBuffer = new byte[0x10];
|
|
||||||
|
|
||||||
for (int i = 0; i < 0x20; i++)
|
|
||||||
{
|
|
||||||
var dec = new Aes128CtrStorage(encStorage, keySet.Package1Keys[i].DataRo.ToArray(), Counter, true);
|
|
||||||
dec.Read(0, decBuffer).ThrowIfFailure();
|
|
||||||
|
|
||||||
if (BitConverter.ToUInt32(decBuffer, 0) == Pk11Magic)
|
|
||||||
{
|
|
||||||
KeyRevision = i;
|
|
||||||
|
|
||||||
Pk11 = new Pk11(new CachedStorage(dec, 4, true));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidDataException("Failed to decrypt PK11! Is the correct key present?");
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenDecryptedPackage()
|
|
||||||
{
|
|
||||||
IStorage[] storages = { OpenPackage1Ldr(), Pk11.OpenDecryptedPk11() };
|
|
||||||
|
|
||||||
return new ConcatenationStorage(storages, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenPackage1Ldr() => Storage.Slice(0, 0x4000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Pk11
|
|
||||||
{
|
|
||||||
private const int DataOffset = 0x20;
|
|
||||||
|
|
||||||
public string Magic { get; }
|
|
||||||
public int[] SectionSizes { get; } = new int[3];
|
|
||||||
public int[] SectionOffsets { get; } = new int[3];
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Pk11(IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
var reader = new BinaryReader(storage.AsStream());
|
|
||||||
|
|
||||||
Magic = reader.ReadAscii(4);
|
|
||||||
SectionSizes[0] = reader.ReadInt32();
|
|
||||||
SectionOffsets[0] = reader.ReadInt32();
|
|
||||||
|
|
||||||
reader.BaseStream.Position += 4;
|
|
||||||
SectionSizes[1] = reader.ReadInt32();
|
|
||||||
SectionOffsets[1] = reader.ReadInt32();
|
|
||||||
SectionSizes[2] = reader.ReadInt32();
|
|
||||||
SectionOffsets[2] = reader.ReadInt32();
|
|
||||||
|
|
||||||
SectionOffsets[0] = DataOffset;
|
|
||||||
SectionOffsets[1] = SectionOffsets[0] + SectionSizes[0];
|
|
||||||
SectionOffsets[2] = SectionOffsets[1] + SectionSizes[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenSection(int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index > 2)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(index), "Section index must be one of: 0, 1, 2");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Storage.Slice(SectionOffsets[index], SectionSizes[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenDecryptedPk11() => Storage;
|
|
||||||
|
|
||||||
public IStorage OpenWarmboot() => OpenSection(GetWarmbootSection());
|
|
||||||
public IStorage OpenNxBootloader() => OpenSection(GetNxBootloaderSection());
|
|
||||||
public IStorage OpenSecureMonitor() => OpenSection(GetSecureMonitorSection());
|
|
||||||
|
|
||||||
// todo: Handle the old layout from before 2.0.0
|
|
||||||
private int GetWarmbootSection() => 0;
|
|
||||||
private int GetNxBootloaderSection() => 1;
|
|
||||||
private int GetSecureMonitorSection() => 2;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,197 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using LibHac.Common.Keys;
|
|
||||||
using LibHac.Fs;
|
|
||||||
using LibHac.FsSystem;
|
|
||||||
|
|
||||||
namespace LibHac
|
|
||||||
{
|
|
||||||
[Obsolete("This class has been deprecated. LibHac.Boot.Package2StorageReader should be used instead.")]
|
|
||||||
public class Package2
|
|
||||||
{
|
|
||||||
private const uint Pk21Magic = 0x31324B50; // PK21
|
|
||||||
|
|
||||||
public Package2Header Header { get; }
|
|
||||||
public int KeyRevision { get; }
|
|
||||||
public byte[] Key { get; }
|
|
||||||
public int PackageSize { get; }
|
|
||||||
public int HeaderVersion { get; }
|
|
||||||
|
|
||||||
private IStorage Storage { get; }
|
|
||||||
|
|
||||||
public Package2(KeySet keySet, IStorage storage)
|
|
||||||
{
|
|
||||||
Storage = storage;
|
|
||||||
IStorage headerStorage = Storage.Slice(0, 0x200);
|
|
||||||
|
|
||||||
KeyRevision = FindKeyGeneration(keySet, headerStorage);
|
|
||||||
Key = keySet.Package2Keys[KeyRevision].DataRo.ToArray();
|
|
||||||
|
|
||||||
Header = new Package2Header(headerStorage, keySet, KeyRevision);
|
|
||||||
|
|
||||||
PackageSize = BitConverter.ToInt32(Header.Counter, 0) ^ BitConverter.ToInt32(Header.Counter, 8) ^
|
|
||||||
BitConverter.ToInt32(Header.Counter, 12);
|
|
||||||
|
|
||||||
HeaderVersion = Header.Counter[4] ^ Header.Counter[6] ^ Header.Counter[7];
|
|
||||||
|
|
||||||
if (PackageSize != 0x200 + Header.SectionSizes[0] + Header.SectionSizes[1] + Header.SectionSizes[2])
|
|
||||||
{
|
|
||||||
throw new InvalidDataException("Package2 Header is corrupt!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenDecryptedPackage()
|
|
||||||
{
|
|
||||||
if (Header.SectionSizes[1] == 0)
|
|
||||||
{
|
|
||||||
IStorage[] storages = { OpenHeaderPart1(), OpenHeaderPart2(), OpenKernel() };
|
|
||||||
|
|
||||||
return new ConcatenationStorage(storages, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IStorage[] storages = { OpenHeaderPart1(), OpenHeaderPart2(), OpenKernel(), OpenIni1() };
|
|
||||||
|
|
||||||
return new ConcatenationStorage(storages, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IStorage OpenHeaderPart1()
|
|
||||||
{
|
|
||||||
return Storage.Slice(0, 0x110);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IStorage OpenHeaderPart2()
|
|
||||||
{
|
|
||||||
IStorage encStorage = Storage.Slice(0x110, 0xF0);
|
|
||||||
|
|
||||||
// The counter starts counting at 0x100, but the block at 0x100 isn't encrypted.
|
|
||||||
// Increase the counter by one and start decrypting at 0x110.
|
|
||||||
byte[] counter = new byte[0x10];
|
|
||||||
Array.Copy(Header.Counter, counter, 0x10);
|
|
||||||
Utilities.IncrementByteArray(counter);
|
|
||||||
|
|
||||||
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, counter, true), 0x4000, 4, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenKernel()
|
|
||||||
{
|
|
||||||
int offset = 0x200;
|
|
||||||
IStorage encStorage = Storage.Slice(offset, Header.SectionSizes[0]);
|
|
||||||
|
|
||||||
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, Header.SectionCounters[0], true), 0x4000, 4, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorage OpenIni1()
|
|
||||||
{
|
|
||||||
// Handle 8.0.0+ INI1 embedded within Kernel
|
|
||||||
// Todo: Figure out how to better deal with this once newer versions are released
|
|
||||||
if (Header.SectionSizes[1] == 0)
|
|
||||||
{
|
|
||||||
IStorage kernelStorage = OpenKernel();
|
|
||||||
|
|
||||||
var reader = new BinaryReader(kernelStorage.AsStream());
|
|
||||||
reader.BaseStream.Position = 0x168;
|
|
||||||
|
|
||||||
int embeddedIniOffset = (int)reader.ReadInt64();
|
|
||||||
|
|
||||||
reader.BaseStream.Position = embeddedIniOffset + 4;
|
|
||||||
int size = reader.ReadInt32();
|
|
||||||
|
|
||||||
return kernelStorage.Slice(embeddedIniOffset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int offset = 0x200 + Header.SectionSizes[0];
|
|
||||||
IStorage encStorage = Storage.Slice(offset, Header.SectionSizes[1]);
|
|
||||||
|
|
||||||
return new CachedStorage(new Aes128CtrStorage(encStorage, Key, Header.SectionCounters[1], true), 0x4000, 4, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int FindKeyGeneration(KeySet keySet, IStorage storage)
|
|
||||||
{
|
|
||||||
byte[] counter = new byte[0x10];
|
|
||||||
byte[] decBuffer = new byte[0x10];
|
|
||||||
|
|
||||||
storage.Read(0x100, counter).ThrowIfFailure();
|
|
||||||
|
|
||||||
for (int i = 0; i < 0x20; i++)
|
|
||||||
{
|
|
||||||
var dec = new Aes128CtrStorage(storage.Slice(0x100), keySet.Package2Keys[i].DataRo.ToArray(), counter,
|
|
||||||
false);
|
|
||||||
dec.Read(0x50, decBuffer).ThrowIfFailure();
|
|
||||||
|
|
||||||
if (BitConverter.ToUInt32(decBuffer, 0) == Pk21Magic)
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidDataException("Failed to decrypt package2! Is the correct key present?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Package2Header
|
|
||||||
{
|
|
||||||
public byte[] Signature { get; }
|
|
||||||
public byte[] Counter { get; }
|
|
||||||
|
|
||||||
public byte[][] SectionCounters { get; } = new byte[4][];
|
|
||||||
public int[] SectionSizes { get; } = new int[4];
|
|
||||||
public int[] SectionOffsets { get; } = new int[4];
|
|
||||||
public byte[][] SectionHashes { get; } = new byte[4][];
|
|
||||||
|
|
||||||
public string Magic { get; }
|
|
||||||
public int BaseOffset { get; }
|
|
||||||
public int VersionMax { get; }
|
|
||||||
public int VersionMin { get; }
|
|
||||||
|
|
||||||
public Validity SignatureValidity { get; }
|
|
||||||
|
|
||||||
public Package2Header(IStorage storage, KeySet keySet, int keyGeneration)
|
|
||||||
{
|
|
||||||
var reader = new BinaryReader(storage.AsStream());
|
|
||||||
byte[] key = keySet.Package2Keys[keyGeneration].DataRo.ToArray();
|
|
||||||
|
|
||||||
Signature = reader.ReadBytes(0x100);
|
|
||||||
byte[] sigData = reader.ReadBytes(0x100);
|
|
||||||
SignatureValidity = CryptoOld.Rsa2048PssVerify(sigData, Signature, keySet.Package2SigningKeyParams.Modulus);
|
|
||||||
|
|
||||||
reader.BaseStream.Position -= 0x100;
|
|
||||||
Counter = reader.ReadBytes(0x10);
|
|
||||||
|
|
||||||
Stream headerStream = new CachedStorage(new Aes128CtrStorage(storage.Slice(0x100), key, Counter, true), 0x4000, 4, true).AsStream();
|
|
||||||
|
|
||||||
headerStream.Position = 0x10;
|
|
||||||
reader = new BinaryReader(headerStream);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
SectionCounters[i] = reader.ReadBytes(0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
Magic = reader.ReadAscii(4);
|
|
||||||
BaseOffset = reader.ReadInt32();
|
|
||||||
|
|
||||||
reader.BaseStream.Position += 4;
|
|
||||||
VersionMax = reader.ReadByte();
|
|
||||||
VersionMin = reader.ReadByte();
|
|
||||||
|
|
||||||
reader.BaseStream.Position += 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
SectionSizes[i] = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
SectionOffsets[i] = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
SectionHashes[i] = reader.ReadBytes(0x20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue