diff --git a/src/common/audio/music/i_soundfont.cpp b/src/common/audio/music/i_soundfont.cpp index e4a6bc39fc..0f3c0020b9 100644 --- a/src/common/audio/music/i_soundfont.cpp +++ b/src/common/audio/music/i_soundfont.cpp @@ -218,7 +218,7 @@ FileReader FZipPatReader::OpenFile(const char *name) auto lump = resf->FindEntry(name); if (lump >= 0) { - return resf->GetEntryReader(lump); + return resf->GetEntryReader(lump, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE); } } fr.OpenFile(name); diff --git a/src/common/filesystem/include/fs_decompress.h b/src/common/filesystem/include/fs_decompress.h index ef4b947458..0ea062ddb4 100644 --- a/src/common/filesystem/include/fs_decompress.h +++ b/src/common/filesystem/include/fs_decompress.h @@ -31,7 +31,8 @@ enum EDecompressFlags { DCF_TRANSFEROWNER = 1, DCF_SEEKABLE = 2, - DCF_EXCEPTIONS = 4 + DCF_EXCEPTIONS = 4, + DCF_CACHED = 8, }; bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size length, int method, int flags = 0); // creates a decompressor stream. 'seekable' uses a buffered version so that the Seek and Tell methods can be used. diff --git a/src/common/filesystem/include/fs_filesystem.h b/src/common/filesystem/include/fs_filesystem.h index 4d7ca8c153..bf3fe0e2b6 100644 --- a/src/common/filesystem/include/fs_filesystem.h +++ b/src/common/filesystem/include/fs_filesystem.h @@ -93,10 +93,19 @@ public: FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); } FileData ReadFileFullName(const char* name) { return ReadFile(GetNumForFullName(name)); } - FileReader OpenFileReader(int lump); // opens a reader that redirects to the containing file's one. - FileReader ReopenFileReader(int lump, bool alwayscache = false); // opens an independent reader. + FileReader OpenFileReader(int lump, int readertype, int readerflags); // opens a reader that redirects to the containing file's one. FileReader OpenFileReader(const char* name); FileReader ReopenFileReader(const char* name, bool alwayscache = false); + FileReader OpenFileReader(int lump) + { + return OpenFileReader(lump, READER_SHARED, READERFLAG_SEEKABLE); + } + + FileReader ReopenFileReader(int lump, bool alwayscache = false) + { + return OpenFileReader(lump, alwayscache ? READER_CACHED : READER_NEW, READERFLAG_SEEKABLE); + } + int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names diff --git a/src/common/filesystem/include/resourcefile.h b/src/common/filesystem/include/resourcefile.h index ddce567719..7709822e11 100644 --- a/src/common/filesystem/include/resourcefile.h +++ b/src/common/filesystem/include/resourcefile.h @@ -86,6 +86,14 @@ enum ELumpFlags RESFF_NEEDFILESTART = 32, // The real position is not known yet and needs to be calculated on access }; +enum EReaderType +{ + READER_SHARED = 0, // returns a view into the parent's reader. + READER_NEW = 1, // opens a new file handle + READER_CACHED = 2, // returns a MemoryArrayReader + READERFLAG_SEEKABLE = 1 // ensure the reader is seekable. +}; + struct FResourceEntry { size_t Length; @@ -156,7 +164,8 @@ public: return (entry < NumLumps) ? Entries[entry].Position : 0; } - virtual FileReader GetEntryReader(uint32_t entry, bool newreader = true); + // default is the safest reader type. + virtual FileReader GetEntryReader(uint32_t entry, int readertype = READER_NEW, int flags = READERFLAG_SEEKABLE); int GetEntryFlags(uint32_t entry) { @@ -180,8 +189,8 @@ public: virtual FileData Read(int entry) { - auto fr = GetEntryReader(entry, false); - return fr.Read(); + auto fr = GetEntryReader(entry, READER_SHARED, 0); + return fr.Read(entry < NumLumps ? Entries[entry].Length : 0); } virtual FCompressedBuffer GetRawData(uint32_t entry); diff --git a/src/common/filesystem/source/file_7z.cpp b/src/common/filesystem/source/file_7z.cpp index ddb58f5ae7..e709c36418 100644 --- a/src/common/filesystem/source/file_7z.cpp +++ b/src/common/filesystem/source/file_7z.cpp @@ -180,7 +180,7 @@ public: bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); virtual ~F7ZFile(); FileData Read(int entry) override; - FileReader GetEntryReader(uint32_t entry, bool) override; + FileReader GetEntryReader(uint32_t entry, int, int) override; }; @@ -335,7 +335,7 @@ FileData F7ZFile::Read(int entry) // //========================================================================== -FileReader F7ZFile::GetEntryReader(uint32_t entry, bool) +FileReader F7ZFile::GetEntryReader(uint32_t entry, int, int) { FileReader fr; if (entry < 0 || entry >= NumLumps) return fr; diff --git a/src/common/filesystem/source/file_directory.cpp b/src/common/filesystem/source/file_directory.cpp index 0339e3a71a..0b9c101cea 100644 --- a/src/common/filesystem/source/file_directory.cpp +++ b/src/common/filesystem/source/file_directory.cpp @@ -64,7 +64,7 @@ class FDirectory : public FResourceFile public: FDirectory(const char * dirname, StringPool* sp, bool nosubdirflag = false); bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); - FileReader GetEntryReader(uint32_t entry, bool newreader = true) override; + FileReader GetEntryReader(uint32_t entry, int, int) override; }; @@ -162,13 +162,18 @@ bool FDirectory::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) // //========================================================================== -FileReader FDirectory::GetEntryReader(uint32_t entry, bool newreader) +FileReader FDirectory::GetEntryReader(uint32_t entry, int readertype, int) { FileReader fr; if (entry < NumLumps) { std::string fn = mBasePath; fn += Entries[entry].FileName; fr.OpenFile(fn.c_str()); + if (readertype == READER_CACHED) + { + auto data = fr.Read(); + fr.OpenMemoryArray(data); + } } return fr; } diff --git a/src/common/filesystem/source/files_decompress.cpp b/src/common/filesystem/source/files_decompress.cpp index 899f59af4a..95c6c7f9b7 100644 --- a/src/common/filesystem/source/files_decompress.cpp +++ b/src/common/filesystem/source/files_decompress.cpp @@ -940,7 +940,7 @@ bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size len return false; } fr = new MemoryArrayReader(buffer); - flags &= ~DCF_SEEKABLE; + flags &= ~(DCF_SEEKABLE | DCF_CACHED); break; } @@ -949,7 +949,7 @@ bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size len FileData buffer(nullptr, length); ShrinkLoop(buffer.writable(), length, *p, p->GetLength()); // this never fails. fr = new MemoryArrayReader(buffer); - flags &= ~DCF_SEEKABLE; + flags &= ~(DCF_SEEKABLE | DCF_CACHED); break; } @@ -965,7 +965,7 @@ bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size len bufr[i] ^= i >> 1; } fr = new MemoryArrayReader(buffer); - flags &= ~DCF_SEEKABLE; + flags &= ~(DCF_SEEKABLE | DCF_CACHED); break; } @@ -980,7 +980,14 @@ bool OpenDecompressor(FileReader& self, FileReader &parent, FileReader::Size len } dec->Length = length; } - if ((flags & DCF_SEEKABLE)) + if ((flags & DCF_CACHED)) + { + // read everything into a MemoryArrayReader. + FileData data(nullptr, length); + fr->Read(data.writable(), length); + fr = new MemoryArrayReader(data); + } + else if ((flags & DCF_SEEKABLE)) { // create a wrapper that can buffer the content so that seeking is possible fr = new BufferingReader(fr); diff --git a/src/common/filesystem/source/filesystem.cpp b/src/common/filesystem/source/filesystem.cpp index d418c3631c..86029186e1 100644 --- a/src/common/filesystem/source/filesystem.cpp +++ b/src/common/filesystem/source/filesystem.cpp @@ -396,7 +396,7 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf std::string path = filename; path += ':'; path += resfile->getName(i); - auto embedded = resfile->GetEntryReader(i, true); + auto embedded = resfile->GetEntryReader(i, READER_NEW, READERFLAG_SEEKABLE); AddFile(path.c_str(), &embedded, filter, Printf, hashfile); } } @@ -428,7 +428,7 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInf int flags = resfile->GetEntryFlags(i); if (!(flags & RESFF_EMBEDDED)) { - auto reader = resfile->GetEntryReader(i, true); + auto reader = resfile->GetEntryReader(i, READER_SHARED, 0); md5Hash(filereader, cksum); for (size_t j = 0; j < sizeof(cksum); ++j) @@ -1306,7 +1306,7 @@ FileData FileSystem::ReadFile (int lump) //========================================================================== -FileReader FileSystem::OpenFileReader(int lump) +FileReader FileSystem::OpenFileReader(int lump, int readertype, int readerflags) { if ((unsigned)lump >= (unsigned)FileInfo.size()) { @@ -1314,18 +1314,7 @@ FileReader FileSystem::OpenFileReader(int lump) } auto file = FileInfo[lump].resfile; - return file->GetEntryReader(FileInfo[lump].resindex, false); -} - -FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache) -{ - if ((unsigned)lump >= (unsigned)FileInfo.size()) - { - throw FileSystemException("ReopenFileReader: %u >= NumEntries", lump); - } - - auto file = FileInfo[lump].resfile; - return file->GetEntryReader(FileInfo[lump].resindex, true); + return file->GetEntryReader(FileInfo[lump].resindex, readertype, readerflags); } FileReader FileSystem::OpenFileReader(const char* name) diff --git a/src/common/filesystem/source/resourcefile.cpp b/src/common/filesystem/source/resourcefile.cpp index f26327713e..3a64cf13b6 100644 --- a/src/common/filesystem/source/resourcefile.cpp +++ b/src/common/filesystem/source/resourcefile.cpp @@ -211,7 +211,7 @@ FCompressedBuffer FResourceFile::GetRawData(uint32_t entry) FCompressedBuffer cbuf = { LumpSize, LumpSize, METHOD_STORED, 0, 0, LumpSize == 0? nullptr : new char[LumpSize] }; if (LumpSize > 0) { - auto fr = GetEntryReader(entry); + auto fr = GetEntryReader(entry, READER_SHARED, 0); size_t read = fr.Read(cbuf.mBuffer, LumpSize); if (read < LumpSize) { @@ -542,7 +542,7 @@ int FResourceFile::FindEntry(const char *name) // //========================================================================== -FileReader FResourceFile::GetEntryReader(uint32_t entry, bool newreader) +FileReader FResourceFile::GetEntryReader(uint32_t entry, int readertype, int readerflags) { FileReader fr; if (entry < NumLumps) @@ -553,20 +553,30 @@ FileReader FResourceFile::GetEntryReader(uint32_t entry, bool newreader) } if (!(Entries[entry].Flags & RESFF_COMPRESSED)) { - if (!newreader) + if (readertype == READER_SHARED) { fr.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].Length); } - else + else if (readertype == READER_NEW) { fr.OpenFile(FileName, Entries[entry].Position, Entries[entry].Length); } + else if (readertype == READER_CACHED) + { + Reader.Seek(Entries[entry].Position, FileReader::SeekSet); + auto data = Reader.Read(Entries[entry].Length); + fr.OpenMemoryArray(data); + } } else { FileReader fri; - fri.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].CompressedSize); - OpenDecompressor(fr, fri, Entries[entry].Length, Entries[entry].Method, FileSys::DCF_TRANSFEROWNER | FileSys::DCF_SEEKABLE | FileSys::DCF_EXCEPTIONS); + if (readertype == READER_NEW) fri.OpenFile(FileName, Entries[entry].Position, Entries[entry].CompressedSize); + else fri.OpenFilePart(Reader, Entries[entry].Position, Entries[entry].CompressedSize); + int flags = DCF_TRANSFEROWNER | DCF_EXCEPTIONS; + if (readertype == READER_CACHED) flags |= DCF_CACHED; + else if (readerflags & READERFLAG_SEEKABLE) flags |= DCF_SEEKABLE; + OpenDecompressor(fr, fri, Entries[entry].Length, Entries[entry].Method, flags); } } return fr; diff --git a/src/common/menu/savegamemanager.cpp b/src/common/menu/savegamemanager.cpp index 9efece88b2..3f2243a870 100644 --- a/src/common/menu/savegamemanager.cpp +++ b/src/common/menu/savegamemanager.cpp @@ -316,7 +316,7 @@ unsigned FSavegameManagerBase::ExtractSaveData(int index) auto pic = resf->FindEntry("savepic.png"); if (pic >= 0) { - FileReader picreader = resf->GetEntryReader(pic, true); + FileReader picreader = resf->GetEntryReader(pic, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE); PNGHandle *png = M_VerifyPNG(picreader); if (png != nullptr) { diff --git a/src/maploader/glnodes.cpp b/src/maploader/glnodes.cpp index 6c97065a3a..b41b22c0b9 100644 --- a/src/maploader/glnodes.cpp +++ b/src/maploader/glnodes.cpp @@ -798,7 +798,7 @@ static int FindGLNodesInFile(FResourceFile * f, const char * label) if (mustcheck) { char check[16]={0}; - auto fr = f->GetEntryReader(i, false); + auto fr = f->GetEntryReader(i, FileSys::READER_SHARED); fr.Read(check, 16); if (MatchHeader(label, check)) return i; } @@ -906,7 +906,7 @@ bool MapLoader::LoadGLNodes(MapData * map) break; } else - gwalumps[i] = f_gwa->GetEntryReader(li + i + 1); + gwalumps[i] = f_gwa->GetEntryReader(li + i + 1, FileSys::READER_NEW, FileSys::READERFLAG_SEEKABLE); } if (result) result = DoLoadGLNodes(gwalumps); } diff --git a/src/p_openmap.cpp b/src/p_openmap.cpp index 722ae18f92..ef688cda6b 100644 --- a/src/p_openmap.cpp +++ b/src/p_openmap.cpp @@ -280,7 +280,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) char maplabel[9]=""; int index=0; - map->MapLumps[0].Reader = map->resource->GetEntryReader(0); + map->MapLumps[0].Reader = map->resource->GetEntryReader(0, FileSys::READER_SHARED); uppercopy(map->MapLumps[0].Name, map->resource->getName(0)); for(uint32_t i = 1; i < map->resource->EntryCount(); i++) @@ -290,7 +290,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) if (i == 1 && !strnicmp(lumpname, "TEXTMAP", 8)) { map->isText = true; - map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetEntryReader(i); + map->MapLumps[ML_TEXTMAP].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[ML_TEXTMAP].Name, lumpname, 8); for(int i = 2;; i++) { @@ -326,7 +326,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) return map; } else continue; - map->MapLumps[index].Reader = map->resource->GetEntryReader(i); + map->MapLumps[index].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[index].Name, lumpname, 8); } } @@ -358,7 +358,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) maplabel[8]=0; } - map->MapLumps[index].Reader = map->resource->GetEntryReader(i); + map->MapLumps[index].Reader = map->resource->GetEntryReader(i, FileSys::READER_SHARED); strncpy(map->MapLumps[index].Name, lumpname, 8); } }