From 199d97d32a49e285cc3b19764c1db45193889126 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 17 Jan 2024 22:57:53 +0100 Subject: [PATCH 1/4] Use forward declaration for VFS::Manager --- components/esm4/reader.cpp | 1 + components/esm4/reader.hpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index ce7f534786..a3ea438d65 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "grouptype.hpp" diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index c63dbd1548..92dc00b96d 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -36,13 +36,17 @@ #include #include -#include namespace ToUTF8 { class StatelessUtf8Encoder; } +namespace VFS +{ + class Manager; +} + namespace ESM4 { #pragma pack(push, 1) From d549cfd66b1132d7835c600a5e91a4e16b9ef7d4 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 16 Jan 2024 23:53:55 +0100 Subject: [PATCH 2/4] Check path for being normalized --- components/vfs/manager.cpp | 2 ++ components/vfs/pathutil.hpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index d312ce9d84..1bf789402d 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -1,6 +1,7 @@ #include "manager.hpp" #include +#include #include #include @@ -44,6 +45,7 @@ namespace VFS Files::IStreamPtr Manager::getNormalized(std::string_view normalizedName) const { + assert(Path::isNormalized(normalizedName)); const auto found = mIndex.find(normalizedName); if (found == mIndex.end()) throw std::runtime_error("Resource '" + std::string(normalizedName) + "' not found"); diff --git a/components/vfs/pathutil.hpp b/components/vfs/pathutil.hpp index 9bcc263842..0856bfffa2 100644 --- a/components/vfs/pathutil.hpp +++ b/components/vfs/pathutil.hpp @@ -15,6 +15,11 @@ namespace VFS::Path return c == '\\' ? '/' : Misc::StringUtils::toLower(c); } + inline constexpr bool isNormalized(std::string_view name) + { + return std::all_of(name.begin(), name.end(), [](char v) { return v == normalize(v); }); + } + inline void normalizeFilenameInPlace(std::string& name) { std::transform(name.begin(), name.end(), name.begin(), normalize); From 9279138fb0c9e138846b259ea0e566f4c8ae01d7 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 16 Jan 2024 23:55:42 +0100 Subject: [PATCH 3/4] Accept normalized path by VFS::Manager functions --- components/vfs/manager.cpp | 13 ++++++------- components/vfs/manager.hpp | 7 ++++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index 1bf789402d..a6add0861a 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -38,9 +38,9 @@ namespace VFS archive->listResources(mIndex); } - Files::IStreamPtr Manager::get(std::string_view name) const + Files::IStreamPtr Manager::get(const Path::Normalized& name) const { - return getNormalized(Path::normalizeFilename(name)); + return getNormalized(name); } Files::IStreamPtr Manager::getNormalized(std::string_view normalizedName) const @@ -52,17 +52,16 @@ namespace VFS return found->second->open(); } - bool Manager::exists(std::string_view name) const + bool Manager::exists(const Path::Normalized& name) const { - return mIndex.find(Path::normalizeFilename(name)) != mIndex.end(); + return mIndex.find(name) != mIndex.end(); } - std::string Manager::getArchive(std::string_view name) const + std::string Manager::getArchive(const Path::Normalized& name) const { - std::string normalized = Path::normalizeFilename(name); for (auto it = mArchives.rbegin(); it != mArchives.rend(); ++it) { - if ((*it)->contains(normalized)) + if ((*it)->contains(name)) return (*it)->getDescription(); } return {}; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index 05990a8607..7598b77e68 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -10,6 +10,7 @@ #include #include "filemap.hpp" +#include "pathutil.hpp" namespace VFS { @@ -40,19 +41,19 @@ namespace VFS /// Does a file with this name exist? /// @note May be called from any thread once the index has been built. - bool exists(std::string_view name) const; + bool exists(const Path::Normalized& name) const; /// Retrieve a file by name. /// @note Throws an exception if the file can not be found. /// @note May be called from any thread once the index has been built. - Files::IStreamPtr get(std::string_view name) const; + Files::IStreamPtr get(const Path::Normalized& name) const; /// Retrieve a file by name (name is already normalized). /// @note Throws an exception if the file can not be found. /// @note May be called from any thread once the index has been built. Files::IStreamPtr getNormalized(std::string_view normalizedName) const; - std::string getArchive(std::string_view name) const; + std::string getArchive(const Path::Normalized& name) const; /// Recursively iterate over the elements of the given path /// In practice it return all files of the VFS starting with the given path From 70061329a11c6a76cf79dce30aae959d537b4594 Mon Sep 17 00:00:00 2001 From: elsid Date: Wed, 17 Jan 2024 23:32:15 +0100 Subject: [PATCH 4/4] Return Path::Normalized from RecursiveDirectoryIterator --- apps/niftest/niftest.cpp | 4 ++-- apps/opencs/model/world/resources.cpp | 15 +++++++-------- components/vfs/recursivedirectoryiterator.hpp | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 9352651030..ee6e84295f 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -113,9 +113,9 @@ void readVFS(std::unique_ptr&& archive, const std::filesystem::pat for (const auto& name : vfs.getRecursiveDirectoryIterator("")) { - if (isNIF(name)) + if (isNIF(name.value())) { - readNIF(archivePath, name, &vfs, quiet); + readNIF(archivePath, name.value(), &vfs, quiet); } } diff --git a/apps/opencs/model/world/resources.cpp b/apps/opencs/model/world/resources.cpp index 345f6008ec..9957af3d66 100644 --- a/apps/opencs/model/world/resources.cpp +++ b/apps/opencs/model/world/resources.cpp @@ -30,18 +30,18 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char* const* e for (const auto& filepath : vfs->getRecursiveDirectoryIterator("")) { - if (filepath.size() < baseSize + 1 || filepath.substr(0, baseSize) != mBaseDirectory - || (filepath[baseSize] != '/' && filepath[baseSize] != '\\')) + const std::string_view view = filepath.view(); + if (view.size() < baseSize + 1 || !view.starts_with(mBaseDirectory) || view[baseSize] != '/') continue; if (extensions) { - std::string::size_type extensionIndex = filepath.find_last_of('.'); + const auto extensionIndex = view.find_last_of('.'); - if (extensionIndex == std::string::npos) + if (extensionIndex == std::string_view::npos) continue; - std::string extension = filepath.substr(extensionIndex + 1); + std::string_view extension = view.substr(extensionIndex + 1); int i = 0; @@ -53,10 +53,9 @@ void CSMWorld::Resources::recreate(const VFS::Manager* vfs, const char* const* e continue; } - std::string file = filepath.substr(baseSize + 1); + std::string file(view.substr(baseSize + 1)); mFiles.push_back(file); - std::replace(file.begin(), file.end(), '\\', '/'); - mIndex.insert(std::make_pair(Misc::StringUtils::lowerCase(file), static_cast(mFiles.size()) - 1)); + mIndex.emplace(std::move(file), static_cast(mFiles.size()) - 1); } } diff --git a/components/vfs/recursivedirectoryiterator.hpp b/components/vfs/recursivedirectoryiterator.hpp index 39fb26e873..3410a2092b 100644 --- a/components/vfs/recursivedirectoryiterator.hpp +++ b/components/vfs/recursivedirectoryiterator.hpp @@ -16,9 +16,9 @@ namespace VFS { } - const std::string& operator*() const { return mIt->first.value(); } + const Path::Normalized& operator*() const { return mIt->first; } - const std::string* operator->() const { return &mIt->first.value(); } + const Path::Normalized* operator->() const { return &mIt->first; } RecursiveDirectoryIterator& operator++() {