Group titles by main application

This commit is contained in:
Alex Barney 2018-07-02 13:16:38 -05:00
parent 44fb0d39d4
commit ca815312d3
4 changed files with 122 additions and 15 deletions

View file

@ -27,6 +27,9 @@ namespace hactoolnet
Console.WriteLine("Listing titles"); Console.WriteLine("Listing titles");
ListTitles(sdfs); ListTitles(sdfs);
Console.WriteLine("Listing applications");
ListApplications(sdfs);
//DecryptNax0(sdfs, "C0628FB07A89E9050BDA258F74868E8D"); //DecryptNax0(sdfs, "C0628FB07A89E9050BDA258F74868E8D");
//DecryptTitle(sdfs, 0x010023900AEE0000); //DecryptTitle(sdfs, 0x010023900AEE0000);
} }
@ -151,5 +154,38 @@ namespace hactoolnet
Console.WriteLine(""); Console.WriteLine("");
} }
} }
static void ListApplications(SdFs sdfs)
{
foreach (var app in sdfs.Applications.Values.OrderBy(x => x.Name))
{
Console.WriteLine($"{app.Name} v{app.DisplayVersion}");
long totalSize = 0;
if (app.Main != null)
{
Console.WriteLine($"Software: {Util.GetBytesReadable(app.Main.GetSize())}");
}
if (app.Patch != null)
{
Console.WriteLine($"Update Data: {Util.GetBytesReadable(app.Patch.GetSize())}");
}
if (app.AddOnContent.Count > 0)
{
Console.WriteLine($"DLC: {Util.GetBytesReadable(app.AddOnContent.Sum(x => x.GetSize()))}");
}
if (app.Nacp?.UserTotalSaveDataSize > 0)
Console.WriteLine($"User save: {Util.GetBytesReadable(app.Nacp.UserTotalSaveDataSize)}");
if (app.Nacp?.DeviceTotalSaveDataSize > 0)
Console.WriteLine($"System save: {Util.GetBytesReadable(app.Nacp.DeviceTotalSaveDataSize)}");
if (app.Nacp?.BcatSaveDataSize > 0)
Console.WriteLine($"BCAT save: {Util.GetBytesReadable(app.Nacp.BcatSaveDataSize)}");
Console.WriteLine("");
}
}
} }
} }

View file

@ -37,6 +37,7 @@ namespace libhac
switch (Type) switch (Type)
{ {
case TitleType.Application: case TitleType.Application:
ApplicationTitleId = TitleId;
PatchTitleId = reader.ReadUInt64(); PatchTitleId = reader.ReadUInt64();
MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true); MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true);
break; break;

View file

