diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index 054dc96a7..d63234509 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -43,15 +43,11 @@ namespace Ryujinx.HLE.FileSystem private readonly struct AocItem { public readonly string ContainerPath; - public readonly Stream ContainerStream; public readonly string NcaPath; - public readonly string Extension; - public AocItem(string containerPath, Stream containerStream, string ncaPath, string extension) + public AocItem(string containerPath, string ncaPath) { ContainerPath = containerPath; - ContainerStream = containerStream; - Extension = extension; NcaPath = ncaPath; } } @@ -191,10 +187,10 @@ namespace Ryujinx.HLE.FileSystem } } - public void AddAocItem(ulong titleId, string containerPath, Stream containerStream, string ncaPath, string extension, bool mergedToContainer = false) + public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool mergedToContainer = false) { // TODO: Check Aoc version. - if (!AocData.TryAdd(titleId, new AocItem(containerPath, containerStream, ncaPath, extension))) + if (!AocData.TryAdd(titleId, new AocItem(containerPath, ncaPath))) { Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}"); } @@ -204,20 +200,12 @@ namespace Ryujinx.HLE.FileSystem if (!mergedToContainer) { - using var pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(containerStream, extension == ".xci", _virtualFileSystem); + using var pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(containerPath, _virtualFileSystem); } } } - public void ClearAocData() - { - foreach (var aoc in AocData) - { - aoc.Value.ContainerStream?.Dispose(); - } - - AocData.Clear(); - } + public void ClearAocData() => AocData.Clear(); public int GetAocCount() => AocData.Count; @@ -232,11 +220,11 @@ namespace Ryujinx.HLE.FileSystem var file = new FileStream(aoc.ContainerPath, FileMode.Open, FileAccess.Read); using var ncaFile = new UniqueRef(); - switch (aoc.Extension) + switch (Path.GetExtension(aoc.ContainerPath)) { case ".xci": - var xci = new Xci(_virtualFileSystem.KeySet, aoc.ContainerStream.AsStorage()).OpenPartition(XciPartitionType.Secure); - xci.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read); + var xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); + xci.OpenFile(ref ncaFile.Ref, aoc.NcaPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); break; case ".nsp": var pfs = new PartitionFileSystem(); @@ -488,27 +476,6 @@ namespace Ryujinx.HLE.FileSystem FinishInstallation(temporaryDirectory, registeredDirectory); } - public void InstallFirmware(Stream stream, bool isXci) - { - ContentPath.TryGetContentPath(StorageId.BuiltInSystem, out var contentPathString); - ContentPath.TryGetRealPath(contentPathString, out var contentDirectory); - string registeredDirectory = Path.Combine(contentDirectory, "registered"); - string temporaryDirectory = Path.Combine(contentDirectory, "temp"); - - if (!isXci) - { - using ZipArchive archive = new ZipArchive(stream); - InstallFromZip(archive, temporaryDirectory); - } - else - { - Xci xci = new(_virtualFileSystem.KeySet, stream.AsStorage()); - InstallFromCart(xci, temporaryDirectory); - } - - FinishInstallation(temporaryDirectory, registeredDirectory); - } - public void InstallKeys(string keysSource, string installDirectory) { if (Directory.Exists(keysSource)) @@ -695,16 +662,13 @@ namespace Ryujinx.HLE.FileSystem throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers."); } + Dictionary> updateNcas = new(); + if (Directory.Exists(firmwarePackage)) { return VerifyAndGetVersionDirectory(firmwarePackage); } - SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory) - { - return VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory)); - } - if (!File.Exists(firmwarePackage)) { throw new FileNotFoundException("Firmware file does not exist."); @@ -712,144 +676,274 @@ namespace Ryujinx.HLE.FileSystem FileInfo info = new(firmwarePackage); - if (info.Extension == ".zip" || info.Extension == ".xci") + using FileStream file = File.OpenRead(firmwarePackage); + + switch (info.Extension) { - using FileStream file = File.OpenRead(firmwarePackage); - - var isXci = info.Extension == ".xci"; - - return VerifyFirmwarePackage(file, isXci); - } - - return null; - } - - public SystemVersion VerifyFirmwarePackage(Stream file, bool isXci) - { - if (!isXci) - { - using ZipArchive archive = new ZipArchive(file, ZipArchiveMode.Read); - return VerifyAndGetVersionZip(archive); - } - else - { - Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); - - if (xci.HasPartition(XciPartitionType.Update)) - { - XciPartition partition = xci.OpenPartition(XciPartitionType.Update); - - return VerifyAndGetVersion(partition); - } - else - { - throw new InvalidFirmwarePackageException("Update not found in xci file."); - } - } - } - - private SystemVersion VerifyAndGetVersionZip(ZipArchive archive) - { - Dictionary> updateNcas = new(); - - SystemVersion systemVersion = null; - - foreach (var entry in archive.Entries) - { - if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00")) - { - using Stream ncaStream = GetZipStream(entry); - IStorage storage = ncaStream.AsStorage(); - - Nca nca = new(_virtualFileSystem.KeySet, storage); - - if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem)) + case ".zip": + using (ZipArchive archive = ZipFile.OpenRead(firmwarePackage)) { - updateNcasItem.Add((nca.Header.ContentType, entry.FullName)); + return VerifyAndGetVersionZip(archive); } - else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) + case ".xci": + Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); + + if (xci.HasPartition(XciPartitionType.Update)) { - updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName)); + XciPartition partition = xci.OpenPartition(XciPartitionType.Update); + + return VerifyAndGetVersion(partition); } - } + else + { + throw new InvalidFirmwarePackageException("Update not found in xci file."); + } + default: + break; } - if (updateNcas.TryGetValue(SystemUpdateTitleId, out var ncaEntry)) + SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory) { - string metaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; + return VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory)); + } - CnmtContentMetaEntry[] metaEntries = null; + SystemVersion VerifyAndGetVersionZip(ZipArchive archive) + { + SystemVersion systemVersion = null; - var fileEntry = archive.GetEntry(metaPath); - - using (Stream ncaStream = GetZipStream(fileEntry)) + foreach (var entry in archive.Entries) { - Nca metaNca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage()); - - IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; - - using var metaFile = new UniqueRef(); - - if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) + if (entry.FullName.EndsWith(".nca") || entry.FullName.EndsWith(".nca/00")) { - var meta = new Cnmt(metaFile.Get.AsStream()); + using Stream ncaStream = GetZipStream(entry); + IStorage storage = ncaStream.AsStorage(); - if (meta.Type == ContentMetaType.SystemUpdate) + Nca nca = new(_virtualFileSystem.KeySet, storage); + + if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem)) { - metaEntries = meta.MetaEntries; - - updateNcas.Remove(SystemUpdateTitleId); + updateNcasItem.Add((nca.Header.ContentType, entry.FullName)); + } + else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) + { + updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName)); } } } - if (metaEntries == null) + if (updateNcas.TryGetValue(SystemUpdateTitleId, out var ncaEntry)) { - throw new FileNotFoundException("System update title was not found in the firmware package."); - } + string metaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; - if (updateNcas.TryGetValue(SystemVersionTitleId, out var updateNcasItem)) - { - string versionEntry = updateNcasItem.FirstOrDefault(x => x.type != NcaContentType.Meta).path; + CnmtContentMetaEntry[] metaEntries = null; - using Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry)); - Nca nca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage()); + var fileEntry = archive.GetEntry(metaPath); - var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - using var systemVersionFile = new UniqueRef(); - - if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) + using (Stream ncaStream = GetZipStream(fileEntry)) { - systemVersion = new SystemVersion(systemVersionFile.Get.AsStream()); - } - } - - foreach (CnmtContentMetaEntry metaEntry in metaEntries) - { - if (updateNcas.TryGetValue(metaEntry.TitleId, out ncaEntry)) - { - metaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; - - string contentPath = ncaEntry.FirstOrDefault(x => x.type != NcaContentType.Meta).path; - - // Nintendo in 9.0.0, removed PPC and only kept the meta nca of it. - // This is a perfect valid case, so we should just ignore the missing content nca and continue. - if (contentPath == null) - { - updateNcas.Remove(metaEntry.TitleId); - - continue; - } - - ZipArchiveEntry metaZipEntry = archive.GetEntry(metaPath); - ZipArchiveEntry contentZipEntry = archive.GetEntry(contentPath); - - using Stream metaNcaStream = GetZipStream(metaZipEntry); - using Stream contentNcaStream = GetZipStream(contentZipEntry); - Nca metaNca = new(_virtualFileSystem.KeySet, metaNcaStream.AsStorage()); + Nca metaNca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage()); + + IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; + + using var metaFile = new UniqueRef(); + + if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) + { + var meta = new Cnmt(metaFile.Get.AsStream()); + + if (meta.Type == ContentMetaType.SystemUpdate) + { + metaEntries = meta.MetaEntries; + + updateNcas.Remove(SystemUpdateTitleId); + } + } + } + + if (metaEntries == null) + { + throw new FileNotFoundException("System update title was not found in the firmware package."); + } + + if (updateNcas.TryGetValue(SystemVersionTitleId, out var updateNcasItem)) + { + string versionEntry = updateNcasItem.FirstOrDefault(x => x.type != NcaContentType.Meta).path; + + using Stream ncaStream = GetZipStream(archive.GetEntry(versionEntry)); + Nca nca = new(_virtualFileSystem.KeySet, ncaStream.AsStorage()); + + var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + using var systemVersionFile = new UniqueRef(); + + if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) + { + systemVersion = new SystemVersion(systemVersionFile.Get.AsStream()); + } + } + + foreach (CnmtContentMetaEntry metaEntry in metaEntries) + { + if (updateNcas.TryGetValue(metaEntry.TitleId, out ncaEntry)) + { + metaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; + + string contentPath = ncaEntry.FirstOrDefault(x => x.type != NcaContentType.Meta).path; + + // Nintendo in 9.0.0, removed PPC and only kept the meta nca of it. + // This is a perfect valid case, so we should just ignore the missing content nca and continue. + if (contentPath == null) + { + updateNcas.Remove(metaEntry.TitleId); + + continue; + } + + ZipArchiveEntry metaZipEntry = archive.GetEntry(metaPath); + ZipArchiveEntry contentZipEntry = archive.GetEntry(contentPath); + + using Stream metaNcaStream = GetZipStream(metaZipEntry); + using Stream contentNcaStream = GetZipStream(contentZipEntry); + Nca metaNca = new(_virtualFileSystem.KeySet, metaNcaStream.AsStorage()); + + IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; + + using var metaFile = new UniqueRef(); + + if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) + { + var meta = new Cnmt(metaFile.Get.AsStream()); + + IStorage contentStorage = contentNcaStream.AsStorage(); + if (contentStorage.GetSize(out long size).IsSuccess()) + { + byte[] contentData = new byte[size]; + + Span content = new(contentData); + + contentStorage.Read(0, content); + + Span hash = new(new byte[32]); + + LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash); + + if (LibHac.Common.Utilities.ArraysEqual(hash.ToArray(), meta.ContentEntries[0].Hash)) + { + updateNcas.Remove(metaEntry.TitleId); + } + } + } + } + } + + if (updateNcas.Count > 0) + { + StringBuilder extraNcas = new(); + + foreach (var entry in updateNcas) + { + foreach (var (type, path) in entry.Value) + { + extraNcas.AppendLine(path); + } + } + + throw new InvalidFirmwarePackageException($"Firmware package contains unrelated archives. Please remove these paths: {Environment.NewLine}{extraNcas}"); + } + } + else + { + throw new FileNotFoundException("System update title was not found in the firmware package."); + } + + return systemVersion; + } + + SystemVersion VerifyAndGetVersion(IFileSystem filesystem) + { + SystemVersion systemVersion = null; + + CnmtContentMetaEntry[] metaEntries = null; + + foreach (var entry in filesystem.EnumerateEntries("/", "*.nca")) + { + IStorage ncaStorage = OpenPossibleFragmentedFile(filesystem, entry.FullPath, OpenMode.Read).AsStorage(); + + Nca nca = new(_virtualFileSystem.KeySet, ncaStorage); + + if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta) + { + IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; + + using var metaFile = new UniqueRef(); + + if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) + { + var meta = new Cnmt(metaFile.Get.AsStream()); + + if (meta.Type == ContentMetaType.SystemUpdate) + { + metaEntries = meta.MetaEntries; + } + } + + continue; + } + else if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) + { + var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); + + using var systemVersionFile = new UniqueRef(); + + if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) + { + systemVersion = new SystemVersion(systemVersionFile.Get.AsStream()); + } + } + + if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem)) + { + updateNcasItem.Add((nca.Header.ContentType, entry.FullPath)); + } + else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) + { + updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath)); + } + + ncaStorage.Dispose(); + } + + if (metaEntries == null) + { + throw new FileNotFoundException("System update title was not found in the firmware package."); + } + + foreach (CnmtContentMetaEntry metaEntry in metaEntries) + { + if (updateNcas.TryGetValue(metaEntry.TitleId, out var ncaEntry)) + { + string metaNcaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; + string contentPath = ncaEntry.FirstOrDefault(x => x.type != NcaContentType.Meta).path; + + // Nintendo in 9.0.0, removed PPC and only kept the meta nca of it. + // This is a perfect valid case, so we should just ignore the missing content nca and continue. + if (contentPath == null) + { + updateNcas.Remove(metaEntry.TitleId); + + continue; + } + + IStorage metaStorage = OpenPossibleFragmentedFile(filesystem, metaNcaPath, OpenMode.Read).AsStorage(); + IStorage contentStorage = OpenPossibleFragmentedFile(filesystem, contentPath, OpenMode.Read).AsStorage(); + + Nca metaNca = new(_virtualFileSystem.KeySet, metaStorage); IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); @@ -861,7 +955,6 @@ namespace Ryujinx.HLE.FileSystem { var meta = new Cnmt(metaFile.Get.AsStream()); - IStorage contentStorage = contentNcaStream.AsStorage(); if (contentStorage.GetSize(out long size).IsSuccess()) { byte[] contentData = new byte[size]; @@ -897,146 +990,11 @@ namespace Ryujinx.HLE.FileSystem throw new InvalidFirmwarePackageException($"Firmware package contains unrelated archives. Please remove these paths: {Environment.NewLine}{extraNcas}"); } - } - else - { - throw new FileNotFoundException("System update title was not found in the firmware package."); + + return systemVersion; } - return systemVersion; - } - - private SystemVersion VerifyAndGetVersion(IFileSystem filesystem) - { - Dictionary> updateNcas = new(); - - SystemVersion systemVersion = null; - - CnmtContentMetaEntry[] metaEntries = null; - - foreach (var entry in filesystem.EnumerateEntries("/", "*.nca")) - { - IStorage ncaStorage = OpenPossibleFragmentedFile(filesystem, entry.FullPath, OpenMode.Read).AsStorage(); - - Nca nca = new(_virtualFileSystem.KeySet, ncaStorage); - - if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta) - { - IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; - - using var metaFile = new UniqueRef(); - - if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) - { - var meta = new Cnmt(metaFile.Get.AsStream()); - - if (meta.Type == ContentMetaType.SystemUpdate) - { - metaEntries = meta.MetaEntries; - } - } - - continue; - } - else if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) - { - var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - using var systemVersionFile = new UniqueRef(); - - if (romfs.OpenFile(ref systemVersionFile.Ref, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) - { - systemVersion = new SystemVersion(systemVersionFile.Get.AsStream()); - } - } - - if (updateNcas.TryGetValue(nca.Header.TitleId, out var updateNcasItem)) - { - updateNcasItem.Add((nca.Header.ContentType, entry.FullPath)); - } - else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) - { - updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath)); - } - - ncaStorage.Dispose(); - } - - if (metaEntries == null) - { - throw new FileNotFoundException("System update title was not found in the firmware package."); - } - - foreach (CnmtContentMetaEntry metaEntry in metaEntries) - { - if (updateNcas.TryGetValue(metaEntry.TitleId, out var ncaEntry)) - { - string metaNcaPath = ncaEntry.FirstOrDefault(x => x.type == NcaContentType.Meta).path; - string contentPath = ncaEntry.FirstOrDefault(x => x.type != NcaContentType.Meta).path; - - // Nintendo in 9.0.0, removed PPC and only kept the meta nca of it. - // This is a perfect valid case, so we should just ignore the missing content nca and continue. - if (contentPath == null) - { - updateNcas.Remove(metaEntry.TitleId); - - continue; - } - - IStorage metaStorage = OpenPossibleFragmentedFile(filesystem, metaNcaPath, OpenMode.Read).AsStorage(); - IStorage contentStorage = OpenPossibleFragmentedFile(filesystem, contentPath, OpenMode.Read).AsStorage(); - - Nca metaNca = new(_virtualFileSystem.KeySet, metaStorage); - - IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; - - using var metaFile = new UniqueRef(); - - if (fs.OpenFile(ref metaFile.Ref, cnmtPath.ToU8Span(), OpenMode.Read).IsSuccess()) - { - var meta = new Cnmt(metaFile.Get.AsStream()); - - if (contentStorage.GetSize(out long size).IsSuccess()) - { - byte[] contentData = new byte[size]; - - Span content = new(contentData); - - contentStorage.Read(0, content); - - Span hash = new(new byte[32]); - - LibHac.Crypto.Sha256.GenerateSha256Hash(content, hash); - - if (LibHac.Common.Utilities.ArraysEqual(hash.ToArray(), meta.ContentEntries[0].Hash)) - { - updateNcas.Remove(metaEntry.TitleId); - } - } - } - } - } - - if (updateNcas.Count > 0) - { - StringBuilder extraNcas = new(); - - foreach (var entry in updateNcas) - { - foreach (var (type, path) in entry.Value) - { - extraNcas.AppendLine(path); - } - } - - throw new InvalidFirmwarePackageException($"Firmware package contains unrelated archives. Please remove these paths: {Environment.NewLine}{extraNcas}"); - } - - return systemVersion; + return null; } public SystemVersion GetCurrentFirmwareVersion() diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs index 0d69897c1..2928ac7fe 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs @@ -127,7 +127,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return nca.Header.ContentType == NcaContentType.Control; } - public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath, Stream updateStream = null) + public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath) { updatePath = null; @@ -138,38 +138,26 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions // Clear the program index part. ulong titleIdBase = mainNca.GetProgramIdBase(); - IFileSystem updatePartitionFileSystem = null; - - if (updateStream == null) + // Load update information if exists. + string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json"); + if (File.Exists(titleUpdateMetadataPath)) { - // Load update information if exists. - string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json"); - if (File.Exists(titleUpdateMetadataPath)) + updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected; + if (File.Exists(updatePath)) { - updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected; - if (File.Exists(updatePath)) - { - updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem); - } - } - } - else - { - updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updateStream, false, fileSystem); - } + IFileSystem updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem); - if (updatePartitionFileSystem != null) - { - foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel)) - { - if ((applicationTitleId & ~0x1FFFUL) != titleIdBase) + foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel)) { - continue; - } + if ((applicationTitleId & ~0x1FFFUL) != titleIdBase) + { + continue; + } - updatePatchNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Program, programIndex); - updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex); - break; + updatePatchNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Program, programIndex); + updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex); + break; + } } } diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs index aec36d159..b3590d9bd 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/PartitionFileSystemExtensions.cs @@ -52,7 +52,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return programs; } - internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, Stream stream, ulong applicationId, out string errorMessage, string extension, Stream updateStream = null) + internal static (bool, ProcessResult) TryLoad(this PartitionFileSystemCore partitionFileSystem, Switch device, string path, ulong applicationId, out string errorMessage) where TMetaData : PartitionFileSystemMetaCore, new() where TFormat : IPartitionFileSystemFormat where THeader : unmanaged, IPartitionFileSystemHeader @@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return (false, ProcessResult.Failed); } - (Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _, updateStream); + (Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _); if (updatePatchNca != null) { @@ -131,7 +131,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions { if (downloadableContentNca.Enabled) { - device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, stream, downloadableContentNca.FullPath, System.IO.Path.GetExtension(downloadableContentContainer.ContainerPath)); + device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath); } } else diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index ee67a95ee..002926fc9 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -35,12 +35,6 @@ namespace Ryujinx.HLE.Loaders.Processes public bool LoadXci(string path, ulong applicationId) { FileStream stream = new(path, FileMode.Open, FileAccess.Read); - - return LoadXci(stream, applicationId); - } - - public bool LoadXci(Stream stream, ulong applicationId, Stream updateStream = null) - { Xci xci = new(_device.Configuration.VirtualFileSystem.KeySet, stream.AsStorage()); if (!xci.HasPartition(XciPartitionType.Secure)) @@ -50,7 +44,7 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } - (bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, stream, applicationId, out string errorMessage, "xci", updateStream); + (bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, path, applicationId, out string errorMessage); if (!success) { @@ -75,16 +69,10 @@ namespace Ryujinx.HLE.Loaders.Processes public bool LoadNsp(string path, ulong applicationId) { FileStream file = new(path, FileMode.Open, FileAccess.Read); - - return LoadNsp(file, applicationId); - } - - public bool LoadNsp(Stream stream, ulong applicationId, Stream updateStream = null) - { PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(stream.AsStorage()).ThrowIfFailure(); + partitionFileSystem.Initialize(file.AsStorage()).ThrowIfFailure(); - (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, stream, applicationId, out string errorMessage, "nsp", updateStream); + (bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, path, applicationId, out string errorMessage); if (processResult.ProcessId == 0) { @@ -113,13 +101,7 @@ namespace Ryujinx.HLE.Loaders.Processes public bool LoadNca(string path) { FileStream file = new(path, FileMode.Open, FileAccess.Read); - - return LoadNca(file); - } - - public bool LoadNca(Stream ncaStream) - { - Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, ncaStream.AsStorage(false)); + Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); ProcessResult processResult = nca.Load(_device, null, null); @@ -267,109 +249,5 @@ namespace Ryujinx.HLE.Loaders.Processes return false; } - - public bool LoadNxo(Stream stream, bool isNro, string name) - { - var nacpData = new BlitStruct(1); - IFileSystem dummyExeFs = null; - Stream romfsStream = null; - - string programName = ""; - ulong programId = 0000000000000000; - - // Load executable. - IExecutable executable; - - if (isNro) - { - NroExecutable nro = new(stream.AsStorage()); - - executable = nro; - - // Open RomFS if exists. - IStorage romFsStorage = nro.OpenNroAssetSection(LibHac.Tools.Ro.NroAssetType.RomFs, false); - romFsStorage.GetSize(out long romFsSize).ThrowIfFailure(); - if (romFsSize != 0) - { - romfsStream = romFsStorage.AsStream(); - } - - // Load Nacp if exists. - IStorage nacpStorage = nro.OpenNroAssetSection(LibHac.Tools.Ro.NroAssetType.Nacp, false); - nacpStorage.GetSize(out long nacpSize).ThrowIfFailure(); - if (nacpSize != 0) - { - nacpStorage.Read(0, nacpData.ByteSpan); - - programName = nacpData.Value.Title[(int)_device.System.State.DesiredTitleLanguage].NameString.ToString(); - - if (string.IsNullOrWhiteSpace(programName)) - { - programName = Array.Find(nacpData.Value.Title.AsReadOnlySpan().ToArray(), x => x.Name[0] != 0).NameString.ToString(); - } - - if (nacpData.Value.PresenceGroupId != 0) - { - programId = nacpData.Value.PresenceGroupId; - } - else if (nacpData.Value.SaveDataOwnerId != 0) - { - programId = nacpData.Value.SaveDataOwnerId; - } - else if (nacpData.Value.AddOnContentBaseId != 0) - { - programId = nacpData.Value.AddOnContentBaseId - 0x1000; - } - } - - // TODO: Add icon maybe ? - } - else - { - executable = new NsoExecutable(new LocalStorage(name, FileAccess.Read), programName); - } - - // Explicitly null TitleId to disable the shader cache. - Graphics.Gpu.GraphicsConfig.TitleId = null; - _device.Gpu.HostInitalized.Set(); - - ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device, - _device.System.KernelContext, - dummyExeFs.GetNpdm(), - nacpData, - diskCacheEnabled: false, - diskCacheSelector: null, - allowCodeMemoryForJit: true, - programName, - programId, - 0, - null, - executable); - - // Make sure the process id is valid. - if (processResult.ProcessId != 0) - { - // Load RomFS. - if (romfsStream != null) - { - _device.Configuration.VirtualFileSystem.SetRomFs(processResult.ProcessId, romfsStream); - } - - // Start process. - if (_processesByPid.TryAdd(processResult.ProcessId, processResult)) - { - if (processResult.Start(_device)) - { - _latestPid = processResult.ProcessId; - - return true; - } - } - } - - return false; - } - - } } diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index 3b89b34a7..c7c01eb8c 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -11,8 +11,6 @@ using Ryujinx.HLE.Loaders.Processes; using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; -using System.IO; -using System.Threading; namespace Ryujinx.HLE { @@ -119,26 +117,6 @@ namespace Ryujinx.HLE return Processes.LoadNxo(fileName); } - public bool LoadXci(Stream xciStream, ulong applicationId = 0, Stream updateStream = null) - { - return Processes.LoadXci(xciStream, applicationId, updateStream); - } - - public bool LoadNca(Stream ncaStream) - { - return Processes.LoadNca(ncaStream); - } - - public bool LoadNsp(Stream nspStream, ulong applicationId = 0, Stream updateStream = null) - { - return Processes.LoadNsp(nspStream, applicationId, updateStream); - } - - public bool LoadProgram(Stream stream, bool isNro, string name) - { - return Processes.LoadNxo(stream, isNro, name); - } - public bool WaitFifo() { return Gpu.GPFifo.WaitForCommands(); diff --git a/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs b/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs index e2a214da1..3c4ce0850 100644 --- a/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs +++ b/src/Ryujinx.HLE/Utilities/PartitionFileSystemUtils.cs @@ -14,21 +14,16 @@ namespace Ryujinx.HLE.Utilities { FileStream file = File.OpenRead(path); - return OpenApplicationFileSystem(file, Path.GetExtension(path).ToLower() == ".xci", fileSystem, throwOnFailure); - } - - public static IFileSystem OpenApplicationFileSystem(Stream stream, bool isXci, VirtualFileSystem fileSystem, bool throwOnFailure = true) - { IFileSystem partitionFileSystem; - if (isXci) + if (Path.GetExtension(path).ToLower() == ".xci") { - partitionFileSystem = new Xci(fileSystem.KeySet, stream.AsStorage()).OpenPartition(XciPartitionType.Secure); + partitionFileSystem = new Xci(fileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); } else { var pfsTemp = new PartitionFileSystem(); - Result initResult = pfsTemp.Initialize(stream.AsStorage()); + Result initResult = pfsTemp.Initialize(file.AsStorage()); if (throwOnFailure) {