forked from mirror/openmw-tes3mp
fleshed out BSAArchive and DirArchive.
Implemented both lists & finds, with pattern matching. Conflicts: components/bsa/bsa_archive.cpp
This commit is contained in:
parent
6567bf38f8
commit
44031ec3d7
2 changed files with 160 additions and 101 deletions
|
@ -164,9 +164,6 @@ void OMW::Engine::loadBSA()
|
||||||
dataDirectory = iter->string();
|
dataDirectory = iter->string();
|
||||||
std::cout << "Data dir " << dataDirectory << std::endl;
|
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||||
Bsa::addDir(dataDirectory, mFSStrict);
|
Bsa::addDir(dataDirectory, mFSStrict);
|
||||||
|
|
||||||
// Workaround until resource listing capabilities are added to DirArchive, we need those to list available splash screens
|
|
||||||
addResourcesDirectory (dataDirectory);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,28 +37,142 @@ namespace
|
||||||
using namespace Ogre;
|
using namespace Ogre;
|
||||||
using namespace Bsa;
|
using namespace Bsa;
|
||||||
|
|
||||||
struct ciLessBoost : std::binary_function<std::string, std::string, bool>
|
struct PathPatternMatcher
|
||||||
|
{
|
||||||
|
PathPatternMatcher (char const * pattern) : pattern (pattern)
|
||||||
{
|
{
|
||||||
bool operator() (const std::string & s1, const std::string & s2) const {
|
|
||||||
//case insensitive version of is_less
|
|
||||||
return boost::ilexicographical_compare(s1, s2);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
struct pathComparer
|
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:
|
private:
|
||||||
std::string find;
|
char const * pattern;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
struct FileNameGatherer
|
||||||
pathComparer(const std::string& toFind) : find(toFind) { }
|
|
||||||
|
|
||||||
bool operator() (const std::string& other)
|
|
||||||
{
|
{
|
||||||
return boost::iequals(find, other);
|
StringVectorPtr ptr;
|
||||||
|
|
||||||
|
FileNameGatherer (StringVectorPtr ptr) : ptr (ptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator () (std::string const & filename) const
|
||||||
|
{
|
||||||
|
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 *> (archive);
|
||||||
|
fi.path = filename.substr (0, pt);
|
||||||
|
fi.filename = filename.substr (pt);
|
||||||
|
fi.compressedSize = fi.uncompressedSize = 0;
|
||||||
|
|
||||||
|
ptr->push_back(fi);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename file_iterator, typename filename_extractor, typename match_handler>
|
||||||
|
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;
|
static bool fsstrict = false;
|
||||||
|
|
||||||
/// An OGRE Archive wrapping a BSAFile archive
|
/// An OGRE Archive wrapping a BSAFile archive
|
||||||
|
@ -94,6 +208,11 @@ class DirArchive: public Ogre::Archive
|
||||||
return mIndex.find (normalized);
|
return mIndex.find (normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char const * extractFilename (index::value_type const & entry)
|
||||||
|
{
|
||||||
|
return entry.first.c_str ();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DirArchive(const String& name)
|
DirArchive(const String& name)
|
||||||
|
@ -143,27 +262,20 @@ public:
|
||||||
|
|
||||||
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
||||||
{
|
{
|
||||||
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
return find ("*", recursive, dirs);
|
||||||
std::cout << "DirArchive<" << getName () << ">::list" << std::endl;
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
|
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
|
||||||
{
|
{
|
||||||
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
return findFileInfo ("*", recursive, dirs);
|
||||||
std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl;
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringVectorPtr find(const String& pattern, bool recursive = true,
|
StringVectorPtr find(const String& pattern, bool recursive = true,
|
||||||
bool dirs = false)
|
bool dirs = false)
|
||||||
{
|
{
|
||||||
|
std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ());
|
||||||
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
||||||
|
matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, FileNameGatherer (ptr));
|
||||||
if (pattern == "*")
|
|
||||||
for (index::const_iterator i = mIndex.begin (); i != mIndex.end (); ++i)
|
|
||||||
ptr->push_back (i->first);
|
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,21 +290,20 @@ public:
|
||||||
bool dirs = false) const
|
bool dirs = false) const
|
||||||
{
|
{
|
||||||
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
||||||
|
FileInfoGatherer gatherer (this, ptr);
|
||||||
|
|
||||||
index::const_iterator i = lookup_filename (pattern);
|
std::string normalizedPattern = normalize_path (pattern.begin (), pattern.end ());
|
||||||
|
|
||||||
|
index::const_iterator i = mIndex.find (normalizedPattern);
|
||||||
|
|
||||||
if (i != mIndex.end ())
|
if (i != mIndex.end ())
|
||||||
{
|
{
|
||||||
FileInfo fi;
|
gatherer (i->first);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
std::size_t npos = i->first.rfind ('/');
|
matchFiles (recursive, normalizedPattern, mIndex.begin (), mIndex.end (), extractFilename, gatherer);
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
ptr->push_back(fi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
|
@ -203,6 +314,11 @@ class BSAArchive : public Archive
|
||||||
{
|
{
|
||||||
BSAFile arc;
|
BSAFile arc;
|
||||||
|
|
||||||
|
static char const * extractFilename (BSAFile::FileStruct const & entry)
|
||||||
|
{
|
||||||
|
return entry.name;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BSAArchive(const String& name)
|
BSAArchive(const String& name)
|
||||||
: Archive(name, "BSA")
|
: Archive(name, "BSA")
|
||||||
|
@ -230,26 +346,18 @@ public:
|
||||||
return arc.exists(filename.c_str());
|
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; }
|
time_t getModifiedTime(const String&) { return 0; }
|
||||||
|
|
||||||
// This is never called as far as I can see.
|
// This is never called as far as I can see.
|
||||||
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
||||||
{
|
{
|
||||||
//std::cout << "list(" << recursive << ", " << dirs << ")\n";
|
return find ("*", recursive, dirs);
|
||||||
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also never called.
|
// Also never called.
|
||||||
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
|
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
|
||||||
{
|
{
|
||||||
//std::cout << "listFileInfo(" << recursive << ", " << dirs << ")\n";
|
return findFileInfo ("*", recursive, dirs);
|
||||||
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// After load() is called, find("*") is called once. It doesn't seem
|
// After load() is called, find("*") is called once. It doesn't seem
|
||||||
|
@ -258,16 +366,8 @@ public:
|
||||||
StringVectorPtr find(const String& pattern, bool recursive = true,
|
StringVectorPtr find(const String& pattern, bool recursive = true,
|
||||||
bool dirs = false)
|
bool dirs = false)
|
||||||
{
|
{
|
||||||
//std::cout << "find(" << pattern << ", " << recursive
|
|
||||||
// << ", " << dirs << ")\n";
|
|
||||||
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
||||||
|
matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileNameGatherer (ptr));
|
||||||
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;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,45 +383,7 @@ public:
|
||||||
bool dirs = false) const
|
bool dirs = false) const
|
||||||
{
|
{
|
||||||
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
||||||
|
matchFiles (recursive, pattern, arc.getList ().begin (), arc.getList ().end (), extractFilename, FileInfoGatherer (this, ptr));
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue