Implements proper save path (#386)

* initial save path implementation

* fix savedatatype offset, remove incomplete createsavedata implimentation

* address nits

* fix crash if npdm is not found

* made saveinfo readonly, other stuff

* remove context param from saveinfo contructor

* fix style

* remove whitespace
This commit is contained in:
emmauss 2018-09-09 01:04:26 +03:00 committed by gdkchan
parent 3227218114
commit fc77b089a6
8 changed files with 145 additions and 19 deletions

View file

@ -0,0 +1,12 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveDataType : byte
{
SystemSaveData,
SaveData,
BcatDeliveryCacheStorage,
DeviceSaveData,
TemporaryStorage,
CacheStorage
}
}

View file

@ -0,0 +1,46 @@
using Ryujinx.HLE.HOS;
using System.IO;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
namespace Ryujinx.HLE.FileSystem
{
static class SaveHelper
{
public static string GetSavePath(SaveInfo SaveMetaData, ServiceCtx Context)
{
string BaseSavePath = NandPath;
long CurrentTitleId = SaveMetaData.TitleId;
switch (SaveMetaData.SaveSpaceId)
{
case SaveSpaceId.NandUser:
BaseSavePath = UserNandPath;
break;
case SaveSpaceId.NandSystem:
BaseSavePath = SystemNandPath;
break;
case SaveSpaceId.SdCard:
BaseSavePath = Path.Combine(SdCardPath, "Nintendo");
break;
}
BaseSavePath = Path.Combine(BaseSavePath, "save");
if (SaveMetaData.TitleId == 0 && SaveMetaData.SaveDataType == SaveDataType.SaveData)
{
if (Context.Process.MetaData != null)
{
CurrentTitleId = Context.Process.MetaData.ACI0.TitleId;
}
}
string SavePath = Path.Combine(BaseSavePath,
SaveMetaData.SaveId.ToString("x16"),
SaveMetaData.UserId.ToString(),
SaveMetaData.SaveDataType == SaveDataType.SaveData ? CurrentTitleId.ToString("x16") : string.Empty);
return SavePath;
}
}
}

View file

@ -0,0 +1,28 @@
using Ryujinx.HLE.HOS.SystemState;
namespace Ryujinx.HLE.FileSystem
{
struct SaveInfo
{
public long TitleId { get; private set; }
public long SaveId { get; private set; }
public UserId UserId { get; private set; }
public SaveDataType SaveDataType { get; private set; }
public SaveSpaceId SaveSpaceId { get; private set; }
public SaveInfo(
long TitleId,
long SaveId,
SaveDataType SaveDataType,
UserId UserId,
SaveSpaceId SaveSpaceId)
{
this.TitleId = TitleId;
this.UserId = UserId;
this.SaveId = SaveId;
this.SaveDataType = SaveDataType;
this.SaveSpaceId = SaveSpaceId;
}
}
}

View file

@ -0,0 +1,10 @@
namespace Ryujinx.HLE.FileSystem
{
enum SaveSpaceId : byte
{
NandSystem,
NandUser,
SdCard,
TemporaryStorage
}
}

View file

@ -0,0 +1,132 @@
using Ryujinx.HLE.HOS;
using System;
using System.IO;
namespace Ryujinx.HLE.FileSystem
{
class VirtualFileSystem : IDisposable
{
public const string BasePath = "RyuFs";
public const string NandPath = "nand";
public const string SdCardPath = "sdmc";
public const string SystemPath = "system";
public static string SystemNandPath = Path.Combine(NandPath, "system");
public static string UserNandPath = Path.Combine(NandPath, "user");
public Stream RomFs { get; private set; }
public void LoadRomFs(string FileName)
{
RomFs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
}
public void SetRomFs(Stream RomfsStream)
{
RomFs?.Close();
RomFs = RomfsStream;
}
public string GetFullPath(string BasePath, string FileName)
{
if (FileName.StartsWith("//"))
{
FileName = FileName.Substring(2);
}
else if (FileName.StartsWith('/'))
{
FileName = FileName.Substring(1);
}
else
{
return null;
}
string FullPath = Path.GetFullPath(Path.Combine(BasePath, FileName));
if (!FullPath.StartsWith(GetBasePath()))
{
return null;
}
return FullPath;
}
public string GetSdCardPath() => MakeDirAndGetFullPath(SdCardPath);
public string GetNandPath() => MakeDirAndGetFullPath(NandPath);
public string GetSystemPath() => MakeDirAndGetFullPath(SystemPath);
public string GetGameSavePath(SaveInfo Save, ServiceCtx Context)
{
return MakeDirAndGetFullPath(SaveHelper.GetSavePath(Save, Context));
}
public string SwitchPathToSystemPath(string SwitchPath)
{
string[] Parts = SwitchPath.Split(":");
if (Parts.Length != 2)
{
return null;
}
return GetFullPath(MakeDirAndGetFullPath(Parts[0]), Parts[1]);
}
public string SystemPathToSwitchPath(string SystemPath)
{
string BaseSystemPath = GetBasePath() + Path.DirectorySeparatorChar;
if (SystemPath.StartsWith(BaseSystemPath))
{
string RawPath = SystemPath.Replace(BaseSystemPath, "");
int FirstSeparatorOffset = RawPath.IndexOf(Path.DirectorySeparatorChar);
if (FirstSeparatorOffset == -1)
{
return $"{RawPath}:/";
}
string BasePath = RawPath.Substring(0, FirstSeparatorOffset);
string FileName = RawPath.Substring(FirstSeparatorOffset + 1);
return $"{BasePath}:/{FileName}";
}
return null;
}
private string MakeDirAndGetFullPath(string Dir)
{
string FullPath = Path.Combine(GetBasePath(), Dir);
if (!Directory.Exists(FullPath))
{
Directory.CreateDirectory(FullPath);
}
return FullPath;
}
public DriveInfo GetDrive()
{
return new DriveInfo(Path.GetPathRoot(GetBasePath()));
}
public string GetBasePath()
{
string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
return Path.Combine(AppDataPath, BasePath);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
RomFs?.Dispose();
}
}
}
}