Support loading DLC data from XCIs

This commit is contained in:
gdkchan 2019-01-31 15:55:36 -02:00
parent d191b256a6
commit f59ba2180b
4 changed files with 96 additions and 21 deletions

View file

@ -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();
}
}
}

View file

@ -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;

View file

@ -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))

View file

@ -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;
}