mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-10-05 13:51:04 +00:00
Update ttvfs to new version
This commit is contained in:
parent
209ad526c6
commit
8026cdd905
43 changed files with 2124 additions and 2427 deletions
|
@ -1,4 +1,4 @@
|
|||
// VFSDir.cpp - basic directory interface + classes
|
||||
// Dir.cpp - basic directory interface + classes
|
||||
// For conditions of distribution and use, see copyright notice in VFS.h
|
||||
|
||||
#include <set>
|
||||
|
@ -7,136 +7,21 @@
|
|||
#include "VFSTools.h"
|
||||
#include "VFSFile.h"
|
||||
#include "VFSDir.h"
|
||||
#include "VFSDirView.h"
|
||||
#include "VFSLoader.h"
|
||||
|
||||
VFS_NAMESPACE_START
|
||||
|
||||
|
||||
VFSDir::VFSDir(const char *fullpath)
|
||||
DirBase::DirBase(const char *fullpath)
|
||||
{
|
||||
_setName(fullpath);
|
||||
}
|
||||
|
||||
VFSDir::~VFSDir()
|
||||
DirBase::~DirBase()
|
||||
{
|
||||
for(Files::iterator it = _files.begin(); it != _files.end(); ++it)
|
||||
it->second.ptr->ref--;
|
||||
for(Dirs::iterator it = _subdirs.begin(); it != _subdirs.end(); ++it)
|
||||
it->second.ptr->ref--;
|
||||
}
|
||||
|
||||
unsigned int VFSDir::load(bool recursive)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
VFSDir *VFSDir::createNew(const char *dir) const
|
||||
{
|
||||
VFSDir *vd = new VFSDir(dir);
|
||||
vd->_setOrigin(getOrigin());
|
||||
return vd;
|
||||
}
|
||||
|
||||
bool VFSDir::add(VFSFile *f, bool overwrite, EntryFlags flag)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
Files::iterator it = _files.find(f->name());
|
||||
|
||||
if(it != _files.end())
|
||||
{
|
||||
if(overwrite)
|
||||
{
|
||||
VFSFile *oldf = it->second.ptr;
|
||||
if(oldf == f)
|
||||
return false;
|
||||
|
||||
_files.erase(it);
|
||||
oldf->ref--;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
f->ref++;
|
||||
_files[f->name()] = MapEntry<VFSFile>(f, flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFSDir::addRecursive(VFSFile *f, bool overwrite, EntryFlags flag)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
// figure out directory from full file name
|
||||
VFSDir *vdir;
|
||||
size_t prefixLen = f->fullnameLen() - f->nameLen();
|
||||
if(prefixLen)
|
||||
{
|
||||
char *dirname = (char*)VFS_STACK_ALLOC(prefixLen);
|
||||
--prefixLen; // -1 to strip the trailing '/'. That's the position where to put the terminating null byte.
|
||||
memcpy(dirname, f->fullname(), prefixLen); // copy trailing null byte
|
||||
dirname[prefixLen] = 0;
|
||||
vdir = getDir(dirname, true);
|
||||
VFS_STACK_FREE(dirname);
|
||||
}
|
||||
else
|
||||
vdir = this;
|
||||
|
||||
return vdir->add(f, true, flag);
|
||||
}
|
||||
|
||||
bool VFSDir::merge(VFSDir *dir, bool overwrite, EntryFlags flag)
|
||||
{
|
||||
if(!dir)
|
||||
return false;
|
||||
if(dir == this)
|
||||
return true; // nothing to do then
|
||||
|
||||
// HACK: make sure the files are there before merging
|
||||
this->load(false);
|
||||
dir->load(false);
|
||||
|
||||
bool result = false;
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
for(Files::iterator it = dir->_files.begin(); it != dir->_files.end(); ++it)
|
||||
result = add(it->second.ptr, overwrite, flag) || result;
|
||||
|
||||
for(Dirs::iterator it = dir->_subdirs.begin(); it != dir->_subdirs.end(); ++it)
|
||||
result = insert(it->second.ptr, overwrite, flag) || result;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VFSDir::insert(VFSDir *subdir, bool overwrite, EntryFlags flag)
|
||||
{
|
||||
if(!subdir)
|
||||
return false;
|
||||
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
// With load() cleaning up the tree, it is ok to add subsequent VFSDirs directly.
|
||||
// This will be very useful at some point when files can be mounted into a directory
|
||||
// belonging to an archive, and this way adding files to the archive.
|
||||
Dirs::iterator it = _subdirs.find(subdir->name());
|
||||
if(it == _subdirs.end())
|
||||
{
|
||||
subdir->ref++;
|
||||
_subdirs[subdir->name()] = MapEntry<VFSDir>(subdir, flag);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.ptr->merge(subdir, overwrite, flag);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VFSFile *VFSDir::getFile(const char *fn)
|
||||
File *DirBase::getFile(const char *fn, bool lazyLoad /* = true */)
|
||||
{
|
||||
while(fn[0] == '.' && fn[1] == '/') // skip ./
|
||||
fn += 2;
|
||||
|
@ -155,10 +40,8 @@ VFSFile *VFSDir::getFile(const char *fn)
|
|||
char *dup = (char*)VFS_STACK_ALLOC(len + 1);
|
||||
memcpy(dup, fn, len + 1); // also copy the null-byte
|
||||
slashpos = dup + (slashpos - fn); // use direct offset, not to have to recount again the first time
|
||||
VFSDir *subdir = this;
|
||||
DirBase *subdir = this;
|
||||
const char *ptr = dup;
|
||||
Dirs::iterator it;
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
goto pos_known;
|
||||
do
|
||||
|
@ -172,11 +55,7 @@ VFSFile *VFSDir::getFile(const char *fn)
|
|||
|
||||
pos_known:
|
||||
*slashpos = 0;
|
||||
it = subdir->_subdirs.find(ptr);
|
||||
if(it != subdir->_subdirs.end())
|
||||
subdir = it->second.ptr; // found it
|
||||
else
|
||||
subdir = NULL; // bail out
|
||||
subdir = subdir->getDirByName(ptr, true, true);
|
||||
}
|
||||
while(subdir);
|
||||
VFS_STACK_FREE(dup);
|
||||
|
@ -184,23 +63,21 @@ VFSFile *VFSDir::getFile(const char *fn)
|
|||
return NULL;
|
||||
// restore pointer into original string, by offset
|
||||
ptr = fn + (ptr - dup);
|
||||
|
||||
Files::iterator ft = subdir->_files.find(ptr);
|
||||
return ft != subdir->_files.end() ? ft->second.ptr : NULL;
|
||||
return subdir->getFileByName(ptr, lazyLoad);
|
||||
}
|
||||
|
||||
// no subdir? file must be in this dir now.
|
||||
VFS_GUARD_OPT(this);
|
||||
Files::iterator it = _files.find(fn);
|
||||
return it != _files.end() ? it->second.ptr : NULL;
|
||||
return getFileByName(fn, lazyLoad);
|
||||
}
|
||||
|
||||
VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
||||
|
||||
DirBase *DirBase::getDir(const char *subdir, bool forceCreate /* = false */, bool lazyLoad /* = true */, bool useSubtrees /* = true */)
|
||||
{
|
||||
if(!subdir[0] || (subdir[0] == '.' && (!subdir[1] || subdir[1] == '/'))) // empty string or "." or "./" ? use this.
|
||||
SkipSelfPath(subdir);
|
||||
if(!subdir[0])
|
||||
return this;
|
||||
|
||||
VFSDir *ret = NULL;
|
||||
DirBase *ret = NULL;
|
||||
char *slashpos = (char *)strchr(subdir, '/');
|
||||
|
||||
// if there is a '/' in the string, descend into subdir and continue there
|
||||
|
@ -212,17 +89,17 @@ VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
|||
char * const t = (char*)VFS_STACK_ALLOC(copysize + 1);
|
||||
memcpy(t, subdir, copysize);
|
||||
t[copysize] = 0;
|
||||
VFS_GUARD_OPT(this);
|
||||
Dirs::iterator it = _subdirs.find(t);
|
||||
if(it != _subdirs.end())
|
||||
|
||||
if(DirBase *dir = getDirByName(t, lazyLoad, useSubtrees))
|
||||
{
|
||||
ret = it->second.ptr->getDir(sub, forceCreate); // descend into subdirs
|
||||
// TODO: get rid of recursion
|
||||
ret = dir->getDir(sub, forceCreate, lazyLoad); // descend into subdirs
|
||||
}
|
||||
else if(forceCreate)
|
||||
{
|
||||
// -> newname = fullname() + '/' + t
|
||||
size_t fullLen = fullnameLen();
|
||||
VFSDir *ins;
|
||||
DirBase *ins;
|
||||
if(fullLen)
|
||||
{
|
||||
char * const newname = (char*)VFS_STACK_ALLOC(fullLen + copysize + 2);
|
||||
|
@ -239,15 +116,13 @@ VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
|||
ins = createNew(t);
|
||||
|
||||
_subdirs[ins->name()] = ins;
|
||||
ret = ins->getDir(sub, true); // create remaining structure
|
||||
ret = ins->getDir(sub, true, lazyLoad); // create remaining structure
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
Dirs::iterator it = _subdirs.find(subdir);
|
||||
if(it != _subdirs.end())
|
||||
ret = it->second.ptr;
|
||||
if(DirBase *dir = getDirByName(subdir, lazyLoad, useSubtrees))
|
||||
ret = dir;
|
||||
else if(forceCreate)
|
||||
{
|
||||
size_t fullLen = fullnameLen();
|
||||
|
@ -278,168 +153,211 @@ VFSDir *VFSDir::getDir(const char *subdir, bool forceCreate /* = false */)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void VFSDir::clearMounted()
|
||||
static void _iterDirs(Dirs &m, DirEnumCallback f, void *user)
|
||||
{
|
||||
for(FileIter it = _files.begin(); it != _files.end(); )
|
||||
{
|
||||
MapEntry<VFSFile>& e = it->second;
|
||||
if(e.isMounted())
|
||||
{
|
||||
e.ptr->ref--;
|
||||
_files.erase(it++);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
for(DirIter it = _subdirs.begin(); it != _subdirs.end(); )
|
||||
{
|
||||
MapEntry<VFSDir>& e = it->second;
|
||||
if(e.isMounted())
|
||||
{
|
||||
e.ptr->ref--;
|
||||
_subdirs.erase(it++);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.ptr->clearMounted();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
for(Dirs::iterator it = m.begin(); it != m.end(); ++it)
|
||||
f(it->second.content(), user);
|
||||
}
|
||||
|
||||
template<typename T> static void iterIncref(T *b, void*) { ++(b->ref); }
|
||||
template<typename T> static void iterDecref(T *b, void*) { --(b->ref); }
|
||||
|
||||
static void _iterDirs(VFSDir::Dirs &m, DirEnumCallback f, void *user)
|
||||
void DirBase::forEachDir(DirEnumCallback f, void *user /* = NULL */, bool safe /* = false */)
|
||||
{
|
||||
for(DirIter it = m.begin(); it != m.end(); ++it)
|
||||
f(it->second.ptr, user);
|
||||
}
|
||||
|
||||
void VFSDir::forEachDir(DirEnumCallback f, void *user /* = NULL */, bool safe /* = false */)
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
if(safe)
|
||||
{
|
||||
Dirs cp = _subdirs;
|
||||
_iterDirs(cp, iterIncref<VFSDir>, NULL);
|
||||
_iterDirs(cp, f, user);
|
||||
_iterDirs(cp, iterDecref<VFSDir>, NULL);
|
||||
}
|
||||
else
|
||||
_iterDirs(_subdirs, f, user);
|
||||
}
|
||||
|
||||
static void _iterFiles(VFSDir::Files &m, FileEnumCallback f, void *user)
|
||||
DirBase *DirBase::getDirByName(const char *dn, bool /* unused: lazyLoad = true */, bool useSubtrees /* = true */)
|
||||
{
|
||||
for(FileIter it = m.begin(); it != m.end(); ++it)
|
||||
f(it->second.ptr, user);
|
||||
Dirs::const_iterator it = _subdirs.find(dn);
|
||||
return it != _subdirs.end() ? it->second : NULL;
|
||||
}
|
||||
|
||||
void VFSDir::forEachFile(FileEnumCallback f, void *user /* = NULL */, bool safe /* = false */)
|
||||
void DirBase::clearGarbage()
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
for(Dirs::iterator it = _subdirs.begin(); it != _subdirs.end(); ++it)
|
||||
it->second->clearGarbage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dir::Dir(const char *fullpath, VFSLoader *ldr)
|
||||
: DirBase(fullpath), _loader(ldr)
|
||||
{
|
||||
}
|
||||
|
||||
Dir::~Dir()
|
||||
{
|
||||
}
|
||||
|
||||
File *Dir::getFileByName(const char *fn, bool lazyLoad /* = true */)
|
||||
{
|
||||
Files::iterator it = _files.find(fn);
|
||||
if(it != _files.end())
|
||||
return it->second;
|
||||
|
||||
if(!lazyLoad || !_loader)
|
||||
return NULL;
|
||||
|
||||
// Lazy-load file if it's not in the tree yet
|
||||
// TODO: get rid of alloc
|
||||
std::string fn2 = joinPath(fullname(), GetBaseNameFromPath(fn));
|
||||
File *f = _loader->Load(fn2.c_str(), fn2.c_str());
|
||||
if(f)
|
||||
_files[f->name()] = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
static void _iterFiles(Files &m, FileEnumCallback f, void *user)
|
||||
{
|
||||
for(Files::iterator it = m.begin(); it != m.end(); ++it)
|
||||
f(it->second.content(), user);
|
||||
}
|
||||
|
||||
void Dir::forEachFile(FileEnumCallback f, void *user /* = NULL */, bool safe /* = false */)
|
||||
{
|
||||
load();
|
||||
if(safe)
|
||||
{
|
||||
Files cp = _files;
|
||||
_iterFiles(cp, iterIncref<VFSFile>, NULL);
|
||||
_iterFiles(cp, f, user);
|
||||
_iterFiles(cp, iterDecref<VFSFile>, NULL);
|
||||
}
|
||||
else
|
||||
_iterFiles(_files, f, user);
|
||||
}
|
||||
|
||||
|
||||
// ----- VFSDirReal start here -----
|
||||
bool Dir::add(File *f)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
Files::iterator it = _files.find(f->name());
|
||||
|
||||
if(it != _files.end())
|
||||
{
|
||||
File *oldf = it->second;
|
||||
if(oldf == f)
|
||||
return false;
|
||||
|
||||
_files.erase(it);
|
||||
}
|
||||
|
||||
_files[f->name()] = f;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dir::addRecursive(File *f, size_t skip /* = 0 */)
|
||||
{
|
||||
if(!f)
|
||||
return false;
|
||||
|
||||
Dir *vdir = this;
|
||||
if(f->fullnameLen() - f->nameLen() > skip)
|
||||
{
|
||||
// figure out directory from full file name
|
||||
size_t prefixLen = f->fullnameLen() - f->nameLen() - skip;
|
||||
|
||||
// prefixLen == 0 is invalid, prefixLen == 1 is just a single '/', which will be stripped away below.
|
||||
// in both cases, just use 'this'.
|
||||
if(prefixLen > 1)
|
||||
{
|
||||
char *dirname = (char*)VFS_STACK_ALLOC(prefixLen);
|
||||
--prefixLen; // -1 to strip the trailing '/'. That's the position where to put the terminating null byte.
|
||||
++skip;
|
||||
memcpy(dirname, f->fullname() + skip, prefixLen); // copy trailing null byte
|
||||
dirname[prefixLen] = 0;
|
||||
vdir = safecastNonNull<Dir*>(getDir(dirname, true));
|
||||
VFS_STACK_FREE(dirname);
|
||||
}
|
||||
}
|
||||
|
||||
return vdir->add(f);
|
||||
}
|
||||
|
||||
void Dir::clearGarbage()
|
||||
{
|
||||
DirBase::clearGarbage();
|
||||
for(Files::iterator it = _files.begin(); it != _files.end(); ++it)
|
||||
it->second->clearGarbage();
|
||||
}
|
||||
|
||||
bool Dir::_addToView(char *path, DirView& view)
|
||||
{
|
||||
if(Dir *dir = safecast<Dir*>(getDir(path)))
|
||||
{
|
||||
view.add(dir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DirBase *Dir::getDirByName(const char *dn, bool lazyLoad /* = true */, bool useSubtrees /* = true */)
|
||||
{
|
||||
DirBase *sub;
|
||||
if((sub = DirBase::getDirByName(dn, lazyLoad, useSubtrees)))
|
||||
return sub;
|
||||
|
||||
if(!lazyLoad || !_loader)
|
||||
return NULL;
|
||||
|
||||
// Lazy-load file if it's not in the tree yet
|
||||
// TODO: get rid of alloc
|
||||
std::string fn2 = joinPath(fullname(), dn);
|
||||
sub = _loader->LoadDir(fn2.c_str(), fn2.c_str());
|
||||
if(sub)
|
||||
_subdirs[sub->name()] = sub;
|
||||
return sub;
|
||||
}
|
||||
|
||||
|
||||
VFSDirReal::VFSDirReal(const char *dir) : VFSDir(dir)
|
||||
|
||||
// ----- DiskDir start here -----
|
||||
|
||||
|
||||
DiskDir::DiskDir(const char *path, VFSLoader *ldr) : Dir(path, ldr)
|
||||
{
|
||||
}
|
||||
|
||||
VFSDir *VFSDirReal::createNew(const char *dir) const
|
||||
DiskDir *DiskDir::createNew(const char *dir) const
|
||||
{
|
||||
return new VFSDirReal(dir);
|
||||
return new DiskDir(dir, getLoader());
|
||||
}
|
||||
|
||||
unsigned int VFSDirReal::load(bool recursive)
|
||||
void DiskDir::load()
|
||||
{
|
||||
VFS_GUARD_OPT(this);
|
||||
|
||||
Files remainF;
|
||||
Dirs remainD;
|
||||
|
||||
remainF.swap(_files);
|
||||
remainD.swap(_subdirs);
|
||||
|
||||
// _files, _subdirs now empty
|
||||
_files.clear();
|
||||
_subdirs.clear();
|
||||
// TODO: cache existing files and keep them unless they do no longer exist
|
||||
|
||||
StringList li;
|
||||
GetFileList(fullname(), li);
|
||||
for(StringList::iterator it = li.begin(); it != li.end(); ++it)
|
||||
{
|
||||
// file was already present, move over and erase
|
||||
FileIter fi = remainF.find(it->c_str());
|
||||
if(fi != remainF.end())
|
||||
{
|
||||
_files[fi->first] = fi->second;
|
||||
remainF.erase(fi);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: use stack alloc
|
||||
std::string tmp = fullname();
|
||||
tmp += '/';
|
||||
tmp += *it;
|
||||
VFSFileReal *f = new VFSFileReal(tmp.c_str());
|
||||
|
||||
DiskFile *f = new DiskFile(tmp.c_str());
|
||||
_files[f->name()] = f;
|
||||
}
|
||||
unsigned int sum = li.size();
|
||||
|
||||
li.clear();
|
||||
GetDirList(fullname(), li, 0);
|
||||
for(std::deque<std::string>::iterator it = li.begin(); it != li.end(); ++it)
|
||||
for(StringList::iterator it = li.begin(); it != li.end(); ++it)
|
||||
{
|
||||
// subdir was already present, move over and erase
|
||||
DirIter fi = remainD.find(it->c_str());
|
||||
if(fi != remainD.end())
|
||||
{
|
||||
if(recursive)
|
||||
sum += fi->second.ptr->load(true);
|
||||
++sum;
|
||||
|
||||
_subdirs[fi->first] = fi->second;
|
||||
remainD.erase(fi);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: use stack alloc
|
||||
std::string full(fullname());
|
||||
full += '/';
|
||||
full += *it; // GetDirList() always returns relative paths
|
||||
|
||||
VFSDir *d = createNew(full.c_str());
|
||||
if(recursive)
|
||||
sum += d->load(true);
|
||||
++sum;
|
||||
Dir *d = createNew(full.c_str());
|
||||
_subdirs[d->name()] = d;
|
||||
}
|
||||
|
||||
// clean up & remove no longer existing files & dirs,
|
||||
// and move over entries mounted here.
|
||||
for(FileIter it = remainF.begin(); it != remainF.end(); ++it)
|
||||
if(it->second.isMounted())
|
||||
_files[it->first] = it->second;
|
||||
else
|
||||
it->second.ptr->ref--;
|
||||
for(DirIter it = remainD.begin(); it != remainD.end(); ++it)
|
||||
if(it->second.isMounted())
|
||||
_subdirs[it->first] = it->second;
|
||||
else
|
||||
it->second.ptr->ref--;
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
VFS_NAMESPACE_END
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue