Skip to content
This repository has been archived by the owner on Sep 18, 2022. It is now read-only.

Commit

Permalink
Changed: Modernize Project
Browse files Browse the repository at this point in the history
  • Loading branch information
Sewer56 committed Mar 24, 2022
1 parent 4b3fe4b commit ee8f1be
Show file tree
Hide file tree
Showing 19 changed files with 1,612 additions and 1,061 deletions.
405 changes: 374 additions & 31 deletions Publish.ps1

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions PublishAll.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

# Set Working Directory
Split-Path $MyInvocation.MyCommand.Path | Push-Location
[Environment]::CurrentDirectory = $PWD

./Publish.ps1 -ProjectPath "Reloaded.Utils.AfsRedirector/Reloaded.Utils.AfsRedirector.csproj" `
-PackageName "Reloaded.Utils.AfsRedirector" `

Pop-Location
213 changes: 106 additions & 107 deletions Reloaded.Utils.AfsRedirector/Afs/VirtualAfs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,129 +5,128 @@
using Reloaded.Utils.AfsRedirector.Structs;
using static Reloaded.Utils.AfsRedirector.Structs.Utilities;

namespace Reloaded.Utils.AfsRedirector.Afs
namespace Reloaded.Utils.AfsRedirector.Afs;

public unsafe class VirtualAfs : IDisposable
{
public unsafe class VirtualAfs : IDisposable
private const int LastOffetsNum = 4;

/// <summary>
/// Contains the data stored in the AFS header.
/// </summary>
public byte[] Header { get; private set; }

/// <summary>
/// A pointer to the virtual afs file header.
/// </summary>
public byte* HeaderPtr { get; private set; }

/// <summary>
/// Mapping of all files in the archive, offset to file.
/// </summary>
public Dictionary<int, VirtualFile> Files { get; private set; }

/// <summary>
/// The alignment of the files inside the archive.
/// </summary>
public int Alignment { get; private set; }

/// <summary>
/// The total size of the file.
/// </summary>
public int FileSize { get; private set; }

private readonly GCHandle? _virtualAfsHandle;
private readonly int[] _recentOffsets = new int[LastOffetsNum];
private int _lastOffsetIndex = 0;

/// <summary>
/// Creates a Virtual AFS given the name of the file and the header of an AFS file.
/// </summary>
/// <param name="afsHeader">The bytes corresponding to the new AFS header.</param>
/// <param name="files">Mapping of all files in the archive, offset to file.</param>
/// <param name="alignment">Sets the alignment of the files inside the archive.</param>
/// <param name="fileSize">Size of the virtual AFS file.</param>
public VirtualAfs(byte[] afsHeader, Dictionary<int, VirtualFile> files, int alignment, int fileSize)
{
private const int LastOffetsNum = 4;

/// <summary>
/// Contains the data stored in the AFS header.
/// </summary>
public byte[] Header { get; private set; }

/// <summary>
/// A pointer to the virtual afs file header.
/// </summary>
public byte* HeaderPtr { get; private set; }

/// <summary>
/// Mapping of all files in the archive, offset to file.
/// </summary>
public Dictionary<int, VirtualFile> Files { get; private set; }

/// <summary>
/// The alignment of the files inside the archive.
/// </summary>
public int Alignment { get; private set; }

/// <summary>
/// The total size of the file.
/// </summary>
public int FileSize { get; private set; }

private GCHandle? _virtualAfsHandle;
private int[] _recentOffsets = new int[LastOffetsNum];
private int _lastOffsetIndex = 0;

/// <summary>
/// Creates a Virtual AFS given the name of the file and the header of an AFS file.
/// </summary>
/// <param name="afsHeader">The bytes corresponding to the new AFS header.</param>
/// <param name="files">Mapping of all files in the archive, offset to file.</param>
/// <param name="alignment">Sets the alignment of the files inside the archive.</param>
/// <param name="fileSize">Size of the virtual AFS file.</param>
public VirtualAfs(byte[] afsHeader, Dictionary<int, VirtualFile> files, int alignment, int fileSize)
{
Header = afsHeader;
Files = files;
Alignment = alignment;
FileSize = fileSize;
Header = afsHeader;
Files = files;
Alignment = alignment;
FileSize = fileSize;

_virtualAfsHandle = GCHandle.Alloc(Header, GCHandleType.Pinned);
HeaderPtr = (byte*) _virtualAfsHandle.Value.AddrOfPinnedObject();
}
_virtualAfsHandle = GCHandle.Alloc(Header, GCHandleType.Pinned);
HeaderPtr = (byte*) _virtualAfsHandle.Value.AddrOfPinnedObject();
}

~VirtualAfs()
{
Dispose();
}
~VirtualAfs()
{
Dispose();
}

public void Dispose()
{
_virtualAfsHandle?.Free();
GC.SuppressFinalize(this);
}

public void Dispose()
/// <summary>
/// Gets a <see cref="VirtualFile"/> ready for reading given an offset and requested read length.
/// </summary>
/// <param name="offset">Offset of the file.</param>
/// <param name="length">Length of the file.</param>
/// <param name="file">The file, ready for reading.</param>
public bool TryFindFile(int offset, int length, out VirtualFile file)
{
// O(1) if read is at known offset. Most likely to occur.
if (Files.ContainsKey(offset))
{
_virtualAfsHandle?.Free();
GC.SuppressFinalize(this);
// Cache for reading.
_recentOffsets[_lastOffsetIndex++] = offset;
_lastOffsetIndex %= _recentOffsets.Length;

// Return offsets :P
file = Files[offset];
file = file.SliceUpTo(0, length);
return true;
}

/// <summary>
/// Gets a <see cref="VirtualFile"/> ready for reading given an offset and requested read length.
/// </summary>
/// <param name="offset">Offset of the file.</param>
/// <param name="length">Length of the file.</param>
/// <param name="file">The file, ready for reading.</param>
public bool TryFindFile(int offset, int length, out VirtualFile file)
// Try O(LastOffetsNum) in very likely probability chunk recent file requested.
var requestedReadRange = new AddressRange(offset, offset + length);
foreach (var recentOffset in _recentOffsets)
{
// O(1) if read is at known offset. Most likely to occur.
if (Files.ContainsKey(offset))
if (Files.ContainsKey(recentOffset))
{
// Cache for reading.
_recentOffsets[_lastOffsetIndex++] = offset;
_lastOffsetIndex %= _recentOffsets.Length;

// Return offsets :P
file = Files[offset];
file = file.SliceUpTo(0, length);
return true;
}
var lastFile = Files[recentOffset];

// Try O(LastOffetsNum) in very likely probability chunk recent file requested.
var requestedReadRange = new AddressRange(offset, offset + length);
foreach (var recentOffset in _recentOffsets)
{
if (Files.ContainsKey(recentOffset))
{
var lastFile = Files[recentOffset];

var entryReadRange = new AddressRange(recentOffset, RoundUp(recentOffset + lastFile.Length, Alignment));
if (entryReadRange.Contains(ref requestedReadRange))
return ReturnFoundFile(entryReadRange, out file);
}
var entryReadRange = new AddressRange(recentOffset, RoundUp(recentOffset + lastFile.Length, Alignment));
if (entryReadRange.Contains(ref requestedReadRange))
return ReturnFoundFile(entryReadRange, out file);
}
}

// Otherwise search one by one in O(N) fashion.
if (AfsFileViewer.TryFromMemory(HeaderPtr, out var fileViewer))
// Otherwise search one by one in O(N) fashion.
if (AfsFileViewer.TryFromMemory(HeaderPtr, out var fileViewer))
{
foreach (var entry in fileViewer.Entries)
{
foreach (var entry in fileViewer.Entries)
{
var entryReadRange = new AddressRange(entry.Offset, RoundUp(entry.Offset + entry.Length, Alignment));
if (entryReadRange.Contains(ref requestedReadRange))
return ReturnFoundFile(entryReadRange, out file);
}
var entryReadRange = new AddressRange(entry.Offset, RoundUp(entry.Offset + entry.Length, Alignment));
if (entryReadRange.Contains(ref requestedReadRange))
return ReturnFoundFile(entryReadRange, out file);
}
}

// Returns a file if it has been found.
bool ReturnFoundFile(AddressRange entryReadRange, out VirtualFile returnFile)
{
int readOffset = requestedReadRange.Start - entryReadRange.Start;
int readLength = length;

returnFile = Files[entryReadRange.Start];
returnFile = returnFile.SliceUpTo(readOffset, readLength);
return true;
}
// Returns a file if it has been found.
bool ReturnFoundFile(AddressRange entryReadRange, out VirtualFile returnFile)
{
int readOffset = requestedReadRange.Start - entryReadRange.Start;
int readLength = length;

file = null;
return false;
returnFile = Files[entryReadRange.Start];
returnFile = returnFile.SliceUpTo(readOffset, readLength);
return true;
}

file = null;
return false;
}
}
}
Loading

0 comments on commit ee8f1be

Please sign in to comment.