diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 95b67a2d8..2af200c2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1096,6 +1096,7 @@ set (PCH_SOURCES common/engine/cycler.cpp common/engine/d_event.cpp common/engine/date.cpp + common/engine/filesys_doom.cpp common/engine/stats.cpp common/engine/sc_man.cpp common/engine/palettecontainer.cpp @@ -1230,6 +1231,7 @@ set( GAME_SOURCES common/filesystem/source/file_whres.cpp common/filesystem/source/file_ssi.cpp common/filesystem/source/file_hog.cpp + common/filesystem/source/file_hog2.cpp common/filesystem/source/file_mvl.cpp common/filesystem/source/file_directory.cpp common/filesystem/source/resourcefile.cpp diff --git a/src/common/engine/filesys_doom.cpp b/src/common/engine/filesys_doom.cpp new file mode 100644 index 000000000..96a413358 --- /dev/null +++ b/src/common/engine/filesys_doom.cpp @@ -0,0 +1,648 @@ +/* +** filesys_doom.cpp +** +** the very special lump name lookup code for Doom's short names. +** Not useful in a generic system. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2024 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "filesystem.h" +#include "printf.h" + +//========================================================================== +// +// +// +//========================================================================== + +void FileSystem::InitHashChains() +{ + Super::InitHashChains(); + unsigned NumEntries = GetNumEntries(); + for (unsigned i = 0; i < (unsigned)NumEntries; i++) + { + files[i].HashFirst = files[i].HashNext = NULL_INDEX; + } + // Now set up the chains + for (unsigned i = 0; i < (unsigned)NumEntries; i++) + { + if (files[i].Namespace == ns_hidden || files[i].ShortName[0] == 0) continue; + unsigned j = FileSys::MakeHash(files[i].ShortName, 8) % NumEntries; + files[i].HashNext = files[j].HashFirst; + files[j].HashFirst = i; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +static void UpperCopy(char* to, const char* from) +{ + int i; + + for (i = 0; i < 8 && from[i]; i++) + to[i] = toupper(from[i]); + for (; i < 8; i++) + to[i] = 0; + to[8] = 0; +} + +//========================================================================== +// +// +// +//========================================================================== + +void FileSystem::SetupName(int fileindex) +{ + const char* name = GetFileName(fileindex); + int containerflags = GetResourceFileFlags(GetFileContainer(fileindex)); + int lflags = GetFileFlags(fileindex); + + if ((containerflags & wadflags) == wadflags) + { + UpperCopy(files[fileindex].ShortName, name); + } + else if ((lflags & FileSys::RESFF_EMBEDDED) || !*name) + { + files[fileindex].Namespace = ns_hidden; + } + else + { + if (lflags & FileSys::RESFF_FULLPATH) files[fileindex].Flags |= LUMPF_FULLPATH; // copy for easier access in lookup function. + auto slash = strrchr(name, '/'); + auto base = slash ? (slash + 1) : name; + UpperCopy(files[fileindex].ShortName, base); + auto dot = strrchr(files[fileindex].ShortName, '.'); + if (dot) while (*dot) *dot++ = 0; + } +} + + +//========================================================================== +// +// IsMarker +// +// (from BOOM) +// +//========================================================================== + +inline bool FileSystem::IsMarker(int lump, const char* marker) noexcept +{ + auto name = files[lump].ShortName; + if (name[0] == marker[0]) + { + return (!strcmp(name, marker) || + (marker[1] == '_' && !strcmp(name + 1, marker))); + } + else return false; +} + +//========================================================================== +// +// SetNameSpace +// +// Sets namespace information for the lumps. It always looks for the first +// x_START and the last x_END lump, except when loading flats. In this case +// F_START may be absent and if that is the case all lumps with a size of +// 4096 will be flagged appropriately. +// +//========================================================================== + +// This class was supposed to be local in the function but GCC +// does not like that. +struct Marker +{ + int markertype; + int index; +}; + +void FileSystem::SetNamespace(int filenum, const char* startmarker, const char* endmarker, namespace_t space, FileSys::FileSystemMessageFunc Printf, bool flathack) +{ + using FileSys::FSMessageLevel; + bool warned = false; + int numstartmarkers = 0, numendmarkers = 0; + TArray markers; + int FirstLump = GetFirstEntry(filenum); + int LastLump = GetLastEntry(filenum); + auto FileName = GetResourceFileName(filenum); + + for (int i = FirstLump; i <= LastLump; i++) + { + if (IsMarker(i, startmarker)) + { + Marker m = { 0, i }; + markers.push_back(m); + numstartmarkers++; + } + else if (IsMarker(i, endmarker)) + { + Marker m = { 1, i }; + markers.push_back(m); + numendmarkers++; + } + } + + if (numstartmarkers == 0) + { + if (numendmarkers == 0) return; // no markers found + + if (Printf) + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); + + + if (flathack) + { + // We have found no F_START but one or more F_END markers. + // mark all lumps before the last F_END marker as potential flats. + unsigned int end = markers[markers.size() - 1].index; + for (int ii = FirstLump; ii <= LastLump; ii++) + { + if (FileLength(ii) == 4096) + { + // We can't add this to the flats namespace but + // it needs to be flagged for the texture manager. + if (Printf) Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName, files[ii].ShortName); + files[ii].Namespace = ns_maybeflat; + } + } + } + return; + } + + size_t i = 0; + while (i < markers.size()) + { + int start, end; + if (markers[i].markertype != 0) + { + if (Printf) Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); + i++; + continue; + } + start = int(i++); + + // skip over subsequent x_START markers + while (i < markers.size() && markers[i].markertype == 0) + { + if (Printf) Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, startmarker); + i++; + continue; + } + // same for x_END markers + while (i < markers.size() - 1 && (markers[i].markertype == 1 && markers[i + 1].markertype == 1)) + { + if (Printf) Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, endmarker); + i++; + continue; + } + // We found a starting marker but no end marker. Ignore this block. + if (i >= markers.size()) + { + if (Printf) Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, startmarker, endmarker); + end = LastLump + 1; + } + else + { + end = markers[i++].index; + } + + // we found a marked block + if (Printf) Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName, startmarker, markers[start].index, end); + for (int j = markers[start].index + 1; j < end; j++) + { + if (files[j].Namespace != ns_global) + { + if (!warned && Printf) + { + Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName, j); + } + warned = true; + } + else if (space == ns_sprites && FileLength(j) < 8) + { + // sf 26/10/99: + // ignore sprite lumps smaller than 8 bytes (the smallest possible) + // in size -- this was used by some dmadds wads + // as an 'empty' graphics resource + if (Printf) Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName, files[j].ShortName, j); + } + else + { + files[j].Namespace = space; + } + } + } +} + + +//========================================================================== +// +// W_SkinHack +// +// Tests a wad file to see if it contains an S_SKIN marker. If it does, +// every lump in the wad is moved into a new namespace. Because skins are +// only supposed to replace player sprites, sounds, or faces, this should +// not be a problem. Yes, there are skins that replace more than that, but +// they are such a pain, and breaking them like this was done on purpose. +// This also renames any S_SKINxx lumps to just S_SKIN. +// +//========================================================================== + +void FileSystem::SkinHack(int filenum, FileSys::FileSystemMessageFunc Printf) +{ + using FileSys::FSMessageLevel; + // this being static is not a problem. The only relevant thing is that each skin gets a different number. + bool skinned = false; + bool hasmap = false; + + int FirstLump = GetFirstEntry(filenum); + int LastLump = GetLastEntry(filenum); + auto FileName = GetResourceFileName(filenum); + + for (int i = FirstLump; i <= LastLump; i++) + { + auto lump = &files[i]; + + if (!strnicmp(lump->ShortName, "S_SKIN", 6)) + { // Wad has at least one skin. + lump->ShortName[6] = 0; + lump->ShortName[7] = 0; + if (!skinned) + { + skinned = true; + + for (int j = FirstLump; j <= LastLump; j++) + { + files[j].Namespace = skin_namespc; + } + skin_namespc++; + } + } + // needless to say, this check is entirely useless these days as map names can be more diverse.. + if ((lump->ShortName[0] == 'M' && + lump->ShortName[1] == 'A' && + lump->ShortName[2] == 'P' && + lump->ShortName[3] >= '0' && lump->ShortName[3] <= '9' && + lump->ShortName[4] >= '0' && lump->ShortName[4] <= '9' && + lump->ShortName[5] == '\0') + || + (lump->ShortName[0] == 'E' && + lump->ShortName[1] >= '0' && lump->ShortName[1] <= '9' && + lump->ShortName[2] == 'M' && + lump->ShortName[3] >= '0' && lump->ShortName[3] <= '9' && + lump->ShortName[4] == '\0')) + { + hasmap = true; + } + } + if (skinned && hasmap && Printf) + { + Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName); + Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n"); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FileSystem::SetupNamespace(int filenum, FileSys::FileSystemMessageFunc Printf) +{ + int flags = GetResourceFileFlags(filenum); + + // Set namespace for entries from WADs. + if ((flags & wadflags) == wadflags) + { + SetNamespace(filenum, "S_START", "S_END", ns_sprites, Printf); + SetNamespace(filenum, "F_START", "F_END", ns_flats, Printf, true); + SetNamespace(filenum, "C_START", "C_END", ns_colormaps, Printf); + SetNamespace(filenum, "A_START", "A_END", ns_acslibrary, Printf); + SetNamespace(filenum, "TX_START", "TX_END", ns_newtextures, Printf); + SetNamespace(filenum, "V_START", "V_END", ns_strifevoices, Printf); + SetNamespace(filenum, "HI_START", "HI_END", ns_hires, Printf); + SetNamespace(filenum, "VX_START", "VX_END", ns_voxels, Printf); + SkinHack(filenum, Printf); + } + else if (!(flags & FResourceFile::NO_FOLDERS)) + { + int FirstLump = GetFirstEntry(filenum); + int LastLump = GetLastEntry(filenum); + auto FileName = GetResourceFileName(filenum); + + for (int i = FirstLump; i <= LastLump; i++) + { + auto lump = &files[i]; + + auto LongName = GetFileName(i); + // Map some directories to WAD namespaces. + // Note that some of these namespaces don't exist in WADS. + // CheckNumForName will handle any request for these namespaces accordingly. + int Namespace = !strncmp(LongName, "flats/", 6) ? ns_flats : + !strncmp(LongName, "textures/", 9) ? ns_newtextures : + !strncmp(LongName, "hires/", 6) ? ns_hires : + !strncmp(LongName, "sprites/", 8) ? ns_sprites : + !strncmp(LongName, "voxels/", 7) ? ns_voxels : + !strncmp(LongName, "colormaps/", 10) ? ns_colormaps : + !strncmp(LongName, "acs/", 4) ? ns_acslibrary : + !strncmp(LongName, "voices/", 7) ? ns_strifevoices : + !strncmp(LongName, "patches/", 8) ? ns_patches : + !strncmp(LongName, "graphics/", 9) ? ns_graphics : + !strncmp(LongName, "sounds/", 7) ? ns_sounds : + !strncmp(LongName, "music/", 6) ? ns_music : + !strchr(LongName, '/') ? ns_global : + ns_hidden; + + lump->Namespace = Namespace; + + switch (Namespace) + { + case ns_hidden: + memset(lump->ShortName, 0, sizeof(lump->ShortName)); + break; + + case ns_sprites: + case ns_voxels: + case ns_hires: + // Since '\' can't be used as a file name's part inside a ZIP + // we have to work around this for sprites because it is a valid + // frame character. + for (auto& c : lump->ShortName) + { + if (c == '^') c = '\\'; + } + break; + } + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +bool FileSystem::InitFiles(std::vector& filenames, FileSys::FileSystemFilterInfo* filter, FileSys::FileSystemMessageFunc Printf, bool allowduplicates) +{ + if (!Super::InitFiles(filenames, filter, Printf, allowduplicates)) return false; + files.Resize(GetNumEntries()); + memset(files.Data(), 0, sizeof(files[0]) * files.size()); + int numfiles = GetNumEntries(); + for (int i = 0; i < numfiles; i++) + { + SetupName(i); + } + + int numresfiles = GetNumWads(); + for (int i = 0; i < numresfiles; i++) + { + SetupNamespace(i, Printf); + } + return true; +} + +//========================================================================== +// +// CheckNumForName +// +// Returns -1 if name not found. The version with a third parameter will +// look exclusively in the specified wad for the lump. +// +// [RH] Changed to use hash lookup ala BOOM instead of a linear search +// and namespace parameter +//========================================================================== + +int FileSystem::CheckNumForName(const char* name, int space) const +{ + char uname[9]; + uint32_t i; + + if (name == nullptr) + { + return -1; + } + + // Let's not search for names that are longer than 8 characters and contain path separators + // They are almost certainly full path names passed to this function. + if (strlen(name) > 8 && strpbrk(name, "/.")) + { + return -1; + } + + UpperCopy(uname, name); + i = files[FileSys::MakeHash(uname, 8) % files.Size()].HashFirst; + + while (i != NULL_INDEX) + { + auto& lump = files[i]; + + if (!memcmp(lump.ShortName, uname, 8)) + { + if (lump.Namespace == space) break; + // If the lump is from one of the special namespaces exclusive to Zips + // the check has to be done differently: + // If we find a lump with this name in the global namespace that does not come + // from a Zip return that. WADs don't know these namespaces and single lumps must + // work as well. + if (space > ns_specialzipdirectory && lump.Namespace == ns_global && !(lump.Flags & LUMPF_FULLPATH)) + break; + } + i = lump.HashNext; + } + + return i != NULL_INDEX ? i : -1; +} + +int FileSystem::CheckNumForName(const char* name, int space, int rfnum, bool exact) const +{ + char uname[9]; + uint32_t i; + + if (rfnum < 0) + { + return CheckNumForName(name, space); + } + + UpperCopy(uname, name); + i = files[FileSys::MakeHash(uname, 8) % files.Size()].HashFirst; + + // If exact is true if will only find lumps in the same WAD, otherwise + // also those in earlier WADs. + + while (i != NULL_INDEX && + (memcmp(files[i].ShortName, uname, 8) || files[i].Namespace != space || + (exact ? (GetFileContainer(i) != rfnum) : (GetFileContainer(i) > rfnum)))) + { + i = files[i].HashNext; + } + + return i != NULL_INDEX ? i : -1; +} + +//========================================================================== +// +// GetNumForName +// +// Calls CheckNumForName, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetNumForName(const char* name, int space) const +{ + int i; + + i = CheckNumForName(name, space); + + if (i == -1) + throw FileSys::FileSystemException("GetNumForName: %s not found!", name); + + return i; +} + + + +//========================================================================== +// +// returns a modifiable pointer to the short name +// +// should only be called before the hash chains are set up. +// If done later this needs rehashing. +// +// This is for custom setup through postprocessFunc +// +//========================================================================== + +char* FileSystem::GetShortName(int i) +{ + if ((unsigned)i >= files.Size()) + throw FileSys::FileSystemException("GetShortName: Invalid index"); + return files[i].ShortName; +} + +//========================================================================== +// +// W_FindLump +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. +// +//========================================================================== + +int FileSystem::FindLump(const char* name, int* lastlump, bool anyns) +{ + if ((size_t)*lastlump >= files.size()) return -1; + char name8[9]; + UpperCopy(name8, name); + + assert(lastlump != nullptr && *lastlump >= 0); + + const int last = (int)files.size(); + + for(int lump = *lastlump; lump < last; lump++) + { + const FileEntry* const lump_p = &files[lump]; + if ((anyns || lump_p->Namespace == ns_global) && !memcmp(lump_p->ShortName, name8, 8)) + { + *lastlump = lump + 1; + return lump; + } + } + + *lastlump = last; + return -1; +} + +//========================================================================== +// +// W_FindLumpMulti +// +// Find a named lump. Specifically allows duplicates for merging of e.g. +// SNDINFO lumps. Returns everything having one of the passed names. +// +//========================================================================== + +int FileSystem::FindLumpMulti(const char** names, int* lastlump, bool anyns, int* nameindex) +{ + assert(lastlump != nullptr && *lastlump >= 0); + + int last = files.Size(); + + for (int lump = *lastlump; lump < last; lump++) + { + auto lump_p = &files[lump]; + if (anyns || lump_p->Namespace == ns_global) + { + for (const char** name = names; *name != nullptr; name++) + { + if (!strnicmp(*name, lump_p->ShortName, 8)) + { + *lastlump = lump + 1; + if (nameindex != nullptr) *nameindex = int(name - names); + return lump; + } + } + } + } + + *lastlump = last; + return -1; +} + +//========================================================================== +// +// This function combines lookup from regular lists and Doom's special one. +// +//========================================================================== + +int FileSystem::CheckNumForAnyName(const char* name, namespace_t namespc) const +{ + if (name != NULL) + { + // Check short names first to avoid interference from short names in the real file system. + if (strlen(name) <= 8 && !strpbrk(name, "./")) + { + return CheckNumForName(name, namespc); + } + + int lookup = Super::CheckNumForFullName(name, false); + if (lookup >= 0) return lookup; + } + return -1; +} + diff --git a/src/common/engine/filesystem.h b/src/common/engine/filesystem.h index 53f491677..f8a791e7b 100644 --- a/src/common/engine/filesystem.h +++ b/src/common/engine/filesystem.h @@ -1,7 +1,129 @@ #pragma once #include "fs_filesystem.h" -using FileSys::FileSystem; using FileSys::FResourceFile; -inline FileSys::FileSystem fileSystem; +// [RH] Namespaces from BOOM. +// These are needed here in the low level part so that WAD files can be properly set up. +enum namespace_t : int { + ns_hidden = -1, + + ns_global = 0, + ns_sprites, + ns_flats, + ns_colormaps, + ns_acslibrary, + ns_newtextures, + ns_bloodraw, // no longer used - kept for ZScript. + ns_bloodsfx, // no longer used - kept for ZScript. + ns_bloodmisc, // no longer used - kept for ZScript. + ns_strifevoices, + ns_hires, + ns_voxels, + ns_maybeflat, + + // These namespaces are only used to mark lumps in special subdirectories + // so that their contents doesn't interfere with the global namespace. + // searching for data in these namespaces works differently for lumps coming + // from Zips or other files. + ns_specialzipdirectory, + ns_sounds, + ns_patches, + ns_graphics, + ns_music, + + ns_firstskin, +}; + + +// extended class that adds Doom's very special short name lookup to the file system. +class FileSystem : public FileSys::FileSystem +{ +private: + struct FileEntry + { + char ShortName[9]; + uint8_t Namespace; + uint8_t Flags; + uint32_t HashFirst; + uint32_t HashNext; + }; + + const int wadflags = FileSys::FResourceFile::NO_EXTENSIONS | FileSys::FResourceFile::NO_FOLDERS | FileSys::FResourceFile::SHORTNAMES; + const uint32_t NULL_INDEX = 0xffffffff; + + TArray files; + int skin_namespc = ns_firstskin; + + + void Start(FileSys::FileSystemMessageFunc Printf); + void SetupName(int fileindex); + bool IsMarker(int lump, const char* marker) noexcept; + void SetNamespace(int filenum, const char* startmarker, const char* endmarker, namespace_t space, FileSys::FileSystemMessageFunc Printf, bool flathack = false); + void SkinHack(int filenum, FileSys::FileSystemMessageFunc Printf); + void SetupNamespace(int filenum, FileSys::FileSystemMessageFunc Printf); + + using Super = FileSys::FileSystem; + +public: + enum + { + LUMPF_MAYBEFLAT = 1, + LUMPF_FULLPATH = 2, + }; + + bool InitFiles(std::vector& filenames, FileSys::FileSystemFilterInfo* filter = nullptr, FileSys::FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false) override; + void InitHashChains() override; + + int CheckNumForAnyName(const char* cname, namespace_t namespc = ns_global) const; + + int CheckNumForName(const char* name, int namespc) const; + int CheckNumForName(const char* name, int namespc, int wadfile, bool exact = true) const; + int GetNumForName(const char* name, int namespc) const; + + inline int CheckNumForName(const uint8_t* name) const { return CheckNumForName((const char*)name, ns_global); } + inline int CheckNumForName(const char* name) const { return CheckNumForName(name, ns_global); } + inline int CheckNumForName(const uint8_t* name, int ns) const { return CheckNumForName((const char*)name, ns); } + inline int GetNumForName(const char* name) const { return GetNumForName(name, ns_global); } + inline int GetNumForName(const uint8_t* name) const { return GetNumForName((const char*)name); } + inline int GetNumForName(const uint8_t* name, int ns) const { return GetNumForName((const char*)name, ns); } + + 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 = nullptr); // same with multiple possible names + + bool CheckFileName(int lump, const char* name) const noexcept + { + if ((size_t)lump >= files.size()) + return false; + + return !strnicmp(files[lump].ShortName, name, 8); + } + + const char* GetFileShortName(int lump) const noexcept + { + if ((size_t)lump >= files.size()) + return nullptr; + else + return files[lump].ShortName; + } + + int GetFileNamespace(int lump) const noexcept + { + if ((size_t)lump >= files.size()) + return ns_global; + else + return files[lump].Namespace; + } + + void SetFileNamespace(int lump, int ns) noexcept + { + if ((size_t)lump < files.size()) files[lump].Namespace = ns; + } + + // This is only for code that wants to edit the names before the game starts. + char* GetShortName(int i); + +}; + +inline FileSystem fileSystem; + diff --git a/src/common/filesystem/include/fs_filesystem.h b/src/common/filesystem/include/fs_filesystem.h index ce49d765f..c12dd2223 100644 --- a/src/common/filesystem/include/fs_filesystem.h +++ b/src/common/filesystem/include/fs_filesystem.h @@ -13,15 +13,6 @@ namespace FileSys { -union LumpShortName -{ - char String[9]; - - uint32_t dword; // These are for accessing the first 4 or 8 chars of - uint64_t qword; // Name as a unit without breaking strict aliasing rules -}; - - struct FolderEntry { const char *name; @@ -32,7 +23,12 @@ class FileSystem { public: FileSystem(); - ~FileSystem (); + virtual ~FileSystem (); + // do not copy! + FileSystem(const FileSystem& other) = delete; + FileSystem& operator =(const FileSystem& other) = delete; + + bool Initialize(std::vector& filenames, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false); // The wadnum for the IWAD int GetIwadNum() { return IwadIndex; } @@ -41,9 +37,6 @@ public: int GetMaxIwadNum() { return MaxIwadIndex; } void SetMaxIwadNum(int x) { MaxIwadIndex = x; } - bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr); - bool InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false); - void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf); int CheckIfResourceFileLoaded (const char *name) noexcept; void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} @@ -53,31 +46,17 @@ public: int GetFirstEntry(int wadnum) const noexcept; int GetLastEntry(int wadnum) const noexcept; int GetEntryCount(int wadnum) const noexcept; + int GetResourceFileFlags(int wadnum) const noexcept; - int CheckNumForName (const char *name, int namespc) const; - int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true) const; - int GetNumForName (const char *name, int namespc) const; - - inline int CheckNumForName (const uint8_t *name) const { return CheckNumForName ((const char *)name, ns_global); } - inline int CheckNumForName (const char *name) const { return CheckNumForName (name, ns_global); } - inline int CheckNumForName (const uint8_t *name, int ns) const { return CheckNumForName ((const char *)name, ns); } - inline int GetNumForName (const char *name) const { return GetNumForName (name, ns_global); } - inline int GetNumForName (const uint8_t *name) const { return GetNumForName ((const char *)name); } - inline int GetNumForName (const uint8_t *name, int ns) const { return GetNumForName ((const char *)name, ns); } - - int CheckNumForFullName (const char *cname, bool trynormal = false, int namespc = ns_global, bool ignoreext = false) const; + int CheckNumForFullName (const char *cname, bool ignoreext = false) const; int CheckNumForFullNameInFile (const char *name, int wadfile) const; int GetNumForFullName (const char *name) const; - int CheckNumForAnyName(const char* cname, namespace_t namespc = ns_global) const - { - return CheckNumForFullName(cname, true, namespc); - } - int FindFile(const char* name) const { return CheckNumForFullName(name); } + bool FileExists(const char* name) const { return FindFile(name) >= 0; @@ -88,14 +67,12 @@ public: return FindFile(name.c_str()) >= 0; } - LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up. void RenameFile(int num, const char* fn); bool CreatePathlessCopy(const char* name, int id, int flags); void ReadFile (int lump, void *dest); // These should only be used if the file data really needs padding. FileData ReadFile (int lump); - FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); } FileData ReadFileFullName(const char* name) { return ReadFile(GetNumForFullName(name)); } FileReader OpenFileReader(int lump, int readertype, int readerflags); // opens a reader that redirects to the containing file's one. @@ -112,29 +89,21 @@ public: } - 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 int FindLumpFullName(const char* name, int* lastlump, bool noext = false); - bool CheckFileName (int lump, const char *name); // [RH] True if lump's name == name int FindFileWithExtensions(const char* name, const char* const* exts, int count) const; int FindResource(int resid, const char* type, int filenum = -1) const noexcept; int GetResource(int resid, const char* type, int filenum = -1) const; - static uint32_t LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name - - ptrdiff_t FileLength (int lump) const; + ptrdiff_t FileLength(int lump) const; int GetFileFlags (int lump); // Return the flags for this lump - const char* GetFileShortName(int lump) const; - const char *GetFileName (int lump, bool returnshort = true) const; // [RH] Returns the lump's full name + const char* GetFileName(int lump) const; // Gets uninterpreted name from the FResourceFile std::string GetFileFullPath (int lump) const; // [RH] Returns wad's name + lump's full name - int GetFileContainer (int lump) const; // [RH] Returns wadnum for a specified lump - int GetFileNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to - void SetFileNamespace(int lump, int ns); + int GetFileContainer (int lump) const; + // [RH] Returns wadnum for a specified lump int GetResourceId(int lump) const; // Returns the RFF index number for this lump const char* GetResourceType(int lump) const; - bool CheckFileName (int lump, const char *name) const; // [RH] Returns true if the names match unsigned GetFilesInFolder(const char *path, std::vector &result, bool atomic) const; int GetNumEntries() const @@ -149,18 +118,16 @@ public: int AddFromBuffer(const char* name, char* data, int size, int id, int flags); FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD - void InitHashChains(); protected: struct LumpRecord; + const uint32_t NULL_INDEX = 0xffffffff; std::vector Files; std::vector FileInfo; std::vector Hashes; // one allocation for all hash lists. - uint32_t *FirstLumpIndex = nullptr; // [RH] Hashing stuff moved out of lumpinfo structure - uint32_t *NextLumpIndex = nullptr; uint32_t *FirstLumpIndex_FullName = nullptr; // The same information for fully qualified paths from .zips uint32_t *NextLumpIndex_FullName = nullptr; @@ -182,7 +149,24 @@ protected: private: void DeleteAll(); void MoveLumpsInFolder(const char *); + void AddFile(const char* filename, FileReader* wadinfo, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf); +protected: + + // These two functions must be overridden by subclasses which want to extend the file system. + virtual bool InitFiles(std::vector& filenames, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false); +public: + virtual void InitHashChains(); }; +//djb2 hash algorithm with case insensitivity hack +inline static uint32_t MakeHash(const char* str, size_t length = SIZE_MAX) +{ + uint32_t hash = 5381; + uint32_t c; + while (length-- > 0 && (c = *str++)) hash = hash * 33 + (c | 32); + return hash; +} + + } \ No newline at end of file diff --git a/src/common/filesystem/include/resourcefile.h b/src/common/filesystem/include/resourcefile.h index e1a55ce7d..124a70158 100644 --- a/src/common/filesystem/include/resourcefile.h +++ b/src/common/filesystem/include/resourcefile.h @@ -16,7 +16,7 @@ std::string ExtractBaseName(const char* path, bool include_extension = false); void strReplace(std::string& str, const char* from, const char* to); // user context in which the file system gets opened. This also contains a few callbacks to avoid direct dependencies on the engine. -struct LumpFilterInfo +struct FileSystemFilterInfo { std::vector gameTypeFilter; // this can contain multiple entries @@ -45,45 +45,10 @@ using FileSystemMessageFunc = int(*)(FSMessageLevel msglevel, const char* format class FResourceFile; -} - -// [RH] Namespaces from BOOM. -// These are needed here in the low level part so that WAD files can be properly set up. -typedef enum { - ns_hidden = -1, - - ns_global = 0, - ns_sprites, - ns_flats, - ns_colormaps, - ns_acslibrary, - ns_newtextures, - ns_bloodraw, // no longer used - kept for ZScript. - ns_bloodsfx, // no longer used - kept for ZScript. - ns_bloodmisc, // no longer used - kept for ZScript. - ns_strifevoices, - ns_hires, - ns_voxels, - - // These namespaces are only used to mark lumps in special subdirectories - // so that their contents doesn't interfere with the global namespace. - // searching for data in these namespaces works differently for lumps coming - // from Zips or other files. - ns_specialzipdirectory, - ns_sounds, - ns_patches, - ns_graphics, - ns_music, - - ns_firstskin, -} namespace_t; - -namespace FileSys { enum ELumpFlags { - RESFF_MAYBEFLAT = 1, // might be a flat inside a WAD outside F_START/END - RESFF_FULLPATH = 2, // contains a full path. This will trigger extended namespace checks when looking up short names. + RESFF_FULLPATH = 2, // contains a full path. RESFF_EMBEDDED = 4, // marks an embedded resource file for later processing. RESFF_SHORTNAME = 8, // the stored name is a short extension-less name RESFF_COMPRESSED = 16, // compressed or encrypted, i.e. cannot be read with the container file's reader. @@ -104,11 +69,10 @@ struct FResourceEntry size_t CompressedSize; const char* FileName; size_t Position; - int ResourceID; + int ResourceID; // Only Blood RFF uses this natively. uint32_t CRC32; uint16_t Flags; uint16_t Method; - int16_t Namespace; }; void SetMainThread(); @@ -116,17 +80,25 @@ void SetMainThread(); class FResourceFile { public: - FResourceFile(const char* filename, StringPool* sp); - FResourceFile(const char* filename, FileReader& r, StringPool* sp); - const char* NormalizeFileName(const char* fn, int fallbackcp = 0); + enum + { + // descibes which kind of limitations this file type has. + NO_FOLDERS = 1, // no paths - only one rpot folder (e.g. Build GRP, Blood RFF, Descent HOG + NO_EXTENSIONS = 2, // no extensions for file names (e.g. Doom WADs.) + SHORTNAMES = 4, // Name is (at most) 8.3 DOS ASCII format, (8.0 in case of WAD) + }; + FResourceFile(const char* filename, StringPool* sp, int flags); + FResourceFile(const char* filename, FileReader& r, StringPool* sp, int flags); + const char* NormalizeFileName(const char* fn, int fallbackcp = 0, bool allowbackslash = false); FResourceEntry* AllocateEntries(int count); void GenerateHash(); - void PostProcessArchive(LumpFilterInfo* filter); + void PostProcessArchive(FileSystemFilterInfo* filter); protected: FileReader Reader; const char* FileName; FResourceEntry* Entries = nullptr; uint32_t NumLumps; + int flags = 0; char Hash[48]; StringPool* stringpool; @@ -136,7 +108,7 @@ protected: Entries[entry].Flags &= ~RESFF_NEEDFILESTART; } bool IsFileInFolder(const char* const resPath); - void CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi); + void CheckEmbedded(uint32_t entry, FileSystemFilterInfo* lfi); private: uint32_t FirstLump; @@ -144,18 +116,19 @@ private: int FilterLumps(const std::string& filtername, uint32_t max); bool FindPrefixRange(const char* filter, uint32_t max, uint32_t &start, uint32_t &end); void JunkLeftoverFilters(uint32_t max); - void FindCommonFolder(LumpFilterInfo* filter); - static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); + void FindCommonFolder(FileSystemFilterInfo* filter); + static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); public: - static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); - static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); - static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); + static FResourceFile *OpenDirectory(const char *filename, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr); virtual ~FResourceFile(); // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. FileReader *GetContainerReader() { return Reader.isOpen()? &Reader : nullptr; } const char* GetFileName() const { return FileName; } uint32_t GetFirstEntry() const { return FirstLump; } + int GetFlags() const noexcept { return flags; } void SetFirstLump(uint32_t f) { FirstLump = f; } const char* GetHash() const { return Hash; } @@ -179,11 +152,6 @@ public: return (entry < NumLumps) ? Entries[entry].Flags : 0; } - int GetEntryNamespace(uint32_t entry) - { - return (entry < NumLumps) ? Entries[entry].Namespace : (int)ns_hidden; - } - int GetEntryResourceID(uint32_t entry) { return (entry < NumLumps) ? Entries[entry].ResourceID : -1; diff --git a/src/common/filesystem/source/file_7z.cpp b/src/common/filesystem/source/file_7z.cpp index 21d6049e3..6a5e135e9 100644 --- a/src/common/filesystem/source/file_7z.cpp +++ b/src/common/filesystem/source/file_7z.cpp @@ -177,7 +177,7 @@ class F7ZFile : public FResourceFile public: F7ZFile(const char * filename, FileReader &filer, StringPool* sp); - bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf); virtual ~F7ZFile(); FileData Read(uint32_t entry) override; FileReader GetEntryReader(uint32_t entry, int, int) override; @@ -192,7 +192,7 @@ public: //========================================================================== F7ZFile::F7ZFile(const char * filename, FileReader &filer, StringPool* sp) - : FResourceFile(filename, filer, sp) + : FResourceFile(filename, filer, sp, 0) { Archive = nullptr; } @@ -204,7 +204,7 @@ F7ZFile::F7ZFile(const char * filename, FileReader &filer, StringPool* sp) // //========================================================================== -bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf) +bool F7ZFile::Open(FileSystemFilterInfo *filter, FileSystemMessageFunc Printf) { Archive = new C7zArchive(Reader); int skipped = 0; @@ -268,7 +268,6 @@ bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf) Entries[j].Length = SzArEx_GetFileSize(archPtr, i); Entries[j].Flags = RESFF_FULLPATH|RESFF_COMPRESSED; Entries[j].ResourceID = -1; - Entries[j].Namespace = ns_global; Entries[j].Method = METHOD_INVALID; Entries[j].Position = i; j++; @@ -351,7 +350,7 @@ FileReader F7ZFile::GetEntryReader(uint32_t entry, int, int) // //========================================================================== -FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *Check7Z(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[k7zSignatureSize]; diff --git a/src/common/filesystem/source/file_directory.cpp b/src/common/filesystem/source/file_directory.cpp index ca87fd9ea..40b4df2f9 100644 --- a/src/common/filesystem/source/file_directory.cpp +++ b/src/common/filesystem/source/file_directory.cpp @@ -57,11 +57,11 @@ class FDirectory : public FResourceFile const char** SystemFilePath; - int AddDirectory(const char* dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf); + int AddDirectory(const char* dirpath, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf); public: FDirectory(const char * dirname, StringPool* sp, bool nosubdirflag = false); - bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf); FileReader GetEntryReader(uint32_t entry, int, int) override; }; @@ -74,7 +74,7 @@ public: //========================================================================== FDirectory::FDirectory(const char * directory, StringPool* sp, bool nosubdirflag) - : FResourceFile("", sp), nosubdir(nosubdirflag) + : FResourceFile("", sp, 0), nosubdir(nosubdirflag) { auto fn = FS_FullPath(directory); if (fn.back() != '/') fn += '/'; @@ -87,7 +87,7 @@ FDirectory::FDirectory(const char * directory, StringPool* sp, bool nosubdirflag // //========================================================================== -int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf) +int FDirectory::AddDirectory(const char *dirpath, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf) { int count = 0; @@ -141,7 +141,6 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy Entries[count].Flags = RESFF_FULLPATH; Entries[count].ResourceID = -1; Entries[count].Method = METHOD_STORED; - Entries[count].Namespace = ns_global; Entries[count].Position = count; count++; } @@ -157,7 +156,7 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy // //========================================================================== -bool FDirectory::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) +bool FDirectory::Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf) { NumLumps = AddDirectory(FileName, filter, Printf); PostProcessArchive(filter); @@ -193,7 +192,7 @@ FileReader FDirectory::GetEntryReader(uint32_t entry, int readertype, int) // //========================================================================== -FResourceFile *CheckDir(const char *filename, bool nosubdirflag, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckDir(const char *filename, bool nosubdirflag, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { auto rf = new FDirectory(filename, sp, nosubdirflag); if (rf->Open(filter, Printf)) return rf; diff --git a/src/common/filesystem/source/file_grp.cpp b/src/common/filesystem/source/file_grp.cpp index 57206b4b1..25f79c6ec 100644 --- a/src/common/filesystem/source/file_grp.cpp +++ b/src/common/filesystem/source/file_grp.cpp @@ -71,7 +71,7 @@ struct GrpLump // //========================================================================== -static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter) +static bool OpenGrp(FResourceFile* file, FileSystemFilterInfo* filter) { GrpHeader header; @@ -91,7 +91,6 @@ static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter) Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].Size); Position += fileinfo[i].Size; Entries[i].Flags = 0; - Entries[i].Namespace = ns_global; fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated Entries[i].ResourceID = -1; Entries[i].Method = METHOD_STORED; @@ -109,7 +108,7 @@ static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter) // //========================================================================== -FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckGRP(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[12]; @@ -120,7 +119,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* file.Seek(0, FileReader::SeekSet); if (!memcmp(head, "KenSilverman", 12)) { - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES); if (OpenGrp(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_hog.cpp b/src/common/filesystem/source/file_hog.cpp index d12f7e2d8..0ed4fa7ce 100644 --- a/src/common/filesystem/source/file_hog.cpp +++ b/src/common/filesystem/source/file_hog.cpp @@ -44,7 +44,7 @@ namespace FileSys { -static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter) +static bool OpenHog(FResourceFile* rf, FileSystemFilterInfo* filter) { auto Reader = rf->GetContainerReader(); FileReader::Size length = Reader->GetLength(); @@ -66,7 +66,6 @@ static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter) Entry.CompressedSize = Entry.Length = elength; Entry.Flags = 0; Entry.CRC32 = 0; - Entry.Namespace = ns_global; Entry.ResourceID = -1; Entry.Method = METHOD_STORED; Entry.FileName = rf->NormalizeFileName(name); @@ -86,7 +85,7 @@ static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter) // //========================================================================== -FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile* CheckHog(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[3]; @@ -96,7 +95,7 @@ FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* file.Read(&head, 3); if (!memcmp(head, "DHF", 3)) { - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES); if (OpenHog(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_hog2.cpp b/src/common/filesystem/source/file_hog2.cpp new file mode 100644 index 000000000..10cc327cc --- /dev/null +++ b/src/common/filesystem/source/file_hog2.cpp @@ -0,0 +1,107 @@ +/* +** file_hog.cpp +** +** reads Descent 3 .hog2 files +** +**--------------------------------------------------------------------------- +** Copyright 2024 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +** +*/ + + +#include "resourcefile.h" +#include "fs_swap.h" + +namespace FileSys { + using namespace byteswap; + + + +static bool OpenHog2(FResourceFile* rf, FileSystemFilterInfo* filter) +{ + auto Reader = rf->GetContainerReader(); + FileReader::Size length = Reader->GetLength(); + + uint32_t numfiles = Reader->ReadUInt32(); + uint32_t offset = Reader->ReadUInt32(); // offset to first file (end of file list) + Reader->Seek(56, FileReader::SeekEnd); // filled with FF + auto Entries = rf->AllocateEntries((int)numfiles); + + for(uint32_t i = 0; i < numfiles; i++) + { + char name[37]; + Reader->Read(name, 36); + name[36] = 0; + Reader->ReadUInt32(); + uint32_t size = Reader->ReadUInt32();; + Reader->ReadUInt32(); + + FResourceEntry& Entry = Entries[i]; + Entry.Position = offset; + Entry.CompressedSize = Entry.Length = size; + Entry.Flags = RESFF_FULLPATH; + Entry.CRC32 = 0; + Entry.ResourceID = -1; + Entry.Method = METHOD_STORED; + Entry.FileName = rf->NormalizeFileName(name); + offset += size; + } + rf->GenerateHash(); + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile* CheckHog2(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +{ + char head[4]; + + if (file.GetLength() >= 68) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + if (!memcmp(head, "HOG2", 4)) + { + auto rf = new FResourceFile(filename, file, sp, 0); + if (OpenHog2(rf, filter)) return rf; + file = rf->Destroy(); + } + file.Seek(0, FileReader::SeekSet); + } + return nullptr; +} + + +} + diff --git a/src/common/filesystem/source/file_lump.cpp b/src/common/filesystem/source/file_lump.cpp index b01d46b5d..37dee28bd 100644 --- a/src/common/filesystem/source/file_lump.cpp +++ b/src/common/filesystem/source/file_lump.cpp @@ -41,11 +41,10 @@ namespace FileSys { // //========================================================================== -static bool OpenLump(FResourceFile* file, LumpFilterInfo*) +static bool OpenLump(FResourceFile* file, FileSystemFilterInfo*) { auto Entries = file->AllocateEntries(1); Entries[0].FileName = file->NormalizeFileName(ExtractBaseName(file->GetFileName(), true).c_str()); - Entries[0].Namespace = ns_global; Entries[0].ResourceID = -1; Entries[0].Position = 0; Entries[0].CompressedSize = Entries[0].Length = file->GetContainerReader()->GetLength(); @@ -60,10 +59,10 @@ static bool OpenLump(FResourceFile* file, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckLump(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { // always succeeds - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS); if (OpenLump(rf, filter)) return rf; file = rf->Destroy(); return NULL; diff --git a/src/common/filesystem/source/file_mvl.cpp b/src/common/filesystem/source/file_mvl.cpp index f08db3161..c9ebf0f8c 100644 --- a/src/common/filesystem/source/file_mvl.cpp +++ b/src/common/filesystem/source/file_mvl.cpp @@ -43,7 +43,7 @@ namespace FileSys { -static bool OpenMvl(FResourceFile* rf, LumpFilterInfo* filter) +static bool OpenMvl(FResourceFile* rf, FileSystemFilterInfo* filter) { auto Reader = rf->GetContainerReader(); auto count = Reader->ReadUInt32(); @@ -75,7 +75,7 @@ static bool OpenMvl(FResourceFile* rf, LumpFilterInfo* filter) // //========================================================================== -FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile* CheckMvl(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[4]; @@ -85,7 +85,7 @@ FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* file.Read(&head, 4); if (!memcmp(head, "DMVL", 4)) { - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES); if (OpenMvl(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_pak.cpp b/src/common/filesystem/source/file_pak.cpp index b66a0f3d9..84265f2eb 100644 --- a/src/common/filesystem/source/file_pak.cpp +++ b/src/common/filesystem/source/file_pak.cpp @@ -63,7 +63,7 @@ struct dpackheader_t // //========================================================================== -static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter) +static bool OpenPak(FResourceFile* file, FileSystemFilterInfo* filter) { dpackheader_t header; @@ -82,7 +82,6 @@ static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter) Entries[i].Position = LittleLong(fileinfo[i].filepos); Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].filelen); Entries[i].Flags = RESFF_FULLPATH; - Entries[i].Namespace = ns_global; Entries[i].ResourceID = -1; Entries[i].Method = METHOD_STORED; Entries[i].FileName = file->NormalizeFileName(fileinfo[i].name); @@ -99,7 +98,7 @@ static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter) // //========================================================================== -FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckPak(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[4]; @@ -110,7 +109,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* file.Seek(0, FileReader::SeekSet); if (!memcmp(head, "PACK", 4)) { - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, 0); if (OpenPak(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_rff.cpp b/src/common/filesystem/source/file_rff.cpp index 673a08ce0..e887b7fd7 100644 --- a/src/common/filesystem/source/file_rff.cpp +++ b/src/common/filesystem/source/file_rff.cpp @@ -91,7 +91,7 @@ void BloodCrypt (void *data, int key, int len) // //========================================================================== -static bool OpenRFF(FResourceFile* file, LumpFilterInfo*) +static bool OpenRFF(FResourceFile* file, FileSystemFilterInfo*) { RFFLump *lumps; RFFInfo header; @@ -123,7 +123,6 @@ static bool OpenRFF(FResourceFile* file, LumpFilterInfo*) Entries[i].Flags = 0; Entries[i].Method = METHOD_STORED; } - Entries[i].Namespace = ns_global; Entries[i].ResourceID = LittleLong(lumps[i].IndexNum); // Rearrange the name and extension to construct the fullname. @@ -150,7 +149,7 @@ static bool OpenRFF(FResourceFile* file, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckRFF(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[4]; @@ -161,7 +160,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* file.Seek(0, FileReader::SeekSet); if (!memcmp(head, "RFF\x1a", 4)) { - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES); if (OpenRFF(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_ssi.cpp b/src/common/filesystem/source/file_ssi.cpp index 82885c6bb..47c7b53b0 100644 --- a/src/common/filesystem/source/file_ssi.cpp +++ b/src/common/filesystem/source/file_ssi.cpp @@ -44,7 +44,7 @@ namespace FileSys { // //========================================================================== -static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilterInfo*) +static bool OpenSSI(FResourceFile* file, int version, int EntryCount, FileSystemFilterInfo*) { uint32_t NumLumps = EntryCount * 2; auto Entries = file->AllocateEntries(NumLumps); @@ -65,7 +65,6 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter Entries[i].Position = j; Entries[i].CompressedSize = Entries[i].Length = flength; Entries[i].Flags = 0; - Entries[i].Namespace = ns_global; Entries[i].Method = METHOD_STORED; Entries[i].ResourceID = -1; Entries[i].FileName = file->NormalizeFileName(fn); @@ -78,7 +77,6 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter Entries[i + 1].Position = j; Entries[i + 1].CompressedSize = Entries[i + 1].Length = flength; Entries[i + 1].Flags = 0; - Entries[i + 1].Namespace = ns_global; Entries[i + 1].ResourceID = -1; Entries[i + 1].FileName = file->NormalizeFileName(fn); Entries[i + 1].Method = METHOD_STORED; @@ -99,7 +97,7 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter // //========================================================================== -FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile* CheckSSI(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char zerobuf[72]; char buf[72]; @@ -129,7 +127,7 @@ FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* { if (!skipstring(70)) return nullptr; } - auto ssi = new FResourceFile(filename, file, sp); + auto ssi = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES); if (OpenSSI(ssi, version, numfiles, filter)) return ssi; file = ssi->Destroy(); } diff --git a/src/common/filesystem/source/file_wad.cpp b/src/common/filesystem/source/file_wad.cpp index 4f8574b73..3fe736bb0 100644 --- a/src/common/filesystem/source/file_wad.cpp +++ b/src/common/filesystem/source/file_wad.cpp @@ -58,52 +58,22 @@ struct wadlump_t char Name[8]; }; -//========================================================================== -// -// Wad file -// -//========================================================================== - -class FWadFile : public FResourceFile -{ - bool IsMarker(int lump, const char *marker); - void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack=false); - void SkinHack (FileSystemMessageFunc Printf); - -public: - FWadFile(const char * filename, FileReader &file, StringPool* sp); - bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); -}; - - -//========================================================================== -// -// FWadFile::FWadFile -// -// Initializes a WAD file -// -//========================================================================== - -FWadFile::FWadFile(const char *filename, FileReader &file, StringPool* sp) - : FResourceFile(filename, file, sp) -{ -} - //========================================================================== // // Open it // //========================================================================== -bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) +static bool OpenWAD(FResourceFile* file, FileSystemFilterInfo*, FileSystemMessageFunc Printf) { wadinfo_t header; uint32_t InfoTableOfs; bool isBigEndian = false; // Little endian is assumed until proven otherwise - auto wadSize = Reader.GetLength(); + auto Reader = file->GetContainerReader(); + auto wadSize = Reader->GetLength(); - Reader.Read(&header, sizeof(header)); - NumLumps = LittleLong(header.NumLumps); + Reader->Read(&header, sizeof(header)); + uint32_t NumLumps = LittleLong(header.NumLumps); InfoTableOfs = LittleLong(header.InfoTableOfs); // Check to see if the little endian interpretation is valid @@ -117,16 +87,16 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) // Check again to detect broken wads if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) { - Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", FileName); + Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", file->GetFileName()); return false; } } - Reader.Seek(InfoTableOfs, FileReader::SeekSet); - auto fd = Reader.Read(NumLumps * sizeof(wadlump_t)); + Reader->Seek(InfoTableOfs, FileReader::SeekSet); + auto fd = Reader->Read(NumLumps * sizeof(wadlump_t)); auto fileinfo = (const wadlump_t*)fd.data(); - AllocateEntries(NumLumps); + auto Entries = file->AllocateEntries(NumLumps); for(uint32_t i = 0; i < NumLumps; i++) { @@ -143,17 +113,17 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) else if (ishigh > 1) { // This may not end up printing something proper because we do not know what encoding might have been used. - Printf(FSMessageLevel::Warning, "%s: Lump name %.8s contains invalid characters\n", FileName, fileinfo[i].Name); + Printf(FSMessageLevel::Warning, "%s: Lump name %.8s contains invalid characters\n", file->GetFileName(), fileinfo[i].Name); + n[0] = 0; } Entries[i].FileName = nullptr; Entries[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); Entries[i].CompressedSize = Entries[i].Length = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); - Entries[i].Namespace = ns_global; Entries[i].Flags = ishigh? RESFF_SHORTNAME | RESFF_COMPRESSED : RESFF_SHORTNAME; Entries[i].Method = ishigh == 1? METHOD_LZSS : METHOD_STORED; - Entries[i].FileName = stringpool->Strdup(n); + Entries[i].FileName = file->NormalizeFileName(n, 0, true); // This doesn't set up the namespace yet. } for (uint32_t i = 0; i < NumLumps; i++) @@ -161,250 +131,21 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) if (Entries[i].Method == METHOD_LZSS) { // compressed size is implicit. - Entries[i].CompressedSize = (i == NumLumps - 1 ? Reader.GetLength() : Entries[i + 1].Position) - Entries[i].Position; + Entries[i].CompressedSize = (i == NumLumps - 1 ? Reader->GetLength() : Entries[i + 1].Position) - Entries[i].Position; } } - - GenerateHash(); // Do this before the lump processing below. - - SetNamespace("s_start", "s_end", ns_sprites, Printf); - SetNamespace("f_start", "f_end", ns_flats, Printf, true); - SetNamespace("c_start", "c_end", ns_colormaps, Printf); - SetNamespace("a_start", "a_end", ns_acslibrary, Printf); - SetNamespace("tx_start", "tx_end", ns_newtextures, Printf); - SetNamespace("v_start", "v_end", ns_strifevoices, Printf); - SetNamespace("hi_start", "hi_end", ns_hires, Printf); - SetNamespace("vx_start", "vx_end", ns_voxels, Printf); - SkinHack(Printf); - + file->GenerateHash(); // Do this before the lump processing below. return true; } -//========================================================================== -// -// IsMarker -// -// (from BOOM) -// -//========================================================================== - -inline bool FWadFile::IsMarker(int lump, const char *marker) -{ - if (Entries[lump].FileName[0] == marker[0]) - { - return (!strcmp(Entries[lump].FileName, marker) || - (marker[1] == '_' && !strcmp(Entries[lump].FileName +1, marker))); - } - else return false; -} - -//========================================================================== -// -// SetNameSpace -// -// Sets namespace information for the lumps. It always looks for the first -// x_START and the last x_END lump, except when loading flats. In this case -// F_START may be absent and if that is the case all lumps with a size of -// 4096 will be flagged appropriately. -// -//========================================================================== - -// This class was supposed to be local in the function but GCC -// does not like that. -struct Marker -{ - int markertype; - unsigned int index; -}; - -void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack) -{ - bool warned = false; - int numstartmarkers = 0, numendmarkers = 0; - unsigned int i; - std::vector markers; - - for(i = 0; i < NumLumps; i++) - { - if (IsMarker(i, startmarker)) - { - Marker m = { 0, i }; - markers.push_back(m); - numstartmarkers++; - } - else if (IsMarker(i, endmarker)) - { - Marker m = { 1, i }; - markers.push_back(m); - numendmarkers++; - } - } - - if (numstartmarkers == 0) - { - if (numendmarkers == 0) return; // no markers found - - Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); - - - if (flathack) - { - // We have found no F_START but one or more F_END markers. - // mark all lumps before the last F_END marker as potential flats. - unsigned int end = markers[markers.size()-1].index; - for(unsigned int ii = 0; ii < end; ii++) - { - if (Entries[ii].Length == 4096) - { - // We can't add this to the flats namespace but - // it needs to be flagged for the texture manager. - Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName, Entries[ii].FileName); - Entries[ii].Flags |= RESFF_MAYBEFLAT; - } - } - } - return; - } - - i = 0; - while (i < markers.size()) - { - int start, end; - if (markers[i].markertype != 0) - { - Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker); - i++; - continue; - } - start = i++; - - // skip over subsequent x_START markers - while (i < markers.size() && markers[i].markertype == 0) - { - Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, startmarker); - i++; - continue; - } - // same for x_END markers - while (i < markers.size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1)) - { - Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, endmarker); - i++; - continue; - } - // We found a starting marker but no end marker. Ignore this block. - if (i >= markers.size()) - { - Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, startmarker, endmarker); - end = NumLumps; - } - else - { - end = markers[i++].index; - } - - // we found a marked block - Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName, startmarker, markers[start].index, end); - for(int j = markers[start].index + 1; j < end; j++) - { - if (Entries[j].Namespace != ns_global) - { - if (!warned) - { - Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName, j); - } - warned = true; - } - else if (space == ns_sprites && Entries[j].Length < 8) - { - // sf 26/10/99: - // ignore sprite lumps smaller than 8 bytes (the smallest possible) - // in size -- this was used by some dmadds wads - // as an 'empty' graphics resource - Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName, Entries[j].FileName, j); - } - else - { - Entries[j].Namespace = space; - } - } - } -} - - -//========================================================================== -// -// W_SkinHack -// -// Tests a wad file to see if it contains an S_SKIN marker. If it does, -// every lump in the wad is moved into a new namespace. Because skins are -// only supposed to replace player sprites, sounds, or faces, this should -// not be a problem. Yes, there are skins that replace more than that, but -// they are such a pain, and breaking them like this was done on purpose. -// This also renames any S_SKINxx lumps to just S_SKIN. -// -//========================================================================== - -void FWadFile::SkinHack (FileSystemMessageFunc Printf) -{ - // this being static is not a problem. The only relevant thing is that each skin gets a different number. - static int namespc = ns_firstskin; - bool skinned = false; - bool hasmap = false; - uint32_t i; - - for (i = 0; i < NumLumps; i++) - { - auto lump = &Entries[i]; - - if (!strnicmp(lump->FileName, "S_SKIN", 6)) - { // Wad has at least one skin. - lump->FileName = "S_SKIN"; - if (!skinned) - { - skinned = true; - uint32_t j; - - for (j = 0; j < NumLumps; j++) - { - Entries[j].Namespace = namespc; - } - namespc++; - } - } - // needless to say, this check is entirely useless these days as map names can be more diverse.. - if ((lump->FileName[0] == 'M' && - lump->FileName[1] == 'A' && - lump->FileName[2] == 'P' && - lump->FileName[3] >= '0' && lump->FileName[3] <= '9' && - lump->FileName[4] >= '0' && lump->FileName[4] <= '9' && - lump->FileName[5] == '\0') - || - (lump->FileName[0] == 'E' && - lump->FileName[1] >= '0' && lump->FileName[1] <= '9' && - lump->FileName[2] == 'M' && - lump->FileName[3] >= '0' && lump->FileName[3] <= '9' && - lump->FileName[4] == '\0')) - { - hasmap = true; - } - } - if (skinned && hasmap) - { - Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName); - Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n"); - } -} - - //========================================================================== // // File open // //========================================================================== -FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckWad(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[4]; @@ -415,8 +156,8 @@ FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* file.Seek(0, FileReader::SeekSet); if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) { - auto rf = new FWadFile(filename, file, sp); - if (rf->Open(filter, Printf)) return rf; + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::NO_EXTENSIONS | FResourceFile::SHORTNAMES); + if (OpenWAD(rf, filter, Printf)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_whres.cpp b/src/common/filesystem/source/file_whres.cpp index d1d2d1a50..a4cc5dd93 100644 --- a/src/common/filesystem/source/file_whres.cpp +++ b/src/common/filesystem/source/file_whres.cpp @@ -47,7 +47,7 @@ namespace FileSys { // //========================================================================== -bool OpenWHRes(FResourceFile* file, LumpFilterInfo*) +bool OpenWHRes(FResourceFile* file, FileSystemFilterInfo*) { uint32_t directory[1024]; @@ -83,7 +83,6 @@ bool OpenWHRes(FResourceFile* file, LumpFilterInfo*) Entries[i].Position = offset; Entries[i].CompressedSize = Entries[i].Length = length; Entries[i].Flags = RESFF_FULLPATH; - Entries[i].Namespace = ns_global; Entries[i].ResourceID = -1; Entries[i].Method = METHOD_STORED; Entries[i].FileName = file->NormalizeFileName(synthname.c_str()); @@ -99,7 +98,7 @@ bool OpenWHRes(FResourceFile* file, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckWHRes(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { if (file.GetLength() >= 8192) // needs to be at least 8192 to contain one file and the directory. { @@ -119,7 +118,7 @@ FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo if (offset != checkpos || length == 0 || offset + length >= (size_t)size - 4096 ) return nullptr; checkpos += (length+4095) / 4096; } - auto rf = new FResourceFile(filename, file, sp); + auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_EXTENSIONS); if (OpenWHRes(rf, filter)) return rf; file = rf->Destroy(); } diff --git a/src/common/filesystem/source/file_zip.cpp b/src/common/filesystem/source/file_zip.cpp index 8351b7146..d49da9e5e 100644 --- a/src/common/filesystem/source/file_zip.cpp +++ b/src/common/filesystem/source/file_zip.cpp @@ -113,7 +113,7 @@ class FZipFile : public FResourceFile public: FZipFile(const char* filename, FileReader& file, StringPool* sp); - bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); + bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf); FCompressedBuffer GetRawData(uint32_t entry) override; }; @@ -124,11 +124,11 @@ public: //========================================================================== FZipFile::FZipFile(const char * filename, FileReader &file, StringPool* sp) -: FResourceFile(filename, file, sp) +: FResourceFile(filename, file, sp, 0) { } -bool FZipFile::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) +bool FZipFile::Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf) { bool zip64 = false; uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64); @@ -376,7 +376,7 @@ void FZipFile::SetEntryAddress(uint32_t entry) // //========================================================================== -FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *CheckZip(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { char head[4]; diff --git a/src/common/filesystem/source/filesystem.cpp b/src/common/filesystem/source/filesystem.cpp index ec305e15f..2726bac89 100644 --- a/src/common/filesystem/source/filesystem.cpp +++ b/src/common/filesystem/source/filesystem.cpp @@ -52,28 +52,6 @@ namespace FileSys { // MACROS ------------------------------------------------------------------ -#define NULL_INDEX (0xffffffff) - -static void UpperCopy(char* to, const char* from) -{ - int i; - - for (i = 0; i < 8 && from[i]; i++) - to[i] = toupper(from[i]); - for (; i < 8; i++) - to[i] = 0; -} - - -//djb2 -static uint32_t MakeHash(const char* str, size_t length = SIZE_MAX) -{ - uint32_t hash = 5381; - uint32_t c; - while (length-- > 0 && (c = *str++)) hash = hash * 33 + (c | 32); - return hash; -} - static void md5Hash(FileReader& reader, uint8_t* digest) { using namespace md5; @@ -92,11 +70,9 @@ static void md5Hash(FileReader& reader, uint8_t* digest) struct FileSystem::LumpRecord { FResourceFile *resfile; - LumpShortName shortName; - const char* LongName; + const char* Name; int resindex; int16_t rfnum; // this is not necessarily the same as resfile's index! - int16_t Namespace; int resourceId; int flags; @@ -109,52 +85,24 @@ struct FileSystem::LumpRecord auto lflags = file->GetEntryFlags(fileindex); if (!name) name = file->getName(fileindex); - if (lflags & RESFF_SHORTNAME) + if ((lflags & RESFF_EMBEDDED) || !name || !*name) { - UpperCopy(shortName.String, name); - shortName.String[8] = 0; - LongName = ""; - Namespace = file->GetEntryNamespace(fileindex); - resourceId = -1; - } - else if ((lflags & RESFF_EMBEDDED) || !name || !*name) - { - shortName.qword = 0; - LongName = ""; - Namespace = ns_hidden; + Name = ""; resourceId = -1; } else { - LongName = name; + Name = name; resourceId = file->GetEntryResourceID(fileindex); - // Map some directories to WAD namespaces. - // Note that some of these namespaces don't exist in WADS. - // CheckNumForName will handle any request for these namespaces accordingly. - Namespace = !strncmp(LongName, "flats/", 6) ? ns_flats : - !strncmp(LongName, "textures/", 9) ? ns_newtextures : - !strncmp(LongName, "hires/", 6) ? ns_hires : - !strncmp(LongName, "sprites/", 8) ? ns_sprites : - !strncmp(LongName, "voxels/", 7) ? ns_voxels : - !strncmp(LongName, "colormaps/", 10) ? ns_colormaps : - !strncmp(LongName, "acs/", 4) ? ns_acslibrary : - !strncmp(LongName, "voices/", 7) ? ns_strifevoices : - !strncmp(LongName, "patches/", 8) ? ns_patches : - !strncmp(LongName, "graphics/", 9) ? ns_graphics : - !strncmp(LongName, "sounds/", 7) ? ns_sounds : - !strncmp(LongName, "music/", 6) ? ns_music : - !strchr(LongName, '/') ? ns_global : - ns_hidden; - - if (Namespace == ns_hidden) shortName.qword = 0; - else if (strstr(LongName, ".{")) + // allow embedding a resource ID in the name - we need to strip that out here. + if (strstr(Name, ".{")) { - std::string longName = LongName; + std::string longName = Name; ptrdiff_t encodedResID = longName.find_last_of(".{"); if (resourceId == -1 && (size_t)encodedResID != std::string::npos) { - const char* p = LongName + encodedResID; + const char* p = Name + encodedResID; char* q; int id = (int)strtoull(p + 2, &q, 10); // only decimal numbers allowed here. if (q[0] == '}' && (q[1] == '.' || q[1] == 0)) @@ -162,27 +110,13 @@ struct FileSystem::LumpRecord longName.erase(longName.begin() + encodedResID, longName.begin() + (q - p) + 1); resourceId = id; } - LongName = sp->Strdup(longName.c_str()); + Name = sp->Strdup(longName.c_str()); } } - auto slash = strrchr(LongName, '/'); - std::string base = slash ? (slash + 1) : LongName; + auto slash = strrchr(Name, '/'); + std::string base = slash ? (slash + 1) : Name; auto dot = base.find_last_of('.'); if (dot != std::string::npos) base.resize(dot); - UpperCopy(shortName.String, base.c_str()); - - // Since '\' can't be used as a file name's part inside a ZIP - // we have to work around this for sprites because it is a valid - // frame character. - if (Namespace == ns_sprites || Namespace == ns_voxels || Namespace == ns_hires) - { - char* c; - - while ((c = (char*)memchr(shortName.String, '^', 8))) - { - *c = '\\'; - } - } } } }; @@ -223,22 +157,16 @@ void FileSystem::DeleteAll () //========================================================================== // -// InitMultipleFiles +// Initialize // -// Pass a null terminated list of files to use. All files are optional, +// Pass a vector of files to use. All files are optional, // but at least one file must be found. File names can appear multiple // times. The name searcher looks backwards, so a later file can // override an earlier one. // //========================================================================== -bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Printf) -{ - std::vector filenames = { filename }; - return InitMultipleFiles(filenames, nullptr, Printf); -} - -bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates) +bool FileSystem::InitFiles(std::vector& filenames, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates) { int numfiles; @@ -254,9 +182,9 @@ bool FileSystem::InitMultipleFiles (std::vector& filenames, LumpFil // first, check for duplicates if (!allowduplicates) { - for (size_t i=0;i& filenames, LumpFil } } - for(size_t i=0;i& filenames, LumpFil { return false; } + return true; +} + +bool FileSystem::Initialize(std::vector& filenames, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates) +{ + if (!InitFiles(filenames, filter, Printf, allowduplicates)) return false; if (filter && filter->postprocessFunc) filter->postprocessFunc(); // [RH] Set up hash table @@ -304,7 +238,7 @@ int FileSystem::AddFromBuffer(const char* name, char* data, int size, int id, in fr.OpenMemoryArray(blob); // wrap this into a single lump resource file (should be done a little better later.) - auto rf = new FResourceFile(name, fr, stringpool); + auto rf = new FResourceFile(name, fr, stringpool, 0); auto Entries = rf->AllocateEntries(1); Entries[0].FileName = rf->NormalizeFileName(ExtractBaseName(name, true).c_str()); Entries[0].ResourceID = -1; @@ -327,7 +261,7 @@ int FileSystem::AddFromBuffer(const char* name, char* data, int size, int id, in // [RH] Removed reload hack //========================================================================== -void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInfo* filter, FileSystemMessageFunc Printf) +void FileSystem::AddFile (const char *filename, FileReader *filer, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf) { int startlump; bool isdir = false; @@ -443,114 +377,6 @@ int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept return -1; } -//========================================================================== -// -// CheckNumForName -// -// Returns -1 if name not found. The version with a third parameter will -// look exclusively in the specified wad for the lump. -// -// [RH] Changed to use hash lookup ala BOOM instead of a linear search -// and namespace parameter -//========================================================================== - -int FileSystem::CheckNumForName (const char *name, int space) const -{ - union - { - char uname[8]; - uint64_t qname; - }; - uint32_t i; - - if (name == NULL) - { - return -1; - } - - // Let's not search for names that are longer than 8 characters and contain path separators - // They are almost certainly full path names passed to this function. - if (strlen(name) > 8 && strpbrk(name, "/.")) - { - return -1; - } - - UpperCopy (uname, name); - i = FirstLumpIndex[MakeHash(uname, 8) % NumEntries]; - - while (i != NULL_INDEX) - { - - if (FileInfo[i].shortName.qword == qname) - { - auto &lump = FileInfo[i]; - if (lump.Namespace == space) break; - // If the lump is from one of the special namespaces exclusive to Zips - // the check has to be done differently: - // If we find a lump with this name in the global namespace that does not come - // from a Zip return that. WADs don't know these namespaces and single lumps must - // work as well. - auto lflags = lump.resfile->GetEntryFlags(lump.resindex); - if (space > ns_specialzipdirectory && lump.Namespace == ns_global && - !((lflags ^lump.flags) & RESFF_FULLPATH)) break; - } - i = NextLumpIndex[i]; - } - - return i != NULL_INDEX ? i : -1; -} - -int FileSystem::CheckNumForName (const char *name, int space, int rfnum, bool exact) const -{ - union - { - char uname[8]; - uint64_t qname; - }; - uint32_t i; - - if (rfnum < 0) - { - return CheckNumForName (name, space); - } - - UpperCopy (uname, name); - i = FirstLumpIndex[MakeHash (uname, 8) % NumEntries]; - - // If exact is true if will only find lumps in the same WAD, otherwise - // also those in earlier WADs. - - while (i != NULL_INDEX && - (FileInfo[i].shortName.qword != qname || FileInfo[i].Namespace != space || - (exact? (FileInfo[i].rfnum != rfnum) : (FileInfo[i].rfnum > rfnum)) )) - { - i = NextLumpIndex[i]; - } - - return i != NULL_INDEX ? i : -1; -} - -//========================================================================== -// -// GetNumForName -// -// Calls CheckNumForName, but bombs out if not found. -// -//========================================================================== - -int FileSystem::GetNumForName (const char *name, int space) const -{ - int i; - - i = CheckNumForName (name, space); - - if (i == -1) - throw FileSystemException("GetNumForName: %s not found!", name); - - return i; -} - - //========================================================================== // // CheckNumForFullName @@ -561,7 +387,7 @@ int FileSystem::GetNumForName (const char *name, int space) const // //========================================================================== -int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) const +int FileSystem::CheckNumForFullName (const char *name, bool ignoreext) const { uint32_t i; @@ -576,21 +402,16 @@ int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int names for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i]) { - if (strnicmp(name, FileInfo[i].LongName, len)) continue; - if (FileInfo[i].LongName[len] == 0) break; // this is a full match - if (ignoreext && FileInfo[i].LongName[len] == '.') + if (strnicmp(name, FileInfo[i].Name, len)) continue; + if (FileInfo[i].Name[len] == 0) break; // this is a full match + if (ignoreext && FileInfo[i].Name[len] == '.') { // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? - if (strpbrk(FileInfo[i].LongName + len + 1, "./") == nullptr) break; + if (strpbrk(FileInfo[i].Name + len + 1, "./") == nullptr) break; } } if (i != NULL_INDEX) return i; - - if (trynormal && strlen(name) <= 8 && !strpbrk(name, "./")) - { - return CheckNumForName(name, namespc); - } return -1; } @@ -606,7 +427,7 @@ int FileSystem::CheckNumForFullNameInFile (const char *name, int rfnum) const i = FirstLumpIndex_FullName[MakeHash (name) % NumEntries]; while (i != NULL_INDEX && - (stricmp(name, FileInfo[i].LongName) || FileInfo[i].rfnum != rfnum)) + (stricmp(name, FileInfo[i].Name) || FileInfo[i].rfnum != rfnum)) { i = NextLumpIndex_FullName[i]; } @@ -657,10 +478,10 @@ int FileSystem::FindFileWithExtensions(const char* name, const char *const *exts for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i]) { - if (strnicmp(name, FileInfo[i].LongName, len)) continue; - if (FileInfo[i].LongName[len] != '.') continue; // we are looking for extensions but this file doesn't have one. + if (strnicmp(name, FileInfo[i].Name, len)) continue; + if (FileInfo[i].Name[len] != '.') continue; // we are looking for extensions but this file doesn't have one. - auto cp = FileInfo[i].LongName + len + 1; + auto cp = FileInfo[i].Name + len + 1; // is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension? if (strpbrk(cp, "./") != nullptr) continue; // No, so it cannot be a valid entry. @@ -696,7 +517,7 @@ int FileSystem::FindResource (int resid, const char *type, int filenum) const no { if (filenum > 0 && FileInfo[i].rfnum != filenum) continue; if (FileInfo[i].resourceId != resid) continue; - auto extp = strrchr(FileInfo[i].LongName, '.'); + auto extp = strrchr(FileInfo[i].Name, '.'); if (!extp) continue; if (!stricmp(extp + 1, type)) return i; } @@ -773,34 +594,28 @@ void FileSystem::InitHashChains (void) unsigned int i, j; NumEntries = (uint32_t)FileInfo.size(); - Hashes.resize(8 * NumEntries); + Hashes.resize(6 * NumEntries); // Mark all buckets as empty memset(Hashes.data(), -1, Hashes.size() * sizeof(Hashes[0])); - FirstLumpIndex = &Hashes[0]; - NextLumpIndex = &Hashes[NumEntries]; - FirstLumpIndex_FullName = &Hashes[NumEntries * 2]; - NextLumpIndex_FullName = &Hashes[NumEntries * 3]; - FirstLumpIndex_NoExt = &Hashes[NumEntries * 4]; - NextLumpIndex_NoExt = &Hashes[NumEntries * 5]; - FirstLumpIndex_ResId = &Hashes[NumEntries * 6]; - NextLumpIndex_ResId = &Hashes[NumEntries * 7]; + FirstLumpIndex_FullName = &Hashes[NumEntries * 0]; + NextLumpIndex_FullName = &Hashes[NumEntries * 1]; + FirstLumpIndex_NoExt = &Hashes[NumEntries * 2]; + NextLumpIndex_NoExt = &Hashes[NumEntries * 3]; + FirstLumpIndex_ResId = &Hashes[NumEntries * 4]; + NextLumpIndex_ResId = &Hashes[NumEntries * 5]; // Now set up the chains for (i = 0; i < (unsigned)NumEntries; i++) { - j = MakeHash (FileInfo[i].shortName.String, 8) % NumEntries; - NextLumpIndex[i] = FirstLumpIndex[j]; - FirstLumpIndex[j] = i; - // Do the same for the full paths - if (FileInfo[i].LongName[0] != 0) + if (FileInfo[i].Name[0] != 0) { - j = MakeHash(FileInfo[i].LongName) % NumEntries; + j = MakeHash(FileInfo[i].Name) % NumEntries; NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; FirstLumpIndex_FullName[j] = i; - std::string nameNoExt = FileInfo[i].LongName; + std::string nameNoExt = FileInfo[i].Name; auto dot = nameNoExt.find_last_of('.'); auto slash = nameNoExt.find_last_of('/'); if ((dot > slash || slash == std::string::npos) && dot != std::string::npos) nameNoExt.resize(dot); @@ -819,24 +634,10 @@ void FileSystem::InitHashChains (void) Files.shrink_to_fit(); } -//========================================================================== -// -// should only be called before the hash chains are set up. -// If done later this needs rehashing. -// -//========================================================================== - -LumpShortName& FileSystem::GetShortName(int i) -{ - if ((unsigned)i >= NumEntries) throw FileSystemException("GetShortName: Invalid index"); - return FileInfo[i].shortName; -} - void FileSystem::RenameFile(int num, const char* newfn) { if ((unsigned)num >= NumEntries) throw FileSystemException("RenameFile: Invalid index"); - FileInfo[num].LongName = stringpool->Strdup(newfn); - // This does not alter the short name - call GetShortname to do that! + FileInfo[num].Name = stringpool->Strdup(newfn); } //========================================================================== @@ -867,14 +668,13 @@ void FileSystem::MoveLumpsInFolder(const char *path) { auto& li = FileInfo[i]; if (li.rfnum >= GetIwadNum()) break; - if (strnicmp(li.LongName, path, len) == 0) + if (strnicmp(li.Name, path, len) == 0) { auto lic = li; // make a copy before pushing. FileInfo.push_back(lic); - li.LongName = ""; //nuke the name of the old record. - li.shortName.qword = 0; + li.Name = ""; //nuke the name of the old record. auto &ln = FileInfo.back(); - ln.SetFromLump(li.resfile, li.resindex, rfnum, stringpool, ln.LongName + len); + ln.SetFromLump(li.resfile, li.resindex, rfnum, stringpool, ln.Name + len); } } } @@ -888,87 +688,6 @@ void FileSystem::MoveLumpsInFolder(const char *path) // //========================================================================== -int FileSystem::FindLump (const char *name, int *lastlump, bool anyns) -{ - if ((size_t)*lastlump >= FileInfo.size()) return -1; - union - { - char name8[8]; - uint64_t qname; - }; - - UpperCopy (name8, name); - - assert(lastlump != NULL && *lastlump >= 0); - - const LumpRecord * last = FileInfo.data() + FileInfo.size(); - - LumpRecord * lump_p = FileInfo.data() + *lastlump; - - while (lump_p < last) - { - if ((anyns || lump_p->Namespace == ns_global) && lump_p->shortName.qword == qname) - { - int lump = int(lump_p - FileInfo.data()); - *lastlump = lump + 1; - return lump; - } - lump_p++; - } - - *lastlump = NumEntries; - return -1; -} - -//========================================================================== -// -// W_FindLumpMulti -// -// Find a named lump. Specifically allows duplicates for merging of e.g. -// SNDINFO lumps. Returns everything having one of the passed names. -// -//========================================================================== - -int FileSystem::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex) -{ - assert(lastlump != NULL && *lastlump >= 0); - - const LumpRecord * last = FileInfo.data() + FileInfo.size(); - - LumpRecord * lump_p = FileInfo.data() + *lastlump; - - while (lump_p < last) - { - if (anyns || lump_p->Namespace == ns_global) - { - - for(const char **name = names; *name != NULL; name++) - { - if (!strnicmp(*name, lump_p->shortName.String, 8)) - { - int lump = int(lump_p - FileInfo.data()); - *lastlump = lump + 1; - if (nameindex != NULL) *nameindex = int(name - names); - return lump; - } - } - } - lump_p++; - } - - *lastlump = NumEntries; - return -1; -} - -//========================================================================== -// -// W_FindLump -// -// Find a named lump. Specifically allows duplicates for merging of e.g. -// SNDINFO lumps. -// -//========================================================================== - int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext) { assert(lastlump != NULL && *lastlump >= 0); @@ -981,7 +700,7 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext) { while (lump_p < last) { - if (!stricmp(name, lump_p->LongName)) + if (!stricmp(name, lump_p->Name)) { int lump = int(lump_p - FileInfo.data()); *lastlump = lump + 1; @@ -995,10 +714,10 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext) auto len = strlen(name); while (lump_p <= &FileInfo.back()) { - auto res = strnicmp(name, lump_p->LongName, len); + auto res = strnicmp(name, lump_p->Name, len); if (res == 0) { - auto p = lump_p->LongName + len; + auto p = lump_p->Name + len; if (*p == 0 || (*p == '.' && strpbrk(p + 1, "./") == 0)) { int lump = int(lump_p - FileInfo.data()); @@ -1017,49 +736,17 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext) //========================================================================== // -// W_CheckLumpName +// FileSystem :: GetFileName +// +// Returns the lump's internal name // //========================================================================== -bool FileSystem::CheckFileName (int lump, const char *name) -{ - if ((size_t)lump >= NumEntries) - return false; - - return !strnicmp (FileInfo[lump].shortName.String, name, 8); -} - -//========================================================================== -// -// GetLumpName -// -//========================================================================== - -const char* FileSystem::GetFileShortName(int lump) const -{ - if ((size_t)lump >= NumEntries) - return nullptr; - else - return FileInfo[lump].shortName.String; -} - -//========================================================================== -// -// FileSystem :: GetFileFullName -// -// Returns the lump's full name if it has one or its short name if not. -// -//========================================================================== - -const char *FileSystem::GetFileName (int lump, bool returnshort) const +const char* FileSystem::GetFileName(int lump) const { if ((size_t)lump >= NumEntries) return NULL; - else if (FileInfo[lump].LongName[0] != 0) - return FileInfo[lump].LongName; - else if (returnshort) - return FileInfo[lump].shortName.String; - else return nullptr; + else return FileInfo[lump].Name; } //========================================================================== @@ -1083,25 +770,6 @@ std::string FileSystem::GetFileFullPath(int lump) const return foo; } -//========================================================================== -// -// GetFileNamespace -// -//========================================================================== - -int FileSystem::GetFileNamespace (int lump) const -{ - if ((size_t)lump >= NumEntries) - return ns_global; - else - return FileInfo[lump].Namespace; -} - -void FileSystem::SetFileNamespace(int lump, int ns) -{ - if ((size_t)lump < NumEntries) FileInfo[lump].Namespace = ns; -} - //========================================================================== // // FileSystem :: GetResourceId @@ -1134,7 +802,7 @@ const char *FileSystem::GetResourceType(int lump) const return nullptr; else { - auto p = strrchr(FileInfo[lump].LongName, '.'); + auto p = strrchr(FileInfo[lump].Name, '.'); if (!p) return ""; // has no extension if (strchr(p, '/')) return ""; // the '.' is part of a directory. return p + 1; @@ -1186,12 +854,12 @@ unsigned FileSystem::GetFilesInFolder(const char *inpath, std::vector= Files.size()) + { + return 0; + } + + return Files[rfnum]->GetFlags(); +} + +//========================================================================== +// +// +//========================================================================== + int FileSystem::GetLastEntry (int rfnum) const noexcept { if ((uint32_t)rfnum >= Files.size()) @@ -1415,7 +1098,7 @@ bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/) if (lump < 0) return false; // Does not exist. auto oldlump = FileInfo[lump]; - auto slash = strrchr(oldlump.LongName, '/'); + auto slash = strrchr(oldlump.Name, '/'); if (slash == nullptr) { @@ -1425,7 +1108,7 @@ bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/) // just create a new reference to the original data with a different name. - oldlump.LongName = slash + 1; + oldlump.Name = slash + 1; oldlump.resourceId = id; oldlump.flags = RESFF_FULLPATH; FileInfo.push_back(oldlump); diff --git a/src/common/filesystem/source/resourcefile.cpp b/src/common/filesystem/source/resourcefile.cpp index 00a5234ca..6736cfa71 100644 --- a/src/common/filesystem/source/resourcefile.cpp +++ b/src/common/filesystem/source/resourcefile.cpp @@ -113,7 +113,7 @@ bool FResourceFile::IsFileInFolder(const char* const resPath) return 0 == stricmp(filePath.c_str(), resPath); } -void FResourceFile::CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi) +void FResourceFile::CheckEmbedded(uint32_t entry, FileSystemFilterInfo* lfi) { // Checks for embedded archives auto FullName = Entries[entry].FileName; @@ -138,29 +138,30 @@ void FResourceFile::CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi) // //========================================================================== -typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile* CheckWHRes(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckLump(const char *filename,FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -FResourceFile *CheckDir(const char *filename, bool nosub, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckWad(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckGRP(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckRFF(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckPak(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckZip(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *Check7Z(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckSSI(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckHog(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckHog2(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckMvl(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile* CheckWHRes(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckLump(const char *filename,FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); +FResourceFile *CheckDir(const char *filename, bool nosub, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp); -static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckSSI, CheckHog, CheckMvl, CheckWHRes, CheckLump }; +static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckHog, CheckMvl, CheckHog2, CheckSSI, CheckWHRes, CheckLump }; static int nulPrintf(FSMessageLevel msg, const char* fmt, ...) { return 0; } -FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { if (!file.isOpen()) return nullptr; if (Printf == nullptr) Printf = nulPrintf; @@ -173,20 +174,20 @@ FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReade return NULL; } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp); } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { FileReader file; if (!file.OpenFile(filename)) return nullptr; return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp); } -FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) +FResourceFile *FResourceFile::OpenDirectory(const char *filename, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp) { if (Printf == nullptr) Printf = nulPrintf; return CheckDir(filename, false, filter, Printf, sp); @@ -198,14 +199,15 @@ FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo // //========================================================================== -FResourceFile::FResourceFile(const char *filename, StringPool* sp) +FResourceFile::FResourceFile(const char *filename, StringPool* sp, int flags_) + :flags(flags_) { stringpool = sp ? sp : new StringPool(false); FileName = stringpool->Strdup(filename); } -FResourceFile::FResourceFile(const char *filename, FileReader &r, StringPool* sp) - : FResourceFile(filename,sp) +FResourceFile::FResourceFile(const char *filename, FileReader &r, StringPool* sp, int flags) + : FResourceFile(filename,sp, flags) { Reader = std::move(r); } @@ -250,7 +252,7 @@ FCompressedBuffer FResourceFile::GetRawData(uint32_t entry) // //========================================================================== -const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp) +const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp, bool allowbackslash) { if (!fn || !*fn) return ""; auto norm = tolower_normalize(fn); @@ -274,7 +276,8 @@ const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp) norm = tolower_normalize(&ffn.front()); } } - FixPathSeparator(norm); + // The WAD format can have legal backslashes in its names so this must be optional. + if (!allowbackslash) FixPathSeparator(norm); auto pooled = stringpool->Strdup(norm); free(norm); return pooled; @@ -354,7 +357,7 @@ void FResourceFile::GenerateHash() // //========================================================================== -void FResourceFile::PostProcessArchive(LumpFilterInfo *filter) +void FResourceFile::PostProcessArchive(FileSystemFilterInfo *filter) { // only do this for archive types which contain full file names. All others are assumed to be pre-sorted. if (NumLumps == 0 || !(Entries[0].Flags & RESFF_FULLPATH)) return; @@ -416,7 +419,7 @@ void FResourceFile::PostProcessArchive(LumpFilterInfo *filter) // //========================================================================== -void FResourceFile::FindCommonFolder(LumpFilterInfo* filter) +void FResourceFile::FindCommonFolder(FileSystemFilterInfo* filter) { std::string name0, name1; bool foundspeciallump = false; diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp index a84639a8c..8e93cb7a3 100644 --- a/src/common/textures/texturemanager.cpp +++ b/src/common/textures/texturemanager.cpp @@ -50,7 +50,6 @@ #include "basics.h" #include "cmdlib.h" -using namespace FileSys; FTextureManager TexMan; @@ -585,7 +584,7 @@ void FTextureManager::AddGroup(int wadnum, int ns, ETextureType usetype) } progressFunc(); } - else if (ns == ns_flats && fileSystem.GetFileFlags(firsttx) & RESFF_MAYBEFLAT) + else if (ns == ns_flats && fileSystem.GetFileNamespace(firsttx) == ns_maybeflat) { if (fileSystem.CheckNumForName(Name, ns) < firsttx) { @@ -1421,12 +1420,11 @@ int FTextureManager::GuesstimateNumTextures () case ns_hires: case ns_patches: case ns_graphics: + case ns_maybeflat: numtex++; break; default: - if (fileSystem.GetFileFlags(i) & RESFF_MAYBEFLAT) numtex++; - break; } } diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 9e93d2aa2..b81e376dc 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -314,7 +314,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize, // Look for IWAD definition lump // //========================================================================== -void GetReserved(FileSys::LumpFilterInfo& lfi); +void GetReserved(FileSys::FileSystemFilterInfo& lfi); FIWadManager::FIWadManager(const char *firstfn, const char *optfn) { @@ -322,10 +322,10 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn) std::vector fns; fns.push_back(firstfn); if (optfn) fns.push_back(optfn); - FileSys::LumpFilterInfo lfi; + FileSys::FileSystemFilterInfo lfi; GetReserved(lfi); - if (check.InitMultipleFiles(fns, &lfi, nullptr)) + if (check.Initialize(fns, &lfi, nullptr)) { // this is for the IWAD picker. As we have a filesystem open here that contains the base files, it is the easiest place to load the strings early. GStrings.LoadStrings(check, language); @@ -350,7 +350,8 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn) int FIWadManager::ScanIWAD (const char *iwad) { FileSystem check; - check.InitSingleFile(iwad, nullptr); + std::vector list({ iwad }); + check.Initialize(list, nullptr); mLumpsFound.Resize(mIWadInfos.Size()); @@ -373,14 +374,13 @@ int FIWadManager::ScanIWAD (const char *iwad) memset(&mLumpsFound[0], 0, mLumpsFound.Size() * sizeof(mLumpsFound[0])); for(int ii = 0; ii < check.GetNumEntries(); ii++) { - - CheckFileName(check.GetFileShortName(ii)); - auto full = check.GetFileName(ii, false); + auto full = check.GetFileName(ii); if (full && strnicmp(full, "maps/", 5) == 0) { FString mapname(&full[5], strcspn(&full[5], ".")); CheckFileName(mapname.GetChars()); } + else CheckFileName(full); } } for (unsigned i = 0; i< mIWadInfos.Size(); i++) @@ -404,11 +404,11 @@ int FIWadManager::CheckIWADInfo(const char* fn) { FileSystem check; - FileSys::LumpFilterInfo lfi; + FileSys::FileSystemFilterInfo lfi; GetReserved(lfi); std::vector filenames = { fn }; - if (check.InitMultipleFiles(filenames, &lfi, nullptr)) + if (check.Initialize(filenames, &lfi, nullptr)) { int num = check.CheckNumForName("IWADINFO"); if (num >= 0) diff --git a/src/d_main.cpp b/src/d_main.cpp index aa5bfdf9a..53f2485b4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -123,8 +123,6 @@ #include "i_system.h" // for SHARE_DIR #endif // __unix__ -using namespace FileSys; - EXTERN_CVAR(Bool, hud_althud) EXTERN_CVAR(Int, vr_mode) EXTERN_CVAR(Bool, cl_customizeinvulmap) @@ -1265,7 +1263,7 @@ void D_DoomLoop () } D_ErrorCleanup (); } - catch (const FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error. + catch (const FileSys::FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error. { if (error.what()) { @@ -1945,7 +1943,7 @@ static FString ParseGameInfo(std::vector &pwads, const char *fn, co return iwad; } -void GetReserved(LumpFilterInfo& lfi) +void GetReserved(FileSys::FileSystemFilterInfo& lfi) { lfi.reservedFolders = { "flats/", "textures/", "hires/", "sprites/", "voxels/", "colormaps/", "acs/", "maps/", "voices/", "patches/", "graphics/", "sounds/", "music/", "materials/", "models/", "fonts/", "brightmaps/" }; @@ -1957,11 +1955,11 @@ static FString CheckGameInfo(std::vector & pwads) { FileSystem check; - LumpFilterInfo lfi; + FileSys::FileSystemFilterInfo lfi; GetReserved(lfi); // Open the entire list as a temporary file system and look for a GAMEINFO lump. The last one will automatically win. - if (check.InitMultipleFiles(pwads, &lfi, nullptr)) + if (check.Initialize(pwads, &lfi, nullptr)) { int num = check.CheckNumForName("GAMEINFO"); if (num >= 0) @@ -2250,48 +2248,48 @@ static void RenameSprites(FileSystem &fileSystem, const TArray& deletel bool MNTRZfound = false; const char* altbigfont = gameinfo.gametype == GAME_Strife ? "SBIGFONT" : (gameinfo.gametype & GAME_Raven) ? "HBIGFONT" : "DBIGFONT"; - static const uint32_t HereticRenames[] = - { MAKE_ID('H','E','A','D'), MAKE_ID('L','I','C','H'), // Ironlich + static const char HereticRenames[][4] = + { {'H','E','A','D'}, {'L','I','C','H'}, // Ironlich }; - static const uint32_t HexenRenames[] = - { MAKE_ID('B','A','R','L'), MAKE_ID('Z','B','A','R'), // ZBarrel - MAKE_ID('A','R','M','1'), MAKE_ID('A','R','_','1'), // MeshArmor - MAKE_ID('A','R','M','2'), MAKE_ID('A','R','_','2'), // FalconShield - MAKE_ID('A','R','M','3'), MAKE_ID('A','R','_','3'), // PlatinumHelm - MAKE_ID('A','R','M','4'), MAKE_ID('A','R','_','4'), // AmuletOfWarding - MAKE_ID('S','U','I','T'), MAKE_ID('Z','S','U','I'), // ZSuitOfArmor and ZArmorChunk - MAKE_ID('T','R','E','1'), MAKE_ID('Z','T','R','E'), // ZTree and ZTreeDead - MAKE_ID('T','R','E','2'), MAKE_ID('T','R','E','S'), // ZTreeSwamp150 - MAKE_ID('C','A','N','D'), MAKE_ID('B','C','A','N'), // ZBlueCandle - MAKE_ID('R','O','C','K'), MAKE_ID('R','O','K','K'), // rocks and dirt in a_debris.cpp - MAKE_ID('W','A','T','R'), MAKE_ID('H','W','A','T'), // Strife also has WATR - MAKE_ID('G','I','B','S'), MAKE_ID('P','O','L','5'), // RealGibs - MAKE_ID('E','G','G','M'), MAKE_ID('P','R','K','M'), // PorkFX - MAKE_ID('I','N','V','U'), MAKE_ID('D','E','F','N'), // Icon of the Defender + static const char HexenRenames[][4] = + { {'B','A','R','L'}, {'Z','B','A','R'}, // ZBarrel + {'A','R','M','1'}, {'A','R','_','1'}, // MeshArmor + {'A','R','M','2'}, {'A','R','_','2'}, // FalconShield + {'A','R','M','3'}, {'A','R','_','3'}, // PlatinumHelm + {'A','R','M','4'}, {'A','R','_','4'}, // AmuletOfWarding + {'S','U','I','T'}, {'Z','S','U','I'}, // ZSuitOfArmor and ZArmorChunk + {'T','R','E','1'}, {'Z','T','R','E'}, // ZTree and ZTreeDead + {'T','R','E','2'}, {'T','R','E','S'}, // ZTreeSwamp150 + {'C','A','N','D'}, {'B','C','A','N'}, // ZBlueCandle + {'R','O','C','K'}, {'R','O','K','K'}, // rocks and dirt in a_debris.cpp + {'W','A','T','R'}, {'H','W','A','T'}, // Strife also has WATR + {'G','I','B','S'}, {'P','O','L','5'}, // RealGibs + {'E','G','G','M'}, {'P','R','K','M'}, // PorkFX + {'I','N','V','U'}, {'D','E','F','N'}, // Icon of the Defender }; - static const uint32_t StrifeRenames[] = - { MAKE_ID('M','I','S','L'), MAKE_ID('S','M','I','S'), // lots of places - MAKE_ID('A','R','M','1'), MAKE_ID('A','R','M','3'), // MetalArmor - MAKE_ID('A','R','M','2'), MAKE_ID('A','R','M','4'), // LeatherArmor - MAKE_ID('P','M','A','P'), MAKE_ID('S','M','A','P'), // StrifeMap - MAKE_ID('T','L','M','P'), MAKE_ID('T','E','C','H'), // TechLampSilver and TechLampBrass - MAKE_ID('T','R','E','1'), MAKE_ID('T','R','E','T'), // TreeStub - MAKE_ID('B','A','R','1'), MAKE_ID('B','A','R','C'), // BarricadeColumn - MAKE_ID('S','H','T','2'), MAKE_ID('M','P','U','F'), // MaulerPuff - MAKE_ID('B','A','R','L'), MAKE_ID('B','B','A','R'), // StrifeBurningBarrel - MAKE_ID('T','R','C','H'), MAKE_ID('T','R','H','L'), // SmallTorchLit - MAKE_ID('S','H','R','D'), MAKE_ID('S','H','A','R'), // glass shards - MAKE_ID('B','L','S','T'), MAKE_ID('M','A','U','L'), // Mauler - MAKE_ID('L','O','G','G'), MAKE_ID('L','O','G','W'), // StickInWater - MAKE_ID('V','A','S','E'), MAKE_ID('V','A','Z','E'), // Pot and Pitcher - MAKE_ID('C','N','D','L'), MAKE_ID('K','N','D','L'), // Candle - MAKE_ID('P','O','T','1'), MAKE_ID('M','P','O','T'), // MetalPot - MAKE_ID('S','P','I','D'), MAKE_ID('S','T','L','K'), // Stalker + static const char StrifeRenames[][4] = + { {'M','I','S','L'}, {'S','M','I','S'}, // lots of places + {'A','R','M','1'}, {'A','R','M','3'}, // MetalArmor + {'A','R','M','2'}, {'A','R','M','4'}, // LeatherArmor + {'P','M','A','P'}, {'S','M','A','P'}, // StrifeMap + {'T','L','M','P'}, {'T','E','C','H'}, // TechLampSilver and TechLampBrass + {'T','R','E','1'}, {'T','R','E','T'}, // TreeStub + {'B','A','R','1'}, {'B','A','R','C'}, // BarricadeColumn + {'S','H','T','2'}, {'M','P','U','F'}, // MaulerPuff + {'B','A','R','L'}, {'B','B','A','R'}, // StrifeBurningBarrel + {'T','R','C','H'}, {'T','R','H','L'}, // SmallTorchLit + {'S','H','R','D'}, {'S','H','A','R'}, // glass shards + {'B','L','S','T'}, {'M','A','U','L'}, // Mauler + {'L','O','G','G'}, {'L','O','G','W'}, // StickInWater + {'V','A','S','E'}, {'V','A','Z','E'}, // Pot and Pitcher + {'C','N','D','L'}, {'K','N','D','L'}, // Candle + {'P','O','T','1'}, {'M','P','O','T'}, // MetalPot + {'S','P','I','D'}, {'S','T','L','K'}, // Stalker }; - const uint32_t* renames; + const char (*renames)[4]; int numrenames; switch (gameinfo.gametype) @@ -2327,8 +2325,8 @@ static void RenameSprites(FileSystem &fileSystem, const TArray& deletel // some frames need to be renamed. if (fileSystem.GetFileNamespace(i) == ns_sprites) { - auto& shortName = fileSystem.GetShortName(i); - if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R') && shortName.String[4] == 'Z') + auto shortName = fileSystem.GetShortName(i); + if (!memcmp(shortName, "MNTRZ", 5)) { MNTRZfound = true; break; @@ -2340,7 +2338,7 @@ static void RenameSprites(FileSystem &fileSystem, const TArray& deletel for (uint32_t i = 0; i < NumFiles; i++) { - auto& shortName = fileSystem.GetShortName(i); + auto shortName = fileSystem.GetShortName(i); if (fileSystem.GetFileNamespace(i) == ns_sprites) { // Only sprites in the IWAD normally get renamed @@ -2348,30 +2346,30 @@ static void RenameSprites(FileSystem &fileSystem, const TArray& deletel { for (int j = 0; j < numrenames; ++j) { - if (shortName.dword == renames[j * 2]) + if (!memcmp(shortName, &renames[j * 8], 4)) { - shortName.dword = renames[j * 2 + 1]; + memcpy(shortName, renames[j * 8 + 4], 4); } } if (gameinfo.gametype == GAME_Hexen) { if (fileSystem.CheckFileName(i, "ARTIINVU")) { - shortName.String[4] = 'D'; shortName.String[5] = 'E'; - shortName.String[6] = 'F'; shortName.String[7] = 'N'; + shortName[4] = 'D'; shortName[5] = 'E'; + shortName[6] = 'F'; shortName[7] = 'N'; } } } if (!MNTRZfound) { - if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R')) + if (!memcmp(shortName, "MNTR", 4)) { for (size_t fi : {4, 6}) { - if (shortName.String[fi] >= 'F' && shortName.String[fi] <= 'K') + if (shortName[fi] >= 'F' && shortName[fi] <= 'K') { - shortName.String[fi] += 'U' - 'F'; + shortName[fi] += 'U' - 'F'; } } } @@ -2381,23 +2379,23 @@ static void RenameSprites(FileSystem &fileSystem, const TArray& deletel // the same blood states can be used everywhere if (!(gameinfo.gametype & GAME_DoomChex)) { - if (shortName.dword == MAKE_ID('B', 'L', 'O', 'D')) + if (!memcmp(shortName, "BLOD", 4)) { - shortName.dword = MAKE_ID('B', 'L', 'U', 'D'); + memcpy(shortName, "BLUD", 4); } } } else if (fileSystem.GetFileNamespace(i) == ns_global) { int fn = fileSystem.GetFileContainer(i); - if (fn >= fileSystem.GetIwadNum() && fn <= fileSystem.GetMaxIwadNum() && deletelumps.Find(shortName.String) < deletelumps.Size()) + if (fn >= fileSystem.GetIwadNum() && fn <= fileSystem.GetMaxIwadNum() && deletelumps.Find(shortName) < deletelumps.Size()) { - shortName.String[0] = 0; // Lump must be deleted from directory. + shortName[0] = 0; // Lump must be deleted from directory. } // Rename the game specific big font lumps so that the font manager does not have to do problematic special checks for them. - else if (!strcmp(shortName.String, altbigfont)) + else if (!strcmp(shortName, altbigfont)) { - strcpy(shortName.String, "BIGFONT"); + strcpy(shortName, "BIGFONT"); } } } @@ -2467,18 +2465,16 @@ void RenameNerve(FileSystem& fileSystem) for (int i = fileSystem.GetFirstEntry(w); i <= fileSystem.GetLastEntry(w); i++) { - auto& shortName = fileSystem.GetShortName(i); + auto shortName = fileSystem.GetShortName(i); // Only rename the maps from NERVE.WAD - if (shortName.dword == MAKE_ID('C', 'W', 'I', 'L')) + if (!memcmp(shortName, "CWILV", 5)) { - shortName.String[0] = 'N'; + shortName[0] = 'N'; } - else if (shortName.dword == MAKE_ID('M', 'A', 'P', '0')) + else if (!memcmp(shortName, "MAP0", 4)) { - shortName.String[6] = shortName.String[4]; - shortName.String[5] = '0'; - shortName.String[4] = 'L'; - shortName.dword = MAKE_ID('L', 'E', 'V', 'E'); + shortName[6] = shortName[4]; + memcpy(shortName, "LEVEL0", 6); } } } @@ -2560,8 +2556,8 @@ void FixMacHexen(FileSystem& fileSystem) for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i) { - auto& shortName = fileSystem.GetShortName(i); - shortName.String[0] = '\0'; + auto shortName = fileSystem.GetShortName(i); + memcpy(shortName, "\0\0\0\0\0\0\0", 8); // these get compared with memcmp so all 8 bytes need to get cleared. } } @@ -2572,21 +2568,21 @@ static void FindStrifeTeaserVoices(FileSystem& fileSystem) unsigned NumFiles = fileSystem.GetNumEntries(); for (uint32_t i = 0; i < NumFiles; i++) { - auto& shortName = fileSystem.GetShortName(i); + auto shortName = fileSystem.GetShortName(i); if (fileSystem.GetFileNamespace(i) == ns_global) { - // Only sprites in the IWAD normally get renamed + // Strife teaser voices are not in the expected namespace. if (fileSystem.GetFileContainer(i) == fileSystem.GetIwadNum()) { - if (shortName.String[0] == 'V' && - shortName.String[1] == 'O' && - shortName.String[2] == 'C') + if (shortName[0] == 'V' && + shortName[1] == 'O' && + shortName[2] == 'C') { int j; for (j = 3; j < 8; ++j) { - if (shortName.String[j] != 0 && !isdigit(shortName.String[j])) + if (shortName[j] != 0 && !isdigit(shortName[j])) break; } if (j == 8) @@ -3048,7 +3044,7 @@ static bool FileNameCheck(const char* base, const char* path) return true; } -static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...) +static int FileSystemPrintf(FileSys::FSMessageLevel level, const char* fmt, ...) { va_list arg; va_start(arg, fmt); @@ -3056,22 +3052,22 @@ static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...) text.VFormat(fmt, arg); switch (level) { - case FSMessageLevel::Error: + case FileSys::FSMessageLevel::Error: return Printf(TEXTCOLOR_RED "%s", text.GetChars()); break; - case FSMessageLevel::Warning: + case FileSys::FSMessageLevel::Warning: Printf(TEXTCOLOR_YELLOW "%s", text.GetChars()); break; - case FSMessageLevel::Attention: + case FileSys::FSMessageLevel::Attention: Printf(TEXTCOLOR_BLUE "%s", text.GetChars()); break; - case FSMessageLevel::Message: + case FileSys::FSMessageLevel::Message: Printf("%s", text.GetChars()); break; - case FSMessageLevel::DebugWarn: + case FileSys::FSMessageLevel::DebugWarn: DPrintf(DMSG_WARNING, "%s", text.GetChars()); break; - case FSMessageLevel::DebugNotify: + case FileSys::FSMessageLevel::DebugNotify: DPrintf(DMSG_NOTIFY, "%s", text.GetChars()); break; } @@ -3143,7 +3139,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw if (!batchrun) Printf ("W_Init: Init WADfiles.\n"); - LumpFilterInfo lfi; + FileSys::FileSystemFilterInfo lfi; static const struct { int match; const char* name; } blanket[] = { @@ -3184,7 +3180,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector& allw ); bool allowduplicates = Args->CheckParm("-allowduplicates"); - if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates)) + if (!fileSystem.Initialize(allwads, &lfi, FileSystemPrintf, allowduplicates)) { I_FatalError("FileSystem: no files found"); }