Support loading DLC data from XCIs
This commit is contained in:
parent
d191b256a6
commit
f59ba2180b
4 changed files with 96 additions and 21 deletions
|
@ -12,16 +12,21 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
{
|
||||
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
||||
|
||||
private Dictionary<string, long> _sharedFontTitleDictionary;
|
||||
|
||||
private SortedDictionary<(ulong, ContentType), string> _contentDictionary;
|
||||
|
||||
private Dictionary<ulong, (int, Nca)> _currentApplicationAocData;
|
||||
|
||||
private Dictionary<string, long> _sharedFontTitleDictionary;
|
||||
|
||||
private Switch _device;
|
||||
|
||||
public ContentManager(Switch device)
|
||||
{
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
_currentApplicationAocData = new Dictionary<ulong, (int, Nca)>();
|
||||
|
||||
_sharedFontTitleDictionary = new Dictionary<string, long>
|
||||
{
|
||||
|
@ -293,5 +298,34 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
return locationList.ToList().Find(x => x.TitleId == titleId && x.ContentType == contentType);
|
||||
}
|
||||
|
||||
public void SetCurrentApplicationAocData(int index, Nca aocData)
|
||||
{
|
||||
_currentApplicationAocData.Add(aocData.Header.TitleId, (index, aocData));
|
||||
}
|
||||
|
||||
public Nca GetCurrentApplicationAocData(long titleId)
|
||||
{
|
||||
return _currentApplicationAocData[(ulong)titleId].Item2;
|
||||
}
|
||||
|
||||
public int GetCurrentApplicationAocDataCount()
|
||||
{
|
||||
return _currentApplicationAocData.Count;
|
||||
}
|
||||
|
||||
public int[] GetCurrentApplicationAocDataIndices()
|
||||
{
|
||||
List<int> indices = new List<int>();
|
||||
|
||||
foreach ((int index, Nca aocData) tuple in _currentApplicationAocData.Values)
|
||||
{
|
||||
indices.Add(tuple.index);
|
||||
}
|
||||
|
||||
indices.Sort();
|
||||
|
||||
return indices.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,6 +292,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Nca nca = new Nca(KeySet, ncaStorage, true);
|
||||
|
||||
nca.Filename = fileEntry.Name;
|
||||
|
||||
if (nca.Header.ContentType == ContentType.Program)
|
||||
{
|
||||
if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
|
||||
|
@ -303,6 +305,10 @@ namespace Ryujinx.HLE.HOS
|
|||
patchNca = nca;
|
||||
}
|
||||
}
|
||||
else if (nca.Header.ContentType == ContentType.AocData)
|
||||
{
|
||||
ContentManager.SetCurrentApplicationAocData(fileEntry.Index, nca);
|
||||
}
|
||||
else if (nca.Header.ContentType == ContentType.Control)
|
||||
{
|
||||
controlNca = nca;
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return 0;
|
||||
}
|
||||
|
||||
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path)
|
||||
// -> object<nn::fssrv::sf::IFileSystem> contentFs
|
||||
public long OpenFileSystemWithId(ServiceCtx context)
|
||||
{
|
||||
|
@ -151,6 +151,19 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
byte[] padding = context.RequestData.ReadBytes(7);
|
||||
long titleId = context.RequestData.ReadInt64();
|
||||
|
||||
if (storageId == StorageId.None)
|
||||
{
|
||||
Nca nca = context.Device.System.ContentManager.GetCurrentApplicationAocData(titleId);
|
||||
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
|
||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream();
|
||||
|
||||
MakeObject(context, new IStorage(romfsStream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContentType contentType = ContentType.Data;
|
||||
|
||||
StorageId installedStorage =
|
||||
|
@ -175,22 +188,25 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
if (File.Exists(ncaPath))
|
||||
{
|
||||
LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage();
|
||||
Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream();
|
||||
LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage();
|
||||
|
||||
Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);
|
||||
|
||||
NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
|
||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream();
|
||||
|
||||
MakeObject(context, new IStorage(romfsStream));
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}.");
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +237,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
long titleId = context.RequestData.ReadInt64();
|
||||
|
||||
UInt128 userId = new UInt128(
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64(),
|
||||
context.RequestData.ReadInt64());
|
||||
|
||||
long saveId = context.RequestData.ReadInt64();
|
||||
|
@ -297,7 +313,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
Pfs nsp = new Pfs(pfsFile.AsStorage());
|
||||
|
||||
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
|
||||
|
||||
|
||||
string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\');
|
||||
|
||||
if (nsp.FileExists(filename))
|
||||
|
|
|
@ -14,27 +14,46 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
|||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
{ 2, CountAddOnContent },
|
||||
{ 3, ListAddOnContent }
|
||||
{ 2, CountAddOnContent },
|
||||
{ 3, ListAddOnContent },
|
||||
{ 5, GetAddOnContentBaseId },
|
||||
{ 7, PrepareAddOnContent }
|
||||
};
|
||||
}
|
||||
|
||||
public static long CountAddOnContent(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceNs);
|
||||
context.ResponseData.Write(context.Device.System.ContentManager.GetCurrentApplicationAocDataCount());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long ListAddOnContent(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNs);
|
||||
int[] aocIndices = context.Device.System.ContentManager.GetCurrentApplicationAocDataIndices();
|
||||
|
||||
//TODO: This is supposed to write a u32 array aswell.
|
||||
//It's unknown what it contains.
|
||||
context.ResponseData.Write(0);
|
||||
for (int index = 0; index < aocIndices.Length; index++)
|
||||
{
|
||||
long address = context.Request.ReceiveBuff[0].Position + index * 4;
|
||||
|
||||
context.Memory.WriteInt32(address, aocIndices[index]);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(aocIndices.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAddOnContentBaseId(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(context.Process.TitleId + 0x1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long PrepareAddOnContent(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServiceNs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue