feat: add support for offline html docs inside the browser applet
This commit is contained in:
parent
f73a7dce4f
commit
7fe5035e88
@ -522,24 +522,21 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
internal RealApplet GetApplicationApplet()
|
||||
{
|
||||
RealApplet applet = null;
|
||||
lock (_lock)
|
||||
if (_application != null)
|
||||
{
|
||||
foreach (var (_, value) in _applets)
|
||||
return _application;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_homeMenu != null)
|
||||
{
|
||||
if (value.IsApplication)
|
||||
{
|
||||
applet = value;
|
||||
break;
|
||||
}
|
||||
return _homeMenu;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _overlayDisp;
|
||||
}
|
||||
}
|
||||
|
||||
if (applet == null)
|
||||
{
|
||||
return _foregroundRequestedApplet;
|
||||
}
|
||||
return applet;
|
||||
}
|
||||
|
||||
public void RemoveProcess(ulong processHandlePid)
|
||||
|
@ -218,6 +218,14 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Lib
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(51)]
|
||||
// ReportVisibleErrorWithErrorContext(nn::err::ErrorCode)
|
||||
public ResultCode ReportVisibleErrorWithErrorContext(ServiceCtx context)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(60)]
|
||||
// GetMainAppletApplicationDesiredLanguage() -> nn::os::Language
|
||||
public ResultCode GetMainAppletApplicationDesiredLanguage(ServiceCtx context)
|
||||
|
@ -26,8 +26,11 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
// GetAppletResourceUserIdOfCallerApplet() -> nn::applet::AppletResourceUserId
|
||||
public ResultCode GetAppletResourceUserIdOfCallerApplet(ServiceCtx context)
|
||||
{
|
||||
ulong appletResourceUserId = _pid;
|
||||
appletResourceUserId = context.Device.System.WindowSystem.GetByAruId(_pid).CallerApplet.ProcessHandle.TitleId;
|
||||
ulong appletResourceUserId = 0x0100000000001000;
|
||||
if (context.Device.System.WindowSystem.GetApplicationApplet() != null)
|
||||
{
|
||||
appletResourceUserId = context.Device.System.WindowSystem.GetApplicationApplet().ProcessHandle.TitleId;
|
||||
}
|
||||
context.ResponseData.Write(appletResourceUserId);
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { appletResourceUserId });
|
||||
return ResultCode.Success;
|
||||
|
@ -5,15 +5,21 @@ using LibHac.Fs;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Spl;
|
||||
using LibHac.Tools.Es;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.Loaders.Processes;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using ApplicationId = LibHac.ApplicationId;
|
||||
using ContentType = LibHac.Fs.ContentType;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
@ -72,6 +78,172 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public static ResultCode OpenXciHtml(ServiceCtx context, ulong applicationId, Switch device, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem)
|
||||
{
|
||||
openedFileSystem = null;
|
||||
|
||||
try
|
||||
{
|
||||
Xci xci = new(context.Device.System.KeySet, ncaStorage);
|
||||
|
||||
if (!xci.HasPartition(XciPartitionType.Secure))
|
||||
{
|
||||
return ResultCode.PartitionNotFound;
|
||||
}
|
||||
|
||||
var partitionFileSystem = xci.OpenPartition(XciPartitionType.Secure);
|
||||
|
||||
Nca nca = null;
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<ulong, ContentMetaData> applications = partitionFileSystem.GetContentData(ContentMetaType.Application, device.FileSystem, device.System.FsIntegrityCheckLevel);
|
||||
|
||||
if (applicationId == 0)
|
||||
{
|
||||
foreach ((ulong _, ContentMetaData content) in applications)
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (applications.TryGetValue(applicationId, out ContentMetaData content))
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
}
|
||||
|
||||
ProcessLoaderHelper.RegisterProgramMapInfo(device, partitionFileSystem).ThrowIfFailure();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ResultCode.InvalidInput;
|
||||
}
|
||||
|
||||
LibHac.Fs.Fsa.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
|
||||
using SharedRef<LibHac.Fs.Fsa.IFileSystem> sharedFs = new(fileSystem);
|
||||
|
||||
using SharedRef<LibHac.FsSrv.Sf.IFileSystem> adapter = FileSystemInterfaceAdapter.CreateShared(ref sharedFs.Ref, true);
|
||||
|
||||
openedFileSystem = new IFileSystem(ref adapter.Ref);
|
||||
return ResultCode.Success;
|
||||
|
||||
}
|
||||
catch (HorizonResultException ex)
|
||||
{
|
||||
return (ResultCode)ex.ResultValue.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static ResultCode OpenNspHtml(ServiceCtx context, string nspPath, ulong applicationId, Switch device, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem)
|
||||
{
|
||||
openedFileSystem = null;
|
||||
|
||||
try
|
||||
{
|
||||
LocalStorage storage = new(nspPath, FileAccess.Read, FileMode.Open);
|
||||
PartitionFileSystem pfs = new();
|
||||
using SharedRef<LibHac.Fs.Fsa.IFileSystem> nsp = new(pfs);
|
||||
pfs.Initialize(storage).ThrowIfFailure();
|
||||
|
||||
ImportTitleKeysFromNsp(nsp.Get, context.Device.System.KeySet);
|
||||
Nca nca = null;
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<ulong, ContentMetaData> applications = nsp.Get.GetContentData(ContentMetaType.Application, device.FileSystem, device.System.FsIntegrityCheckLevel);
|
||||
|
||||
if (applicationId == 0)
|
||||
{
|
||||
foreach ((ulong _, ContentMetaData content) in applications)
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (applications.TryGetValue(applicationId, out ContentMetaData content))
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
}
|
||||
|
||||
ProcessLoaderHelper.RegisterProgramMapInfo(device, nsp.Get).ThrowIfFailure();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ResultCode.InvalidInput;
|
||||
}
|
||||
|
||||
LibHac.Fs.Fsa.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
|
||||
using SharedRef<LibHac.Fs.Fsa.IFileSystem> sharedFs = new(fileSystem);
|
||||
|
||||
using SharedRef<LibHac.FsSrv.Sf.IFileSystem> adapter = FileSystemInterfaceAdapter.CreateShared(ref sharedFs.Ref, true);
|
||||
|
||||
openedFileSystem = new IFileSystem(ref adapter.Ref);
|
||||
return ResultCode.Success;
|
||||
|
||||
}
|
||||
catch (HorizonResultException ex)
|
||||
{
|
||||
return (ResultCode)ex.ResultValue.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static ResultCode OpenNcaHtml(ServiceCtx context, string nspPath, ulong applicationId, Switch device, LibHac.Fs.IStorage ncaStorage, out IFileSystem openedFileSystem)
|
||||
{
|
||||
openedFileSystem = null;
|
||||
|
||||
try
|
||||
{
|
||||
Nca ncaApp = new(context.Device.System.KeySet, ncaStorage);
|
||||
|
||||
if (!ncaApp.SectionExists(NcaSectionType.Data))
|
||||
{
|
||||
return ResultCode.PartitionNotFound;
|
||||
}
|
||||
|
||||
LibHac.Fs.Fsa.IFileSystem fileSystemB = ncaApp.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
|
||||
|
||||
Nca nca = null;
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<ulong, ContentMetaData> applications = fileSystemB.GetContentData(ContentMetaType.Application, device.FileSystem, device.System.FsIntegrityCheckLevel);
|
||||
|
||||
if (applicationId == 0)
|
||||
{
|
||||
foreach ((ulong _, ContentMetaData content) in applications)
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (applications.TryGetValue(applicationId, out ContentMetaData content))
|
||||
{
|
||||
nca = content.GetNcaByType(device.FileSystem.KeySet, LibHac.Ncm.ContentType.HtmlDocument, device.Configuration.UserChannelPersistence.Index);
|
||||
}
|
||||
|
||||
ProcessLoaderHelper.RegisterProgramMapInfo(device, fileSystemB).ThrowIfFailure();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ResultCode.InvalidInput;
|
||||
}
|
||||
|
||||
LibHac.Fs.Fsa.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
|
||||
using SharedRef<LibHac.Fs.Fsa.IFileSystem> sharedFs = new(fileSystem);
|
||||
|
||||
using SharedRef<LibHac.FsSrv.Sf.IFileSystem> adapter = FileSystemInterfaceAdapter.CreateShared(ref sharedFs.Ref, true);
|
||||
|
||||
openedFileSystem = new IFileSystem(ref adapter.Ref);
|
||||
return ResultCode.Success;
|
||||
|
||||
}
|
||||
catch (HorizonResultException ex)
|
||||
{
|
||||
return (ResultCode)ex.ResultValue.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static ResultCode OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath, out IFileSystem openedFileSystem)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ using LibHac.FsSystem;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Sf;
|
||||
using LibHac.Spl;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common;
|
||||
@ -15,6 +16,7 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy;
|
||||
using Ryujinx.HLE.HOS.Services.Ns.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Pcv;
|
||||
using Ryujinx.HLE.Loaders.Processes;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.IO;
|
||||
@ -52,8 +54,14 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
// OpenFileSystemWithPatch(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid) -> object<nn::fssrv::sf::IFileSystem> contentFs
|
||||
public ResultCode OpenFileSystemWithPatch(ServiceCtx context)
|
||||
{
|
||||
// TODO: Find out why the title id read from here is incorrect.
|
||||
FileSystemType fileSystemType = (FileSystemType)context.RequestData.ReadInt32();
|
||||
ulong titleId = context.RequestData.ReadUInt64();
|
||||
ulong titleId = 0x0100000000001000;
|
||||
if (context.Device.System.WindowSystem.GetApplicationApplet() != null)
|
||||
{
|
||||
titleId = context.Device.System.WindowSystem.GetApplicationApplet().ProcessHandle.TitleId;
|
||||
}
|
||||
Logger.Info?.Print(LogClass.ServiceAm, $" { titleId} {fileSystemType} ");
|
||||
string switchPath = string.Empty;
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFs);
|
||||
foreach (RyuApplicationData ryuApplicationData in context.Device.Configuration.Titles)
|
||||
@ -70,14 +78,75 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
return ResultCode.PathDoesNotExist;
|
||||
}
|
||||
string fullPath = FileSystem.VirtualFileSystem.SwitchPathToSystemPath(switchPath);
|
||||
ResultCode result = FileSystemProxyHelper.OpenFileSystemFromInternalFile(context, fullPath, out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
if (fullPath == null)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
fullPath = switchPath;
|
||||
}
|
||||
FileStream fileStream = new(fullPath, FileMode.Open, FileAccess.Read);
|
||||
string extension = System.IO.Path.GetExtension(fullPath);
|
||||
|
||||
return result;
|
||||
if (fileSystemType == FileSystemType.ContentManual)
|
||||
{
|
||||
if (extension == ".xci")
|
||||
{
|
||||
ResultCode result = FileSystemProxyHelper.OpenXciHtml(context, titleId, context.Device,fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (extension == ".nsp")
|
||||
{
|
||||
ResultCode result = FileSystemProxyHelper.OpenNspHtml(context, fullPath, titleId, context.Device,fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResultCode result = FileSystemProxyHelper.OpenNcaHtml(context, fullPath, titleId, context.Device,fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (extension == ".nca")
|
||||
{
|
||||
ResultCode result = FileSystemProxyHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (extension == ".nsp")
|
||||
{
|
||||
ResultCode result = FileSystemProxyHelper.OpenNsp(context, fullPath, out FileSystemProxy.IFileSystem fileSystem);
|
||||
|
||||
if (result == ResultCode.Success)
|
||||
{
|
||||
MakeObject(context, fileSystem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return ResultCode.InvalidInput;
|
||||
}
|
||||
|
||||
[CommandCmif(8)]
|
||||
|
@ -16,7 +16,13 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
||||
// GetRunningApplicationProgramId() -> u64
|
||||
public ResultCode GetRunningApplicationProgramId(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(context.Device.Processes.ActiveApplication.ProgramId);
|
||||
ulong appletResourceUserId = 0x0100000000001000;
|
||||
if (context.Device.System.WindowSystem.GetApplicationApplet() != null)
|
||||
{
|
||||
appletResourceUserId = context.Device.System.WindowSystem.GetApplicationApplet().ProcessHandle.TitleId;
|
||||
}
|
||||
|
||||
context.ResponseData.Write(appletResourceUserId);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Ns
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Ns
|
||||
{
|
||||
class IReadOnlyApplicationRecordInterface : IpcService
|
||||
{
|
||||
|
||||
[CommandCmif(2)] // 10.0.0+
|
||||
// IsDataCorruptedResult() -> bool
|
||||
public ResultCode IsDataCorrupted(ServiceCtx context)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceNs);
|
||||
context.ResponseData.Write(false);
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user