Core/VirtualDirectory: Handle physical directories as virtual directories
This commit is contained in:
parent
e7f4714747
commit
2229dfd6e5
|
|
@ -30,8 +30,9 @@ namespace Nz
|
|||
struct FileContentEntry;
|
||||
struct PhysicalDirectoryEntry;
|
||||
struct PhysicalFileEntry;
|
||||
struct VirtualDirectoryEntry;
|
||||
|
||||
using Entry = std::variant<DataPointerEntry, DirectoryEntry, FileContentEntry, PhysicalDirectoryEntry, PhysicalFileEntry>;
|
||||
using Entry = std::variant<DataPointerEntry, FileContentEntry, PhysicalDirectoryEntry, PhysicalFileEntry, VirtualDirectoryEntry>;
|
||||
|
||||
inline VirtualDirectory(std::weak_ptr<VirtualDirectory> parentDirectory = {});
|
||||
inline VirtualDirectory(std::filesystem::path physicalPath, std::weak_ptr<VirtualDirectory> parentDirectory = {});
|
||||
|
|
@ -45,12 +46,13 @@ namespace Nz
|
|||
|
||||
template<typename F> void Foreach(F&& callback, bool includeDots = false);
|
||||
|
||||
template<typename F> bool GetDirectoryEntry(std::string_view path, F&& callback);
|
||||
template<typename F> bool GetEntry(std::string_view path, F&& callback);
|
||||
template<typename F> bool GetFileContent(std::string_view path, F&& callback);
|
||||
|
||||
inline bool IsUprootAllowed() const;
|
||||
|
||||
inline DirectoryEntry& StoreDirectory(std::string_view path, VirtualDirectoryPtr directory);
|
||||
inline VirtualDirectoryEntry& StoreDirectory(std::string_view path, VirtualDirectoryPtr directory);
|
||||
inline PhysicalDirectoryEntry& StoreDirectory(std::string_view path, std::filesystem::path directoryPath);
|
||||
inline FileContentEntry& StoreFile(std::string_view path, std::vector<UInt8> file);
|
||||
inline PhysicalFileEntry& StoreFile(std::string_view path, std::filesystem::path filePath);
|
||||
|
|
@ -59,32 +61,38 @@ namespace Nz
|
|||
VirtualDirectory& operator=(const VirtualDirectory&) = delete;
|
||||
VirtualDirectory& operator=(VirtualDirectory&&) = delete;
|
||||
|
||||
// File entries
|
||||
struct DataPointerEntry
|
||||
{
|
||||
const void* data;
|
||||
std::size_t size;
|
||||
};
|
||||
|
||||
struct DirectoryEntry
|
||||
{
|
||||
VirtualDirectoryPtr directory;
|
||||
};
|
||||
|
||||
struct FileContentEntry
|
||||
{
|
||||
std::vector<UInt8> data;
|
||||
};
|
||||
|
||||
struct PhysicalDirectoryEntry
|
||||
struct PhysicalFileEntry
|
||||
{
|
||||
std::filesystem::path filePath;
|
||||
};
|
||||
|
||||
struct PhysicalFileEntry
|
||||
// Directory entries
|
||||
struct DirectoryEntry
|
||||
{
|
||||
VirtualDirectoryPtr directory;
|
||||
};
|
||||
|
||||
struct PhysicalDirectoryEntry : DirectoryEntry
|
||||
{
|
||||
std::filesystem::path filePath;
|
||||
};
|
||||
|
||||
struct VirtualDirectoryEntry : DirectoryEntry
|
||||
{
|
||||
};
|
||||
|
||||
private:
|
||||
template<typename F> bool GetEntryInternal(std::string_view name, F&& callback);
|
||||
inline bool CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName);
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ namespace Nz
|
|||
{
|
||||
if (includeDots)
|
||||
{
|
||||
Entry ourselves = DirectoryEntry{ shared_from_this() };
|
||||
Entry ourselves = VirtualDirectoryEntry{ shared_from_this() };
|
||||
callback(std::string_view("."), ourselves);
|
||||
if (VirtualDirectoryPtr parent = m_parent.lock())
|
||||
{
|
||||
Entry parentEntry = DirectoryEntry{ parent };
|
||||
Entry parentEntry = VirtualDirectoryEntry{ parent };
|
||||
if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
|
||||
return;
|
||||
}
|
||||
|
|
@ -77,7 +77,10 @@ namespace Nz
|
|||
if (std::filesystem::is_regular_file(status))
|
||||
entry = PhysicalFileEntry{ physicalEntry.path() };
|
||||
else if (std::filesystem::is_directory(status))
|
||||
entry = PhysicalDirectoryEntry{ physicalEntry.path() };
|
||||
{
|
||||
VirtualDirectoryPtr virtualDir = std::make_shared<VirtualDirectory>(physicalEntry.path(), weak_from_this());
|
||||
entry = PhysicalDirectoryEntry{ std::move(virtualDir), physicalEntry.path() };
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
|
|
@ -87,6 +90,30 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
bool VirtualDirectory::GetDirectoryEntry(std::string_view path, F&& callback)
|
||||
{
|
||||
return GetEntry(path, [&](const Entry& entry)
|
||||
{
|
||||
return std::visit([&](auto&& entry)
|
||||
{
|
||||
using T = std::decay_t<decltype(entry)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, VirtualDirectoryEntry> || std::is_same_v<T, PhysicalDirectoryEntry>)
|
||||
{
|
||||
return CallbackReturn(callback, static_cast<const DirectoryEntry&>(entry));
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, DataPointerEntry> || std::is_same_v<T, FileContentEntry> || std::is_same_v<T, PhysicalFileEntry>)
|
||||
{
|
||||
NazaraError("entry is a file");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
static_assert(AlwaysFalse<T>(), "incomplete visitor");
|
||||
}, entry);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
|
||||
{
|
||||
assert(!path.empty());
|
||||
|
|
@ -117,7 +144,7 @@ namespace Nz
|
|||
|
||||
return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
|
||||
{
|
||||
if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
|
||||
if (auto dirEntry = std::get_if<VirtualDirectoryEntry>(&entry))
|
||||
{
|
||||
currentDir = dirEntry->directory;
|
||||
return true;
|
||||
|
|
@ -150,7 +177,10 @@ namespace Nz
|
|||
if (std::filesystem::is_regular_file(status))
|
||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||
else if (std::filesystem::is_directory(status))
|
||||
entry = PhysicalDirectoryEntry{ std::move(filePath) };
|
||||
{
|
||||
VirtualDirectoryPtr virtualDir = std::make_shared<VirtualDirectory>(filePath, weak_from_this());
|
||||
entry = PhysicalDirectoryEntry{ std::move(virtualDir), std::move(filePath) };
|
||||
}
|
||||
else
|
||||
return false; //< either not known or of a special type
|
||||
|
||||
|
|
@ -189,7 +219,7 @@ namespace Nz
|
|||
|
||||
return CallbackReturn(callback, static_cast<P1>(source->data()), SafeCast<P2>(source->size()));
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, DirectoryEntry> || std::is_same_v<T, PhysicalDirectoryEntry>)
|
||||
else if constexpr (std::is_same_v<T, VirtualDirectoryEntry> || std::is_same_v<T, PhysicalDirectoryEntry>)
|
||||
{
|
||||
NazaraError("entry is a directory");
|
||||
return false;
|
||||
|
|
@ -205,7 +235,7 @@ namespace Nz
|
|||
return m_isUprootAllowed;
|
||||
}
|
||||
|
||||
inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> DirectoryEntry&
|
||||
inline auto VirtualDirectory::StoreDirectory(std::string_view path, VirtualDirectoryPtr directory) -> VirtualDirectoryEntry&
|
||||
{
|
||||
assert(!path.empty());
|
||||
|
||||
|
|
@ -217,7 +247,7 @@ namespace Nz
|
|||
if (entryName == "." || entryName == "..")
|
||||
throw std::runtime_error("invalid entry name");
|
||||
|
||||
return dir->StoreInternal(std::string(entryName), DirectoryEntry{ std::move(directory) });
|
||||
return dir->StoreInternal(std::string(entryName), VirtualDirectoryEntry{ std::move(directory) });
|
||||
}
|
||||
|
||||
inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
|
||||
|
|
@ -232,7 +262,11 @@ namespace Nz
|
|||
if (entryName == "." || entryName == "..")
|
||||
throw std::runtime_error("invalid entry name");
|
||||
|
||||
return dir->StoreInternal(std::string(entryName), PhysicalDirectoryEntry{ std::move(directoryPath) });
|
||||
PhysicalDirectoryEntry entry;
|
||||
entry.directory = std::make_shared<VirtualDirectory>(directoryPath, dir);
|
||||
entry.filePath = std::move(directoryPath);
|
||||
|
||||
return dir->StoreInternal(std::string(entryName), std::move(entry));
|
||||
}
|
||||
|
||||
inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
|
||||
|
|
@ -284,7 +318,7 @@ namespace Nz
|
|||
{
|
||||
if (name == ".")
|
||||
{
|
||||
Entry entry{ DirectoryEntry{ shared_from_this() } };
|
||||
Entry entry{ VirtualDirectoryEntry{ shared_from_this() } };
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
|
||||
|
|
@ -298,7 +332,7 @@ namespace Nz
|
|||
|
||||
if (parentEntry)
|
||||
{
|
||||
Entry entry = DirectoryEntry{ std::move(parentEntry) };
|
||||
Entry entry = VirtualDirectoryEntry{ std::move(parentEntry) };
|
||||
return CallbackReturn(callback, entry);
|
||||
}
|
||||
}
|
||||
|
|
@ -319,7 +353,10 @@ namespace Nz
|
|||
if (std::filesystem::is_regular_file(status))
|
||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||
else if (std::filesystem::is_directory(status))
|
||||
entry = PhysicalDirectoryEntry{ std::move(filePath) };
|
||||
{
|
||||
VirtualDirectoryPtr virtualDir = std::make_shared<VirtualDirectory>(filePath, weak_from_this());
|
||||
entry = PhysicalDirectoryEntry{ std::move(virtualDir), std::move(filePath) };
|
||||
}
|
||||
else
|
||||
return false; //< either not known or of a special type
|
||||
|
||||
|
|
@ -343,7 +380,7 @@ namespace Nz
|
|||
|
||||
bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
|
||||
{
|
||||
if (auto dirEntry = std::get_if<DirectoryEntry>(&entry))
|
||||
if (auto dirEntry = std::get_if<VirtualDirectoryEntry>(&entry))
|
||||
directory = dirEntry->directory;
|
||||
else
|
||||
allowCreation = false; //< does exist but is not a directory
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
|
||||
CHECK(virtualDir->GetEntry("Foo", [](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
return std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry);
|
||||
return std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
}));
|
||||
|
||||
CHECK(virtualDir->GetEntry("Foo/Bar", [](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
return std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry);
|
||||
return std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
}));
|
||||
|
||||
CHECK_FALSE(virtualDir->GetEntry("Foo/Bar/File.bin", [](const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
|
|
@ -257,8 +257,8 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
|
||||
auto CheckOurselves = [&](const auto& entry)
|
||||
{
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry));
|
||||
const auto& dirEntry = std::get<Nz::VirtualDirectory::DirectoryEntry>(entry);
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry));
|
||||
const auto& dirEntry = std::get<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
return dirEntry.directory == resourceDir;
|
||||
};
|
||||
|
||||
|
|
@ -279,6 +279,24 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
|||
CHECK(CheckFileContentHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
}
|
||||
|
||||
WHEN("Accessing physical folder as a virtual folder")
|
||||
{
|
||||
CHECK(resourceDir->GetDirectoryEntry("Utility", [&](const Nz::VirtualDirectory::DirectoryEntry& directoryEntry)
|
||||
{
|
||||
bool found = false;
|
||||
directoryEntry.directory->Foreach([&](std::string_view entryName, const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
if (entryName == "GIF")
|
||||
{
|
||||
CHECK(std::holds_alternative<Nz::VirtualDirectory::PhysicalDirectoryEntry>(entry));
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}));
|
||||
}
|
||||
|
||||
WHEN("Testing uproot escape")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> engineDir = std::make_shared<Nz::VirtualDirectory>(GetAssetDir() / "Audio");
|
||||
|
|
|
|||
Loading…
Reference in New Issue