2014-04-06 17:19:33 +00:00
|
|
|
#include "VFSDirInternal.h"
|
|
|
|
#include "VFSDirView.h"
|
|
|
|
#include "VFSInternal.h"
|
|
|
|
#include "VFSFile.h"
|
|
|
|
#include "VFSTools.h"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
VFS_NAMESPACE_START
|
|
|
|
|
|
|
|
|
|
|
|
// Internal class, not to be used outside
|
|
|
|
|
|
|
|
InternalDir::InternalDir(const char *fullpath)
|
|
|
|
: DirBase(fullpath)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
InternalDir::~InternalDir()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::_clearDirs()
|
|
|
|
{
|
|
|
|
_subdirs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::_clearMounts()
|
|
|
|
{
|
|
|
|
_mountedDirs.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
InternalDir *InternalDir::createNew(const char *dir) const
|
|
|
|
{
|
|
|
|
return new InternalDir(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::close()
|
|
|
|
{
|
|
|
|
for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it)
|
|
|
|
(*it)->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::_addMountDir(CountedPtr<DirBase> d)
|
|
|
|
{
|
2014-04-07 00:25:58 +00:00
|
|
|
if(d.content() == this)
|
|
|
|
return;
|
|
|
|
|
2014-04-06 17:19:33 +00:00
|
|
|
// move to end of vector if already mounted
|
|
|
|
for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it)
|
|
|
|
if(*it == d)
|
|
|
|
{
|
|
|
|
_mountedDirs.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_mountedDirs.push_back(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::_removeMountDir(DirBase *d)
|
|
|
|
{
|
|
|
|
for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it)
|
|
|
|
if(it->content() == d)
|
|
|
|
{
|
|
|
|
_mountedDirs.erase(it);
|
|
|
|
return; // pointers are unique
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
File *InternalDir::getFileByName(const char *fn, bool lazyLoad /* = true */)
|
|
|
|
{
|
|
|
|
if(_mountedDirs.size())
|
|
|
|
for(MountedDirs::reverse_iterator it = _mountedDirs.rbegin(); it != _mountedDirs.rend(); ++it)
|
|
|
|
if(File *f = (*it)->getFileByName(fn, lazyLoad))
|
|
|
|
return f;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DirBase *InternalDir::getDirByName(const char *dn, bool lazyLoad /* = true */, bool useSubtrees /* = true */)
|
|
|
|
{
|
|
|
|
DirBase *sub;
|
|
|
|
if((sub = DirBase::getDirByName(dn, lazyLoad)))
|
|
|
|
return sub;
|
|
|
|
|
|
|
|
if(useSubtrees)
|
|
|
|
for(MountedDirs::reverse_iterator it = _mountedDirs.rbegin(); it != _mountedDirs.rend(); ++it)
|
|
|
|
if((sub = (*it)->getDirByName(dn, lazyLoad)))
|
|
|
|
return sub;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _addFileCallback(File *f, void *p)
|
|
|
|
{
|
|
|
|
((Files*)p)->insert(std::make_pair(f->name(), f)); // only inserts if not exist
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::forEachFile(FileEnumCallback f, void *user /* = NULL */, bool /*ignored*/)
|
|
|
|
{
|
|
|
|
Files flist; // TODO: optimize allocation
|
|
|
|
for(MountedDirs::reverse_iterator it = _mountedDirs.rbegin(); it != _mountedDirs.rend(); ++it)
|
|
|
|
(*it)->forEachFile(_addFileCallback, &flist);
|
|
|
|
|
|
|
|
for(Files::iterator it = flist.begin(); it != flist.end(); ++it)
|
|
|
|
f(it->second, user);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _iterDirs(Dirs &m, DirEnumCallback f, void *user)
|
|
|
|
{
|
|
|
|
for(Dirs::iterator it = m.begin(); it != m.end(); ++it)
|
|
|
|
f(it->second.content(), user);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InternalDir::forEachDir(DirEnumCallback f, void *user /* = NULL */, bool safe /* = false */)
|
|
|
|
{
|
|
|
|
for(MountedDirs::reverse_iterator it = _mountedDirs.rbegin(); it != _mountedDirs.rend(); ++it)
|
|
|
|
(*it)->forEachDir(f, user, safe);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool InternalDir::fillView(const char *path, DirView& view)
|
|
|
|
{
|
|
|
|
SkipSelfPath(path);
|
|
|
|
view.init(path);
|
|
|
|
size_t len = strlen(path) + 1;
|
|
|
|
char *pathcopy = (char*)VFS_STACK_ALLOC(len);
|
|
|
|
memcpy(pathcopy, path, len);
|
|
|
|
bool added = _addToView(pathcopy, view);
|
|
|
|
VFS_STACK_FREE(pathcopy);
|
|
|
|
return added;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool InternalDir::_addToView(char *path, DirView& view)
|
|
|
|
{
|
|
|
|
bool added = false;
|
|
|
|
|
|
|
|
if(!*path)
|
|
|
|
{
|
|
|
|
for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it)
|
|
|
|
{
|
|
|
|
added = true;
|
|
|
|
view.add(it->content());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SkipSelfPath(path);
|
|
|
|
char dummy = 0;
|
|
|
|
char *slashpos = strchr(path, '/');
|
|
|
|
char *tail = slashpos ? slashpos+1 : &dummy;
|
|
|
|
|
|
|
|
if(slashpos)
|
|
|
|
*slashpos = 0;
|
|
|
|
|
|
|
|
for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it)
|
|
|
|
if(DirBase *subdir = (*it)->getDirByName(path))
|
|
|
|
added = subdir->_addToView(tail, view) || added;
|
|
|
|
|
|
|
|
if(InternalDir *subdir = safecast<InternalDir*>(getDirByName(path, true, false)))
|
|
|
|
added = subdir->_addToView(tail, view) || added;
|
|
|
|
|
|
|
|
if(slashpos)
|
|
|
|
*slashpos = '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
return added;
|
|
|
|
}
|
|
|
|
|
2014-04-07 00:25:58 +00:00
|
|
|
File *InternalDir::getFileFromSubdir(const char *subdir, const char *file)
|
|
|
|
{
|
|
|
|
for(MountedDirs::reverse_iterator it = _mountedDirs.rbegin(); it != _mountedDirs.rend(); ++it)
|
|
|
|
if(File* f = (*it)->getFileFromSubdir(subdir, file))
|
|
|
|
return f;
|
2014-04-06 17:19:33 +00:00
|
|
|
|
2014-04-07 00:25:58 +00:00
|
|
|
InternalDir *d = safecast<InternalDir*>(DirBase::getDirByName(subdir, false, false)); // vcall not required here
|
|
|
|
return d ? d->getFile(file) : NULL;
|
|
|
|
}
|
2014-04-06 17:19:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
VFS_NAMESPACE_END
|
|
|
|
|