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/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) 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) {