Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 39 additions & 19 deletions CascLib/RootHandlers/MNDXRootHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
#if NET8_0_OR_GREATER
using System.Linq;
#endif
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -80,6 +83,10 @@ class MNDXRootHandler : RootHandlerBase

private Dictionary<int, string> Packages = new Dictionary<int, string>();
private Dictionary<int, LocaleFlags> PackagesLocale = new Dictionary<int, LocaleFlags>();
private Dictionary<string, int> IndexByPackages = new Dictionary<string, int>();
#if NET9_0_OR_GREATER
private Dictionary<string, int>.AlternateLookup<ReadOnlySpan<char>> IndexByPackagesSpanLookup;
#endif

private Dictionary<ulong, RootEntry> mndxData = new Dictionary<ulong, RootEntry>();

Expand All @@ -88,6 +95,9 @@ class MNDXRootHandler : RootHandlerBase

public MNDXRootHandler(BinaryReader stream, BackgroundWorkerEx worker)
{
#if NET9_0_OR_GREATER
IndexByPackagesSpanLookup = IndexByPackages.GetAlternateLookup<ReadOnlySpan<char>>();
#endif
worker?.ReportProgress(0, "Loading \"root\"...");

var header = stream.Read<MNDXHeader>();
Expand Down Expand Up @@ -233,28 +243,36 @@ public override IEnumerable<RootEntry> GetEntries(ulong hash)

private int FindMNDXPackage(string fileName)
{
int nMaxLength = 0;
int pMatching = -1;

int fileNameLen = fileName.Length;

foreach (var package in Packages)
if (IndexByPackages.TryGetValue(fileName, out int pkgIndex))
return pkgIndex;

#if NET8_0_OR_GREATER
int splitterCount = fileName.Count(x => x == '/');
Span<Range> filePathRanges = stackalloc Range[splitterCount + 1];

ReadOnlySpan<char> fileNameSpan = fileName.AsSpan();
int size = fileNameSpan.SplitAny(filePathRanges, "/", StringSplitOptions.None);
#else
string[] fileNameSplit = fileName.Split('/');
int size = fileNameSplit.Length;
#endif
// skip first since already checked full path
for (int i = size - 2; i >= 0; i--)
{
string pkgName = package.Value;
int pkgNameLen = pkgName.Length;

if (pkgNameLen < fileNameLen && pkgNameLen > nMaxLength)
{
// Compare the package name
if (string.CompareOrdinal(fileName, 0, pkgName, 0, pkgNameLen) == 0)
{
pMatching = package.Key;
nMaxLength = pkgNameLen;
}
}
#if NET9_0_OR_GREATER
ReadOnlySpan<char> part = fileNameSpan[..filePathRanges[i].End.Value];
if (IndexByPackagesSpanLookup.TryGetValue(part, out pkgIndex))
#elif NET8_0_OR_GREATER
ReadOnlySpan<char> part = fileNameSpan[..filePathRanges[i].End.Value];
if (IndexByPackages.TryGetValue(part.ToString(), out pkgIndex))
#else
string part = string.Join("/", fileNameSplit, 0, i + 1);
if (IndexByPackages.TryGetValue(part, out pkgIndex))
#endif
return pkgIndex;
}

return pMatching;
throw new KeyNotFoundException($"Package not found for file '{fileName}'");
}

private CASC_ROOT_ENTRY_MNDX FindMNDXInfo(string path, int dwPackage)
Expand Down Expand Up @@ -329,6 +347,7 @@ public override void LoadListFile(string path, BackgroundWorkerEx worker = null)
foreach (var result in MarFiles[0].EnumerateFiles())
{
Packages.Add(result.FileNameIndex, result.FoundPath);
IndexByPackages.Add(result.FoundPath, result.FileNameIndex);

Match match1 = regex1.Match(result.FoundPath);
Match match2 = regex2.Match(result.FoundPath);
Expand Down Expand Up @@ -418,6 +437,7 @@ public override void Clear()
mndxRootEntriesValid.Clear();
Packages.Clear();
PackagesLocale.Clear();
IndexByPackages.Clear();
Root.Files.Clear();
Root.Folders.Clear();
CASCFile.Files.Clear();
Expand Down