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 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)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ namespace LibHac.Fs
|
|||
mountName = default;
|
||||
subPath = default;
|
||||
|
||||
return ResultFs.InvalidMountName;
|
||||
return ResultFs.InvalidMountName.Log();
|
||||
}
|
||||
|
||||
mountName = path.Slice(0, mountLen);
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
public static Result InvalidMountName => new Result(ModuleFs, 6065);
|
||||
public static Result ExtensionSizeTooLarge => new Result(ModuleFs, 6066);
|
||||
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 FileExtensionWithoutOpenModeAllowAppend => new Result(ModuleFs, 6201);
|
||||
|
|
|
@ -78,30 +78,6 @@ namespace LibHac.Fs
|
|||
[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)]
|
||||
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.Ncm;
|
||||
|
||||
|
@ -159,6 +162,63 @@ namespace LibHac.Fs.Shim
|
|||
() => $", 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)
|
||||
{
|
||||
IFileSystemProxy fsProxy = fsClient.GetFileSystemProxyServiceObject();
|
||||
|
@ -166,4 +226,38 @@ namespace LibHac.Fs.Shim
|
|||
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.Runtime.CompilerServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
|
@ -707,7 +708,34 @@ namespace LibHac.FsService
|
|||
|
||||
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,
|
||||
|
@ -719,7 +747,46 @@ namespace LibHac.FsService
|
|||
public Result FindSaveDataWithFilter(out long count, Span<byte> saveDataInfoBuffer, SaveDataSpaceId spaceId,
|
||||
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)
|
||||
|
|
|
@ -15,5 +15,6 @@ namespace LibHac.FsService
|
|||
Result SetState(ulong saveDataId, SaveDataState state);
|
||||
Result GetKey(out SaveDataAttribute key, 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.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
|
@ -23,6 +25,7 @@ namespace LibHac.FsService
|
|||
private bool IsInitialized { get; set; }
|
||||
private bool IsKvdbLoaded { get; set; }
|
||||
private ulong LastPublishedId { get; set; }
|
||||
private int Version { get; set; }
|
||||
|
||||
public SaveDataIndexer(FileSystemClient fsClient, string mountName, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
|
@ -30,6 +33,7 @@ namespace LibHac.FsService
|
|||
MountName = mountName;
|
||||
SaveDataId = saveDataId;
|
||||
SpaceId = spaceId;
|
||||
Version = 1;
|
||||
}
|
||||
|
||||
public static void GetSaveDataInfo(out SaveDataInfo info, ref SaveDataAttribute key, ref SaveDataIndexerValue value)
|
||||
|
@ -140,6 +144,9 @@ namespace LibHac.FsService
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = AdjustOpenedInfoReaders(ref key);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
saveDataId = newSaveDataId;
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -194,11 +201,10 @@ namespace LibHac.FsService
|
|||
};
|
||||
|
||||
rc = KvDatabase.Set(ref key, SpanHelpers.AsByteSpan(ref newValue));
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
if (rc.IsFailure())
|
||||
{
|
||||
// todo: Missing some function call here
|
||||
}
|
||||
rc = AdjustOpenedInfoReaders(ref key);
|
||||
if (rc.IsFailure()) return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -224,7 +230,10 @@ namespace LibHac.FsService
|
|||
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)
|
||||
{
|
||||
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 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);
|
||||
}
|
||||
|
||||
reader = new SaveDataIndexerReader(_bisIndexer.Indexer, _bisIndexer.Locker);
|
||||
reader = new SaveDataIndexerReader(_sdCardIndexer.Indexer, _sdCardIndexer.Locker);
|
||||
return Result.Success;
|
||||
|
||||
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 string FileName { get; }
|
||||
|
||||
public int Count => KvDict.Count;
|
||||
|
||||
public KeyValueDatabase() { }
|
||||
|
||||
public KeyValueDatabase(FileSystemClient fsClient, string fileName)
|
||||
|
@ -147,6 +149,11 @@ namespace LibHac.Kvdb
|
|||
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)
|
||||
{
|
||||
Debug.Assert(FsClient != null);
|
||||
|
|
Loading…
Reference in a new issue