Skip to content

Commit

Permalink
Convert ArchivedFiles over to MnemonicDB (#1235)
Browse files Browse the repository at this point in the history
* Implement the new model

* Swap over the code as well

* Delete the ZipFileStore that we haven't used in months.

* Convert the TODO to a future notice

* Remove dead code
  • Loading branch information
halgari authored Apr 18, 2024
1 parent 32199c6 commit 5a6d93a
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 319 deletions.
80 changes: 80 additions & 0 deletions src/NexusMods.DataModel/ArchiveContents/ArchivedFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using NexusMods.Archives.Nx.Headers.Managed;
using NexusMods.DataModel.Attributes;
using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.Models;
// ReSharper disable MemberHidesStaticFromOuterClass

namespace NexusMods.DataModel.ArchiveContents;

/// <summary>
/// A metadata entry for an archived file entry. These are the items stored inside the .nx archives. Each
/// entry contains the hash, the decompressed size, and a reference to the container. In the case of Nx containers
/// it also contains the Nx internal header data for the entry so that we can do point lookups, of files.
/// </summary>
public static class ArchivedFile
{
private const string Namespace = "NexusMods.DataModel.ArchivedFile";

/// <summary>
/// The compressed container (.nx archive) that contains the file, the entity referenced
/// here should have the relative path to the file.
/// </summary>
public static readonly ReferenceAttribute Container = new(Namespace, nameof(Container));

/// <summary>
/// The hash of the file entry
/// </summary>
public static readonly HashAttribute Hash = new(Namespace, nameof(Hash)) {IsIndexed = true};

/// <summary>
/// The file entry data for the NX block offset data
/// </summary>
public static readonly NxFileEntryAttribute NxFileEntry = new(Namespace, nameof(NxFileEntry));


/// <summary>
/// Model for the archived file entry.
/// </summary>
public class Model(ITransaction tx) : AEntity(tx)
{

/// <summary>
/// Id of the containing archive.
/// </summary>
public EntityId ContainerId
{
get => ArchivedFile.Container.Get(this);
set => ArchivedFile.Container.Add(this, value);
}

/// <summary>
/// The container that contains this file.
/// </summary>
public ArchivedFileContainer.Model Container
{
get => Db.Get<ArchivedFileContainer.Model>(ContainerId);
set => ContainerId = value.Id;
}

/// <summary>
/// Hash of the file entry
/// </summary>
public Hash Hash
{
get => ArchivedFile.Hash.Get(this);
set => ArchivedFile.Hash.Add(this, value);
}

/// <summary>
/// The Nx file entry data for the NX block offset data
/// </summary>
public FileEntry NxFileEntry
{
get => ArchivedFile.NxFileEntry.Get(this);
set => ArchivedFile.NxFileEntry.Add(this, value);
}
}

}
43 changes: 43 additions & 0 deletions src/NexusMods.DataModel/ArchiveContents/ArchivedFileContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using NexusMods.DataModel.Attributes;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.IndexSegments;
using NexusMods.MnemonicDB.Abstractions.Models;
using NexusMods.Paths;

namespace NexusMods.DataModel.ArchiveContents;

/// <summary>
/// Represents a container for archived files.
/// </summary>
public static class ArchivedFileContainer
{
private const string Namespace = "NexusMods.DataModel.ArchiveContents.ArchivedFileContainer";

/// <summary>
/// The name of the container on-disk. This will be relative to some archive root path.
/// </summary>
public static readonly RelativePathAttribute Path = new(Namespace, nameof(Path));

/// <summary>
/// Model for the archived file container.
/// </summary>
/// <param name="tx"></param>
public class Model(ITransaction tx) : AEntity(tx)
{
/// <summary>
/// The name of the container on-disk. This will be relative to some archive root path.
/// </summary>
public RelativePath Path
{
get => ArchivedFileContainer.Path.Get(this);
set => ArchivedFileContainer.Path.Add(this, value);
}

/// <summary>
/// The file entries contained in this container.
/// </summary>
public Entities<EntityIds, ArchivedFile.Model> Contents
=> GetReverse<ArchivedFile.Model>(ArchivedFile.Container);
}

}
25 changes: 0 additions & 25 deletions src/NexusMods.DataModel/ArchiveContents/FileContainedInEx.cs

This file was deleted.

37 changes: 37 additions & 0 deletions src/NexusMods.DataModel/ArchiveContents/NxFileEntryAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using NexusMods.Archives.Nx.Headers.Managed;
using NexusMods.Archives.Nx.Headers.Native;
using NexusMods.Archives.Nx.Utilities;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;

namespace NexusMods.DataModel.ArchiveContents;

/// <summary>
/// Stores a NXArchive file entry as a blob.
/// </summary>
public class NxFileEntryAttribute(string ns, string name) : BlobAttribute<FileEntry>(ns, name)
{
/// <inheritdoc />
protected override unsafe FileEntry FromLowLevel(ReadOnlySpan<byte> value, ValueTags tag)
{
fixed (byte* ptr = value)
{
var reader = new LittleEndianReader(ptr);
FileEntry tmpEntry = default;
tmpEntry.FromReaderV1(ref reader);
return tmpEntry;
}
}

/// <inheritdoc />
protected override unsafe void WriteValue<TWriter>(FileEntry value, TWriter writer)
{
var buffer = writer.GetSpan(sizeof(FileEntry));
fixed (byte* ptr = buffer)
{
var interWriter = new LittleEndianWriter(ptr);
value.WriteAsV1(ref interWriter);
writer.Advance(sizeof(FileEntry));
}
}
}
23 changes: 23 additions & 0 deletions src/NexusMods.DataModel/Attributes/HashAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NexusMods.Hashing.xxHash64;
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;

namespace NexusMods.DataModel.Attributes;

/// <summary>
/// Stores a <see cref="Hash"/> as a <see cref="ulong"/>.
/// </summary>
public class HashAttribute(string ns, string name) : ScalarAttribute<Hash, ulong>(ValueTags.UInt64, ns, name)
{
/// <inheritdoc />
protected override ulong ToLowLevel(Hash value)
{
return value.Value;
}

/// <inheritdoc />
protected override Hash FromLowLevel(ulong value, ValueTags tags)
{
return Hash.From(value);
}
}
23 changes: 23 additions & 0 deletions src/NexusMods.DataModel/Attributes/RelativePathAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using NexusMods.MnemonicDB.Abstractions.Attributes;
using NexusMods.MnemonicDB.Abstractions.ElementComparers;
using NexusMods.Paths;

namespace NexusMods.DataModel.Attributes;

/// <summary>
/// Represents a relative path.
/// </summary>
public class RelativePathAttribute(string ns, string name) : ScalarAttribute<RelativePath, string>(ValueTags.Utf8Insensitive, ns, name)
{
/// <inheritdoc />
protected override string ToLowLevel(RelativePath value)
{
return value.Path;
}

/// <inheritdoc />
protected override RelativePath FromLowLevel(string value, ValueTags tags)
{
return RelativePath.FromUnsanitizedInput(value);
}
}
Loading

0 comments on commit 5a6d93a

Please sign in to comment.