From 1d899ae8ccc4f5c10b27d2c62ee8789872b03b1e Mon Sep 17 00:00:00 2001 From: RDW Date: Wed, 21 Aug 2024 04:11:39 +0200 Subject: [PATCH] Runtime: Add a function to more easily unpack VFS assets It's handy for non-executable files, such as shader programs (my use case) or shared libraries which need to be FFI-loaded. The latter should ideally be loaded from the VFS directly, but that's still a bit off in the future. This is a first step in the general direction, however. --- Runtime/Libraries/vfs.lua | 15 +++++++++++++++ Tests/BDD/vfs-library.spec.lua | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Runtime/Libraries/vfs.lua b/Runtime/Libraries/vfs.lua index ad7c38c6..a88366df 100644 --- a/Runtime/Libraries/vfs.lua +++ b/Runtime/Libraries/vfs.lua @@ -78,6 +78,21 @@ function vfs.dofile(zipApp, filePath) return nil, "Failed to load file " .. filePath .. " (no such entry exists)" end +function vfs.extract(zipApp, filePath) + validation.validateTable(zipApp, "zipApp") + validation.validateString(filePath, "filePath") + + local reader = zipApp.reader + for index = 1, reader:get_num_files() do + if reader:get_filename(index) == filePath then + local fileContents = reader:extract(index) + return fileContents + end + end + + return nil, "Failed to extract file " .. filePath .. " (no such entry exists)" +end + -- VFS searcher: Allow require to find files stored in the VFS of LUAZIP apps -- See https://www.lua.org/manual/5.2/manual.html#pdf-package.searchers function vfs.searcher(zipApp, moduleName) diff --git a/Tests/BDD/vfs-library.spec.lua b/Tests/BDD/vfs-library.spec.lua index 614e81b2..ba7d2cbf 100644 --- a/Tests/BDD/vfs-library.spec.lua +++ b/Tests/BDD/vfs-library.spec.lua @@ -68,4 +68,39 @@ describe("vfs", function() assertEquals(vfs.dofile(zipApp, path.win32.join("subdirectory", "another-file.lua")), 42) end) end) + + describe("extract", function() + local fileContents = C_FileSystem.ReadFile(path.join("Tests", "Fixtures", "hello-world-app.bin")) + local zipApp = assert(vfs.decode(fileContents)) + + it("should throw if an invalid zip app was passed", function() + assertThrows(function() + vfs.extract(nil, nil) + end, "Expected argument zipApp to be a table value, but received a nil value instead") + end) + + it("should throw if an invalid file path was passed", function() + assertThrows(function() + vfs.extract(zipApp, nil) + end, "Expected argument filePath to be a string value, but received a nil value instead") + end) + + it("should throw if the given file doesn't exist within the archive", function() + assertFailure(function() + return vfs.extract(zipApp, "this-file-does-not-exist") + end, "Failed to extract file this-file-does-not-exist (no such entry exists)") + end) + + it("should return the decompressed file contents", function() + local filePath = path.join("Tests", "Fixtures", "hello-world-app", "subdirectory", "another-file.lua") + local expectedFileContents = C_FileSystem.ReadFile(filePath) + + -- The fixture was apparently generated with different formatter settings - whatever + expectedFileContents = expectedFileContents:gsub("\n", "") + expectedFileContents = expectedFileContents:gsub("\r", "") + + local vfsPath = path.win32.join("subdirectory", "another-file.lua") + assertEquals(vfs.extract(zipApp, vfsPath), expectedFileContents) + end) + end) end)