aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Horizon.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Horizon.cs')
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs282
1 files changed, 112 insertions, 170 deletions
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index acb6b1d1..0b55ee0a 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -1,5 +1,6 @@
using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Font;
@@ -195,58 +196,9 @@ namespace Ryujinx.HLE.HOS
Device.FileSystem.LoadRomFs(romFsFile);
}
- string npdmFileName = Path.Combine(exeFsDir, "main.npdm");
+ LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
- Npdm metaData = null;
-
- if (File.Exists(npdmFileName))
- {
- Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
-
- using (FileStream input = new FileStream(npdmFileName, FileMode.Open))
- {
- metaData = new Npdm(input);
- }
- }
- else
- {
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
-
- metaData = GetDefaultNpdm();
- }
-
- List<IExecutable> staticObjects = new List<IExecutable>();
-
- void LoadNso(string searchPattern)
- {
- foreach (string file in Directory.GetFiles(exeFsDir, searchPattern))
- {
- if (Path.GetExtension(file) != string.Empty)
- {
- continue;
- }
-
- Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(file)}...");
-
- using (FileStream input = new FileStream(file, FileMode.Open))
- {
- NxStaticObject staticObject = new NxStaticObject(input);
-
- staticObjects.Add(staticObject);
- }
- }
- }
-
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
-
- LoadNso("rtld");
- LoadNso("main");
- LoadNso("subsdk*");
- LoadNso("sdk");
-
- ContentManager.LoadEntries();
-
- ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
+ LoadExeFs(codeFs, out _);
}
public void LoadXci(string xciFile)
@@ -255,7 +207,7 @@ namespace Ryujinx.HLE.HOS
Xci xci = new Xci(KeySet, file.AsStorage());
- (Nca mainNca, Nca controlNca) = GetXciGameData(xci);
+ (Nca mainNca, Nca patchNca, Nca controlNca) = GetXciGameData(xci);
if (mainNca == null)
{
@@ -266,7 +218,7 @@ namespace Ryujinx.HLE.HOS
ContentManager.LoadEntries();
- LoadNca(mainNca, controlNca);
+ LoadNca(mainNca, patchNca, controlNca);
}
public void LoadKip(string kipFile)
@@ -277,9 +229,9 @@ namespace Ryujinx.HLE.HOS
}
}
- private (Nca Main, Nca Control) GetXciGameData(Xci xci)
+ private (Nca Main, Nca patch, Nca Control) GetXciGameData(Xci xci)
{
- if (xci.SecurePartition == null)
+ if (!xci.HasPartition(XciPartitionType.Secure))
{
throw new InvalidDataException("Could not find XCI secure partition");
}
@@ -288,9 +240,11 @@ namespace Ryujinx.HLE.HOS
Nca patchNca = null;
Nca controlNca = null;
- foreach (PfsFileEntry ticketEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".tik")))
+ XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure);
+
+ foreach (DirectoryEntry ticketEntry in securePartition.EnumerateEntries("*.tik"))
{
- Ticket ticket = new Ticket(xci.SecurePartition.OpenFile(ticketEntry).AsStream());
+ Ticket ticket = new Ticket(securePartition.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
{
@@ -298,21 +252,23 @@ namespace Ryujinx.HLE.HOS
}
}
- foreach (PfsFileEntry fileEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
+ foreach (DirectoryEntry fileEntry in securePartition.EnumerateEntries("*.nca"))
{
- IStorage ncaStorage = xci.SecurePartition.OpenFile(fileEntry);
+ IStorage ncaStorage = securePartition.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage();
- Nca nca = new Nca(KeySet, ncaStorage, true);
+ Nca nca = new Nca(KeySet, ncaStorage);
if (nca.Header.ContentType == ContentType.Program)
{
- if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
+ int dataIndex = Nca.SectionIndexFromType(NcaSectionType.Data, ContentType.Program);
+
+ if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
{
- mainNca = nca;
+ patchNca = nca;
}
- else if (nca.Sections.Any(x => x?.Type == SectionType.Bktr))
+ else
{
- patchNca = nca;
+ mainNca = nca;
}
}
else if (nca.Header.ContentType == ContentType.Control)
@@ -326,50 +282,43 @@ namespace Ryujinx.HLE.HOS
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
}
- mainNca.SetBaseNca(patchNca);
-
if (controlNca != null)
{
ReadControlData(controlNca);
}
- if (patchNca != null)
- {
- patchNca.SetBaseNca(mainNca);
-
- return (patchNca, controlNca);
- }
-
- return (mainNca, controlNca);
+ return (mainNca, patchNca, controlNca);
}
public void ReadControlData(Nca controlNca)
{
- Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel, true));
+ IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
- IStorage controlFile = controlRomfs.OpenFile("/control.nacp");
+ IFile controlFile = controlFs.OpenFile("/control.nacp", OpenMode.Read);
ControlData = new Nacp(controlFile.AsStream());
+
+ TitleName = CurrentTitle = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
}
public void LoadNca(string ncaFile)
{
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
- Nca nca = new Nca(KeySet, file.AsStorage(false), false);
+ Nca nca = new Nca(KeySet, file.AsStorage(false));
- LoadNca(nca, null);
+ LoadNca(nca, null, null);
}
public void LoadNsp(string nspFile)
{
FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read);
- Pfs nsp = new Pfs(file.AsStorage(false));
+ PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
- foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik")))
+ foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik"))
{
- Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream());
+ Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
{
@@ -378,15 +327,27 @@ namespace Ryujinx.HLE.HOS
}
Nca mainNca = null;
+ Nca patchNca = null;
Nca controlNca = null;
- foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca")))
+ foreach (DirectoryEntry fileEntry in nsp.EnumerateEntries("*.nca"))
{
- Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true);
+ IStorage ncaStorage = nsp.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage();
+
+ Nca nca = new Nca(KeySet, ncaStorage);
if (nca.Header.ContentType == ContentType.Program)
{
- mainNca = nca;
+ int dataIndex = Nca.SectionIndexFromType(NcaSectionType.Data, ContentType.Program);
+
+ if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
+ {
+ patchNca = nca;
+ }
+ else
+ {
+ mainNca = nca;
+ }
}
else if (nca.Header.ContentType == ContentType.Control)
{
@@ -396,105 +357,112 @@ namespace Ryujinx.HLE.HOS
if (mainNca != null)
{
- LoadNca(mainNca, controlNca);
+ LoadNca(mainNca, patchNca, controlNca);
return;
}
// This is not a normal NSP, it's actually a ExeFS as a NSP
- Npdm metaData = null;
-
- PfsFileEntry npdmFile = nsp.Files.FirstOrDefault(x => x.Name.Equals("main.npdm"));
-
- if (npdmFile != null)
- {
- Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
+ LoadExeFs(nsp, out _);
+ }
- metaData = new Npdm(nsp.OpenFile(npdmFile).AsStream());
- }
- else
+ public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
+ {
+ if (mainNca.Header.ContentType != ContentType.Program)
{
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
+ Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
- metaData = GetDefaultNpdm();
+ return;
}
- List<IExecutable> staticObjects = new List<IExecutable>();
+ IStorage dataStorage = null;
+ IFileSystem codeFs = null;
- void LoadNso(string searchPattern)
+ if (patchNca == null)
{
- PfsFileEntry entry = nsp.Files.FirstOrDefault(x => x.Name.Equals(searchPattern));
-
- if (entry != null)
+ if (mainNca.CanOpenSection(NcaSectionType.Data))
{
- Logger.PrintInfo(LogClass.Loader, $"Loading {entry.Name}...");
-
- NxStaticObject staticObject = new NxStaticObject(nsp.OpenFile(entry).AsStream());
+ dataStorage = mainNca.OpenStorage(NcaSectionType.Data, FsIntegrityCheckLevel);
+ }
- staticObjects.Add(staticObject);
+ if (mainNca.CanOpenSection(NcaSectionType.Code))
+ {
+ codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, FsIntegrityCheckLevel);
}
}
+ else
+ {
+ if (patchNca.CanOpenSection(NcaSectionType.Data))
+ {
+ dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, FsIntegrityCheckLevel);
+ }
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
+ if (patchNca.CanOpenSection(NcaSectionType.Code))
+ {
+ codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, FsIntegrityCheckLevel);
+ }
+ }
- LoadNso("rtld");
- LoadNso("main");
- LoadNso("subsdk*");
- LoadNso("sdk");
+ if (codeFs == null)
+ {
+ Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
- ContentManager.LoadEntries();
+ return;
+ }
- if (staticObjects.Count == 0)
+ if (dataStorage == null)
{
- Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
+ Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
}
else
{
- ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
+ Device.FileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
}
- }
- public void LoadNca(Nca mainNca, Nca controlNca)
- {
- if (mainNca.Header.ContentType != ContentType.Program)
+ LoadExeFs(codeFs, out Npdm metaData);
+
+ Nacp ReadControlData()
{
- Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
+ IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
- return;
- }
+ IFile controlFile = controlRomfs.OpenFile("/control.nacp", OpenMode.Read);
+
+ Nacp controlData = new Nacp(controlFile.AsStream());
- IStorage romfsStorage = mainNca.OpenSection(ProgramPartitionType.Data, false, FsIntegrityCheckLevel, false);
- IStorage exefsStorage = mainNca.OpenSection(ProgramPartitionType.Code, false, FsIntegrityCheckLevel, true);
+ TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
+ TitleID = metaData.Aci0.TitleId.ToString("x16");
- if (exefsStorage == null)
- {
- Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
+ CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
- return;
+ if (string.IsNullOrWhiteSpace(CurrentTitle))
+ {
+ TitleName = CurrentTitle = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
+ }
+
+ return controlData;
}
- if (romfsStorage == null)
+ if (controlNca != null)
{
- Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
+ ReadControlData();
}
else
{
- Device.FileSystem.SetRomFs(romfsStorage.AsStream(false));
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
}
+ }
- Pfs exefs = new Pfs(exefsStorage);
-
- Npdm metaData = null;
-
- if (exefs.FileExists("main.npdm"))
+ private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
+ {
+ if (codeFs.FileExists("/main.npdm"))
{
Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
- metaData = new Npdm(exefs.OpenFile("main.npdm").AsStream());
+ metaData = new Npdm(codeFs.OpenFile("/main.npdm", OpenMode.Read).AsStream());
}
else
{
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
+ Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
metaData = GetDefaultNpdm();
}
@@ -503,48 +471,22 @@ namespace Ryujinx.HLE.HOS
void LoadNso(string filename)
{
- foreach (PfsFileEntry file in exefs.Files.Where(x => x.Name.StartsWith(filename)))
+ foreach (DirectoryEntry file in codeFs.EnumerateEntries($"{filename}*"))
{
if (Path.GetExtension(file.Name) != string.Empty)
{
continue;
}
- Logger.PrintInfo(LogClass.Loader, $"Loading {filename}...");
+ Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}...");
- NxStaticObject staticObject = new NxStaticObject(exefs.OpenFile(file).AsStream());
+ NxStaticObject staticObject = new NxStaticObject(codeFs.OpenFile(file.FullPath, OpenMode.Read).AsStream());
staticObjects.Add(staticObject);
}
}
- Nacp ReadControlData()
- {
- Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel, true));
-
- IStorage controlFile = controlRomfs.OpenFile("/control.nacp");
-
- Nacp controlData = new Nacp(controlFile.AsStream());
-
- TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
- TitleID = metaData.Aci0.TitleId.ToString("x16");
-
- if (string.IsNullOrWhiteSpace(CurrentTitle))
- {
- TitleName = CurrentTitle = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
- }
-
- return controlData;
- }
-
- if (controlNca != null)
- {
- ReadControlData();
- }
- else
- {
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
- }
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
LoadNso("rtld");
LoadNso("main");
@@ -613,7 +555,7 @@ namespace Ryujinx.HLE.HOS
ContentManager.LoadEntries();
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
TitleName = metaData.TitleName;
ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject });