mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 20:53:50 +00:00
reworked DirArchive to improve performance
Replaced old file index with a simple map. The map works by storing the file's relative path with path seperators normalized, and in lower case if not in strict mode. Incoming searches are normalized in the same way then the name is searched in the map. The value in the map is the original full path to the file which is then used to created a ConstrainedDataStream. In addition to changing the index, the commonly used Archive methods are implemented so that they don't fall back on the default FileSystemArchive implementations.
This commit is contained in:
parent
43cd88a24e
commit
67491f6c49
1 changed files with 112 additions and 100 deletions
|
@ -29,6 +29,8 @@
|
||||||
#include <OgreArchiveManager.h>
|
#include <OgreArchiveManager.h>
|
||||||
#include "bsa_file.hpp"
|
#include "bsa_file.hpp"
|
||||||
|
|
||||||
|
#include "../files/constrainedfiledatastream.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -60,104 +62,64 @@ public:
|
||||||
static bool fsstrict = false;
|
static bool fsstrict = false;
|
||||||
|
|
||||||
/// An OGRE Archive wrapping a BSAFile archive
|
/// An OGRE Archive wrapping a BSAFile archive
|
||||||
class DirArchive: public Ogre::FileSystemArchive
|
class DirArchive: public Ogre::Archive
|
||||||
{
|
{
|
||||||
boost::filesystem::path currentdir;
|
typedef std::map <std::string, std::string> index;
|
||||||
std::map<std::string, std::vector<std::string>, ciLessBoost> m;
|
|
||||||
unsigned int cutoff;
|
|
||||||
|
|
||||||
bool findFile(const String& filename, std::string& copy) const
|
index mIndex;
|
||||||
|
|
||||||
|
static char strict_normalize_char(char ch)
|
||||||
{
|
{
|
||||||
copy = filename;
|
return ch == '\\' ? '/' : ch;
|
||||||
std::replace(copy.begin(), copy.end(), '\\', '/');
|
|
||||||
|
|
||||||
if(copy.at(0) == '/')
|
|
||||||
copy.erase(0, 1);
|
|
||||||
|
|
||||||
if(fsstrict == true)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
std::string folder;
|
|
||||||
//int delimiter = 0;
|
|
||||||
size_t lastSlash = copy.rfind('/');
|
|
||||||
if (lastSlash != std::string::npos)
|
|
||||||
{
|
|
||||||
folder = copy.substr(0, lastSlash);
|
|
||||||
//delimiter = lastSlash+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> current;
|
|
||||||
{
|
|
||||||
std::map<std::string,std::vector<std::string>,ciLessBoost>::const_iterator found = m.find(folder);
|
|
||||||
|
|
||||||
if (found == m.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
current = found->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>::iterator find = std::lower_bound(current.begin(), current.end(), copy, ciLessBoost());
|
|
||||||
if (find != current.end() && !ciLessBoost()(copy, current.front()))
|
|
||||||
{
|
|
||||||
if (!boost::iequals(copy, *find))
|
|
||||||
if ((find = std::find_if(current.begin(), current.end(), pathComparer(copy))) == current.end()) //\todo Check if this line is actually needed
|
|
||||||
return false;
|
|
||||||
|
|
||||||
copy = *find;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
static char nonstrict_normalize_char(char ch)
|
||||||
|
{
|
||||||
|
return ch == '\\' ? '/' : std::tolower (ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string normalize_path (std::string::const_iterator begin, std::string::const_iterator end)
|
||||||
|
{
|
||||||
|
std::string normalized;
|
||||||
|
normalized.reserve (end-begin);
|
||||||
|
char (*normalize_char) (char) = fsstrict ? &strict_normalize_char : &nonstrict_normalize_char;
|
||||||
|
std::transform (begin, end, std::back_inserter (normalized), normalize_char);
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
index::const_iterator lookup_filename (std::string const & filename) const
|
||||||
|
{
|
||||||
|
std::string normalized = normalize_path (filename.begin (), filename.end ());
|
||||||
|
|
||||||
|
return mIndex.find (normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
DirArchive(const String& name)
|
DirArchive(const String& name)
|
||||||
: FileSystemArchive(name, "Dir"), currentdir (name)
|
: Archive(name, "Dir")
|
||||||
{
|
{
|
||||||
mType = "Dir";
|
typedef boost::filesystem::recursive_directory_iterator directory_iterator;
|
||||||
std::string s = name;
|
|
||||||
cutoff = s.size() + 1;
|
|
||||||
if(fsstrict == false)
|
|
||||||
populateMap(currentdir);
|
|
||||||
|
|
||||||
}
|
directory_iterator end;
|
||||||
void populateMap(boost::filesystem::path d){
|
|
||||||
//need to cut off first
|
size_t prefix = name.size ();
|
||||||
boost::filesystem::directory_iterator dir_iter(d), dir_end;
|
|
||||||
std::vector<std::string> filesind;
|
if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/')
|
||||||
for(;dir_iter != dir_end; dir_iter++)
|
++prefix;
|
||||||
{
|
|
||||||
if(boost::filesystem::is_directory(*dir_iter))
|
for (directory_iterator i (name); i != end; ++i)
|
||||||
populateMap(*dir_iter);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
std::string s = dir_iter->path().string();
|
if(boost::filesystem::is_directory (*i))
|
||||||
std::replace(s.begin(), s.end(), '\\', '/');
|
continue;
|
||||||
|
|
||||||
std::string small;
|
std::string proper = i->path ().string ();
|
||||||
if(cutoff < s.size())
|
|
||||||
small = s.substr(cutoff, s.size() - cutoff);
|
|
||||||
else
|
|
||||||
small = s.substr(cutoff - 1, s.size() - cutoff);
|
|
||||||
|
|
||||||
filesind.push_back(small);
|
std::string searchable = normalize_path (proper.begin () + prefix, proper.end ());
|
||||||
|
|
||||||
|
mIndex.insert (std::make_pair (std::move (searchable), std::move (proper)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(filesind.begin(), filesind.end(), ciLessBoost());
|
|
||||||
|
|
||||||
std::string small;
|
|
||||||
std::string original = d.string();
|
|
||||||
std::replace(original.begin(), original.end(), '\\', '/');
|
|
||||||
if(cutoff < original.size())
|
|
||||||
small = original.substr(cutoff, original.size() - cutoff);
|
|
||||||
else
|
|
||||||
small = original.substr(cutoff - 1, original.size() - cutoff);
|
|
||||||
|
|
||||||
m[small] = filesind;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCaseSensitive() const { return fsstrict; }
|
bool isCaseSensitive() const { return fsstrict; }
|
||||||
|
|
||||||
|
@ -165,26 +127,76 @@ class DirArchive: public Ogre::FileSystemArchive
|
||||||
void load() {}
|
void load() {}
|
||||||
void unload() {}
|
void unload() {}
|
||||||
|
|
||||||
bool exists(const String& filename) {
|
|
||||||
std::string copy;
|
|
||||||
|
|
||||||
if (findFile(filename, copy))
|
|
||||||
return FileSystemArchive::exists(copy);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataStreamPtr open(const String& filename, bool readonly = true) const
|
DataStreamPtr open(const String& filename, bool readonly = true) const
|
||||||
{
|
{
|
||||||
std::string copy;
|
index::const_iterator i = lookup_filename (filename);
|
||||||
|
|
||||||
if (findFile(filename, copy))
|
if (i == mIndex.end ())
|
||||||
return FileSystemArchive::open(copy, readonly);
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "The file '" << filename << "' could not be found.";
|
||||||
|
throw std::runtime_error (os.str ());
|
||||||
|
}
|
||||||
|
|
||||||
DataStreamPtr p;
|
return openConstrainedFileDataStream (i->second.c_str ());
|
||||||
return p;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
StringVectorPtr list(bool recursive = true, bool dirs = false)
|
||||||
|
{
|
||||||
|
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
||||||
|
std::cout << "DirArchive<" << getName () << ">::list" << std::endl;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
|
||||||
|
{
|
||||||
|
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
||||||
|
std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringVectorPtr find(const String& pattern, bool recursive = true,
|
||||||
|
bool dirs = false)
|
||||||
|
{
|
||||||
|
StringVectorPtr ptr = StringVectorPtr(new StringVector());
|
||||||
|
|
||||||
|
if (pattern == "*")
|
||||||
|
for (index::const_iterator i = mIndex.begin (); i != mIndex.end (); ++i)
|
||||||
|
ptr->push_back (i->first);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists(const String& filename)
|
||||||
|
{
|
||||||
|
return lookup_filename (filename) != mIndex.end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t getModifiedTime(const String&) { return 0; }
|
||||||
|
|
||||||
|
FileInfoListPtr findFileInfo(const String& pattern, bool recursive = true,
|
||||||
|
bool dirs = false) const
|
||||||
|
{
|
||||||
|
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
|
||||||
|
|
||||||
|
index::const_iterator i = lookup_filename (pattern);
|
||||||
|
|
||||||
|
if (i != mIndex.end ())
|
||||||
|
{
|
||||||
|
FileInfo fi;
|
||||||
|
|
||||||
|
std::size_t npos = i->first.rfind ('/');
|
||||||
|
|
||||||
|
fi.archive = this;
|
||||||
|
fi.filename = npos != -1 ? i->first.substr (npos) : i->first;
|
||||||
|
fi.path = npos != -1 ? i->first.substr (0, npos) : "";
|
||||||
|
fi.compressedSize = fi.uncompressedSize = 0;
|
||||||
|
|
||||||
|
ptr->push_back(fi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BSAArchive : public Archive
|
class BSAArchive : public Archive
|
||||||
|
|
Loading…
Reference in a new issue