From d260e5c1bd39a07209eba69f9a291bd9f871bbe3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:00:00 +0200 Subject: [PATCH 1/6] added file collection class --- CMakeLists.txt | 4 + components/files/collections.cpp | 25 ++++++ components/files/collections.hpp | 26 ++++++ components/files/multidircollection.cpp | 102 ++++++++++++++++++++++++ components/files/multidircollection.hpp | 78 ++++++++++++++++++ 5 files changed, 235 insertions(+) create mode 100644 components/files/collections.cpp create mode 100644 components/files/collections.hpp create mode 100644 components/files/multidircollection.cpp create mode 100644 components/files/multidircollection.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d02e50f4..c5001a894 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,9 +183,13 @@ source_group(components\\misc FILES ${MISC} ${MISC_HEADER}) set(FILES ${COMP_DIR}/files/path.cpp + ${COMP_DIR}/files/multidircollection.cpp + ${COMP_DIR}/files/collections.cpp ) set(FILES_HEADER ${COMP_DIR}/files/path.hpp + ${COMP_DIR}/files/multidircollection.hpp + ${COMP_DIR}/files/collections.hpp ) source_group(components\\files FILES ${FILES} ${FILES_HEADER}) diff --git a/components/files/collections.cpp b/components/files/collections.cpp new file mode 100644 index 000000000..6d1c00ab1 --- /dev/null +++ b/components/files/collections.cpp @@ -0,0 +1,25 @@ + +#include "collections.hpp" + +namespace Files +{ + Collections::Collections (const std::vector& directories, bool foldCase) + : mDirectories (directories), mFoldCase (foldCase) + {} + + const MultiDirCollection& Collections::getCollection (const std::string& extension) const + { + std::map::iterator iter = mCollections.find (extension); + + if (iter==mCollections.end()) + { + std::pair::iterator, bool> result = + mCollections.insert (std::make_pair (extension, + MultiDirCollection (mDirectories, extension, mFoldCase))); + + iter = result.first; + } + + return iter->second; + } +} diff --git a/components/files/collections.hpp b/components/files/collections.hpp new file mode 100644 index 000000000..9e23892af --- /dev/null +++ b/components/files/collections.hpp @@ -0,0 +1,26 @@ +#ifndef COMPONENTS_FILES_COLLECTION_HPP +#define COMPONENTS_FILES_COLLECTION_HPP + +#include "multidircollection.hpp" + +namespace Files +{ + class Collections + { + std::vector mDirectories; + bool mFoldCase; + mutable std::map mCollections; + + public: + + Collections (const std::vector& directories, bool foldCase); + ///< Directories are listed with increasing priority. + + const MultiDirCollection& getCollection (const std::string& extension) const; + ///< Return a file collection for the given extension. Extension must contain the + /// leading dot and must be all lower-case. + + }; +} + +#endif diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp new file mode 100644 index 000000000..0543312e0 --- /dev/null +++ b/components/files/multidircollection.cpp @@ -0,0 +1,102 @@ + +#include "multidircollection.hpp" + +#include + +#include +#include + +#include + +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; + + std::size_t len = left.length(); + + if (len!=right.length()) + return false; + + for (std::size_t i=0; i& directories, + const std::string& extension, bool foldCase) + : mFiles (NameLess (foldCase)) + { + NameEqual equal (foldCase); + + for (std::vector::const_iterator iter = directories.begin(); + iter!=directories.end(); ++iter) + { + boost::filesystem::path dataDirectory = *iter; + + for (boost::filesystem::directory_iterator iter (dataDirectory); + iter!=boost::filesystem::directory_iterator(); ++iter) + { + boost::filesystem::path path = *iter; + + if (!equal (extension, path.extension())) + continue; + + std::string filename = path.filename(); + + TIter result = mFiles.find (filename); + + if (result==mFiles.end()) + { + mFiles.insert (std::make_pair (filename, path)); + } + else if (result->first==filename) + { + mFiles[filename] = path; + } + else + { + // handle case folding + mFiles.erase (result->first); + mFiles.insert (std::make_pair (filename, path)); + } + } + } + } + + boost::filesystem::path MultiDirCollection::getPath (const std::string& file) const + { + TIter iter = mFiles.find (file); + + if (iter==mFiles.end()) + throw std::runtime_error ("file " + file + " not found"); + + return iter->second; + } + + MultiDirCollection::TIter MultiDirCollection::begin() const + { + return mFiles.begin(); + } + + MultiDirCollection::TIter MultiDirCollection::end() const + { + return mFiles.end(); + } +} diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp new file mode 100644 index 000000000..36270dfd1 --- /dev/null +++ b/components/files/multidircollection.hpp @@ -0,0 +1,78 @@ +#ifndef COMPONENTS_FILES_MULTIDIRSOLLECTION_HPP +#define COMPONENTS_FILES_MULTIDIRSOLLECTION_HPP + +#include +#include +#include + +#include + +namespace Files +{ + struct NameLess + { + bool mStrict; + + NameLess (bool strict) : mStrict (strict) {} + + bool operator() (const std::string& left, const std::string& right) const + { + if (mStrict) + return left=r) + return false; + } + + return left.length() TContainer; + typedef TContainer::const_iterator TIter; + + private: + + TContainer mFiles; + + public: + + MultiDirCollection (const std::vector& directories, + const std::string& extension, bool foldCase); + ///< Directories are listed with increasing priority. + /// \param extension The extension that should be listed in this collection. Must + /// contain the leading dot. + /// \param foldCase Ignore filename case + + boost::filesystem::path getPath (const std::string& file) const; + ///< Return full path (including filename) of \æ file. + /// + /// If the file does not exist, an exception is thrown. \a file must include + /// the extension. + + TIter begin() const; + ///< Return iterator pointing to the first file. + + TIter end() const; + ///< Return iterator pointing past the last file. + + }; +} + +#endif From 6e880cffb24ba19dd8622ae3477a42622e78b023 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:32:42 +0200 Subject: [PATCH 2/6] changed engine class to support multiple data directories for esm files --- apps/openmw/engine.cpp | 26 ++++++++++++-------------- apps/openmw/engine.hpp | 9 +++++---- apps/openmw/main.cpp | 4 +++- apps/openmw/mwworld/world.cpp | 8 +++++--- apps/openmw/mwworld/world.hpp | 8 +++++++- components/files/collections.cpp | 2 ++ components/files/collections.hpp | 2 ++ 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1ca5c68b4..fbba304b9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -240,15 +240,12 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { - boost::filesystem::directory_iterator end; + const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); - for (boost::filesystem::directory_iterator iter (mDataDir); iter!=end; ++iter) + for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter) { - if (boost::filesystem::extension (iter->path())==".bsa") - { - std::cout << "Adding " << iter->path().string() << std::endl; - addBSA(iter->path().string()); - } + std::cout << "Adding " << iter->second.string() << std::endl; + addBSA (iter->second.string()); } } @@ -263,9 +260,13 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) // Set data dir -void OMW::Engine::setDataDir (const boost::filesystem::path& dataDir) +void OMW::Engine::setDataDirs (const std::vector& dataDirs) { - mDataDir = boost::filesystem::system_complete (dataDir); + /// \todo remove mDataDir, once resources system can handle multiple directories + assert (!dataDirs.empty()); + mDataDir = dataDirs[0]; + + mFileCollections = Files::Collections (dataDirs, true); } // Set resource dir @@ -318,15 +319,12 @@ void OMW::Engine::setNewGame() void OMW::Engine::go() { assert (!mEnvironment.mWorld); - assert (!mDataDir.empty()); assert (!mCellName.empty()); assert (!mMaster.empty()); test.name = ""; total = 0; - std::cout << "Data directory: " << mDataDir << "\n"; - std::string cfgDir = Files::getPath (Files::Path_ConfigGlobal, "openmw", ""); std::string cfgUserDir = Files::getPath (Files::Path_ConfigUser, "openmw", ""); std::string plugCfg = "plugins.cfg"; @@ -358,8 +356,8 @@ void OMW::Engine::go() mPhysicEngine = new OEngine::Physic::PhysicEngine(shapeLoader); // Create the world - mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mDataDir, mMaster, mResDir, mNewGame, mEnvironment); - + mEnvironment.mWorld = new MWWorld::World (mOgre, mPhysicEngine, mFileCollections, mMaster, + mResDir, mNewGame, mEnvironment); // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), mOgre.getScene(), false, cfgDir); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 2f8a5b1d2..4631f60a7 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "mwworld/environment.hpp" #include "mwworld/ptr.hpp" @@ -55,8 +56,6 @@ namespace OMW class Engine : private Ogre::FrameListener { - - //int nFiles; boost::filesystem::path mDataDir; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer mOgre; @@ -84,6 +83,8 @@ namespace OMW MWWorld::Ptr mIgnoreLocalPtr; + Files::Collections mFileCollections; + // not implemented Engine (const Engine&); Engine& operator= (const Engine&); @@ -108,8 +109,8 @@ namespace OMW ~Engine(); - /// Set data dir - void setDataDir (const boost::filesystem::path& dataDir); + /// Set data dirs + void setDataDirs (const std::vector& dataDirs); /// Set resource dir void setResourceDir (const boost::filesystem::path& parResDir); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index c5f53d7b5..7eba8c303 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -105,7 +105,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings - engine.setDataDir (variables["data"].as()); + std::vector dataDirs; + dataDirs.push_back (variables["data"].as()); + engine.setDataDirs (dataDirs); engine.setResourceDir (variables["resources"].as()); // master and plugin diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 81151ccdc..68e3a745d 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwrender/sky.hpp" #include "../mwrender/interior.hpp" @@ -406,15 +407,16 @@ namespace MWWorld mCellChanged = true; } - World::World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const boost::filesystem::path& dataDir, + World::World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment) : mSkyManager (0), mScene (renderer,physEng), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), mSky (false), mCellChanged (false), mEnvironment (environment) { mPhysEngine = physEng; - boost::filesystem::path masterPath (dataDir); - masterPath /= master; + + boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master)); std::cout << "Loading ESM " << masterPath.string() << "\n"; diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index d722eb166..160c20314 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -26,6 +26,11 @@ namespace ESM struct Position; } +namespace Files +{ + class Collections; +} + namespace Render { class OgreRenderer; @@ -107,7 +112,8 @@ namespace MWWorld /// interior cell. public: - World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, const boost::filesystem::path& dataDir, + World (OEngine::Render::OgreRenderer& renderer, OEngine::Physic::PhysicEngine* physEng, + const Files::Collections& fileCollections, const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment); diff --git a/components/files/collections.cpp b/components/files/collections.cpp index 6d1c00ab1..8cd4865b3 100644 --- a/components/files/collections.cpp +++ b/components/files/collections.cpp @@ -3,6 +3,8 @@ namespace Files { + Collections::Collections() : mFoldCase (false) {} + Collections::Collections (const std::vector& directories, bool foldCase) : mDirectories (directories), mFoldCase (foldCase) {} diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 9e23892af..6eaf0303e 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -13,6 +13,8 @@ namespace Files public: + Collections(); + Collections (const std::vector& directories, bool foldCase); ///< Directories are listed with increasing priority. From e60f0e3b38c38004aa550dabbc616834c4da6875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:39:11 +0200 Subject: [PATCH 3/6] --data switch accepts multiple directories now --- apps/openmw/main.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 7eba8c303..0545e5a98 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -42,8 +42,10 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) desc.add_options() ("help", "print help message") - ("data", bpo::value()->default_value ("data"), - "set data directory") + ("data", bpo::value >() + ->default_value (std::vector(), "data") + ->multitoken(), + "set data directories (later directories have higher priority)") ("resources", bpo::value()->default_value ("resources"), "set resources directory") ("start", bpo::value()->default_value ("Beshara"), @@ -105,9 +107,10 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings - std::vector dataDirs; - dataDirs.push_back (variables["data"].as()); - engine.setDataDirs (dataDirs); + std::vector dataDirs = variables["data"].as >(); + std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); + engine.setDataDirs (dataDirs2); + engine.setResourceDir (variables["resources"].as()); // master and plugin From ef1e986a877d65c7db4065c9d846c95325bc50da Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:50:28 +0200 Subject: [PATCH 4/6] added --data-local switch --- apps/openmw/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 0545e5a98..8dff52024 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -46,6 +46,8 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ->default_value (std::vector(), "data") ->multitoken(), "set data directories (later directories have higher priority)") + ("data-local", bpo::value()->default_value (""), + "set local data directory (highest priority)") ("resources", bpo::value()->default_value ("resources"), "set resources directory") ("start", bpo::value()->default_value ("Beshara"), @@ -109,6 +111,11 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) // directory settings std::vector dataDirs = variables["data"].as >(); std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); + + std::string local = variables["data-local"].as(); + if (!local.empty()) + dataDirs.push_back (local); + engine.setDataDirs (dataDirs2); engine.setResourceDir (variables["resources"].as()); From 8829398bfc24ff1085020f58bf967f720681d80a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 19:56:16 +0200 Subject: [PATCH 5/6] added --fs-strict switch --- apps/openmw/engine.cpp | 8 +++++++- apps/openmw/engine.hpp | 7 +++++++ apps/openmw/main.cpp | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fbba304b9..e1ce97bfa 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -218,6 +218,7 @@ OMW::Engine::Engine() , mScriptManager (0) , mScriptContext (0) , mGuiManager (0) + , mFSStrict (false) { MWClass::registerClasses(); } @@ -258,6 +259,11 @@ void OMW::Engine::addResourcesDirectory (const boost::filesystem::path& path) Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); } +void OMW::Engine::enableFSStrict() +{ + mFSStrict = true; +} + // Set data dir void OMW::Engine::setDataDirs (const std::vector& dataDirs) @@ -266,7 +272,7 @@ void OMW::Engine::setDataDirs (const std::vector& dataD assert (!dataDirs.empty()); mDataDir = dataDirs[0]; - mFileCollections = Files::Collections (dataDirs, true); + mFileCollections = Files::Collections (dataDirs, !mFSStrict); } // Set resource dir diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 4631f60a7..e49ddfc06 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -84,6 +84,7 @@ namespace OMW MWWorld::Ptr mIgnoreLocalPtr; Files::Collections mFileCollections; + bool mFSStrict; // not implemented Engine (const Engine&); @@ -109,6 +110,12 @@ namespace OMW ~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(); + /// Set data dirs void setDataDirs (const std::vector& dataDirs); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 8dff52024..e117a0688 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -74,6 +74,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ( "script-all", boost::program_options::value()-> implicit_value (true)->default_value (false), "compile all scripts (excluding dialogue scripts) at startup") + ( "fs-strict", boost::program_options::value()-> + implicit_value (true)->default_value (false), + "strict file system handling (no case folding)") ; bpo::variables_map variables; @@ -109,6 +112,9 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } // directory settings + if (variables["fs-strict"].as()==true) + engine.enableFSStrict(); + std::vector dataDirs = variables["data"].as >(); std::vector dataDirs2 (dataDirs.begin(), dataDirs.end()); From d9f1b642134692805452e9788ba8c2188f4cc61f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 5 May 2011 21:39:52 +0200 Subject: [PATCH 6/6] some file collection bug fixing --- components/files/multidircollection.cpp | 4 ++-- components/files/multidircollection.hpp | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 0543312e0..4428b364e 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -41,9 +41,9 @@ namespace Files MultiDirCollection::MultiDirCollection (const std::vector& directories, const std::string& extension, bool foldCase) - : mFiles (NameLess (foldCase)) + : mFiles (NameLess (!foldCase)) { - NameEqual equal (foldCase); + NameEqual equal (!foldCase); for (std::vector::const_iterator iter = directories.begin(); iter!=directories.end(); ++iter) diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index 36270dfd1..bd0304e40 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -27,7 +27,9 @@ namespace Files char l = std::tolower (left[i]); char r = std::tolower (right[i]); - if (l>=r) + if (lr) return false; }