From eeda48ec50b2234cc1859fa534ed23b7110d22c1 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 31 May 2023 23:11:03 +0200 Subject: [PATCH] Drop support for --fs-strict --- CHANGELOG.md | 1 + README.md | 2 - apps/bulletobjecttool/main.cpp | 8 +-- apps/navmeshtool/main.cpp | 8 +-- apps/niftest/niftest.cpp | 4 +- apps/opencs/editor.cpp | 5 +- apps/opencs/editor.hpp | 1 - apps/opencs/model/doc/document.cpp | 4 +- apps/opencs/model/doc/document.hpp | 2 +- apps/opencs/model/doc/documentmanager.cpp | 8 +-- apps/opencs/model/doc/documentmanager.hpp | 3 +- apps/opencs/model/world/data.cpp | 9 ++- apps/opencs/model/world/data.hpp | 5 +- apps/openmw/engine.cpp | 10 +--- apps/openmw/engine.hpp | 7 --- apps/openmw/main.cpp | 3 - apps/openmw/mwlua/luamanagerimp.cpp | 1 - apps/openmw/mwsound/sound_buffer.cpp | 9 ++- apps/openmw/mwsound/sound_buffer.hpp | 3 +- apps/openmw/mwsound/soundmanagerimp.cpp | 6 +- apps/openmw/options.cpp | 3 - apps/openmw_test_suite/esm3/readerscache.cpp | 2 +- apps/openmw_test_suite/esmloader/load.cpp | 2 +- apps/openmw_test_suite/mwworld/test_store.cpp | 2 +- .../nifosg/testnifloader.cpp | 2 +- apps/openmw_test_suite/testing_util.hpp | 12 +--- components/files/collections.cpp | 20 ++----- components/files/collections.hpp | 3 +- components/files/multidircollection.cpp | 24 +------- components/files/multidircollection.hpp | 21 +------ components/lua_ui/resources.cpp | 4 +- components/lua_ui/resources.hpp | 6 -- components/misc/resourcehelpers.cpp | 8 ++- components/resource/bulletshapemanager.cpp | 7 ++- components/resource/imagemanager.cpp | 3 +- components/resource/keyframemanager.cpp | 5 +- components/resource/keyframemanager.hpp | 2 +- components/resource/resourcemanager.hpp | 4 +- components/resource/scenemanager.cpp | 5 +- components/vfs/archive.hpp | 11 ++-- components/vfs/bsaarchive.hpp | 11 ++-- components/vfs/filesystemarchive.cpp | 17 +++--- components/vfs/filesystemarchive.hpp | 4 +- components/vfs/manager.cpp | 58 +++---------------- components/vfs/manager.hpp | 17 +----- components/vfs/pathutil.hpp | 50 ++++++++++++++++ 46 files changed, 147 insertions(+), 255 deletions(-) create mode 100644 components/vfs/pathutil.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index df087c3979..1b2eb2c31a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Task #7113: Move from std::atoi to std::from_char Task #7117: Replace boost::scoped_array with std::vector Task #7151: Do not use std::strerror to get errno error message + Task #7394: Drop support for --fs-strict 0.48.0 ------ diff --git a/README.md b/README.md index 029054703b..95ca19685d 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,6 @@ Command line options --skip-menu [=arg(=1)] (=0) skip main menu on game startup --new-game [=arg(=1)] (=0) run new game sequence (ignored if skip-menu=0) - --fs-strict [=arg(=1)] (=0) strict file system handling (no case - folding) --encoding arg (=win1252) Character encoding used in OpenMW game messages: diff --git a/apps/bulletobjecttool/main.cpp b/apps/bulletobjecttool/main.cpp index c41a0370ac..2610061af6 100644 --- a/apps/bulletobjecttool/main.cpp +++ b/apps/bulletobjecttool/main.cpp @@ -83,9 +83,6 @@ namespace addOption("content", bpo::value()->default_value(StringsVector(), "")->multitoken()->composing(), "content file(s): esm/esp, or omwgame/omwaddon/omwscripts"); - addOption("fs-strict", bpo::value()->implicit_value(true)->default_value(false), - "strict file system handling (no case folding)"); - addOption("encoding", bpo::value()->default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, " @@ -148,18 +145,17 @@ namespace config.filterOutNonExistingPaths(dataDirs); - const auto fsStrict = variables["fs-strict"].as(); const auto resDir = variables["resources"].as(); const auto v = Version::getOpenmwVersion(resDir); Log(Debug::Info) << v.describe(); dataDirs.insert(dataDirs.begin(), resDir / "vfs"); - const auto fileCollections = Files::Collections(dataDirs, !fsStrict); + const auto fileCollections = Files::Collections(dataDirs); const auto archives = variables["fallback-archive"].as(); const auto contentFiles = variables["content"].as(); Fallback::Map::init(variables["fallback"].as().mMap); - VFS::Manager vfs(fsStrict); + VFS::Manager vfs; VFS::registerArchives(&vfs, fileCollections, archives, true); diff --git a/apps/navmeshtool/main.cpp b/apps/navmeshtool/main.cpp index 0dfaf86783..2a379a6fe3 100644 --- a/apps/navmeshtool/main.cpp +++ b/apps/navmeshtool/main.cpp @@ -96,9 +96,6 @@ namespace NavMeshTool bpo::value()->default_value(StringsVector(), "")->multitoken()->composing(), "content file(s): esm/esp, or omwgame/omwaddon/omwscripts"); - addOption("fs-strict", bpo::value()->implicit_value(true)->default_value(false), - "strict file system handling (no case folding)"); - addOption("encoding", bpo::value()->default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, " @@ -167,12 +164,11 @@ namespace NavMeshTool config.filterOutNonExistingPaths(dataDirs); - const auto fsStrict = variables["fs-strict"].as(); const auto resDir = variables["resources"].as(); Version::Version v = Version::getOpenmwVersion(resDir); Log(Debug::Info) << v.describe(); dataDirs.insert(dataDirs.begin(), resDir / "vfs"); - const auto fileCollections = Files::Collections(dataDirs, !fsStrict); + const auto fileCollections = Files::Collections(dataDirs); const auto archives = variables["fallback-archive"].as(); const auto contentFiles = variables["content"].as(); const std::size_t threadsNumber = variables["threads"].as(); @@ -194,7 +190,7 @@ namespace NavMeshTool Fallback::Map::init(variables["fallback"].as().mMap); - VFS::Manager vfs(fsStrict); + VFS::Manager vfs; VFS::registerArchives(&vfs, fileCollections, archives, true); diff --git a/apps/niftest/niftest.cpp b/apps/niftest/niftest.cpp index 9bb9b67143..d08ccce4b8 100644 --- a/apps/niftest/niftest.cpp +++ b/apps/niftest/niftest.cpp @@ -79,7 +79,7 @@ void readVFS(std::unique_ptr&& anArchive, const std::filesystem::p if (anArchive == nullptr) return; - VFS::Manager myManager(true); + VFS::Manager myManager; myManager.addArchive(std::move(anArchive)); myManager.buildIndex(); @@ -176,7 +176,7 @@ int main(int argc, char** argv) std::unique_ptr vfs; if (!archives.empty()) { - vfs = std::make_unique(true); + vfs = std::make_unique(); for (const std::filesystem::path& path : archives) if (auto archive = makeArchive(path)) vfs->addArchive(std::move(archive)); diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 82a3c6e2f5..416d059735 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -62,7 +62,7 @@ CS::Editor::Editor(int argc, char** argv) NifOsg::Loader::setShowMarkers(true); - mDocumentManager.setFileData(mFsStrict, config.first, config.second); + mDocumentManager.setFileData(config.first, config.second); mNewGame.setLocalData(mLocal); mFileDialog.setLocalData(mLocal); @@ -118,7 +118,6 @@ boost::program_options::variables_map CS::Editor::readConfiguration() addOption("data-local", boost::program_options::value()->default_value( Files::MaybeQuotedPathContainer::value_type(), "")); - addOption("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)); addOption("encoding", boost::program_options::value()->default_value("win1252")); addOption("resources", boost::program_options::value()->default_value(Files::MaybeQuotedPath(), "resources")); @@ -165,8 +164,6 @@ std::pair> CS::Editor::readConfig if (variables["script-blacklist-use"].as()) mDocumentManager.setBlacklistedScripts(variables["script-blacklist"].as>()); - mFsStrict = variables["fs-strict"].as(); - Files::PathContainer dataDirs, dataLocal; if (!variables["data"].empty()) { diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 453a3d848a..79c658c04d 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -60,7 +60,6 @@ namespace CS std::filesystem::path mPid; QLockFile mLockFile; std::ofstream mPidFile; - bool mFsStrict; CSVTools::Merge mMerge; CSVDoc::ViewManager* mViewManager; std::filesystem::path mFileToLoad; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 41ff885649..9ee2a8bc48 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -296,12 +296,12 @@ void CSMDoc::Document::createBase() CSMDoc::Document::Document(const Files::ConfigurationManager& configuration, std::vector files, bool new_, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, - const std::vector& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& blacklistedScripts, const Files::PathContainer& dataPaths, const std::vector& archives) : mSavePath(savePath) , mContentFiles(std::move(files)) , mNew(new_) - , mData(encoding, fsStrict, dataPaths, archives, resDir) + , mData(encoding, dataPaths, archives, resDir) , mTools(*this, encoding) , mProjectPath((configuration.getUserDataPath() / "projects") / (savePath.filename().u8string() + u8".project")) , mSavingOperation(*this, mProjectPath, encoding) diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 99e081a80c..4acdfafa41 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -95,7 +95,7 @@ namespace CSMDoc public: Document(const Files::ConfigurationManager& configuration, std::vector files, bool new_, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, - const std::vector& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, + const std::vector& blacklistedScripts, const Files::PathContainer& dataPaths, const std::vector& archives); ~Document() override = default; diff --git a/apps/opencs/model/doc/documentmanager.cpp b/apps/opencs/model/doc/documentmanager.cpp index d9dd0dd8f2..4052c8a789 100644 --- a/apps/opencs/model/doc/documentmanager.cpp +++ b/apps/opencs/model/doc/documentmanager.cpp @@ -17,7 +17,6 @@ CSMDoc::DocumentManager::DocumentManager(const Files::ConfigurationManager& configuration) : mConfiguration(configuration) , mEncoding(ToUTF8::WINDOWS_1252) - , mFsStrict(false) { std::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; @@ -62,8 +61,8 @@ void CSMDoc::DocumentManager::addDocument( CSMDoc::Document* CSMDoc::DocumentManager::makeDocument( const std::vector& files, const std::filesystem::path& savePath, bool new_) { - return new Document(mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mFsStrict, - mDataPaths, mArchives); + return new Document( + mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mDataPaths, mArchives); } void CSMDoc::DocumentManager::insertDocument(CSMDoc::Document* document) @@ -123,9 +122,8 @@ void CSMDoc::DocumentManager::documentNotLoaded(Document* document, const std::s } void CSMDoc::DocumentManager::setFileData( - bool strict, const Files::PathContainer& dataPaths, const std::vector& archives) + const Files::PathContainer& dataPaths, const std::vector& archives) { - mFsStrict = strict; mDataPaths = dataPaths; mArchives = archives; } diff --git a/apps/opencs/model/doc/documentmanager.hpp b/apps/opencs/model/doc/documentmanager.hpp index 31256ca08a..25f7d1d4f0 100644 --- a/apps/opencs/model/doc/documentmanager.hpp +++ b/apps/opencs/model/doc/documentmanager.hpp @@ -35,7 +35,6 @@ namespace CSMDoc std::filesystem::path mResDir; - bool mFsStrict; Files::PathContainer mDataPaths; std::vector mArchives; @@ -68,7 +67,7 @@ namespace CSMDoc void setBlacklistedScripts(const std::vector& scriptIds); /// Sets the file data that gets passed to newly created documents. - void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector& archives); + void setFileData(const Files::PathContainer& dataPaths, const std::vector& archives); bool isEmpty(); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 1653e8a6b1..07e9879795 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -132,7 +132,7 @@ int CSMWorld::Data::count(RecordBase::State state, const CollectionBase& collect return number; } -CSMWorld::Data::Data(ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, +CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& dataPaths, const std::vector& archives, const std::filesystem::path& resDir) : mEncoder(encoding) , mPathgrids(mCells) @@ -140,12 +140,11 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, bool fsStrict, const Files::Path , mReader(nullptr) , mDialogue(nullptr) , mReaderIndex(1) - , mFsStrict(fsStrict) , mDataPaths(dataPaths) , mArchives(archives) { - mVFS = std::make_unique(mFsStrict); - VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); + mVFS = std::make_unique(); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true); mResourcesManager.setVFS(mVFS.get()); mResourceSystem = std::make_unique(mVFS.get()); @@ -1444,7 +1443,7 @@ std::vector CSMWorld::Data::getIds(bool listDeleted) const void CSMWorld::Data::assetsChanged() { mVFS.get()->reset(); - VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); + VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true); const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics, UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos }; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 16d7a28f53..1b63986eac 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -127,7 +127,6 @@ namespace CSMWorld std::map> mRefLoadCache; int mReaderIndex; - bool mFsStrict; Files::PathContainer mDataPaths; std::vector mArchives; std::unique_ptr mVFS; @@ -153,8 +152,8 @@ namespace CSMWorld void loadFallbackEntries(); public: - Data(ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, - const std::vector& archives, const std::filesystem::path& resDir); + Data(ToUTF8::FromType encoding, const Files::PathContainer& dataPaths, const std::vector& archives, + const std::filesystem::path& resDir); ~Data() override; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index b366666231..f4a737fa89 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -359,7 +359,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mActivationDistanceOverride(-1) , mGrab(true) , mRandomSeed(0) - , mFSStrict(false) , mScriptBlacklistUse(true) , mNewGame(false) , mCfgMgr(configurationManager) @@ -418,18 +417,13 @@ OMW::Engine::~Engine() SDL_Quit(); } -void OMW::Engine::enableFSStrict(bool fsStrict) -{ - mFSStrict = fsStrict; -} - // Set data dir void OMW::Engine::setDataDirs(const Files::PathContainer& dataDirs) { mDataDirs = dataDirs; mDataDirs.insert(mDataDirs.begin(), mResDir / "vfs"); - mFileCollections = Files::Collections(mDataDirs, !mFSStrict); + mFileCollections = Files::Collections(mDataDirs); } // Add BSA archive @@ -658,7 +652,7 @@ void OMW::Engine::prepareEngine() createWindow(); - mVFS = std::make_unique(mFSStrict); + mVFS = std::make_unique(); VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e9713560f6..2cd224785b 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -177,7 +177,6 @@ namespace OMW std::unique_ptr mScriptContext; Files::Collections mFileCollections; - bool mFSStrict; Translation::Storage mTranslationDataStorage; std::vector mScriptBlacklist; bool mScriptBlacklistUse; @@ -201,12 +200,6 @@ namespace OMW Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); - /// Enable strict filesystem mode (do not fold case) - /// - /// \attention The strict mode must be specified before any path-related settings - /// are given to the engine. - void enableFSStrict(bool fsStrict); - /// Set data dirs void setDataDirs(const Files::PathContainer& dataDirs); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 6f327a5dd4..e326e0aa2b 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -91,9 +91,6 @@ bool parseOptions(int argc, char** argv, OMW::Engine& engine, Files::Configurati Log(Debug::Info) << ToUTF8::encodingUsingMessage(encoding); engine.setEncoding(ToUTF8::calculateEncoding(encoding)); - // directory settings - engine.enableFSStrict(variables["fs-strict"].as()); - Files::PathContainer dataDirs(asPathContainer(variables["data"].as())); Files::PathContainer::value_type local(variables["data-local"] diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index bb84dc7989..f032ef9ec1 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -48,7 +48,6 @@ namespace MWLua LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir) : mLua(vfs, &mConfiguration, createLuaStateSettings()) - , mUiResourceManager(vfs) { Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion(); mLua.addInternalLibSearchPath(libsDir); diff --git a/apps/openmw/mwsound/sound_buffer.cpp b/apps/openmw/mwsound/sound_buffer.cpp index ce95e26bca..29f1625439 100644 --- a/apps/openmw/mwsound/sound_buffer.cpp +++ b/apps/openmw/mwsound/sound_buffer.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -35,9 +35,8 @@ namespace MWSound } } - SoundBufferPool::SoundBufferPool(const VFS::Manager& vfs, Sound_Output& output) - : mVfs(&vfs) - , mOutput(&output) + SoundBufferPool::SoundBufferPool(Sound_Output& output) + : mOutput(&output) , mBufferCacheMax(std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1) * 1024 * 1024) , mBufferCacheMin( std::min(static_cast(std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1)) @@ -135,7 +134,7 @@ namespace MWSound max = std::max(min, max); Sound_Buffer& sfx = mSoundBuffers.emplace_back("Sound/" + sound.mSound, volume, min, max); - sfx.mResourceName = mVfs->normalizeFilename(sfx.mResourceName); + VFS::Path::normalizeFilenameInPlace(sfx.mResourceName); mBufferNameMap.emplace(soundId, &sfx); return &sfx; diff --git a/apps/openmw/mwsound/sound_buffer.hpp b/apps/openmw/mwsound/sound_buffer.hpp index ca201954a4..a56bcc04ff 100644 --- a/apps/openmw/mwsound/sound_buffer.hpp +++ b/apps/openmw/mwsound/sound_buffer.hpp @@ -59,7 +59,7 @@ namespace MWSound class SoundBufferPool { public: - SoundBufferPool(const VFS::Manager& vfs, Sound_Output& output); + SoundBufferPool(Sound_Output& output); SoundBufferPool(const SoundBufferPool&) = delete; @@ -92,7 +92,6 @@ namespace MWSound void clear(); private: - const VFS::Manager* const mVfs; Sound_Output* mOutput; std::deque mSoundBuffers; std::unordered_map mBufferNameMap; diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index bb9931db33..146d947abd 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -81,7 +81,7 @@ namespace MWSound : mVFS(vfs) , mOutput(std::make_unique(*this)) , mWaterSoundUpdater(makeWaterSoundUpdaterSettings()) - , mSoundBuffers(*vfs, *mOutput) + , mSoundBuffers(*mOutput) , mListenerUnderwater(false) , mListenerPos(0, 0, 0) , mListenerDir(1, 0, 0) @@ -357,7 +357,7 @@ namespace MWSound if (!mOutput->isInitialized()) return; - DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); + DecoderPtr decoder = loadVoice("Sound/" + filename); if (!decoder) return; @@ -389,7 +389,7 @@ namespace MWSound if (!mOutput->isInitialized()) return; - DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); + DecoderPtr decoder = loadVoice("Sound/" + filename); if (!decoder) return; diff --git a/apps/openmw/options.cpp b/apps/openmw/options.cpp index 3c0790f0a7..1554e252d0 100644 --- a/apps/openmw/options.cpp +++ b/apps/openmw/options.cpp @@ -85,9 +85,6 @@ namespace OpenMW addOption("new-game", bpo::value()->implicit_value(true)->default_value(false), "run new game sequence (ignored if skip-menu=0)"); - addOption("fs-strict", bpo::value()->implicit_value(true)->default_value(false), - "strict file system handling (no case folding)"); - addOption("encoding", bpo::value()->default_value("win1252"), "Character encoding used in OpenMW game messages:\n" "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, " diff --git a/apps/openmw_test_suite/esm3/readerscache.cpp b/apps/openmw_test_suite/esm3/readerscache.cpp index ccb5c971ac..f222a29bf8 100644 --- a/apps/openmw_test_suite/esm3/readerscache.cpp +++ b/apps/openmw_test_suite/esm3/readerscache.cpp @@ -40,7 +40,7 @@ namespace static constexpr std::size_t sInitialOffset = 324; static constexpr std::size_t sSkip = 100; const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } }; - const Files::Collections mFileCollections{ mDataDirs, true }; + const Files::Collections mFileCollections{ mDataDirs }; const std::string mContentFile = "template.omwgame"; const std::filesystem::path mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile); }; diff --git a/apps/openmw_test_suite/esmloader/load.cpp b/apps/openmw_test_suite/esmloader/load.cpp index 8df24827be..20e06507d1 100644 --- a/apps/openmw_test_suite/esmloader/load.cpp +++ b/apps/openmw_test_suite/esmloader/load.cpp @@ -26,7 +26,7 @@ namespace struct EsmLoaderTest : Test { const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } }; - const Files::Collections mFileCollections{ mDataDirs, true }; + const Files::Collections mFileCollections{ mDataDirs }; const std::vector mContentFiles{ { "template.omwgame" } }; }; diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index ba54e4a5e0..3ebf9e7960 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -114,7 +114,7 @@ protected: if (!dataLocal.empty()) dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end()); - Files::Collections collections(dataDirs, true); + Files::Collections collections(dataDirs); std::vector contentFiles = variables["content"].as>(); for (auto& contentFile : contentFiles) diff --git a/apps/openmw_test_suite/nifosg/testnifloader.cpp b/apps/openmw_test_suite/nifosg/testnifloader.cpp index 24b2de30ae..5c9caf4799 100644 --- a/apps/openmw_test_suite/nifosg/testnifloader.cpp +++ b/apps/openmw_test_suite/nifosg/testnifloader.cpp @@ -27,7 +27,7 @@ namespace struct BaseNifOsgLoaderTest { - VFS::Manager mVfs{ false }; + VFS::Manager mVfs; Resource::ImageManager mImageManager{ &mVfs }; const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt"); osg::ref_ptr mOptions = new osgDB::Options; diff --git a/apps/openmw_test_suite/testing_util.hpp b/apps/openmw_test_suite/testing_util.hpp index 2f76a9df1d..6a965adc18 100644 --- a/apps/openmw_test_suite/testing_util.hpp +++ b/apps/openmw_test_suite/testing_util.hpp @@ -56,22 +56,16 @@ namespace TestingOpenMW { } - void listResources(std::map& out, char (*normalize_function)(char)) override - { - out = mFiles; - } + void listResources(std::map& out) override { out = mFiles; } - bool contains(const std::string& file, char (*normalize_function)(char)) const override - { - return mFiles.count(file) != 0; - } + bool contains(const std::string& file) const override { return mFiles.count(file) != 0; } std::string getDescription() const override { return "TestData"; } }; inline std::unique_ptr createTestVFS(std::map files) { - auto vfs = std::make_unique(true); + auto vfs = std::make_unique(); vfs->addArchive(std::make_unique(std::move(files))); vfs->buildIndex(); return vfs; diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 47734bb084..a1b444a746 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -8,14 +8,12 @@ namespace Files { Collections::Collections() : mDirectories() - , mFoldCase(false) , mCollections() { } - Collections::Collections(const Files::PathContainer& directories, bool foldCase) + Collections::Collections(const Files::PathContainer& directories) : mDirectories(directories) - , mFoldCase(foldCase) , mCollections() { } @@ -27,7 +25,7 @@ namespace Files if (iter == mCollections.end()) { std::pair result - = mCollections.emplace(ext, MultiDirCollection(mDirectories, ext, mFoldCase)); + = mCollections.emplace(ext, MultiDirCollection(mDirectories, ext)); iter = result.first; } @@ -44,12 +42,7 @@ namespace Files const auto& path = iter2.path(); const auto str = Files::pathToUnicodeString(path.filename()); - if (mFoldCase) - { - if (Misc::StringUtils::ciEqual(file, str)) - return path; - } - else if (str == file) + if (Misc::StringUtils::ciEqual(file, str)) return path; } } @@ -66,12 +59,7 @@ namespace Files const auto& path = iter2.path(); const auto str = Files::pathToUnicodeString(path.filename()); - if (mFoldCase) - { - if (Misc::StringUtils::ciEqual(file, str)) - return true; - } - else if (str == file) + if (Misc::StringUtils::ciEqual(file, str)) return true; } } diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 8aac182966..88e047aa45 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -13,7 +13,7 @@ namespace Files Collections(); ///< Directories are listed with increasing priority. - Collections(const Files::PathContainer& directories, bool foldCase); + Collections(const Files::PathContainer& directories); ///< Return a file collection for the given extension. Extension must contain the /// leading dot and must be all lower-case. @@ -35,7 +35,6 @@ namespace Files typedef std::map MultiDirCollectionContainer; Files::PathContainer mDirectories; - bool mFoldCase; mutable MultiDirCollectionContainer mCollections; }; } diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 8c9461da74..16c9251f24 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -7,29 +7,9 @@ namespace Files { - struct NameEqual - { - bool mStrict; - - NameEqual(bool strict) - : mStrict(strict) - { - } - bool operator()(const std::string& left, const std::string& right) const - { - if (mStrict) - return left == right; - return Misc::StringUtils::ciEqual(left, right); - } - }; - - MultiDirCollection::MultiDirCollection( - const Files::PathContainer& directories, const std::string& extension, bool foldCase) - : mFiles(NameLess(!foldCase)) + MultiDirCollection::MultiDirCollection(const Files::PathContainer& directories, const std::string& extension) { - NameEqual equal(!foldCase); - for (const auto& directory : directories) { if (!std::filesystem::is_directory(directory)) @@ -42,7 +22,7 @@ namespace Files { const auto& path = dirIter.path(); - if (!equal(extension, Files::pathToUnicodeString(path.extension()))) + if (!Misc::StringUtils::ciEqual(extension, Files::pathToUnicodeString(path.extension()))) continue; const auto filename = Files::pathToUnicodeString(path.filename()); diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index 5d5b5c5570..f6549f9ddb 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -13,23 +13,6 @@ namespace Files { typedef std::vector PathContainer; - struct NameLess - { - bool mStrict; - - NameLess(bool strict) - : mStrict(strict) - { - } - - bool operator()(const std::string& left, const std::string& right) const - { - if (mStrict) - return left < right; - return Misc::StringUtils::ciLess(left, right); - } - }; - /// \brief File collection across several directories /// /// This class lists all files with one specific extensions within one or more @@ -38,14 +21,14 @@ namespace Files class MultiDirCollection { public: - typedef std::map TContainer; + typedef std::map TContainer; typedef TContainer::const_iterator TIter; private: TContainer mFiles; public: - MultiDirCollection(const Files::PathContainer& directories, const std::string& extension, bool foldCase); + MultiDirCollection(const Files::PathContainer& directories, const std::string& extension); ///< Directories are listed with increasing priority. /// \param extension The extension that should be listed in this collection. Must /// contain the leading dot. diff --git a/components/lua_ui/resources.cpp b/components/lua_ui/resources.cpp index 19738f43ff..6c98292765 100644 --- a/components/lua_ui/resources.cpp +++ b/components/lua_ui/resources.cpp @@ -1,12 +1,12 @@ #include "resources.hpp" -#include +#include namespace LuaUi { std::shared_ptr ResourceManager::registerTexture(TextureData data) { - data.mPath = mVfs->normalizeFilename(data.mPath); + VFS::Path::normalizeFilenameInPlace(data.mPath); TextureResources& list = mTextures[data.mPath]; list.push_back(std::make_shared(data)); diff --git a/components/lua_ui/resources.hpp b/components/lua_ui/resources.hpp index 7c3cec24ae..f2e1753a2c 100644 --- a/components/lua_ui/resources.hpp +++ b/components/lua_ui/resources.hpp @@ -28,16 +28,10 @@ namespace LuaUi class ResourceManager { public: - ResourceManager(const VFS::Manager* vfs) - : mVfs(vfs) - { - } - std::shared_ptr registerTexture(TextureData data); void clear(); private: - const VFS::Manager* mVfs; using TextureResources = std::vector>; std::unordered_map mTextures; }; diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 9e25c9a0af..dbe3b76544 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace { @@ -157,9 +158,10 @@ std::string Misc::ResourceHelpers::correctSoundPath(std::string_view resPath, co { std::string sound{ resPath }; changeExtension(sound, ".mp3"); - return vfs->normalizeFilename(sound); + VFS::Path::normalizeFilenameInPlace(sound); + return sound; } - return vfs->normalizeFilename(resPath); + return VFS::Path::normalizeFilename(resPath); } bool Misc::ResourceHelpers::isHiddenMarker(const ESM::RefId& id) @@ -173,7 +175,7 @@ namespace { if (auto w = Misc::findExtension(resPath); w != std::string::npos) resPath.insert(w, pattern); - return vfs->normalizeFilename(resPath); + return VFS::Path::normalizeFilename(resPath); } std::string getBestLODMeshName(std::string const& resPath, const VFS::Manager* vfs, std::string_view pattern) diff --git a/components/resource/bulletshapemanager.cpp b/components/resource/bulletshapemanager.cpp index c2d38e164d..0e2089cb06 100644 --- a/components/resource/bulletshapemanager.cpp +++ b/components/resource/bulletshapemanager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -109,7 +110,7 @@ namespace Resource osg::ref_ptr BulletShapeManager::getShape(const std::string& name) { - const std::string normalized = mVFS->normalizeFilename(name); + const std::string normalized = VFS::Path::normalizeFilename(name); osg::ref_ptr shape; osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); @@ -169,7 +170,7 @@ namespace Resource osg::ref_ptr BulletShapeManager::cacheInstance(const std::string& name) { - const std::string normalized = mVFS->normalizeFilename(name); + const std::string normalized = VFS::Path::normalizeFilename(name); osg::ref_ptr instance = createInstance(normalized); if (instance) @@ -179,7 +180,7 @@ namespace Resource osg::ref_ptr BulletShapeManager::getInstance(const std::string& name) { - const std::string normalized = mVFS->normalizeFilename(name); + const std::string normalized = VFS::Path::normalizeFilename(name); osg::ref_ptr obj = mInstanceCache->takeFromObjectCache(normalized); if (obj.get()) diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index 417b8079be..178e681d4e 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "objectcache.hpp" @@ -85,7 +86,7 @@ namespace Resource osg::ref_ptr ImageManager::getImage(std::string_view filename, bool disableFlip) { - const std::string normalized = mVFS->normalizeFilename(filename); + const std::string normalized = VFS::Path::normalizeFilename(filename); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 6e9e6c1ed4..a8d345be53 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "animation.hpp" #include "objectcache.hpp" @@ -210,11 +211,9 @@ namespace Resource { } - KeyframeManager::~KeyframeManager() {} - osg::ref_ptr KeyframeManager::get(const std::string& name) { - const std::string normalized = mVFS->normalizeFilename(name); + const std::string normalized = VFS::Path::normalizeFilename(name); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 138838c0f7..d075e65d4c 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -49,7 +49,7 @@ namespace Resource { public: KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager); - ~KeyframeManager(); + ~KeyframeManager() = default; /// Retrieve a read-only keyframe resource by name (case-insensitive). /// @note Throws an exception if the resource is not found. diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index d53c4230f0..fc5ecc7f03 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -22,7 +22,7 @@ namespace Resource class BaseResourceManager { public: - virtual ~BaseResourceManager() {} + virtual ~BaseResourceManager() = default; virtual void updateCache(double referenceTime) {} virtual void clearCache() {} virtual void setExpiryDelay(double expiryDelay) {} @@ -46,7 +46,7 @@ namespace Resource { } - virtual ~GenericResourceManager() {} + virtual ~GenericResourceManager() = default; /// Clear cache entries that have not been referenced for longer than expiryDelay. void updateCache(double referenceTime) override diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 7e8449407b..78b2d5165a 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -507,7 +508,7 @@ namespace Resource bool SceneManager::checkLoaded(const std::string& name, double timeStamp) { - return mCache->checkInObjectCache(mVFS->normalizeFilename(name), timeStamp); + return mCache->checkInObjectCache(VFS::Path::normalizeFilename(name), timeStamp); } /// @brief Callback to read image files from the VFS. @@ -862,7 +863,7 @@ namespace Resource osg::ref_ptr SceneManager::getTemplate(const std::string& name, bool compile) { - std::string normalized = mVFS->normalizeFilename(name); + std::string normalized = VFS::Path::normalizeFilename(name); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) diff --git a/components/vfs/archive.hpp b/components/vfs/archive.hpp index 604a77e002..e377e8c5b6 100644 --- a/components/vfs/archive.hpp +++ b/components/vfs/archive.hpp @@ -12,7 +12,7 @@ namespace VFS class File { public: - virtual ~File() {} + virtual ~File() = default; virtual Files::IStreamPtr open() = 0; @@ -22,14 +22,13 @@ namespace VFS class Archive { public: - virtual ~Archive() {} + virtual ~Archive() = default; - /// List all resources contained in this archive, and run the resource names through the given normalize - /// function. - virtual void listResources(std::map& out, char (*normalize_function)(char)) = 0; + /// List all resources contained in this archive. + virtual void listResources(std::map& out) = 0; /// True if this archive contains the provided normalized file. - virtual bool contains(const std::string& file, char (*normalize_function)(char)) const = 0; + virtual bool contains(const std::string& file) const = 0; virtual std::string getDescription() const = 0; }; diff --git a/components/vfs/bsaarchive.hpp b/components/vfs/bsaarchive.hpp index 019715518e..517c95e273 100644 --- a/components/vfs/bsaarchive.hpp +++ b/components/vfs/bsaarchive.hpp @@ -2,6 +2,7 @@ #define VFS_BSAARCHIVE_HPP_ #include "archive.hpp" +#include "pathutil.hpp" #include #include @@ -47,24 +48,22 @@ namespace VFS virtual ~BsaArchive() {} - void listResources(std::map& out, char (*normalize_function)(char)) override + void listResources(std::map& out) override { for (auto& resource : mResources) { std::string ent = resource.mInfo->name(); - std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function); + Path::normalizeFilenameInPlace(ent); out[ent] = &resource; } } - bool contains(const std::string& file, char (*normalize_function)(char)) const override + bool contains(const std::string& file) const override { for (const auto& it : mResources) { - std::string ent = it.mInfo->name(); - std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function); - if (file == ent) + if (Path::pathEqual(file, it.mInfo->name())) return true; } return false; diff --git a/components/vfs/filesystemarchive.cpp b/components/vfs/filesystemarchive.cpp index ca74768732..96f5e87f5e 100644 --- a/components/vfs/filesystemarchive.cpp +++ b/components/vfs/filesystemarchive.cpp @@ -1,9 +1,9 @@ #include "filesystemarchive.hpp" -#include - #include +#include "pathutil.hpp" + #include #include #include @@ -17,7 +17,7 @@ namespace VFS { } - void FileSystemArchive::listResources(std::map& out, char (*normalize_function)(char)) + void FileSystemArchive::listResources(std::map& out) { if (!mBuiltIndex) { @@ -33,16 +33,13 @@ namespace VFS continue; const auto& path = i.path(); - const auto& proper = Files::pathToUnicodeString(path); + const std::string proper = Files::pathToUnicodeString(path); FileSystemArchiveFile file(path); - std::string searchable; - - std::transform(std::next(proper.begin(), static_cast(prefix)), - proper.end(), std::back_inserter(searchable), normalize_function); + std::string searchable = Path::normalizeFilename(std::string_view{ proper }.substr(prefix)); - const auto inserted = mIndex.insert(std::make_pair(searchable, file)); + const auto inserted = mIndex.emplace(searchable, file); if (!inserted.second) Log(Debug::Warning) << "Warning: found duplicate file for '" << proper @@ -61,7 +58,7 @@ namespace VFS } } - bool FileSystemArchive::contains(const std::string& file, char (*normalize_function)(char)) const + bool FileSystemArchive::contains(const std::string& file) const { return mIndex.find(file) != mIndex.end(); } diff --git a/components/vfs/filesystemarchive.hpp b/components/vfs/filesystemarchive.hpp index e1ebbd96f0..39d711b327 100644 --- a/components/vfs/filesystemarchive.hpp +++ b/components/vfs/filesystemarchive.hpp @@ -27,9 +27,9 @@ namespace VFS public: FileSystemArchive(const std::filesystem::path& path); - void listResources(std::map& out, char (*normalize_function)(char)) override; + void listResources(std::map& out) override; - bool contains(const std::string& file, char (*normalize_function)(char)) const override; + bool contains(const std::string& file) const override; std::string getDescription() const override; diff --git a/components/vfs/manager.cpp b/components/vfs/manager.cpp index c94a7593c0..bfc001e4f2 100644 --- a/components/vfs/manager.cpp +++ b/components/vfs/manager.cpp @@ -7,38 +7,10 @@ #include #include "archive.hpp" - -namespace -{ - - char strict_normalize_char(char ch) - { - return ch == '\\' ? '/' : ch; - } - - char nonstrict_normalize_char(char ch) - { - return ch == '\\' ? '/' : Misc::StringUtils::toLower(ch); - } - - void normalize_path(std::string& path, bool strict) - { - char (*normalize_char)(char) = strict ? &strict_normalize_char : &nonstrict_normalize_char; - std::transform(path.begin(), path.end(), path.begin(), normalize_char); - } - -} +#include "pathutil.hpp" namespace VFS { - - Manager::Manager(bool strict) - : mStrict(strict) - { - } - - Manager::~Manager() {} - void Manager::reset() { mIndex.clear(); @@ -55,15 +27,12 @@ namespace VFS mIndex.clear(); for (const auto& archive : mArchives) - archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); + archive->listResources(mIndex); } Files::IStreamPtr Manager::get(std::string_view name) const { - std::string normalized(name); - normalize_path(normalized, mStrict); - - return getNormalized(normalized); + return getNormalized(Path::normalizeFilename(name)); } Files::IStreamPtr Manager::getNormalized(const std::string& normalizedName) const @@ -76,26 +45,15 @@ namespace VFS bool Manager::exists(std::string_view name) const { - std::string normalized(name); - normalize_path(normalized, mStrict); - - return mIndex.find(normalized) != mIndex.end(); - } - - std::string Manager::normalizeFilename(std::string_view name) const - { - std::string result(name); - normalize_path(result, mStrict); - return result; + return mIndex.find(Path::normalizeFilename(name)) != mIndex.end(); } std::string Manager::getArchive(std::string_view name) const { - std::string normalized(name); - normalize_path(normalized, mStrict); + std::string normalized = Path::normalizeFilename(name); for (auto it = mArchives.rbegin(); it != mArchives.rend(); ++it) { - if ((*it)->contains(normalized, mStrict ? &strict_normalize_char : &nonstrict_normalize_char)) + if ((*it)->contains(normalized)) return (*it)->getDescription(); } return {}; @@ -104,7 +62,7 @@ namespace VFS std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const { std::string normalized = Files::pathToUnicodeString(name); - normalize_path(normalized, mStrict); + Path::normalizeFilenameInPlace(normalized); const auto found = mIndex.find(normalized); if (found == mIndex.end()) @@ -124,7 +82,7 @@ namespace VFS { if (path.empty()) return { mIndex.begin(), mIndex.end() }; - auto normalized = normalizeFilename(path); + std::string normalized = Path::normalizeFilename(path); const auto it = mIndex.lower_bound(normalized); if (it == mIndex.end() || !startsWith(it->first, normalized)) return { it, it }; diff --git a/components/vfs/manager.hpp b/components/vfs/manager.hpp index d9e0d0e9c5..db38e4b240 100644 --- a/components/vfs/manager.hpp +++ b/components/vfs/manager.hpp @@ -9,12 +9,11 @@ #include #include +#include "archive.hpp" + namespace VFS { - class Archive; - class File; - template class IteratorPair { @@ -62,12 +61,6 @@ namespace VFS using RecursiveDirectoryRange = IteratorPair; public: - /// @param strict Use strict path handling? If enabled, no case folding will - /// be done, but slash/backslash conversions are always done. - Manager(bool strict); - - ~Manager(); - // Empty the file index and unregister archives. void reset(); @@ -82,10 +75,6 @@ namespace VFS /// @note May be called from any thread once the index has been built. bool exists(std::string_view name) const; - /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing if mStrict is false. - /// @note May be called from any thread once the index has been built. - [[nodiscard]] std::string normalizeFilename(std::string_view 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. @@ -110,8 +99,6 @@ namespace VFS std::filesystem::path getAbsoluteFileName(const std::filesystem::path& name) const; private: - bool mStrict; - std::vector> mArchives; std::map mIndex; diff --git a/components/vfs/pathutil.hpp b/components/vfs/pathutil.hpp new file mode 100644 index 0000000000..b400dc3bd0 --- /dev/null +++ b/components/vfs/pathutil.hpp @@ -0,0 +1,50 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_PATH_H +#define OPENMW_COMPONENTS_RESOURCE_PATH_H + +#include + +#include +#include +#include + +namespace VFS::Path +{ + inline constexpr char normalize(char c) + { + return c == '\\' ? '/' : Misc::StringUtils::toLower(c); + } + + inline void normalizeFilenameInPlace(std::string& name) + { + for (char& ch : name) + ch = normalize(ch); + } + + /// Normalize the given filename, making slashes/backslashes consistent, and lower-casing. + [[nodiscard]] inline std::string normalizeFilename(std::string_view name) + { + std::string out(name); + normalizeFilenameInPlace(out); + return out; + } + + struct PathCharLess + { + bool operator()(char x, char y) const { return normalize(x) < normalize(y); } + }; + + inline bool pathLess(std::string_view x, std::string_view y) + { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end(), PathCharLess()); + } + + inline bool pathEqual(std::string_view x, std::string_view y) + { + if (std::size(x) != std::size(y)) + return false; + return std::equal( + std::begin(x), std::end(x), std::begin(y), [](char l, char r) { return normalize(l) == normalize(r); }); + } +} + +#endif