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<StorageId, LinkedList<LocationEntry>> _locationEntries;
|
||||||
|
|
||||||
private Dictionary<string, long> _sharedFontTitleDictionary;
|
|
||||||
|
|
||||||
private SortedDictionary<(ulong, ContentType), string> _contentDictionary;
|
private SortedDictionary<(ulong, ContentType), string> _contentDictionary;
|
||||||
|
|
||||||
|
private Dictionary<ulong, (int, Nca)> _currentApplicationAocData;
|
||||||
|
|
||||||
|
private Dictionary<string, long> _sharedFontTitleDictionary;
|
||||||
|
|
||||||
private Switch _device;
|
private Switch _device;
|
||||||
|
|
||||||
public ContentManager(Switch device)
|
public ContentManager(Switch device)
|
||||||
{
|
{
|
||||||
|
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||||
|
|
||||||
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
_contentDictionary = new SortedDictionary<(ulong, ContentType), string>();
|
||||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
|
||||||
|
_currentApplicationAocData = new Dictionary<ulong, (int, Nca)>();
|
||||||
|
|
||||||
_sharedFontTitleDictionary = new Dictionary<string, long>
|
_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);
|
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 nca = new Nca(KeySet, ncaStorage, true);
|
||||||
|
|
||||||
|
nca.Filename = fileEntry.Name;
|
||||||
|
|
||||||
if (nca.Header.ContentType == ContentType.Program)
|
if (nca.Header.ContentType == ContentType.Program)
|
||||||
{
|
{
|
||||||
if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
|
if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
|
||||||
|
@ -303,6 +305,10 @@ namespace Ryujinx.HLE.HOS
|
||||||
patchNca = nca;
|
patchNca = nca;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (nca.Header.ContentType == ContentType.AocData)
|
||||||
|
{
|
||||||
|
ContentManager.SetCurrentApplicationAocData(fileEntry.Index, nca);
|
||||||
|
}
|
||||||
else if (nca.Header.ContentType == ContentType.Control)
|
else if (nca.Header.ContentType == ContentType.Control)
|
||||||
{
|
{
|
||||||
controlNca = nca;
|
controlNca = nca;
|
||||||
|
|
|
@ -151,6 +151,19 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||||
byte[] padding = context.RequestData.ReadBytes(7);
|
byte[] padding = context.RequestData.ReadBytes(7);
|
||||||
long titleId = context.RequestData.ReadInt64();
|
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;
|
ContentType contentType = ContentType.Data;
|
||||||
|
|
||||||
StorageId installedStorage =
|
StorageId installedStorage =
|
||||||
|
@ -175,10 +188,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||||
|
|
||||||
if (File.Exists(ncaPath))
|
if (File.Exists(ncaPath))
|
||||||
{
|
{
|
||||||
LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage();
|
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);
|
Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);
|
||||||
Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream();
|
|
||||||
|
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));
|
MakeObject(context, new IStorage(romfsStream));
|
||||||
|
|
||||||
|
|
|
@ -14,27 +14,46 @@ namespace Ryujinx.HLE.HOS.Services.Ns
|
||||||
{
|
{
|
||||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||||
{
|
{
|
||||||
{ 2, CountAddOnContent },
|
{ 2, CountAddOnContent },
|
||||||
{ 3, ListAddOnContent }
|
{ 3, ListAddOnContent },
|
||||||
|
{ 5, GetAddOnContentBaseId },
|
||||||
|
{ 7, PrepareAddOnContent }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long CountAddOnContent(ServiceCtx context)
|
public static long CountAddOnContent(ServiceCtx context)
|
||||||
{
|
{
|
||||||
context.ResponseData.Write(0);
|
context.ResponseData.Write(context.Device.System.ContentManager.GetCurrentApplicationAocDataCount());
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceNs);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long ListAddOnContent(ServiceCtx context)
|
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.
|
for (int index = 0; index < aocIndices.Length; index++)
|
||||||
//It's unknown what it contains.
|
{
|
||||||
context.ResponseData.Write(0);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue