Drop support for --fs-strict

revert-6246b479
Evil Eye 2 years ago
parent 75c371de66
commit eeda48ec50

@ -75,6 +75,7 @@
Task #7113: Move from std::atoi to std::from_char Task #7113: Move from std::atoi to std::from_char
Task #7117: Replace boost::scoped_array with std::vector Task #7117: Replace boost::scoped_array with std::vector
Task #7151: Do not use std::strerror to get errno error message Task #7151: Do not use std::strerror to get errno error message
Task #7394: Drop support for --fs-strict
0.48.0 0.48.0
------ ------

@ -85,8 +85,6 @@ Command line options
--skip-menu [=arg(=1)] (=0) skip main menu on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup
--new-game [=arg(=1)] (=0) run new game sequence (ignored if --new-game [=arg(=1)] (=0) run new game sequence (ignored if
skip-menu=0) skip-menu=0)
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
folding)
--encoding arg (=win1252) Character encoding used in OpenMW game --encoding arg (=win1252) Character encoding used in OpenMW game
messages: messages:

@ -83,9 +83,6 @@ namespace
addOption("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(), addOption("content", bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(),
"content file(s): esm/esp, or omwgame/omwaddon/omwscripts"); "content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)->default_value(false),
"strict file system handling (no case folding)");
addOption("encoding", bpo::value<std::string>()->default_value("win1252"), addOption("encoding", bpo::value<std::string>()->default_value("win1252"),
"Character encoding used in OpenMW game messages:\n" "Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, " "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, "
@ -148,18 +145,17 @@ namespace
config.filterOutNonExistingPaths(dataDirs); config.filterOutNonExistingPaths(dataDirs);
const auto fsStrict = variables["fs-strict"].as<bool>();
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>(); const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
const auto v = Version::getOpenmwVersion(resDir); const auto v = Version::getOpenmwVersion(resDir);
Log(Debug::Info) << v.describe(); Log(Debug::Info) << v.describe();
dataDirs.insert(dataDirs.begin(), resDir / "vfs"); 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<StringsVector>(); const auto archives = variables["fallback-archive"].as<StringsVector>();
const auto contentFiles = variables["content"].as<StringsVector>(); const auto contentFiles = variables["content"].as<StringsVector>();
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap); Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
VFS::Manager vfs(fsStrict); VFS::Manager vfs;
VFS::registerArchives(&vfs, fileCollections, archives, true); VFS::registerArchives(&vfs, fileCollections, archives, true);

@ -96,9 +96,6 @@ namespace NavMeshTool
bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(), bpo::value<StringsVector>()->default_value(StringsVector(), "")->multitoken()->composing(),
"content file(s): esm/esp, or omwgame/omwaddon/omwscripts"); "content file(s): esm/esp, or omwgame/omwaddon/omwscripts");
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)->default_value(false),
"strict file system handling (no case folding)");
addOption("encoding", bpo::value<std::string>()->default_value("win1252"), addOption("encoding", bpo::value<std::string>()->default_value("win1252"),
"Character encoding used in OpenMW game messages:\n" "Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, " "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, "
@ -167,12 +164,11 @@ namespace NavMeshTool
config.filterOutNonExistingPaths(dataDirs); config.filterOutNonExistingPaths(dataDirs);
const auto fsStrict = variables["fs-strict"].as<bool>();
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>(); const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
Version::Version v = Version::getOpenmwVersion(resDir); Version::Version v = Version::getOpenmwVersion(resDir);
Log(Debug::Info) << v.describe(); Log(Debug::Info) << v.describe();
dataDirs.insert(dataDirs.begin(), resDir / "vfs"); 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<StringsVector>(); const auto archives = variables["fallback-archive"].as<StringsVector>();
const auto contentFiles = variables["content"].as<StringsVector>(); const auto contentFiles = variables["content"].as<StringsVector>();
const std::size_t threadsNumber = variables["threads"].as<std::size_t>(); const std::size_t threadsNumber = variables["threads"].as<std::size_t>();
@ -194,7 +190,7 @@ namespace NavMeshTool
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap); Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
VFS::Manager vfs(fsStrict); VFS::Manager vfs;
VFS::registerArchives(&vfs, fileCollections, archives, true); VFS::registerArchives(&vfs, fileCollections, archives, true);

@ -79,7 +79,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& anArchive, const std::filesystem::p
if (anArchive == nullptr) if (anArchive == nullptr)
return; return;
VFS::Manager myManager(true); VFS::Manager myManager;
myManager.addArchive(std::move(anArchive)); myManager.addArchive(std::move(anArchive));
myManager.buildIndex(); myManager.buildIndex();
@ -176,7 +176,7 @@ int main(int argc, char** argv)
std::unique_ptr<VFS::Manager> vfs; std::unique_ptr<VFS::Manager> vfs;
if (!archives.empty()) if (!archives.empty())
{ {
vfs = std::make_unique<VFS::Manager>(true); vfs = std::make_unique<VFS::Manager>();
for (const std::filesystem::path& path : archives) for (const std::filesystem::path& path : archives)
if (auto archive = makeArchive(path)) if (auto archive = makeArchive(path))
vfs->addArchive(std::move(archive)); vfs->addArchive(std::move(archive));

@ -62,7 +62,7 @@ CS::Editor::Editor(int argc, char** argv)
NifOsg::Loader::setShowMarkers(true); NifOsg::Loader::setShowMarkers(true);
mDocumentManager.setFileData(mFsStrict, config.first, config.second); mDocumentManager.setFileData(config.first, config.second);
mNewGame.setLocalData(mLocal); mNewGame.setLocalData(mLocal);
mFileDialog.setLocalData(mLocal); mFileDialog.setLocalData(mLocal);
@ -118,7 +118,6 @@ boost::program_options::variables_map CS::Editor::readConfiguration()
addOption("data-local", addOption("data-local",
boost::program_options::value<Files::MaybeQuotedPathContainer::value_type>()->default_value( boost::program_options::value<Files::MaybeQuotedPathContainer::value_type>()->default_value(
Files::MaybeQuotedPathContainer::value_type(), "")); Files::MaybeQuotedPathContainer::value_type(), ""));
addOption("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false));
addOption("encoding", boost::program_options::value<std::string>()->default_value("win1252")); addOption("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
addOption("resources", addOption("resources",
boost::program_options::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources")); boost::program_options::value<Files::MaybeQuotedPath>()->default_value(Files::MaybeQuotedPath(), "resources"));
@ -165,8 +164,6 @@ std::pair<Files::PathContainer, std::vector<std::string>> CS::Editor::readConfig
if (variables["script-blacklist-use"].as<bool>()) if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts(variables["script-blacklist"].as<std::vector<std::string>>()); mDocumentManager.setBlacklistedScripts(variables["script-blacklist"].as<std::vector<std::string>>());
mFsStrict = variables["fs-strict"].as<bool>();
Files::PathContainer dataDirs, dataLocal; Files::PathContainer dataDirs, dataLocal;
if (!variables["data"].empty()) if (!variables["data"].empty())
{ {

@ -60,7 +60,6 @@ namespace CS
std::filesystem::path mPid; std::filesystem::path mPid;
QLockFile mLockFile; QLockFile mLockFile;
std::ofstream mPidFile; std::ofstream mPidFile;
bool mFsStrict;
CSVTools::Merge mMerge; CSVTools::Merge mMerge;
CSVDoc::ViewManager* mViewManager; CSVDoc::ViewManager* mViewManager;
std::filesystem::path mFileToLoad; std::filesystem::path mFileToLoad;

@ -296,12 +296,12 @@ void CSMDoc::Document::createBase()
CSMDoc::Document::Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files, CSMDoc::Document::Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files,
bool new_, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, bool new_, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding,
const std::vector<std::string>& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& blacklistedScripts, const Files::PathContainer& dataPaths,
const std::vector<std::string>& archives) const std::vector<std::string>& archives)
: mSavePath(savePath) : mSavePath(savePath)
, mContentFiles(std::move(files)) , mContentFiles(std::move(files))
, mNew(new_) , mNew(new_)
, mData(encoding, fsStrict, dataPaths, archives, resDir) , mData(encoding, dataPaths, archives, resDir)
, mTools(*this, encoding) , mTools(*this, encoding)
, mProjectPath((configuration.getUserDataPath() / "projects") / (savePath.filename().u8string() + u8".project")) , mProjectPath((configuration.getUserDataPath() / "projects") / (savePath.filename().u8string() + u8".project"))
, mSavingOperation(*this, mProjectPath, encoding) , mSavingOperation(*this, mProjectPath, encoding)

@ -95,7 +95,7 @@ namespace CSMDoc
public: public:
Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files, bool new_, Document(const Files::ConfigurationManager& configuration, std::vector<std::filesystem::path> files, bool new_,
const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding, const std::filesystem::path& savePath, const std::filesystem::path& resDir, ToUTF8::FromType encoding,
const std::vector<std::string>& blacklistedScripts, bool fsStrict, const Files::PathContainer& dataPaths, const std::vector<std::string>& blacklistedScripts, const Files::PathContainer& dataPaths,
const std::vector<std::string>& archives); const std::vector<std::string>& archives);
~Document() override = default; ~Document() override = default;

@ -17,7 +17,6 @@
CSMDoc::DocumentManager::DocumentManager(const Files::ConfigurationManager& configuration) CSMDoc::DocumentManager::DocumentManager(const Files::ConfigurationManager& configuration)
: mConfiguration(configuration) : mConfiguration(configuration)
, mEncoding(ToUTF8::WINDOWS_1252) , mEncoding(ToUTF8::WINDOWS_1252)
, mFsStrict(false)
{ {
std::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; std::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
@ -62,8 +61,8 @@ void CSMDoc::DocumentManager::addDocument(
CSMDoc::Document* CSMDoc::DocumentManager::makeDocument( CSMDoc::Document* CSMDoc::DocumentManager::makeDocument(
const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_) const std::vector<std::filesystem::path>& files, const std::filesystem::path& savePath, bool new_)
{ {
return new Document(mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mFsStrict, return new Document(
mDataPaths, mArchives); mConfiguration, files, new_, savePath, mResDir, mEncoding, mBlacklistedScripts, mDataPaths, mArchives);
} }
void CSMDoc::DocumentManager::insertDocument(CSMDoc::Document* document) void CSMDoc::DocumentManager::insertDocument(CSMDoc::Document* document)
@ -123,9 +122,8 @@ void CSMDoc::DocumentManager::documentNotLoaded(Document* document, const std::s
} }
void CSMDoc::DocumentManager::setFileData( void CSMDoc::DocumentManager::setFileData(
bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives) const Files::PathContainer& dataPaths, const std::vector<std::string>& archives)
{ {
mFsStrict = strict;
mDataPaths = dataPaths; mDataPaths = dataPaths;
mArchives = archives; mArchives = archives;
} }

@ -35,7 +35,6 @@ namespace CSMDoc
std::filesystem::path mResDir; std::filesystem::path mResDir;
bool mFsStrict;
Files::PathContainer mDataPaths; Files::PathContainer mDataPaths;
std::vector<std::string> mArchives; std::vector<std::string> mArchives;
@ -68,7 +67,7 @@ namespace CSMDoc
void setBlacklistedScripts(const std::vector<std::string>& scriptIds); void setBlacklistedScripts(const std::vector<std::string>& scriptIds);
/// Sets the file data that gets passed to newly created documents. /// Sets the file data that gets passed to newly created documents.
void setFileData(bool strict, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives); void setFileData(const Files::PathContainer& dataPaths, const std::vector<std::string>& archives);
bool isEmpty(); bool isEmpty();

@ -132,7 +132,7 @@ int CSMWorld::Data::count(RecordBase::State state, const CollectionBase& collect
return number; 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<std::string>& archives, const std::filesystem::path& resDir) const std::vector<std::string>& archives, const std::filesystem::path& resDir)
: mEncoder(encoding) : mEncoder(encoding)
, mPathgrids(mCells) , mPathgrids(mCells)
@ -140,12 +140,11 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, bool fsStrict, const Files::Path
, mReader(nullptr) , mReader(nullptr)
, mDialogue(nullptr) , mDialogue(nullptr)
, mReaderIndex(1) , mReaderIndex(1)
, mFsStrict(fsStrict)
, mDataPaths(dataPaths) , mDataPaths(dataPaths)
, mArchives(archives) , mArchives(archives)
{ {
mVFS = std::make_unique<VFS::Manager>(mFsStrict); mVFS = std::make_unique<VFS::Manager>();
VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths, !mFsStrict), mArchives, true); VFS::registerArchives(mVFS.get(), Files::Collections(mDataPaths), mArchives, true);
mResourcesManager.setVFS(mVFS.get()); mResourcesManager.setVFS(mVFS.get());
mResourceSystem = std::make_unique<Resource::ResourceSystem>(mVFS.get()); mResourceSystem = std::make_unique<Resource::ResourceSystem>(mVFS.get());
@ -1444,7 +1443,7 @@ std::vector<ESM::RefId> CSMWorld::Data::getIds(bool listDeleted) const
void CSMWorld::Data::assetsChanged() void CSMWorld::Data::assetsChanged()
{ {
mVFS.get()->reset(); 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, const UniversalId assetTableIds[] = { UniversalId::Type_Meshes, UniversalId::Type_Icons, UniversalId::Type_Musics,
UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos }; UniversalId::Type_SoundsRes, UniversalId::Type_Textures, UniversalId::Type_Videos };

@ -127,7 +127,6 @@ namespace CSMWorld
std::map<ESM::RefId, std::map<unsigned int, unsigned int>> mRefLoadCache; std::map<ESM::RefId, std::map<unsigned int, unsigned int>> mRefLoadCache;
int mReaderIndex; int mReaderIndex;
bool mFsStrict;
Files::PathContainer mDataPaths; Files::PathContainer mDataPaths;
std::vector<std::string> mArchives; std::vector<std::string> mArchives;
std::unique_ptr<VFS::Manager> mVFS; std::unique_ptr<VFS::Manager> mVFS;
@ -153,8 +152,8 @@ namespace CSMWorld
void loadFallbackEntries(); void loadFallbackEntries();
public: public:
Data(ToUTF8::FromType encoding, bool fsStrict, const Files::PathContainer& dataPaths, Data(ToUTF8::FromType encoding, const Files::PathContainer& dataPaths, const std::vector<std::string>& archives,
const std::vector<std::string>& archives, const std::filesystem::path& resDir); const std::filesystem::path& resDir);
~Data() override; ~Data() override;

@ -359,7 +359,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mActivationDistanceOverride(-1) , mActivationDistanceOverride(-1)
, mGrab(true) , mGrab(true)
, mRandomSeed(0) , mRandomSeed(0)
, mFSStrict(false)
, mScriptBlacklistUse(true) , mScriptBlacklistUse(true)
, mNewGame(false) , mNewGame(false)
, mCfgMgr(configurationManager) , mCfgMgr(configurationManager)
@ -418,18 +417,13 @@ OMW::Engine::~Engine()
SDL_Quit(); SDL_Quit();
} }
void OMW::Engine::enableFSStrict(bool fsStrict)
{
mFSStrict = fsStrict;
}
// Set data dir // Set data dir
void OMW::Engine::setDataDirs(const Files::PathContainer& dataDirs) void OMW::Engine::setDataDirs(const Files::PathContainer& dataDirs)
{ {
mDataDirs = dataDirs; mDataDirs = dataDirs;
mDataDirs.insert(mDataDirs.begin(), mResDir / "vfs"); mDataDirs.insert(mDataDirs.begin(), mResDir / "vfs");
mFileCollections = Files::Collections(mDataDirs, !mFSStrict); mFileCollections = Files::Collections(mDataDirs);
} }
// Add BSA archive // Add BSA archive
@ -658,7 +652,7 @@ void OMW::Engine::prepareEngine()
createWindow(); createWindow();
mVFS = std::make_unique<VFS::Manager>(mFSStrict); mVFS = std::make_unique<VFS::Manager>();
VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true); VFS::registerArchives(mVFS.get(), mFileCollections, mArchives, true);

@ -177,7 +177,6 @@ namespace OMW
std::unique_ptr<Compiler::Context> mScriptContext; std::unique_ptr<Compiler::Context> mScriptContext;
Files::Collections mFileCollections; Files::Collections mFileCollections;
bool mFSStrict;
Translation::Storage mTranslationDataStorage; Translation::Storage mTranslationDataStorage;
std::vector<ESM::RefId> mScriptBlacklist; std::vector<ESM::RefId> mScriptBlacklist;
bool mScriptBlacklistUse; bool mScriptBlacklistUse;
@ -201,12 +200,6 @@ namespace OMW
Engine(Files::ConfigurationManager& configurationManager); Engine(Files::ConfigurationManager& configurationManager);
virtual ~Engine(); 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 /// Set data dirs
void setDataDirs(const Files::PathContainer& dataDirs); void setDataDirs(const Files::PathContainer& dataDirs);

@ -91,9 +91,6 @@ bool parseOptions(int argc, char** argv, OMW::Engine& engine, Files::Configurati
Log(Debug::Info) << ToUTF8::encodingUsingMessage(encoding); Log(Debug::Info) << ToUTF8::encodingUsingMessage(encoding);
engine.setEncoding(ToUTF8::calculateEncoding(encoding)); engine.setEncoding(ToUTF8::calculateEncoding(encoding));
// directory settings
engine.enableFSStrict(variables["fs-strict"].as<bool>());
Files::PathContainer dataDirs(asPathContainer(variables["data"].as<Files::MaybeQuotedPathContainer>())); Files::PathContainer dataDirs(asPathContainer(variables["data"].as<Files::MaybeQuotedPathContainer>()));
Files::PathContainer::value_type local(variables["data-local"] Files::PathContainer::value_type local(variables["data-local"]

@ -48,7 +48,6 @@ namespace MWLua
LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir) LuaManager::LuaManager(const VFS::Manager* vfs, const std::filesystem::path& libsDir)
: mLua(vfs, &mConfiguration, createLuaStateSettings()) : mLua(vfs, &mConfiguration, createLuaStateSettings())
, mUiResourceManager(vfs)
{ {
Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion(); Log(Debug::Info) << "Lua version: " << LuaUtil::getLuaVersion();
mLua.addInternalLibSearchPath(libsDir); mLua.addInternalLibSearchPath(libsDir);

@ -7,7 +7,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/esm3/loadsoun.hpp> #include <components/esm3/loadsoun.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/pathutil.hpp>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@ -35,9 +35,8 @@ namespace MWSound
} }
} }
SoundBufferPool::SoundBufferPool(const VFS::Manager& vfs, Sound_Output& output) SoundBufferPool::SoundBufferPool(Sound_Output& output)
: mVfs(&vfs) : mOutput(&output)
, mOutput(&output)
, mBufferCacheMax(std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1) * 1024 * 1024) , mBufferCacheMax(std::max(Settings::Manager::getInt("buffer cache max", "Sound"), 1) * 1024 * 1024)
, mBufferCacheMin( , mBufferCacheMin(
std::min(static_cast<std::size_t>(std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1)) std::min(static_cast<std::size_t>(std::max(Settings::Manager::getInt("buffer cache min", "Sound"), 1))
@ -135,7 +134,7 @@ namespace MWSound
max = std::max(min, max); max = std::max(min, max);
Sound_Buffer& sfx = mSoundBuffers.emplace_back("Sound/" + sound.mSound, volume, 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); mBufferNameMap.emplace(soundId, &sfx);
return &sfx; return &sfx;

@ -59,7 +59,7 @@ namespace MWSound
class SoundBufferPool class SoundBufferPool
{ {
public: public:
SoundBufferPool(const VFS::Manager& vfs, Sound_Output& output); SoundBufferPool(Sound_Output& output);
SoundBufferPool(const SoundBufferPool&) = delete; SoundBufferPool(const SoundBufferPool&) = delete;
@ -92,7 +92,6 @@ namespace MWSound
void clear(); void clear();
private: private:
const VFS::Manager* const mVfs;
Sound_Output* mOutput; Sound_Output* mOutput;
std::deque<Sound_Buffer> mSoundBuffers; std::deque<Sound_Buffer> mSoundBuffers;
std::unordered_map<ESM::RefId, Sound_Buffer*> mBufferNameMap; std::unordered_map<ESM::RefId, Sound_Buffer*> mBufferNameMap;

@ -81,7 +81,7 @@ namespace MWSound
: mVFS(vfs) : mVFS(vfs)
, mOutput(std::make_unique<OpenAL_Output>(*this)) , mOutput(std::make_unique<OpenAL_Output>(*this))
, mWaterSoundUpdater(makeWaterSoundUpdaterSettings()) , mWaterSoundUpdater(makeWaterSoundUpdaterSettings())
, mSoundBuffers(*vfs, *mOutput) , mSoundBuffers(*mOutput)
, mListenerUnderwater(false) , mListenerUnderwater(false)
, mListenerPos(0, 0, 0) , mListenerPos(0, 0, 0)
, mListenerDir(1, 0, 0) , mListenerDir(1, 0, 0)
@ -357,7 +357,7 @@ namespace MWSound
if (!mOutput->isInitialized()) if (!mOutput->isInitialized())
return; return;
DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); DecoderPtr decoder = loadVoice("Sound/" + filename);
if (!decoder) if (!decoder)
return; return;
@ -389,7 +389,7 @@ namespace MWSound
if (!mOutput->isInitialized()) if (!mOutput->isInitialized())
return; return;
DecoderPtr decoder = loadVoice(mVFS->normalizeFilename("Sound/" + filename)); DecoderPtr decoder = loadVoice("Sound/" + filename);
if (!decoder) if (!decoder)
return; return;

@ -85,9 +85,6 @@ namespace OpenMW
addOption("new-game", bpo::value<bool>()->implicit_value(true)->default_value(false), addOption("new-game", bpo::value<bool>()->implicit_value(true)->default_value(false),
"run new game sequence (ignored if skip-menu=0)"); "run new game sequence (ignored if skip-menu=0)");
addOption("fs-strict", bpo::value<bool>()->implicit_value(true)->default_value(false),
"strict file system handling (no case folding)");
addOption("encoding", bpo::value<std::string>()->default_value("win1252"), addOption("encoding", bpo::value<std::string>()->default_value("win1252"),
"Character encoding used in OpenMW game messages:\n" "Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, " "\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, "

@ -40,7 +40,7 @@ namespace
static constexpr std::size_t sInitialOffset = 324; static constexpr std::size_t sInitialOffset = 324;
static constexpr std::size_t sSkip = 100; static constexpr std::size_t sSkip = 100;
const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } }; 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::string mContentFile = "template.omwgame";
const std::filesystem::path mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile); const std::filesystem::path mContentFilePath = mFileCollections.getCollection(".omwgame").getPath(mContentFile);
}; };

@ -26,7 +26,7 @@ namespace
struct EsmLoaderTest : Test struct EsmLoaderTest : Test
{ {
const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } }; const Files::PathContainer mDataDirs{ { std::filesystem::path{ OPENMW_DATA_DIR } } };
const Files::Collections mFileCollections{ mDataDirs, true }; const Files::Collections mFileCollections{ mDataDirs };
const std::vector<std::string> mContentFiles{ { "template.omwgame" } }; const std::vector<std::string> mContentFiles{ { "template.omwgame" } };
}; };

@ -114,7 +114,7 @@ protected:
if (!dataLocal.empty()) if (!dataLocal.empty())
dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end()); dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end());
Files::Collections collections(dataDirs, true); Files::Collections collections(dataDirs);
std::vector<std::string> contentFiles = variables["content"].as<std::vector<std::string>>(); std::vector<std::string> contentFiles = variables["content"].as<std::vector<std::string>>();
for (auto& contentFile : contentFiles) for (auto& contentFile : contentFiles)

@ -27,7 +27,7 @@ namespace
struct BaseNifOsgLoaderTest struct BaseNifOsgLoaderTest
{ {
VFS::Manager mVfs{ false }; VFS::Manager mVfs;
Resource::ImageManager mImageManager{ &mVfs }; Resource::ImageManager mImageManager{ &mVfs };
const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt"); const osgDB::ReaderWriter* mReaderWriter = osgDB::Registry::instance()->getReaderWriterForExtension("osgt");
osg::ref_ptr<osgDB::Options> mOptions = new osgDB::Options; osg::ref_ptr<osgDB::Options> mOptions = new osgDB::Options;

@ -56,22 +56,16 @@ namespace TestingOpenMW
{ {
} }
void listResources(std::map<std::string, VFS::File*>& out, char (*normalize_function)(char)) override void listResources(std::map<std::string, VFS::File*>& out) override { out = mFiles; }
{
out = mFiles;
}
bool contains(const std::string& file, char (*normalize_function)(char)) const override bool contains(const std::string& file) const override { return mFiles.count(file) != 0; }
{
return mFiles.count(file) != 0;
}
std::string getDescription() const override { return "TestData"; } std::string getDescription() const override { return "TestData"; }
}; };
inline std::unique_ptr<VFS::Manager> createTestVFS(std::map<std::string, VFS::File*> files) inline std::unique_ptr<VFS::Manager> createTestVFS(std::map<std::string, VFS::File*> files)
{ {
auto vfs = std::make_unique<VFS::Manager>(true); auto vfs = std::make_unique<VFS::Manager>();
vfs->addArchive(std::make_unique<VFSTestData>(std::move(files))); vfs->addArchive(std::make_unique<VFSTestData>(std::move(files)));
vfs->buildIndex(); vfs->buildIndex();
return vfs; return vfs;

@ -8,14 +8,12 @@ namespace Files
{ {
Collections::Collections() Collections::Collections()
: mDirectories() : mDirectories()
, mFoldCase(false)
, mCollections() , mCollections()
{ {
} }
Collections::Collections(const Files::PathContainer& directories, bool foldCase) Collections::Collections(const Files::PathContainer& directories)
: mDirectories(directories) : mDirectories(directories)
, mFoldCase(foldCase)
, mCollections() , mCollections()
{ {
} }
@ -27,7 +25,7 @@ namespace Files
if (iter == mCollections.end()) if (iter == mCollections.end())
{ {
std::pair<MultiDirCollectionContainer::iterator, bool> result std::pair<MultiDirCollectionContainer::iterator, bool> result
= mCollections.emplace(ext, MultiDirCollection(mDirectories, ext, mFoldCase)); = mCollections.emplace(ext, MultiDirCollection(mDirectories, ext));
iter = result.first; iter = result.first;
} }
@ -44,14 +42,9 @@ namespace Files
const auto& path = iter2.path(); const auto& path = iter2.path();
const auto str = Files::pathToUnicodeString(path.filename()); const auto str = Files::pathToUnicodeString(path.filename());
if (mFoldCase)
{
if (Misc::StringUtils::ciEqual(file, str)) if (Misc::StringUtils::ciEqual(file, str))
return path; return path;
} }
else if (str == file)
return path;
}
} }
throw std::runtime_error("file " + file + " not found"); throw std::runtime_error("file " + file + " not found");
@ -66,14 +59,9 @@ namespace Files
const auto& path = iter2.path(); const auto& path = iter2.path();
const auto str = Files::pathToUnicodeString(path.filename()); const auto str = Files::pathToUnicodeString(path.filename());
if (mFoldCase)
{
if (Misc::StringUtils::ciEqual(file, str)) if (Misc::StringUtils::ciEqual(file, str))
return true; return true;
} }
else if (str == file)
return true;
}
} }
return false; return false;

