LibHac/libhac/SdFs.cs

131 lines
4.2 KiB
C#
Raw Normal View History

2018-06-22 21:05:29 +02:00
using System;
using System.Collections.Generic;
2018-06-21 18:16:51 +02:00
using System.IO;
using System.Linq;
namespace libhac
{
2018-06-26 00:26:47 +02:00
public class SdFs : IDisposable
2018-06-21 18:16:51 +02:00
{
public Keyset Keyset { get; }
public string RootDir { get; }
public string ContentsDir { get; }
public string[] Files { get; }
2018-06-27 02:10:21 +02:00
public Dictionary<string, Nca> Ncas { get; } = new Dictionary<string, Nca>(StringComparer.OrdinalIgnoreCase);
public Dictionary<ulong, Title> Titles { get; } = new Dictionary<ulong, Title>();
2018-06-26 00:26:47 +02:00
private List<Nax0> Nax0s { get; } = new List<Nax0>();
2018-06-21 18:16:51 +02:00
public SdFs(Keyset keyset, string sdPath)
{
if (Directory.Exists(Path.Combine(sdPath, "Nintendo")))
{
RootDir = sdPath;
Keyset = keyset;
ContentsDir = Path.Combine(sdPath, "Nintendo", "Contents");
}
Files = Directory.GetFiles(ContentsDir, "00", SearchOption.AllDirectories).Select(Path.GetDirectoryName).ToArray();
2018-06-27 02:10:21 +02:00
OpenAllNcas();
ReadTitles();
2018-06-21 18:16:51 +02:00
}
private void OpenAllNcas()
2018-06-21 18:16:51 +02:00
{
foreach (var file in Files)
{
2018-06-22 21:05:29 +02:00
Nca nca = null;
try
{
var sdPath = "/" + Util.GetRelativePath(file, ContentsDir).Replace('\\', '/');
2018-06-25 21:01:24 +02:00
var nax0 = Nax0.CreateFromPath(Keyset, file, sdPath);
2018-06-26 00:26:47 +02:00
Nax0s.Add(nax0);
nca = new Nca(Keyset, nax0.Stream, false);
2018-06-27 02:10:21 +02:00
nca.NcaId = Path.GetFileNameWithoutExtension(file);
var extention = nca.Header.ContentType == ContentType.Meta ? ".cnmt.nca" : ".nca";
nca.Filename = nca.NcaId + extention;
2018-06-22 21:05:29 +02:00
}
catch (Exception ex)
{
Console.WriteLine($"{ex.Message} {file}");
}
2018-06-27 02:10:21 +02:00
if (nca != null) Ncas.Add(nca.NcaId, nca);
}
}
private void ReadTitles()
2018-06-27 02:10:21 +02:00
{
foreach (var nca in Ncas.Values.Where(x => x.Header.ContentType == ContentType.Meta))
{
var title = new Title();
// Meta contents always have 1 Partition FS section with 1 file in it
Stream sect = nca.OpenSection(0, false);
2018-06-27 02:10:21 +02:00
var pfs0 = new Pfs0(sect);
var file = pfs0.GetFile(0);
var metadata = new Cnmt(new MemoryStream(file));
title.Id = metadata.TitleId;
title.Version = new TitleVersion(metadata.TitleVersion);
title.Metadata = metadata;
2018-06-29 21:53:51 +02:00
title.MetaNca = nca;
title.Ncas.Add(nca);
foreach (var content in metadata.ContentEntries)
{
var ncaId = content.NcaId.ToHexString();
if (Ncas.TryGetValue(ncaId, out Nca contentNca))
{
title.Ncas.Add(contentNca);
}
2018-06-29 21:53:51 +02:00
switch (content.Type)
{
case CnmtContentType.Program:
title.ProgramNca = contentNca;
break;
case CnmtContentType.Control:
title.ControlNca = contentNca;
break;
}
}
2018-06-27 02:10:21 +02:00
Titles.Add(title.Id, title);
2018-06-21 18:16:51 +02:00
}
2018-06-26 00:26:47 +02:00
}
private void DisposeNcas()
{
2018-06-27 02:10:21 +02:00
foreach (Nca nca in Ncas.Values)
2018-06-26 00:26:47 +02:00
{
nca.Dispose();
}
Ncas.Clear();
2018-06-21 18:16:51 +02:00
2018-06-27 02:10:21 +02:00
// Disposing the Nca disposes the Nax0 as well
2018-06-26 00:26:47 +02:00
Nax0s.Clear();
2018-06-27 02:10:21 +02:00
Titles.Clear();
2018-06-26 00:26:47 +02:00
}
public void Dispose()
{
DisposeNcas();
2018-06-21 18:16:51 +02:00
}
}
2018-06-27 02:10:21 +02:00
public class Title
{
public ulong Id { get; internal set; }
public TitleVersion Version { get; internal set; }
public List<Nca> Ncas { get; } = new List<Nca>();
public Cnmt Metadata { get; internal set; }
2018-06-29 21:53:51 +02:00
public Nca MetaNca { get; internal set; }
public Nca ProgramNca { get; internal set; }
public Nca ControlNca { get; internal set; }
2018-06-27 02:10:21 +02:00
}
2018-06-21 18:16:51 +02:00
}