mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add some SaveDataInfoReader functions
This commit is contained in:
parent
3af543e4e1
commit
f0aac13fab
10 changed files with 426 additions and 36 deletions
|
@ -108,7 +108,7 @@ namespace LibHac.Fs
|
||||||
int mountLen = 0;
|
int mountLen = 0;
|
||||||
int maxMountLen = Math.Min(path.Length, PathTools.MountNameLength);
|
int maxMountLen = Math.Min(path.Length, PathTools.MountNameLength);
|
||||||
|
|
||||||
for (int i = 0; i < maxMountLen; i++)
|
for (int i = 0; i <= maxMountLen; i++)
|
||||||
{
|
{
|
||||||
if (path[i] == PathTools.MountSeparator)
|
if (path[i] == PathTools.MountSeparator)
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@ namespace LibHac.Fs
|
||||||
mountName = default;
|
mountName = default;
|
||||||
subPath = default;
|
subPath = default;
|
||||||
|
|
||||||
return ResultFs.InvalidMountName;
|
return ResultFs.InvalidMountName.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
mountName = path.Slice(0, mountLen);
|
mountName = path.Slice(0, mountLen);
|
||||||
|
|
|
@ -97,6 +97,8 @@
|
||||||
public static Result InvalidMountName => new Result(ModuleFs, 6065);
|
public static Result InvalidMountName => new Result(ModuleFs, 6065);
|
||||||
public static Result ExtensionSizeTooLarge => new Result(ModuleFs, 6066);
|
public static Result ExtensionSizeTooLarge => new Result(ModuleFs, 6066);
|
||||||
public static Result ExtensionSizeInvalid => new Result(ModuleFs, 6067);
|
public static Result ExtensionSizeInvalid => new Result(ModuleFs, 6067);
|
||||||
|
public static Result ReadOldSaveDataInfoReader => new Result(ModuleFs, 6068);
|
||||||
|
public static Result InvalidSaveDataSpaceId => new Result(ModuleFs, 6082);
|
||||||
|
|
||||||
public static Result InvalidOpenModeOperation => new Result(ModuleFs, 6200);
|
public static Result InvalidOpenModeOperation => new Result(ModuleFs, 6200);
|
||||||
public static Result FileExtensionWithoutOpenModeAllowAppend => new Result(ModuleFs, 6201);
|
public static Result FileExtensionWithoutOpenModeAllowAppend => new Result(ModuleFs, 6201);
|
||||||
|
|
|
@ -78,30 +78,6 @@ namespace LibHac.Fs
|
||||||
[FieldOffset(0x2A)] public short Index;
|
[FieldOffset(0x2A)] public short Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = 0x50)]
|
|
||||||
public struct SaveDataFilterInternal
|
|
||||||
{
|
|
||||||
[FieldOffset(0x00)] public bool FilterBySaveDataSpaceId;
|
|
||||||
[FieldOffset(0x01)] public SaveDataSpaceId SpaceId;
|
|
||||||
|
|
||||||
[FieldOffset(0x08)] public bool FilterByTitleId;
|
|
||||||
[FieldOffset(0x10)] public TitleId TitleID;
|
|
||||||
|
|
||||||
[FieldOffset(0x18)] public bool FilterBySaveDataType;
|
|
||||||
[FieldOffset(0x19)] public SaveDataType SaveDataType;
|
|
||||||
|
|
||||||
[FieldOffset(0x20)] public bool FilterByUserId;
|
|
||||||
[FieldOffset(0x28)] public UserId UserId;
|
|
||||||
|
|
||||||
[FieldOffset(0x38)] public bool FilterBySaveDataId;
|
|
||||||
[FieldOffset(0x40)] public ulong SaveDataId;
|
|
||||||
|
|
||||||
[FieldOffset(0x48)] public bool FilterByIndex;
|
|
||||||
[FieldOffset(0x4A)] public short Index;
|
|
||||||
|
|
||||||
[FieldOffset(0x4C)] public int Rank;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Size = HashLength)]
|
[StructLayout(LayoutKind.Explicit, Size = HashLength)]
|
||||||
public struct HashSalt
|
public struct HashSalt
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
using LibHac.FsService;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.FsService;
|
||||||
using LibHac.FsSystem.Save;
|
using LibHac.FsSystem.Save;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
|
|
||||||
|
@ -159,6 +162,63 @@ namespace LibHac.Fs.Shim
|
||||||
() => $", savedataspaceid: {spaceId}, savedataid: 0x{saveDataId:X}");
|
() => $", savedataspaceid: {spaceId}, savedataid: 0x{saveDataId:X}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Result FindSaveDataWithFilter(this FileSystemClient fs, out SaveDataInfo info, SaveDataSpaceId spaceId,
|
||||||
|
ref SaveDataFilter filter)
|
||||||
|
{
|
||||||
|
info = default;
|
||||||
|
|
||||||
|
SaveDataFilter tempFilter = filter;
|
||||||
|
var tempInfo = new SaveDataInfo();
|
||||||
|
|
||||||
|
Result result = fs.RunOperationWithAccessLog(LocalAccessLogMode.System,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||||
|
|
||||||
|
tempInfo = new SaveDataInfo();
|
||||||
|
|
||||||
|
Result rc = fsProxy.FindSaveDataWithFilter(out long count, SpanHelpers.AsByteSpan(ref tempInfo),
|
||||||
|
spaceId, ref tempFilter);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return ResultFs.TargetNotFound.Log();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
},
|
||||||
|
() => $", savedataspaceid: {spaceId}");
|
||||||
|
|
||||||
|
if (result.IsSuccess())
|
||||||
|
{
|
||||||
|
info = tempInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result OpenSaveDataIterator(this FileSystemClient fs, out SaveDataIterator iterator, SaveDataSpaceId spaceId)
|
||||||
|
{
|
||||||
|
var tempIterator = new SaveDataIterator();
|
||||||
|
|
||||||
|
Result result = fs.RunOperationWithAccessLog(LocalAccessLogMode.System,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
IFileSystemProxy fsProxy = fs.GetFileSystemProxyServiceObject();
|
||||||
|
|
||||||
|
Result rc = fsProxy.OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader reader, spaceId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
tempIterator = new SaveDataIterator(fs, reader);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
},
|
||||||
|
() => $", savedataspaceid: {spaceId}");
|
||||||
|
|
||||||
|
iterator = result.IsSuccess() ? tempIterator : default;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static Result DisableAutoSaveDataCreation(this FileSystemClient fsClient)
|
public static Result DisableAutoSaveDataCreation(this FileSystemClient fsClient)
|
||||||
{
|
{
|
||||||
IFileSystemProxy fsProxy = fsClient.GetFileSystemProxyServiceObject();
|
IFileSystemProxy fsProxy = fsClient.GetFileSystemProxyServiceObject();
|
||||||
|
@ -166,4 +226,38 @@ namespace LibHac.Fs.Shim
|
||||||
return fsProxy.DisableAutoSaveDataCreation();
|
return fsProxy.DisableAutoSaveDataCreation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct SaveDataIterator
|
||||||
|
{
|
||||||
|
private FileSystemClient FsClient { get; }
|
||||||
|
private ISaveDataInfoReader Reader { get; }
|
||||||
|
|
||||||
|
internal SaveDataIterator(FileSystemClient fsClient, ISaveDataInfoReader reader)
|
||||||
|
{
|
||||||
|
FsClient = fsClient;
|
||||||
|
Reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ReadSaveDataInfo(out long readCount, Span<SaveDataInfo> buffer)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
|
||||||
|
Span<byte> byteBuffer = MemoryMarshal.Cast<SaveDataInfo, byte>(buffer);
|
||||||
|
|
||||||
|
if (FsClient.IsEnabledAccessLog(LocalAccessLogMode.System))
|
||||||
|
{
|
||||||
|
TimeSpan startTime = FsClient.Time.GetCurrent();
|
||||||
|
rc = Reader.ReadSaveDataInfo(out readCount, byteBuffer);
|
||||||
|
TimeSpan endTime = FsClient.Time.GetCurrent();
|
||||||
|
|
||||||
|
FsClient.OutputAccessLog(rc, startTime, endTime, $", size: {buffer.Length}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = Reader.ReadSaveDataInfo(out readCount, byteBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
@ -707,7 +708,34 @@ namespace LibHac.FsService
|
||||||
|
|
||||||
public Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId)
|
public Result OpenSaveDataInfoReaderBySaveDataSpaceId(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
infoReader = default;
|
||||||
|
|
||||||
|
// Missing permission check
|
||||||
|
|
||||||
|
SaveDataIndexerReader indexReader = default;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Result rc = FsServer.SaveDataIndexerManager.GetSaveDataIndexer(out indexReader, spaceId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = indexReader.Indexer.OpenSaveDataInfoReader(out ISaveDataInfoReader baseInfoReader);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var filter = new SaveDataFilterInternal
|
||||||
|
{
|
||||||
|
FilterBySaveDataSpaceId = true,
|
||||||
|
SpaceId = GetSpaceIdForIndexer(spaceId)
|
||||||
|
};
|
||||||
|
|
||||||
|
infoReader = new SaveDataInfoFilterReader(baseInfoReader, ref filter);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
indexReader.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenSaveDataInfoReaderWithFilter(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId,
|
public Result OpenSaveDataInfoReaderWithFilter(out ISaveDataInfoReader infoReader, SaveDataSpaceId spaceId,
|
||||||
|
@ -719,7 +747,46 @@ namespace LibHac.FsService
|
||||||
public Result FindSaveDataWithFilter(out long count, Span<byte> saveDataInfoBuffer, SaveDataSpaceId spaceId,
|
public Result FindSaveDataWithFilter(out long count, Span<byte> saveDataInfoBuffer, SaveDataSpaceId spaceId,
|
||||||
ref SaveDataFilter filter)
|
ref SaveDataFilter filter)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
count = default;
|
||||||
|
|
||||||
|
if (saveDataInfoBuffer.Length != Unsafe.SizeOf<SaveDataInfo>())
|
||||||
|
{
|
||||||
|
return ResultFs.InvalidArgument.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing permission check
|
||||||
|
|
||||||
|
var internalFilter = new SaveDataFilterInternal(ref filter, GetSpaceIdForIndexer(spaceId));
|
||||||
|
|
||||||
|
ref SaveDataInfo saveDataInfo = ref Unsafe.As<byte, SaveDataInfo>(ref saveDataInfoBuffer[0]);
|
||||||
|
|
||||||
|
return FindSaveDataWithFilterImpl(out count, out saveDataInfo, spaceId, ref internalFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result FindSaveDataWithFilterImpl(out long count, out SaveDataInfo info, SaveDataSpaceId spaceId,
|
||||||
|
ref SaveDataFilterInternal filter)
|
||||||
|
{
|
||||||
|
count = default;
|
||||||
|
info = default;
|
||||||
|
|
||||||
|
SaveDataIndexerReader indexReader = default;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Result rc = FsServer.SaveDataIndexerManager.GetSaveDataIndexer(out indexReader, spaceId);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = indexReader.Indexer.OpenSaveDataInfoReader(out ISaveDataInfoReader baseInfoReader);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var infoReader = new SaveDataInfoFilterReader(baseInfoReader, ref filter);
|
||||||
|
|
||||||
|
return infoReader.ReadSaveDataInfo(out count, SpanHelpers.AsByteSpan(ref info));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
indexReader.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
public Result OpenSaveDataInternalStorageFileSystem(out IFileSystem fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
|
|
@ -15,5 +15,6 @@ namespace LibHac.FsService
|
||||||
Result SetState(ulong saveDataId, SaveDataState state);
|
Result SetState(ulong saveDataId, SaveDataState state);
|
||||||
Result GetKey(out SaveDataAttribute key, ulong saveDataId);
|
Result GetKey(out SaveDataAttribute key, ulong saveDataId);
|
||||||
Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId);
|
Result GetBySaveDataId(out SaveDataIndexerValue value, ulong saveDataId);
|
||||||
|
Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.Fs.Shim;
|
using LibHac.Fs.Shim;
|
||||||
|
@ -23,6 +25,7 @@ namespace LibHac.FsService
|
||||||
private bool IsInitialized { get; set; }
|
private bool IsInitialized { get; set; }
|
||||||
private bool IsKvdbLoaded { get; set; }
|
private bool IsKvdbLoaded { get; set; }
|
||||||
private ulong LastPublishedId { get; set; }
|
private ulong LastPublishedId { get; set; }
|
||||||
|
private int Version { get; set; }
|
||||||
|
|
||||||
public SaveDataIndexer(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, ulong saveDataId)
|
public SaveDataIndexer(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +33,7 @@ namespace LibHac.FsService
|
||||||
MountName = mountName;
|
MountName = mountName;
|
||||||
SaveDataId = saveDataId;
|
SaveDataId = saveDataId;
|
||||||
SpaceId = spaceId;
|
SpaceId = spaceId;
|
||||||
|
Version = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetSaveDataInfo(out SaveDataInfo info, ref SaveDataAttribute key, ref SaveDataIndexerValue value)
|
public static void GetSaveDataInfo(out SaveDataInfo info, ref SaveDataAttribute key, ref SaveDataIndexerValue value)
|
||||||
|
@ -140,6 +144,9 @@ namespace LibHac.FsService
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = AdjustOpenedInfoReaders(ref key);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
saveDataId = newSaveDataId;
|
saveDataId = newSaveDataId;
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
@ -194,11 +201,10 @@ namespace LibHac.FsService
|
||||||
};
|
};
|
||||||
|
|
||||||
rc = KvDatabase.Set(ref key, SpanHelpers.AsByteSpan(ref newValue));
|
rc = KvDatabase.Set(ref key, SpanHelpers.AsByteSpan(ref newValue));
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
if (rc.IsFailure())
|
rc = AdjustOpenedInfoReaders(ref key);
|
||||||
{
|
if (rc.IsFailure()) return rc;
|
||||||
// todo: Missing some function call here
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -224,7 +230,10 @@ namespace LibHac.FsService
|
||||||
return ResultFs.TargetNotFound.Log();
|
return ResultFs.TargetNotFound.Log();
|
||||||
}
|
}
|
||||||
|
|
||||||
return KvDatabase.Delete(ref key);
|
rc = KvDatabase.Delete(ref key);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
return AdjustOpenedInfoReaders(ref key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +342,26 @@ namespace LibHac.FsService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Result OpenSaveDataInfoReader(out ISaveDataInfoReader infoReader)
|
||||||
|
{
|
||||||
|
infoReader = default;
|
||||||
|
|
||||||
|
lock (Locker)
|
||||||
|
{
|
||||||
|
Result rc = Initialize();
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
rc = EnsureKvDatabaseLoaded(false);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
var reader = new SaveDataInfoReader(this);
|
||||||
|
|
||||||
|
infoReader = reader;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryGetBySaveDataIdInternal(out SaveDataAttribute key, out SaveDataIndexerValue value, ulong saveDataId)
|
private bool TryGetBySaveDataIdInternal(out SaveDataAttribute key, out SaveDataIndexerValue value, ulong saveDataId)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<SaveDataAttribute, byte[]> kvp in KvDatabase)
|
foreach (KeyValuePair<SaveDataAttribute, byte[]> kvp in KvDatabase)
|
||||||
|
@ -459,6 +488,12 @@ namespace LibHac.FsService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Result AdjustOpenedInfoReaders(ref SaveDataAttribute key)
|
||||||
|
{
|
||||||
|
// todo
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
private ref struct Mounter
|
private ref struct Mounter
|
||||||
{
|
{
|
||||||
private FileSystemClient FsClient { get; set; }
|
private FileSystemClient FsClient { get; set; }
|
||||||
|
@ -516,5 +551,57 @@ namespace LibHac.FsService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SaveDataInfoReader : ISaveDataInfoReader
|
||||||
|
{
|
||||||
|
private SaveDataIndexer Indexer { get; }
|
||||||
|
private int Version { get; }
|
||||||
|
public int Position { get; set; }
|
||||||
|
|
||||||
|
public SaveDataInfoReader(SaveDataIndexer indexer)
|
||||||
|
{
|
||||||
|
Indexer = indexer;
|
||||||
|
Version = indexer.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ReadSaveDataInfo(out long readCount, Span<byte> saveDataInfoBuffer)
|
||||||
|
{
|
||||||
|
readCount = default;
|
||||||
|
|
||||||
|
lock (Indexer.Locker)
|
||||||
|
{
|
||||||
|
// Indexer has been reloaded since this info reader was created
|
||||||
|
if (Version != Indexer.Version)
|
||||||
|
{
|
||||||
|
return ResultFs.ReadOldSaveDataInfoReader.Log();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more to iterate
|
||||||
|
if (Position == Indexer.KvDatabase.Count)
|
||||||
|
{
|
||||||
|
readCount = 0;
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
Span<SaveDataInfo> outInfo = MemoryMarshal.Cast<byte, SaveDataInfo>(saveDataInfoBuffer);
|
||||||
|
|
||||||
|
// Todo: A more efficient way of doing this
|
||||||
|
List<(SaveDataAttribute key, byte[] value)> list = Indexer.KvDatabase.ToList();
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < outInfo.Length && Position < list.Count; i++, Position++)
|
||||||
|
{
|
||||||
|
SaveDataAttribute key = list[Position].key;
|
||||||
|
ref SaveDataIndexerValue value = ref Unsafe.As<byte, SaveDataIndexerValue>(ref list[Position].value[0]);
|
||||||
|
|
||||||
|
GetSaveDataInfo(out outInfo[i], ref key, ref value);
|
||||||
|
}
|
||||||
|
|
||||||
|
readCount = i;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace LibHac.FsService
|
||||||
_sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd", SaveDataSpaceId.SdSystem, SaveDataId);
|
_sdCardIndexer.Indexer = new SaveDataIndexer(FsClient, "saveDataIxrDbSd", SaveDataSpaceId.SdSystem, SaveDataId);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader = new SaveDataIndexerReader(_bisIndexer.Indexer, _bisIndexer.Locker);
|
reader = new SaveDataIndexerReader(_sdCardIndexer.Indexer, _sdCardIndexer.Locker);
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
|
||||||
case SaveDataSpaceId.TemporaryStorage:
|
case SaveDataSpaceId.TemporaryStorage:
|
||||||
|
|
156
src/LibHac/FsService/SaveDataInfoFilterReader.cs
Normal file
156
src/LibHac/FsService/SaveDataInfoFilterReader.cs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.FsSystem.Save;
|
||||||
|
using LibHac.Ncm;
|
||||||
|
|
||||||
|
namespace LibHac.FsService
|
||||||
|
{
|
||||||
|
internal class SaveDataInfoFilterReader : ISaveDataInfoReader
|
||||||
|
{
|
||||||
|
private ISaveDataInfoReader Reader { get; }
|
||||||
|
private SaveDataFilterInternal Filter { get; }
|
||||||
|
|
||||||
|
public SaveDataInfoFilterReader(ISaveDataInfoReader reader, ref SaveDataFilterInternal filter)
|
||||||
|
{
|
||||||
|
Reader = reader;
|
||||||
|
Filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result ReadSaveDataInfo(out long readCount, Span<byte> saveDataInfoBuffer)
|
||||||
|
{
|
||||||
|
readCount = default;
|
||||||
|
|
||||||
|
Span<SaveDataInfo> outInfo = MemoryMarshal.Cast<byte, SaveDataInfo>(saveDataInfoBuffer);
|
||||||
|
|
||||||
|
SaveDataInfo tempInfo = default;
|
||||||
|
Span<byte> tempInfoBytes = SpanHelpers.AsByteSpan(ref tempInfo);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (count < outInfo.Length)
|
||||||
|
{
|
||||||
|
Result rc = Reader.ReadSaveDataInfo(out long baseReadCount, tempInfoBytes);
|
||||||
|
if (rc.IsFailure()) return rc;
|
||||||
|
|
||||||
|
if (baseReadCount == 0) break;
|
||||||
|
|
||||||
|
if (Filter.Matches(ref tempInfo))
|
||||||
|
{
|
||||||
|
outInfo[count] = tempInfo;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readCount = count;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 0x50)]
|
||||||
|
internal struct SaveDataFilterInternal
|
||||||
|
{
|
||||||
|
[FieldOffset(0x00)] public bool FilterBySaveDataSpaceId;
|
||||||
|
[FieldOffset(0x01)] public SaveDataSpaceId SpaceId;
|
||||||
|
|
||||||
|
[FieldOffset(0x08)] public bool FilterByTitleId;
|
||||||
|
[FieldOffset(0x10)] public TitleId TitleId;
|
||||||
|
|
||||||
|
[FieldOffset(0x18)] public bool FilterBySaveDataType;
|
||||||
|
[FieldOffset(0x19)] public SaveDataType SaveDataType;
|
||||||
|
|
||||||
|
[FieldOffset(0x20)] public bool FilterByUserId;
|
||||||
|
[FieldOffset(0x28)] public UserId UserId;
|
||||||
|
|
||||||
|
[FieldOffset(0x38)] public bool FilterBySaveDataId;
|
||||||
|
[FieldOffset(0x40)] public ulong SaveDataId;
|
||||||
|
|
||||||
|
[FieldOffset(0x48)] public bool FilterByIndex;
|
||||||
|
[FieldOffset(0x4A)] public short Index;
|
||||||
|
|
||||||
|
[FieldOffset(0x4C)] public int Rank;
|
||||||
|
|
||||||
|
public SaveDataFilterInternal(ref SaveDataFilter filter, SaveDataSpaceId spaceId)
|
||||||
|
{
|
||||||
|
this = default;
|
||||||
|
|
||||||
|
FilterBySaveDataSpaceId = true;
|
||||||
|
SpaceId = spaceId;
|
||||||
|
|
||||||
|
Rank = filter.Rank;
|
||||||
|
|
||||||
|
if (filter.FilterByTitleId)
|
||||||
|
{
|
||||||
|
FilterByTitleId = true;
|
||||||
|
TitleId = filter.TitleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.FilterBySaveDataType)
|
||||||
|
{
|
||||||
|
FilterBySaveDataType = true;
|
||||||
|
SaveDataType = filter.SaveDataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.FilterByUserId)
|
||||||
|
{
|
||||||
|
FilterByUserId = true;
|
||||||
|
UserId = filter.UserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.FilterBySaveDataId)
|
||||||
|
{
|
||||||
|
FilterBySaveDataId = true;
|
||||||
|
SaveDataId = filter.SaveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter.FilterByIndex)
|
||||||
|
{
|
||||||
|
FilterByIndex = true;
|
||||||
|
Index = filter.Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Matches(ref SaveDataInfo info)
|
||||||
|
{
|
||||||
|
if (FilterBySaveDataSpaceId && info.SpaceId != SpaceId)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterByTitleId && info.TitleId != TitleId)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterBySaveDataType && info.Type != SaveDataType)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterByUserId && info.UserId != UserId)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterBySaveDataId && info.SaveDataId != SaveDataId)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FilterByIndex && info.Index != Index)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Rank & 1) == 0 && info.Rank != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,8 @@ namespace LibHac.Kvdb
|
||||||
private FileSystemClient FsClient { get; }
|
private FileSystemClient FsClient { get; }
|
||||||
private string FileName { get; }
|
private string FileName { get; }
|
||||||
|
|
||||||
|
public int Count => KvDict.Count;
|
||||||
|
|
||||||
public KeyValueDatabase() { }
|
public KeyValueDatabase() { }
|
||||||
|
|
||||||
public KeyValueDatabase(FileSystemClient fsClient, string fileName)
|
public KeyValueDatabase(FileSystemClient fsClient, string fileName)
|
||||||
|
@ -147,6 +149,11 @@ namespace LibHac.Kvdb
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<(TKey key, byte[] value)> ToList()
|
||||||
|
{
|
||||||
|
return KvDict.OrderBy(x => x.Key).Select(entry => (entry.Key, entry.Value)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
private Result ReadFile(out byte[] data)
|
private Result ReadFile(out byte[] data)
|
||||||
{
|
{
|
||||||
Debug.Assert(FsClient != null);
|
Debug.Assert(FsClient != null);
|
||||||
|
|
Loading…
Reference in a new issue