forked from MeloNX/MeloNX
extend stream loading support
(cherry picked from commit cff4a63e5a6deb33734f296b550723f0c6a9a693)
This commit is contained in:
parent
6919b123b7
commit
7de794cf81
src/Ryujinx.HLE
@ -483,6 +483,27 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
FinishInstallation(temporaryDirectory, registeredDirectory);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(registeredDirectory))
|
if (Directory.Exists(registeredDirectory))
|
||||||
@ -601,13 +622,16 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers.");
|
throw new MissingKeyException("HeaderKey is empty. Cannot decrypt NCA headers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new();
|
|
||||||
|
|
||||||
if (Directory.Exists(firmwarePackage))
|
if (Directory.Exists(firmwarePackage))
|
||||||
{
|
{
|
||||||
return VerifyAndGetVersionDirectory(firmwarePackage);
|
return VerifyAndGetVersionDirectory(firmwarePackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
|
||||||
|
{
|
||||||
|
return VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
if (!File.Exists(firmwarePackage))
|
if (!File.Exists(firmwarePackage))
|
||||||
{
|
{
|
||||||
throw new FileNotFoundException("Firmware file does not exist.");
|
throw new FileNotFoundException("Firmware file does not exist.");
|
||||||
@ -615,16 +639,28 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
FileInfo info = new(firmwarePackage);
|
FileInfo info = new(firmwarePackage);
|
||||||
|
|
||||||
|
|
||||||
|
if (info.Extension == ".zip" || info.Extension == ".xci")
|
||||||
|
{
|
||||||
using FileStream file = File.OpenRead(firmwarePackage);
|
using FileStream file = File.OpenRead(firmwarePackage);
|
||||||
|
|
||||||
switch (info.Extension)
|
var isXci = info.Extension == ".xci";
|
||||||
|
|
||||||
|
return VerifyFirmwarePackage(file, isXci);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SystemVersion VerifyFirmwarePackage(Stream file, bool isXci)
|
||||||
{
|
{
|
||||||
case ".zip":
|
if (!isXci)
|
||||||
using (ZipArchive archive = ZipFile.OpenRead(firmwarePackage))
|
|
||||||
{
|
{
|
||||||
|
using ZipArchive archive = new ZipArchive(file, ZipArchiveMode.Read);
|
||||||
return VerifyAndGetVersionZip(archive);
|
return VerifyAndGetVersionZip(archive);
|
||||||
}
|
}
|
||||||
case ".xci":
|
else
|
||||||
|
{
|
||||||
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||||
|
|
||||||
if (xci.HasPartition(XciPartitionType.Update))
|
if (xci.HasPartition(XciPartitionType.Update))
|
||||||
@ -637,17 +673,13 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
throw new InvalidFirmwarePackageException("Update not found in xci file.");
|
throw new InvalidFirmwarePackageException("Update not found in xci file.");
|
||||||
}
|
}
|
||||||
default:
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemVersion VerifyAndGetVersionDirectory(string firmwareDirectory)
|
private SystemVersion VerifyAndGetVersionZip(ZipArchive archive)
|
||||||
{
|
{
|
||||||
return VerifyAndGetVersion(new LocalFileSystem(firmwareDirectory));
|
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new();
|
||||||
}
|
|
||||||
|
|
||||||
SystemVersion VerifyAndGetVersionZip(ZipArchive archive)
|
|
||||||
{
|
|
||||||
SystemVersion systemVersion = null;
|
SystemVersion systemVersion = null;
|
||||||
|
|
||||||
foreach (var entry in archive.Entries)
|
foreach (var entry in archive.Entries)
|
||||||
@ -803,8 +835,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return systemVersion;
|
return systemVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemVersion VerifyAndGetVersion(IFileSystem filesystem)
|
private SystemVersion VerifyAndGetVersion(IFileSystem filesystem)
|
||||||
{
|
{
|
||||||
|
Dictionary<ulong, List<(NcaContentType type, string path)>> updateNcas = new();
|
||||||
|
|
||||||
SystemVersion systemVersion = null;
|
SystemVersion systemVersion = null;
|
||||||
|
|
||||||
CnmtContentMetaEntry[] metaEntries = null;
|
CnmtContentMetaEntry[] metaEntries = null;
|
||||||
@ -935,9 +969,6 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
return systemVersion;
|
return systemVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemVersion GetCurrentFirmwareVersion()
|
public SystemVersion GetCurrentFirmwareVersion()
|
||||||
{
|
{
|
||||||
LoadEntries();
|
LoadEntries();
|
||||||
|
@ -127,7 +127,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
return nca.Header.ContentType == NcaContentType.Control;
|
return nca.Header.ContentType == NcaContentType.Control;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath)
|
public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath, Stream updateStream = null)
|
||||||
{
|
{
|
||||||
updatePath = null;
|
updatePath = null;
|
||||||
|
|
||||||
@ -138,6 +138,10 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
// Clear the program index part.
|
// Clear the program index part.
|
||||||
ulong titleIdBase = mainNca.GetProgramIdBase();
|
ulong titleIdBase = mainNca.GetProgramIdBase();
|
||||||
|
|
||||||
|
IFileSystem updatePartitionFileSystem = null;
|
||||||
|
|
||||||
|
if (updateStream == null)
|
||||||
|
{
|
||||||
// Load update information if exists.
|
// Load update information if exists.
|
||||||
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
|
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
|
||||||
if (File.Exists(titleUpdateMetadataPath))
|
if (File.Exists(titleUpdateMetadataPath))
|
||||||
@ -145,7 +149,14 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
|
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
|
||||||
if (File.Exists(updatePath))
|
if (File.Exists(updatePath))
|
||||||
{
|
{
|
||||||
IFileSystem updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem);
|
updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updateStream, false, fileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel))
|
foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel))
|
||||||
{
|
{
|
||||||
@ -158,8 +169,6 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex);
|
updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (updatePatchNca, updateControlNca);
|
return (updatePatchNca, updateControlNca);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
return programs;
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, Stream stream, ulong applicationId, out string errorMessage, string extension)
|
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, Stream stream, ulong applicationId, out string errorMessage, string extension, Stream updateStream = null)
|
||||||
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
|
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
|
||||||
where TFormat : IPartitionFileSystemFormat
|
where TFormat : IPartitionFileSystemFormat
|
||||||
where THeader : unmanaged, IPartitionFileSystemHeader
|
where THeader : unmanaged, IPartitionFileSystemHeader
|
||||||
@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
return (false, ProcessResult.Failed);
|
return (false, ProcessResult.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _);
|
(Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _, updateStream);
|
||||||
|
|
||||||
if (updatePatchNca != null)
|
if (updatePatchNca != null)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return LoadXci(stream, applicationId);
|
return LoadXci(stream, applicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadXci(Stream stream, ulong applicationId)
|
public bool LoadXci(Stream stream, ulong applicationId, Stream updateStream = null)
|
||||||
{
|
{
|
||||||
Xci xci = new(_device.Configuration.VirtualFileSystem.KeySet, stream.AsStorage());
|
Xci xci = new(_device.Configuration.VirtualFileSystem.KeySet, stream.AsStorage());
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
(bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, stream, applicationId, out string errorMessage, "xci");
|
(bool success, ProcessResult processResult) = xci.OpenPartition(XciPartitionType.Secure).TryLoad(_device, stream, applicationId, out string errorMessage, "xci", updateStream);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@ -79,12 +79,12 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return LoadNsp(file, applicationId);
|
return LoadNsp(file, applicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadNsp(Stream stream, ulong applicationId)
|
public bool LoadNsp(Stream stream, ulong applicationId, Stream updateStream = null)
|
||||||
{
|
{
|
||||||
PartitionFileSystem partitionFileSystem = new();
|
PartitionFileSystem partitionFileSystem = new();
|
||||||
partitionFileSystem.Initialize(stream.AsStorage()).ThrowIfFailure();
|
partitionFileSystem.Initialize(stream.AsStorage()).ThrowIfFailure();
|
||||||
|
|
||||||
(bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, stream, applicationId, out string errorMessage, "nsp");
|
(bool success, ProcessResult processResult) = partitionFileSystem.TryLoad(_device, stream, applicationId, out string errorMessage, "nsp", updateStream);
|
||||||
|
|
||||||
if (processResult.ProcessId == 0)
|
if (processResult.ProcessId == 0)
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ namespace Ryujinx.HLE
|
|||||||
return Processes.LoadNxo(fileName);
|
return Processes.LoadNxo(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadXci(Stream xciStream)
|
public bool LoadXci(Stream xciStream, Stream updateStream = null)
|
||||||
{
|
{
|
||||||
return Processes.LoadXci(xciStream);
|
return Processes.LoadXci(xciStream);
|
||||||
}
|
}
|
||||||
@ -104,9 +104,9 @@ namespace Ryujinx.HLE
|
|||||||
return Processes.LoadNca(ncaStream);
|
return Processes.LoadNca(ncaStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadNsp(Stream nspStream)
|
public bool LoadNsp(Stream nspStream, Stream updateStream = null)
|
||||||
{
|
{
|
||||||
return Processes.LoadNsp(nspStream);
|
return Processes.LoadNsp(nspStream, updateStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadProgram(Stream stream, bool isNro, string name)
|
public bool LoadProgram(Stream stream, bool isNro, string name)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user