mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Remove the old KeyValueDatabase
This commit is contained in:
parent
a551360da0
commit
d575415b0e
6 changed files with 1 additions and 381 deletions
|
@ -1,16 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace LibHac.Kvdb
|
|
||||||
{
|
|
||||||
public interface IExportable
|
|
||||||
{
|
|
||||||
int ExportSize { get; }
|
|
||||||
void ToBytes(Span<byte> output);
|
|
||||||
void FromBytes(ReadOnlySpan<byte> input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prevent further modification of this object.
|
|
||||||
/// </summary>
|
|
||||||
void Freeze();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace LibHac.Kvdb
|
|
||||||
{
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0xC)]
|
|
||||||
internal struct ImkvdbHeader
|
|
||||||
{
|
|
||||||
public const uint ExpectedMagic = 0x564B4D49; // IMKV
|
|
||||||
|
|
||||||
public uint Magic;
|
|
||||||
public int Reserved;
|
|
||||||
public int EntryCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = 0xC)]
|
|
||||||
internal struct ImkvdbEntryHeader
|
|
||||||
{
|
|
||||||
public const uint ExpectedMagic = 0x4E454D49; // IMEN
|
|
||||||
|
|
||||||
public uint Magic;
|
|
||||||
public int KeySize;
|
|
||||||
public int ValueSize;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace LibHac.Kvdb
|
|
||||||
{
|
|
||||||
public ref struct ImkvdbReader
|
|
||||||
{
|
|
||||||
private readonly ReadOnlySpan<byte> _data;
|
|
||||||
private int _position;
|
|
||||||
|
|
||||||
public ImkvdbReader(ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
_data = data;
|
|
||||||
_position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result ReadHeader(out int entryCount)
|
|
||||||
{
|
|
||||||
entryCount = default;
|
|
||||||
|
|
||||||
if (_position + Unsafe.SizeOf<ImkvdbHeader>() > _data.Length)
|
|
||||||
return ResultKvdb.InvalidKeyValue.Log();
|
|
||||||
|
|
||||||
ref ImkvdbHeader header = ref Unsafe.As<byte, ImkvdbHeader>(ref Unsafe.AsRef(_data[_position]));
|
|
||||||
|
|
||||||
if (header.Magic != ImkvdbHeader.ExpectedMagic)
|
|
||||||
{
|
|
||||||
return ResultKvdb.InvalidKeyValue.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
entryCount = header.EntryCount;
|
|
||||||
_position += Unsafe.SizeOf<ImkvdbHeader>();
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result GetEntrySize(out int keySize, out int valueSize)
|
|
||||||
{
|
|
||||||
keySize = default;
|
|
||||||
valueSize = default;
|
|
||||||
|
|
||||||
if (_position + Unsafe.SizeOf<ImkvdbHeader>() > _data.Length)
|
|
||||||
return ResultKvdb.InvalidKeyValue.Log();
|
|
||||||
|
|
||||||
ref ImkvdbEntryHeader header = ref Unsafe.As<byte, ImkvdbEntryHeader>(ref Unsafe.AsRef(_data[_position]));
|
|
||||||
|
|
||||||
if (header.Magic != ImkvdbEntryHeader.ExpectedMagic)
|
|
||||||
{
|
|
||||||
return ResultKvdb.InvalidKeyValue.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
keySize = header.KeySize;
|
|
||||||
valueSize = header.ValueSize;
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result ReadEntry(out ReadOnlySpan<byte> key, out ReadOnlySpan<byte> value)
|
|
||||||
{
|
|
||||||
key = default;
|
|
||||||
value = default;
|
|
||||||
|
|
||||||
Result rc = GetEntrySize(out int keySize, out int valueSize);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
_position += Unsafe.SizeOf<ImkvdbEntryHeader>();
|
|
||||||
|
|
||||||
if (_position + keySize + valueSize > _data.Length)
|
|
||||||
return ResultKvdb.InvalidKeyValue.Log();
|
|
||||||
|
|
||||||
key = _data.Slice(_position, keySize);
|
|
||||||
value = _data.Slice(_position + keySize, valueSize);
|
|
||||||
|
|
||||||
_position += keySize + valueSize;
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace LibHac.Kvdb
|
|
||||||
{
|
|
||||||
public ref struct ImkvdbWriter
|
|
||||||
{
|
|
||||||
private readonly Span<byte> _data;
|
|
||||||
private int _position;
|
|
||||||
|
|
||||||
public ImkvdbWriter(Span<byte> data)
|
|
||||||
{
|
|
||||||
_data = data;
|
|
||||||
_position = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteHeader(int entryCount)
|
|
||||||
{
|
|
||||||
if (_position + Unsafe.SizeOf<ImkvdbHeader>() > _data.Length) throw new InvalidOperationException();
|
|
||||||
|
|
||||||
ref ImkvdbHeader header = ref Unsafe.As<byte, ImkvdbHeader>(ref _data[_position]);
|
|
||||||
|
|
||||||
header.Magic = ImkvdbHeader.ExpectedMagic;
|
|
||||||
header.Reserved = 0;
|
|
||||||
header.EntryCount = entryCount;
|
|
||||||
|
|
||||||
_position += Unsafe.SizeOf<ImkvdbHeader>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WriteEntry(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value)
|
|
||||||
{
|
|
||||||
WriteEntryHeader(key.Length, value.Length);
|
|
||||||
Write(key);
|
|
||||||
Write(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WriteEntryHeader(int keySize, int valueSize)
|
|
||||||
{
|
|
||||||
if (_position + Unsafe.SizeOf<ImkvdbEntryHeader>() > _data.Length) throw new InvalidOperationException();
|
|
||||||
|
|
||||||
ref ImkvdbEntryHeader header = ref Unsafe.As<byte, ImkvdbEntryHeader>(ref _data[_position]);
|
|
||||||
|
|
||||||
header.Magic = ImkvdbEntryHeader.ExpectedMagic;
|
|
||||||
header.KeySize = keySize;
|
|
||||||
header.ValueSize = valueSize;
|
|
||||||
|
|
||||||
_position += Unsafe.SizeOf<ImkvdbEntryHeader>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Write(ReadOnlySpan<byte> value)
|
|
||||||
{
|
|
||||||
int valueSize = value.Length;
|
|
||||||
if (_position + valueSize > _data.Length) throw new InvalidOperationException();
|
|
||||||
|
|
||||||
Span<byte> dest = _data.Slice(_position, valueSize);
|
|
||||||
value.CopyTo(dest);
|
|
||||||
|
|
||||||
_position += valueSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,199 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using LibHac.Common;
|
|
||||||
using LibHac.Fs;
|
|
||||||
|
|
||||||
namespace LibHac.Kvdb
|
|
||||||
{
|
|
||||||
public class KeyValueDatabase<TKey> where TKey : unmanaged, IComparable<TKey>, IEquatable<TKey>
|
|
||||||
{
|
|
||||||
private Dictionary<TKey, byte[]> KvDict { get; } = new Dictionary<TKey, byte[]>();
|
|
||||||
|
|
||||||
private FileSystemClient FsClient { get; }
|
|
||||||
private U8String FileName { get; }
|
|
||||||
|
|
||||||
public int Count => KvDict.Count;
|
|
||||||
|
|
||||||
public KeyValueDatabase() { }
|
|
||||||
|
|
||||||
public KeyValueDatabase(FileSystemClient fsClient, U8Span fileName)
|
|
||||||
{
|
|
||||||
FsClient = fsClient;
|
|
||||||
FileName = fileName.ToU8String();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result Get(ref TKey key, Span<byte> valueBuffer)
|
|
||||||
{
|
|
||||||
Result rc = GetValue(ref key, out byte[] value);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
int size = Math.Min(valueBuffer.Length, value.Length);
|
|
||||||
|
|
||||||
value.AsSpan(0, size).CopyTo(valueBuffer);
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result GetValue(ref TKey key, out byte[] value)
|
|
||||||
{
|
|
||||||
if (!KvDict.TryGetValue(key, out value))
|
|
||||||
{
|
|
||||||
return ResultKvdb.KeyNotFound.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result Set(ref TKey key, ReadOnlySpan<byte> value)
|
|
||||||
{
|
|
||||||
KvDict[key] = value.ToArray();
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result Delete(ref TKey key)
|
|
||||||
{
|
|
||||||
bool deleted = KvDict.Remove(key);
|
|
||||||
|
|
||||||
return deleted ? Result.Success : ResultKvdb.KeyNotFound.Log();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<TKey, byte[]>.Enumerator GetEnumerator()
|
|
||||||
{
|
|
||||||
return KvDict.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result ReadDatabaseFromBuffer(ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
KvDict.Clear();
|
|
||||||
|
|
||||||
var reader = new ImkvdbReader(data);
|
|
||||||
|
|
||||||
Result rc = reader.ReadHeader(out int entryCount);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
for (int i = 0; i < entryCount; i++)
|
|
||||||
{
|
|
||||||
rc = reader.ReadEntry(out ReadOnlySpan<byte> keyBytes, out ReadOnlySpan<byte> valueBytes);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
Debug.Assert(keyBytes.Length == Unsafe.SizeOf<TKey>());
|
|
||||||
|
|
||||||
var key = new TKey();
|
|
||||||
keyBytes.CopyTo(SpanHelpers.AsByteSpan(ref key));
|
|
||||||
|
|
||||||
byte[] value = valueBytes.ToArray();
|
|
||||||
|
|
||||||
KvDict.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result WriteDatabaseToBuffer(Span<byte> output)
|
|
||||||
{
|
|
||||||
var writer = new ImkvdbWriter(output);
|
|
||||||
|
|
||||||
writer.WriteHeader(KvDict.Count);
|
|
||||||
|
|
||||||
foreach (KeyValuePair<TKey, byte[]> entry in KvDict.OrderBy(x => x.Key))
|
|
||||||
{
|
|
||||||
TKey key = entry.Key;
|
|
||||||
writer.WriteEntry(SpanHelpers.AsByteSpan(ref key), entry.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result ReadDatabaseFromFile()
|
|
||||||
{
|
|
||||||
if (FsClient == null || FileName.IsNull())
|
|
||||||
return ResultFs.PreconditionViolation.Log();
|
|
||||||
|
|
||||||
Result rc = ReadFile(out byte[] data);
|
|
||||||
|
|
||||||
if (rc.IsFailure())
|
|
||||||
{
|
|
||||||
return ResultFs.PathNotFound.Includes(rc) ? Result.Success : rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReadDatabaseFromBuffer(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result WriteDatabaseToFile()
|
|
||||||
{
|
|
||||||
if (FsClient == null || FileName.IsNull())
|
|
||||||
return ResultFs.PreconditionViolation.Log();
|
|
||||||
|
|
||||||
var buffer = new byte[GetExportedSize()];
|
|
||||||
|
|
||||||
Result rc = WriteDatabaseToBuffer(buffer);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
return WriteFile(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetExportedSize()
|
|
||||||
{
|
|
||||||
int size = Unsafe.SizeOf<ImkvdbHeader>();
|
|
||||||
|
|
||||||
foreach (byte[] value in KvDict.Values)
|
|
||||||
{
|
|
||||||
size += Unsafe.SizeOf<ImkvdbEntryHeader>();
|
|
||||||
size += Unsafe.SizeOf<TKey>();
|
|
||||||
size += value.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
Debug.Assert(!FileName.IsEmpty());
|
|
||||||
|
|
||||||
data = default;
|
|
||||||
|
|
||||||
Result rc = FsClient.OpenFile(out FileHandle handle, FileName, OpenMode.Read);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = FsClient.GetFileSize(out long fileSize, handle);
|
|
||||||
|
|
||||||
if (rc.IsSuccess())
|
|
||||||
{
|
|
||||||
data = new byte[fileSize];
|
|
||||||
|
|
||||||
rc = FsClient.ReadFile(handle, 0, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
FsClient.CloseFile(handle);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Result WriteFile(ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
Debug.Assert(FsClient != null);
|
|
||||||
Debug.Assert(!FileName.IsEmpty());
|
|
||||||
|
|
||||||
FsClient.DeleteFile(FileName);
|
|
||||||
|
|
||||||
Result rc = FsClient.CreateFile(FileName, data.Length);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = FsClient.OpenFile(out FileHandle handle, FileName, OpenMode.Write);
|
|
||||||
if (rc.IsFailure()) return rc;
|
|
||||||
|
|
||||||
rc = FsClient.WriteFile(handle, 0, data, WriteOption.Flush);
|
|
||||||
FsClient.CloseFile(handle);
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using LibHac.Kvdb;
|
|
||||||
|
|
||||||
namespace LibHac.Ncm
|
namespace LibHac.Ncm
|
||||||
{
|
{
|
||||||
public class ContentMetaKey : IComparable<ContentMetaKey>, IComparable, IEquatable<ContentMetaKey>, IExportable
|
public class ContentMetaKey : IComparable<ContentMetaKey>, IComparable, IEquatable<ContentMetaKey>
|
||||||
{
|
{
|
||||||
public ulong TitleId { get; private set; }
|
public ulong TitleId { get; private set; }
|
||||||
public uint Version { get; private set; }
|
public uint Version { get; private set; }
|
||||||
|
|
Loading…
Reference in a new issue