@ -13,7 +13,7 @@ namespace Files
Collections(); Collections();
///< Directories are listed with increasing priority. ///< 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 ///< Return a file collection for the given extension. Extension must contain the
/// leading dot and must be all lower-case. /// leading dot and must be all lower-case.
@ -35,7 +35,6 @@ namespace Files
typedef std::map<std::string, MultiDirCollection> MultiDirCollectionContainer; typedef std::map<std::string, MultiDirCollection> MultiDirCollectionContainer;
Files::PathContainer mDirectories; Files::PathContainer mDirectories;
bool mFoldCase;
mutable MultiDirCollectionContainer mCollections; mutable MultiDirCollectionContainer mCollections;
}; };
} }

@ -7,29 +7,9 @@
namespace Files namespace Files
{ {
struct NameEqual
{
bool mStrict;
NameEqual(bool strict)
: mStrict(strict)
{
}
bool operator()(const std::string& left, const std::string& right) const MultiDirCollection::MultiDirCollection(const Files::PathContainer& directories, const std::string& extension)
{ {
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))
{
NameEqual equal(!foldCase);
for (const auto& directory : directories) for (const auto& directory : directories)
{ {
if (!std::filesystem::is_directory(directory)) if (!std::filesystem::is_directory(directory))
@ -42,7 +22,7 @@ namespace Files
{ {
const auto& path = dirIter.path(); const auto& path = dirIter.path();
if (!equal(extension, Files::pathToUnicodeString(path.extension()))) if (!Misc::StringUtils::ciEqual(extension, Files::pathToUnicodeString(path.extension())))
continue; continue;
const auto filename = Files::pathToUnicodeString(path.filename()); const auto filename = Files::pathToUnicodeString(path.filename());

@ -13,23 +13,6 @@ namespace Files
{ {
typedef std::vector<std::filesystem::path> PathContainer; typedef std::vector<std::filesystem::path> 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 /// \brief File collection across several directories
/// ///
/// This class lists all files with one specific extensions within one or more /// This class lists all files with one specific extensions within one or more
@ -38,14 +21,14 @@ namespace Files
class MultiDirCollection class MultiDirCollection
{ {
public: public:
typedef std::map<std::string, std::filesystem::path, NameLess> TContainer; typedef std::map<std::string, std::filesystem::path, Misc::StringUtils::CiComp> TContainer;
typedef TContainer::const_iterator TIter; typedef TContainer::const_iterator TIter;
private: private:
TContainer mFiles; TContainer mFiles;
public: 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. ///< Directories are listed with increasing priority.
/// \param extension The extension that should be listed in this collection. Must /// \param extension The extension that should be listed in this collection. Must
/// contain the leading dot. /// contain the leading dot.

@ -1,12 +1,12 @@
#include "resources.hpp" #include "resources.hpp"
#include <components/vfs/manager.hpp> #include <components/vfs/pathutil.hpp>
namespace LuaUi namespace LuaUi
{ {
std::shared_ptr<TextureResource> ResourceManager::registerTexture(TextureData data) std::shared_ptr<TextureResource> ResourceManager::registerTexture(TextureData data)
{ {
data.mPath = mVfs->normalizeFilename(data.mPath); VFS::Path::normalizeFilenameInPlace(data.mPath);
TextureResources& list = mTextures[data.mPath]; TextureResources& list = mTextures[data.mPath];
list.push_back(std::make_shared<TextureResource>(data)); list.push_back(std::make_shared<TextureResource>(data));

@ -28,16 +28,10 @@ namespace LuaUi
class ResourceManager class ResourceManager
{ {
public: public:
ResourceManager(const VFS::Manager* vfs)
: mVfs(vfs)
{
}
std::shared_ptr<TextureResource> registerTexture(TextureData data); std::shared_ptr<TextureResource> registerTexture(TextureData data);
void clear(); void clear();
private: private:
const VFS::Manager* mVfs;
using TextureResources = std::vector<std::shared_ptr<TextureResource>>; using TextureResources = std::vector<std::shared_ptr<TextureResource>>;
std::unordered_map<std::string, TextureResources> mTextures; std::unordered_map<std::string, TextureResources> mTextures;
}; };

@ -12,6 +12,7 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
namespace namespace
{ {
@ -157,9 +158,10 @@ std::string Misc::ResourceHelpers::correctSoundPath(std::string_view resPath, co
{ {
std::string sound{ resPath }; std::string sound{ resPath };
changeExtension(sound, ".mp3"); 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) bool Misc::ResourceHelpers::isHiddenMarker(const ESM::RefId& id)
@ -173,7 +175,7 @@ namespace
{ {
if (auto w = Misc::findExtension(resPath); w != std::string::npos) if (auto w = Misc::findExtension(resPath); w != std::string::npos)
resPath.insert(w, pattern); 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) std::string getBestLODMeshName(std::string const& resPath, const VFS::Manager* vfs, std::string_view pattern)

@ -13,6 +13,7 @@
#include <components/misc/pathhelpers.hpp> #include <components/misc/pathhelpers.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
#include <components/nifbullet/bulletnifloader.hpp> #include <components/nifbullet/bulletnifloader.hpp>
@ -109,7 +110,7 @@ namespace Resource
osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string& name) osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string& name)
{ {
const std::string normalized = mVFS->normalizeFilename(name); const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<BulletShape> shape; osg::ref_ptr<BulletShape> shape;
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
@ -169,7 +170,7 @@ namespace Resource
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(const std::string& name) osg::ref_ptr<BulletShapeInstance> BulletShapeManager::cacheInstance(const std::string& name)
{ {
const std::string normalized = mVFS->normalizeFilename(name); const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<BulletShapeInstance> instance = createInstance(normalized); osg::ref_ptr<BulletShapeInstance> instance = createInstance(normalized);
if (instance) if (instance)
@ -179,7 +180,7 @@ namespace Resource
osg::ref_ptr<BulletShapeInstance> BulletShapeManager::getInstance(const std::string& name) osg::ref_ptr<BulletShapeInstance> BulletShapeManager::getInstance(const std::string& name)
{ {
const std::string normalized = mVFS->normalizeFilename(name); const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mInstanceCache->takeFromObjectCache(normalized);
if (obj.get()) if (obj.get())

@ -6,6 +6,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/pathhelpers.hpp> #include <components/misc/pathhelpers.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
#include "objectcache.hpp" #include "objectcache.hpp"
@ -85,7 +86,7 @@ namespace Resource
osg::ref_ptr<osg::Image> ImageManager::getImage(std::string_view filename, bool disableFlip) osg::ref_ptr<osg::Image> 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<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj) if (obj)

@ -14,6 +14,7 @@
#include <components/nifosg/nifloader.hpp> #include <components/nifosg/nifloader.hpp>
#include <components/sceneutil/keyframe.hpp> #include <components/sceneutil/keyframe.hpp>
#include <components/sceneutil/osgacontroller.hpp> #include <components/sceneutil/osgacontroller.hpp>
#include <components/vfs/pathutil.hpp>
#include "animation.hpp" #include "animation.hpp"
#include "objectcache.hpp" #include "objectcache.hpp"
@ -210,11 +211,9 @@ namespace Resource
{ {
} }
KeyframeManager::~KeyframeManager() {}
osg::ref_ptr<const SceneUtil::KeyframeHolder> KeyframeManager::get(const std::string& name) osg::ref_ptr<const SceneUtil::KeyframeHolder> KeyframeManager::get(const std::string& name)
{ {
const std::string normalized = mVFS->normalizeFilename(name); const std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj) if (obj)

@ -49,7 +49,7 @@ namespace Resource
{ {
public: public:
KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager); KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager);
~KeyframeManager(); ~KeyframeManager() = default;
/// Retrieve a read-only keyframe resource by name (case-insensitive). /// Retrieve a read-only keyframe resource by name (case-insensitive).
/// @note Throws an exception if the resource is not found. /// @note Throws an exception if the resource is not found.

@ -22,7 +22,7 @@ namespace Resource
class BaseResourceManager class BaseResourceManager
{ {
public: public:
virtual ~BaseResourceManager() {} virtual ~BaseResourceManager() = default;
virtual void updateCache(double referenceTime) {} virtual void updateCache(double referenceTime) {}
virtual void clearCache() {} virtual void clearCache() {}
virtual void setExpiryDelay(double expiryDelay) {} 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. /// Clear cache entries that have not been referenced for longer than expiryDelay.
void updateCache(double referenceTime) override void updateCache(double referenceTime) override

@ -32,6 +32,7 @@
#include <components/misc/strings/conversion.hpp> #include <components/misc/strings/conversion.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/vfs/pathutil.hpp>
#include <components/sceneutil/clone.hpp> #include <components/sceneutil/clone.hpp>
#include <components/sceneutil/controller.hpp> #include <components/sceneutil/controller.hpp>
@ -507,7 +508,7 @@ namespace Resource
bool SceneManager::checkLoaded(const std::string& name, double timeStamp) 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. /// @brief Callback to read image files from the VFS.
@ -862,7 +863,7 @@ namespace Resource
osg::ref_ptr<const osg::Node> SceneManager::getTemplate(const std::string& name, bool compile) osg::ref_ptr<const osg::Node> SceneManager::getTemplate(const std::string& name, bool compile)
{ {
std::string normalized = mVFS->normalizeFilename(name); std::string normalized = VFS::Path::normalizeFilename(name);
osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized); osg::ref_ptr<osg::Object> obj = mCache->getRefFromObjectCache(normalized);
if (obj) if (obj)

@ -12,7 +12,7 @@ namespace VFS
class File class File
{ {
public: public:
virtual ~File() {} virtual ~File() = default;
virtual Files::IStreamPtr open() = 0; virtual Files::IStreamPtr open() = 0;
@ -22,14 +22,13 @@ namespace VFS
class Archive class Archive
{ {
public: public:
virtual ~Archive() {} virtual ~Archive() = default;
/// List all resources contained in this archive, and run the resource names through the given normalize /// List all resources contained in this archive.
/// function. virtual void listResources(std::map<std::string, File*>& out) = 0;
virtual void listResources(std::map<std::string, File*>& out, char (*normalize_function)(char)) = 0;
/// True if this archive contains the provided normalized file. /// 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; virtual std::string getDescription() const = 0;
}; };

@ -2,6 +2,7 @@
#define VFS_BSAARCHIVE_HPP_ #define VFS_BSAARCHIVE_HPP_
#include "archive.hpp" #include "archive.hpp"
#include "pathutil.hpp"
#include <components/bsa/ba2dx10file.hpp> #include <components/bsa/ba2dx10file.hpp>
#include <components/bsa/ba2gnrlfile.hpp> #include <components/bsa/ba2gnrlfile.hpp>
@ -47,24 +48,22 @@ namespace VFS
virtual ~BsaArchive() {} virtual ~BsaArchive() {}
void listResources(std::map<std::string, File*>& out, char (*normalize_function)(char)) override void listResources(std::map<std::string, File*>& out) override
{ {
for (auto& resource : mResources) for (auto& resource : mResources)
{ {
std::string ent = resource.mInfo->name(); std::string ent = resource.mInfo->name();
std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function); Path::normalizeFilenameInPlace(ent);
out[ent] = &resource; 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) for (const auto& it : mResources)
{ {
std::string ent = it.mInfo->name(); if (Path::pathEqual(file, it.mInfo->name()))
std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function);
if (file == ent)
return true; return true;
} }
return false; return false;

@ -1,9 +1,9 @@
#include "filesystemarchive.hpp" #include "filesystemarchive.hpp"
#include <algorithm>
#include <filesystem> #include <filesystem>
#include "pathutil.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/files/constrainedfilestream.hpp> #include <components/files/constrainedfilestream.hpp>
#include <components/files/conversion.hpp> #include <components/files/conversion.hpp>
@ -17,7 +17,7 @@ namespace VFS
{ {
} }
void FileSystemArchive::listResources(std::map<std::string, File*>& out, char (*normalize_function)(char)) void FileSystemArchive::listResources(std::map<std::string, File*>& out)
{ {
if (!mBuiltIndex) if (!mBuiltIndex)
{ {
@ -33,16 +33,13 @@ namespace VFS
continue; continue;
const auto& path = i.path(); const auto& path = i.path();
const auto& proper = Files::pathToUnicodeString(path); const std::string proper = Files::pathToUnicodeString(path);
FileSystemArchiveFile file(path); FileSystemArchiveFile file(path);
std::string searchable; std::string searchable = Path::normalizeFilename(std::string_view{ proper }.substr(prefix));
std::transform(std::next(proper.begin(), static_cast<std::string::difference_type>(prefix)),
proper.end(), std::back_inserter(searchable), normalize_function);
const auto inserted = mIndex.insert(std::make_pair(searchable, file)); const auto inserted = mIndex.emplace(searchable, file);
if (!inserted.second) if (!inserted.second)
Log(Debug::Warning) Log(Debug::Warning)
<< "Warning: found duplicate file for '" << proper << "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(); return mIndex.find(file) != mIndex.end();
} }

@ -27,9 +27,9 @@ namespace VFS
public: public:
FileSystemArchive(const std::filesystem::path& path); FileSystemArchive(const std::filesystem::path& path);
void listResources(std::map<std::string, File*>& out, char (*normalize_function)(char)) override; void listResources(std::map<std::string, File*>& 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; std::string getDescription() const override;

@ -7,38 +7,10 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include "archive.hpp" #include "archive.hpp"
#include "pathutil.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);
}
}
namespace VFS namespace VFS
{ {
Manager::Manager(bool strict)
: mStrict(strict)
{
}
Manager::~Manager() {}
void Manager::reset() void Manager::reset()
{ {
mIndex.clear(); mIndex.clear();
@ -55,15 +27,12 @@ namespace VFS
mIndex.clear(); mIndex.clear();
for (const auto& archive : mArchives) 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 Files::IStreamPtr Manager::get(std::string_view name) const
{ {
std::string normalized(name); return getNormalized(Path::normalizeFilename(name));
normalize_path(normalized, mStrict);
return getNormalized(normalized);
} }
Files::IStreamPtr Manager::getNormalized(const std::string& normalizedName) const Files::IStreamPtr Manager::getNormalized(const std::string& normalizedName) const
@ -76,26 +45,15 @@ namespace VFS
bool Manager::exists(std::string_view name) const bool Manager::exists(std::string_view name) const
{ {
std::string normalized(name); return mIndex.find(Path::normalizeFilename(name)) != mIndex.end();
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;
} }
std::string Manager::getArchive(std::string_view name) const std::string Manager::getArchive(std::string_view name) const
{ {
std::string normalized(name); std::string normalized = Path::normalizeFilename(name);
normalize_path(normalized, mStrict);
for (auto it = mArchives.rbegin(); it != mArchives.rend(); ++it) 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 (*it)->getDescription();
} }
return {}; return {};
@ -104,7 +62,7 @@ namespace VFS
std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path& name) const
{ {
std::string normalized = Files::pathToUnicodeString(name); std::string normalized = Files::pathToUnicodeString(name);
normalize_path(normalized, mStrict); Path::normalizeFilenameInPlace(normalized);
const auto found = mIndex.find(normalized); const auto found = mIndex.find(normalized);
if (found == mIndex.end()) if (found == mIndex.end())
@ -124,7 +82,7 @@ namespace VFS
{ {
if (path.empty()) if (path.empty())
return { mIndex.begin(), mIndex.end() }; return { mIndex.begin(), mIndex.end() };
auto normalized = normalizeFilename(path); std::string normalized = Path::normalizeFilename(path);
const auto it = mIndex.lower_bound(normalized); const auto it = mIndex.lower_bound(normalized);
if (it == mIndex.end() || !startsWith(it->first, normalized)) if (it == mIndex.end() || !startsWith(it->first, normalized))
return { it, it }; return { it, it };

@ -9,12 +9,11 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "archive.hpp"
namespace VFS namespace VFS
{ {
class Archive;
class File;
template <typename Iterator> template <typename Iterator>
class IteratorPair class IteratorPair
{ {
@ -62,12 +61,6 @@ namespace VFS
using RecursiveDirectoryRange = IteratorPair<RecursiveDirectoryIterator>; using RecursiveDirectoryRange = IteratorPair<RecursiveDirectoryIterator>;
public: 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. // Empty the file index and unregister archives.
void reset(); void reset();
@ -82,10 +75,6 @@ namespace VFS
/// @note May be called from any thread once the index has been built. /// @note May be called from any thread once the index has been built.
bool exists(std::string_view name) const; 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. /// Retrieve a file by name.
/// @note Throws an exception if the file can not be found. /// @note Throws an exception if the file can not be found.
/// @note May be called from any thread once the index has been built. /// @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; std::filesystem::path getAbsoluteFileName(const std::filesystem::path& name) const;
private: private:
bool mStrict;
std::vector<std::unique_ptr<Archive>> mArchives; std::vector<std::unique_ptr<Archive>> mArchives;
std::map<std::string, File*> mIndex; std::map<std::string, File*> mIndex;

@ -0,0 +1,50 @@
#ifndef OPENMW_COMPONENTS_RESOURCE_PATH_H
#define OPENMW_COMPONENTS_RESOURCE_PATH_H
#include <components/misc/strings/lower.hpp>
#include <algorithm>
#include <string>
#include <string_view>
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
Loading…
Cancel
Save