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.
actorid
Nathan Jeffords 12 years ago
parent 43cd88a24e
commit 67491f6c49

@ -29,6 +29,8 @@
#include <OgreArchiveManager.h>
#include "bsa_file.hpp"
#include "../files/constrainedfiledatastream.hpp"
namespace
{
@ -60,104 +62,64 @@ public:
static bool fsstrict = false;
/// An OGRE Archive wrapping a BSAFile archive
class DirArchive: public Ogre::FileSystemArchive
class DirArchive: public Ogre::Archive
{
boost::filesystem::path currentdir;
std::map<std::string, std::vector<std::string>, ciLessBoost> m;
unsigned int cutoff;
bool findFile(const String& filename, std::string& copy) const
{
copy = filename;
std::replace(copy.begin(), copy.end(), '\\', '/');
if(copy.at(0) == '/')
copy.erase(0, 1);
typedef std::map <std::string, std::string> index;
if(fsstrict == true)
return true;
index mIndex;
std::string folder;
//int delimiter = 0;
size_t lastSlash = copy.rfind('/');
if (lastSlash != std::string::npos)
{
folder = copy.substr(0, lastSlash);
//delimiter = lastSlash+1;
}
static char strict_normalize_char(char ch)
{
return ch == '\\' ? '/' : ch;
}
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;
}
static char nonstrict_normalize_char(char ch)
{
return ch == '\\' ? '/' : std::tolower (ch);
}
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;
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;
}
copy = *find;
return true;
}
index::const_iterator lookup_filename (std::string const & filename) const
{
std::string normalized = normalize_path (filename.begin (), filename.end ());
return false;
return mIndex.find (normalized);
}
public:
public:
DirArchive(const String& name)
: FileSystemArchive(name, "Dir"), currentdir (name)
: Archive(name, "Dir")
{
mType = "Dir";
std::string s = name;
cutoff = s.size() + 1;
if(fsstrict == false)
populateMap(currentdir);
typedef boost::filesystem::recursive_directory_iterator directory_iterator;
}
void populateMap(boost::filesystem::path d){
//need to cut off first
boost::filesystem::directory_iterator dir_iter(d), dir_end;
std::vector<std::string> filesind;
for(;dir_iter != dir_end; dir_iter++)
{
if(boost::filesystem::is_directory(*dir_iter))
populateMap(*dir_iter);
else
directory_iterator end;
size_t prefix = name.size ();
if (name.size () > 0 && name [prefix - 1] != '\\' && name [prefix - 1] != '/')
++prefix;
for (directory_iterator i (name); i != end; ++i)
{
std::string s = dir_iter->path().string();
std::replace(s.begin(), s.end(), '\\', '/');
if(boost::filesystem::is_directory (*i))
continue;
std::string proper = i->path ().string ();
std::string small;
if(cutoff < s.size())
small = s.substr(cutoff, s.size() - cutoff);
else
small = s.substr(cutoff - 1, s.size() - cutoff);
std::string searchable = normalize_path (proper.begin () + prefix, proper.end ());
filesind.push_back(small);
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; }
@ -165,26 +127,76 @@ class DirArchive: public Ogre::FileSystemArchive
void load() {}
void unload() {}
bool exists(const String& filename) {
std::string copy;
DataStreamPtr open(const String& filename, bool readonly = true) const
{
index::const_iterator i = lookup_filename (filename);
if (findFile(filename, copy))
return FileSystemArchive::exists(copy);
if (i == mIndex.end ())
{
std::ostringstream os;
os << "The file '" << filename << "' could not be found.";
throw std::runtime_error (os.str ());
}
return false;
}
return openConstrainedFileDataStream (i->second.c_str ());
}
DataStreamPtr open(const String& filename, bool readonly = true) const
{
std::string copy;
StringVectorPtr list(bool recursive = true, bool dirs = false)
{
StringVectorPtr ptr = StringVectorPtr(new StringVector());
std::cout << "DirArchive<" << getName () << ">::list" << std::endl;
return ptr;
}
if (findFile(filename, copy))
return FileSystemArchive::open(copy, readonly);
FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false)
{
FileInfoListPtr ptr = FileInfoListPtr(new FileInfoList());
std::cout << "DirArchive<" << getName () << ">::listFileInfo" << std::endl;
return ptr;
}
DataStreamPtr p;
return p;
}
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

Loading…
Cancel
Save