@ -6,6 +6,17 @@ namespace libhac
{ {
public NacpLang[] Languages { get; } = new NacpLang[0x10]; public NacpLang[] Languages { get; } = new NacpLang[0x10];
public string Version { get; } public string Version { 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 BcatSaveDataSize { get; }
public long TotalSaveDataSize { get; }
public long UserTotalSaveDataSize { get; }
public long DeviceTotalSaveDataSize { get; }
public Nacp(BinaryReader reader) public Nacp(BinaryReader reader)
{ {
@ -18,6 +29,18 @@ namespace libhac
reader.BaseStream.Position = start + 0x3060; reader.BaseStream.Position = start + 0x3060;
Version = reader.ReadUtf8Z(); Version = reader.ReadUtf8Z();
reader.BaseStream.Position = start + 0x3070;
AddOnContentBaseId = reader.ReadUInt64();
SaveDataOwnerId = reader.ReadUInt64();
UserAccountSaveDataSize = reader.ReadInt64();
UserAccountSaveDataJournalSize = reader.ReadInt64();
DeviceSaveDataSize = reader.ReadInt64();
DeviceSaveDataJournalSize = reader.ReadInt64();
BcatSaveDataSize = reader.ReadInt64();
UserTotalSaveDataSize = UserAccountSaveDataSize + UserAccountSaveDataJournalSize;
DeviceTotalSaveDataSize = DeviceSaveDataSize + DeviceSaveDataJournalSize;
TotalSaveDataSize = UserTotalSaveDataSize + DeviceTotalSaveDataSize;
} }
} }

View file

@ -15,6 +15,7 @@ namespace libhac
public Dictionary<string, Nca> Ncas { get; } = new Dictionary<string, Nca>(StringComparer.OrdinalIgnoreCase); public Dictionary<string, Nca> Ncas { get; } = new Dictionary<string, Nca>(StringComparer.OrdinalIgnoreCase);
public Dictionary<ulong, Title> Titles { get; } = new Dictionary<ulong, Title>(); public Dictionary<ulong, Title> Titles { get; } = new Dictionary<ulong, Title>();
public Dictionary<ulong, Application> Applications { get; } = new Dictionary<ulong, Application>();
private List<Nax0> Nax0s { get; } = new List<Nax0>(); private List<Nax0> Nax0s { get; } = new List<Nax0>();
@ -35,6 +36,7 @@ namespace libhac
OpenAllNcas(); OpenAllNcas();
ReadTitles(); ReadTitles();
ReadControls(); ReadControls();
CreateApplications();
} }
private void OpenAllNcas() private void OpenAllNcas()
@ -68,7 +70,7 @@ namespace libhac
{ {
nca = new Nca(Keyset, stream, false); nca = new Nca(Keyset, stream, false);
} }
nca.NcaId = Path.GetFileNameWithoutExtension(file); nca.NcaId = Path.GetFileNameWithoutExtension(file);
var extention = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca"; var extention = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca";
nca.Filename = nca.NcaId + extention; nca.Filename = nca.NcaId + extention;
@ -147,6 +149,23 @@ namespace libhac
} }
} }
private void CreateApplications()
{
foreach (var title in Titles.Values.Where(x => x.Metadata.Type >= TitleType.Application))
{
var meta = title.Metadata;
ulong appId = meta.ApplicationTitleId;
if (!Applications.TryGetValue(appId, out var app))
{
app = new Application();
Applications.Add(appId, app);
}
app.AddTitle(title);
}
}
internal static Stream OpenSplitNcaStream(string path) internal static Stream OpenSplitNcaStream(string path)
{ {
List<string> files = new List<string>(); List<string> files = new List<string>();
@ -218,44 +237,72 @@ namespace libhac
public Nca MetaNca { get; internal set; } public Nca MetaNca { get; internal set; }
public Nca ProgramNca { get; internal set; } public Nca ProgramNca { get; internal set; }
public Nca ControlNca { get; internal set; } public Nca ControlNca { get; internal set; }
public long GetSize()
{
return Metadata.ContentEntries
.Where(x => x.Type < CnmtContentType.UpdatePatch)
.Sum(x => x.Size);
}
} }
public class Application public class Application
{ {
public Title Main { get; private set; } public Title Main { get; private set; }
public Title Patch { get; private set; } public Title Patch { get; private set; }
public List<Title> AddOnContent { get; private set; } public List<Title> AddOnContent { get; } = new List<Title>();
public ulong TitleId { get; private set; }
public TitleVersion Version { get; private set; }
public Nacp Nacp { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public string Version { get; private set; } public string DisplayVersion { get; private set; }
public void SetMainTitle(Title title) public void AddTitle(Title title)
{ {
Main = title; if (TitleId != 0 && title.Metadata.ApplicationTitleId != TitleId)
throw new InvalidDataException("Title IDs do not match");
TitleId = title.Metadata.ApplicationTitleId;
switch (title.Metadata.Type)
{
case TitleType.Application:
Main = title;
break;
case TitleType.Patch:
Patch = title;
break;
case TitleType.AddOnContent:
AddOnContent.Add(title);
break;
case TitleType.DeltaTitle:
break;
}
UpdateInfo();
} }
public void SetPatchTitle(Title title) private void UpdateInfo()
{
if (title.Metadata.Type != TitleType.Patch) throw new InvalidDataException("Title is not a patch");
Patch = title;
}
private void UpdateName()
{ {
if (Patch != null) if (Patch != null)
{ {
Name = Patch.Name; Name = Patch.Name;
Version = Patch.Control?.Version ?? ""; Version = Patch.Version;
DisplayVersion = Patch.Control?.Version ?? "";
Nacp = Patch.Control;
} }
else if (Main != null) else if (Main != null)
{ {
Name = Main.Name; Name = Main.Name;
Version = Main.Control?.Version ?? ""; Version = Main.Version;
DisplayVersion = Main.Control?.Version ?? "";
Nacp = Main.Control;
} }
else else
{ {
Name = ""; Name = "";
Version = ""; DisplayVersion = "";
} }
} }
} }