From b437a7cb2c8487f40930037d3fcd943e0b539a9b Mon Sep 17 00:00:00 2001 From: fgenesis Date: Mon, 7 Apr 2014 02:25:58 +0200 Subject: [PATCH] Fix ttvfs bugs, sync with dev repo --- Aquaria/DSQ.cpp | 10 +-- ExternalLibs/ttvfs/VFSDefines.h | 2 +- ExternalLibs/ttvfs/VFSDir.cpp | 79 ++++++--------------- ExternalLibs/ttvfs/VFSDir.h | 5 +- ExternalLibs/ttvfs/VFSDirInternal.cpp | 11 +++ ExternalLibs/ttvfs/VFSDirInternal.h | 1 + ExternalLibs/ttvfs/VFSDirView.cpp | 7 +- ExternalLibs/ttvfs/VFSDirView.h | 13 ++-- ExternalLibs/ttvfs/VFSLoader.cpp | 9 ++- ExternalLibs/ttvfs/VFSRoot.cpp | 27 ++++--- ExternalLibs/ttvfs/VFSRoot.h | 5 +- ExternalLibs/ttvfs_cfileapi/ttvfs_stdio.cpp | 21 +++--- ExternalLibs/ttvfs_zip/VFSDirZip.cpp | 2 +- 13 files changed, 84 insertions(+), 108 deletions(-) diff --git a/Aquaria/DSQ.cpp b/Aquaria/DSQ.cpp index f718025..19d476f 100644 --- a/Aquaria/DSQ.cpp +++ b/Aquaria/DSQ.cpp @@ -2804,19 +2804,13 @@ bool DSQ::mountModPackage(const std::string& pkg) { // Load archive only if no such directory exists already (prevent loading multiple times) vd = vfs.AddArchive(pkg.c_str()); - if(vd) - debugLog("Package: Loaded file " + pkg); - else + if(!vd) { debugLog("Package: Unable to load " + pkg); return false; } } - if(!vfs.Mount(pkg.c_str(), mod.getBaseModPath().c_str())) - { - debugLog("Package: Failed to mount: " + pkg); - return false; - } + vfs.Mount(pkg.c_str(), mod.getBaseModPath().c_str()); debugLog("Package: Mounted " + pkg + " as archive in _mods"); return true; #else diff --git a/ExternalLibs/ttvfs/VFSDefines.h b/ExternalLibs/ttvfs/VFSDefines.h index 642c5a1..b5c0e41 100644 --- a/ExternalLibs/ttvfs/VFSDefines.h +++ b/ExternalLibs/ttvfs/VFSDefines.h @@ -8,7 +8,7 @@ // Define this to allow dealing with files > 4 GB, using non-standard functions. // This may or may not work with your platform/compiler, good luck. -#define VFS_LARGEFILE_SUPPORT +//#define VFS_LARGEFILE_SUPPORT // Define this to make all operations case insensitive. // Windows systems generally don't care much, but for Linux and Mac this can be used diff --git a/ExternalLibs/ttvfs/VFSDir.cpp b/ExternalLibs/ttvfs/VFSDir.cpp index e29e848..211ced1 100644 --- a/ExternalLibs/ttvfs/VFSDir.cpp +++ b/ExternalLibs/ttvfs/VFSDir.cpp @@ -21,56 +21,22 @@ DirBase::~DirBase() { } -File *DirBase::getFile(const char *fn, bool lazyLoad /* = true */) +File *DirBase::getFile(const char *fn) { - while(fn[0] == '.' && fn[1] == '/') // skip ./ - fn += 2; + const char *slashpos = strchr(fn, '/'); + if(!slashpos) + return getFileByName(fn, true); - char *slashpos = (char *)strchr(fn, '/'); + const size_t len = slashpos - fn; + char *dirname = (char*)VFS_STACK_ALLOC(len + 1); + memcpy(dirname, fn, len); + dirname[len] = 0; - // if there is a '/' in the string, descend into subdir and continue there - if(slashpos) - { - // "" (the empty directory name) is allowed, so we can't return 'this' when hitting an empty string the first time. - // This whole mess is required for absolute unix-style paths ("/home/foo/..."), - // which, to integrate into the tree properly, sit in the root directory's ""-subdir. - // FIXME: Bad paths (double-slashes and the like) need to be normalized elsewhere, currently! - - size_t len = strlen(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 - DirBase *subdir = this; - const char *ptr = dup; - - goto pos_known; - do - { - ptr = slashpos + 1; - while(ptr[0] == '.' && ptr[1] == '/') // skip ./ - ptr += 2; - slashpos = (char *)strchr(ptr, '/'); - if(!slashpos) - break; - - pos_known: - *slashpos = 0; - subdir = subdir->getDirByName(ptr, true, true); - } - while(subdir); - VFS_STACK_FREE(dup); - if(!subdir) - return NULL; - // restore pointer into original string, by offset - ptr = fn + (ptr - dup); - return subdir->getFileByName(ptr, lazyLoad); - } - - // no subdir? file must be in this dir now. - return getFileByName(fn, lazyLoad); + File *f = getFileFromSubdir(dirname, slashpos + 1); + VFS_STACK_FREE(dirname); + return f; } - DirBase *DirBase::getDir(const char *subdir, bool forceCreate /* = false */, bool lazyLoad /* = true */, bool useSubtrees /* = true */) { SkipSelfPath(subdir); @@ -203,7 +169,6 @@ File *Dir::getFileByName(const char *fn, bool lazyLoad /* = true */) 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) @@ -267,7 +232,6 @@ bool Dir::addRecursive(File *f, size_t skip /* = 0 */) { 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(getDir(dirname, true)); @@ -313,6 +277,12 @@ DirBase *Dir::getDirByName(const char *dn, bool lazyLoad /* = true */, bool useS return sub; } +File *Dir::getFileFromSubdir(const char *subdir, const char *file) +{ + Dir *d = safecast(getDirByName(subdir, true, false)); // useSubtrees is irrelevant here + return d ? d->getFile(file) : NULL; +} + // ----- DiskDir start here ----- @@ -337,12 +307,7 @@ void DiskDir::load() GetFileList(fullname(), li); for(StringList::iterator it = li.begin(); it != li.end(); ++it) { - // TODO: use stack alloc - std::string tmp = fullname(); - tmp += '/'; - tmp += *it; - - DiskFile *f = new DiskFile(tmp.c_str()); + DiskFile *f = new DiskFile(joinPath(fullname(), it->c_str()).c_str()); _files[f->name()] = f; } @@ -350,12 +315,8 @@ void DiskDir::load() GetDirList(fullname(), li, 0); for(StringList::iterator it = li.begin(); it != li.end(); ++it) { - // TODO: use stack alloc - std::string full(fullname()); - full += '/'; - full += *it; // GetDirList() always returns relative paths - - Dir *d = createNew(full.c_str()); + // GetDirList() returns relative paths, so need to join + Dir *d = createNew(joinPath(fullname(), it->c_str()).c_str()); _subdirs[d->name()] = d; } } diff --git a/ExternalLibs/ttvfs/VFSDir.h b/ExternalLibs/ttvfs/VFSDir.h index adbd2a3..65b4969 100644 --- a/ExternalLibs/ttvfs/VFSDir.h +++ b/ExternalLibs/ttvfs/VFSDir.h @@ -78,7 +78,7 @@ public: /** Returns a file for this dir's subtree. Descends if necessary. Returns NULL if the file is not found. */ - File *getFile(const char *fn, bool lazyLoad = true); + File *getFile(const char *fn); /** Returns a subdir, descends if necessary. If forceCreate is true, create directory tree if it does not exist, and return the originally requested @@ -90,6 +90,8 @@ public: virtual File *getFileByName(const char *fn, bool lazyLoad = true) = 0; virtual DirBase *getDirByName(const char *fn, bool lazyLoad = true, bool useSubtrees = true); + virtual File *getFileFromSubdir(const char *subdir, const char *file) = 0; + /** Iterate over all files or directories, calling a callback function, optionally with additional userdata. If safe is true, iterate over a copy. This is useful if the callback function modifies the tree, e.g. @@ -135,6 +137,7 @@ public: bool _addToView(char *path, DirView& view); DirBase *getDirByName(const char *dn, bool lazyLoad = true, bool useSubtrees = true); File *getFileByName(const char *fn, bool lazyLoad = true); + File *getFileFromSubdir(const char *subdir, const char *file); protected: diff --git a/ExternalLibs/ttvfs/VFSDirInternal.cpp b/ExternalLibs/ttvfs/VFSDirInternal.cpp index 045ea6d..9ed63ab 100644 --- a/ExternalLibs/ttvfs/VFSDirInternal.cpp +++ b/ExternalLibs/ttvfs/VFSDirInternal.cpp @@ -42,6 +42,9 @@ void InternalDir::close() void InternalDir::_addMountDir(CountedPtr d) { + if(d.content() == this) + return; + // move to end of vector if already mounted for(MountedDirs::iterator it = _mountedDirs.begin(); it != _mountedDirs.end(); ++it) if(*it == d) @@ -162,7 +165,15 @@ bool InternalDir::_addToView(char *path, DirView& view) return added; } +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; + InternalDir *d = safecast(DirBase::getDirByName(subdir, false, false)); // vcall not required here + return d ? d->getFile(file) : NULL; +} VFS_NAMESPACE_END diff --git a/ExternalLibs/ttvfs/VFSDirInternal.h b/ExternalLibs/ttvfs/VFSDirInternal.h index 7ea62b5..4274929 100644 --- a/ExternalLibs/ttvfs/VFSDirInternal.h +++ b/ExternalLibs/ttvfs/VFSDirInternal.h @@ -26,6 +26,7 @@ public: void forEachDir(DirEnumCallback f, void *user = NULL, bool safe = false); File *getFileByName(const char *fn, bool lazyLoad = true); DirBase *getDirByName(const char *fn, bool lazyLoad = true, bool useSubtrees = true); + File *getFileFromSubdir(const char *subdir, const char *file); void close(); protected: diff --git a/ExternalLibs/ttvfs/VFSDirView.cpp b/ExternalLibs/ttvfs/VFSDirView.cpp index 90589c8..b3d5b6c 100644 --- a/ExternalLibs/ttvfs/VFSDirView.cpp +++ b/ExternalLibs/ttvfs/VFSDirView.cpp @@ -65,9 +65,12 @@ bool DirView::_addToView(char *path, DirView& view) return true; } -static void __test__() +File *DirView::getFileFromSubdir(const char *subdir, const char *file) { - new DirView; + for(ViewList::reverse_iterator it = _view.rbegin(); it != _view.rend(); ++it) + if(File* f = (*it)->getFileFromSubdir(subdir, file)) + return f; + return NULL; } VFS_NAMESPACE_END diff --git a/ExternalLibs/ttvfs/VFSDirView.h b/ExternalLibs/ttvfs/VFSDirView.h index 81a987a..023a501 100644 --- a/ExternalLibs/ttvfs/VFSDirView.h +++ b/ExternalLibs/ttvfs/VFSDirView.h @@ -13,16 +13,17 @@ class DirView : public DirBase { public: DirView(); - ~DirView(); + virtual ~DirView(); void init(const char *); void add(DirBase *); - virtual File *getFileByName(const char *fn, bool lazyLoad = true); - virtual void forEachDir(DirEnumCallback f, void *user = NULL, bool safe = false); - virtual void forEachFile(FileEnumCallback f, void *user = NULL, bool safe = false); + File *getFileByName(const char *fn, bool lazyLoad = true); + void forEachDir(DirEnumCallback f, void *user = NULL, bool safe = false); + void forEachFile(FileEnumCallback f, void *user = NULL, bool safe = false); + File *getFileFromSubdir(const char *subdir, const char *file); - virtual const char *getType() const { return "DirView"; } - virtual DirBase *createNew(const char *dir) const { return NULL; } + const char *getType() const { return "DirView"; } + DirBase *createNew(const char *dir) const { return NULL; } bool _addToView(char *path, DirView& view); diff --git a/ExternalLibs/ttvfs/VFSLoader.cpp b/ExternalLibs/ttvfs/VFSLoader.cpp index 243ca47..650c4eb 100644 --- a/ExternalLibs/ttvfs/VFSLoader.cpp +++ b/ExternalLibs/ttvfs/VFSLoader.cpp @@ -121,13 +121,16 @@ Dir *DiskLoader::LoadDir(const char *fn, const char * /*ignored*/) char *t = (char*)VFS_STACK_ALLOC(s+1); memcpy(t, fn, s+1); // copy terminating '\0' as well if(findFileHarder(&t[0])) // fixes the filename on the way - { fn = &t[0]; - } +#endif + + ret = safecastNonNull(getRoot()->getDir(fn, true, false)); + +#if !defined(_WIN32) && defined(VFS_IGNORE_CASE) VFS_STACK_FREE(t); #endif - return safecastNonNull(getRoot()->getDir(fn, true, false)); + return ret; } VFS_NAMESPACE_END diff --git a/ExternalLibs/ttvfs/VFSRoot.cpp b/ExternalLibs/ttvfs/VFSRoot.cpp index 1f64faf..d54f20f 100644 --- a/ExternalLibs/ttvfs/VFSRoot.cpp +++ b/ExternalLibs/ttvfs/VFSRoot.cpp @@ -51,7 +51,6 @@ Root::Root() Root::~Root() { - Clear(); } void Root::Clear() @@ -63,32 +62,27 @@ void Root::Clear() archLdrs.clear(); } -bool Root::Mount(const char *src, const char *dest) +void Root::Mount(const char *src, const char *dest) { return AddVFSDir(GetDir(src, true), dest); } -bool Root::AddVFSDir(DirBase *dir, const char *subdir /* = NULL */) +void Root::AddVFSDir(DirBase *dir, const char *subdir /* = NULL */) { - if(!dir) - return false; if(!subdir) subdir = dir->fullname(); - InternalDir *into = safecastNonNull(merged->getDir(subdir, true, true, false)); into->_addMountDir(dir); - - return true; } bool Root::Unmount(const char *src, const char *dest) { DirBase *vdsrc = GetDir(src, false); - InternalDir *vddest = safecastNonNull(GetDir(dest, false)); + InternalDir *vddest = safecast(GetDir(dest, false)); if(!vdsrc || !vddest) return false; - vddest->_removeMountDir(vdsrc); // FIXME: verify this works + vddest->_removeMountDir(vdsrc); return true; } @@ -102,17 +96,20 @@ void Root::AddArchiveLoader(VFSArchiveLoader *ldr) { archLdrs.push_back(ldr); } - Dir *Root::AddArchive(const char *arch, void *opaque /* = NULL */) { - File *af = GetFile(arch); - if(!af) + return AddArchive(GetFile(arch), arch, opaque); +} + +Dir *Root::AddArchive(File *file, const char *path /* = NULL */, void *opaque /* = NULL */) +{ + if(!file || !file->open("rb")) return NULL; Dir *ad = NULL; VFSLoader *fileLdr = NULL; for(ArchiveLoaderArray::iterator it = archLdrs.begin(); it != archLdrs.end(); ++it) - if((ad = (*it)->Load(af, &fileLdr, opaque))) + if((ad = (*it)->Load(file, &fileLdr, opaque))) break; if(!ad) return NULL; @@ -120,7 +117,7 @@ Dir *Root::AddArchive(const char *arch, void *opaque /* = NULL */) if(fileLdr) loaders.push_back(fileLdr); - AddVFSDir(ad, arch); + AddVFSDir(ad, path ? path : file->fullname()); return ad; } diff --git a/ExternalLibs/ttvfs/VFSRoot.h b/ExternalLibs/ttvfs/VFSRoot.h index 78b28dd..7c46b8f 100644 --- a/ExternalLibs/ttvfs/VFSRoot.h +++ b/ExternalLibs/ttvfs/VFSRoot.h @@ -41,7 +41,7 @@ public: /** Mount a directory in the tree to a different location. Requires a previous call to Prepare(). This can be imagined like the contents of a directory appearing in a different location. Be careful not to create circles! */ - bool Mount(const char *src, const char *dest); + void Mount(const char *src, const char *dest); /** Drops a directory from the tree. Internally, this calls Reload(false), which is a heavy operation compared to Mount(). Be warned. */ @@ -51,7 +51,7 @@ public: add into the subdir stored in the Dir object. The tree will be extended if target dir does not exist. Files in the tree will be replaced if already existing. Like with Mount(); be careful not to create cycles. */ - bool AddVFSDir(DirBase *dir, const char *subdir = NULL); + void AddVFSDir(DirBase *dir, const char *subdir = NULL); /** Add an archive file to the tree, which can then be addressed like a folder, e.g. "path/to/example.zip/file.txt". @@ -61,6 +61,7 @@ public: Read the comments in VFSArchiveLoader.h for an explanation how it works. If you have no idea, leave it NULL, because it can easily cause a crash if not used carefully. */ Dir *AddArchive(const char *arch, void *opaque = NULL); + Dir *AddArchive(File *file, const char *path = NULL, void *opaque = NULL); /** Add a loader that can look for files on demand. Do not add more then once instance of a loader type. */ diff --git a/ExternalLibs/ttvfs_cfileapi/ttvfs_stdio.cpp b/ExternalLibs/ttvfs_cfileapi/ttvfs_stdio.cpp index ecc9a94..f8a58ef 100644 --- a/ExternalLibs/ttvfs_cfileapi/ttvfs_stdio.cpp +++ b/ExternalLibs/ttvfs_cfileapi/ttvfs_stdio.cpp @@ -107,18 +107,19 @@ InStream::InStream(const char *fn) bool InStream::open(const char *fn) { ttvfs::File *vf = vfs->GetFile(fn); - if(vf && vf->open("r")) + if(!vf || !vf->open("r")) { - size_t sz = (size_t)vf->size(); - std::string s; - s.resize(sz); - vf->read(&s[0], sz); - str(s); - vf->close(); - return true; + setstate(std::ios::failbit); + return false; } - setstate(std::ios::failbit); - return false; + size_t sz = (size_t)vf->size(); + std::string s; + s.resize(sz); + size_t bytes = vf->read(&s[0], sz); + s.resize(bytes); + str(s); + vf->close(); + return true; } int ttvfs_stdio_fsize(VFILE *f, size_t *sizep) diff --git a/ExternalLibs/ttvfs_zip/VFSDirZip.cpp b/ExternalLibs/ttvfs_zip/VFSDirZip.cpp index 278832e..6ab4ef0 100644 --- a/ExternalLibs/ttvfs_zip/VFSDirZip.cpp +++ b/ExternalLibs/ttvfs_zip/VFSDirZip.cpp @@ -47,7 +47,7 @@ void ZipDir::load() _archiveHandle->openRead(); const unsigned int files = mz_zip_reader_get_num_files(MZ); - const size_t len = fullnameLen(); + const size_t len = fullnameLen() + 1; // +1 for trailing '/' when used as path name in addRecursive() mz_zip_archive_file_stat fs; for (unsigned int i = 0; i < files; ++i)