diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 8c288a2ee..b19cafab7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -164,9 +164,6 @@ void OMW::Engine::loadBSA() dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); - - // Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens - addResourcesDirectory (dataDirectory); } } diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index 011b81351..9913fb8aa 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -37,28 +37,142 @@ namespace using namespace Ogre; using namespace Bsa; -struct ciLessBoost : std::binary_function +struct PathPatternMatcher { - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return boost::ilexicographical_compare(s1, s2); + PathPatternMatcher (char const * pattern) : pattern (pattern) + { + } + + bool operator () (char const * input) + { + char const * p = pattern; + char const * i = input; + + while (*p && *i) + { + if (*p == '*') + { + ++p; + + while (*i && *i != *p && *i != '/' && *i != '\\') + ++i; + } + else + if (*p == '?') + { + if (*i == '/' || *i == '\\') + break; + + ++i, ++p; + } + if (*p == '/' || *p == '\\') + { + if (*i != '/' && *i != '\\') + break; + + ++i, ++p; + } + else + { + if (*i != *p) + break; + + ++i, ++p; + } + } + + return *p == 0 && *i == 0; } + +private: + char const * pattern; }; -struct pathComparer +struct FileNameGatherer { -private: - std::string find; + StringVectorPtr ptr; -public: - pathComparer(const std::string& toFind) : find(toFind) { } + FileNameGatherer (StringVectorPtr ptr) : ptr (ptr) + { + } - bool operator() (const std::string& other) + void operator () (std::string const & filename) const { - return boost::iequals(find, other); + ptr->push_back (filename); } }; +struct FileInfoGatherer +{ + Archive const * archive; + FileInfoListPtr ptr; + + FileInfoGatherer (Archive const * archive, FileInfoListPtr ptr) : + archive (archive), ptr (ptr) + { + } + + void operator () (std::string filename) const + { + FileInfo fi; + + std::size_t pt = filename.rfind ('/'); + if (pt == std::string::npos) + pt = 0; + + fi.archive = const_cast (archive); + fi.path = filename.substr (0, pt); + fi.filename = filename.substr (pt); + fi.compressedSize = fi.uncompressedSize = 0; + + ptr->push_back(fi); + } +}; + +template +void matchFiles (bool recursive, std::string const & pattern, file_iterator begin, file_iterator end, filename_extractor filenameExtractor, match_handler matchHandler) +{ + if (recursive && pattern == "*") + { + for (file_iterator i = begin; i != end; ++i) + matchHandler (filenameExtractor (*i)); + } + else + { + PathPatternMatcher matcher (pattern.c_str ()); + + if (recursive) + { + for (file_iterator i = begin; i != end; ++i) + { + char const * filename = filenameExtractor (*i); + char const * matchable_part = filename; + + for (char const * j = matchable_part; *j; ++j) + { + if (*j == '/' || *j == '\\') + matchable_part = j + 1; + } + + if (matcher (matchable_part)) + matchHandler (filename); + } + } + else + { + for (file_iterator i = begin; i != end; ++i) + { + char const * filename = filenameExtractor (*i); + + if (matcher (filename)) + matchHandler (filename); + } + } + } +} + + + static bool fsstrict = false; /// An OGRE Archive wrapping a BSAFile archive @@ -94,6 +208,11 @@ class DirArchive: public Ogre::Archive return mIndex.find (normalized); } + static char const * extractFilename (index::value_type const & entry) + { + return entry.first.c_str (); + } + public: DirArchive(const String& name) @@ -143,27 +262,20 @@ public: StringVectorPtr list(bool recursive = true, bool dirs = false) { - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - std::cout << "DirArchive<" << getName () << ">::list" << std::endl; - return ptr; + return find ("*", recursive, dirs); } FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl; - return ptr; + return findFileInfo ("*", recursive, dirs); } StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { + std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); StringVectorPtr ptr = StringVectorPtr(new StringVector()); - - if (pattern == "*") - for (index::const_iterator i = mIndex.begin (); i != mIndex.end (); ++i) - ptr->push_back (i->first); - + matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr)); return ptr; } @@ -178,21 +290,20 @@ public: bool dirs = false) const { FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); + FileInfoGatherer gatherer (this, ptr); + + std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ()); - index::const_iterator i = lookup_filename (pattern); + index::const_iterator i = mIndex.find (normalizedPattern); if (i != mIndex.end ()) { - FileInfo fi; - - std::size_t npos = i->first.rfind ('/'); - - fi.archive = this; - fi.filename = npos != std::string::npos ? i->first.substr (npos) : i->first; - fi.path = npos != std::string::npos ? i->first.substr (0, npos) : ""; - fi.compressedSize = fi.uncompressedSize = 0; + gatherer (i->first); + } + else + { - ptr->push_back(fi); + matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer); } return ptr; @@ -203,6 +314,11 @@ class BSAArchive : public Archive { BSAFile arc; + static char const * extractFilename (BSAFile::FileStruct const & entry) + { + return entry.name; + } + public: BSAArchive(const String& name) : Archive(name, "BSA") @@ -230,26 +346,18 @@ public: return arc.exists(filename.c_str()); } - bool cexists(const String& filename) const { - return arc.exists(filename.c_str()); - } - time_t getModifiedTime(const String&) { return 0; } // This is never called as far as I can see. StringVectorPtr list(bool recursive = true, bool dirs = false) { - //std::cout << "list(" << recursive << ", " << dirs << ")\n"; - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - return ptr; + return find ("*", recursive, dirs); } // Also never called. FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false) { - //std::cout << "listFileInfo(" << recursive << ", " << dirs << ")\n"; - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - return ptr; + return findFileInfo ("*", recursive, dirs); } // After load() is called, find("*") is called once. It doesn't seem @@ -258,17 +366,9 @@ public: StringVectorPtr find(const String& pattern, bool recursive = true, bool dirs = false) { - //std::cout << "find(" << pattern << ", " << recursive - // << ", " << dirs << ")\n"; - StringVectorPtr ptr = StringVectorPtr(new StringVector()); - - BSAFile::FileList const & files = arc.getList (); - - if (pattern == "*") - for (BSAFile::FileList::const_iterator i = files.begin (); i != files.end (); ++i) - ptr->push_back (i->name); - - return ptr; + StringVectorPtr ptr = StringVectorPtr(new StringVector()); + matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr)); + return ptr; } /* Gets called once for each of the ogre formats, *.program, @@ -281,47 +381,9 @@ public: */ FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, bool dirs = false) const - { - FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - // Check if the file exists (only works for single files - wild - // cards and recursive search isn't implemented.) - if(cexists(pattern)) - { - FileInfo fi; - fi.archive = this; - fi.filename = pattern; - // It apparently doesn't matter that we return bogus - // information - fi.path = ""; - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - - return ptr; - } - - FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true, - bool dirs = false) { FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList()); - - // Check if the file exists (only works for single files - wild - // cards and recursive search isn't implemented.) - if(cexists(pattern)) - { - FileInfo fi; - fi.archive = this; - fi.filename = pattern; - // It apparently doesn't matter that we return bogus - // information - fi.path = ""; - fi.compressedSize = fi.uncompressedSize = 0; - - ptr->push_back(fi); - } - + matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr)); return ptr; } };