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");
ListTitles(sdfs);
Console.WriteLine("Listing applications");
ListApplications(sdfs);
//DecryptNax0(sdfs, "C0628FB07A89E9050BDA258F74868E8D");
//DecryptTitle(sdfs, 0x010023900AEE0000);
}
@ -151,5 +154,38 @@ namespace hactoolnet
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)
{
case TitleType.Application:
ApplicationTitleId = TitleId;
PatchTitleId = reader.ReadUInt64();
MinimumSystemVersion = new TitleVersion(reader.ReadUInt32(), true);
break;

View file

@ -6,6 +6,17 @@ namespace libhac
{
public NacpLang[] Languages { get; } = new NacpLang[0x10];
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)
{
@ -18,6 +29,18 @@ namespace libhac
reader.BaseStream.Position = start + 0x3060;
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<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>();
@ -35,6 +36,7 @@ namespace libhac
OpenAllNcas();
ReadTitles();
ReadControls();
CreateApplications();
}
private void OpenAllNcas()
@ -68,7 +70,7 @@ namespace libhac
{
nca = new Nca(Keyset, stream, false);
}
nca.NcaId = Path.GetFileNameWithoutExtension(file);
var extention = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca";
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)
{
List<string> files = new List<string>();
@ -218,44 +237,72 @@ namespace libhac
public Nca MetaNca { get; internal set; }
public Nca ProgramNca { 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 Title Main { 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 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)
{
if (title.Metadata.Type != TitleType.Patch) throw new InvalidDataException("Title is not a patch");
Patch = title;
}
private void UpdateName()
private void UpdateInfo()
{
if (Patch != null)
{
Name = Patch.Name;
Version = Patch.Control?.Version ?? "";
Version = Patch.Version;
DisplayVersion = Patch.Control?.Version ?? "";
Nacp = Patch.Control;
}
else if (Main != null)
{
Name = Main.Name;
Version = Main.Control?.Version ?? "";
Version = Main.Version;
DisplayVersion = Main.Control?.Version ?? "";
Nacp = Main.Control;
}
else
{
Name = "";
Version = "";
DisplayVersion = "";
}
}
}