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 FileContentEntry;
|
||||||
struct PhysicalDirectoryEntry;
|
struct PhysicalDirectoryEntry;
|
||||||
struct PhysicalFileEntry;
|
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::weak_ptr<VirtualDirectory> parentDirectory = {});
|
||||||
inline VirtualDirectory(std::filesystem::path physicalPath, 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> 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 GetEntry(std::string_view path, F&& callback);
|
||||||
template<typename F> bool GetFileContent(std::string_view path, F&& callback);
|
template<typename F> bool GetFileContent(std::string_view path, F&& callback);
|
||||||
|
|
||||||
inline bool IsUprootAllowed() const;
|
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 PhysicalDirectoryEntry& StoreDirectory(std::string_view path, std::filesystem::path directoryPath);
|
||||||
inline FileContentEntry& StoreFile(std::string_view path, std::vector<UInt8> file);
|
inline FileContentEntry& StoreFile(std::string_view path, std::vector<UInt8> file);
|
||||||
inline PhysicalFileEntry& StoreFile(std::string_view path, std::filesystem::path filePath);
|
inline PhysicalFileEntry& StoreFile(std::string_view path, std::filesystem::path filePath);
|
||||||
|
|
@ -59,32 +61,38 @@ namespace Nz
|
||||||
VirtualDirectory& operator=(const VirtualDirectory&) = delete;
|
VirtualDirectory& operator=(const VirtualDirectory&) = delete;
|
||||||
VirtualDirectory& operator=(VirtualDirectory&&) = delete;
|
VirtualDirectory& operator=(VirtualDirectory&&) = delete;
|
||||||
|
|
||||||
|
// File entries
|
||||||
struct DataPointerEntry
|
struct DataPointerEntry
|
||||||
{
|
{
|
||||||
const void* data;
|
const void* data;
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DirectoryEntry
|
|
||||||
{
|
|
||||||
VirtualDirectoryPtr directory;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileContentEntry
|
struct FileContentEntry
|
||||||
{
|
{
|
||||||
std::vector<UInt8> data;
|
std::vector<UInt8> data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PhysicalDirectoryEntry
|
struct PhysicalFileEntry
|
||||||
{
|
{
|
||||||
std::filesystem::path filePath;
|
std::filesystem::path filePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PhysicalFileEntry
|
// Directory entries
|
||||||
|
struct DirectoryEntry
|
||||||
|
{
|
||||||
|
VirtualDirectoryPtr directory;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PhysicalDirectoryEntry : DirectoryEntry
|
||||||
{
|
{
|
||||||
std::filesystem::path filePath;
|
std::filesystem::path filePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct VirtualDirectoryEntry : DirectoryEntry
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename F> bool GetEntryInternal(std::string_view name, F&& callback);
|
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);
|
inline bool CreateOrRetrieveDirectory(std::string_view path, std::shared_ptr<VirtualDirectory>& directory, std::string_view& entryName);
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,11 @@ namespace Nz
|
||||||
{
|
{
|
||||||
if (includeDots)
|
if (includeDots)
|
||||||
{
|
{
|
||||||
Entry ourselves = DirectoryEntry{ shared_from_this() };
|
Entry ourselves = VirtualDirectoryEntry{ shared_from_this() };
|
||||||
callback(std::string_view("."), ourselves);
|
callback(std::string_view("."), ourselves);
|
||||||
if (VirtualDirectoryPtr parent = m_parent.lock())
|
if (VirtualDirectoryPtr parent = m_parent.lock())
|
||||||
{
|
{
|
||||||
Entry parentEntry = DirectoryEntry{ parent };
|
Entry parentEntry = VirtualDirectoryEntry{ parent };
|
||||||
if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
|
if (!CallbackReturn(callback, std::string_view(".."), parentEntry))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +77,10 @@ namespace Nz
|
||||||
if (std::filesystem::is_regular_file(status))
|
if (std::filesystem::is_regular_file(status))
|
||||||
entry = PhysicalFileEntry{ physicalEntry.path() };
|
entry = PhysicalFileEntry{ physicalEntry.path() };
|
||||||
else if (std::filesystem::is_directory(status))
|
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
|
else
|
||||||
continue;
|
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)
|
template<typename F> bool VirtualDirectory::GetEntry(std::string_view path, F&& callback)
|
||||||
{
|
{
|
||||||
assert(!path.empty());
|
assert(!path.empty());
|
||||||
|
|
@ -117,7 +144,7 @@ namespace Nz
|
||||||
|
|
||||||
return currentDir->GetEntryInternal(dirName, [&](const Entry& entry)
|
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;
|
currentDir = dirEntry->directory;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -150,7 +177,10 @@ namespace Nz
|
||||||
if (std::filesystem::is_regular_file(status))
|
if (std::filesystem::is_regular_file(status))
|
||||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||||
else if (std::filesystem::is_directory(status))
|
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
|
else
|
||||||
return false; //< either not known or of a special type
|
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()));
|
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");
|
NazaraError("entry is a directory");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -205,7 +235,7 @@ namespace Nz
|
||||||
return m_isUprootAllowed;
|
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());
|
assert(!path.empty());
|
||||||
|
|
||||||
|
|
@ -217,7 +247,7 @@ namespace Nz
|
||||||
if (entryName == "." || entryName == "..")
|
if (entryName == "." || entryName == "..")
|
||||||
throw std::runtime_error("invalid entry name");
|
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&
|
inline auto VirtualDirectory::StoreDirectory(std::string_view path, std::filesystem::path directoryPath) -> PhysicalDirectoryEntry&
|
||||||
|
|
@ -232,7 +262,11 @@ namespace Nz
|
||||||
if (entryName == "." || entryName == "..")
|
if (entryName == "." || entryName == "..")
|
||||||
throw std::runtime_error("invalid entry name");
|
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&
|
inline auto VirtualDirectory::StoreFile(std::string_view path, std::vector<UInt8> file) -> FileContentEntry&
|
||||||
|
|
@ -284,7 +318,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
if (name == ".")
|
if (name == ".")
|
||||||
{
|
{
|
||||||
Entry entry{ DirectoryEntry{ shared_from_this() } };
|
Entry entry{ VirtualDirectoryEntry{ shared_from_this() } };
|
||||||
return CallbackReturn(callback, entry);
|
return CallbackReturn(callback, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,7 +332,7 @@ namespace Nz
|
||||||
|
|
||||||
if (parentEntry)
|
if (parentEntry)
|
||||||
{
|
{
|
||||||
Entry entry = DirectoryEntry{ std::move(parentEntry) };
|
Entry entry = VirtualDirectoryEntry{ std::move(parentEntry) };
|
||||||
return CallbackReturn(callback, entry);
|
return CallbackReturn(callback, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -319,7 +353,10 @@ namespace Nz
|
||||||
if (std::filesystem::is_regular_file(status))
|
if (std::filesystem::is_regular_file(status))
|
||||||
entry = PhysicalFileEntry{ std::move(filePath) };
|
entry = PhysicalFileEntry{ std::move(filePath) };
|
||||||
else if (std::filesystem::is_directory(status))
|
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
|
else
|
||||||
return false; //< either not known or of a special type
|
return false; //< either not known or of a special type
|
||||||
|
|
||||||
|
|
@ -343,7 +380,7 @@ namespace Nz
|
||||||
|
|
||||||
bool dirFound = directory->GetEntryInternal(dirName, [&](const Entry& entry)
|
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;
|
directory = dirEntry->directory;
|
||||||
else
|
else
|
||||||
allowCreation = false; //< does exist but is not a directory
|
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)
|
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)
|
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*/)
|
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)
|
auto CheckOurselves = [&](const auto& entry)
|
||||||
{
|
{
|
||||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::DirectoryEntry>(entry));
|
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry));
|
||||||
const auto& dirEntry = std::get<Nz::VirtualDirectory::DirectoryEntry>(entry);
|
const auto& dirEntry = std::get<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||||
return dirEntry.directory == resourceDir;
|
return dirEntry.directory == resourceDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -279,6 +279,24 @@ TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
||||||
CHECK(CheckFileContentHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
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")
|
WHEN("Testing uproot escape")
|
||||||
{
|
{
|
||||||
std::shared_ptr<Nz::VirtualDirectory> engineDir = std::make_shared<Nz::VirtualDirectory>(GetAssetDir() / "Audio");
|
std::shared_ptr<Nz::VirtualDirectory> engineDir = std::make_shared<Nz::VirtualDirectory>(GetAssetDir() / "Audio");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue