diff --git a/.gitignore b/.gitignore index ada874bb2..e57bcfc62 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ Docs/mainpage.hpp CMakeFiles */CMakeFiles CMakeCache.txt +moc_*.cxx +cmake_install.cmake +*.[ao] + diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index c8311846f..8b59f1b81 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "datafilespage.hpp" #include "lineedit.hpp" @@ -26,7 +26,9 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2) return index1.row() <= index2.row(); } -DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent) +DataFilesPage::DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent) + : QWidget(parent) + , mCfgMgr(cfg) { mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters mPluginsModel = new PluginsModel(); // Contains selectable plugins @@ -236,13 +238,11 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict) void DataFilesPage::setupConfig() { - Cfg::ConfigurationManager cfg; - - QString config = (cfg.getRuntimeConfigPath() / "launcher.cfg").string().c_str(); + QString config = (mCfgMgr.getLocalPath() / "launcher.cfg").string().c_str(); QFile file(config); if (!file.exists()) { - config = QString::fromStdString((cfg.getLocalConfigPath() / "launcher.cfg").string()); + config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string()); } file.setFileName(config); // Just for displaying information diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 2d0a385a7..db1068abd 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -19,12 +19,14 @@ class PluginsModel; class PluginsView; class ComboBox; +namespace Files { struct ConfigurationManager; } + class DataFilesPage : public QWidget { Q_OBJECT public: - DataFilesPage(QWidget *parent = 0); + DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); ComboBox *mProfilesComboBox; QSettings *mLauncherConfig; @@ -81,6 +83,8 @@ private: QAction *mCheckAction; QAction *mUncheckAction; + Files::ConfigurationManager& mCfgMgr; + void addPlugins(const QModelIndex &index); void removePlugins(const QModelIndex &index); void uncheckPlugins(); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 92fbf3350..d41a33356 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,8 +1,11 @@ #include #include "graphicspage.hpp" +#include -GraphicsPage::GraphicsPage(QWidget *parent) : QWidget(parent) +GraphicsPage::GraphicsPage(Files::ConfigurationManager& cfg, QWidget *parent) + : QWidget(parent) + , mCfgMgr(cfg) { QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this); @@ -147,21 +150,21 @@ void GraphicsPage::createPages() void GraphicsPage::setupConfig() { - QString ogreCfg = mCfg.getOgreConfigPath().string().c_str(); + QString ogreCfg = mCfgMgr.getOgreConfigPath().string().c_str(); QFile file(ogreCfg); mOgreConfig = new QSettings(ogreCfg, QSettings::IniFormat); } void GraphicsPage::setupOgre() { - QString pluginCfg = mCfg.getPluginsConfigPath().string().c_str(); + QString pluginCfg = mCfgMgr.getPluginsConfigPath().string().c_str(); QFile file(pluginCfg); // Create a log manager so we can surpress debug text to stdout/stderr Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager; - logMgr->createLog((mCfg.getLogPath().string() + "/launcherOgre.log"), true, false, false); + logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false); - QString ogreCfg = QString::fromStdString(mCfg.getOgreConfigPath().string()); + QString ogreCfg = QString::fromStdString(mCfgMgr.getOgreConfigPath().string()); file.setFileName(ogreCfg); //we need to check that the path to the configuration file exists before we diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 5d50cfc61..ffd7a41b8 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -7,19 +7,20 @@ #include #include #include -#include class QComboBox; class QCheckBox; class QStackedWidget; class QSettings; +namespace Files { struct ConfigurationManager; } + class GraphicsPage : public QWidget { Q_OBJECT public: - GraphicsPage(QWidget *parent = 0); + GraphicsPage(Files::ConfigurationManager& cfg, QWidget *parent = 0); QSettings *mOgreConfig; @@ -29,7 +30,7 @@ public slots: void rendererChanged(const QString &renderer); private: - Cfg::ConfigurationManager mCfg; + Files::ConfigurationManager& mCfgMgr; Ogre::Root *mOgre; Ogre::RenderSystem *mSelectedRenderSystem; Ogre::RenderSystem *mOpenGLRenderSystem; diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 4ec8b309c..dd9f0d653 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -152,27 +152,27 @@ QStringList MainDialog::readConfig(const QString &fileName) void MainDialog::createPages() { mPlayPage = new PlayPage(this); - mGraphicsPage = new GraphicsPage(this); - mDataFilesPage = new DataFilesPage(this); + mGraphicsPage = new GraphicsPage(mCfgMgr, this); + mDataFilesPage = new DataFilesPage(mCfgMgr, this); // Retrieve all data entries from the configs QStringList dataDirs; // Global location - QFile file(QString::fromStdString((mCfg.getGlobalConfigPath()/"openmw.cfg").string())); + QFile file(QString::fromStdString((mCfgMgr.getGlobalPath()/"openmw.cfg").string())); if (file.exists()) { dataDirs = readConfig(file.fileName()); } - // User location - file.setFileName(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string())); + // Local location + file.setFileName("./openmw.cfg"); + if (file.exists()) { dataDirs = readConfig(file.fileName()); } - // Local location - file.setFileName("./openmw.cfg"); - + // User location + file.setFileName(QString::fromStdString((mCfgMgr.getUserPath()/"openmw.cfg").string())); if (file.exists()) { dataDirs = readConfig(file.fileName()); } @@ -328,7 +328,7 @@ void MainDialog::writeConfig() dataFiles.append(mDataFilesPage->checkedPlugins()); // Open the config as a QFile - QFile file(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string())); + QFile file(QString::fromStdString((mCfgMgr.getUserPath()/"openmw.cfg").string())); if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { // File cannot be opened or created diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 047050902..718fde4f7 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -3,7 +3,7 @@ #include -#include +#include class QListWidget; class QListWidgetItem; @@ -47,7 +47,7 @@ private: QStringList mDataDirs; bool mStrict; - Cfg::ConfigurationManager mCfg; + Files::ConfigurationManager mCfgMgr; }; #endif diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3579977b0..892e7a188 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -18,7 +18,9 @@ #include #include #include -#include +#include +#include + #include #include @@ -173,7 +175,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) return true; } -OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager) +OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mPhysicEngine (0) , mFpsLevel(0) @@ -214,15 +216,16 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa"); - - for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter) + std::string dataDirectory; + for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter) { - std::cout << "Adding " << iter->second.string() << std::endl; - Bsa::addBSA (iter->second.string()); - } + std::cout << "Adding " << iter->second.string() << std::endl; + Bsa::addBSA(iter->second.string()); - std::cout << "Data dir " << mDataDir.string() << std::endl; - Bsa::addDir(mDataDir.string(), mFSStrict); + dataDirectory = iter->second.parent_path().string(); + std::cout << "Data dir " << dataDirectory << std::endl; + Bsa::addDir(dataDirectory, mFSStrict); + } } // add resources directory @@ -245,7 +248,7 @@ void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs) { /// \todo remove mDataDir, once resources system can handle multiple directories assert (!dataDirs.empty()); - mDataDir = dataDirs.back(); + mDataDirs = dataDirs; mFileCollections = Files::Collections (dataDirs, !mFSStrict); } @@ -358,7 +361,7 @@ void OMW::Engine::go() mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(), mOgre->getCamera(), mEnvironment.mWorld->getStore(), - (mDataDir), + mDataDirs, mUseSound, mFSStrict, mEnvironment); // Create script system diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 88eea728e..b6d52a35d 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -11,7 +11,6 @@ #include #include -#include #include "mwworld/environment.hpp" #include "mwworld/ptr.hpp" @@ -54,13 +53,18 @@ namespace OEngine } } +namespace Files +{ + struct ConfigurationManager; +} + namespace OMW { /// \brief Main engine class, that brings together all the components of OpenMW class Engine : private Ogre::FrameListener { std::string mEncoding; - boost::filesystem::path mDataDir; + Files::PathContainer mDataDirs; boost::filesystem::path mResDir; OEngine::Render::OgreRenderer *mOgre; OEngine::Physic::PhysicEngine* mPhysicEngine; @@ -104,7 +108,7 @@ namespace OMW virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); public: - Engine(Cfg::ConfigurationManager& configurationManager); + Engine(Files::ConfigurationManager& configurationManager); virtual ~Engine(); /// Enable strict filesystem mode (do not fold case) @@ -164,7 +168,7 @@ namespace OMW void setAnimationVerbose(bool animverbose); private: - Cfg::ConfigurationManager& mCfgMgr; + Files::ConfigurationManager& mCfgMgr; }; } diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 2d0c8e44b..72c2deb13 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -6,9 +6,9 @@ #include #include -#include +#include #include -#include +#include #include "engine.hpp" @@ -46,7 +46,7 @@ using namespace std; * \retval true - Everything goes OK * \retval false - Error */ -bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::ConfigurationManager& cfgMgr) +bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::ConfigurationManager& cfgMgr) { // Create a local alias for brevity namespace bpo = boost::program_options; @@ -160,6 +160,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio engine.enableFSStrict(variables["fs-strict"].as()); Files::PathContainer dataDirs(variables["data"].as()); + cfgMgr.processPaths(dataDirs); std::string local(variables["data-local"].as()); if (!local.empty()) @@ -224,7 +225,7 @@ int main(int argc, char**argv) try { - Cfg::ConfigurationManager cfgMgr; + Files::ConfigurationManager cfgMgr; OMW::Engine engine(cfgMgr); if (parseOptions(argc, argv, engine, cfgMgr)) diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 7390e4c5c..76ef23bc2 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -4,8 +4,6 @@ #include #include -using namespace std; - #include #include @@ -15,6 +13,7 @@ using namespace std; #include #include + #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" @@ -90,24 +89,28 @@ namespace MWSound // relative to the sound dir, and translates them into full paths // of existing files in the filesystem, if they exist. bool FSstrict; - FileFinder::FileFinder files; - FileFinder::FileFinderStrict strict; - FileFinder::FileFinder musicpath; - FileFinder::FileFinderStrict musicpathStrict; - - SoundImpl(Ogre::Root *root, Ogre::Camera *camera, - const ESMS::ESMStore &str, - const std::string &soundDir, const std::string &musicDir, bool fsstrict) + FileFinder::LessTreeFileFinder files; + FileFinder::StrictTreeFileFinder strict; + FileFinder::LessTreeFileFinder musicpath; + FileFinder::StrictTreeFileFinder musicpathStrict; + + SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str, + const Files::PathContainer& soundDir, + const Files::PathContainer& musicDir, + bool fsstrict) : mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) , updater(mgr) , cameraTracker(mgr) , store(str) - , files(soundDir), strict(soundDir) - ,musicpath(musicDir), musicpathStrict(musicDir) + , FSstrict(fsstrict) + , files(soundDir) + , strict(soundDir) + , musicpath(musicDir) + , musicpathStrict(musicDir) { - FSstrict = fsstrict; - cout << "Sound output: " << SOUND_OUT << endl; - cout << "Sound decoder: " << SOUND_IN << endl; + + std::cout << "Sound output: " << SOUND_OUT << std::endl; + std::cout << "Sound decoder: " << SOUND_IN << std::endl; // Attach the camera to the camera tracker cameraTracker.followCamera(camera); @@ -136,36 +139,49 @@ namespace MWSound bool hasFile(const std::string &str, bool music = false) { - if(FSstrict == false) + bool found = false; + if(!FSstrict) { if(music) { - if(musicpath.has(str)) return true; - + found = musicpath.has(str); // Not found? Try with .mp3 - return musicpath.has(toMp3(str)); + if (!found) + { + found = musicpath.has(toMp3(str)); + } } else { - if(files.has(str)) return true; - return files.has(toMp3(str)); + found = files.has(str); + if (!found) + { + found = files.has(toMp3(str)); + } } } else { if(music) { - if(musicpathStrict.has(str)) return true; - + found = musicpathStrict.has(str); // Not found? Try with .mp3 - return musicpathStrict.has(toMp3(str)); + if (!found) + { + found = musicpathStrict.has(toMp3(str)); + } } else { - if(strict.has(str)) return true; - return strict.has(toMp3(str)); + found = strict.has(str); + if (!found) + { + found = strict.has(toMp3(str)); + } } } + + return found; } // Convert a Morrowind sound path (eg. Fx\funny.wav) to full path @@ -258,13 +274,13 @@ namespace MWSound } catch(...) { - cout << "Error loading " << file << ", skipping.\n"; + std::cout << "Error loading " << file << ", skipping.\n"; } } // Clears all the sub-elements of a given iterator, and then // removes it from 'sounds'. - void clearAll(PtrMap::iterator it) + void clearAll(PtrMap::iterator& it) { IDMap::iterator sit = it->second.begin(); @@ -362,9 +378,9 @@ namespace MWSound } } } - }; + }; /* SoundImpl */ - void SoundManager::streamMusicFull (const std::string& filename) + void SoundManager::streamMusicFull(const std::string& filename) { if(!mData) return; @@ -381,20 +397,24 @@ namespace MWSound } SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, - const ESMS::ESMStore &store, - boost::filesystem::path dataDir, - bool useSound, bool fsstrict, MWWorld::Environment& environment) - : mData(NULL), fsStrict (fsstrict), mEnvironment (environment) + const ESMS::ESMStore &store, const Files::PathContainer& dataDirs, + bool useSound, bool fsstrict, MWWorld::Environment& environment) + : mData(NULL) + , fsStrict(fsstrict) + , mEnvironment(environment) { - MP3Lookup(dataDir / "Music/Explore/"); - if(useSound) - mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict); + for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + MP3Lookup((*it) / "Music/Explore/"); + } + if(useSound) + { + mData = new SoundImpl(root, camera, store, dataDirs /* Sound */, dataDirs /* Music */, fsstrict); + } test.name = ""; total = 0; - - } SoundManager::~SoundManager() @@ -407,14 +427,12 @@ namespace MWSound { if(mData->hasFile(filename, true)) { - std::string fullpath = mData->convertPath(filename, true); - streamMusicFull(fullpath); + streamMusicFull(mData->convertPath(filename, true)); } } - - void SoundManager::MP3Lookup(boost::filesystem::path dir) -{ + void SoundManager::MP3Lookup(const boost::filesystem::path& dir) + { boost::filesystem::directory_iterator dir_iter(dir), dir_end; std::string mp3extension = ".mp3"; @@ -425,35 +443,30 @@ namespace MWSound files.push_back(*dir_iter); } } -} + } void SoundManager::startRandomTitle() -{ - std::vector::iterator fileIter; - - if(files.size() > 0) + { + if(!files.empty()) { - fileIter = files.begin(); - srand ( time(NULL) ); + Files::PathContainer::iterator fileIter = files.begin(); + srand( time(NULL) ); int r = rand() % files.size() + 1; //old random code - for(int i = 1; i < r; i++) - { - fileIter++; - } + std::advance(fileIter, r - 1); std::string music = fileIter->string(); + std::cout << "Playing " << music << "\n"; + try { - std::cout << "Playing " << music << "\n"; streamMusicFull(music); } - catch(std::exception &e) + catch (std::exception &e) { std::cout << " Music Error: " << e.what() << "\n"; } } -} - + } bool SoundManager::isMusicPlaying() { @@ -465,14 +478,12 @@ namespace MWSound return test; } - SoundManager::SoundImpl SoundManager::getMData() + SoundManager::SoundImpl SoundManager::getMData() { // bool test = mData->music->isPlaying(); return *mData; } - - void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) { // The range values are not tested @@ -480,7 +491,7 @@ namespace MWSound if(mData->hasFile(filename)) mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false); else - cout << "Sound file " << filename << " not found, skipping.\n"; + std::cout << "Sound file " << filename << " not found, skipping.\n"; } bool SoundManager::sayDone (MWWorld::Ptr ptr) const @@ -490,20 +501,20 @@ namespace MWSound } - void SoundManager::playSound (const std::string& soundId, float volume, float pitch) + void SoundManager::playSound(const std::string& soundId, float volume, float pitch) { if(!mData) return; // Play and forget float min, max; const std::string &file = mData->lookup(soundId, volume, min, max); - if(file != "") - { + if (file != "") + { SoundPtr snd = mData->mgr->load(file); snd->setVolume(volume); snd->setRange(min,max); snd->setPitch(pitch); snd->play(); - } + } } void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId, @@ -514,7 +525,7 @@ namespace MWSound // Look up the sound in the ESM data float min, max; const std::string &file = mData->lookup(soundId, volume, min, max); - if(file != "") + if (file != "") mData->add(file, ptr, soundId, volume, pitch, min, max, loop); } @@ -541,18 +552,19 @@ namespace MWSound void SoundManager::updateObject(MWWorld::Ptr ptr) { - if(!mData) return; - mData->updatePositions(ptr); + if (mData != NULL) + { + mData->updatePositions(ptr); + } } void SoundManager::update (float duration) { - std::string effect; - MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); //If the region has changed - if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){ + if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10) + { timer.restart(); if (test.name != current->cell->region) { @@ -564,11 +576,12 @@ namespace MWSound { std::vector::iterator soundIter = test.soundList.begin(); //mEnvironment.mSoundManager - if(total == 0){ - while (!(soundIter == test.soundList.end())) + if(total == 0) + { + while (soundIter != test.soundList.end()) { - ESM::NAME32 go = soundIter->sound; int chance = (int) soundIter->chance; + //ESM::NAME32 go = soundIter->sound; //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; soundIter++; total += chance; @@ -578,7 +591,7 @@ namespace MWSound int r = rand() % total; //old random code int pos = 0; soundIter = test.soundList.begin(); - while (!(soundIter == test.soundList.end())) + while (soundIter != test.soundList.end()) { const ESM::NAME32 go = soundIter->sound; int chance = (int) soundIter->chance; @@ -586,13 +599,11 @@ namespace MWSound soundIter++; if( r - pos < chance) { - effect = go.name; //play sound std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0); + mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0); break; - } pos += chance; } diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index 7dff16c76..5c3f473f2 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -2,14 +2,15 @@ #define GAME_SOUND_SOUNDMANAGER_H #include -#include #include +#include + #include "../mwworld/ptr.hpp" #include +#include -#include namespace Ogre { @@ -37,7 +38,7 @@ namespace MWSound struct SoundImpl; SoundImpl *mData; - std::vector files; + Files::PathContainer files; bool fsStrict; MWWorld::Environment& mEnvironment; @@ -52,7 +53,7 @@ namespace MWSound public: SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store, - boost::filesystem::path dataDir, bool useSound, bool fsstrict, + const Files::PathContainer& dataDir, bool useSound, bool fsstrict, MWWorld::Environment& environment); ~SoundManager(); @@ -61,7 +62,7 @@ namespace MWSound /// \param filename name of a sound file in "Music/" in the data directory. void startRandomTitle(); - void MP3Lookup(boost::filesystem::path dir); + void MP3Lookup(const boost::filesystem::path& dir); bool isMusicPlaying(); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7fcac6eb8..6bf7bacf4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -6,10 +6,6 @@ add_component_dir (bsa bsa_archive bsa_file ) -add_component_dir (cfg - configurationmanager - ) - add_component_dir (nif controlled effect nif_types record controller extra node record_ptr data nif_file property ) @@ -47,7 +43,7 @@ add_component_dir (misc ) add_component_dir (files - linuxpath windowspath macospath path multidircollection collections fileops + linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager ) add_component_dir (compiler diff --git a/components/cfg/configurationmanager.cpp b/components/cfg/configurationmanager.cpp deleted file mode 100644 index 0998debee..000000000 --- a/components/cfg/configurationmanager.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "configurationmanager.hpp" - -#include -#include -#include - -namespace Cfg -{ - -static const char* const openmwCfgFile = "openmw.cfg"; -static const char* const ogreCfgFile = "ogre.cfg"; -static const char* const pluginsCfgFile = "plugins.cfg"; - - -ConfigurationManager::ConfigurationManager() - : mPath("openmw") -{ - /** - * According to task #168 plugins.cfg file shall be located in global - * configuration path or in runtime configuration path. - */ - mPluginsCfgPath = mPath.getGlobalConfigPath() / pluginsCfgFile; - if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) - { - mPluginsCfgPath = mPath.getRuntimeConfigPath() / pluginsCfgFile; - if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) - { - std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl; - mPluginsCfgPath.clear(); - } - } - - /** - * According to task #168 ogre.cfg file shall be located only - * in user configuration path. - */ - mOgreCfgPath = mPath.getLocalConfigPath() / ogreCfgFile; - - mLogPath = mPath.getLocalConfigPath(); -} - -ConfigurationManager::~ConfigurationManager() -{ -} - -void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables, - boost::program_options::options_description& description) -{ - loadConfig(mPath.getLocalConfigPath(), variables, description); - boost::program_options::notify(variables); - loadConfig(mPath.getRuntimeConfigPath(), variables, description); - boost::program_options::notify(variables); - loadConfig(mPath.getGlobalConfigPath(), variables, description); - boost::program_options::notify(variables); -} - -void ConfigurationManager::loadConfig(const boost::filesystem::path& path, - boost::program_options::variables_map& variables, - boost::program_options::options_description& description) -{ - boost::filesystem::path cfgFile(path); - cfgFile /= std::string(openmwCfgFile); - if (boost::filesystem::is_regular_file(cfgFile)) - { - std::cout << "Loading config file: " << cfgFile.string() << "... "; - - std::ifstream configFileStream(cfgFile.string().c_str()); - if (configFileStream.is_open()) - { - boost::program_options::store(boost::program_options::parse_config_file( - configFileStream, description), variables); - - std::cout << "done." << std::endl; - } - else - { - std::cout << "failed." << std::endl; - } - } -} - -const boost::filesystem::path& ConfigurationManager::getGlobalConfigPath() const -{ - return mPath.getGlobalConfigPath(); -} - -void ConfigurationManager::setGlobalConfigPath(const boost::filesystem::path& newPath) -{ - mPath.setGlobalConfigPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getLocalConfigPath() const -{ - return mPath.getLocalConfigPath(); -} - -void ConfigurationManager::setLocalConfigPath(const boost::filesystem::path& newPath) -{ - mPath.setLocalConfigPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getRuntimeConfigPath() const -{ - return mPath.getRuntimeConfigPath(); -} - -void ConfigurationManager::setRuntimeConfigPath(const boost::filesystem::path& newPath) -{ - mPath.setRuntimeConfigPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const -{ - return mPath.getGlobalDataPath(); -} - -void ConfigurationManager::setGlobalDataPath(const boost::filesystem::path& newPath) -{ - mPath.setGlobalDataPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getLocalDataPath() const -{ - return mPath.getLocalDataPath(); -} - -void ConfigurationManager::setLocalDataPath(const boost::filesystem::path& newPath) -{ - mPath.setLocalDataPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getRuntimeDataPath() const -{ - return mPath.getRuntimeDataPath(); -} - -void ConfigurationManager::setRuntimeDataPath(const boost::filesystem::path& newPath) -{ - mPath.setRuntimeDataPath(newPath); -} - -const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const -{ - return mOgreCfgPath; -} - -const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const -{ - return mPluginsCfgPath; -} - -const boost::filesystem::path& ConfigurationManager::getLogPath() const -{ - return mLogPath; -} - -} /* namespace Cfg */ diff --git a/components/file_finder/file_finder.hpp b/components/file_finder/file_finder.hpp index 0e1e07226..8a15af73a 100644 --- a/components/file_finder/file_finder.hpp +++ b/components/file_finder/file_finder.hpp @@ -1,9 +1,11 @@ #ifndef FILE_FINDER_MAIN_H #define FILE_FINDER_MAIN_H +#include + #include "search.hpp" #include "filename_less.hpp" -#include +#include namespace FileFinder { @@ -11,7 +13,8 @@ namespace FileFinder template class FileFinderT { - std::map table; + typedef std::map TableContainer; + TableContainer table; struct Inserter : ReturnPath { @@ -35,12 +38,12 @@ public: // Remember the original path length, so we can cut it away from // the relative paths used as keys - std::string pstring = path.string(); + const std::string& pstring = path.string(); inserter.cut = pstring.size(); // If the path does not end in a slash, then boost will add one // later, which means one more character we have to remove. - char last = pstring[pstring.size()-1]; + char last = *pstring.rbegin(); if(last != '\\' && last != '/') inserter.cut++; @@ -56,12 +59,84 @@ public: // Find the full path from a relative path. const std::string &lookup(const std::string& file) const { - return table.find(file)->second; + static std::string empty; + typename TableContainer::const_iterator it = table.find(file); + return (it != table.end()) ? it->second : empty; } }; +template +< + class LESS +> +struct TreeFileFinder +{ + typedef TreeFileFinder finder_t; + + TreeFileFinder(const Files::PathContainer& paths, bool recurse = true) + { + struct : ReturnPath + { + finder_t *owner; + int cut; + + void add(const boost::filesystem::path &pth) + { + std::string file = pth.string(); + std::string key = file.substr(cut); + owner->mTable[key] = file; + } + } inserter; + + inserter.owner = this; + + for (Files::PathContainer::const_iterator it = paths.begin(); it != paths.end(); ++it) + { + + // Remember the original path length, so we can cut it away from + // the relative paths used as keys + const std::string& pstring = it->string(); + inserter.cut = pstring.size(); + + // If the path does not end in a slash, then boost will add one + // later, which means one more character we have to remove. + char last = *pstring.rbegin(); + if (last != '\\' && last != '/') + { + inserter.cut++; + } + + // Fill the map + find(*it, inserter, recurse); + } + } + + bool has(const std::string& file) const + { + return mTable.find(file) != mTable.end(); + } + + const std::string& lookup(const std::string& file) const + { + static std::string empty; + typename TableContainer::const_iterator it = mTable.find(file); + return (it != mTable.end()) ? it->second : empty; + } + + private: + typedef std::map TableContainer; + TableContainer mTable; + +// Inserter inserter; +}; + + // The default is to use path_less for equality checks typedef FileFinderT FileFinder; typedef FileFinderT FileFinderStrict; -} -#endif + +typedef TreeFileFinder LessTreeFileFinder; +typedef TreeFileFinder StrictTreeFileFinder; + +} /* namespace FileFinder */ +#endif /* FILE_FINDER_MAIN_H */ diff --git a/components/file_finder/search.cpp b/components/file_finder/search.cpp index b05b30e83..06deaf83a 100644 --- a/components/file_finder/search.cpp +++ b/components/file_finder/search.cpp @@ -2,27 +2,35 @@ #include -using namespace std; -using namespace boost::filesystem; - -void FileFinder::find(const path & dir_path, ReturnPath &ret, bool recurse) +void FileFinder::find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse) { - if ( !exists( dir_path ) ) - { - cout << "Path " << dir_path << " not found\n"; - return; - } - - directory_iterator end_itr; // default construction yields past-the-end - for ( directory_iterator itr(dir_path); - itr != end_itr; - ++itr ) + if (boost::filesystem::exists(dir_path)) { - if ( is_directory( *itr ) ) + if (!recurse) { - if(recurse) find(*itr, ret); + boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end + for (boost::filesystem::directory_iterator itr(dir_path); itr != end_itr; ++itr) + { + if (!boost::filesystem::is_directory( *itr )) + { + ret.add(*itr); + } + } } - else - ret.add(*itr); + else + { + boost::filesystem::recursive_directory_iterator end_itr; // default construction yields past-the-end + for (boost::filesystem::recursive_directory_iterator itr(dir_path); itr != end_itr; ++itr) + { + if (!boost::filesystem::is_directory(*itr)) + { + ret.add(*itr); + } + } + } + } + else + { + std::cout << "Path " << dir_path << " not found" << std::endl; } } diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp new file mode 100644 index 000000000..28d49a50c --- /dev/null +++ b/components/files/configurationmanager.cpp @@ -0,0 +1,194 @@ +#include "configurationmanager.hpp" + +#include +#include +#include +#include + +namespace Files +{ + +static const char* const openmwCfgFile = "openmw.cfg"; +static const char* const ogreCfgFile = "ogre.cfg"; +static const char* const pluginsCfgFile = "plugins.cfg"; + +const char* const mwToken = "?mw?"; +const char* const localToken = "?local?"; +const char* const userToken = "?user?"; +const char* const globalToken = "?global?"; + +ConfigurationManager::ConfigurationManager() + : mFixedPath("openmw") +{ + setupTokensMapping(); + + /** + * According to task #168 plugins.cfg file shall be located in global + * configuration path or in local configuration path. + */ + mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile; + if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) + { + mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile; + if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) + { + std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl; + mPluginsCfgPath.clear(); + } + } + + /** + * According to task #168 ogre.cfg file shall be located only + * in user configuration path. + */ + mOgreCfgPath = mFixedPath.getUserPath() / ogreCfgFile; + + /** + * FIXME: Logs shoudn't be stored in the same dir where configuration is placed. + */ + mLogPath = mFixedPath.getUserPath(); +} + +ConfigurationManager::~ConfigurationManager() +{ +} + +void ConfigurationManager::setupTokensMapping() +{ + mTokensMapping.insert(std::make_pair(mwToken, &FixedPath<>::getInstallPath)); + mTokensMapping.insert(std::make_pair(localToken, &FixedPath<>::getLocalDataPath)); + mTokensMapping.insert(std::make_pair(userToken, &FixedPath<>::getUserDataPath)); + mTokensMapping.insert(std::make_pair(globalToken, &FixedPath<>::getGlobalDataPath)); +} + +void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables, + boost::program_options::options_description& description) +{ + loadConfig(mFixedPath.getUserPath(), variables, description); + boost::program_options::notify(variables); + + loadConfig(mFixedPath.getLocalPath(), variables, description); + boost::program_options::notify(variables); + loadConfig(mFixedPath.getGlobalPath(), variables, description); + boost::program_options::notify(variables); + +} + +struct EmptyPath : public std::unary_function +{ + bool operator()(const boost::filesystem::path& path) const + { + return path.empty(); + } +}; + +void ConfigurationManager::processPaths(Files::PathContainer& dataDirs) +{ + for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) + { + const std::string& path = it->string(); + + // Check if path contains a token + if (!path.empty() && *path.begin() == '?' && *path.rbegin() == '?') + { + TokensMappingContainer::iterator tokenIt = mTokensMapping.find(path); + if (tokenIt != mTokensMapping.end()) + { + boost::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))()); + + if (boost::filesystem::is_directory(tempPath)) + { + (*it) = tempPath; + } + else + { + (*it).clear(); + } + } + else + { + // Clean invalid / unknown token, it will be removed outside the loop + (*it).clear(); + } + } + } + + dataDirs.erase(std::remove_if(dataDirs.begin(), dataDirs.end(), EmptyPath()), dataDirs.end()); +} + +void ConfigurationManager::loadConfig(const boost::filesystem::path& path, + boost::program_options::variables_map& variables, + boost::program_options::options_description& description) +{ + boost::filesystem::path cfgFile(path); + cfgFile /= std::string(openmwCfgFile); + if (boost::filesystem::is_regular_file(cfgFile)) + { + std::cout << "Loading config file: " << cfgFile.string() << "... "; + + std::ifstream configFileStream(cfgFile.string().c_str()); + if (configFileStream.is_open()) + { + boost::program_options::store(boost::program_options::parse_config_file( + configFileStream, description), variables); + + std::cout << "done." << std::endl; + } + else + { + std::cout << "failed." << std::endl; + } + } +} + +const boost::filesystem::path& ConfigurationManager::getGlobalPath() const +{ + return mFixedPath.getGlobalPath(); +} + +const boost::filesystem::path& ConfigurationManager::getUserPath() const +{ + return mFixedPath.getUserPath(); +} + +const boost::filesystem::path& ConfigurationManager::getLocalPath() const +{ + return mFixedPath.getLocalPath(); +} + +const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const +{ + return mFixedPath.getGlobalDataPath(); +} + +const boost::filesystem::path& ConfigurationManager::getUserDataPath() const +{ + return mFixedPath.getUserDataPath(); +} + +const boost::filesystem::path& ConfigurationManager::getLocalDataPath() const +{ + return mFixedPath.getLocalDataPath(); +} + +const boost::filesystem::path& ConfigurationManager::getInstallPath() const +{ + return mFixedPath.getInstallPath(); +} + +const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const +{ + return mOgreCfgPath; +} + +const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const +{ + return mPluginsCfgPath; +} + +const boost::filesystem::path& ConfigurationManager::getLogPath() const +{ + return mLogPath; +} + +} /* namespace Cfg */ diff --git a/components/cfg/configurationmanager.hpp b/components/files/configurationmanager.hpp similarity index 50% rename from components/cfg/configurationmanager.hpp rename to components/files/configurationmanager.hpp index 7f13d0914..7d77df9c0 100644 --- a/components/cfg/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -1,15 +1,18 @@ -#ifndef COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP -#define COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP +#ifndef COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP +#define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP + +#include #include #include -#include +#include +#include /** - * \namespace Cfg + * \namespace Files */ -namespace Cfg +namespace Files { /** @@ -22,41 +25,43 @@ struct ConfigurationManager void readConfiguration(boost::program_options::variables_map& variables, boost::program_options::options_description& description); + void processPaths(Files::PathContainer& dataDirs); - const boost::filesystem::path& getGlobalConfigPath() const; - void setGlobalConfigPath(const boost::filesystem::path& newPath); - - const boost::filesystem::path& getLocalConfigPath() const; - void setLocalConfigPath(const boost::filesystem::path& newPath); - - const boost::filesystem::path& getRuntimeConfigPath() const; - void setRuntimeConfigPath(const boost::filesystem::path& newPath); + /**< Fixed paths */ + const boost::filesystem::path& getGlobalPath() const; + const boost::filesystem::path& getUserPath() const; + const boost::filesystem::path& getLocalPath() const; const boost::filesystem::path& getGlobalDataPath() const; - void setGlobalDataPath(const boost::filesystem::path& newPath); - + const boost::filesystem::path& getUserDataPath() const; const boost::filesystem::path& getLocalDataPath() const; - void setLocalDataPath(const boost::filesystem::path& newPath); - - const boost::filesystem::path& getRuntimeDataPath() const; - void setRuntimeDataPath(const boost::filesystem::path& newPath); + const boost::filesystem::path& getInstallPath() const; const boost::filesystem::path& getOgreConfigPath() const; const boost::filesystem::path& getPluginsConfigPath() const; const boost::filesystem::path& getLogPath() const; private: + typedef Files::FixedPath<> FixedPathType; + + typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; + typedef std::tr1::unordered_map TokensMappingContainer; + void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, boost::program_options::options_description& description); - Files::Path<> mPath; + void setupTokensMapping(); + + FixedPathType mFixedPath; boost::filesystem::path mOgreCfgPath; boost::filesystem::path mPluginsCfgPath; boost::filesystem::path mLogPath; + + TokensMappingContainer mTokensMapping; }; } /* namespace Cfg */ -#endif /* COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP */ +#endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ diff --git a/components/files/fixedpath.hpp b/components/files/fixedpath.hpp new file mode 100644 index 000000000..1bf582ab9 --- /dev/null +++ b/components/files/fixedpath.hpp @@ -0,0 +1,162 @@ +/** + * Open Morrowind - an opensource Elder Scrolls III: Morrowind + * engine implementation. + * + * Copyright (C) 2011 Open Morrowind Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file components/files/fixedpath.hpp */ + +#ifndef COMPONENTS_FILES_FIXEDPATH_HPP +#define COMPONENTS_FILES_FIXEDPATH_HPP + +#include +#include + +#if defined(__linux__) || defined(__FreeBSD__) + #include + namespace Files { typedef LinuxPath TargetPathType; } + +#elif defined(__WIN32) || defined(__WINDOWS__) + #include + namespace Files { typedef WindowsPath TargetPathType; } + +#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) + #include + namespace Files { typedef MacOsPath TargetPathType; } + +#else + #error "Unknown platform!" +#endif + + +/** + * \namespace Files + */ +namespace Files +{ + +/** + * \struct Path + * + * \tparam P - Path strategy class type (depends on target system) + * + */ +template +< + class P = TargetPathType +> +struct FixedPath +{ + typedef P PathType; + + /** + * \brief Path constructor. + * + * \param [in] application_name - Name of the application + */ + FixedPath(const std::string& application_name) + : mPath() + , mUserPath(mPath.getUserPath()) + , mGlobalPath(mPath.getGlobalPath()) + , mLocalPath(mPath.getLocalPath()) + , mUserDataPath(mPath.getUserDataPath()) + , mGlobalDataPath(mPath.getGlobalDataPath()) + , mLocalDataPath(mPath.getLocalDataPath()) + , mInstallPath(mPath.getInstallPath()) + { + if (!application_name.empty()) + { + boost::filesystem::path suffix(application_name + std::string("/")); + + mUserPath /= suffix; + mGlobalPath /= suffix; + + mLocalDataPath /= suffix; + mGlobalDataPath /= suffix; + } + } + + /** + * \brief Return path pointing to the user local configuration directory. + * + * \return boost::filesystem::path + */ + const boost::filesystem::path& getUserPath() const + { + return mUserPath; + } + + /** + * \brief Return path pointing to the global (system) configuration directory. + * + * \return boost::filesystem::path + */ + const boost::filesystem::path& getGlobalPath() const + { + return mGlobalPath; + } + + /** + * \brief Return path pointing to the directory where application was started. + * + * \return boost::filesystem::path + */ + const boost::filesystem::path& getLocalPath() const + { + return mLocalPath; + } + + const boost::filesystem::path& getInstallPath() const + { + return mInstallPath; + } + + const boost::filesystem::path& getGlobalDataPath() const + { + return mGlobalDataPath; + } + + const boost::filesystem::path& getUserDataPath() const + { + return mUserDataPath; + } + + const boost::filesystem::path& getLocalDataPath() const + { + return mLocalDataPath; + } + + private: + PathType mPath; + + boost::filesystem::path mUserPath; /**< User path */ + boost::filesystem::path mGlobalPath; /**< Global path */ + boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */ + + boost::filesystem::path mUserDataPath; /**< User data path */ + boost::filesystem::path mGlobalDataPath; /**< Global application data path */ + boost::filesystem::path mLocalDataPath; /**< Local path to the configuration files. + By default it is a 'data' directory in same + directory where application was run */ + boost::filesystem::path mInstallPath; + +}; + + +} /* namespace Files */ + +#endif /* COMPONENTS_FILES_FIXEDPATH_HPP */ diff --git a/components/files/linuxpath.cpp b/components/files/linuxpath.cpp index c485002fd..41891661e 100644 --- a/components/files/linuxpath.cpp +++ b/components/files/linuxpath.cpp @@ -22,12 +22,13 @@ #include "linuxpath.hpp" -#if defined(__linux__) +#if defined(__linux__) || defined(__FreeBSD__) #include #include #include #include +#include /** * \namespace Files @@ -35,9 +36,9 @@ namespace Files { -boost::filesystem::path LinuxPath::getLocalConfigPath() const +boost::filesystem::path LinuxPath::getUserPath() const { - boost::filesystem::path localConfigPath("."); + boost::filesystem::path userPath("."); boost::filesystem::path suffix("/"); const char* theDir = getenv("OPENMW_CONFIG"); @@ -63,17 +64,17 @@ boost::filesystem::path LinuxPath::getLocalConfigPath() const } if (theDir != NULL) { - localConfigPath = boost::filesystem::path(theDir); + userPath = boost::filesystem::path(theDir); } - localConfigPath /= suffix; + userPath /= suffix; - return localConfigPath; + return userPath; } -boost::filesystem::path LinuxPath::getGlobalConfigPath() const +boost::filesystem::path LinuxPath::getGlobalPath() const { - boost::filesystem::path globalConfigPath("/etc/xdg/"); + boost::filesystem::path globalPath("/etc/xdg/"); char* theDir = getenv("XDG_CONFIG_DIRS"); if (theDir != NULL) @@ -82,20 +83,20 @@ boost::filesystem::path LinuxPath::getGlobalConfigPath() const char* ptr = strtok(theDir, ":"); if (ptr != NULL) { - globalConfigPath = boost::filesystem::path(ptr); - globalConfigPath /= boost::filesystem::path("/"); + globalPath = boost::filesystem::path(ptr); + globalPath /= boost::filesystem::path("/"); } } - return globalConfigPath; + return globalPath; } -boost::filesystem::path LinuxPath::getRuntimeConfigPath() const +boost::filesystem::path LinuxPath::getLocalPath() const { return boost::filesystem::path("./"); } -boost::filesystem::path LinuxPath::getLocalDataPath() const +boost::filesystem::path LinuxPath::getUserDataPath() const { boost::filesystem::path localDataPath("."); boost::filesystem::path suffix("/"); @@ -149,12 +150,84 @@ boost::filesystem::path LinuxPath::getGlobalDataPath() const return globalDataPath; } -boost::filesystem::path LinuxPath::getRuntimeDataPath() const +boost::filesystem::path LinuxPath::getLocalDataPath() const { return boost::filesystem::path("./data/"); } +boost::filesystem::path LinuxPath::getInstallPath() const +{ + boost::filesystem::path installPath; + + char *homePath = getenv("HOME"); + if (homePath == NULL) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd != NULL) + { + homePath = pwd->pw_dir; + } + } + + if (homePath != NULL) + { + boost::filesystem::path wineDefaultRegistry(homePath); + wineDefaultRegistry /= ".wine/system.reg"; + + if (boost::filesystem::is_regular_file(wineDefaultRegistry)) + { + boost::filesystem::ifstream file(wineDefaultRegistry); + bool isRegEntry = false; + std::string line; + std::string mwpath; + + while (std::getline(file, line) && !line.empty()) + { + if (line[0] == '[') // we found an entry + { + isRegEntry = (line.find("Softworks\\Morrowind]") != std::string::npos); + } + else if (isRegEntry) + { + if (line[0] == '"') // empty line means new registry key + { + std::string key = line.substr(1, line.find('"', 1) - 1); + if (strcasecmp(key.c_str(), "Installed Path") == 0) + { + std::string::size_type valuePos = line.find('=') + 2; + mwpath = line.substr(valuePos, line.rfind('"') - valuePos); + + std::string::size_type pos = mwpath.find("\\"); + while (pos != std::string::npos) + { + mwpath.replace(pos, 2, "/"); + pos = mwpath.find("\\", pos + 1); + } + break; + } + } + } + } + + if (!mwpath.empty()) + { + // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks + mwpath[0] = tolower(mwpath[0]); + installPath /= homePath; + installPath /= ".wine/dosdevices/"; + installPath /= mwpath; + + if (!boost::filesystem::is_directory(installPath)) + { + installPath.clear(); + } + } + } + } + + return installPath; +} } /* namespace Files */ -#endif /* defined(__linux__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) */ diff --git a/components/files/linuxpath.hpp b/components/files/linuxpath.hpp index d6e717fc4..71f45ae32 100644 --- a/components/files/linuxpath.hpp +++ b/components/files/linuxpath.hpp @@ -23,7 +23,7 @@ #ifndef COMPONENTS_FILES_LINUXPATH_H #define COMPONENTS_FILES_LINUXPATH_H -#if defined(__linux__) +#if defined(__linux__) || defined(__FreeBSD__) #include @@ -39,18 +39,18 @@ namespace Files struct LinuxPath { /** - * \brief Return path to the local configuration directory. + * \brief Return path to the user directory. * * \return boost::filesystem::path */ - boost::filesystem::path getLocalConfigPath() const; + boost::filesystem::path getUserPath() const; /** * \brief Return path to the global (system) configuration directory. * * \return boost::filesystem::path */ - boost::filesystem::path getGlobalConfigPath() const; + boost::filesystem::path getGlobalPath() const; /** * \brief Return path to the runtime configuration directory which is the @@ -58,33 +58,39 @@ struct LinuxPath * * \return boost::filesystem::path */ - boost::filesystem::path getRuntimeConfigPath() const; + boost::filesystem::path getLocalPath() const; /** - * \brief Return path to the local data directory. + * \brief * * \return boost::filesystem::path */ - boost::filesystem::path getLocalDataPath() const; + boost::filesystem::path getUserDataPath() const; /** - * \brief Return path to the global (system) data directory. + * \brief * * \return boost::filesystem::path */ boost::filesystem::path getGlobalDataPath() const; /** - * \brief Return runtime data path which is a location where - * an application was started with 'data' suffix. + * \brief + * + * \return boost::filesystem::path + */ + boost::filesystem::path getLocalDataPath() const; + + /** + * \brief Gets the path of the installed Morrowind version if there is one. * * \return boost::filesystem::path */ - boost::filesystem::path getRuntimeDataPath() const; + boost::filesystem::path getInstallPath() const; }; } /* namespace Files */ -#endif /* defined(__linux__) */ +#endif /* defined(__linux__) || defined(__FreeBSD__) */ #endif /* COMPONENTS_FILES_LINUXPATH_H */ diff --git a/components/files/macospath.cpp b/components/files/macospath.cpp index 46e775030..789c87709 100644 --- a/components/files/macospath.cpp +++ b/components/files/macospath.cpp @@ -34,9 +34,9 @@ namespace Files { -boost::filesystem::path MacOsPath::getLocalConfigPath() const +boost::filesystem::path MacOsPath::getUserPath() const { - boost::filesystem::path localConfigPath("."); + boost::filesystem::path userPath("."); boost::filesystem::path suffix("/"); const char* theDir = getenv("HOME"); @@ -50,26 +50,26 @@ boost::filesystem::path MacOsPath::getLocalConfigPath() const } if (theDir != NULL) { - localConfigPath = boost::filesystem::path(theDir) / "Library/Preferences/"; + userPath = boost::filesystem::path(theDir) / "Library/Preferences/"; } - localConfigPath /= suffix; + userPath /= suffix; - return localConfigPath; + return userPath; } -boost::filesystem::path MacOsPath::getGlobalConfigPath() const +boost::filesystem::path MacOsPath::getGlobalPath() const { - boost::filesystem::path globalConfigPath("/Library/Preferences/"); - return globalConfigPath; + boost::filesystem::path globalPath("/Library/Preferences/"); + return globalPath; } -boost::filesystem::path MacOsPath::getRuntimeConfigPath() const +boost::filesystem::path MacOsPath::getLocalPath() const { return boost::filesystem::path("./"); } -boost::filesystem::path MacOsPath::getLocalDataPath() const +boost::filesystem::path MacOsPath::getUserDataPath() const { boost::filesystem::path localDataPath("."); boost::filesystem::path suffix("/"); @@ -107,11 +107,87 @@ boost::filesystem::path MacOsPath::getGlobalDataPath() const return globalDataPath; } -boost::filesystem::path MacOsPath::getRuntimeDataPath() const +boost::filesystem::path MacOsPath::getLocalDataPath() const { return boost::filesystem::path("./data/"); } +/** + * FIXME: This should be verified on MacOS system! + */ +boost::filesystem::path MacOsPath::getInstallPath() const +{ + boost::filesystem::path installPath; + + char *homePath = getenv("HOME"); + if (homePath == NULL) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd != NULL) + { + homePath = pwd->pw_dir; + } + } + + if (homePath != NULL) + { + boost::filesystem::path wineDefaultRegistry(homePath); + wineDefaultRegistry /= ".wine/system.reg"; + + if (boost::filesystem::is_regular_file(wineDefaultRegistry)) + { + boost::filesystem::ifstream file(wineDefaultRegistry); + bool isRegEntry = false; + std::string line; + std::string mwpath; + + while (std::getline(file, line) && !line.empty()) + { + if (line[0] == '[') // we found an entry + { + isRegEntry = (line.find("Softworks\\Morrowind]") != std::string::npos); + } + else if (isRegEntry) + { + if (line[0] == '"') // empty line means new registry key + { + std::string key = line.substr(1, line.find('"', 1) - 1); + if (strcasecmp(key.c_str(), "Installed Path") == 0) + { + std::string::size_type valuePos = line.find('=') + 2; + mwpath = line.substr(valuePos, line.rfind('"') - valuePos); + + std::string::size_type pos = mwpath.find("\\"); + while (pos != std::string::npos) + { + mwpath.replace(pos, 2, "/"); + pos = mwpath.find("\\", pos + 1); + } + break; + } + } + } + } + + if (!mwpath.empty()) + { + // Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks + mwpath[0] = tolower(mwpath[0]); + installPath /= homePath; + installPath /= ".wine/dosdevices/"; + installPath /= mwpath; + + if (!boost::filesystem::is_directory(installPath)) + { + installPath.clear(); + } + } + } + } + + return installPath; +} + } /* namespace Files */ diff --git a/components/files/macospath.hpp b/components/files/macospath.hpp index 26f2c907f..2194dbb94 100644 --- a/components/files/macospath.hpp +++ b/components/files/macospath.hpp @@ -43,14 +43,14 @@ struct MacOsPath * * \return boost::filesystem::path */ - boost::filesystem::path getLocalConfigPath() const; + boost::filesystem::path getUserPath() const; /** * \brief Return path to the global (system) configuration directory. * * \return boost::filesystem::path */ - boost::filesystem::path getGlobalConfigPath() const; + boost::filesystem::path getGlobalPath() const; /** * \brief Return path to the runtime configuration directory which is the @@ -58,29 +58,9 @@ struct MacOsPath * * \return boost::filesystem::path */ - boost::filesystem::path getRuntimeConfigPath() const; + boost::filesystem::path getLocalPath() const; - /** - * \brief Return path to the local data directory. - * - * \return boost::filesystem::path - */ - boost::filesystem::path getLocalDataPath() const; - - /** - * \brief Return path to the global (system) data directory. - * - * \return boost::filesystem::path - */ - boost::filesystem::path getGlobalDataPath() const; - - /** - * \brief Return runtime data path which is a location where - * an application was started with 'data' suffix. - * - * \return boost::filesystem::path - */ - boost::filesystem::path getRuntimeDataPath() const; + boost::filesystem::path getInstallPath() const; }; } /* namespace Files */ diff --git a/components/files/multidircollection.hpp b/components/files/multidircollection.hpp index 391f8b6a4..e8abeb45d 100644 --- a/components/files/multidircollection.hpp +++ b/components/files/multidircollection.hpp @@ -68,7 +68,7 @@ namespace Files /// \param foldCase Ignore filename case boost::filesystem::path getPath (const std::string& file) const; - ///< Return full path (including filename) of \æ file. + ///< Return full path (including filename) of \a file. /// /// If the file does not exist, an exception is thrown. \a file must include /// the extension. diff --git a/components/files/path.hpp b/components/files/path.hpp deleted file mode 100644 index 23c702bbb..000000000 --- a/components/files/path.hpp +++ /dev/null @@ -1,232 +0,0 @@ -/** - * Open Morrowind - an opensource Elder Scrolls III: Morrowind - * engine implementation. - * - * Copyright (C) 2011 Open Morrowind Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** \file components/files/path.hpp */ - -#ifndef COMPONENTS_FILES_PATH_HPP -#define COMPONENTS_FILES_PATH_HPP - -#include -#include - -#if defined(__linux__) - #include - namespace Files { typedef LinuxPath TargetPathType; } - -#elif defined(__WIN32) || defined(__WINDOWS__) || defined (_WINDOWS) - #include - namespace Files { typedef WindowsPath TargetPathType; } - -#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__) - #include - namespace Files { typedef MacOsPath TargetPathType; } - -#else - #error "Unknown platform!" -#endif - - -/** - * \namespace Files - */ -namespace Files -{ - -/** - * \struct Path - * - * \tparam P - Path strategy class type (depends on target system) - * - */ -template -< - class P = TargetPathType -> -struct Path -{ - typedef P PathType; - - /** - * \brief Path constructor. - * - * \param [in] application_name - Name of the application - */ - Path(const std::string& application_name) - : mPath() - , mLocalConfigPath(mPath.getLocalConfigPath()) - , mGlobalConfigPath(mPath.getGlobalConfigPath()) - , mRuntimeConfigPath(mPath.getRuntimeConfigPath()) - , mLocalDataPath(mPath.getLocalDataPath()) - , mGlobalDataPath(mPath.getGlobalDataPath()) - , mRuntimeDataPath(mPath.getRuntimeDataPath()) - { - if (!application_name.empty()) - { - boost::filesystem::path suffix(application_name + std::string("/")); - - mLocalConfigPath /= suffix; - mGlobalConfigPath /= suffix; - - mLocalDataPath /= suffix; - mGlobalDataPath /= suffix; - } - } - - /** - * \brief Return path pointing to the user local configuration directory. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getLocalConfigPath() const - { - return mLocalConfigPath; - } - - /** - * \brief Sets new local configuration path. - * - * \param [in] path - New path - */ - void setLocalConfigPath(const boost::filesystem::path& path) - { - mLocalConfigPath = path; - } - - /** - * \brief Return path pointing to the global (system) configuration directory. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getGlobalConfigPath() const - { - return mGlobalConfigPath; - } - - /** - * \brief Sets new global configuration path. - * - * \param [in] path - New path - */ - void setGlobalConfigPath(const boost::filesystem::path& path) - { - mGlobalConfigPath = path; - } - - /** - * \brief Return path pointing to the directory where application was started. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getRuntimeConfigPath() const - { - return mRuntimeConfigPath; - } - - /** - * \brief Sets new runtime configuration path. - * - * \param [in] path - New path - */ - void setRuntimeConfigPath(const boost::filesystem::path& path) - { - mRuntimeConfigPath = path; - } - - /** - * \brief Return path pointing to the user local data directory. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getLocalDataPath() const - { - return mLocalDataPath; - } - - /** - * \brief Sets new local data path. - * - * \param [in] path - New path - */ - void setLocalDataPath(const boost::filesystem::path& path) - { - mLocalDataPath = path; - } - - /** - * \brief Return path pointing to the global (system) data directory. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getGlobalDataPath() const - { - return mGlobalDataPath; - } - - /** - * \brief Sets new global (system) data directory. - * - * \param [in] path - New path - */ - void setGlobalDataPath(const boost::filesystem::path& path) - { - mGlobalDataPath = path; - } - - /** - * \brief Return path pointing to the directory where application was started. - * - * \return boost::filesystem::path - */ - const boost::filesystem::path& getRuntimeDataPath() const - { - return mRuntimeDataPath; - } - - /** - * \brief Sets new runtime data directory. - * - * \param [in] path - New path - */ - void setRuntimeDataPath(const boost::filesystem::path& path) - { - mRuntimeDataPath = path; - } - - private: - PathType mPath; - - boost::filesystem::path mLocalConfigPath; /**< User local path to the configuration files */ - boost::filesystem::path mGlobalConfigPath; /**< Global path to the configuration files */ - boost::filesystem::path mRuntimeConfigPath; /**< Runtime path to the configuration files. - By default it is the same directory where - application was run */ - - boost::filesystem::path mLocalDataPath; /**< User local application data path (user plugins / mods / etc.) */ - boost::filesystem::path mGlobalDataPath; /**< Global application data path */ - boost::filesystem::path mRuntimeDataPath; /**< Runtime path to the configuration files. - By default it is a 'data' directory in same - directory where application was run */ - -}; - - -} /* namespace Files */ - -#endif /* COMPONENTS_FILES_PATH_HPP */ diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index b971cbbbf..9bb66a3cb 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -13,9 +13,9 @@ namespace Files { -boost::filesystem::path WindowsPath::getLocalConfigPath() const +boost::filesystem::path WindowsPath::getUserPath() const { - boost::filesystem::path localConfigPath("."); + boost::filesystem::path userPath("."); boost::filesystem::path suffix("/"); TCHAR path[MAX_PATH]; @@ -24,17 +24,17 @@ boost::filesystem::path WindowsPath::getLocalConfigPath() const if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) { PathAppend(path, TEXT("My Games")); - localConfigPath = boost::filesystem::path(path); + userPath = boost::filesystem::path(path); } - localConfigPath /= suffix; + userPath /= suffix; - return localConfigPath; + return userPath; } -boost::filesystem::path WindowsPath::getGlobalConfigPath() const +boost::filesystem::path WindowsPath::getGlobalPath() const { - boost::filesystem::path globalConfigPath("."); + boost::filesystem::path globalPath("."); boost::filesystem::path suffix("/"); TCHAR path[MAX_PATH]; @@ -42,34 +42,75 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, NULL, 0, path))) { - globalConfigPath = boost::filesystem::path(path); + globalPath = boost::filesystem::path(path); } - globalConfigPath /= suffix; + globalPath /= suffix; - return globalConfigPath; + return globalPath; } -boost::filesystem::path WindowsPath::getRuntimeConfigPath() const +boost::filesystem::path WindowsPath::getLocalPath() const { return boost::filesystem::path("./"); } -boost::filesystem::path WindowsPath::getLocalDataPath() const +/** + * FIXME: Someone with Windows system should check this and correct if necessary + */ +boost::filesystem::path WindowsPath::getUserDataPath() const { - return getLocalConfigPath(); + return getUserConfigPath(); } +/** + * FIXME: Someone with Windows system should check this and correct if necessary + */ boost::filesystem::path WindowsPath::getGlobalDataPath() const { return getGlobalConfigPath(); } -boost::filesystem::path WindowsPath::getRuntimeDataPath() const +/** + * FIXME: Someone with Windows system should check this and correct if necessary + */ +boost::filesystem::path WindowsPath::getLocalDataPath() const { return boost::filesystem::path("./data/"); } +boost::filesystem::path WindowsPath::getInstallPath() const +{ + boost::filesystem::path installPath(""); + + HKEY hKey; + + BOOL f64 = FALSE; + LPCTSTR regkey; + if (IsWow64Process(GetCurrentProcess(), &f64) && f64) + { + regkey = "SOFTWARE\\Wow6432Node\\Bethesda Softworks\\Morrowind"; + } + else + { + regkey = "SOFTWARE\\Bethesda Softworks\\Morrowind"; + } + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(regkey), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) + { + //Key existed, let's try to read the install dir + std::vector buf(512); + int len = 512; + + if (RegQueryValueEx(hKey, TEXT("Installed Path"), NULL, NULL, (LPBYTE)&buf[0], (LPDWORD)&len) == ERROR_SUCCESS) + { + installPath = &buf[0]; + } + } + + return installPath; +} + } /* namespace Files */ #endif /* defined(_WIN32) || defined(__WINDOWS__) */ diff --git a/components/files/windowspath.hpp b/components/files/windowspath.hpp index 47dfc08d8..0240de257 100644 --- a/components/files/windowspath.hpp +++ b/components/files/windowspath.hpp @@ -43,29 +43,29 @@ struct WindowsPath * * \return boost::filesystem::path */ - boost::filesystem::path getLocalConfigPath() const; + boost::filesystem::path getUserPath() const; /** * \brief Returns "X:\Program Files\" * * \return boost::filesystem::path */ - boost::filesystem::path getGlobalConfigPath() const; + boost::filesystem::path getGlobalPath() const; /** - * \brief Return runtime configuration path which is a location where + * \brief Return local path which is a location where * an application was started * * \return boost::filesystem::path */ - boost::filesystem::path getRuntimeConfigPath() const; + boost::filesystem::path getLocalPath() const; /** - * \brief Return same path like getLocalConfigPath + * \brief Return same path like getUserConfigPath * * \return boost::filesystem::path */ - boost::filesystem::path getLocalDataPath() const; + boost::filesystem::path getUserDataPath() const; /** * \brief Return same path like getGlobalConfigPath @@ -80,7 +80,14 @@ struct WindowsPath * * \return boost::filesystem::path */ - boost::filesystem::path getRuntimeDataPath() const; + boost::filesystem::path getLocalDataPath() const; + + /** + * \brief Gets the path of the installed Morrowind version if there is one. + * + * \return boost::filesystem::path + */ + boost::filesystem::path getInstallPath() const; }; } /* namespace Files */