diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d02e50f48..c5001a8946 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 0000000000..6d1c00ab1e --- /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 0000000000..9e23892af9 --- /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 0000000000..0543312e01 --- /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 0000000000..36270dfd10 --- /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