Skip to content

File Providers

In this project File Providers are types that satisfy the IFileDataProvider or IOutputDataProvider interfaces.

These interfaces declare the IFileData GetFileData(long start, uint length) method. The IFileData interface is defined as:

/// <summary>
///     An interface for providing access to underlying file data.
/// </summary>
/// <remarks>
///     For read operations where entire file is not yet available e.g. over a network; you should stall until you can
///     provide enough data to provide.
/// </remarks>
public unsafe interface IFileData : IDisposable
{
    /// <summary>
    ///     Data of the underlying item.
    /// </summary>
    public byte* Data { get; }

    /// <summary>
    ///     Length of the underlying data.
    /// </summary>
    public ulong DataLength { get; }
}

And represents a chunk of data from a file. This can be a chunk of a file to be written, or a chunk of a file to be read. Sources of IFileData can vary, for example, it can be a Memory Mapped File on disk, data received from the web or simply an array in memory.

The .nx Packer and Unpacker will call the method GetFileData(long start, uint length) to get a slice of the data which it can directly read or write to.

Example

Actual Example from Source Code

/// <summary>
///     File data provider that provides info from an array.
/// </summary>
public sealed class FromArrayProvider : IFileDataProvider
{
    /// <summary>
    ///     The array held by this provider.
    /// </summary>
    public required byte[] Data { get; init; }

    /// <inheritdoc />
    public IFileData GetFileData(ulong start, ulong length) => new ArrayFileData(Data, start, length);
}

/// <summary>
///     Implementation of <see cref="IFileData" /> backed up by a pinned array.
/// </summary>
public sealed unsafe class ArrayFileData : IFileData
{
    /// <inheritdoc />
    public byte* Data { get; }

    /// <inheritdoc />
    public ulong DataLength { get; }

    private GCHandle _handle;
    private bool _disposed;

    /// <summary>
    ///     Creates file data backed by an array.
    /// </summary>
    /// <param name="data">The data backed up by the array.</param>
    /// <param name="start">Start offset.</param>
    /// <param name="length">Length into the data.</param>
    public ArrayFileData(byte[] data, ulong start, ulong length)
    {
        _handle = GCHandle.Alloc(data, GCHandleType.Pinned);
        Data = (byte*)_handle.AddrOfPinnedObject() + start;
        // ReSharper disable once RedundantCast
        DataLength = )length;
    }

    /// <inheritdoc />
    ~ArrayFileData() => Dispose();

    /// <inheritdoc />
    public void Dispose()
    {
        if (_disposed)
            return;

        _disposed = true;
        _handle.Free();
        GC.SuppressFinalize(this);
    }
}