mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Merge upstream
This commit is contained in:
commit
c1e60f8c75
11 changed files with 108 additions and 111 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -260,3 +260,6 @@ paket-files/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
**/launchSettings.json
|
**/launchSettings.json
|
||||||
|
|
||||||
|
|
||||||
|
global.json
|
|
@ -45,7 +45,7 @@ try {
|
||||||
}
|
}
|
||||||
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
|
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
|
||||||
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
|
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
|
||||||
(!(Test-Path variable:DotNetVersion) -or $(& cmd /c 'dotnet --version 2>&1') -eq $DotNetVersion)) {
|
(!(Test-Path variable:DotNetVersion) -or $(& cmd.exe /c 'dotnet --version 2>&1') -eq $DotNetVersion)) {
|
||||||
$env:DOTNET_EXE = (Get-Command "dotnet").Path
|
$env:DOTNET_EXE = (Get-Command "dotnet").Path
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -121,21 +121,17 @@ namespace LibHac
|
||||||
{
|
{
|
||||||
var counter = new byte[0x10];
|
var counter = new byte[0x10];
|
||||||
Array.Copy(encryptedKey, counter, 0x10);
|
Array.Copy(encryptedKey, counter, 0x10);
|
||||||
var body = new byte[0x230];
|
var key = new byte[0x230];
|
||||||
Array.Copy(encryptedKey, 0x10, body, 0, 0x230);
|
Array.Copy(encryptedKey, 0x10, key, 0, 0x230);
|
||||||
var dec = new byte[0x230];
|
|
||||||
|
|
||||||
using (var storageDec = new Aes128CtrStorage(new MemoryStorage(body), kek, counter, false))
|
new Aes128CtrTransform(kek, counter).TransformBlock(key);
|
||||||
{
|
|
||||||
storageDec.Read(dec, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
var d = new byte[0x100];
|
var d = new byte[0x100];
|
||||||
var n = new byte[0x100];
|
var n = new byte[0x100];
|
||||||
var e = new byte[4];
|
var e = new byte[4];
|
||||||
Array.Copy(dec, 0, d, 0, 0x100);
|
Array.Copy(key, 0, d, 0, 0x100);
|
||||||
Array.Copy(dec, 0x100, n, 0, 0x100);
|
Array.Copy(key, 0x100, n, 0, 0x100);
|
||||||
Array.Copy(dec, 0x200, e, 0, 4);
|
Array.Copy(key, 0x200, e, 0, 4);
|
||||||
|
|
||||||
BigInteger dInt = GetBigInteger(d);
|
BigInteger dInt = GetBigInteger(d);
|
||||||
BigInteger nInt = GetBigInteger(n);
|
BigInteger nInt = GetBigInteger(n);
|
||||||
|
|
|
@ -17,7 +17,9 @@ namespace LibHac.IO.Save
|
||||||
Header = new AllocationTableHeader(HeaderStorage);
|
Header = new AllocationTableHeader(HeaderStorage);
|
||||||
|
|
||||||
Stream tableStream = storage.AsStream();
|
Stream tableStream = storage.AsStream();
|
||||||
int blockCount = (int)(Header.AllocationTableBlockCount);
|
|
||||||
|
// The first entry in the table is reserved. Block 0 is at table index 1
|
||||||
|
int blockCount = (int)(Header.AllocationTableBlockCount) + 1;
|
||||||
|
|
||||||
Entries = new AllocationTableEntry[blockCount];
|
Entries = new AllocationTableEntry[blockCount];
|
||||||
tableStream.Position = 0;
|
tableStream.Position = 0;
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace LibHac.IO
|
|
||||||
{
|
|
||||||
public class StorageStream : Stream
|
|
||||||
{
|
|
||||||
private IStorage BaseStorage { get; }
|
|
||||||
private bool LeaveOpen { get; }
|
|
||||||
|
|
||||||
public StorageStream(IStorage baseStorage, bool leaveOpen)
|
|
||||||
{
|
|
||||||
BaseStorage = baseStorage;
|
|
||||||
LeaveOpen = leaveOpen;
|
|
||||||
Length = baseStorage.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
int toRead = (int)Math.Min(count, Length - Position);
|
|
||||||
BaseStorage.Read(buffer, Position, toRead, offset);
|
|
||||||
|
|
||||||
Position += toRead;
|
|
||||||
return toRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
BaseStorage.Write(buffer, Position, count, offset);
|
|
||||||
Position += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
BaseStorage.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
switch (origin)
|
|
||||||
{
|
|
||||||
case SeekOrigin.Begin:
|
|
||||||
Position = offset;
|
|
||||||
break;
|
|
||||||
case SeekOrigin.Current:
|
|
||||||
Position += offset;
|
|
||||||
break;
|
|
||||||
case SeekOrigin.End:
|
|
||||||
Position = Length - offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanRead => (BaseStorage as Storage)?.CanRead ?? true;
|
|
||||||
public override bool CanSeek => true;
|
|
||||||
public override bool CanWrite => (BaseStorage as Storage)?.CanWrite ?? true;
|
|
||||||
|
|
||||||
public override long Length { get; }
|
|
||||||
public override long Position { get; set; }
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!LeaveOpen) BaseStorage?.Dispose();
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ namespace LibHac
|
||||||
public ContentType ContentType;
|
public ContentType ContentType;
|
||||||
public byte CryptoType; // Which keyblob (field 1)
|
public byte CryptoType; // Which keyblob (field 1)
|
||||||
public byte KaekInd; // Which kaek index?
|
public byte KaekInd; // Which kaek index?
|
||||||
public ulong NcaSize; // Entire archive size.
|
public long NcaSize; // Entire archive size.
|
||||||
public ulong TitleId;
|
public ulong TitleId;
|
||||||
public TitleVersion SdkVersion; // What SDK was this built with?
|
public TitleVersion SdkVersion; // What SDK was this built with?
|
||||||
public byte CryptoType2; // Which keyblob (field 2)
|
public byte CryptoType2; // Which keyblob (field 2)
|
||||||
|
@ -46,7 +46,7 @@ namespace LibHac
|
||||||
ContentType = (ContentType)reader.ReadByte();
|
ContentType = (ContentType)reader.ReadByte();
|
||||||
CryptoType = reader.ReadByte();
|
CryptoType = reader.ReadByte();
|
||||||
KaekInd = reader.ReadByte();
|
KaekInd = reader.ReadByte();
|
||||||
NcaSize = reader.ReadUInt64();
|
NcaSize = reader.ReadInt64();
|
||||||
TitleId = reader.ReadUInt64();
|
TitleId = reader.ReadUInt64();
|
||||||
reader.BaseStream.Position += 4;
|
reader.BaseStream.Position += 4;
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ namespace hactoolnet
|
||||||
new CliOption("logodir", 1, (o, a) => o.LogoDir = a[0]),
|
new CliOption("logodir", 1, (o, a) => o.LogoDir = a[0]),
|
||||||
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
new CliOption("listapps", 0, (o, a) => o.ListApps = true),
|
||||||
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
new CliOption("listtitles", 0, (o, a) => o.ListTitles = true),
|
||||||
|
new CliOption("listncas", 0, (o, a) => o.ListNcas = true),
|
||||||
new CliOption("listromfs", 0, (o, a) => o.ListRomFs = true),
|
new CliOption("listromfs", 0, (o, a) => o.ListRomFs = true),
|
||||||
new CliOption("listfiles", 0, (o, a) => o.ListFiles = true),
|
new CliOption("listfiles", 0, (o, a) => o.ListFiles = true),
|
||||||
new CliOption("sign", 0, (o, a) => o.SignSave = true),
|
new CliOption("sign", 0, (o, a) => o.SignSave = true),
|
||||||
|
@ -194,6 +195,7 @@ namespace hactoolnet
|
||||||
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
|
sb.AppendLine(" --sdseed <seed> Set console unique seed for SD card NAX0 encryption.");
|
||||||
sb.AppendLine(" --listapps List application info.");
|
sb.AppendLine(" --listapps List application info.");
|
||||||
sb.AppendLine(" --listtitles List title info for all titles.");
|
sb.AppendLine(" --listtitles List title info for all titles.");
|
||||||
|
sb.AppendLine(" --listncas List info for all NCAs.");
|
||||||
sb.AppendLine(" --title <title id> Specify title ID to use.");
|
sb.AppendLine(" --title <title id> Specify title ID to use.");
|
||||||
sb.AppendLine(" --outdir <dir> Specify directory path to save title NCAs to. (--title must be specified)");
|
sb.AppendLine(" --outdir <dir> Specify directory path to save title NCAs to. (--title must be specified)");
|
||||||
sb.AppendLine(" --exefs <file> Specify ExeFS directory path. (--title must be specified)");
|
sb.AppendLine(" --exefs <file> Specify ExeFS directory path. (--title must be specified)");
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace hactoolnet
|
||||||
public string LogoDir;
|
public string LogoDir;
|
||||||
public bool ListApps;
|
public bool ListApps;
|
||||||
public bool ListTitles;
|
public bool ListTitles;
|
||||||
|
public bool ListNcas;
|
||||||
public bool ListRomFs;
|
public bool ListRomFs;
|
||||||
public bool ListFiles;
|
public bool ListFiles;
|
||||||
public bool SignSave;
|
public bool SignSave;
|
||||||
|
|
|
@ -15,9 +15,14 @@ namespace hactoolnet
|
||||||
{
|
{
|
||||||
var switchFs = new SwitchFs(ctx.Keyset, new LocalFileSystem(ctx.Options.InFile));
|
var switchFs = new SwitchFs(ctx.Keyset, new LocalFileSystem(ctx.Options.InFile));
|
||||||
|
|
||||||
|
if (ctx.Options.ListNcas)
|
||||||
|
{
|
||||||
|
ctx.Logger.LogMessage(ListNcas(switchFs));
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx.Options.ListTitles)
|
if (ctx.Options.ListTitles)
|
||||||
{
|
{
|
||||||
ListTitles(switchFs);
|
ctx.Logger.LogMessage(ListTitles(switchFs));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.Options.ListApps)
|
if (ctx.Options.ListApps)
|
||||||
|
@ -213,31 +218,34 @@ namespace hactoolnet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ListTitles(SwitchFs sdfs)
|
static string ListTitles(SwitchFs sdfs)
|
||||||
{
|
{
|
||||||
|
var table = new TableBuilder("Title ID", "Version", "", "Type", "Size", "Display Version", "Name");
|
||||||
|
|
||||||
foreach (Title title in sdfs.Titles.Values.OrderBy(x => x.Id))
|
foreach (Title title in sdfs.Titles.Values.OrderBy(x => x.Id))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{title.Name} {title.Control?.DisplayVersion}");
|
table.AddRow($"{title.Id:X16}",
|
||||||
Console.WriteLine($"{title.Id:X16} v{title.Version.Version} ({title.Version}) {title.Metadata.Type}");
|
$"v{title.Version?.Version}",
|
||||||
|
title.Version?.ToString(),
|
||||||
|
title.Metadata?.Type.ToString(),
|
||||||
|
Util.GetBytesReadable(title.GetSize()),
|
||||||
|
title.Control?.DisplayVersion,
|
||||||
|
title.Name);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (CnmtContentEntry content in title.Metadata.ContentEntries)
|
return table.Print();
|
||||||
|
}
|
||||||
|
|
||||||
|
static string ListNcas(SwitchFs sdfs)
|
||||||
{
|
{
|
||||||
Console.WriteLine(
|
var table = new TableBuilder("NCA ID", "Type", "Title ID");
|
||||||
$" {content.NcaId.ToHexString()}.nca {content.Type} {Util.GetBytesReadable(content.Size)}");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Nca nca in title.Ncas)
|
foreach (Nca nca in sdfs.Ncas.Values.OrderBy(x => x.NcaId))
|
||||||
{
|
{
|
||||||
Console.WriteLine($" {nca.HasRightsId} {nca.NcaId} {nca.Header.ContentType}");
|
table.AddRow(nca.NcaId, nca.Header.ContentType.ToString(), nca.Header.TitleId.ToString("X16"));
|
||||||
|
|
||||||
foreach (NcaSection sect in nca.Sections.Where(x => x != null))
|
|
||||||
{
|
|
||||||
Console.WriteLine($" {sect.SectionNum} {sect.Type} {sect.Header.EncryptionType} {sect.MasterHashValidity}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("");
|
return table.Print();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static string ListApplications(SwitchFs sdfs)
|
static string ListApplications(SwitchFs sdfs)
|
||||||
|
|
59
src/hactoolnet/TableBuilder.cs
Normal file
59
src/hactoolnet/TableBuilder.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace hactoolnet
|
||||||
|
{
|
||||||
|
public class TableBuilder
|
||||||
|
{
|
||||||
|
private List<string[]> Rows { get; } = new List<string[]>();
|
||||||
|
private int ColumnCount { get; set; }
|
||||||
|
|
||||||
|
public TableBuilder(params string[] header)
|
||||||
|
{
|
||||||
|
ColumnCount = header.Length;
|
||||||
|
Rows.Add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableBuilder(int columnCount)
|
||||||
|
{
|
||||||
|
ColumnCount = columnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRow(params string[] row)
|
||||||
|
{
|
||||||
|
if (row.Length != ColumnCount)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(row), "All rows must have the same number of columns");
|
||||||
|
}
|
||||||
|
|
||||||
|
Rows.Add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Print()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var width = new int[ColumnCount];
|
||||||
|
|
||||||
|
foreach (string[] row in Rows)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ColumnCount - 1; i++)
|
||||||
|
{
|
||||||
|
width[i] = Math.Max(width[i], row[i]?.Length ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string[] row in Rows)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ColumnCount; i++)
|
||||||
|
{
|
||||||
|
sb.Append($"{(row[i] ?? string.Empty).PadRight(width[i] + 1, ' ')}");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue