From cff42b44fa77dcf2f2bd585e15e4524fdfe45418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Mar 2014 20:47:37 +0200 Subject: [PATCH 1/2] Fixed|libdeng2|ArchiveFeed: Handling corrupt source data Even if the source archive was invalid and caused an exception when reading, the feed was still added to the source file's deletion audience. However, the exception caused the ArchiveFeed constructor to be automatically undone, leaving an invalid pointer in the source file's audience. --- doomsday/libdeng2/src/filesys/archivefeed.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doomsday/libdeng2/src/filesys/archivefeed.cpp b/doomsday/libdeng2/src/filesys/archivefeed.cpp index 4f5a0f22c6..d521a972fd 100644 --- a/doomsday/libdeng2/src/filesys/archivefeed.cpp +++ b/doomsday/libdeng2/src/filesys/archivefeed.cpp @@ -48,8 +48,6 @@ DENG2_PIMPL(ArchiveFeed) Instance(Public *feed, File &f) : Base(feed), file(&f), arch(0), parentFeed(0) { - file->audienceForDeletion() += this; - // If the file happens to be a byte array file, we can use it // directly to store the Archive. if(IByteArray *bytes = f.maybeAs()) @@ -67,6 +65,8 @@ DENG2_PIMPL(ArchiveFeed) f >> serializedArchive; arch = new ZipArchive(serializedArchive); } + + file->audienceForDeletion() += this; } Instance(Public *feed, ArchiveFeed &parentFeed, String const &path) From 1f8bd4b5b6ffcf285f231a08c761723e5f5efc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= Date: Tue, 25 Mar 2014 21:01:57 +0200 Subject: [PATCH 2/2] libdeng2|FS: Reinterpreting files Added File::reinterpret() and a test for it in test_archive. This allows taking an ordinary file or an already interpreted file and reinterpreting it just like a feed would do at the time when the file was originally created. --- doomsday/libdeng2/include/de/filesys/file.h | 18 +++++++++++ doomsday/libdeng2/src/filesys/file.cpp | 34 +++++++++++++++++++++ doomsday/tests/test_archive/main.cpp | 11 +++++++ 3 files changed, 63 insertions(+) diff --git a/doomsday/libdeng2/include/de/filesys/file.h b/doomsday/libdeng2/include/de/filesys/file.h index d8cd645d59..def55e5763 100644 --- a/doomsday/libdeng2/include/de/filesys/file.h +++ b/doomsday/libdeng2/include/de/filesys/file.h @@ -331,6 +331,24 @@ class DENG2_PUBLIC File : public Lockable, public IIOStream */ void verifyWriteAccess(); + /** + * Reinterprets the file. If there is a known interpretation for the file contents, + * the interpreter will replace this file in the folder. If the file is already + * interpreted, the previous interpreter is deleted and the original source file is + * reinterpreted. + * + * If the file is in a folder, the folder takes ownership of the returned + * interpreter. If the file does not have a parent, ownership of the interpreter is + * given to the caller, while this file's ownership transfers to the interpreter. + * + * Note that feeds have the responsibility to apply interpretation on the files they + * produce (using FileSystem::interpret()). + * + * @return The new interpreter, or this file if left uninterpreted. See above for + * ownership policy. + */ + File *reinterpret(); + // Implements IIOStream. IOStream &operator << (IByteArray const &bytes); IIStream &operator >> (IByteArray &bytes); diff --git a/doomsday/libdeng2/src/filesys/file.cpp b/doomsday/libdeng2/src/filesys/file.cpp index 83d03ebfee..a00d98f2e4 100644 --- a/doomsday/libdeng2/src/filesys/file.cpp +++ b/doomsday/libdeng2/src/filesys/file.cpp @@ -316,6 +316,40 @@ void File::verifyWriteAccess() } } +File *File::reinterpret() +{ + Folder *folder = parent(); + File *original = source(); + File *result = this; + bool deleteThis = false; + + if(original != this) + { + // Already interpreted. The current interpretation will be replaced. + DENG2_ASSERT(!original->parent()); + d->source = 0; // source is owned, so take it away + deleteThis = true; + } + if(folder) + { + folder->remove(*this); + } + + original->flush(); + result = fileSystem().interpret(original); + + if(deleteThis) + { + DENG2_ASSERT(result != this); + delete this; + } + if(folder) + { + folder->add(result); + } + return result; +} + IOStream &File::operator << (IByteArray const &bytes) { DENG2_UNUSED(bytes); diff --git a/doomsday/tests/test_archive/main.cpp b/doomsday/tests/test_archive/main.cpp index 7f32e295a2..cb06f737c4 100644 --- a/doomsday/tests/test_archive/main.cpp +++ b/doomsday/tests/test_archive/main.cpp @@ -84,6 +84,17 @@ int main(int argc, char **argv) LOG_MSG ("General description: %s") << zip2.description(); LOG_VERBOSE("Verbose description: %s") << zip2.description(); LOGDEV_MSG ("Developer description: %s") << zip2.description(); + + // Manual reinterpretation can be requested. + DENG2_ASSERT(zip2.parent() != 0); + File *updated = zip2.reinterpret(); + DENG2_ASSERT(!zip2.parent()); // became a source + + // This should now be a package folder so let's fill it with the archive + // contents. + updated->as().populate(); + + LOG_MSG("After reinterpretation: %s") << updated->description(); } catch(Error const &err) {