diff --git a/Sledge.Formats.Packages/FileSystem/PackageFileResolver.cs b/Sledge.Formats.Packages/FileSystem/PackageFileResolver.cs
new file mode 100644
index 0000000..d78a9da
--- /dev/null
+++ b/Sledge.Formats.Packages/FileSystem/PackageFileResolver.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Sledge.Formats.FileSystem;
+
+namespace Sledge.Formats.Packages.FileSystem
+{
+ ///
+ /// A file resolver for a package.
+ ///
+ public class PackageFileResolver : IFileResolver, IDisposable
+ {
+ private readonly bool _leaveOpen;
+ private readonly IPackage _package;
+
+ ///
+ /// Create an instance wrapping an instance.
+ ///
+ /// The instance
+ /// False to dispose the package when this instance is disposed, true to leave it undisposed
+ public PackageFileResolver(IPackage package, bool leaveOpen = false)
+ {
+ _package = package;
+ _leaveOpen = leaveOpen;
+ }
+
+ private string NormalisePath(string path)
+ {
+ return path.TrimStart('/');
+ }
+
+ public bool FolderExists(string path)
+ {
+ path = NormalisePath(path) + "/";
+ if (path == "/") return true;
+ return _package.Entries.Any(x => x.Path.StartsWith(path));
+ }
+
+ public bool FileExists(string path)
+ {
+ path = NormalisePath(path);
+ return _package.Entries.Any(x => x.Path == path);
+ }
+
+ public long FileSize(string path)
+ {
+ path = NormalisePath(path);
+ var entry = _package.Entries.FirstOrDefault(x => x.Path == path) ?? throw new FileNotFoundException();
+ return entry.Size;
+ }
+
+ public Stream OpenFile(string path)
+ {
+ path = NormalisePath(path);
+ var entry = _package.Entries.FirstOrDefault(x => x.Path == path) ?? throw new FileNotFoundException();
+ return _package.Open(entry);
+ }
+
+ public IEnumerable GetFiles(string path)
+ {
+ if (!FolderExists(path)) throw new DirectoryNotFoundException();
+ path = NormalisePath(path) + "/";
+ if (path == "/") path = "";
+
+ return _package.Entries.Where(x => x.Path != path && x.Path.StartsWith(path))
+ .Select(x => x.Path.Substring(path.Length))
+ .Where(x => !x.Contains('/'))
+ .Select(x => path + x);
+ }
+
+ public IEnumerable GetFolders(string path)
+ {
+ if (!FolderExists(path)) throw new DirectoryNotFoundException();
+ path = NormalisePath(path) + "/";
+ if (path == "/") path = "";
+
+ return _package.Entries.Where(x => x.Path != path && x.Path.StartsWith(path))
+ .Select(x => x.Path.Substring(path.Length))
+ .Where(x => x.Contains('/'))
+ .Select(x => path + x.Split('/').First())
+ .Distinct();
+ }
+
+ public void Dispose()
+ {
+ if (_leaveOpen) return;
+ _package?.Dispose();
+ }
+ }
+}
diff --git a/Sledge.Formats.Packages/Sledge.Formats.Packages.csproj b/Sledge.Formats.Packages/Sledge.Formats.Packages.csproj
index d96c814..c9ed772 100644
--- a/Sledge.Formats.Packages/Sledge.Formats.Packages.csproj
+++ b/Sledge.Formats.Packages/Sledge.Formats.Packages.csproj
@@ -11,8 +11,8 @@
sledge-logo.png
https://github.com/LogicAndTrick/sledge-formats
Git
- Add standard Stream constructor to PakPackage and VpkPackage
- 1.0.2
+ Implement PackageFileResolver as an IFileResolver for VPK/PAK packages
+ 1.1.0
diff --git a/Sledge.Formats.Tests/FileSystem/TestAllFileResolvers.cs b/Sledge.Formats.Tests/FileSystem/TestAllFileResolvers.cs
index bc58863..60f1eb8 100644
--- a/Sledge.Formats.Tests/FileSystem/TestAllFileResolvers.cs
+++ b/Sledge.Formats.Tests/FileSystem/TestAllFileResolvers.cs
@@ -6,6 +6,8 @@
using System.Text;
using Sledge.Formats.FileSystem;
using System.IO;
+using Sledge.Formats.Packages;
+using Sledge.Formats.Packages.FileSystem;
namespace Sledge.Formats.Tests.FileSystem;
@@ -48,7 +50,8 @@ public static void Initialize(TestContext testContext)
{ "Disk", CreateDiskFileResolver() },
{ "ZipArchive", CreateZipArchiveResolver() },
{ "VirtualSubdirectory", CreateVirtualSubdirectoryFileResolver() },
- { "Composite", CreateCompositeFileResolver() }
+ { "Composite", CreateCompositeFileResolver() },
+ { "Package", CreatePackageResolver() }
};
}
@@ -121,6 +124,22 @@ private static IFileResolver CreateZipArchiveResolver()
return resolver;
}
+ private static IFileResolver CreatePackageResolver()
+ {
+ // since this library can't create pak files (yet???), I made this in PakScape manually
+ const string pakFile = "UEFDS5UAAABAAgAAZm9sZGVyMy9mMy50eHRmb2xkZXIyL2RhdGEyLmxvZ2ZvbGRlcjIvZGF0YTEubG9nZm9sZGVyL2RhdGEyLmxvZ2ZvbGRlci9kYXRhMS5sb2d0ZXN0Mi50eHR0ZXN0MS50eHRmb2xkZXI1L2ZvbGRlcjUuMS9hYWEudHh0Zm9sZGVyNC9mNC50eHRmb2xkZXIzL2YzLnR4dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAOAAAAZm9sZGVyMi9kYXRhMi5sb2cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAEQAAAGZvbGRlcjIvZGF0YTEubG9nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKwAAABEAAABmb2xkZXIvZGF0YTIubG9nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAAQAAAAZm9sZGVyL2RhdGExLmxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAEAAAAHRlc3QyLnR4dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXAAAAAkAAAB0ZXN0MS50eHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGUAAAAJAAAAZm9sZGVyNS9mb2xkZXI1LjEvYWFhLnR4dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABuAAAAGQAAAGZvbGRlcjQvZjQudHh0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhwAAAA4AAAA=";
+ var ms = new MemoryStream(Convert.FromBase64String(pakFile));
+ var package = new PakPackage(ms);
+ var resolver = new PackageFileResolver(package, true);
+ CleanupActions.Add(() =>
+ {
+ resolver.Dispose();
+ package.Dispose();
+ ms.Dispose();
+ });
+ return resolver;
+ }
+
private static IFileResolver CreateCompositeFileResolver()
{
var ms = new MemoryStream();
@@ -183,6 +202,7 @@ void AddDisk(string filepath)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestRootDirectory(string implementationName)
{
// test that "" and "/" both take us to the root folder
@@ -200,6 +220,7 @@ public void TestRootDirectory(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestFolderExists(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -222,6 +243,7 @@ public void TestFolderExists(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestFileExists(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -244,6 +266,7 @@ public void TestFileExists(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestOpenFile(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -260,6 +283,7 @@ public void TestOpenFile(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestFileSize(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -274,6 +298,7 @@ public void TestFileSize(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestFileNotFound(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -300,6 +325,7 @@ public void TestFileNotFound(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestGetFiles(string implementationName)
{
var resolver = _resolvers[implementationName];
@@ -316,6 +342,7 @@ public void TestGetFiles(string implementationName)
[DataRow("ZipArchive")]
[DataRow("VirtualSubdirectory")]
[DataRow("Composite")]
+ [DataRow("Package")]
public void TestGetFolders(string implementationName)
{
var resolver = _resolvers[implementationName];
diff --git a/Sledge.Formats.Tests/Sledge.Formats.Tests.csproj b/Sledge.Formats.Tests/Sledge.Formats.Tests.csproj
index 6264a47..6686dc0 100644
--- a/Sledge.Formats.Tests/Sledge.Formats.Tests.csproj
+++ b/Sledge.Formats.Tests/Sledge.Formats.Tests.csproj
@@ -15,6 +15,7 @@
+
diff --git a/Sledge.Formats/FileSystem/ZipArchiveResolver.cs b/Sledge.Formats/FileSystem/ZipArchiveResolver.cs
index 05283bf..00c1851 100644
--- a/Sledge.Formats/FileSystem/ZipArchiveResolver.cs
+++ b/Sledge.Formats/FileSystem/ZipArchiveResolver.cs
@@ -25,7 +25,7 @@ public ZipArchiveResolver(string filePath)
}
///
- /// Create an instance for a .
+ /// Create an instance for a .
///
/// The ZipArchive instance
/// False to dispose the archive when this instance is disposed, true to leave it undisposed