diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 2841327ec..2a7e2768d 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -588,7 +588,6 @@ file( GLOB HEADER_FILES core/utility/*.h core/utility/rapidjson/*.h core/console/*.h - core/filesystem/*.h core/music/*.h core/sound/*.h core/sound/backend/*.h @@ -604,6 +603,7 @@ file( GLOB HEADER_FILES core/rendering/hwrenderer/utility/*.h common/utility/*.h + common/filesystem/*.h common/thirdparty/*.h common/thirdparty/rapidjson/*.h common/thirdparty/math./*h @@ -737,6 +737,18 @@ set (PCH_SOURCES common/utility/zstrformat.cpp common/thirdparty/md5.cpp common/thirdparty/superfasthash.cpp + common/filesystem/filesystem.cpp + common/filesystem/ancientzip.cpp + common/filesystem/file_7z.cpp + common/filesystem/file_grp.cpp + common/filesystem/file_lump.cpp + common/filesystem/file_rff.cpp + common/filesystem/file_wad.cpp + common/filesystem/file_zip.cpp + common/filesystem/file_pak.cpp + common/filesystem/file_whres.cpp + common/filesystem/file_directory.cpp + common/filesystem/resourcefile.cpp core/utility/name.cpp core/utility/m_png.cpp @@ -744,17 +756,6 @@ set (PCH_SOURCES core/utility/stringtable.cpp core/utility/stats.cpp - core/filesystem/filesystem.cpp - core/filesystem/ancientzip.cpp - core/filesystem/file_zip.cpp - core/filesystem/file_7z.cpp - core/filesystem/file_grp.cpp - core/filesystem/file_rff.cpp - core/filesystem/file_pak.cpp - core/filesystem/file_lump.cpp - core/filesystem/file_directory.cpp - core/filesystem/resourcefile.cpp - core/textures/bitmap.cpp core/textures/buildtiles.cpp core/textures/texture.cpp @@ -893,7 +894,6 @@ include_directories( core/utility core/console core/textures - core/filesystem core/music core/sound core/sound/backend @@ -910,6 +910,7 @@ include_directories( core/rendering platform common/thirdparty + common/filesystem common/utility ${CMAKE_BINARY_DIR}/libraries/gdtoa @@ -1008,7 +1009,6 @@ source_group("Core\\Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/co source_group("Core\\2D" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/2d/.+") source_group("Core\\Console" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/console/.+") source_group("Core\\Fonts" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/fonts/.+") -source_group("Core\\File System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/filesystem/.+") source_group("Core\\Music" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/music/.+") source_group("Core\\Sound" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/sound/.+") source_group("Core\\Sound\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/core/sound/backend/.+") @@ -1021,6 +1021,7 @@ source_group("Platform" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platfor source_group("Platform\\Win32" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/win32/.+") source_group("Platform\\POSIX" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/platform/posix/.+") source_group("Common" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/.+") +source_group("Common\\File System" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/filesystem/.+") source_group("Common\\Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/.+") source_group("Common\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/.+") source_group("Common\\Third Party\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/math/.+") diff --git a/source/blood/src/barf.cpp b/source/blood/src/barf.cpp index ea5e84576..145a6af87 100644 --- a/source/blood/src/barf.cpp +++ b/source/blood/src/barf.cpp @@ -29,10 +29,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "misc.h" #include "globals.h" #include "sound.h" -#include "filesystem/resourcefile.h" +#include "filesystem.h" BEGIN_BLD_NS +// I don't think we still need these. +#define DICT_LOAD 0 +#define DICT_LOCK 0 + static Resource gBarfRes; #define kMaxCmdLineDefines 5 @@ -905,12 +909,12 @@ void ReadAllRFS() for (int i = 0; i < numf; i++) { auto rl = fileSystem.GetResourceType(i); - if (rl == NAME_RFS) + if (!stricmp(rl, "RFS")) { ParseScript(i); found = true; } } - if (found) fileSystem.Rehash(); + if (found) fileSystem.InitHashChains(); } END_BLD_NS diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index d697710b3..1ddfe6ee3 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -1078,7 +1078,7 @@ int GameInterface::app_main() loaddefinitions_game(defsfile, FALSE); powerupInit(); Printf("Loading cosine table\n"); - trigInit(gSysRes); + trigInit(); Printf("Initializing view subsystem\n"); viewInit(); Printf("Initializing dynamic fire\n"); diff --git a/source/blood/src/inifile.cpp b/source/blood/src/inifile.cpp index 78fd149ec..e50097167 100644 --- a/source/blood/src/inifile.cpp +++ b/source/blood/src/inifile.cpp @@ -130,7 +130,7 @@ void IniFile::Load() curNode = &head; - auto fp = fileSystem.OpenFileReader(fileName, 0); + auto fp = fileSystem.OpenFileReader(fileName); if (fp.isOpen()) { int nSize = fp.GetLength(); diff --git a/source/blood/src/resource.h b/source/blood/src/resource.h index a5e22d91b..df9b55063 100644 --- a/source/blood/src/resource.h +++ b/source/blood/src/resource.h @@ -23,9 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once #include "common.h" -#include "filesystem/resourcefile.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" using Resource = FileSystem; // Map NBlood's resource system to our own. -using DICTNODE = FResourceEntry; +using DICTNODE = FResourceLump; diff --git a/source/blood/src/seq.cpp b/source/blood/src/seq.cpp index 4aede988c..11b069827 100644 --- a/source/blood/src/seq.cpp +++ b/source/blood/src/seq.cpp @@ -83,9 +83,8 @@ void seqPrecacheId(int id) DICTNODE *hSeq = gSysRes.Lookup(id, "SEQ"); if (!hSeq) return; - Seq *pSeq = (Seq*)gSysRes.Lock(hSeq); + Seq *pSeq = (Seq*)gSysRes.Load(hSeq); pSeq->Precache(); - gSysRes.Unlock(hSeq); } SEQINST siWall[kMaxXWalls]; @@ -375,7 +374,6 @@ void UnlockInstance(SEQINST *pInst) dassert(pInst != NULL); dassert(pInst->hSeq != NULL); dassert(pInst->pSequence != NULL); - gSysRes.Unlock(pInst->hSeq); pInst->hSeq = NULL; pInst->pSequence = NULL; pInst->at13 = 0; @@ -403,7 +401,7 @@ void seqSpawn(int a1, int a2, int a3, int a4) } dassert(i < activeCount); } - Seq *pSeq = (Seq*)gSysRes.Lock(hSeq); + Seq *pSeq = (Seq*)gSysRes.Load(hSeq); if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0) ThrowError("Invalid sequence %d", a1); if ((pSeq->version & 0xff00) != 0x300) @@ -588,7 +586,7 @@ void SeqLoadSave::Load(void) ThrowError("Missing sequence #%d", nSeq); continue; } - Seq *pSeq = (Seq*)gSysRes.Lock(hSeq); + Seq *pSeq = (Seq*)gSysRes.Load(hSeq); if (memcmp(pSeq->signature, "SEQ\x1a", 4) != 0) ThrowError("Invalid sequence %d", nSeq); if ((pSeq->version & 0xff00) != 0x300) diff --git a/source/blood/src/sound.cpp b/source/blood/src/sound.cpp index 3d55c56c7..e8dc02298 100644 --- a/source/blood/src/sound.cpp +++ b/source/blood/src/sound.cpp @@ -103,14 +103,14 @@ void sndInit(void) for (int i = fileSystem.GetNumEntries() - 1; i >= 0; i--) { auto type = fileSystem.GetResourceType(i); - if (type == NAME_SFX) + if (!stricmp(type, "SFX")) { if (soundEngine->FindSoundByResID(fileSystem.GetResourceId(i)) == 0) S_AddBloodSFX(i); } - else if (type == NAME_WAV || type == NAME_OGG || type == NAME_FLAC || type == NAME_VOC) + else if (!stricmp(type, "WAV") || !stricmp(type, "OGG") || !stricmp(type, "FLAC") || !stricmp(type, "VOC")) { - soundEngine->AddSoundLump(fileSystem.GetFileName(i), i, 0, fileSystem.GetResourceId(i)| 0x40000000, 6); // mark the resource ID as special. + soundEngine->AddSoundLump(fileSystem.GetFileFullName(i), i, 0, fileSystem.GetResourceId(i)| 0x40000000, 6); // mark the resource ID as special. } } soundEngine->HashSounds(); diff --git a/source/blood/src/tile.cpp b/source/blood/src/tile.cpp index 4c83dfb9e..9e672d976 100644 --- a/source/blood/src/tile.cpp +++ b/source/blood/src/tile.cpp @@ -86,12 +86,12 @@ int tileInit(char a1, const char *a2) for (int i = 0; i < kMaxTiles; i++) voxelIndex[i] = 0; - auto hFile = fileSystem.OpenFileReader("SURFACE.DAT", 0); + auto hFile = fileSystem.OpenFileReader("SURFACE.DAT"); if (hFile.isOpen()) { hFile.Read(surfType, sizeof(surfType)); } - hFile = fileSystem.OpenFileReader("VOXEL.DAT", 0); + hFile = fileSystem.OpenFileReader("VOXEL.DAT"); if (hFile.isOpen()) { hFile.Read(voxelIndex, sizeof(voxelIndex)); @@ -100,7 +100,7 @@ int tileInit(char a1, const char *a2) voxelIndex[i] = B_LITTLE16(voxelIndex[i]); #endif } - hFile = fileSystem.OpenFileReader("SHADE.DAT", 0); + hFile = fileSystem.OpenFileReader("SHADE.DAT"); if (hFile.isOpen()) { hFile.Read(tileShade, sizeof(tileShade)); diff --git a/source/blood/src/trig.cpp b/source/blood/src/trig.cpp index dba977224..cbe6d7a1b 100644 --- a/source/blood/src/trig.cpp +++ b/source/blood/src/trig.cpp @@ -59,14 +59,12 @@ void RotatePoint(int *x, int *y, int nAngle, int ox, int oy) *y = oy+dmulscale30r(dx, Sin(nAngle), dy, Cos(nAngle)); } -void trigInit(Resource &Res) +void trigInit() { - DICTNODE *pTable = Res.Lookup("cosine","dat"); - if (!pTable) - ThrowError("Cosine table not found"); - if (pTable->Size() != 2048) + auto fr = fileSystem.OpenFileReader("cosine.dat"); + auto len = fr.Read(costable, 2048); + if (len != 2048) ThrowError("Cosine table incorrect size"); - memcpy(costable, Res.Load(pTable), pTable->Size()); #if B_BIG_ENDIAN == 1 for (int i = 0; i < 512; i++) { diff --git a/source/blood/src/trig.h b/source/blood/src/trig.h index c8371e960..33e968e9c 100644 --- a/source/blood/src/trig.h +++ b/source/blood/src/trig.h @@ -31,7 +31,7 @@ extern int costable[2048]; int GetOctant(int x, int y); void RotateVector(int *dx, int *dy, int nAngle); void RotatePoint(int *x, int *y, int nAngle, int ox, int oy); -void trigInit(Resource &Res); +void trigInit(); inline int Sin(int ang) { diff --git a/source/blood/src/view.cpp b/source/blood/src/view.cpp index 2dfc15de5..d92135dee 100644 --- a/source/blood/src/view.cpp +++ b/source/blood/src/view.cpp @@ -1795,6 +1795,7 @@ void viewPrecacheTiles(void) } } +static TArray lensdata; int *lensTable; int gZoom = 1024; @@ -1811,11 +1812,10 @@ void viewInit(void) FontSet(3, 4384, 1); FontSet(4, 4480, 0); - DICTNODE *hLens = gSysRes.Lookup("LENS", "DAT"); - dassert(hLens != NULL); - dassert(hLens->Size() == kLensSize * kLensSize * sizeof(int)); + lensdata = fileSystem.LoadFile("lens.dat"); + dassert(lensdata.Size() == kLensSize * kLensSize * sizeof(int)); - lensTable = (int*)gSysRes.Lock(hLens); + lensTable = (int*)lensdata.Data(); #if B_BIG_ENDIAN == 1 for (int i = 0; i < kLensSize*kLensSize; i++) { diff --git a/source/build/include/palette.h b/source/build/include/palette.h index 7ed31ce19..0d476468e 100644 --- a/source/build/include/palette.h +++ b/source/build/include/palette.h @@ -12,7 +12,7 @@ #define palette_h_ #include "renderstyle.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #define MAXBASEPALS 256 #define MAXPALOOKUPS 256 diff --git a/source/build/src/defs.cpp b/source/build/src/defs.cpp index e24f59fed..4727657f6 100644 --- a/source/build/src/defs.cpp +++ b/source/build/src/defs.cpp @@ -2628,7 +2628,7 @@ static int32_t defsparser(scriptfile *script) break; } - FileReader fil = fileSystem.OpenFileReader(fn, 0); + FileReader fil = fileSystem.OpenFileReader(fn); if (!fil.isOpen()) { Printf("Error: basepalette: Failed opening \"%s\" on line %s:%d\n", fn, @@ -2800,7 +2800,7 @@ static int32_t defsparser(scriptfile *script) break; } - FileReader fil = fileSystem.OpenFileReader(fn, 0); + FileReader fil = fileSystem.OpenFileReader(fn); if (!fil.isOpen()) { Printf("Error: palookup: Failed opening \"%s\" on line %s:%d\n", fn, @@ -3093,7 +3093,7 @@ static int32_t defsparser(scriptfile *script) break; } - FileReader fil = fileSystem.OpenFileReader(fn, 0); + FileReader fil = fileSystem.OpenFileReader(fn); if (!fil.isOpen()) { Printf("Error: blendtable: Failed opening \"%s\" on line %s:%d\n", fn, diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index 01671661c..83cd3b0b3 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -24,7 +24,6 @@ #include "c_console.h" #include "v_2ddrawer.h" #include "v_draw.h" -#include "imgui.h" #include "stats.h" #include "menu.h" #include "version.h" @@ -3405,7 +3404,7 @@ int32_t engineLoadBoard(const char *filename, char flags, vec3_t *dapos, int16_t flags &= 3; - FileReader fr = fileSystem.OpenFileReader(filename, 0); + FileReader fr = fileSystem.OpenFileReader(filename); if (!fr.isOpen()) { mapversion = 7; return -1; } @@ -3593,7 +3592,7 @@ int32_t engineLoadBoardV5V6(const char *filename, char fromwhere, vec3_t *dapos, struct walltypev6 v6wall; struct spritetypev6 v6spr; - FileReader fr = fileSystem.OpenFileReader(filename, fromwhere); + FileReader fr = fileSystem.OpenFileReader(filename); if (!fr.isOpen()) { mapversion = 5L; return -1; } @@ -3865,7 +3864,7 @@ int32_t qloadkvx(int32_t voxindex, const char *filename) if ((unsigned)voxindex >= MAXVOXELS) return -1; - auto fil = fileSystem.OpenFileReader(filename, 0); + auto fil = fileSystem.OpenFileReader(filename); if (!fil.isOpen()) return -1; diff --git a/source/build/src/mdsprite.cpp b/source/build/src/mdsprite.cpp index 371b08749..bf4e5db8c 100644 --- a/source/build/src/mdsprite.cpp +++ b/source/build/src/mdsprite.cpp @@ -1850,7 +1850,7 @@ static mdmodel_t *mdload(const char *filnam) vm = (mdmodel_t *)voxload(filnam); if (vm) return vm; - auto fil = fileSystem.OpenFileReader(filnam,0); + auto fil = fileSystem.OpenFileReader(filnam); if (!fil.isOpen()) return NULL; diff --git a/source/build/src/palette.cpp b/source/build/src/palette.cpp index 1aa500489..a8558df68 100644 --- a/source/build/src/palette.cpp +++ b/source/build/src/palette.cpp @@ -104,7 +104,7 @@ void paletteLoadFromDisk(void) return; } - auto fil = fileSystem.OpenFileReader("palette.dat", 0); + auto fil = fileSystem.OpenFileReader("palette.dat"); if (!fil.isOpen()) return; diff --git a/source/build/src/scriptfile.cpp b/source/build/src/scriptfile.cpp index f304567b1..395a642cc 100644 --- a/source/build/src/scriptfile.cpp +++ b/source/build/src/scriptfile.cpp @@ -9,7 +9,7 @@ #include "scriptfile.h" #include "baselayer.h" #include "compat.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #define ISWS(x) ((x == ' ') || (x == '\t') || (x == '\r') || (x == '\n')) @@ -299,7 +299,7 @@ void scriptfile_preparse(scriptfile *sf, char *tx, int32_t flen) scriptfile *scriptfile_fromfile(const char *fn) { - auto fr = fileSystem.OpenFileReader(fn, 0); + auto fr = fileSystem.OpenFileReader(fn); if (!fr.isOpen()) return nullptr; uint32_t flen = fr.GetLength(); diff --git a/source/build/src/voxmodel.cpp b/source/build/src/voxmodel.cpp index 45427f660..d29832f5d 100644 --- a/source/build/src/voxmodel.cpp +++ b/source/build/src/voxmodel.cpp @@ -606,7 +606,7 @@ static void read_pal(FileReader &fil, int32_t pal[256]) static int32_t loadvox(const char *filnam) { - auto fil = fileSystem.OpenFileReader(filnam, 0); + auto fil = fileSystem.OpenFileReader(filnam); if (!fil.isOpen()) return -1; @@ -682,7 +682,7 @@ static int32_t loadkvx(const char *filnam) { int32_t i, mip1leng; - auto fil = fileSystem.OpenFileReader(filnam, 0); + auto fil = fileSystem.OpenFileReader(filnam); if (!fil.isOpen()) return -1; @@ -766,7 +766,7 @@ static int32_t loadkv6(const char *filnam) { int32_t i; - auto fil = fileSystem.OpenFileReader(filnam, 0); + auto fil = fileSystem.OpenFileReader(filnam); if (!fil.isOpen()) return -1; diff --git a/source/core/filesystem/ancientzip.cpp b/source/common/filesystem/ancientzip.cpp similarity index 100% rename from source/core/filesystem/ancientzip.cpp rename to source/common/filesystem/ancientzip.cpp diff --git a/source/core/filesystem/ancientzip.h b/source/common/filesystem/ancientzip.h similarity index 95% rename from source/core/filesystem/ancientzip.h rename to source/common/filesystem/ancientzip.h index a1abfac84..3b1497e02 100644 --- a/source/core/filesystem/ancientzip.h +++ b/source/common/filesystem/ancientzip.h @@ -1,4 +1,3 @@ -#include #include "files.h" #include "engineerrors.h" @@ -42,7 +41,7 @@ public: int Explode(unsigned char *out, unsigned int outsize, FileReader &in, unsigned int insize, int flags); }; -class CExplosionError : public CRecoverableError +class CExplosionError : CRecoverableError { public: CExplosionError(const char *message) : CRecoverableError(message) {} diff --git a/source/core/filesystem/file_7z.cpp b/source/common/filesystem/file_7z.cpp similarity index 93% rename from source/core/filesystem/file_7z.cpp rename to source/common/filesystem/file_7z.cpp index 1516f8d32..8b44a9e6f 100644 --- a/source/core/filesystem/file_7z.cpp +++ b/source/common/filesystem/file_7z.cpp @@ -40,8 +40,6 @@ #include "resourcefile.h" #include "cmdlib.h" #include "printf.h" -//#include "v_text.h" -//#include "w_wad.h" @@ -171,7 +169,7 @@ struct F7ZLump : public FResourceLump { int Position; - int ValidateCache() override; + virtual int FillCache(); }; @@ -191,7 +189,7 @@ class F7ZFile : public FResourceFile public: F7ZFile(const char * filename, FileReader &filer); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); virtual ~F7ZFile(); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -218,7 +216,7 @@ F7ZFile::F7ZFile(const char * filename, FileReader &filer) // //========================================================================== -bool F7ZFile::Open(bool quiet) +bool F7ZFile::Open(bool quiet, LumpFilterInfo *filter) { Archive = new C7zArchive(Reader); int skipped = 0; @@ -231,7 +229,7 @@ bool F7ZFile::Open(bool quiet) Archive = NULL; if (!quiet) { - Printf("\n%s: ", FileName.GetChars()); + Printf("\n" TEXTCOLOR_RED "%s: ", FileName.GetChars()); if (res == SZ_ERROR_UNSUPPORTED) { Printf("Decoder does not support this archive\n"); @@ -285,16 +283,17 @@ bool F7ZFile::Open(bool quiet) { nameASCII[c] = static_cast(nameUTF16[c]); } + FixPathSeperator(&nameASCII[0]); FString name = &nameASCII[0]; - name.Substitute("\\", "/"); name.ToLower(); lump_p->LumpNameSetup(name); lump_p->LumpSize = static_cast(SzArEx_GetFileSize(archPtr, i)); lump_p->Owner = this; - lump_p->Flags = LUMPF_ZIPFILE|LUMPF_COMPRESSED; + lump_p->Flags = LUMPF_FULLPATH|LUMPF_COMPRESSED; lump_p->Position = i; + lump_p->CheckEmbedded(); lump_p++; } // Resize the lump record array to its actual size @@ -314,9 +313,8 @@ bool F7ZFile::Open(bool quiet) } } - if (!quiet) Printf(", %d lumps\n", NumLumps); - - PostProcessArchive(&Lumps[0], sizeof(F7ZLump)); + GenerateHash(); + PostProcessArchive(&Lumps[0], sizeof(F7ZLump), filter); return true; } @@ -344,10 +342,11 @@ F7ZFile::~F7ZFile() // //========================================================================== -int F7ZLump::ValidateCache() +int F7ZLump::FillCache() { - Cache.Resize(LumpSize); - static_cast(Owner)->Archive->Extract(Position, (char*)Cache.Data()); + Cache = new char[LumpSize]; + static_cast(Owner)->Archive->Extract(Position, Cache); + RefCount = 1; return 1; } @@ -357,7 +356,7 @@ int F7ZLump::ValidateCache() // //========================================================================== -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet) +FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { char head[k7zSignatureSize]; @@ -369,7 +368,7 @@ FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet) if (!memcmp(head, k7zSignature, k7zSignatureSize)) { FResourceFile *rf = new F7ZFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/source/core/filesystem/file_directory.cpp b/source/common/filesystem/file_directory.cpp similarity index 89% rename from source/core/filesystem/file_directory.cpp rename to source/common/filesystem/file_directory.cpp index 2a2117eb1..b24d6888d 100644 --- a/source/core/filesystem/file_directory.cpp +++ b/source/common/filesystem/file_directory.cpp @@ -35,11 +35,6 @@ #include -#ifdef _WIN32 -#include -#else -#include -#endif #include "resourcefile.h" #include "cmdlib.h" @@ -56,8 +51,8 @@ struct FDirectoryLump : public FResourceLump { - virtual FileReader NewReader() override; - int ValidateCache() override; + FileReader NewReader() override; + int FillCache() override; FString mFullPath; }; @@ -79,7 +74,7 @@ class FDirectory : public FResourceFile public: FDirectory(const char * dirname, bool nosubdirflag = false); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -150,10 +145,8 @@ int FDirectory::AddDirectory(const char *dirpath) (fi[1] == '\0' || (fi[1] == '.' && fi[2] == '\0')))) { - // Movie and music subdirectories must always pass. - if (fi.CompareNoCase("movie") && fi.CompareNoCase("music")) - // Skip if requested and do not record . and .. directories. - continue; + // Do not record . and .. directories. + continue; } FString newdir = dirpath; newdir << fi << '/'; @@ -170,7 +163,7 @@ int FDirectory::AddDirectory(const char *dirpath) FString fn = FString(dirpath) + fi; if (GetFileInfo(fn, &size, nullptr)) { - AddEntry(fn, size); + AddEntry(fn, (int)size); count++; } } @@ -187,11 +180,10 @@ int FDirectory::AddDirectory(const char *dirpath) // //========================================================================== -bool FDirectory::Open(bool quiet) +bool FDirectory::Open(bool quiet, LumpFilterInfo* filter) { NumLumps = AddDirectory(FileName); - if (!quiet) Printf(", %d lumps\n", NumLumps); - PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump)); + PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump), filter); return true; } @@ -217,6 +209,7 @@ void FDirectory::AddEntry(const char *fullpath, int size) lump_p->LumpSize = size; lump_p->Owner = this; lump_p->Flags = 0; + lump_p->CheckEmbedded(); } @@ -239,17 +232,17 @@ FileReader FDirectoryLump::NewReader() // //========================================================================== -int FDirectoryLump::ValidateCache() +int FDirectoryLump::FillCache() { FileReader fr; + Cache = new char[LumpSize]; if (!fr.OpenFile(mFullPath)) { - memset(Cache.Data(), 0, LumpSize); + memset(Cache, 0, LumpSize); return 0; } - LumpSize = fr.GetLength(); // keep this updated - Cache.Resize(LumpSize); - fr.Read(Cache.Data(), LumpSize); + fr.Read(Cache, LumpSize); + RefCount = 1; return 1; } @@ -259,10 +252,10 @@ int FDirectoryLump::ValidateCache() // //========================================================================== -FResourceFile *CheckDir(const char *filename, bool quiet, bool nosubdirflag) +FResourceFile *CheckDir(const char *filename, bool quiet, bool nosubdirflag, LumpFilterInfo* filter) { FResourceFile *rf = new FDirectory(filename, nosubdirflag); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; delete rf; return NULL; } diff --git a/source/core/filesystem/file_grp.cpp b/source/common/filesystem/file_grp.cpp similarity index 95% rename from source/core/filesystem/file_grp.cpp rename to source/common/filesystem/file_grp.cpp index ad12cf486..fbb5148c8 100644 --- a/source/core/filesystem/file_grp.cpp +++ b/source/common/filesystem/file_grp.cpp @@ -72,7 +72,7 @@ class FGrpFile : public FUncompressedFile { public: FGrpFile(const char * filename, FileReader &file); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); }; @@ -93,7 +93,7 @@ FGrpFile::FGrpFile(const char *filename, FileReader &file) // //========================================================================== -bool FGrpFile::Open(bool quiet) +bool FGrpFile::Open(bool quiet, LumpFilterInfo*) { GrpInfo header; @@ -117,7 +117,7 @@ bool FGrpFile::Open(bool quiet) fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated Lumps[i].LumpNameSetup(fileinfo[i].NameWithZero); } - if (!quiet) Printf(", %d lumps\n", NumLumps); + GenerateHash(); delete[] fileinfo; return true; } @@ -129,7 +129,7 @@ bool FGrpFile::Open(bool quiet) // //========================================================================== -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet) +FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { char head[12]; @@ -141,7 +141,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet) if (!memcmp(head, "KenSilverman", 12)) { FResourceFile *rf = new FGrpFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/source/core/filesystem/file_lump.cpp b/source/common/filesystem/file_lump.cpp similarity index 90% rename from source/core/filesystem/file_lump.cpp rename to source/common/filesystem/file_lump.cpp index 50344f225..60902900d 100644 --- a/source/core/filesystem/file_lump.cpp +++ b/source/common/filesystem/file_lump.cpp @@ -34,6 +34,7 @@ #include "resourcefile.h" #include "cmdlib.h" +#include "printf.h" //========================================================================== // @@ -45,7 +46,7 @@ class FLumpFile : public FUncompressedFile { public: FLumpFile(const char * filename, FileReader &file); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); }; @@ -66,16 +67,21 @@ FLumpFile::FLumpFile(const char *filename, FileReader &file) // //========================================================================== -bool FLumpFile::Open(bool quiet) +bool FLumpFile::Open(bool quiet, LumpFilterInfo*) { + FString name(ExtractFileBase(FileName, true)); + Lumps.Resize(1); + Lumps[0].LumpNameSetup(name); Lumps[0].Owner = this; Lumps[0].Position = 0; Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].Flags = 0; - auto p = FileName.LastIndexOf('/'); - Lumps[0].LumpNameSetup(FileName.GetChars() + p); NumLumps = 1; + if (!quiet) + { + Printf("\n"); + } return true; } @@ -85,11 +91,11 @@ bool FLumpFile::Open(bool quiet) // //========================================================================== -FResourceFile *CheckLump(const char *filename, FileReader &file, bool quiet) +FResourceFile *CheckLump(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { // always succeeds FResourceFile *rf = new FLumpFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; return NULL; diff --git a/source/core/filesystem/file_pak.cpp b/source/common/filesystem/file_pak.cpp similarity index 92% rename from source/core/filesystem/file_pak.cpp rename to source/common/filesystem/file_pak.cpp index 3102c52f2..60137f235 100644 --- a/source/core/filesystem/file_pak.cpp +++ b/source/common/filesystem/file_pak.cpp @@ -34,8 +34,6 @@ #include "resourcefile.h" #include "printf.h" -//#include "w_wad.h" -//#include "doomtype.h" //========================================================================== // @@ -67,7 +65,7 @@ class FPakFile : public FUncompressedFile { public: FPakFile(const char * filename, FileReader &file); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); }; @@ -90,7 +88,7 @@ FPakFile::FPakFile(const char *filename, FileReader &file) // //========================================================================== -bool FPakFile::Open(bool quiet) +bool FPakFile::Open(bool quiet, LumpFilterInfo* filter) { dpackheader_t header; @@ -104,15 +102,17 @@ bool FPakFile::Open(bool quiet) Lumps.Resize(NumLumps); - if (!quiet) Printf(", %d lumps\n", NumLumps); - for(uint32_t i = 0; i < NumLumps; i++) { Lumps[i].LumpNameSetup(fileinfo[i].name); + Lumps[i].Flags = LUMPF_FULLPATH; Lumps[i].Owner = this; Lumps[i].Position = LittleLong(fileinfo[i].filepos); Lumps[i].LumpSize = LittleLong(fileinfo[i].filelen); + Lumps[i].CheckEmbedded(); } + GenerateHash(); + PostProcessArchive(&Lumps[0], sizeof(Lumps[0]), filter); return true; } @@ -123,7 +123,7 @@ bool FPakFile::Open(bool quiet) // //========================================================================== -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet) +FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { char head[4]; @@ -135,7 +135,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet) if (!memcmp(head, "PACK", 4)) { FResourceFile *rf = new FPakFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/source/core/filesystem/file_rff.cpp b/source/common/filesystem/file_rff.cpp similarity index 84% rename from source/core/filesystem/file_rff.cpp rename to source/common/filesystem/file_rff.cpp index 1097c5c01..80805d641 100644 --- a/source/core/filesystem/file_rff.cpp +++ b/source/common/filesystem/file_rff.cpp @@ -32,8 +32,9 @@ ** ** */ -#include + #include "resourcefile.h" +#include "templates.h" #include "printf.h" //========================================================================== @@ -61,7 +62,7 @@ struct RFFLump uint8_t Flags; char Extension[3]; char Name[8]; - uint32_t ResourceId; + uint32_t IndexNum; // Used by .sfx, possibly others }; //========================================================================== @@ -72,10 +73,12 @@ struct RFFLump struct FRFFLump : public FUncompressedLump { - virtual FileReader *GetReader() override; - int ValidateCache() override; + virtual FileReader *GetReader(); + virtual int FillCache(); uint32_t IndexNum; + + int GetIndexNum() const { return IndexNum; } }; //========================================================================== @@ -103,11 +106,12 @@ void BloodCrypt (void *data, int key, int len) class FRFFFile : public FResourceFile { - TArray Lumps; + FRFFLump *Lumps; public: FRFFFile(const char * filename, FileReader &file); - virtual bool Open(bool quiet); + virtual ~FRFFFile(); + virtual bool Open(bool quiet, LumpFilterInfo* filter); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -121,6 +125,7 @@ public: FRFFFile::FRFFFile(const char *filename, FileReader &file) : FResourceFile(filename, file) { + Lumps = NULL; } //========================================================================== @@ -129,7 +134,7 @@ FRFFFile::FRFFFile(const char *filename, FileReader &file) // //========================================================================== -bool FRFFFile::Open(bool quiet) +bool FRFFFile::Open(bool quiet, LumpFilterInfo*) { RFFLump *lumps; RFFInfo header; @@ -143,22 +148,18 @@ bool FRFFFile::Open(bool quiet) Reader.Read (lumps, header.NumLumps * sizeof(RFFLump)); BloodCrypt (lumps, header.DirOfs, header.NumLumps * sizeof(RFFLump)); - Lumps.Grow(NumLumps); + Lumps = new FRFFLump[NumLumps]; - if (!quiet) Printf(", %d lumps\n", NumLumps); for (uint32_t i = 0; i < NumLumps; ++i) { - Lumps.Reserve(1); - auto& Lump = Lumps.Last(); - - Lump.Position = LittleLong(lumps[i].FilePos); - Lump.LumpSize = LittleLong(lumps[i].Size); - Lump.Owner = this; + Lumps[i].Position = LittleLong(lumps[i].FilePos); + Lumps[i].LumpSize = LittleLong(lumps[i].Size); + Lumps[i].Owner = this; if (lumps[i].Flags & 0x10) { - Lump.Flags |= LUMPF_BLOODCRYPT; + Lumps[i].Flags |= LUMPF_COMPRESSED; // flags the lump as not directly usable } - Lump.ResourceId = LittleLong(lumps[i].ResourceId); + Lumps[i].IndexNum = LittleLong(lumps[i].IndexNum); // Rearrange the name and extension to construct the fullname. char name[13]; strncpy(name, lumps[i].Name, 8); @@ -170,12 +171,21 @@ bool FRFFFile::Open(bool quiet) name[len+2] = lumps[i].Extension[1]; name[len+3] = lumps[i].Extension[2]; name[len+4] = 0; - Lump.LumpNameSetup(name); + Lumps[i].LumpNameSetup(name); } delete[] lumps; + GenerateHash(); return true; } +FRFFFile::~FRFFFile() +{ + if (Lumps != NULL) + { + delete[] Lumps; + } +} + //========================================================================== // @@ -187,7 +197,7 @@ FileReader *FRFFLump::GetReader() { // Don't return the reader if this lump is encrypted // In that case always force caching of the lump - if (!(Flags & LUMPF_BLOODCRYPT)) + if (!(Flags & LUMPF_COMPRESSED)) { return FUncompressedLump::GetReader(); } @@ -203,14 +213,14 @@ FileReader *FRFFLump::GetReader() // //========================================================================== -int FRFFLump::ValidateCache() +int FRFFLump::FillCache() { - int res = FUncompressedLump::ValidateCache(); + int res = FUncompressedLump::FillCache(); - if (res && (Flags & LUMPF_BLOODCRYPT)) + if (Flags & LUMPF_COMPRESSED) { - int cryptlen = std::min (LumpSize, 256); - uint8_t *data = Cache.Data(); + int cryptlen = MIN (LumpSize, 256); + uint8_t *data = (uint8_t *)Cache; for (int i = 0; i < cryptlen; ++i) { @@ -227,7 +237,7 @@ int FRFFLump::ValidateCache() // //========================================================================== -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet) +FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { char head[4]; @@ -239,7 +249,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet) if (!memcmp(head, "RFF\x1a", 4)) { FResourceFile *rf = new FRFFFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/source/common/filesystem/file_wad.cpp b/source/common/filesystem/file_wad.cpp new file mode 100644 index 000000000..2cbb4a3dc --- /dev/null +++ b/source/common/filesystem/file_wad.cpp @@ -0,0 +1,484 @@ +/* +** file_wad.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2009 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 +#include "resourcefile.h" +#include "v_text.h" +#include "filesystem.h" +#include "engineerrors.h" + + +struct wadinfo_t +{ + // Should be "IWAD" or "PWAD". + uint32_t Magic; + uint32_t NumLumps; + uint32_t InfoTableOfs; +}; + +struct wadlump_t +{ + uint32_t FilePos; + uint32_t Size; + char Name[8]; +}; + +//========================================================================== +// +// Wad Lump (with console doom LZSS support) +// +//========================================================================== + +class FWadFileLump : public FResourceLump +{ +public: + bool Compressed; + int Position; + int Namespace; + + int GetNamespace() const override { return Namespace; } + + int GetFileOffset() { return Position; } + FileReader *GetReader() + { + if(!Compressed) + { + Owner->Reader.Seek(Position, FileReader::SeekSet); + return &Owner->Reader; + } + return NULL; + } + int FillCache() + { + if(!Compressed) + { + const char * buffer = Owner->Reader.GetBuffer(); + + if (buffer != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } + } + + Owner->Reader.Seek(Position, FileReader::SeekSet); + Cache = new char[LumpSize]; + + if(Compressed) + { + FileReader lzss; + if (lzss.OpenDecompressor(Owner->Reader, LumpSize, METHOD_LZSS, false, [](const char* err) { I_Error("%s", err); })) + { + lzss.Read(Cache, LumpSize); + } + } + else + Owner->Reader.Read(Cache, LumpSize); + + RefCount = 1; + return 1; + } +}; + +//========================================================================== +// +// Wad file +// +//========================================================================== + +class FWadFile : public FResourceFile +{ + TArray Lumps; + + bool IsMarker(int lump, const char *marker); + void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack=false); + void SkinHack (); + +public: + FWadFile(const char * filename, FileReader &file); + FResourceLump *GetLump(int lump) { return &Lumps[lump]; } + bool Open(bool quiet, LumpFilterInfo* filter); +}; + + +//========================================================================== +// +// FWadFile::FWadFile +// +// Initializes a WAD file +// +//========================================================================== + +FWadFile::FWadFile(const char *filename, FileReader &file) + : FResourceFile(filename, file) +{ +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FWadFile::Open(bool quiet, LumpFilterInfo*) +{ + wadinfo_t header; + uint32_t InfoTableOfs; + bool isBigEndian = false; // Little endian is assumed until proven otherwise + auto wadSize = Reader.GetLength(); + + Reader.Read(&header, sizeof(header)); + NumLumps = LittleLong(header.NumLumps); + InfoTableOfs = LittleLong(header.InfoTableOfs); + + // Check to see if the little endian interpretation is valid + // This should be sufficient to detect big endian wads. + if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) + { + NumLumps = BigLong(header.NumLumps); + InfoTableOfs = BigLong(header.InfoTableOfs); + isBigEndian = true; + + // Check again to detect broken wads + if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) + { + I_Error("Cannot load broken WAD file %s\n", FileName.GetChars()); + } + } + + TArray fileinfo(NumLumps, true); + Reader.Seek (InfoTableOfs, FileReader::SeekSet); + Reader.Read (fileinfo.Data(), NumLumps * sizeof(wadlump_t)); + + Lumps.Resize(NumLumps); + + for(uint32_t i = 0; i < NumLumps; i++) + { + char n[9]; + uppercopy(n, fileinfo[i].Name); + n[8] = 0; + // This needs to be done differently. We cannot simply assume that all lumps where the first character's high bit is set are compressed without verification. + // This requires explicit toggling for precisely the files that need it. +#if 0 + Lumps[i].Compressed = !(gameinfo.flags & GI_SHAREWARE) && (n[0] & 0x80) == 0x80; +#else + Lumps[i].Compressed = false; +#endif + n[0] &= ~0x80; + Lumps[i].LumpNameSetup(n); + + Lumps[i].Owner = this; + Lumps[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos); + Lumps[i].LumpSize = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size); + Lumps[i].Namespace = ns_global; + Lumps[i].Flags = Lumps[i].Compressed ? LUMPF_COMPRESSED | LUMPF_SHORTNAME : LUMPF_SHORTNAME; + + // Check if the lump is within the WAD file and print a warning if not. + if (Lumps[i].Position + Lumps[i].LumpSize > wadSize || Lumps[i].Position < 0 || Lumps[i].LumpSize < 0) + { + if (Lumps[i].LumpSize != 0) + { + Printf(PRINT_HIGH, "%s: Lump %s contains invalid positioning info and will be ignored\n", FileName.GetChars(), Lumps[i].getName()); + Lumps[i].LumpNameSetup(""); + } + Lumps[i].LumpSize = Lumps[i].Position = 0; + } + } + + GenerateHash(); // Do this before the lump processing below. + + if (!quiet) // don't bother with namespaces in quiet mode. We won't need them. + { + SetNamespace("S_START", "S_END", ns_sprites); + SetNamespace("F_START", "F_END", ns_flats, true); + SetNamespace("C_START", "C_END", ns_colormaps); + SetNamespace("A_START", "A_END", ns_acslibrary); + SetNamespace("TX_START", "TX_END", ns_newtextures); + SetNamespace("V_START", "V_END", ns_strifevoices); + SetNamespace("HI_START", "HI_END", ns_hires); + SetNamespace("VX_START", "VX_END", ns_voxels); + SkinHack(); + } + return true; +} + +//========================================================================== +// +// IsMarker +// +// (from BOOM) +// +//========================================================================== + +inline bool FWadFile::IsMarker(int lump, const char *marker) +{ + if (Lumps[lump].getName()[0] == marker[0]) + { + return (!strcmp(Lumps[lump].getName(), marker) || + (marker[1] == '_' && !strcmp(Lumps[lump].getName() +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, bool flathack) +{ + bool warned = false; + int numstartmarkers = 0, numendmarkers = 0; + unsigned int i; + TArray markers; + + for(i = 0; i < NumLumps; i++) + { + if (IsMarker(i, startmarker)) + { + Marker m = { 0, i }; + markers.Push(m); + numstartmarkers++; + } + else if (IsMarker(i, endmarker)) + { + Marker m = { 1, i }; + markers.Push(m); + numendmarkers++; + } + } + + if (numstartmarkers == 0) + { + if (numendmarkers == 0) return; // no markers found + + Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", 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 i = 0; i < end; i++) + { + if (Lumps[i].LumpSize == 4096) + { + // We can't add this to the flats namespace but + // it needs to be flagged for the texture manager. + DPrintf(DMSG_NOTIFY, "Marking %s as potential flat\n", Lumps[i].getName()); + Lumps[i].Flags |= LUMPF_MAYBEFLAT; + } + } + } + return; + } + + i = 0; + while (i < markers.Size()) + { + int start, end; + if (markers[i].markertype != 0) + { + Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); + i++; + continue; + } + start = i++; + + // skip over subsequent x_START markers + while (i < markers.Size() && markers[i].markertype == 0) + { + Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", startmarker); + i++; + continue; + } + // same for x_END markers + while (i < markers.Size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1)) + { + Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", endmarker); + i++; + continue; + } + // We found a starting marker but no end marker. Ignore this block. + if (i >= markers.Size()) + { + Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", startmarker, endmarker); + end = NumLumps; + } + else + { + end = markers[i++].index; + } + + // we found a marked block + DPrintf(DMSG_NOTIFY, "Found %s block at (%d-%d)\n", startmarker, markers[start].index, end); + for(int j = markers[start].index + 1; j < end; j++) + { + if (Lumps[j].Namespace != ns_global) + { + if (!warned) + { + Printf(TEXTCOLOR_YELLOW"WARNING: Overlapping namespaces found (lump %d)\n", j); + } + warned = true; + } + else if (space == ns_sprites && Lumps[j].LumpSize < 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 + DPrintf(DMSG_WARNING, " Skipped empty sprite %s (lump %d)\n", Lumps[j].getName(), j); + } + else + { + Lumps[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 () +{ + // 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++) + { + FResourceLump *lump = &Lumps[i]; + + if (!strnicmp(lump->getName(), "S_SKIN", 6)) + { // Wad has at least one skin. + lump->LumpNameSetup("S_SKIN"); + if (!skinned) + { + skinned = true; + uint32_t j; + + for (j = 0; j < NumLumps; j++) + { + Lumps[j].Namespace = namespc; + } + namespc++; + } + } + if ((lump->getName()[0] == 'M' && + lump->getName()[1] == 'A' && + lump->getName()[2] == 'P' && + lump->getName()[3] >= '0' && lump->getName()[3] <= '9' && + lump->getName()[4] >= '0' && lump->getName()[4] <= '9' && + lump->getName()[5] >= '\0') + || + (lump->getName()[0] == 'E' && + lump->getName()[1] >= '0' && lump->getName()[1] <= '9' && + lump->getName()[2] == 'M' && + lump->getName()[3] >= '0' && lump->getName()[3] <= '9' && + lump->getName()[4] >= '\0')) + { + hasmap = true; + } + } + if (skinned && hasmap) + { + Printf (TEXTCOLOR_BLUE + "The maps in %s will not be loaded because it has a skin.\n" + TEXTCOLOR_BLUE + "You should remove the skin from the wad to play these maps.\n", + FileName.GetChars()); + } +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +{ + char head[4]; + + if (file.GetLength() >= 12) + { + file.Seek(0, FileReader::SeekSet); + file.Read(&head, 4); + file.Seek(0, FileReader::SeekSet); + if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) + { + FResourceFile *rf = new FWadFile(filename, file); + if (rf->Open(quiet, filter)) return rf; + + file = std::move(rf->Reader); // to avoid destruction of reader + delete rf; + } + } + return NULL; +} + diff --git a/source/common/filesystem/file_whres.cpp b/source/common/filesystem/file_whres.cpp new file mode 100644 index 000000000..1c2a6d79c --- /dev/null +++ b/source/common/filesystem/file_whres.cpp @@ -0,0 +1,158 @@ +/* +** file_whres.cpp +** +** reads a Witchaven/TekWar sound resource file +** +**--------------------------------------------------------------------------- +** Copyright 2009-2019 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 "printf.h" +#include "cmdlib.h" + +//========================================================================== +// +// +// +//========================================================================== + +struct whresentry +{ + int filepospage, filelen, priority; +} ; + +struct dpackheader_t +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} ; + + +//========================================================================== +// +// Wad file +// +//========================================================================== + +class FWHResFile : public FUncompressedFile +{ + FString basename; +public: + FWHResFile(const char * filename, FileReader &file); + bool Open(bool quiet, LumpFilterInfo* filter); +}; + + +//========================================================================== +// +// FWadFile::FWadFile +// +// Initializes a WAD file +// +//========================================================================== + +FWHResFile::FWHResFile(const char *filename, FileReader &file) + : FUncompressedFile(filename, file) +{ + basename = ExtractFileBase(filename, false); +} + +//========================================================================== +// +// Open it +// +//========================================================================== + +bool FWHResFile::Open(bool quiet, LumpFilterInfo*) +{ + int directory[1024]; + + Reader.Seek(-4096, FileReader::SeekEnd); + Reader.Read(directory, 4096); + + int nl =1024/3; + Lumps.Resize(nl); + + + int i = 0; + for(int k = 0; k < nl; k++) + { + int offset = LittleLong(directory[k*3]) * 4096; + int length = LittleLong(directory[k*3+1]); + if (length <= 0) break; + FStringf synthname("%s/%04d", basename.GetChars(), k); + Lumps[i].LumpNameSetup(synthname); + Lumps[i].Owner = this; + Lumps[i].Position = offset; + Lumps[i].LumpSize = length; + i++; + } + NumLumps = i; + Lumps.Clamp(NumLumps); + Lumps.ShrinkToFit(); + return true; +} + + +//========================================================================== +// +// File open +// +//========================================================================== + +FResourceFile *CheckWHRes(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +{ + if (file.GetLength() >= 8192) // needs to be at least 8192 to contain one file and the directory. + { + int directory[1024]; + int nl =1024/3; + + file.Seek(-4096, FileReader::SeekEnd); + file.Read(directory, 4096); + + int checkpos = 0; + for(int k = 0; k < nl; k++) + { + int offset = LittleLong(directory[k*3]); + int length = LittleLong(directory[k*3+1]); + if (length <= 0 && offset == 0) break; + if (offset != checkpos || length <= 0) return nullptr; + checkpos += (length+4095) / 4096; + } + FResourceFile *rf = new FWHResFile(filename, file); + if (rf->Open(quiet, filter)) return rf; + file = std::move(rf->Reader); // to avoid destruction of reader + delete rf; + } + return NULL; +} + \ No newline at end of file diff --git a/source/core/filesystem/file_zip.cpp b/source/common/filesystem/file_zip.cpp similarity index 80% rename from source/core/filesystem/file_zip.cpp rename to source/common/filesystem/file_zip.cpp index ecba36dce..ac39d0d2c 100644 --- a/source/core/filesystem/file_zip.cpp +++ b/source/common/filesystem/file_zip.cpp @@ -34,15 +34,14 @@ */ #include -#include -#include "printf.h" #include "file_zip.h" -#include "ancientzip.h" +#include "cmdlib.h" #include "templates.h" -//#include "v_text.h" -//#include "w_wad.h" +#include "printf.h" #include "w_zip.h" +#include "ancientzip.h" + #define BUFREADCOMMENT (0x400) //========================================================================== @@ -68,7 +67,7 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L case METHOD_LZMA: { FileReader frz; - if (frz.OpenDecompressor(Reader, LumpSize, Method, false, nullptr)) + if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { I_Error("%s", err); })) { frz.Read(Cache, LumpSize); } @@ -94,9 +93,9 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int L return false; } } - catch (const CRecoverableError &err) + catch (CRecoverableError &err) { - Printf("%s\n", err.what()); + Printf("%s\n", err.GetMessage()); return false; } return true; @@ -125,7 +124,7 @@ static uint32_t Zip_FindCentralDir(FileReader &fin) uint32_t uPosFound=0; FileSize = (uint32_t)fin.GetLength(); - uMaxBack = std::min(0xffff, FileSize); + uMaxBack = MIN(0xffff, FileSize); uBackRead = 4; while (uBackRead < uMaxBack) @@ -138,7 +137,7 @@ static uint32_t Zip_FindCentralDir(FileReader &fin) uBackRead += BUFREADCOMMENT; uReadPos = FileSize - uBackRead; - uReadSize = std::min((BUFREADCOMMENT + 4), (FileSize - uReadPos)); + uReadSize = MIN((BUFREADCOMMENT + 4), (FileSize - uReadPos)); if (fin.Seek(uReadPos, FileReader::SeekSet) != 0) break; @@ -171,7 +170,7 @@ FZipFile::FZipFile(const char * filename, FileReader &file) Lumps = NULL; } -bool FZipFile::Open(bool quiet) +bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) { uint32_t centraldir = Zip_FindCentralDir(Reader); FZipEndOfCentralDirectory info; @@ -181,7 +180,7 @@ bool FZipFile::Open(bool quiet) if (centraldir == 0) { - if (!quiet) Printf("\n%s: ZIP file corrupt!\n", FileName.GetChars()); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", FileName.GetChars()); return false; } @@ -193,7 +192,7 @@ bool FZipFile::Open(bool quiet) if (info.NumEntries != info.NumEntriesOnAllDisks || info.FirstDisk != 0 || info.DiskNumber != 0) { - if (!quiet) Printf("\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); return false; } @@ -209,6 +208,61 @@ bool FZipFile::Open(bool quiet) char *dirptr = (char*)directory; FZipLump *lump_p = Lumps; + FString name0; + bool foundspeciallump = false; + + // Check if all files have the same prefix so that this can be stripped out. + // This will only be done if there is either a MAPINFO, ZMAPINFO or GAMEINFO lump in the subdirectory, denoting a ZDoom mod. + if (NumLumps > 1) for (uint32_t i = 0; i < NumLumps; i++) + { + FZipCentralDirectoryInfo *zip_fh = (FZipCentralDirectoryInfo *)dirptr; + + int len = LittleShort(zip_fh->NameLength); + FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + + dirptr += sizeof(FZipCentralDirectoryInfo) + + LittleShort(zip_fh->NameLength) + + LittleShort(zip_fh->ExtraLength) + + LittleShort(zip_fh->CommentLength); + + if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. + { + free(directory); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); + return false; + } + + name.ToLower(); + if (i == 0) + { + // check for special names, if one of these gets found this must be treated as a normal zip. + bool isspecial = name.IndexOf("/") < 0 || (filter && filter->reservedFolders.Find(name) < filter->reservedFolders.Size()); + if (isspecial) break; + name0 = name; + } + else + { + if (name.IndexOf(name0) != 0) + { + name0 = ""; + break; + } + else if (!foundspeciallump && filter) + { + // at least one of the more common definition lumps must be present. + for (auto &p : filter->requiredPrefixes) + { + if (name.IndexOf(name0 + p) == 0) + { + foundspeciallump = true; + break; + } + } + } + } + } + // If it ran through the list without finding anything it should not attempt any path remapping. + if (!foundspeciallump) name0 = ""; dirptr = (char*)directory; lump_p = Lumps; @@ -218,6 +272,7 @@ bool FZipFile::Open(bool quiet) int len = LittleShort(zip_fh->NameLength); FString name(dirptr + sizeof(FZipCentralDirectoryInfo), len); + if (name0.IsNotEmpty()) name = name.Mid(name0.Len()); dirptr += sizeof(FZipCentralDirectoryInfo) + LittleShort(zip_fh->NameLength) + LittleShort(zip_fh->ExtraLength) + @@ -226,7 +281,7 @@ bool FZipFile::Open(bool quiet) if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. { free(directory); - if (!quiet) Printf("\n%s: Central directory corrupted.", FileName.GetChars()); + if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); return false; } @@ -246,7 +301,7 @@ bool FZipFile::Open(bool quiet) zip_fh->Method != METHOD_IMPLODE && zip_fh->Method != METHOD_SHRINK) { - if (!quiet) Printf("\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); + if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); skipped++; continue; } @@ -254,34 +309,36 @@ bool FZipFile::Open(bool quiet) zip_fh->Flags = LittleShort(zip_fh->Flags); if (zip_fh->Flags & ZF_ENCRYPTED) { - if (!quiet) Printf("\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); + if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); skipped++; continue; } - name.Substitute("\\", "/"); + FixPathSeperator(name); name.ToLower(); lump_p->LumpNameSetup(name); lump_p->LumpSize = LittleLong(zip_fh->UncompressedSize); lump_p->Owner = this; // The start of the Reader will be determined the first time it is accessed. - lump_p->Flags = LUMPF_ZIPFILE | LUMPFZIP_NEEDFILESTART; + lump_p->Flags = LUMPF_FULLPATH; + lump_p->NeedFileStart = true; lump_p->Method = uint8_t(zip_fh->Method); if (lump_p->Method != METHOD_STORED) lump_p->Flags |= LUMPF_COMPRESSED; lump_p->GPFlags = zip_fh->Flags; lump_p->CRC32 = zip_fh->CRC32; lump_p->CompressedSize = LittleLong(zip_fh->CompressedSize); lump_p->Position = LittleLong(zip_fh->LocalHeaderOffset); + lump_p->CheckEmbedded(); lump_p++; } // Resize the lump record array to its actual size NumLumps -= skipped; free(directory); - if (!quiet) Printf(", %d lumps\n", NumLumps); - PostProcessArchive(&Lumps[0], sizeof(FZipLump)); + GenerateHash(); + PostProcessArchive(&Lumps[0], sizeof(FZipLump), filter); return true; } @@ -305,7 +362,7 @@ FZipFile::~FZipFile() FCompressedBuffer FZipLump::GetRawData() { FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)CompressedSize, Method, GPFlags, CRC32, new char[CompressedSize] }; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + if (NeedFileStart) SetLumpAddress(); Owner->Reader.Seek(Position, FileReader::SeekSet); Owner->Reader.Read(cbuf.mBuffer, CompressedSize); return cbuf; @@ -329,7 +386,7 @@ void FZipLump::SetLumpAddress() Owner->Reader.Read(&localHeader, sizeof(localHeader)); skiplen = LittleShort(localHeader.NameLength) + LittleShort(localHeader.ExtraLength); Position += sizeof(localHeader) + skiplen; - Flags &= ~LUMPFZIP_NEEDFILESTART; + NeedFileStart = false; } //========================================================================== @@ -344,7 +401,7 @@ FileReader *FZipLump::GetReader() // In that case always force caching of the lump if (Method == METHOD_STORED) { - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + if (NeedFileStart) SetLumpAddress(); Owner->Reader.Seek(Position, FileReader::SeekSet); return &Owner->Reader; } @@ -357,13 +414,23 @@ FileReader *FZipLump::GetReader() // //========================================================================== -int FZipLump::ValidateCache() +int FZipLump::FillCache() { - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + if (NeedFileStart) SetLumpAddress(); + const char *buffer; + + if (Method == METHOD_STORED && (buffer = Owner->Reader.GetBuffer()) != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache.Resize(LumpSize); - UncompressZipLump((char*)Cache.Data(), Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); + Cache = new char[LumpSize]; + UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); + RefCount = 1; return 1; } @@ -376,7 +443,7 @@ int FZipLump::ValidateCache() int FZipLump::GetFileOffset() { if (Method != METHOD_STORED) return -1; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + if (NeedFileStart) SetLumpAddress(); return Position; } @@ -386,7 +453,7 @@ int FZipLump::GetFileOffset() // //========================================================================== -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet) +FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) { char head[4]; @@ -398,7 +465,7 @@ FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet) if (!memcmp(head, "PK\x3\x4", 4)) { FResourceFile *rf = new FZipFile(filename, file); - if (rf->Open(quiet)) return rf; + if (rf->Open(quiet, filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/source/core/filesystem/file_zip.h b/source/common/filesystem/file_zip.h similarity index 77% rename from source/core/filesystem/file_zip.h rename to source/common/filesystem/file_zip.h index 8d0600ba3..330e7289d 100644 --- a/source/core/filesystem/file_zip.h +++ b/source/common/filesystem/file_zip.h @@ -3,11 +3,6 @@ #include "resourcefile.h" -enum -{ - LUMPFZIP_NEEDFILESTART = 128 -}; - //========================================================================== // // Zip Lump @@ -18,17 +13,18 @@ struct FZipLump : public FResourceLump { uint16_t GPFlags; uint8_t Method; + bool NeedFileStart; int CompressedSize; int Position; unsigned CRC32; - virtual FileReader *GetReader() override; - virtual int ValidateCache() override; + virtual FileReader *GetReader(); + virtual int FillCache(); private: void SetLumpAddress(); - virtual int GetFileOffset() override; - FCompressedBuffer GetRawData() override; + virtual int GetFileOffset(); + FCompressedBuffer GetRawData(); }; @@ -45,9 +41,9 @@ class FZipFile : public FResourceFile public: FZipFile(const char * filename, FileReader &file); virtual ~FZipFile(); - bool Open(bool quiet); + bool Open(bool quiet, LumpFilterInfo* filter); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; -#endif +#endif \ No newline at end of file diff --git a/source/common/filesystem/filesystem.cpp b/source/common/filesystem/filesystem.cpp new file mode 100644 index 000000000..2bced8429 --- /dev/null +++ b/source/common/filesystem/filesystem.cpp @@ -0,0 +1,1707 @@ +/* +** filesystem.cpp +** +**--------------------------------------------------------------------------- +** Copyright 1998-2009 Randy Heit +** Copyright 2005-2020 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. +**--------------------------------------------------------------------------- +** +** +*/ + + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include + +#include "m_argv.h" +#include "cmdlib.h" +#include "filesystem.h" +#include "m_crc32.h" +#include "printf.h" +#include "md5.h" + +extern FILE* hashfile; + +// MACROS ------------------------------------------------------------------ + +#define NULL_INDEX (0xffffffff) + + +struct FileSystem::LumpRecord +{ + FResourceLump *lump; + FTexture* linkedTexture; + LumpShortName shortName; + FString longName; + int rfnum; + int Namespace; + int resourceId; + + void SetFromLump(int filenum, FResourceLump* lmp) + { + lump = lmp; + rfnum = filenum; + linkedTexture = nullptr; + + if (lump->Flags & LUMPF_SHORTNAME) + { + uppercopy(shortName.String, lump->getName()); + shortName.String[8] = 0; + longName = ""; + Namespace = lump->GetNamespace(); + resourceId = 0; + } + else if ((lump->Flags & LUMPF_EMBEDDED) || !lump->getName() || !*lump->getName()) + { + shortName.qword = 0; + longName = ""; + Namespace = ns_hidden; + resourceId = 0; + } + else + { + longName = lump->getName(); + resourceId = lump->GetIndexNum(); + + // 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.GetChars(), "flats/", 6) ? ns_flats : + !strncmp(longName.GetChars(), "textures/", 9) ? ns_newtextures : + !strncmp(longName.GetChars(), "hires/", 6) ? ns_hires : + !strncmp(longName.GetChars(), "sprites/", 8) ? ns_sprites : + !strncmp(longName.GetChars(), "voxels/", 7) ? ns_voxels : + !strncmp(longName.GetChars(), "colormaps/", 10) ? ns_colormaps : + !strncmp(longName.GetChars(), "acs/", 4) ? ns_acslibrary : + !strncmp(longName.GetChars(), "voices/", 7) ? ns_strifevoices : + !strncmp(longName.GetChars(), "patches/", 8) ? ns_patches : + !strncmp(longName.GetChars(), "graphics/", 9) ? ns_graphics : + !strncmp(longName.GetChars(), "sounds/", 7) ? ns_sounds : + !strncmp(longName.GetChars(), "music/", 6) ? ns_music : + !strchr(longName.GetChars(), '/') ? ns_global : + ns_hidden; + + if (Namespace == ns_hidden) shortName.qword = 0; + else + { + long slash = longName.LastIndexOf('/'); + FString base = (slash >= 0) ? longName.Mid(slash + 1) : longName; + auto dot = base.LastIndexOf('.'); + if (dot >= 0) base.Truncate(dot); + uppercopy(shortName.String, base); + shortName.String[8] = 0; + + // 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 = '\\'; + } + } + } + } + } +}; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void PrintLastError (); + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FileSystem fileSystem; + +// CODE -------------------------------------------------------------------- + +FileSystem::FileSystem() +{ + // This is needed to initialize the LumpRecord array, which depends on data only available here. +} + +FileSystem::~FileSystem () +{ + DeleteAll(); +} + +void FileSystem::DeleteAll () +{ + Hashes.Clear(); + NumEntries = 0; + + // explicitly delete all manually added lumps. + for (auto &frec : FileInfo) + { + if (frec.rfnum == -1) delete frec.lump; + } + FileInfo.Clear(); + for (int i = Files.Size() - 1; i >= 0; --i) + { + delete Files[i]; + } + Files.Clear(); +} + +//========================================================================== +// +// InitMultipleFiles +// +// Pass a null terminated list 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. +// +//========================================================================== + +void FileSystem::InitSingleFile(const char* filename, bool quiet) +{ + TArray filenames; + filenames.Push(filename); + InitMultipleFiles(filenames, true); +} + +void FileSystem::InitMultipleFiles (TArray &filenames, bool quiet, LumpFilterInfo* filter) +{ + int numfiles; + + // open all the files, load headers, and count lumps + DeleteAll(); + numfiles = 0; + + for(unsigned i=0;iGetHash().GetChars()); + MoveLumpsInFolder(path); + } + + NumEntries = FileInfo.Size(); + if (NumEntries == 0) + { + if (!quiet) I_FatalError("W_InitMultipleFiles: no files found"); + else return; + } + if (filter && filter->postprocessFunc) filter->postprocessFunc(); + + // [RH] Set up hash table + InitHashChains (); +} + +//========================================================================== +// +// AddLump +// +// Adds a given lump to the directory. Does not perform rehashing +// +//========================================================================== + +void FileSystem::AddLump(FResourceLump *lump) +{ + FileSystem::LumpRecord *lumprec = &FileInfo[FileInfo.Reserve(1)]; + lumprec->SetFromLump(-1, lump); +} + +//----------------------------------------------------------------------- +// +// Adds an external file to the lump list but not to the hash chains +// It's just a simple means to assign a lump number to some file so that +// the texture manager can read from it. +// +//----------------------------------------------------------------------- + +int FileSystem::AddExternalFile(const char *filename) +{ + FResourceLump *lump = new FExternalLump(filename); + AddLump(lump); + return FileInfo.Size() - 1; // later +} + +//========================================================================== +// +// AddFromBuffer +// +// Adds an in-memory resource to the virtual directory +// +//========================================================================== + +int FileSystem::AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags) +{ + FStringf fullname("%s.%s", name, type); + auto newlump = new FMemoryLump(data, size); + newlump->LumpNameSetup(fullname); + AddLump(newlump); + FileInfo.Last().resourceId = id; + return FileInfo.Size()-1; +} + +//========================================================================== +// +// AddFile +// +// Files with a .wad extension are wadlink files with multiple lumps, +// other files are single lumps with the base filename for the lump name. +// +// [RH] Removed reload hack +//========================================================================== + +void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, LumpFilterInfo* filter) +{ + int startlump; + bool isdir = false; + FileReader filereader; + + if (filer == nullptr) + { + // Does this exist? If so, is it a directory? + if (!DirEntryExists(filename, &isdir)) + { + if (!quiet) + { + Printf(TEXTCOLOR_RED "%s: File or Directory not found\n", filename); + PrintLastError(); + } + return; + } + + if (!isdir) + { + if (!filereader.OpenFile(filename)) + { // Didn't find file + if (!quiet) + { + Printf(TEXTCOLOR_RED "%s: File not found\n", filename); + PrintLastError(); + } + return; + } + } + } + else filereader = std::move(*filer); + + if (!batchrun && !quiet) Printf (" adding %s", filename); + startlump = NumEntries; + + FResourceFile *resfile; + + if (!isdir) + resfile = FResourceFile::OpenResourceFile(filename, filereader, quiet, false, filter); + else + resfile = FResourceFile::OpenDirectory(filename, quiet, filter); + + if (resfile != NULL) + { + if (!quiet && !batchrun) Printf(", %d lumps\n", resfile->LumpCount()); + + uint32_t lumpstart = FileInfo.Size(); + + resfile->SetFirstLump(lumpstart); + for (uint32_t i=0; i < resfile->LumpCount(); i++) + { + FResourceLump *lump = resfile->GetLump(i); + FileSystem::LumpRecord *lump_p = &FileInfo[FileInfo.Reserve(1)]; + lump_p->SetFromLump(Files.Size(), lump); + } + + Files.Push(resfile); + + for (uint32_t i=0; i < resfile->LumpCount(); i++) + { + FResourceLump *lump = resfile->GetLump(i); + if (lump->Flags & LUMPF_EMBEDDED) + { + FString path; + path.Format("%s:%s", filename, lump->getName()); + auto embedded = lump->NewReader(); + AddFile(path, &embedded, quiet, filter); + } + } + + if (hashfile && !quiet) + { + uint8_t cksum[16]; + char cksumout[33]; + memset(cksumout, 0, sizeof(cksumout)); + + if (filereader.isOpen()) + { + MD5Context md5; + filereader.Seek(0, FileReader::SeekSet); + md5Update(filereader, md5, (unsigned)filereader.GetLength()); + md5.Final(cksum); + + for (size_t j = 0; j < sizeof(cksum); ++j) + { + sprintf(cksumout + (j * 2), "%02X", cksum[j]); + } + + fprintf(hashfile, "file: %s, hash: %s, size: %d\n", filename, cksumout, (int)filereader.GetLength()); + } + + else + fprintf(hashfile, "file: %s, Directory structure\n", filename); + + for (uint32_t i = 0; i < resfile->LumpCount(); i++) + { + FResourceLump *lump = resfile->GetLump(i); + + if (!(lump->Flags & LUMPF_EMBEDDED)) + { + MD5Context md5; + auto reader = lump->NewReader(); + md5Update(reader, md5, lump->LumpSize); + md5.Final(cksum); + + for (size_t j = 0; j < sizeof(cksum); ++j) + { + sprintf(cksumout + (j * 2), "%02X", cksum[j]); + } + + fprintf(hashfile, "file: %s, lump: %s, hash: %s, size: %d\n", filename, lump->getName(), cksumout, lump->LumpSize); + } + } + } + return; + } +} + +//========================================================================== +// +// CheckIfResourceFileLoaded +// +// Returns true if the specified file is loaded, false otherwise. +// If a fully-qualified path is specified, then the file must match exactly. +// Otherwise, any file with that name will work, whatever its path. +// Returns the file's index if found, or -1 if not. +// +//========================================================================== + +int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept +{ + unsigned int i; + + if (strrchr (name, '/') != NULL) + { + for (i = 0; i < Files.Size(); ++i) + { + if (stricmp (GetResourceFileFullName (i), name) == 0) + { + return i; + } + } + } + else + { + for (i = 0; i < Files.Size(); ++i) + { + auto pth = ExtractFileBase(GetResourceFileName(i), true); + if (stricmp (pth.GetChars(), name) == 0) + { + return i; + } + } + } + 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) +{ + 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[LumpNameHash (uname) % 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. + if (space > ns_specialzipdirectory && lump.Namespace == ns_global && + !(lump.lump->Flags & LUMPF_FULLPATH)) break; + } + i = NextLumpIndex[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +int FileSystem::CheckNumForName (const char *name, int space, int rfnum, bool exact) +{ + union + { + char uname[8]; + uint64_t qname; + }; + uint32_t i; + + if (rfnum < 0) + { + return CheckNumForName (name, space); + } + + uppercopy (uname, name); + i = FirstLumpIndex[LumpNameHash (uname) % 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) +{ + int i; + + i = CheckNumForName (name, space); + + if (i == -1) + I_Error ("GetNumForName: %s not found!", name); + + return i; +} + + +//========================================================================== +// +// CheckNumForFullName +// +// Same as above but looks for a fully qualified name from a .zip +// These don't care about namespaces though because those are part +// of the path. +// +//========================================================================== + +int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) +{ + uint32_t i; + + if (name == NULL) + { + return -1; + } + if (*name == '/') name++; // ignore leading slashes in file names. + uint32_t *fli = ignoreext ? FirstLumpIndex_NoExt : FirstLumpIndex_FullName; + uint32_t *nli = ignoreext ? NextLumpIndex_NoExt : NextLumpIndex_FullName; + auto len = strlen(name); + + for (i = fli[MakeKey(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] == '.') + { + // 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.GetChars() + len + 1, "./") == nullptr) break; + } + } + + if (i != NULL_INDEX) return i; + + if (trynormal && strlen(name) <= 8 && !strpbrk(name, "./")) + { + return CheckNumForName(name, namespc); + } + return -1; +} + +int FileSystem::CheckNumForFullName (const char *name, int rfnum) +{ + uint32_t i; + + if (rfnum < 0) + { + return CheckNumForFullName (name); + } + + i = FirstLumpIndex_FullName[MakeKey (name) % NumEntries]; + + while (i != NULL_INDEX && + (stricmp(name, FileInfo[i].longName) || FileInfo[i].rfnum != rfnum)) + { + i = NextLumpIndex_FullName[i]; + } + + return i != NULL_INDEX ? i : -1; +} + +//========================================================================== +// +// GetNumForFullName +// +// Calls CheckNumForFullName, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetNumForFullName (const char *name) +{ + int i; + + i = CheckNumForFullName (name); + + if (i == -1) + I_Error ("GetNumForFullName: %s not found!", name); + + return i; +} + +//========================================================================== +// +// FindFile +// +// Looks up a file by name, either eith or without path and extension +// +//========================================================================== + +int FileSystem::FindFileWithExtensions(const char* name, const char *const *exts, int count) +{ + uint32_t i; + + if (name == NULL) + { + return -1; + } + if (*name == '/') name++; // ignore leading slashes in file names. + uint32_t* fli = FirstLumpIndex_NoExt; + uint32_t* nli = NextLumpIndex_NoExt; + auto len = strlen(name); + + for (i = fli[MakeKey(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. + + auto cp = FileInfo[i].longName.GetChars() + 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. + + for (int j = 0; j < count; j++) + { + if (!stricmp(cp, exts[j])) return i; // found a match + } + } + return -1; +} + +//========================================================================== +// +// FindResource +// +// Looks for content based on Blood resource IDs. +// +//========================================================================== + +int FileSystem::FindResource (int resid, const char *type, int filenum) const noexcept +{ + uint32_t i; + + if (type == NULL || resid < 0) + { + return -1; + } + + uint32_t* fli = FirstLumpIndex_ResId; + uint32_t* nli = NextLumpIndex_ResId; + + for (i = fli[resid % NumEntries]; i != NULL_INDEX; i = nli[i]) + { + if (filenum > 0 && FileInfo[i].rfnum != filenum) continue; + if (FileInfo[i].resourceId != resid) continue; + auto extp = strrchr(FileInfo[i].longName, '.'); + if (!extp) continue; + if (!stricmp(extp + 1, type)) return i; + } + return -1; +} + +//========================================================================== +// +// GetResource +// +// Calls GetResource, but bombs out if not found. +// +//========================================================================== + +int FileSystem::GetResource (int resid, const char *type, int filenum) const +{ + int i; + + i = FindResource (resid, type, filenum); + + if (i == -1) + { + I_Error("GetResource: %d of type %s not found!", resid, type); + } + return i; +} + +//========================================================================== +// +// link a texture with a given lump +// +//========================================================================== + +void FileSystem::SetLinkedTexture(int lump, FTexture *tex) +{ + if ((size_t)lump < NumEntries) + { + FileInfo[lump].linkedTexture = tex; + } +} + +//========================================================================== +// +// retrieve linked texture +// +//========================================================================== + +FTexture *FileSystem::GetLinkedTexture(int lump) +{ + if ((size_t)lump < NumEntries) + { + return FileInfo[lump].linkedTexture; + } + return NULL; +} + +//========================================================================== +// +// FileLength +// +// Returns the buffer size needed to load the given lump. +// +//========================================================================== + +int FileSystem::FileLength (int lump) const +{ + if ((size_t)lump >= NumEntries) + { + return -1; + } + return FileInfo[lump].lump->LumpSize; +} + +//========================================================================== +// +// GetFileOffset +// +// Returns the offset from the beginning of the file to the lump. +// Returns -1 if the lump is compressed or can't be read directly +// +//========================================================================== + +int FileSystem::GetFileOffset (int lump) +{ + if ((size_t)lump >= NumEntries) + { + return -1; + } + return FileInfo[lump].lump->GetFileOffset(); +} + +//========================================================================== +// +// +// +//========================================================================== + +int FileSystem::GetFileFlags (int lump) +{ + if ((size_t)lump >= NumEntries) + { + return 0; + } + + return FileInfo[lump].lump->Flags; +} + +//========================================================================== +// +// LumpNameHash +// +// NOTE: s should already be uppercase, in contrast to the BOOM version. +// +// Hash function used for lump names. +// Must be mod'ed with table size. +// Can be used for any 8-character names. +// +//========================================================================== + +uint32_t FileSystem::LumpNameHash (const char *s) +{ + const uint32_t *table = GetCRCTable ();; + uint32_t hash = 0xffffffff; + int i; + + for (i = 8; i > 0 && *s; --i, ++s) + { + hash = CRC1 (hash, *s, table); + } + return hash ^ 0xffffffff; +} + +//========================================================================== +// +// InitHashChains +// +// Prepares the lumpinfos for hashing. +// (Hey! This looks suspiciously like something from Boom! :-) +// +//========================================================================== + +void FileSystem::InitHashChains (void) +{ + unsigned int i, j; + + Hashes.Resize(8 * 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]; + + + // Now set up the chains + for (i = 0; i < (unsigned)NumEntries; i++) + { + j = LumpNameHash (FileInfo[i].shortName.String) % NumEntries; + NextLumpIndex[i] = FirstLumpIndex[j]; + FirstLumpIndex[j] = i; + + // Do the same for the full paths + if (FileInfo[i].longName.IsNotEmpty()) + { + j = MakeKey(FileInfo[i].longName) % NumEntries; + NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j]; + FirstLumpIndex_FullName[j] = i; + + FString nameNoExt = FileInfo[i].longName; + auto dot = nameNoExt.LastIndexOf('.'); + auto slash = nameNoExt.LastIndexOf('/'); + if (dot > slash) nameNoExt.Truncate(dot); + + j = MakeKey(nameNoExt) % NumEntries; + NextLumpIndex_NoExt[i] = FirstLumpIndex_NoExt[j]; + FirstLumpIndex_NoExt[j] = i; + + j = FileInfo[i].resourceId % NumEntries; + NextLumpIndex_ResId[i] = FirstLumpIndex_ResId[j]; + FirstLumpIndex_ResId[j] = i; + + } + } + FileInfo.ShrinkToFit(); + Files.ShrinkToFit(); +} + +//========================================================================== +// +// 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) I_Error("GetShortName: Invalid index"); + return FileInfo[i].shortName; +} + +void FileSystem::RenameFile(int num, const char* newfn) +{ + if ((unsigned)num >= NumEntries) I_Error("RenameFile: Invalid index"); + FileInfo[num].longName = newfn; + // This does not alter the short name - call GetShortname to do that! +} + +//========================================================================== +// +// MoveLumpsInFolder +// +// Moves all content from the given subfolder of the internal +// resources to the current end of the directory. +// Used to allow modifying content in the base files, this is needed +// so that Hacx and Harmony can override some content that clashes +// with localization, and to inject modifying data into mods, in case +// this is needed for some compatibility requirement. +// +//========================================================================== + +static FResourceLump placeholderLump; + +void FileSystem::MoveLumpsInFolder(const char *path) +{ + auto len = strlen(path); + auto rfnum = FileInfo.Last().rfnum; + + unsigned i; + for (i = 0; i < FileInfo.Size(); i++) + { + auto& li = FileInfo[i]; + if (li.rfnum >= GetIwadNum()) break; + if (li.longName.Left(len).CompareNoCase(path) == 0) + { + FileInfo.Push(li); + li.lump = &placeholderLump; // Make the old entry point to something empty. We cannot delete the lump record here because it'd require adjustment of all indices in the list. + auto &ln = FileInfo.Last(); + ln.lump->LumpNameSetup(ln.longName.Mid(len)); + ln.SetFromLump(rfnum, ln.lump); + } + } +} + +//========================================================================== +// +// 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) +{ + union + { + char name8[8]; + uint64_t qname; + }; + LumpRecord *lump_p; + + uppercopy (name8, name); + + assert(lastlump != NULL && *lastlump >= 0); + lump_p = &FileInfo[*lastlump]; + while (lump_p < &FileInfo[NumEntries]) + { + if ((anyns || lump_p->Namespace == ns_global) && lump_p->shortName.qword == qname) + { + int lump = int(lump_p - &FileInfo[0]); + *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) +{ + LumpRecord *lump_p; + + assert(lastlump != NULL && *lastlump >= 0); + lump_p = &FileInfo[*lastlump]; + while (lump_p < &FileInfo[NumEntries]) + { + 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[0]); + *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); + auto lump_p = &FileInfo[*lastlump]; + + if (!noext) + { + while (lump_p < &FileInfo[NumEntries]) + { + if (!stricmp(name, lump_p->longName)) + { + int lump = int(lump_p - &FileInfo[0]); + *lastlump = lump + 1; + return lump; + } + lump_p++; + } + } + else + { + auto len = strlen(name); + while (lump_p < &FileInfo[NumEntries]) + { + auto res = strnicmp(name, lump_p->longName, len); + if (res == 0) + { + auto p = lump_p->longName.GetChars() + len; + if (*p == 0 || (*p == '.' && strpbrk(p + 1, "./") == 0)) + { + int lump = int(lump_p - &FileInfo[0]); + *lastlump = lump + 1; + return lump; + } + } + lump_p++; + } + } + + + *lastlump = NumEntries; + return -1; +} + +//========================================================================== +// +// W_CheckLumpName +// +//========================================================================== + +bool FileSystem::CheckFileName (int lump, const char *name) +{ + if ((size_t)lump >= NumEntries) + return false; + + return !strnicmp (FileInfo[lump].shortName.String, name, 8); +} + +//========================================================================== +// +// GetLumpName +// +//========================================================================== + +void FileSystem::GetFileShortName (char *to, int lump) const +{ + if ((size_t)lump >= NumEntries) + *to = 0; + else + uppercopy (to, FileInfo[lump].shortName.String); +} + +const char* FileSystem::GetFileShortName(int lump) const +{ + if ((size_t)lump >= NumEntries) + return nullptr; + else + return FileInfo[lump].shortName.String; +} + +void FileSystem::GetFileShortName(FString &to, int lump) const +{ + if ((size_t)lump >= NumEntries) + to = FString(); + else { + to = FileInfo[lump].shortName.String; + to.ToUpper(); + } +} + +//========================================================================== +// +// FileSystem :: GetFileFullName +// +// Returns the lump's full name if it has one or its short name if not. +// +//========================================================================== + +const char *FileSystem::GetFileFullName (int lump, bool returnshort) const +{ + if ((size_t)lump >= NumEntries) + return NULL; + else if (FileInfo[lump].longName.IsNotEmpty()) + return FileInfo[lump].longName; + else if (returnshort) + return FileInfo[lump].shortName.String; + else return nullptr; +} + +//========================================================================== +// +// FileSystem :: GetFileFullPath +// +// Returns the name of the lump's wad prefixed to the lump's full name. +// +//========================================================================== + +FString FileSystem::GetFileFullPath(int lump) const +{ + FString foo; + + if ((size_t) lump < NumEntries) + { + foo << GetResourceFileName(FileInfo[lump].rfnum) << ':' << GetFileFullName(lump); + } + 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 +// +// Returns the index number for this lump. This is *not* the lump's position +// in the lump directory, but rather a special value that RFF can associate +// with files. Other archive types will return 0, since they don't have it. +// +//========================================================================== + +int FileSystem::GetResourceId(int lump) const +{ + if ((size_t)lump >= NumEntries) + return -1; + else + return FileInfo[lump].resourceId; +} + +//========================================================================== +// +// GetResourceType +// +// is equivalent with the extension +// +//========================================================================== + +const char *FileSystem::GetResourceType(int lump) const +{ + if ((size_t)lump >= NumEntries) + return nullptr; + else + { + auto p = strrchr(FileInfo[lump].longName.GetChars(), '.'); + if (!p) return ""; // has no extension + if (strchr(p, '/')) return ""; // the '.' is part of a directory. + return p + 1; + } +} + +//========================================================================== +// +// GetFileContainer +// +//========================================================================== + +int FileSystem::GetFileContainer (int lump) const +{ + if ((size_t)lump >= FileInfo.Size()) + return -1; + return FileInfo[lump].rfnum; +} + +//========================================================================== +// +// GetFilesInFolder +// +// Gets all lumps within a single folder in the hierarchy. +// If 'atomic' is set, it treats folders as atomic, i.e. only the +// content of the last found resource file having the given folder name gets used. +// +//========================================================================== + +static int folderentrycmp(const void *a, const void *b) +{ + auto A = (FolderEntry*)a; + auto B = (FolderEntry*)b; + return strcmp(A->name, B->name); +} + +//========================================================================== +// +// +// +//========================================================================== + +unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray &result, bool atomic) const +{ + FString path = inpath; + FixPathSeperator(path); + path.ToLower(); + if (path[path.Len() - 1] != '/') path += '/'; + result.Clear(); + for (unsigned i = 0; i < FileInfo.Size(); i++) + { + if (FileInfo[i].longName.IndexOf(path) == 0) + { + // Only if it hasn't been replaced. + if ((unsigned)fileSystem.CheckNumForFullName(FileInfo[i].longName) == i) + { + result.Push({ FileInfo[i].longName.GetChars(), i }); + } + } + } + if (result.Size()) + { + int maxfile = -1; + if (atomic) + { + // Find the highest resource file having content in the given folder. + for (auto & entry : result) + { + int thisfile = fileSystem.GetFileContainer(entry.lumpnum); + if (thisfile > maxfile) maxfile = thisfile; + } + // Delete everything from older files. + for (int i = result.Size() - 1; i >= 0; i--) + { + if (fileSystem.GetFileContainer(result[i].lumpnum) != maxfile) result.Delete(i); + } + } + qsort(result.Data(), result.Size(), sizeof(FolderEntry), folderentrycmp); + } + return result.Size(); +} + +//========================================================================== +// +// GetFileData +// +// Loads the lump into a TArray and returns it. +// +//========================================================================== + +TArray FileSystem::GetFileData(int lump, int pad) +{ + if ((size_t)lump >= FileInfo.Size()) + return TArray(); + + auto lumpr = OpenFileReader(lump); + auto size = lumpr.GetLength(); + TArray data(size + pad, true); + auto numread = lumpr.Read(data.Data(), size); + + if (numread != size) + { + I_Error("GetFileData: only read %ld of %ld on lump %i\n", + numread, size, lump); + } + if (pad > 0) memset(&data[size], 0, pad); + return data; +} +//========================================================================== +// +// W_ReadFile +// +// Loads the lump into the given buffer, which must be >= W_LumpLength(). +// +//========================================================================== + +void FileSystem::ReadFile (int lump, void *dest) +{ + auto lumpr = OpenFileReader (lump); + auto size = lumpr.GetLength (); + auto numread = lumpr.Read (dest, size); + + if (numread != size) + { + I_Error ("W_ReadFile: only read %ld of %ld on lump %i\n", + numread, size, lump); + } +} + + +//========================================================================== +// +// ReadFile - variant 2 +// +// Loads the lump into a newly created buffer and returns it. +// +//========================================================================== + +FileData FileSystem::ReadFile (int lump) +{ + return FileData(FString(ELumpNum(lump))); +} + +//========================================================================== +// +// OpenFileReader +// +// uses a more abstract interface to allow for easier low level optimization later +// +//========================================================================== + + +FileReader FileSystem::OpenFileReader(int lump) +{ + if ((unsigned)lump >= (unsigned)FileInfo.Size()) + { + I_Error("OpenFileReader: %u >= NumEntries", lump); + } + + auto rl = FileInfo[lump].lump; + auto rd = rl->GetReader(); + + if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !(rl->Flags & LUMPF_COMPRESSED)) + { + FileReader rdr; + rdr.OpenFilePart(*rd, rl->GetFileOffset(), rl->LumpSize); + return rdr; + } + return rl->NewReader(); // This always gets a reader to the cache +} + +FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache) +{ + if ((unsigned)lump >= (unsigned)FileInfo.Size()) + { + I_Error("ReopenFileReader: %u >= NumEntries", lump); + } + + auto rl = FileInfo[lump].lump; + auto rd = rl->GetReader(); + + if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !alwayscache && !(rl->Flags & LUMPF_COMPRESSED)) + { + int fileno = fileSystem.GetFileContainer(lump); + const char *filename = fileSystem.GetResourceFileName(fileno); + FileReader fr; + if (fr.OpenFile(filename, rl->GetFileOffset(), rl->LumpSize)) + { + return fr; + } + } + return rl->NewReader(); // This always gets a reader to the cache +} + +FileReader FileSystem::OpenFileReader(const char* name) +{ + auto lump = CheckNumForFullName(name); + if (lump < 0) return FileReader(); + else return OpenFileReader(lump); +} + +//========================================================================== +// +// GetFileReader +// +// Retrieves the File reader object to access the given WAD +// Careful: This is only useful for real WAD files! +// +//========================================================================== + +FileReader *FileSystem::GetFileReader(int rfnum) +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return NULL; + } + + return Files[rfnum]->GetReader(); +} + +//========================================================================== +// +// GetResourceFileName +// +// Returns the name of the given wad. +// +//========================================================================== + +const char *FileSystem::GetResourceFileName (int rfnum) const noexcept +{ + const char *name, *slash; + + if ((uint32_t)rfnum >= Files.Size()) + { + return NULL; + } + + name = Files[rfnum]->FileName; + slash = strrchr (name, '/'); + return slash != NULL ? slash+1 : name; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetFirstEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->GetFirstEntry(); +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetLastEntry (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->GetFirstEntry() + Files[rfnum]->LumpCount() - 1; +} + +//========================================================================== +// +// +//========================================================================== + +int FileSystem::GetEntryCount (int rfnum) const noexcept +{ + if ((uint32_t)rfnum >= Files.Size()) + { + return 0; + } + + return Files[rfnum]->LumpCount(); +} + + +//========================================================================== +// +// GetResourceFileFullName +// +// Returns the name of the given wad, including any path +// +//========================================================================== + +const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept +{ + if ((unsigned int)rfnum >= Files.Size()) + { + return nullptr; + } + + return Files[rfnum]->FileName; +} + + +//========================================================================== +// +// Clones an existing resource with different properties +// +//========================================================================== + +bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/) +{ + FString name2, type2, path; + + // The old code said 'filename' and ignored the path, this looked like a bug. + auto lump = FindFile(name); + if (lump < 0) return false; // Does not exist. + + auto oldlump = FileInfo[lump]; + int slash = oldlump.longName.LastIndexOf('/'); + if (slash == -1) return true; // already is pathless. + + // just create a new reference to the original data with a different name. + oldlump.longName = oldlump.longName.Mid(slash + 1); + oldlump.resourceId = id; + FileInfo.Push(oldlump); + return true; +} + +// FileData ----------------------------------------------------------------- + +FileData::FileData () +{ +} + +FileData::FileData (const FileData ©) +{ + Block = copy.Block; +} + +FileData &FileData::operator = (const FileData ©) +{ + Block = copy.Block; + return *this; +} + +FileData::FileData (const FString &source) +: Block (source) +{ +} + +FileData::~FileData () +{ +} + +FString::FString (ELumpNum lumpnum) +{ + auto lumpr = fileSystem.OpenFileReader ((int)lumpnum); + auto size = lumpr.GetLength (); + AllocBuffer (1 + size); + auto numread = lumpr.Read (&Chars[0], size); + Chars[size] = '\0'; + + if (numread != size) + { + I_Error ("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", + numread, size, lumpnum, fileSystem.GetFileFullName((int)lumpnum)); + } +} + +//========================================================================== +// +// PrintLastError +// +//========================================================================== + +#ifdef _WIN32 +//#define WIN32_LEAN_AND_MEAN +//#include + +extern "C" { +__declspec(dllimport) unsigned long __stdcall FormatMessageA( + unsigned long dwFlags, + const void *lpSource, + unsigned long dwMessageId, + unsigned long dwLanguageId, + char **lpBuffer, + unsigned long nSize, + va_list *Arguments + ); +__declspec(dllimport) void * __stdcall LocalFree (void *); +__declspec(dllimport) unsigned long __stdcall GetLastError (); +} + +static void PrintLastError () +{ + char *lpMsgBuf; + FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS*/, + NULL, + GetLastError(), + 1 << 10 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, // Default language + &lpMsgBuf, + 0, + NULL + ); + Printf (TEXTCOLOR_RED " %s\n", lpMsgBuf); + // Free the buffer. + LocalFree( lpMsgBuf ); +} +#else +static void PrintLastError () +{ + Printf (TEXTCOLOR_RED " %s\n", strerror(errno)); +} +#endif + +//========================================================================== +// +// NBlood style lookup functions +// +//========================================================================== + +FResourceLump *FileSystem::Lookup(const char *name, const char *type) +{ + FStringf fname("%s.%s", name, type); + auto lump = FindFile(fname); + if (lump >= 0) return FileInfo[lump].lump; + else return nullptr; +} + +FResourceLump *FileSystem::Lookup(unsigned int id, const char *type) +{ + auto lump = FindResource(id, type); + if (lump >= 0) return FileInfo[lump].lump; + else return nullptr; +} +FResourceLump* FileSystem::GetFileAt(int no) +{ + return FileInfo[no].lump; +} + +//========================================================================== +// +// Stand-ins for Blood's resource class +// +//========================================================================== + +const void *FileSystem::Lock(int lump) +{ + if ((size_t)lump >= FileInfo.Size()) return nullptr; + auto lumpp = FileInfo[lump].lump; + return lumpp->Lock(); +} + +void FileSystem::Unlock(int lump) +{ + if ((size_t)lump >= FileInfo.Size()) return; + auto lumpp = FileInfo[lump].lump; + lumpp->Unlock(); +} + +const void *FileSystem::Get(int lump) +{ + if ((size_t)lump >= FileInfo.Size()) return nullptr; + auto lumpp = FileInfo[lump].lump; + auto p = lumpp->Lock(); + lumpp->RefCount = INT_MAX/2; // lock forever. + return p; +} + +//========================================================================== +// +// Stand-ins for Blood's resource class +// +//========================================================================== + +const void *FileSystem::Lock(FResourceLump *lump) +{ + if (lump) return lump->Lock(); + else return nullptr; +} + +void FileSystem::Unlock(FResourceLump *lump) +{ + if (lump) lump->Unlock(); +} + +const void *FileSystem::Load(FResourceLump *lump) +{ + if (lump) + { + auto p = lump->Lock(); + lump->RefCount = INT_MAX/2; // lock forever. + return p; + } + else return nullptr; +} + diff --git a/source/common/filesystem/filesystem.h b/source/common/filesystem/filesystem.h new file mode 100644 index 000000000..f71aefb85 --- /dev/null +++ b/source/common/filesystem/filesystem.h @@ -0,0 +1,237 @@ +#pragma once +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// File system I/O functions. +// +//----------------------------------------------------------------------------- + + + +#include "files.h" +#include "tarray.h" +#include "cmdlib.h" +#include "zstring.h" +#include "resourcefile.h" + +class FResourceFile; +struct FResourceLump; +class FTexture; + +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 +}; + + +// A lump in memory. +class FileData +{ +public: + FileData (); + + FileData (const FileData ©); + FileData &operator= (const FileData ©); + ~FileData (); + void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } + size_t GetSize () { return Block.Len(); } + FString GetString () { return Block; } + +private: + FileData (const FString &source); + + FString Block; + + friend class FileSystem; +}; + +struct FolderEntry +{ + const char *name; + unsigned lumpnum; +}; + +class FileSystem +{ +public: + FileSystem (); + ~FileSystem (); + + // The wadnum for the IWAD + int GetIwadNum() { return IwadIndex; } + void SetIwadNum(int x) { IwadIndex = x; } + + int GetMaxIwadNum() { return MaxIwadIndex; } + void SetMaxIwadNum(int x) { MaxIwadIndex = x; } + + void InitSingleFile(const char *filename, bool quiet = false); + void InitMultipleFiles (TArray &filenames, bool quiet = false, LumpFilterInfo* filter = nullptr); + void AddFile (const char *filename, FileReader *wadinfo, bool quiet, LumpFilterInfo* filter); + int CheckIfResourceFileLoaded (const char *name) noexcept; + void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} + + const char *GetResourceFileName (int filenum) const noexcept; + const char *GetResourceFileFullName (int wadnum) const noexcept; + + int GetFirstEntry(int wadnum) const noexcept; + int GetLastEntry(int wadnum) const noexcept; + int GetEntryCount(int wadnum) const noexcept; + + int CheckNumForName (const char *name, int namespc); + int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true); + int GetNumForName (const char *name, int namespc); + + inline int CheckNumForName (const uint8_t *name) { return CheckNumForName ((const char *)name, ns_global); } + inline int CheckNumForName (const char *name) { return CheckNumForName (name, ns_global); } + inline int CheckNumForName (const FString &name) { return CheckNumForName (name.GetChars()); } + inline int CheckNumForName (const uint8_t *name, int ns) { return CheckNumForName ((const char *)name, ns); } + inline int GetNumForName (const char *name) { return GetNumForName (name, ns_global); } + inline int GetNumForName (const FString &name) { return GetNumForName (name.GetChars(), ns_global); } + inline int GetNumForName (const uint8_t *name) { return GetNumForName ((const char *)name); } + inline int GetNumForName (const uint8_t *name, int ns) { return GetNumForName ((const char *)name, ns); } + + int CheckNumForFullName (const char *name, bool trynormal = false, int namespc = ns_global, bool ignoreext = false); + int CheckNumForFullName (const char *name, int wadfile); + int GetNumForFullName (const char *name); + int FindFile(const char* name) + { + return CheckNumForFullName(name); + } + + bool FileExists(const char* name) + { + return FindFile(name) >= 0; + } + + bool FileExists(const FString& name) + { + return FindFile(name) >= 0; + } + + bool FileExists(const std::string& name) + { + 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); + + inline int CheckNumForFullName(const FString &name, bool trynormal = false, int namespc = ns_global) { return CheckNumForFullName(name.GetChars(), trynormal, namespc); } + inline int CheckNumForFullName (const FString &name, int wadfile) { return CheckNumForFullName(name.GetChars(), wadfile); } + inline int GetNumForFullName (const FString &name) { return GetNumForFullName(name.GetChars()); } + + void SetLinkedTexture(int lump, FTexture *tex); + FTexture *GetLinkedTexture(int lump); + + + void ReadFile (int lump, void *dest); + TArray GetFileData(int lump, int pad = 0); // reads lump into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!) + FileData ReadFile (int lump); + FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); } + + inline TArray LoadFile(const char* name, int padding = 0) + { + auto lump = FindFile(name); + if (lump < 0) return TArray(); + return GetFileData(lump, padding); + } + + FileReader OpenFileReader(int lump); // opens a reader that redirects to the containing file's one. + FileReader ReopenFileReader(int lump, bool alwayscache = false); // opens an independent reader. + FileReader OpenFileReader(const char* name); + + 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); + 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 + + int FileLength (int lump) const; + int GetFileOffset (int lump); // [RH] Returns offset of lump in the wadfile + int GetFileFlags (int lump); // Return the flags for this lump + void GetFileShortName (char *to, int lump) const; // [RH] Copies the lump name to to using uppercopy + void GetFileShortName (FString &to, int lump) const; + const char* GetFileShortName(int lump) const; + const char *GetFileFullName (int lump, bool returnshort = true) const; // [RH] Returns the lump's full name + FString 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 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, TArray &result, bool atomic) const; + + int GetNumEntries() const + { + return NumEntries; + } + + int GetNumWads() const + { + return Files.Size(); + } + + void AddLump(FResourceLump* lump); + int AddExternalFile(const char *filename); + int AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags); + FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD + void InitHashChains(); + + // Blood stuff + FResourceLump* Lookup(const char* name, const char* type); + FResourceLump* Lookup(unsigned int id, const char* type); + + FResourceLump* GetFileAt(int no); + + const void* Lock(int lump); + void Unlock(int lump); + const void* Get(int lump); + static const void* Lock(FResourceLump* lump); + static void Unlock(FResourceLump* lump); + static const void* Load(FResourceLump* lump);; + +protected: + + struct LumpRecord; + + TArray Files; + TArray FileInfo; + + TArray Hashes; // one allocation for all hash lists. + uint32_t *FirstLumpIndex; // [RH] Hashing stuff moved out of lumpinfo structure + uint32_t *NextLumpIndex; + + uint32_t *FirstLumpIndex_FullName; // The same information for fully qualified paths from .zips + uint32_t *NextLumpIndex_FullName; + + uint32_t *FirstLumpIndex_NoExt; // The same information for fully qualified paths from .zips + uint32_t *NextLumpIndex_NoExt; + + uint32_t* FirstLumpIndex_ResId; // The same information for fully qualified paths from .zips + uint32_t* NextLumpIndex_ResId; + + uint32_t NumEntries = 0; // Not necessarily the same as FileInfo.Size() + uint32_t NumWads; + + int IwadIndex = -1; + int MaxIwadIndex = -1; + +private: + void DeleteAll(); + void MoveLumpsInFolder(const char *); + +}; + +extern FileSystem fileSystem; + diff --git a/source/core/filesystem/resourcefile.cpp b/source/common/filesystem/resourcefile.cpp similarity index 70% rename from source/core/filesystem/resourcefile.cpp rename to source/common/filesystem/resourcefile.cpp index 344dde414..08919cee7 100644 --- a/source/core/filesystem/resourcefile.cpp +++ b/source/common/filesystem/resourcefile.cpp @@ -36,10 +36,9 @@ #include #include "resourcefile.h" -#include "name.h" -#include "m_swap.h" -#include "gamecontrol.h" #include "cmdlib.h" +#include "md5.h" + //========================================================================== // @@ -55,13 +54,13 @@ public: FLumpReader(FResourceLump *src) : MemoryReader(NULL, src->LumpSize), source(src) { - bufptr = (const char*)src->Lock(); - src->Cache.Data(); + src->Lock(); + bufptr = src->Cache; } ~FLumpReader() { - source->Unlock(true); + source->Unlock(); } }; @@ -74,34 +73,82 @@ public: FResourceLump::~FResourceLump() { + if (Cache != NULL && RefCount >= 0) + { + delete [] Cache; + Cache = NULL; + } Owner = NULL; } //========================================================================== // -// Sets up the file name information -// This is stored as FNames for various formats. +// Sets up the lump name information for anything not coming from a WAD file. // //========================================================================== void FResourceLump::LumpNameSetup(FString iname) { - auto pathLen = iname.LastIndexOf('/') + 1; - LumpName[FullNameType] = iname.GetChars(); - LumpName[BaseNameType] = iname.GetChars() + pathLen; - - auto extStart = iname.LastIndexOf('.'); - if (extStart <= pathLen) extStart = -1; - if (extStart > 0) + // this causes interference with real Dehacked lumps. + if (!iname.CompareNoCase("dehacked.exe")) { - LumpName[ExtensionType] = iname.GetChars() + extStart + 1; - iname.Truncate(extStart); + iname = ""; } - LumpName[FullNameNoExtType] = iname.GetChars(); - LumpName[BaseNameNoExtType] = iname.GetChars() + pathLen; + + FullName = iname; } +//========================================================================== +// +// Checks for embedded resource files +// +//========================================================================== + +static bool IsWadInFolder(const FResourceFile* const archive, const char* const resPath) +{ + // Checks a special case when was put in + // directory inside + + if (NULL == archive) + { + return false; + } + + const FString dirName = ExtractFileBase(archive->FileName); + const FString fileName = ExtractFileBase(resPath, true); + const FString filePath = dirName + '/' + fileName; + + return 0 == filePath.CompareNoCase(resPath); +} + +void FResourceLump::CheckEmbedded() +{ + // Checks for embedded archives + const char *c = strstr(FullName, ".wad"); + if (c && strlen(c) == 4 && (!strchr(FullName, '/') || IsWadInFolder(Owner, FullName))) + { + Flags |= LUMPF_EMBEDDED; + } + /* later + else + { + if (c==NULL) c = strstr(Name, ".zip"); + if (c==NULL) c = strstr(Name, ".pk3"); + if (c==NULL) c = strstr(Name, ".7z"); + if (c==NULL) c = strstr(Name, ".pak"); + if (c && strlen(c) <= 4) + { + // Mark all embedded archives in any directory + Flags |= LUMPF_EMBEDDED; + memset(Name, 0, 8); + } + } + */ + +} + + //========================================================================== // // this is just for completeness. For non-Zips only an uncompressed lump can @@ -113,8 +160,8 @@ FCompressedBuffer FResourceLump::GetRawData() { FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)LumpSize, METHOD_STORED, 0, 0, new char[LumpSize] }; memcpy(cbuf.mBuffer, Lock(), LumpSize); + Unlock(); cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize); - Unlock(true); return cbuf; } @@ -149,33 +196,15 @@ FileReader FResourceLump::NewReader() void *FResourceLump::Lock() { - if (Cache.Size()) + if (Cache != NULL) { if (RefCount > 0) RefCount++; } else if (LumpSize > 0) { - ValidateCache(); - // NBlood has some endian conversion right in here which is extremely dangerous and needs to be handled differently. - // Fortunately Big Endian platforms are mostly irrelevant so this is something to be sorted out later (if ever) - RefCount++; + FillCache(); } - return Cache.Data(); -} - -//========================================================================== -// -// Caches a lump's content without increasing the reference counter -// -//========================================================================== - -void *FResourceLump::Get() -{ - if (Cache.Size() == 0) - { - ValidateCache(); - } - return Cache.Data(); + return Cache; } //========================================================================== @@ -184,15 +213,17 @@ void *FResourceLump::Get() // //========================================================================== -void FResourceLump::Unlock(bool mayfree) +int FResourceLump::Unlock() { if (LumpSize > 0 && RefCount > 0) { if (--RefCount == 0) { - if (mayfree) Cache.Reset(); + delete [] Cache; + Cache = NULL; } } + return RefCount; } //========================================================================== @@ -201,53 +232,45 @@ void FResourceLump::Unlock(bool mayfree) // //========================================================================== -typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, bool quiet); +typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet); -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet); -FResourceFile *CheckLump(const char *filename,FileReader &file, bool quiet); -FResourceFile *CheckDir(const char *filename, bool quiet, bool nosubdirflag); +FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckLump(const char *filename,FileReader &file, bool quiet, LumpFilterInfo* filter); +FResourceFile *CheckDir(const char *filename, bool quiet, bool nosub, LumpFilterInfo* filter); -static CheckFunc funcs[] = { CheckGRP, CheckRFF, CheckZip, Check7Z, CheckPak, CheckLump }; +static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckLump }; -FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) +FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter) { for(size_t i = 0; i < countof(funcs) - containeronly; i++) { - FResourceFile *resfile = funcs[i](filename, file, quiet); + FResourceFile *resfile = funcs[i](filename, file, quiet, filter); if (resfile != NULL) return resfile; } return NULL; } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter) { - return DoOpenResourceFile(filename, file, quiet, containeronly); + return DoOpenResourceFile(filename, file, quiet, containeronly, filter); } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool quiet, bool containeronly) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool quiet, bool containeronly, LumpFilterInfo* filter) { FileReader file; if (!file.OpenFile(filename)) return nullptr; - return DoOpenResourceFile(filename, file, quiet, containeronly); + return DoOpenResourceFile(filename, file, quiet, containeronly, filter); } -/* -FResourceFile *FResourceFile::OpenResourceFileFromLump(int lumpnum, bool quiet, bool containeronly) +FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet, LumpFilterInfo* filter) { - FileReader file = Wads.ReopenLumpReader(lumpnum); - return DoOpenResourceFile("internal", file, quiet, containeronly); -} -*/ - -FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet, bool nosubdirflag) -{ - return CheckDir(filename, quiet, nosubdirflag); + return CheckDir(filename, quiet, false, filter); } //========================================================================== @@ -275,7 +298,39 @@ int lumpcmp(const void * a, const void * b) { FResourceLump * rec1 = (FResourceLump *)a; FResourceLump * rec2 = (FResourceLump *)b; - return stricmp(rec1->LumpName[FResourceLump::FullNameType].GetChars(), rec2->LumpName[FResourceLump::FullNameType].GetChars()); + return stricmp(rec1->getName(), rec2->getName()); +} + +//========================================================================== +// +// FResourceFile :: GenerateHash +// +// Generates a hash identifier for use in file identification. +// Potential uses are mod-wide compatibility settings or localization add-ons. +// This only hashes the lump directory but not the actual content +// +//========================================================================== + +void FResourceFile::GenerateHash() +{ + // hash the lump directory after sorting + + Hash.Format(("%08X-%04X-"), (unsigned)Reader.GetLength(), NumLumps); + + MD5Context md5; + + uint8_t digest[16]; + for(uint32_t i = 0; i < NumLumps; i++) + { + auto lump = GetLump(i); + md5.Update((const uint8_t*)lump->FullName.GetChars(), (unsigned)lump->FullName.Len() + 1); + md5.Update((const uint8_t*)&lump->LumpSize, 4); + } + md5.Final(digest); + for (auto c : digest) + { + Hash.AppendFormat("%02X", c); + } } //========================================================================== @@ -289,28 +344,30 @@ int lumpcmp(const void * a, const void * b) // //========================================================================== -void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize) +void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize, LumpFilterInfo *filter) { // Entries in archives are sorted alphabetically qsort(lumps, NumLumps, lumpsize, lumpcmp); - + if (!filter) return; // Filter out lumps using the same names as the Autoload.* sections // in the ini file use. We reduce the maximum lump concidered after // each one so that we don't risk refiltering already filtered lumps. uint32_t max = NumLumps; + max -= FilterLumpsByGameType(filter, lumps, lumpsize, max); + long len; int lastpos = -1; FString file; - - auto segments = LumpFilter.Split("."); - FString build; - - for (auto& segment : segments) + FString LumpFilter = filter->dotFilter; + if (LumpFilter.IndexOf('.') < 0) { - if (build.IsEmpty()) build = segment; - else build << "." << segment; - max -= FilterLumps(build, lumps, lumpsize, max); + max -= FilterLumps(LumpFilter, lumps, lumpsize, max); + } + else while ((len = LumpFilter.IndexOf('.', lastpos+1)) > 0) + { + max -= FilterLumps(LumpFilter.Left(len), lumps, lumpsize, max); + lastpos = len; } JunkLeftoverFilters(lumps, lumpsize, max); } @@ -338,6 +395,13 @@ int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, bool found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); + // Workaround for old Doom filter names. + if (!found && filtername.IndexOf("doom.id.doom") == 0) + { + filter.Substitute("doom.id.doom", "doom.doom"); + found = FindPrefixRange(filter, lumps, lumpsize, max, start, end); + } + if (found) { void *from = (uint8_t *)lumps + start * lumpsize; @@ -347,8 +411,8 @@ int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, for (uint32_t i = start; i < end; ++i, lump_p = (uint8_t *)lump_p + lumpsize) { FResourceLump *lump = (FResourceLump *)lump_p; - assert(filter.CompareNoCase(lump->FullName(), (int)filter.Len()) == 0); - lump->LumpNameSetup(lump->FullName() + filter.Len()); + assert(lump->FullName.CompareNoCase(filter, (int)filter.Len()) == 0); + lump->LumpNameSetup(lump->FullName.Mid(filter.Len())); } // Move filtered lumps to the end of the lump list. @@ -374,6 +438,29 @@ int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, return end - start; } +//========================================================================== +// +// FResourceFile :: FilterLumpsByGameType +// +// Matches any lumps that match "filter/game-/*". Includes +// inclusive gametypes like Raven. +// +//========================================================================== + +int FResourceFile::FilterLumpsByGameType(LumpFilterInfo *filter, void *lumps, size_t lumpsize, uint32_t max) +{ + if (filter == nullptr) + { + return 0; + } + int count = 0; + for (auto &fstring : filter->gameTypeFilter) + { + count += FilterLumps(fstring, lumps, lumpsize, max); + } + return count; +} + //========================================================================== // // FResourceFile :: JunkLeftoverFilters @@ -394,8 +481,7 @@ void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t m for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize) { FResourceLump *lump = (FResourceLump *)p; - for (auto &ln : lump->LumpName) - ln = NAME_None; + lump->FullName = ""; } } } @@ -428,11 +514,10 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize { mid = min + (max - min) / 2; lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len()); - + cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); if (cmp == 0) break; - else if (cmp > 0) + else if (cmp < 0) min = mid + 1; else max = mid - 1; @@ -449,7 +534,7 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize { mid = min + (max - min) / 2; lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len()); + cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); // Go left on matches and right on misses. if (cmp == 0) max = mid - 1; @@ -464,7 +549,7 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize { mid = min + (max - min) / 2; lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); - cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len()); + cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); // Go right on matches and left on misses. if (cmp == 0) min = mid + 1; @@ -483,12 +568,10 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize FResourceLump *FResourceFile::FindLump(const char *name) { - FName lname(name, true); - if (lname == NAME_None) return nullptr; for (unsigned i = 0; i < NumLumps; i++) { FResourceLump *lump = GetLump(i); - if (lump->LumpName[FResourceLump::FullNameType] == lname) + if (!stricmp(name, lump->FullName)) { return lump; } @@ -514,11 +597,22 @@ FileReader *FUncompressedLump::GetReader() // //========================================================================== -int FUncompressedLump::ValidateCache() +int FUncompressedLump::FillCache() { + const char * buffer = Owner->Reader.GetBuffer(); + + if (buffer != NULL) + { + // This is an in-memory file so the cache can point directly to the file's data. + Cache = const_cast(buffer) + Position; + RefCount = -1; + return -1; + } + Owner->Reader.Seek(Position, FileReader::SeekSet); - Cache.Resize(LumpSize); - Owner->Reader.Read(Cache.Data(), LumpSize); + Cache = new char[LumpSize]; + Owner->Reader.Read(Cache, LumpSize); + RefCount = 1; return 1; } @@ -573,18 +667,22 @@ FExternalLump::FExternalLump(const char *_filename, int filesize) // //========================================================================== -int FExternalLump::ValidateCache() +int FExternalLump::FillCache() { - Cache.Resize(LumpSize); + Cache = new char[LumpSize]; FileReader f; if (f.OpenFile(Filename)) { - f.Read(Cache.Data(), LumpSize); + f.Read(Cache, LumpSize); } else { - memset(Cache.Data(), 0, LumpSize); + memset(Cache, 0, LumpSize); } + RefCount = 1; return 1; } + + + diff --git a/source/core/filesystem/resourcefile.h b/source/common/filesystem/resourcefile.h similarity index 53% rename from source/core/filesystem/resourcefile.h rename to source/common/filesystem/resourcefile.h index ea94e137a..82ba8c7a5 100644 --- a/source/core/filesystem/resourcefile.h +++ b/source/common/filesystem/resourcefile.h @@ -3,14 +3,24 @@ #ifndef __RESFILE_H #define __RESFILE_H -#include #include "files.h" -#include "zstring.h" -#include "name.h" + +struct LumpFilterInfo +{ + TArray gameTypeFilter; // this can contain multiple entries + FString dotFilter; + + // The following are for checking if the root directory of a zip can be removed. + TArray reservedFolders; + TArray requiredPrefixes; + std::function postprocessFunc; +}; class FResourceFile; class FTexture; +// [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, @@ -20,9 +30,9 @@ typedef enum { ns_colormaps, ns_acslibrary, ns_newtextures, - ns_bloodraw, - ns_bloodsfx, - ns_bloodmisc, + 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, @@ -42,17 +52,14 @@ typedef enum { enum ELumpFlags { - LUMPF_MAYBEFLAT=1, // might be a flat outside F_START/END - LUMPF_ZIPFILE=2, // contains a full path - LUMPF_EMBEDDED=4, // from an embedded WAD - LUMPF_BLOODCRYPT = 8, // encrypted - LUMPF_COMPRESSED = 16, // compressed - LUMPF_SEQUENTIAL = 32, // compressed but a sequential reader can be retrieved. + LUMPF_MAYBEFLAT = 1, // might be a flat outside F_START/END + LUMPF_FULLPATH = 2, // contains a full path. This will trigger extended namespace checks when looking up short names. + LUMPF_EMBEDDED = 4, // marks an embedded resource file for later processing. + LUMPF_SHORTNAME = 8, // the stored name is a short extension-less name + LUMPF_COMPRESSED = 16, // compressed or encrypted, i.e. cannot be read with the container file's reader. }; -class FResourceFile; - -// This holds a compressed Zip entry with all needed info to decompress it. +// This holds a compresed Zip entry with all needed info to decompress it. struct FCompressedBuffer { unsigned mSize; @@ -74,60 +81,50 @@ struct FCompressedBuffer } }; - struct FResourceLump { - enum ENameType - { - FullNameType, - FullNameNoExtType, - BaseNameType, - BaseNameNoExtType, - ExtensionType, - DoomLumpType, - NUMNAMETYPES - }; - friend class FResourceFile; - friend struct FClonedLump; + friend class FWadFile; // this still needs direct access. - unsigned LumpSize = 0; - int RefCount = 0; - int Flags = 0; - int ResourceId = -1; - int Namespace = ns_global; - FName LumpName[NUMNAMETYPES] = {}; - FResourceFile * Owner = nullptr; - TArray Cache; + int LumpSize; + int RefCount; +protected: + FString FullName; +public: + uint8_t Flags; + char * Cache; + FResourceFile * Owner; - FResourceLump() = default; + FResourceLump() + { + Cache = NULL; + Owner = NULL; + Flags = 0; + RefCount = 0; + } virtual ~FResourceLump(); virtual FileReader *GetReader(); virtual FileReader NewReader(); virtual int GetFileOffset() { return -1; } + virtual int GetIndexNum() const { return -1; } + virtual int GetNamespace() const { return 0; } void LumpNameSetup(FString iname); + void CheckEmbedded(); virtual FCompressedBuffer GetRawData(); - virtual void *Lock(); // validates the cache and increases the refcount. - virtual void Unlock(bool freeunrefd = false); // recreases the refcount and optionally frees the buffer - virtual void *Get(); // validates the cache and returns a pointer without locking - - // Wrappers for emulating Blood's resource system + void *Lock(); // validates the cache and increases the refcount. + int Unlock(); // decreases the refcount and frees the buffer + unsigned Size() const{ return LumpSize; } int LockCount() const { return RefCount; } - const char *ResName() const { return LumpName[BaseNameNoExtType].GetChars(); } - const FName ResType() { return LumpName[ExtensionType]; } - const char *FullName() const { return LumpName[FullNameType].GetChars(); } + const char* getName() { return FullName.GetChars(); } protected: - virtual int ValidateCache() { return -1; } + virtual int FillCache() { return -1; } }; -// Map NBlood's resource system to our own. -using DICTNODE = FResourceLump; - class FResourceFile { public: @@ -135,35 +132,38 @@ public: FString FileName; protected: uint32_t NumLumps; + FString Hash; FResourceFile(const char *filename); FResourceFile(const char *filename, FileReader &r); // for archives that can contain directories - void PostProcessArchive(void *lumps, size_t lumpsize); + void GenerateHash(); + void PostProcessArchive(void *lumps, size_t lumpsize, LumpFilterInfo *filter); private: uint32_t FirstLump; int FilterLumps(FString filtername, void *lumps, size_t lumpsize, uint32_t max); + int FilterLumpsByGameType(LumpFilterInfo *filter, void *lumps, size_t lumpsize, uint32_t max); bool FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t max, uint32_t &start, uint32_t &end); void JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max); - static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly); + static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter); public: - static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool quiet = false, bool containeronly = false); - static FResourceFile *OpenResourceFile(const char *filename, bool quiet = false, bool containeronly = false); - static FResourceFile* OpenDirectory(const char* filename, bool quiet = false, bool nosubdirs = false); + static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool quiet = false, bool containeronly = false, LumpFilterInfo* filter = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, bool quiet = false, bool containeronly = false, LumpFilterInfo* filter = nullptr); + static FResourceFile *OpenDirectory(const char *filename, bool quiet = false, LumpFilterInfo* filter = nullptr); virtual ~FResourceFile(); // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; } uint32_t LumpCount() const { return NumLumps; } - uint32_t GetFirstLump() const { return FirstLump; } + uint32_t GetFirstEntry() const { return FirstLump; } void SetFirstLump(uint32_t f) { FirstLump = f; } + const FString &GetHash() const { return Hash; } - - virtual bool Open(bool quiet) = 0; + virtual bool Open(bool quiet, LumpFilterInfo* filter) = 0; virtual FResourceLump *GetLump(int no) = 0; FResourceLump *FindLump(const char *name); }; @@ -172,14 +172,14 @@ struct FUncompressedLump : public FResourceLump { int Position; - FileReader *GetReader() override; - int ValidateCache() override; - virtual int GetFileOffset() override { return Position; } + virtual FileReader *GetReader(); + virtual int FillCache(); + virtual int GetFileOffset() { return Position; } }; -// Base class for uncompressed resource files (GRP, PAK and single lumps) +// Base class for uncompressed resource files (WAD, GRP, PAK and single lumps) class FUncompressedFile : public FResourceFile { protected: @@ -196,7 +196,7 @@ struct FExternalLump : public FResourceLump FString Filename; FExternalLump(const char *_filename, int filesize = -1); - virtual int ValidateCache() override; + virtual int FillCache(); }; @@ -204,29 +204,20 @@ struct FMemoryLump : public FResourceLump { FMemoryLump(const void* data, int length) { + RefCount = INT_MAX / 2; LumpSize = length; - Cache.Resize(length); - memcpy(Cache.Data(), data, length); + Cache = new char[length]; + memcpy(Cache, data, length); } - virtual int ValidateCache() override + + virtual int FillCache() override { RefCount = INT_MAX / 2; // Make sure it never counts down to 0 by resetting it to something high each time it is used. return 1; } }; -struct FClonedLump : public FResourceLump -{ - FResourceLump* parent; - FClonedLump(FResourceLump* lump) - { - parent = lump; - } - void* Lock() override { return parent->Lock(); } - void Unlock(bool mayfree) override { parent->Unlock(mayfree); } - void* Get() override { return parent->Get(); } - int ValidateCache() override { return parent->ValidateCache(); } -}; + diff --git a/source/common/filesystem/w_zip.h b/source/common/filesystem/w_zip.h new file mode 100644 index 000000000..cdf75867d --- /dev/null +++ b/source/common/filesystem/w_zip.h @@ -0,0 +1,70 @@ +#ifndef __W_ZIP +#define __W_ZIP + +#include "basics.h" + +#pragma pack(1) +// FZipCentralInfo +struct FZipEndOfCentralDirectory +{ + uint32_t Magic; + uint16_t DiskNumber; + uint16_t FirstDisk; + uint16_t NumEntries; + uint16_t NumEntriesOnAllDisks; + uint32_t DirectorySize; + uint32_t DirectoryOffset; + uint16_t ZipCommentLength; +} FORCE_PACKED; + +// FZipFileInfo +struct FZipCentralDirectoryInfo +{ + uint32_t Magic; + uint8_t VersionMadeBy[2]; + uint8_t VersionToExtract[2]; + uint16_t Flags; + uint16_t Method; + uint16_t ModTime; + uint16_t ModDate; + uint32_t CRC32; + uint32_t CompressedSize; + uint32_t UncompressedSize; + uint16_t NameLength; + uint16_t ExtraLength; + uint16_t CommentLength; + uint16_t StartingDiskNumber; + uint16_t InternalAttributes; + uint32_t ExternalAttributes; + uint32_t LocalHeaderOffset; + // file name and other variable length info follows +} FORCE_PACKED; + +// FZipLocalHeader +struct FZipLocalFileHeader +{ + uint32_t Magic; + uint8_t VersionToExtract[2]; + uint16_t Flags; + uint16_t Method; + uint16_t ModTime; + uint16_t ModDate; + uint32_t CRC32; + uint32_t CompressedSize; + uint32_t UncompressedSize; + uint16_t NameLength; + uint16_t ExtraLength; + // file name and other variable length info follows +} FORCE_PACKED; + + +#pragma pack() + +#define ZIP_LOCALFILE MAKE_ID('P','K',3,4) +#define ZIP_CENTRALFILE MAKE_ID('P','K',1,2) +#define ZIP_ENDOFDIR MAKE_ID('P','K',5,6) + +// File header flags. +#define ZF_ENCRYPTED 0x1 + +#endif diff --git a/source/common/utility/basics.h b/source/common/utility/basics.h index 2c5fb6f98..1ae1f1764 100644 --- a/source/common/utility/basics.h +++ b/source/common/utility/basics.h @@ -23,6 +23,18 @@ typedef int32_t fixed_t; typedef uint32_t angle_t; +#if defined(__GNUC__) +// With versions of GCC newer than 4.2, it appears it was determined that the +// cost of an unaligned pointer on PPC was high enough to add padding to the +// end of packed structs. For whatever reason __packed__ and pragma pack are +// handled differently in this regard. Note that this only needs to be applied +// to types which are used in arrays or sizeof is needed. This also prevents +// code from taking references to the struct members. +#define FORCE_PACKED __attribute__((__packed__)) +#else +#define FORCE_PACKED +#endif + #ifdef __GNUC__ #define GCCPRINTF(stri,firstargi) __attribute__((format(printf,stri,firstargi))) diff --git a/source/common/utility/cmdlib.cpp b/source/common/utility/cmdlib.cpp index 3eb07adc9..2b14df653 100644 --- a/source/common/utility/cmdlib.cpp +++ b/source/common/utility/cmdlib.cpp @@ -36,6 +36,8 @@ #include "cmdlib.h" #include "findfile.h" +#include "files.h" +#include "md5.h" #include #include @@ -1032,3 +1034,36 @@ FString M_ZLibError(int zerr) return errs[-zerr - 1]; } } + +void md5Update(FileReader& file, MD5Context& md5, unsigned len) +{ + uint8_t readbuf[8192]; + unsigned t; + + while (len > 0) + { + t = std::min(len, sizeof(readbuf)); + len -= t; + t = (long)file.Read(readbuf, t); + md5.Update(readbuf, t); + } +} + + +//========================================================================== +// +// uppercoppy +// +// [RH] Copy up to 8 chars, upper-casing them in the process +//========================================================================== + +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; +} + diff --git a/source/common/utility/cmdlib.h b/source/common/utility/cmdlib.h index 75cb5a012..c3ea527f2 100644 --- a/source/common/utility/cmdlib.h +++ b/source/common/utility/cmdlib.h @@ -84,4 +84,10 @@ inline int32_t Scale(int32_t a, int32_t b, int32_t c) return (int32_t)(((int64_t)a * b) / c); } +class FileReader; +struct MD5Context; + +void md5Update(FileReader& file, MD5Context& md5, unsigned len); +void uppercopy(char* to, const char* from); + #endif diff --git a/source/common/utility/files.h b/source/common/utility/files.h index 5563f5ce9..d40587457 100644 --- a/source/common/utility/files.h +++ b/source/common/utility/files.h @@ -293,7 +293,7 @@ public: } - friend class FWadCollection; + friend class FileSystem; }; class DecompressorBase : public FileReaderInterface diff --git a/source/common/utility/tarray.h b/source/common/utility/tarray.h index 6f930c34d..7bafeb9ee 100644 --- a/source/common/utility/tarray.h +++ b/source/common/utility/tarray.h @@ -94,6 +94,10 @@ public: TIterator operator-(difference_type offset) const { return TIterator(m_ptr - offset); } difference_type operator-(const TIterator &other) const { return m_ptr - other.m_ptr; } + // Random access operators + T& operator[](difference_type i) { return m_ptr[i]; } + const T& operator[](difference_type i) const { return m_ptr[i]; } + T &operator*() { return *m_ptr; } const T &operator*() const { return *m_ptr; } T* operator->() { return m_ptr; } diff --git a/source/core/2d/v_text.h b/source/core/2d/v_text.h index 29714d317..f90cd542c 100644 --- a/source/core/2d/v_text.h +++ b/source/core/2d/v_text.h @@ -36,6 +36,7 @@ #include "zstring.h" #include "tarray.h" +#include "printf.h" class FFont; @@ -48,34 +49,6 @@ struct FBrokenLines #define TEXTCOLOR_ESCAPE '\034' #define TEXTCOLOR_ESCAPESTR "\034" -#define TEXTCOLOR_BRICK "\034A" -#define TEXTCOLOR_TAN "\034B" -#define TEXTCOLOR_GRAY "\034C" -#define TEXTCOLOR_GREY "\034C" -#define TEXTCOLOR_GREEN "\034D" -#define TEXTCOLOR_BROWN "\034E" -#define TEXTCOLOR_GOLD "\034F" -#define TEXTCOLOR_RED "\034G" -#define TEXTCOLOR_BLUE "\034H" -#define TEXTCOLOR_ORANGE "\034I" -#define TEXTCOLOR_WHITE "\034J" -#define TEXTCOLOR_YELLOW "\034K" -#define TEXTCOLOR_UNTRANSLATED "\034L" -#define TEXTCOLOR_BLACK "\034M" -#define TEXTCOLOR_LIGHTBLUE "\034N" -#define TEXTCOLOR_CREAM "\034O" -#define TEXTCOLOR_OLIVE "\034P" -#define TEXTCOLOR_DARKGREEN "\034Q" -#define TEXTCOLOR_DARKRED "\034R" -#define TEXTCOLOR_DARKBROWN "\034S" -#define TEXTCOLOR_PURPLE "\034T" -#define TEXTCOLOR_DARKGRAY "\034U" -#define TEXTCOLOR_CYAN "\034V" -#define TEXTCOLOR_ICE "\034W" -#define TEXTCOLOR_FIRE "\034X" -#define TEXTCOLOR_SAPPHIRE "\034Y" -#define TEXTCOLOR_TEAL "\034Z" - #define TEXTCOLOR_NORMAL "\034-" #define TEXTCOLOR_BOLD "\034+" diff --git a/source/core/compositesaveame.h b/source/core/compositesaveame.h index 733ea4d1b..d4a3222ab 100644 --- a/source/core/compositesaveame.h +++ b/source/core/compositesaveame.h @@ -4,7 +4,7 @@ #include "files.h" #include "zstring.h" #include "tarray.h" -#include "filesystem/resourcefile.h" +#include "resourcefile.h" class CompositeSavegameWriter { diff --git a/source/core/console/c_bind.cpp b/source/core/console/c_bind.cpp index b0eb1c4a0..cc4d5fef3 100644 --- a/source/core/console/c_bind.cpp +++ b/source/core/console/c_bind.cpp @@ -683,17 +683,17 @@ void ReadBindings(int lump, bool override) void CONFIG_SetDefaultKeys(const char* baseconfig) { - auto lump = fileSystem.GetFile("engine/commonbinds.txt", ELookupMode::FullName, 0); + auto lump = fileSystem.CheckNumForFullName("engine/commonbinds.txt"); if (lump >= 0) ReadBindings(lump, true); int lastlump = 0; - while ((lump = fileSystem.Iterate(baseconfig, &lastlump)) != -1) + while ((lump = fileSystem.FindLumpFullName(baseconfig, &lastlump)) != -1) { if (fileSystem.GetFileContainer(lump) > 0) break; ReadBindings(lump, true); } - while ((lump = fileSystem.Iterate("defbinds.txt", &lastlump)) != -1) + while ((lump = fileSystem.FindLumpFullName("defbinds.txt", &lastlump)) != -1) { ReadBindings(lump, false); } diff --git a/source/core/filesystem/cache.cpp b/source/core/filesystem/cache.cpp deleted file mode 100644 index f1cd0f291..000000000 --- a/source/core/filesystem/cache.cpp +++ /dev/null @@ -1,129 +0,0 @@ - - -struct CacheNode -{ - size_t size; - CacheNode *next, *prev; - int lockCount; - int lastusetick; // This is to ensure that a node lives for the duration of the frame it is last axxessed on - - virtual ~CacheNode(); - virtual void Purge() = 0; // needs to be implemented by the child class to allow different types of menory to be used. -}; - -class Cache -{ - size_t maxSize; - size_t currentSize; - CacheNode purgeHead; - int currenttick; - -public: - Cache() - { - maxSize = 100'000'000; - currentSize = 0; - purgeHead = { 0, &purgeHead, &purgeHead, 0 }; - } - - SetSize(size_t newsize) - { - if (newsize < maxSize) Purge(); - maxSize = newsize; - } - - void AddToPurgeList(CacheNode *h) - { - h->prev = purgeHead.prev; - purgeHead.prev->next = h; - h->next = &purgeHead; - purgeHead.prev = h; - } - - void RemoveFromPurgeList(CacheNode *h) - { - h->prev->next = h->next; - h->next->prev = h->prev; - } - - void Alloc(CacheNode *h) - { - currentSize += h->size; - if (currentSize > maxSize) - { - Purge(); - } - AddToPurgeList(h); - } - - void Release(CacheNode *h) - { - currentSize -= h->size; - RemoveFromPurgeList(h); - } - - void Validata(CacheNode *h) - { - if (h->LockCount == 0) - { - // Move node to the top of the linked list. - RemoveFromPurgeList(h); - AddToPurgeList(h); - } - } - - void *Lock(CacheNode *h) - { - // This merely locks the node. Allocation must be reported separately. - assert(h != NULL); - if (h->lockCount == 0) - { - RemoveFromPurgeList(h); - } - - h->lockCount++; - return h->ptr; - } - - void Unlock(CacheNode *h) - { - assert(h != NULL); - if (h->lockCount > 0) - { - h->lockCount--; - if (h->lockCount == 0) - { - AddToPurgeList(); - if (currentSize > maxSize) - { - Release(h); - h->Purge(); - } - } - } - } - - void PurgeCache(bool all = false) - { - // Do not delete from the list while it's being iterated. Better store in a temporary list and delete from there. - TArray nodesToPurge(10); - int purgeSize = 0; - for (CacheNode *node = purgeHead.next; node != &purgeHead; node = node->next) - { - if (node->lastusetick < currenttick) - { - nodesToPurge.Push(npde); - purgeSize += node->size; - if (currentSize - purgeSize < maxSize && !all) break; - } - } - for (auto h : nodesToPurge) - { - Release(h); - h->Purge(); - } - } -}; - - - diff --git a/source/core/filesystem/filesystem.cpp b/source/core/filesystem/filesystem.cpp deleted file mode 100644 index f755c2cc3..000000000 --- a/source/core/filesystem/filesystem.cpp +++ /dev/null @@ -1,1158 +0,0 @@ -/* -** filesystem.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1998-2009 Randy Heit -** Copyright 2005-2019 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. -**--------------------------------------------------------------------------- -** -** -*/ - - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include - -#include "m_argv.h" -#include "cmdlib.h" -#include "printf.h" -#include "name.h" -//#include "c_dispatch.h" -#include "filesystem.h" -#include "resourcefile.h" -#include "v_text.h" -#include "c_dispatch.h" -#include "zstring.h" -//#include "md5.h" -//#include "doomstat.h" - -// MACROS ------------------------------------------------------------------ - -#define NULL_INDEX (0xffffffff) - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void PrintLastError (); - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FileSystem fileSystem; - -// CODE -------------------------------------------------------------------- - - -FileSystem::~FileSystem () -{ - DeleteAll(); -} - -void FileSystem::DeleteAll () -{ - NumEntries = 0; - - // explicitly delete all manually added lumps. - for (auto &frec : FileInfo) - { - if (frec.rfnum == -1) delete frec.lump; - } - FileInfo.Clear(); - for (int i = Files.Size() - 1; i >= 0; --i) - { - delete Files[i]; - } - Files.Clear(); -} - -//========================================================================== -// -// InitMultipleFiles -// -// Pass a null terminated list of files to use. All files are optional, -// but at least one file must be found. Lump names can appear multiple -// times. The name searcher looks backwards, so a later file can -// override an earlier one. -// -//========================================================================== - -int FileSystem::InitMultipleFiles(TArray& filenames, const TArray& deletelumps, int maingamefiles) -{ - int numfiles; - - // open all the files, load headers, and count lumps - DeleteAll(); - numfiles = 0; - - for (unsigned i = 0; i < filenames.Size(); i++) - { - int baselump = NumEntries; - bool nosubdirflag = false; - const char* fn = filenames[i]; - if (*fn == '*') - { - fn++; - nosubdirflag = true; - } - AddFile(filenames[i], nullptr, nosubdirflag); - } - - NumEntries = FileInfo.Size(); - if (NumEntries == 0) - { - return 0; - } - DeleteStuff(deletelumps, maingamefiles); - Rehash(); - return NumEntries; -} - -void FileSystem::Rehash() -{ - // [RH] Set up hash table - Hashes.Resize(NumLookupModes * 2 * NumEntries); - for (int i = 0; i < NumLookupModes; i++) - { - FirstFileIndex[i] = &Hashes[i * 2 * NumEntries]; - NextFileIndex[i] = &Hashes[(i * 2 + 1) * NumEntries]; - } - InitHashChains (); - FileInfo.ShrinkToFit(); - Files.ShrinkToFit(); -} - -//========================================================================== -// -// Deletes unwanted content from the main game files -// -//========================================================================== - -void FileSystem::DeleteStuff(const TArray& deletelumps, int numgamefiles) -{ - // This must account for the game directory being inserted at index 2. - // Deletion may only occur in the main game file, the directory and the add-on, there are no secondary dependencies, i.e. more than two game files. - numgamefiles++; - for (auto str : deletelumps) - { - FString renameTo; - auto ndx = str.IndexOf("*"); - if (ndx >= 0) - { - renameTo = FName(str.Mid(ndx + 1)).GetChars(); - str.Truncate(ndx); - } - FName check = FName(str); - - for (uint32_t i = 0; i < FileInfo.Size(); i++) - { - if (FileInfo[i].rfnum >= 1 && FileInfo[i].rfnum <= numgamefiles && check == FileInfo[i].lump->LumpName[FResourceLump::FullNameType]) - { - if (renameTo.IsEmpty()) - { - for (auto& n : FileInfo[i].lump->LumpName) n = NAME_None; - } - else FileInfo[i].lump->LumpNameSetup(renameTo); - } - } - } -} - -//========================================================================== -// -// AddFile -// -//========================================================================== - -void FileSystem::AddFile (const char *filename, FileReader *filer, bool nosubdirflag) -{ - int startlump; - bool isdir = false; - FileReader fr; - - if (filer == nullptr) - { - // Does this exist? If so, is it a directory? - if (!DirEntryExists(filename, &isdir)) - { - Printf("%s: File or Directory not found\n", filename); - PrintLastError(); - return; - } - - if (!isdir) - { - if (!fr.OpenFile(filename)) - { // Didn't find file - Printf ("%s: File not found\n", filename); - PrintLastError (); - return; - } - } - } - else fr = std::move(*filer); - - Printf (" adding %s", filename); - startlump = NumEntries; - - FResourceFile *resfile; - - if (!isdir) - resfile = FResourceFile::OpenResourceFile(filename, fr); - else - resfile = FResourceFile::OpenDirectory(filename, false, nosubdirflag); - - if (resfile != NULL) - { - uint32_t lumpstart = FileInfo.Size(); - - resfile->SetFirstLump(lumpstart); - for (uint32_t i=0; i < resfile->LumpCount(); i++) - { - FResourceLump *lump = resfile->GetLump(i); - FileSystem::FileRecord *lump_p = &FileInfo[FileInfo.Reserve(1)]; - - lump_p->lump = lump; - lump_p->rfnum = Files.Size(); - } - - Files.Push(resfile); - } -} - -//========================================================================== -// -// CheckIfResourceFileLoaded -// -// Returns true if the specified file is loaded, false otherwise. -// If a fully-qualified path is specified, then the file must match exactly. -// Otherwise, any file with that name will work, whatever its path. -// Returns the file's index if found, or -1 if not. -// -//========================================================================== - -int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept -{ - unsigned int i; - - if (strrchr (name, '/') != NULL) - { - for (i = 0; i < Files.Size(); ++i) - { - if (stricmp (GetResourceFileFullName (i), name) == 0) - { - return i; - } - } - } - else - { - for (i = 0; i < Files.Size(); ++i) - { - auto pth = ExtractFileBase(GetResourceFileName(i), true); - if (stricmp (pth.GetChars(), name) == 0) - { - return i; - } - } - } - return -1; -} - -//========================================================================== -// -// FindFile -// -// Looks up a file by name, either eith or without path and extension -// -//========================================================================== - -int FileSystem::FindFile (const char *name, ELookupMode lookupmode, int filenum) const noexcept -{ - uint32_t i; - - if (name == NULL) - { - return -1; - } - if (*name == '/') name++; // maps get a '/' prepended to their name. No idea what's the point, but this must be removed here. - FName lname(name, true); - if (lname == NAME_None) return -1; - - if (lookupmode == ELookupMode::IdWithType) return -1; - int lookupindex = (int)lookupmode; - uint32_t* fli = FirstFileIndex[lookupindex]; - uint32_t* nli = NextFileIndex[lookupindex]; - - for (i = fli[lname.GetIndex() % NumEntries]; i != NULL_INDEX; i = nli[i]) - { - if (filenum > 0 && FileInfo[i].rfnum != filenum) continue; - auto lump = FileInfo[i].lump; - if (lump->LumpName[lookupindex] == lname) return i; - } - return -1; -} - -//========================================================================== -// -// GetFile -// -// Calls FindFile, but bombs out if not found. -// -//========================================================================== - -int FileSystem::GetFile (const char *name, ELookupMode lookupmode, int filenum) const -{ - int i; - - i = FindFile (name, lookupmode, filenum); - - if (i == -1) - { - FStringf error("GetFile: %s not found!", name); - throw FileSystemError(error.GetChars()); - } - return i; -} - -//========================================================================== -// -// FindFile -// -// Looks up a file by name, either eith or without path and extension -// -//========================================================================== - -int FileSystem::FindFileWithExtensions(const char* name, const FName *exts, int count) -{ - uint32_t i; - - if (name == NULL) - { - return -1; - } - if (*name == '/') name++; // maps get a '/' prepended to their name. No idea what's the point, but this must be removed here. - FName lname(name, true); - if (lname == NAME_None) return -1; - - const int lookupindex = FResourceLump::FullNameNoExtType; - uint32_t* fli = FirstFileIndex[lookupindex]; - uint32_t* nli = NextFileIndex[lookupindex]; - - for (i = fli[lname.GetIndex() % NumEntries]; i != NULL_INDEX; i = nli[i]) - { - auto lump = FileInfo[i].lump; - if (lump->LumpName[lookupindex] == lname) - { - for (int c = 0; c < count; c++) - { - if (lump->LumpName[FResourceLump::ExtensionType] == exts[c]) return i; - } - } - } - return -1; -} - -//========================================================================== -// -// FindResource -// -// Looks for content based on Blood resource IDs. -// -//========================================================================== - -int FileSystem::FindResource (int resid, const char *type, int filenum) const noexcept -{ - uint32_t i; - - if (type == NULL) - { - return -1; - } - FName lname(type, true); - if (lname == NAME_None) return -1; - - const int lookuptype = (int)ELookupMode::IdWithType; - uint32_t* fli = FirstFileIndex[lookuptype]; - uint32_t* nli = NextFileIndex[lookuptype]; - - for (i = fli[int(resid) % NumEntries]; i != NULL_INDEX; i = nli[i]) - { - if (filenum > 0 && FileInfo[i].rfnum != filenum) continue; - if (FileInfo[i].lump->ResourceId != resid) continue; - auto lump = FileInfo[i].lump; - if (lump->LumpName[lookuptype] == lname) return i; - } - return -1; -} - -//========================================================================== -// -// GetResource -// -// Calls GetResource, but bombs out if not found. -// -//========================================================================== - -int FileSystem::GetResource (int resid, const char *type, int filenum) const -{ - int i; - - i = FindResource (resid, type, filenum); - - if (i == -1) - { - FStringf error("GetResource: %d of type %s not found!", resid, type); - throw FileSystemError(error.GetChars()); - } - return i; -} - -//========================================================================== -// -// LumpLength -// -// Returns the buffer size needed to load the given lump. -// -//========================================================================== - -int FileSystem::FileLength (int lump) const -{ - if ((size_t)lump >= NumEntries) - { - return -1; - } - return FileInfo[lump].lump->LumpSize; -} - -//========================================================================== -// -// GetLumpOffset -// -// Returns the offset from the beginning of the file to the lump. -// Returns -1 if the lump is compressed or can't be read directly -// -//========================================================================== - -int FileSystem::GetFileOffset (int lump) -{ - if ((size_t)lump >= NumEntries) - { - return -1; - } - return FileInfo[lump].lump->GetFileOffset(); -} - -//========================================================================== -// -// GetLumpOffset -// -//========================================================================== - -int FileSystem::GetFileFlags (int lump) -{ - if ((size_t)lump >= NumEntries) - { - return 0; - } - - return FileInfo[lump].lump->Flags; -} - -//========================================================================== -// -// InitHashChains -// -// Prepares the lumpinfos for hashing. -// (Hey! This looks suspiciously like something from Boom! :-) -// -//========================================================================== - -void FileSystem::InitHashChains (void) -{ - // Mark all buckets as empty - memset(Hashes.Data(), 255, Hashes.Size() * sizeof(Hashes[0])); - - // Now set up the chains - for (int i = 0; i < (unsigned)NumEntries; i++) - { - auto lump = FileInfo[i].lump; - for (int l = 0; l < NumLookupModes; l++) - { - int hash; - if (l != (int)ELookupMode::IdWithType && lump->LumpName[l] != NAME_None) - { - hash = lump->LumpName[l].GetIndex() % NumEntries; - } - else if (l == (int)ELookupMode::IdWithType && lump->ResourceId >= 0) - { - hash = int(lump->ResourceId) % NumEntries; - } - else continue; - NextFileIndex[l][i] = FirstFileIndex[l][hash]; - FirstFileIndex[l][hash] = i; - } - } -} - -void FileSystem::AddLump(FResourceLump *lump) -{ - FileRecord rec = { -1, lump}; - FileInfo.Push(rec); - NumEntries++; -} - -//========================================================================== -// -// Iterate -// -// Find a named lump. Specifically allows duplicates for merging of e.g. -// SNDINFO lumps. -// -//========================================================================== - -int FileSystem::Iterate (const char *name, int *lastlump, ELookupMode lookupmode) -{ - FileRecord *lump_p; - - int lookupindex = static_cast(lookupmode); - FName lname(name, true); - assert(lastlump != NULL && *lastlump >= 0); - if (lname == NAME_None) - { - *lastlump = NumEntries; - return -1; - } - - lump_p = &FileInfo[*lastlump]; - while (lump_p <= &FileInfo.Last()) - { - auto lump = lump_p->lump; - if (lump->LumpName[lookupindex] == lname) - { - int lump = int(lump_p - &FileInfo[0]); - *lastlump = lump + 1; - return lump; - } - lump_p++; - } - *lastlump = NumEntries; - return -1; -} - -//========================================================================== -// -// GetLumpName -// -//========================================================================== - -const char *FileSystem::GetFileName (int lump) const -{ - if ((size_t)lump >= NumEntries) - return nullptr; - else - return FileInfo[lump].lump->FullName(); -} - -//========================================================================== -// -// FileSystem :: GetFilrFullPath -// -// Returns the name of the lump's wad prefixed to the lump's full name. -// -//========================================================================== - -FString FileSystem::GetFileFullPath(int lump) const -{ - FString foo; - - if ((size_t) lump < NumEntries) - { - foo << GetResourceFileName(FileInfo[lump].rfnum) << ':' << GetFileName(lump); - } - return foo; -} - -//========================================================================== -// -// FileSystem :: GetFileIndexNum -// -// Returns the index number for this lump. This is *not* the lump's position -// in the lump directory, but rather a special value that RFF can associate -// with files. Other archive types will return -1, since they don't have it. -// -//========================================================================== - -int FileSystem::GetResourceId(int lump) const -{ - if ((size_t)lump >= NumEntries) - return -1; - else - return FileInfo[lump].lump->ResourceId; -} - -FName FileSystem::GetResourceType(int lump) const -{ - if ((size_t)lump >= NumEntries) - return NAME_None; - else - return FileInfo[lump].lump->LumpName[FResourceLump::ExtensionType]; -} - - -//========================================================================== -// -// GetLumpFile -// -//========================================================================== - -int FileSystem::GetFileContainer (int lump) const -{ - if ((size_t)lump >= FileInfo.Size()) - return -1; - return FileInfo[lump].rfnum; -} - -//========================================================================== -// -// GetLumpsInFolder -// -// Gets all lumps within a single folder in the hierarchy. -// If 'atomic' is set, it treats folders as atomic, i.e. only the -// content of the last found resource file having the given folder name gets used. -// -//========================================================================== - -static int folderentrycmp(const void *a, const void *b) -{ - auto A = (FolderEntry*)a; - auto B = (FolderEntry*)b; - return strcmp(A->name, B->name); -} - -//========================================================================== -// -// -// -//========================================================================== - -unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray &result, bool atomic) const -{ - FString path = inpath; - path.Substitute("\\", "/"); - path.ToLower(); - if (path[path.Len() - 1] != '/') path += '/'; - result.Clear(); - for (unsigned i = 0; i < FileInfo.Size(); i++) - { - if (!strncmp(FileInfo[i].lump->FullName(), path, path.Len())) - { - // Only if it hasn't been replaced. - if ((unsigned)FindFile(FileInfo[i].lump->FullName()) == i) - { - result.Push({ FileInfo[i].lump->FullName(), i }); - } - } - } - if (result.Size()) - { - int maxfile = -1; - if (atomic) - { - // Find the highest resource file having content in the given folder. - for (auto & entry : result) - { - int thisfile = FileInfo[entry.lumpnum].rfnum; - if (thisfile > maxfile) maxfile = thisfile; - } - // Delete everything from older files. - for (int i = result.Size() - 1; i >= 0; i--) - { - if (FileInfo[result[i].lumpnum].rfnum != maxfile) result.Delete(i); - } - } - qsort(result.Data(), result.Size(), sizeof(FolderEntry), folderentrycmp); - } - return result.Size(); -} - - -//========================================================================== -// -// ReadFile -// -// Loads the lump into a TArray and returns it. -// -//========================================================================== - -TArray FileSystem::GetFileData(int lump, int pad) -{ - if ((size_t)lump >= FileInfo.Size()) - return TArray(); - - auto lumpr = OpenFileReader(lump); - auto size = lumpr.GetLength(); - TArray data(size + pad, true); - auto numread = lumpr.Read(data.Data(), size); - - if (numread != size) - { - FStringf err("GetFileRecordReadFile: only read %ld of %ld on lump %i\n", numread, size, lump); - throw FileSystemError(err); - } - if (pad > 0) memset(&data[size], 0, pad); - return data; -} - -//========================================================================== -// -// Interface to the lump cache -// -//========================================================================== - -const void *FileSystem::Lock(int lump) -{ - if ((size_t)lump >= FileInfo.Size()) return nullptr; - auto lumpp = FileInfo[lump].lump; - return lumpp->Lock(); -} - -void FileSystem::Unlock(int lump, bool mayfree) -{ - if ((size_t)lump >= FileInfo.Size()) return; - auto lumpp = FileInfo[lump].lump; - lumpp->Unlock(mayfree); -} - -const void *FileSystem::Get(int lump) -{ - if ((size_t)lump >= FileInfo.Size()) return nullptr; - auto lumpp = FileInfo[lump].lump; - return lumpp->Get(); -} - -//========================================================================== -// -// Stand-ins for Blood's resource class -// -//========================================================================== - -const void *FileSystem::Lock(FResourceLump *lump) -{ - if (lump) return lump->Lock(); - else return nullptr; -} - -void FileSystem::Unlock(FResourceLump *lump) -{ - if (lump) return lump->Unlock(); -} - -const void *FileSystem::Load(FResourceLump *lump) -{ - if (lump) return lump->Get(); - else return nullptr; -} - -//========================================================================== -// -// ReadFile - variant 2 -// -// Loads the lump into a newly created buffer and returns it. -// -//========================================================================== - -FileData FileSystem::ReadFile (int lump) -{ - return FileData(FString(ELumpNum(lump))); -} - -//========================================================================== -// -// OpenLumpReader -// -// uses a more abstract interface to allow for easier low level optimization later -// -//========================================================================== - - -FileReader FileSystem::OpenFileReader(int lump) -{ - if ((unsigned)lump >= (unsigned)FileInfo.Size()) - { - FStringf err("OpenFileReader: %u >= NumEntries", lump); - throw FileSystemError(err); - } - - auto rl = FileInfo[lump].lump; - auto rd = rl->GetReader(); - - if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !(rl->Flags & (LUMPF_BLOODCRYPT | LUMPF_COMPRESSED))) - { - FileReader rdr; - rdr.OpenFilePart(*rd, rl->GetFileOffset(), rl->LumpSize); - return rdr; - } - return rl->NewReader(); // This always gets a reader to the cache -} - -FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache) -{ - if ((unsigned)lump >= (unsigned)FileInfo.Size()) - { - FStringf err("ReopenFileReader: %u >= NumEntries", lump); - throw FileSystemError(err); - } - - auto rl = FileInfo[lump].lump; - auto rd = rl->GetReader(); - - if (rl->RefCount == 0 && rd != nullptr && !rd->GetBuffer() && !alwayscache && !(rl->Flags & (LUMPF_BLOODCRYPT|LUMPF_COMPRESSED))) - { - int fileno = FileInfo[lump].rfnum; - const char *filename = GetResourceFileFullName(fileno); - FileReader fr; - if (fr.OpenFile(filename, rl->GetFileOffset(), rl->LumpSize)) - { - return fr; - } - } - return rl->NewReader(); // This always gets a reader to the cache -} - -FileReader FileSystem::OpenFileReader(const char* name, int where) -{ - auto lump = FindFile(name); - if (lump < 0) return FileReader(); - else return OpenFileReader(lump); -} - -//========================================================================== -// -// GetAllFilesOfType -// -//========================================================================== - -TArray FileSystem::GetAllFilesOfType(FName type, bool withsubdirs) -{ - TArray found; - for (unsigned i = 0; i < FileInfo.Size(); i++) - { - auto& fi = FileInfo[i]; - if (fi.lump->ResType() == type) - { - if (!withsubdirs && fi.lump->LumpName[FResourceLump::BaseNameNoExtType] != fi.lump->LumpName[FResourceLump::FullNameNoExtType]) continue; - auto check = FindFile(fi.lump->FullName()); - if (check == i) found.Push(fi.lump->FullName()); - } - } - return found; -} - -//========================================================================== -// -// GetResourceFileName -// -// Returns the name of the given wad. -// -//========================================================================== - -const char *FileSystem::GetResourceFileName (int rfnum) const noexcept -{ - const char *name, *slash; - - if ((uint32_t)rfnum >= Files.Size()) - { - return NULL; - } - - name = Files[rfnum]->FileName; - slash = strrchr (name, '/'); - return slash != NULL ? slash+1 : name; -} - -//========================================================================== -// -// -//========================================================================== - -int FileSystem::GetFirstEntry (int rfnum) const noexcept -{ - if ((uint32_t)rfnum >= Files.Size()) - { - return 0; - } - - return Files[rfnum]->GetFirstLump(); -} - -//========================================================================== -// -// -//========================================================================== - -int FileSystem::GetLastEntry (int rfnum) const noexcept -{ - if ((uint32_t)rfnum >= Files.Size()) - { - return 0; - } - - return Files[rfnum]->GetFirstLump() + Files[rfnum]->LumpCount() - 1; -} - -//========================================================================== -// -// -//========================================================================== - -int FileSystem::GetEntryCount (int rfnum) const noexcept -{ - if ((uint32_t)rfnum >= Files.Size()) - { - return 0; - } - - return Files[rfnum]->LumpCount(); -} - - -//========================================================================== -// -// GetResourceFileFullName -// -// Returns the name of the given wad, including any path -// -//========================================================================== - -const char *FileSystem::GetResourceFileFullName (int rfnum) const noexcept -{ - if ((unsigned int)rfnum >= Files.Size()) - { - return nullptr; - } - - return Files[rfnum]->FileName; -} - -//========================================================================== -// -// AddFromBuffer -// -// Adds an in-memory resource to the virtual directory -// -//========================================================================== - -int FileSystem::AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags) -{ - FStringf fullname("%s.%s", name, type); - auto newlump = new FMemoryLump(data, size); - newlump->LumpNameSetup(fullname); - newlump->ResourceId = id; - AddLump(newlump); - return Files.Size()-1; -} - -//========================================================================== -// -// Blood style lookup functions -// -//========================================================================== - -FResourceLump *FileSystem::Lookup(const char *name, const char *type) -{ - FStringf fname("%s.%s", name, type); - auto lump = FindFile(fname); - if (lump >= 0) return FileInfo[lump].lump; - else return nullptr; -} - -FResourceLump *FileSystem::Lookup(unsigned int id, const char *type) -{ - auto lump = FindResource(id, type); - if (lump >= 0) return FileInfo[lump].lump; - else return nullptr; -} - -//========================================================================== -// -// Clones an existing resource with different properties -// -//========================================================================== - -bool FileSystem::CreatePathlessCopy(const char *name, int id, int flags) -{ - FString name2, type2, path; - - // The old code said 'filename' and ignored the path, this looked like a bug. - auto lump = FindFile(name); - if (lump < 0) return false; // Does not exist. - - auto oldlump = FileInfo[lump].lump; - FName filename = oldlump->LumpName[FResourceLump::BaseNameType]; - FName fullname = oldlump->LumpName[FResourceLump::FullNameType]; - - // If the lump we are about to add already got the right properties, do nothing, aside from loading/locking as requested - if (filename == fullname && (id == -1 || id == oldlump->ResourceId)) - { - if (flags & DICT_LOCK) oldlump->Lock(); - else if (flags & DICT_LOAD) oldlump->Get(); - return true; - } - - // Create a clone of the resource to give it new lookup properties. - auto newlump = new FClonedLump(FileInfo[lump].lump); - newlump->LumpNameSetup(filename.GetChars()); - newlump->ResourceId = id; - if (flags & DICT_LOCK) newlump->Lock(); - else if (flags & DICT_LOAD) newlump->Get(); - AddLump(newlump); - return true; -} - -//========================================================================== -// -// IsEncryptedFile -// -// Returns true if the first 256 bytes of the lump are encrypted for Blood. -// -//========================================================================== - -bool FileSystem::IsEncryptedFile(int lump) const noexcept -{ - if ((unsigned)lump >= (unsigned)NumEntries) - { - return false; - } - return !!(FileInfo[lump].lump->Flags & LUMPF_BLOODCRYPT); -} - - -// FileData ----------------------------------------------------------------- - -FileData::FileData () -{ -} - -FileData::FileData (const FileData ©) -{ - Block = copy.Block; -} - -FileData &FileData::operator = (const FileData ©) -{ - Block = copy.Block; - return *this; -} - -FileData::FileData (const FString &source) -: Block (source) -{ -} - -FileData::~FileData () -{ -} - -FString::FString (ELumpNum lumpnum) -{ - auto lumpr = fileSystem.OpenFileReader ((int)lumpnum); - auto size = lumpr.GetLength (); - AllocBuffer (1 + size); - auto numread = lumpr.Read (&Chars[0], size); - Chars[size] = '\0'; - - if (numread != size) - { - FStringf err("ConstructStringFromLump: Only read %ld of %ld bytes on lump %i (%s)\n", - numread, size, lumpnum, fileSystem.GetFileName((int)lumpnum)); - } -} - -//========================================================================== -// -// PrintLastError -// -//========================================================================== - -#ifdef _WIN32 -//#define WIN32_LEAN_AND_MEAN -//#include - -extern "C" { -__declspec(dllimport) unsigned long __stdcall FormatMessageA( - unsigned long dwFlags, - const void *lpSource, - unsigned long dwMessageId, - unsigned long dwLanguageId, - char **lpBuffer, - unsigned long nSize, - va_list *Arguments - ); -__declspec(dllimport) void * __stdcall LocalFree (void *); -__declspec(dllimport) unsigned long __stdcall GetLastError (); -} - -static void PrintLastError () -{ - char *lpMsgBuf; - FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS*/, - NULL, - GetLastError(), - 1 << 10 /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, // Default language - (char **)&lpMsgBuf, - 0, - NULL - ); - Printf (TEXTCOLOR_RED " %s\n", lpMsgBuf); - // Free the buffer. - LocalFree( lpMsgBuf ); -} -#else -static void PrintLastError () -{ - Printf (TEXTCOLOR_RED " %s\n", strerror(errno)); -} -#endif - -CCMD(printfs) -{ - fileSystem.PrintDirectory(); -} - -void FileSystem::PrintDirectory() -{ - for (int i = 0; i < NumEntries; i++) - { - auto lump = FileInfo[i].lump; - auto f = GetFileContainer(i); - auto n = GetResourceFileFullName(f); - Printf("%5d: %9d %64s %4s %3d %s\n", i, lump->LumpSize, lump->LumpName[0].GetChars(), lump->LumpName[4].GetChars(), lump->ResourceId, n); - } -} diff --git a/source/core/filesystem/filesystem.h b/source/core/filesystem/filesystem.h deleted file mode 100644 index 3378d5042..000000000 --- a/source/core/filesystem/filesystem.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// File system I/O functions. -// -//----------------------------------------------------------------------------- - - -#include -#include "files.h" -#include "tarray.h" -#include "name.h" -#include "zstring.h" -#include "engineerrors.h" - -#ifdef FindResource -#undef FindResource -#endif - -// We do not want to expose the resource file interface here. -class FResourceFile; -struct FResourceLump; - -class FileSystemError : CRecoverableError -{ -public: - FileSystemError(const char* err) : CRecoverableError(err) {} -}; - -// A file in memory. -class FileData -{ -public: - FileData (); - - FileData (const FileData ©); - FileData &operator= (const FileData ©); - ~FileData (); - void *GetMem () { return Block.Len() == 0 ? NULL : (void *)Block.GetChars(); } - size_t GetSize () { return Block.Len(); } - FString GetString () { return Block; } - -private: - FileData (const FString &source); - - FString Block; - - friend class FileSystem; -}; - -struct FolderEntry -{ - const char *name; - unsigned lumpnum; -}; - -enum DICTFLAGS { - DICT_LOAD = 4, - DICT_LOCK = 8, -}; - -enum class ELookupMode // Todo: Merge with FResourceLump::ENameType -{ - FullName, - NoExtension, - BaseName, - BaseWithExtension, - IdWithType, - NumLookupModes -}; - -enum -{ - NumLookupModes = (int)ELookupMode::NumLookupModes + 1 -}; - - -class FileSystem -{ -public: - FileSystem () = default; - ~FileSystem (); - - int InitMultipleFiles (TArray &filenames, const TArray &todelete, int maingamefiles); - void DeleteStuff(const TArray& deletelumps, int numgamefiles); - void Rehash(); - - void AddFile (const char *filename, FileReader *wadinfo = NULL, bool nosubdirflag = false); - void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} - int CheckIfResourceFileLoaded (const char *name) noexcept; - - const char *GetResourceFileName (int filenum) const noexcept; - const char *GetResourceFileFullName (int filenum) const noexcept; - - int GetFirstEntry(int filenum) const noexcept; - int GetLastEntry(int filenum) const noexcept; - int GetEntryCount(int filenum) const noexcept; - - int FindFile (const char *name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept; - int FindFileWithExtensions(const char* name, const FName* exts, int count); - int GetFile (const char *name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for. - bool FileExists(const char* name) - { - return FindFile(name) >= 0; - } - - int FindFile (const FString &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.GetChars(), lookupmode, filenum); } - int GetFile (const FString &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.GetChars(), lookupmode, filenum); } - bool FileExists(const FString & name) - { - return FindFile(name) >= 0; - } - - int FindFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.c_str(), lookupmode, filenum); } - int GetFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.c_str(), lookupmode, filenum); } - bool FileExists(const std::string& name) - { - return FindFile(name) >= 0; - } - - - int FindResource (int resid, const char *type, int filenum = -1) const noexcept; - int GetResource (int resid, const char *type, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for. - - int AddFromBuffer(const char* name, const char* type, char* data, int size, int id, int flags); - - - TArray GetAllFilesOfType(FName type, bool withsubdirs = false); - TArray GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!) - FileData ReadFile (int file); - FileData ReadFile (const char *name) { return ReadFile (GetFile (name)); } - - inline TArray LoadFile(const char* name, int padding) - { - auto lump = FindFile(name); - if (lump < 0) return TArray(); - return GetFileData(lump, padding); - } - - - - const void *Lock(int lump); - void Unlock(int lump, bool mayfree = false); - const void *Get(int lump); - - // These are designed to be stand-ins for Blood's resource class. - static const void *Lock(FResourceLump *lump); - static void Unlock(FResourceLump *lump); - static const void *Load(FResourceLump *lump); - FResourceLump *Lookup(const char *name, const char *type); - FResourceLump *Lookup(unsigned int id, const char *type); - bool CreatePathlessCopy(const char *name, int id, int flags); - - FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one. - FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader. - FileReader OpenFileReader(const char* name, int where); - - int Iterate (const char *name, int *lastfile, ELookupMode lookupmode = ELookupMode::FullName); // [RH] Find files with duplication - - int FileLength (int file) const; - int GetFileOffset (int file); // [RH] Returns offset of file in the wadfile - int GetFileFlags (int file); // Return the flags for this file - const char *GetFileName (int file) const; - FString GetFileFullPath (int file) const; // [RH] Returns wad's name + file's full name - int GetFileContainer (int file) const; // [RH] Returns filenum for a specified file - int GetRFFIndexNum (int file) const; // Returns the RFF index number for this file - unsigned GetFilesInFolder(const char *path, TArray &result, bool atomic) const; - - bool IsEncryptedFile(int file) const noexcept; - int GetResourceId(int file) const; - FName GetResourceType(int file) const; - - int GetNumResourceFiles() const { return NumFiles; } - int GetNumEntries () const { return NumEntries; } - FResourceLump* GetFileAt(int lump) const - { - return FileInfo[lump].lump; - } - void PrintDirectory(); - -protected: - - struct FileRecord - { - int rfnum; - FResourceLump* lump; - }; - - TArray Files; - TArray FileInfo; - - TArray Hashes; // one allocation for all hash lists. - uint32_t *FirstFileIndex[NumLookupModes]; // Hash information for the base name (no path and no extension) - uint32_t *NextFileIndex[NumLookupModes]; - - uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size() - uint32_t NumEntries; // Hash modulus. Can be smaller than NumFiles if things get added at run time. - - void InitHashChains (); // [RH] Set up the lumpinfo hashing - void AddLump(FResourceLump* lump); - -private: - void DeleteAll(); -}; - -extern FileSystem fileSystem; - diff --git a/source/core/fonts/fontchars.cpp b/source/core/fonts/fontchars.cpp index 50f987718..becaaa9cc 100644 --- a/source/core/fonts/fontchars.cpp +++ b/source/core/fonts/fontchars.cpp @@ -34,7 +34,7 @@ ** */ -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "bitmap.h" #include "image.h" #include "imagehelpers.h" diff --git a/source/core/fonts/singlelumpfont.cpp b/source/core/fonts/singlelumpfont.cpp index 73d5b8938..66c48de75 100644 --- a/source/core/fonts/singlelumpfont.cpp +++ b/source/core/fonts/singlelumpfont.cpp @@ -40,7 +40,7 @@ #include "fontchars.h" #include "printf.h" #include "imagehelpers.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "fontinternals.h" diff --git a/source/core/fonts/v_font.cpp b/source/core/fonts/v_font.cpp index 5648851d0..20a56d976 100644 --- a/source/core/fonts/v_font.cpp +++ b/source/core/fonts/v_font.cpp @@ -93,7 +93,7 @@ FFont *V_GetFont(const char *name, const char *fontlumpname) FFont *font = FFont::FindFont (name); if (font == nullptr) { - auto lumpy = fileSystem.OpenFileReader(fontlumpname, 0); + auto lumpy = fileSystem.OpenFileReader(fontlumpname); if (!lumpy.isOpen()) return nullptr; uint32_t head; lumpy.Read (&head, 4); @@ -404,7 +404,7 @@ void V_InitFontColors () TranslationLookup.Clear(); TranslationColors.Clear(); - while ((lump = fileSystem.Iterate("engine/textcolors.txt", &lastlump)) != -1) + while ((lump = fileSystem.FindLumpFullName("engine/textcolors.txt", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index a1480ea47..aa668a8b4 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -73,6 +73,8 @@ MapRecord *currentLevel; // level that is currently played. (The real level, not MapRecord* lastLevel; // Same here, for the last level. MapRecord userMapRecord; // stand-in for the user map. +FILE* hashfile; + FStartupInfo RazeStartupInfo; FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown. diff --git a/source/core/initfs.cpp b/source/core/initfs.cpp index 44ce771e9..dfcdddb41 100644 --- a/source/core/initfs.cpp +++ b/source/core/initfs.cpp @@ -33,8 +33,7 @@ ** */ -#include "filesystem/filesystem.h" -#include "filesystem/resourcefile.h" +#include "filesystem.h" #include "cmdlib.h" #include "zstring.h" #include "gamecontrol.h" @@ -420,7 +419,7 @@ static FString CheckGameInfo(TArray& pwads) { FResourceLump* lmp = resfile->GetLump(i); - if (lmp->LumpName[0] == gameinfo) + if (FName(lmp->getName(), true) == gameinfo) { // Found one! FString iwad = ParseGameInfo(pwads, resfile->FileName, (const char*)lmp->Lock(), lmp->LumpSize); @@ -473,6 +472,38 @@ FString GetGameFronUserFiles() return CheckGameInfo(Files); } +//========================================================================== +// +// Deletes unwanted content from the main game files +// +//========================================================================== + +static void DeleteStuff(FileSystem &fileSystem, const TArray& deletelumps, int numgamefiles) +{ + // This must account for the game directory being inserted at index 2. + // Deletion may only occur in the main game file, the directory and the add-on, there are no secondary dependencies, i.e. more than two game files. + numgamefiles++; + for (auto str : deletelumps) + { + FString renameTo; + auto ndx = str.IndexOf("*"); + if (ndx >= 0) + { + renameTo = FName(str.Mid(ndx + 1)).GetChars(); + str.Truncate(ndx); + } + + for (uint32_t i = 0; i < fileSystem.GetNumEntries(); i++) + { + int cf = fileSystem.GetFileContainer(i); + auto fname = fileSystem.GetFileFullName(i, false); + if (cf >= 1 && cf <= numgamefiles && !str.CompareNoCase(fname)) + { + fileSystem.RenameFile(i, renameTo); + } + } + } +} //========================================================================== // // @@ -575,15 +606,21 @@ void InitFileSystem(TArray& groups) todelete.Append(g.FileInfo.tobedeleted); } todelete.Append(userConfig.toBeDeleted); - fileSystem.InitMultipleFiles(Files, todelete, groups.Size()); + LumpFilterInfo lfi; + lfi.dotFilter = LumpFilter; + lfi.postprocessFunc = [&]() + { + DeleteStuff(fileSystem, todelete, groups.Size()); + }; + fileSystem.InitMultipleFiles(Files, false, &lfi); if (Args->CheckParm("-dumpfs")) { FILE* f = fopen("filesystem.dir", "wb"); for (int i = 0; i < fileSystem.GetNumEntries(); i++) { auto fd = fileSystem.GetFileAt(i); - fprintf(f, "%.50s %60s %d\n", fd->FullName(), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(i)), fd->Size()); + fprintf(f, "%.50s %60s %d\n", fd->getName(), fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(i)), fd->Size()); } fclose(f); } diff --git a/source/core/menu/menudef.cpp b/source/core/menu/menudef.cpp index ea5de38c7..a562dfdf8 100644 --- a/source/core/menu/menudef.cpp +++ b/source/core/menu/menudef.cpp @@ -1162,7 +1162,7 @@ void M_ParseMenuDefs() DefaultOptionMenuSettings.Reset(); M_DeinitMenus(); - while ((lump = fileSystem.Iterate("engine/menudef.txt", &lastlump)) != -1) + while ((lump = fileSystem.FindLumpFullName("engine/menudef.txt", &lastlump)) != -1) { FScanner sc(lump); diff --git a/source/core/menu/savegamemanager.cpp b/source/core/menu/savegamemanager.cpp index 3f4f3dcc2..b6584d1d6 100644 --- a/source/core/menu/savegamemanager.cpp +++ b/source/core/menu/savegamemanager.cpp @@ -379,12 +379,14 @@ unsigned FSavegameManager::ExtractSaveData(int index) return index; } - void* data = info->Get(); + void* data = info->Lock(); FSerializer arc; if (!arc.OpenReader((const char*)data, info->LumpSize)) { + info->Unlock(); return index; } + info->Unlock(); FString comment, fcomment, ncomment, mtime; diff --git a/source/core/music/music.cpp b/source/core/music/music.cpp index 0b9a1b969..c8fce3237 100644 --- a/source/core/music/music.cpp +++ b/source/core/music/music.cpp @@ -67,40 +67,12 @@ CVAR(Bool, printmusicinfo, false, 0) CVAR(Bool, mus_extendedlookup, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) // Order is: streaming formats, module formats, emulated formats and MIDI formats - for external files the first one found wins so ambiguous names should be avoided -static FName knownMusicExts[] = { - NAME_OGG, - NAME_FLAC, - NAME_MP3, - NAME_MP2, - NAME_XA, - NAME_XM, - NAME_MOD, - NAME_IT, - NAME_S3M, - NAME_MTM, - NAME_STM, - NAME_669, - NAME_PTM, - NAME_AMF, - NAME_OKT, - NAME_DSM, - NAME_AMFF, - NAME_SPC, - NAME_VGM, - NAME_VGZ, - NAME_AY, - NAME_GBS, - NAME_GYM, - NAME_HES, - NAME_KSS, - NAME_NSF, - NAME_NSFE, - NAME_SAP, - NAME_MID, - NAME_HMP, - NAME_HMI, - NAME_XMI, - NAME_VOC, +static const char* knownMusicExts[] = { + "OGG", "FLAC", "MP3", "MP2", "XA", "XM", "MOD", + "IT", "S3M", "MTM", "STM", "669", "PTM", "AMF", + "OKT", "DSM", "AMFF", "SPC", "VGM", "VGZ", "AY", + "GBS", "GYM", "HES", "KSS", "NSF", "NSFE", "SAP", + "MID", "HMP", "HMI", "XMI", "VOC" }; @@ -112,7 +84,7 @@ FString G_SetupFilenameBasedMusic(const char* fn, const char* defmusic) // Test if a real file with this name exists with all known extensions for music. for (auto& ext : knownMusicExts) { - test.Format("%s.%s", name.GetChars(), ext.GetChars()); + test.Format("%s.%s", name.GetChars(), ext); if (FileExists(test)) return test; #ifdef __unix__ test.Format("%s.%s", name.GetChars(), FString(ext.GetChars()).MakeLower().GetChars()); diff --git a/source/core/music/s_advsound.cpp b/source/core/music/s_advsound.cpp index 757666aec..1c0a831fa 100644 --- a/source/core/music/s_advsound.cpp +++ b/source/core/music/s_advsound.cpp @@ -97,7 +97,7 @@ void S_ParseSndInfo () { int lump, lastlump = 0; - while ((lump = fileSystem.Iterate("engine/mussetting.txt", &lastlump)) >= 0) + while ((lump = fileSystem.FindLumpFullName("engine/mussetting.txt", &lastlump)) >= 0) { S_AddSNDINFO (lump); } diff --git a/source/core/rts.cpp b/source/core/rts.cpp index 5ce19f36d..938ae157b 100644 --- a/source/core/rts.cpp +++ b/source/core/rts.cpp @@ -35,7 +35,7 @@ #include #include "zstring.h" #include "tarray.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "rts.h" #include "m_swap.h" #include "s_soundinternal.h" @@ -81,7 +81,7 @@ bool RTS_IsInitialized() { if (LumpInfo.Size() > 0) return true; if (RTSName.IsEmpty()) return false; - auto fr = fileSystem.OpenFileReader(RTSName, 0); + auto fr = fileSystem.OpenFileReader(RTSName); RTSName = ""; // don't try ever again. if (!fr.isOpen()) return false; RTSFile = fr.Read(); diff --git a/source/core/savegamehelp.cpp b/source/core/savegamehelp.cpp index 5cd9035b0..3f7c2a671 100644 --- a/source/core/savegamehelp.cpp +++ b/source/core/savegamehelp.cpp @@ -39,7 +39,7 @@ #include "gstrings.h" #include "i_specialpaths.h" #include "cmdlib.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "statistics.h" #include "secrets.h" #include "quotemgr.h" @@ -101,12 +101,14 @@ bool OpenSaveGameForRead(const char *name) return false; } + void* data = info->Lock(); FSerializer arc; - void* data = info->Get(); if (!arc.OpenReader((const char*)data, info->LumpSize)) { + info->Unlock(); return false; } + info->Unlock(); // Load system-side data from savegames. SerializeSession(arc); diff --git a/source/core/savegamehelp.h b/source/core/savegamehelp.h index c045d4b58..2cfbb58fc 100644 --- a/source/core/savegamehelp.h +++ b/source/core/savegamehelp.h @@ -1,6 +1,6 @@ #pragma once -#include "filesystem/resourcefile.h" +#include "resourcefile.h" bool OpenSaveGameForWrite(const char *fname, const char *name); bool OpenSaveGameForRead(const char *name); diff --git a/source/core/searchpaths.cpp b/source/core/searchpaths.cpp index c2f05ef4c..9de094f72 100644 --- a/source/core/searchpaths.cpp +++ b/source/core/searchpaths.cpp @@ -46,8 +46,7 @@ #include "version.h" #include "gamecontrol.h" #include "m_argv.h" -#include "filesystem/filesystem.h" -#include "filesystem/resourcefile.h" +#include "filesystem.h" #include "findfile.h" static const char* res_exts[] = { ".grp", ".zip", ".pk3", ".pk4", ".7z", ".pk7" }; diff --git a/source/core/secrets.cpp b/source/core/secrets.cpp index b12fc251e..81337b8f0 100644 --- a/source/core/secrets.cpp +++ b/source/core/secrets.cpp @@ -1,5 +1,5 @@ #include "c_dispatch.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "printf.h" #include "v_text.h" #include "tarray.h" diff --git a/source/core/serializer.h b/source/core/serializer.h index 8870765ac..d1180a4c1 100644 --- a/source/core/serializer.h +++ b/source/core/serializer.h @@ -4,10 +4,11 @@ #include #include #include "tarray.h" -#include "filesystem/file_zip.h" +#include "file_zip.h" #include "tflags.h" #include "vectors.h" #include "palentry.h" +#include "name.h" extern bool save_full; diff --git a/source/core/sound/s_sound.cpp b/source/core/sound/s_sound.cpp index d66f650cb..091048572 100644 --- a/source/core/sound/s_sound.cpp +++ b/source/core/sound/s_sound.cpp @@ -1758,7 +1758,7 @@ CVAR(Bool, snd_extendedlookup, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) int S_LookupSound(const char* fn) { - static const FName sndformats[] = { NAME_OGG, NAME_FLAC, NAME_WAV }; + static const char * const sndformats[] = { "OGG", "FLAC", "WAV" }; if (snd_extendedlookup) { int lump = fileSystem.FindFileWithExtensions(StripExtension(fn), sndformats, countof(sndformats)); diff --git a/source/core/textures/buildtiles.cpp b/source/core/textures/buildtiles.cpp index 56f45c412..115a23670 100644 --- a/source/core/textures/buildtiles.cpp +++ b/source/core/textures/buildtiles.cpp @@ -308,7 +308,7 @@ int BuildTiles::LoadArtFile(const char *fn, bool mapart, int firsttile) auto old = FindFile(fn); if (old >= ArtFiles.Size()) // Do not process if already loaded. { - FileReader fr = fileSystem.OpenFileReader(fn, 0); + FileReader fr = fileSystem.OpenFileReader(fn); if (fr.isOpen()) { auto artdata = fr.Read(); @@ -598,7 +598,7 @@ void artSetupMapArt(const char* filename) artClearMapArt(); FStringf firstname("%s_00.art", filename); - auto fr = fileSystem.OpenFileReader(firstname, 0); + auto fr = fileSystem.OpenFileReader(firstname); if (!fr.isOpen()) return; for (bssize_t i = 0; i < MAXARTFILES_TOTAL - MAXARTFILES_BASE; i++) diff --git a/source/core/textures/formats/arttexture.cpp b/source/core/textures/formats/arttexture.cpp index fa3f697e0..41fbfd53d 100644 --- a/source/core/textures/formats/arttexture.cpp +++ b/source/core/textures/formats/arttexture.cpp @@ -118,7 +118,7 @@ FArtTexture::FArtTexture(int width, int height, int p) void FArtTexture::CreatePalettedPixels(uint8_t* buffer) { - FileReader fr = fileSystem.OpenFileReader(Name, 0); + FileReader fr = fileSystem.OpenFileReader(Name); if (!fr.isOpen()) return; int numpixels = Width * Height; fr.Read(buffer, numpixels); @@ -139,7 +139,7 @@ int FArtTexture::CopyPixels(FBitmap *bmp, int conversion) // Both Src and Dst are ordered the same with no padding. int numpixels = Width * Height; bool hasalpha = false; - FileReader fr = fileSystem.OpenFileReader(Name, 0); + FileReader fr = fileSystem.OpenFileReader(Name); if (!fr.isOpen()) return 0; TArray source(numpixels, true); fr.Read(source.Data(), numpixels); diff --git a/source/core/textures/formats/ddstexture.cpp b/source/core/textures/formats/ddstexture.cpp index 7527c4359..58b2c3377 100644 --- a/source/core/textures/formats/ddstexture.cpp +++ b/source/core/textures/formats/ddstexture.cpp @@ -55,7 +55,7 @@ #include "imagehelpers.h" #include "image.h" #include "m_png.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" // Since we want this to compile under Linux too, we need to define this // stuff ourselves instead of including a DirectX header. @@ -374,7 +374,7 @@ void FDDSTexture::CalcBitShift (uint32_t mask, uint8_t *lshiftp, uint8_t *rshift void FDDSTexture::CreatePalettedPixels(uint8_t *buffer) { - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return; // Just leave the texture blank. lump.Seek (sizeof(DDSURFACEDESC2) + 4, FileReader::SeekSet); @@ -781,7 +781,7 @@ void FDDSTexture::DecompressDXT5 (FileReader &lump, bool premultiplied, uint8_t int FDDSTexture::CopyPixels(FBitmap *bmp, int conversion) { - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return -1; // Just leave the texture blank. uint8_t *TexBuffer = bmp->GetPixels(); diff --git a/source/core/textures/formats/jpegtexture.cpp b/source/core/textures/formats/jpegtexture.cpp index 5f3b0e2ad..a5795c2ff 100644 --- a/source/core/textures/formats/jpegtexture.cpp +++ b/source/core/textures/formats/jpegtexture.cpp @@ -40,7 +40,7 @@ #include "printf.h" #include "bitmap.h" #include "image.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "imagehelpers.h" #include "v_text.h" @@ -262,7 +262,7 @@ FJPEGTexture::FJPEGTexture (int width, int height) void FJPEGTexture::CreatePalettedPixels(uint8_t *buffer) { - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return; // Just leave the texture blank. JSAMPLE *buff = NULL; @@ -385,7 +385,7 @@ int FJPEGTexture::CopyPixels(FBitmap *bmp, int conversion) { PalEntry pe[256]; - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return -1; // Just leave the texture blank. jpeg_decompress_struct cinfo; diff --git a/source/core/textures/formats/pcxtexture.cpp b/source/core/textures/formats/pcxtexture.cpp index 9a0c3d348..2db53f2e1 100644 --- a/source/core/textures/formats/pcxtexture.cpp +++ b/source/core/textures/formats/pcxtexture.cpp @@ -39,7 +39,7 @@ #include "bitmap.h" #include "imagehelpers.h" #include "image.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" //========================================================================== // @@ -350,7 +350,7 @@ void FPCXTexture::CreatePalettedPixels(uint8_t *buffer) PCXHeader header; int bitcount; - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return; // Just leave the texture blank. lump.Read(&header, sizeof(header)); @@ -436,7 +436,7 @@ int FPCXTexture::CopyPixels(FBitmap *bmp, int conversion) int bitcount; TArray Pixels; - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return -1; // Just leave the texture blank. lump.Read(&header, sizeof(header)); diff --git a/source/core/textures/formats/pngtexture.cpp b/source/core/textures/formats/pngtexture.cpp index 04b962871..db9f406f1 100644 --- a/source/core/textures/formats/pngtexture.cpp +++ b/source/core/textures/formats/pngtexture.cpp @@ -41,7 +41,7 @@ #include "imagehelpers.h" #include "image.h" #include "printf.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" //========================================================================== // @@ -291,7 +291,7 @@ void FPNGTexture::CreatePalettedPixels(uint8_t *buffer) FileReader *lump; FileReader lfr; - lfr = fileSystem.OpenFileReader(Name, 0); + lfr = fileSystem.OpenFileReader(Name); if (!lfr.isOpen()) return; lump = 𝔩 @@ -408,7 +408,7 @@ int FPNGTexture::CopyPixels(FBitmap *bmp, int conversion) FileReader *lump; FileReader lfr; - lfr = fileSystem.OpenFileReader(Name, 0); + lfr = fileSystem.OpenFileReader(Name); if (!lfr.isOpen()) return -1; // Just leave the texture blank. lump = 𝔩 diff --git a/source/core/textures/formats/stbtexture.cpp b/source/core/textures/formats/stbtexture.cpp index d9bf916f2..902f84547 100644 --- a/source/core/textures/formats/stbtexture.cpp +++ b/source/core/textures/formats/stbtexture.cpp @@ -49,7 +49,7 @@ #include "bitmap.h" #include "imagehelpers.h" #include "image.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" //========================================================================== // @@ -154,7 +154,7 @@ void FStbTexture::CreatePalettedPixels(uint8_t *buffer) int FStbTexture::CopyPixels(FBitmap *bmp, int conversion) { - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return -1; // Just leave the texture blank. int x, y, chan; auto image = stbi_load_from_callbacks(&callbacks, &lump, &x, &y, &chan, STBI_rgb_alpha); diff --git a/source/core/textures/formats/tgatexture.cpp b/source/core/textures/formats/tgatexture.cpp index d920160e7..1230e08f3 100644 --- a/source/core/textures/formats/tgatexture.cpp +++ b/source/core/textures/formats/tgatexture.cpp @@ -37,7 +37,7 @@ #include "templates.h" #include "bitmap.h" #include "image.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "imagehelpers.h" @@ -179,7 +179,7 @@ void FTGATexture::ReadCompressed(FileReader &lump, uint8_t * buffer, int bytespe void FTGATexture::CreatePalettedPixels(uint8_t *buffer) { uint8_t PaletteMap[256]; - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return; TGAHeader hdr; uint16_t w; @@ -385,7 +385,7 @@ void FTGATexture::CreatePalettedPixels(uint8_t *buffer) int FTGATexture::CopyPixels(FBitmap *bmp, int conversion) { PalEntry pe[256]; - auto lump = fileSystem.OpenFileReader(Name, 0); + auto lump = fileSystem.OpenFileReader(Name); if (!lump.isOpen()) return -1; TGAHeader hdr; uint16_t w; diff --git a/source/core/textures/image.cpp b/source/core/textures/image.cpp index 39ee8018d..5f1a517ac 100644 --- a/source/core/textures/image.cpp +++ b/source/core/textures/image.cpp @@ -38,7 +38,7 @@ #include "bitmap.h" #include "image.h" #include "files.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "imagehelpers.h" int FImageSource::NextID; @@ -79,7 +79,7 @@ FImageSource * FImageSource::GetImage(const char *name) { nullptr } }; - auto data = fileSystem.OpenFileReader(name, 0); + auto data = fileSystem.OpenFileReader(name); if (!data.isOpen()) return nullptr; for (size_t i = 0; CreateInfo[i].TryCreate; i++) diff --git a/source/core/utility/namedef.h b/source/core/utility/namedef.h index cc65b9d01..fd63f637a 100644 --- a/source/core/utility/namedef.h +++ b/source/core/utility/namedef.h @@ -9,48 +9,6 @@ xx(None) xx(Null) xx(_) xx(Untranslated) -xx(QAV) -xx(SEQ) -xx(SFX) -xx(RAW) -xx(AIF) -xx(AIFF) -xx(MAP) -xx(RFS) -xx(WAV) -xx(OGG) -xx(FLAC) -xx(VOC) -xx(MP3) -xx(XM) -xx(MOD) -xx(IT) -xx(S3M) -xx(MTM) -xx(MID) -xx(HMP) -xx(HMI) -xx(XMI) -xx(SPC) -xx(VGM) -xx(VGZ) -xx(MP2) -xx(XA) -xx(STM) -xx(669) -xx(PTM) -xx(AMF) -xx(OKT) -xx(DSM) -xx(AMFF) -xx(AY) -xx(GBS) -xx(GYM) -xx(HES) -xx(KSS) -xx(NSF) -xx(NSFE) -xx(SAP) xx(Controlmessage) diff --git a/source/core/utility/printf.h b/source/core/utility/printf.h index 22b550678..900eb4f74 100644 --- a/source/core/utility/printf.h +++ b/source/core/utility/printf.h @@ -11,6 +11,34 @@ extern "C" int mysnprintf(char* buffer, size_t count, const char* format, ...) ATTRIBUTE((format(printf, 3, 4))); extern "C" int myvsnprintf(char* buffer, size_t count, const char* format, va_list argptr) ATTRIBUTE((format(printf, 3, 0))); +#define TEXTCOLOR_BRICK "\034A" +#define TEXTCOLOR_TAN "\034B" +#define TEXTCOLOR_GRAY "\034C" +#define TEXTCOLOR_GREY "\034C" +#define TEXTCOLOR_GREEN "\034D" +#define TEXTCOLOR_BROWN "\034E" +#define TEXTCOLOR_GOLD "\034F" +#define TEXTCOLOR_RED "\034G" +#define TEXTCOLOR_BLUE "\034H" +#define TEXTCOLOR_ORANGE "\034I" +#define TEXTCOLOR_WHITE "\034J" +#define TEXTCOLOR_YELLOW "\034K" +#define TEXTCOLOR_UNTRANSLATED "\034L" +#define TEXTCOLOR_BLACK "\034M" +#define TEXTCOLOR_LIGHTBLUE "\034N" +#define TEXTCOLOR_CREAM "\034O" +#define TEXTCOLOR_OLIVE "\034P" +#define TEXTCOLOR_DARKGREEN "\034Q" +#define TEXTCOLOR_DARKRED "\034R" +#define TEXTCOLOR_DARKBROWN "\034S" +#define TEXTCOLOR_PURPLE "\034T" +#define TEXTCOLOR_DARKGRAY "\034U" +#define TEXTCOLOR_CYAN "\034V" +#define TEXTCOLOR_ICE "\034W" +#define TEXTCOLOR_FIRE "\034X" +#define TEXTCOLOR_SAPPHIRE "\034Y" +#define TEXTCOLOR_TEAL "\034Z" + // game print flags enum { @@ -48,3 +76,8 @@ int VPrintf(int printlevel, const char* format, va_list parms); int Printf (int printlevel, const char *format, ...) ATTRIBUTE((format(printf,2,3))); int Printf (const char *format, ...) ATTRIBUTE((format(printf,1,2))); int DPrintf (int level, const char *format, ...) ATTRIBUTE((format(printf,2,3))); + +void debugprintf(const char* f, ...); // Prints to the debugger's log. + +// flag to silence non-error output +extern bool batchrun; diff --git a/source/core/utility/sc_man.cpp b/source/core/utility/sc_man.cpp index 0633280a7..5e20fd2e6 100644 --- a/source/core/utility/sc_man.cpp +++ b/source/core/utility/sc_man.cpp @@ -48,7 +48,7 @@ #include "templates.h" #include "zstring.h" #include "name.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" // MACROS ------------------------------------------------------------------ @@ -171,7 +171,7 @@ FScanner &FScanner::operator=(const FScanner &other) void FScanner::Open (const char *name) { - auto fr = fileSystem.OpenFileReader(name, 0); + auto fr = fileSystem.OpenFileReader(name); if (!fr.isOpen()) { I_Error("Could not find script lump '%s'\n", name); @@ -199,7 +199,7 @@ FScanner::FScanner(int lump) Close(); auto data = fileSystem.GetFileData(lump, 1); ScriptBuffer = data; - ScriptName = fileSystem.GetFileName(lump); + ScriptName = fileSystem.GetFileFullName(lump); LumpNum = lump; PrepareScript(); } diff --git a/source/core/utility/stringtable.cpp b/source/core/utility/stringtable.cpp index eca32f315..692f9ad2e 100644 --- a/source/core/utility/stringtable.cpp +++ b/source/core/utility/stringtable.cpp @@ -61,13 +61,13 @@ void FStringTable::LoadStrings () int lastlump, lump; lastlump = 0; - while ((lump = fileSystem.Iterate("engine/lmacros", &lastlump, ELookupMode::NoExtension)) != -1) + while ((lump = fileSystem.FindLumpFullName("engine/lmacros", &lastlump, true)) != -1) { readMacros(lump); } lastlump = 0; - while ((lump = fileSystem.Iterate ("engine/language", &lastlump, ELookupMode::NoExtension)) != -1) + while ((lump = fileSystem.FindLumpFullName("engine/language", &lastlump, true)) != -1) { auto lumpdata = fileSystem.GetFileData(lump); diff --git a/source/duke3d/src/anim.cpp b/source/duke3d/src/anim.cpp index f09f4f94b..6c002f0a5 100644 --- a/source/duke3d/src/anim.cpp +++ b/source/duke3d/src/anim.cpp @@ -244,7 +244,7 @@ int32_t Anim_Play(const char *fn) FileReader handle; if (!Bstrcmp(dot, ".ivf")) { - handle = fileSystem.OpenFileReader(fn, 0); + handle = fileSystem.OpenFileReader(fn); if (!handle.isOpen()) break; } @@ -263,7 +263,7 @@ int32_t Anim_Play(const char *fn) vpxfndot[3] = 'f'; vpxfndot[4] = '\0'; - handle = fileSystem.OpenFileReader(vpxfn, 0); + handle = fileSystem.OpenFileReader(vpxfn); if (!handle.isOpen()) break; @@ -404,7 +404,7 @@ int32_t Anim_Play(const char *fn) int32_t ogltexfiltermode = hw_texfilter; TArray buffer; - auto fr = fileSystem.OpenFileReader(fn, 0); + auto fr = fileSystem.OpenFileReader(fn); if (!fr.isOpen()) goto end_anim; diff --git a/source/duke3d/src/common.cpp b/source/duke3d/src/common.cpp index 061fc4233..88c051014 100644 --- a/source/duke3d/src/common.cpp +++ b/source/duke3d/src/common.cpp @@ -106,7 +106,7 @@ void G_LoadLookups(void) { int32_t j; - auto fr = fileSystem.OpenFileReader("lookup.dat", 0); + auto fr = fileSystem.OpenFileReader("lookup.dat"); if (!fr.isOpen()) return; diff --git a/source/duke3d/src/demo.h b/source/duke3d/src/demo.h index f27b0f9dd..3d0475f39 100644 --- a/source/duke3d/src/demo.h +++ b/source/duke3d/src/demo.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define demo_h_ #include "compat.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" BEGIN_DUKE_NS diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index b125c2bae..8f75db897 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -46,7 +46,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "printf.h" #include "m_argv.h" #include "c_dispatch.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "statistics.h" #include "menu/menu.h" #include "mapinfo.h" diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp index 30602091c..96d3628f1 100644 --- a/source/duke3d/src/gamedef.cpp +++ b/source/duke3d/src/gamedef.cpp @@ -1931,7 +1931,7 @@ static int C_CountCaseStatements() static void C_Include(const char *confile) { - auto fp = fileSystem.OpenFileReader(confile,0); + auto fp = fileSystem.OpenFileReader(confile); if (!fp.isOpen()) { @@ -5936,7 +5936,7 @@ void C_Compile(const char *fileName) Gv_Init(); C_InitProjectiles(); - auto kFile = fileSystem.OpenFileReader(fileName,0); + auto kFile = fileSystem.OpenFileReader(fileName); if (!kFile.isOpen()) { diff --git a/source/duke3d/src/gamevars.h b/source/duke3d/src/gamevars.h index 89262e7af..d83903df3 100644 --- a/source/duke3d/src/gamevars.h +++ b/source/duke3d/src/gamevars.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "fix16.hpp" #include "gamedef.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" BEGIN_DUKE_NS diff --git a/source/exhumed/src/exhumed.cpp b/source/exhumed/src/exhumed.cpp index 7667cce56..3bf117f99 100644 --- a/source/exhumed/src/exhumed.cpp +++ b/source/exhumed/src/exhumed.cpp @@ -2808,7 +2808,7 @@ void InitSpiritHead() lNextStateChange = (int)totalclock; lHeadStartClock = (int)totalclock; - auto headfd = fileSystem.OpenFileReader(filename, 512); // 512?? + auto headfd = fileSystem.OpenFileReader(filename); // 512?? if (!headfd.isOpen()) { memset(cPupData, 0, sizeof(cPupData)); diff --git a/source/exhumed/src/exhumed.h b/source/exhumed/src/exhumed.h index 8e584fc88..0319beb92 100644 --- a/source/exhumed/src/exhumed.h +++ b/source/exhumed/src/exhumed.h @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "tarray.h" #include "save.h" #include "zstring.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" BEGIN_PS_NS diff --git a/source/exhumed/src/light.cpp b/source/exhumed/src/light.cpp index e56bef4a9..11d1cfa67 100644 --- a/source/exhumed/src/light.cpp +++ b/source/exhumed/src/light.cpp @@ -85,7 +85,7 @@ int LoadPaletteLookups() for (int i = 0; i < kMaxGrads; i++) { - auto hFile = fileSystem.OpenFileReader(GradList[i], 1); + auto hFile = fileSystem.OpenFileReader(GradList[i]); if (!hFile.isOpen()) { Printf("Error reading palette lookup '%s'\n", GradList[i]); diff --git a/source/exhumed/src/menu.cpp b/source/exhumed/src/menu.cpp index fdad9dc4e..256505f0e 100644 --- a/source/exhumed/src/menu.cpp +++ b/source/exhumed/src/menu.cpp @@ -1004,7 +1004,7 @@ int LoadCinemaPalette(int nPal) // original code strcpy'd into a buffer first... - auto hFile = fileSystem.OpenFileReader(cinpalfname[nPal], 0); + auto hFile = fileSystem.OpenFileReader(cinpalfname[nPal]); if (!hFile.isOpen()) { return -2; } diff --git a/source/exhumed/src/movie.cpp b/source/exhumed/src/movie.cpp index a69c818f1..45e1b43f6 100644 --- a/source/exhumed/src/movie.cpp +++ b/source/exhumed/src/movie.cpp @@ -194,7 +194,7 @@ void PlayMovie(const char* fileName) int bDoFade = kTrue; int hFx = -1; - auto fp = fileSystem.OpenFileReader(fileName, 0); + auto fp = fileSystem.OpenFileReader(fileName); if (!fp.isOpen()) { Printf("Unable to open %s\n", fileName); diff --git a/source/glbackend/glbackend.cpp b/source/glbackend/glbackend.cpp index 4c122c2e1..ba666fea4 100644 --- a/source/glbackend/glbackend.cpp +++ b/source/glbackend/glbackend.cpp @@ -39,10 +39,10 @@ #include "gl_shader.h" #include "textures.h" #include "palette.h" -#include "imgui.h" +//#include "imgui.h" #include "gamecontrol.h" -#include "imgui_impl_sdl.h" -#include "imgui_impl_opengl3.h" +//#include "imgui_impl_sdl.h" +//#include "imgui_impl_opengl3.h" #include "baselayer.h" #include "gl_interface.h" #include "v_2ddrawer.h" @@ -60,7 +60,7 @@ TArray matrixArray; FileReader GetResource(const char* fn) { - auto fr = fileSystem.OpenFileReader(fn, 0); + auto fr = fileSystem.OpenFileReader(fn); if (!fr.isOpen()) { I_Error("Fatal: '%s' not found", fn); @@ -77,8 +77,8 @@ GLInstance::GLInstance() matrixArray.Push(mat); } -void ImGui_Init_Backend(); -ImGuiContext* im_ctx; +//void ImGui_Init_Backend(); +//ImGuiContext* im_ctx; TArray ttf; void GLInstance::Init(int ydim) diff --git a/source/libsmackerdec/src/FileStream.cpp b/source/libsmackerdec/src/FileStream.cpp index af0046545..5676e2bd3 100644 --- a/source/libsmackerdec/src/FileStream.cpp +++ b/source/libsmackerdec/src/FileStream.cpp @@ -18,7 +18,7 @@ */ #include "FileStream.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include #include "cmdlib.h" @@ -28,7 +28,7 @@ bool FileStream::Open(const char *fileName) { FString fixedname = fileName; FixPathSeperator(fixedname); - file = fileSystem.OpenFileReader(fixedname, 0); + file = fileSystem.OpenFileReader(fixedname); if (!file.isOpen()) { // log error diff --git a/source/platform/win32/i_input.cpp b/source/platform/win32/i_input.cpp index e7633bc1b..c3e7d65d8 100644 --- a/source/platform/win32/i_input.cpp +++ b/source/platform/win32/i_input.cpp @@ -136,6 +136,7 @@ extern bool AppActive; int SessionState = 0; int BlockMouseMove; +int refreshfreq; static bool EventHandlerResultForNativeMouse; diff --git a/source/platform/win32/i_specialpaths.cpp b/source/platform/win32/i_specialpaths.cpp index b90734dfa..616e85c01 100644 --- a/source/platform/win32/i_specialpaths.cpp +++ b/source/platform/win32/i_specialpaths.cpp @@ -45,7 +45,6 @@ #include "version.h" // for GAMENAME // Stuff that needs to be set up later. -static bool batchrun; // Vanilla MinGW does not have folder ids #if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) diff --git a/source/rr/src/anim.cpp b/source/rr/src/anim.cpp index 55e8dd11e..f7b5bcaf5 100644 --- a/source/rr/src/anim.cpp +++ b/source/rr/src/anim.cpp @@ -280,7 +280,7 @@ int32_t Anim_Play(const char *fn) FileReader handle; if (!Bstrcmp(dot, ".ivf")) { - handle = fileSystem.OpenFileReader(fn, 0); + handle = fileSystem.OpenFileReader(fn); if (!handle.isOpen()) break; } @@ -299,7 +299,7 @@ int32_t Anim_Play(const char *fn) vpxfndot[3] = 'f'; vpxfndot[4] = '\0'; - handle = fileSystem.OpenFileReader(vpxfn, 0); + handle = fileSystem.OpenFileReader(vpxfn); if (!handle.isOpen()) break; @@ -436,7 +436,7 @@ int32_t Anim_Play(const char *fn) // ANM playback --- v v v --- int32_t ogltexfiltermode = hw_texfilter; - auto fr = fileSystem.OpenFileReader(fn, 0); + auto fr = fileSystem.OpenFileReader(fn); if (!fr.isOpen()) return 0; diff --git a/source/rr/src/common.cpp b/source/rr/src/common.cpp index da818ae1d..132884208 100644 --- a/source/rr/src/common.cpp +++ b/source/rr/src/common.cpp @@ -105,7 +105,7 @@ void G_LoadLookups(void) { int32_t j; - auto fr = fileSystem.OpenFileReader("lookup.dat", 0); + auto fr = fileSystem.OpenFileReader("lookup.dat"); if (!fr.isOpen()) return; diff --git a/source/rr/src/game.cpp b/source/rr/src/game.cpp index f97947d20..138103815 100644 --- a/source/rr/src/game.cpp +++ b/source/rr/src/game.cpp @@ -43,7 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "gameconfigfile.h" #include "printf.h" #include "m_argv.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "statistics.h" #include "c_dispatch.h" #include "mapinfo.h" diff --git a/source/rr/src/gamedef.cpp b/source/rr/src/gamedef.cpp index 9a76f5697..d94f3e007 100644 --- a/source/rr/src/gamedef.cpp +++ b/source/rr/src/gamedef.cpp @@ -955,7 +955,7 @@ static int32_t C_CheckEmptyBranch(int32_t tw, intptr_t lastScriptPtr) static void C_Include(const char *confile) { - auto fp = fileSystem.OpenFileReader(confile,0); + auto fp = fileSystem.OpenFileReader(confile); if (!fp.isOpen()) { @@ -2646,7 +2646,7 @@ void C_Compile(const char *fileName) C_InitHashes(); Gv_Init(); - auto kFile = fileSystem.OpenFileReader(fileName,0); + auto kFile = fileSystem.OpenFileReader(fileName); if (!kFile.isOpen()) { diff --git a/source/sw/src/anim.cpp b/source/sw/src/anim.cpp index f5e683188..2d12cc923 100644 --- a/source/sw/src/anim.cpp +++ b/source/sw/src/anim.cpp @@ -241,7 +241,7 @@ playanm(short anim_num) MONO_PRINT(ds); TArray buffer; - auto fr = fileSystem.OpenFileReader(ANIMname[ANIMnum], 0); + auto fr = fileSystem.OpenFileReader(ANIMname[ANIMnum]); if (!fr.isOpen()) goto ENDOFANIMLOOP; diff --git a/source/sw/src/demo.h b/source/sw/src/demo.h index e0324923f..3fa3402fc 100644 --- a/source/sw/src/demo.h +++ b/source/sw/src/demo.h @@ -55,7 +55,7 @@ extern int DemoRecCnt; // Can only record 1-player game #if DEMO_FILE_TYPE == DEMO_FILE_GROUP typedef FileReader DFILE; #define DREAD(ptr, size, num, handle) (handle).Read((ptr),(size)*(num)) -#define DOPEN_READ(name) fileSystem.OpenFileReader(name,0) +#define DOPEN_READ(name) fileSystem.OpenFileReader(name) #define DCLOSE(handle) ((handle).Close()) #define DF_ERR(f) (!(f).isOpen()) #else diff --git a/source/sw/src/scrip2.cpp b/source/sw/src/scrip2.cpp index 7a781b77b..eab38165d 100644 --- a/source/sw/src/scrip2.cpp +++ b/source/sw/src/scrip2.cpp @@ -82,7 +82,7 @@ SWBOOL LoadScriptFile(const char *filename) - if (!(fp = fileSystem.OpenFileReader(filename, 0)).isOpen()) + if (!(fp = fileSystem.OpenFileReader(filename)).isOpen()) { // If there's no script file, forget it. return FALSE; diff --git a/source/sw/src/sounds.cpp b/source/sw/src/sounds.cpp index 3d7afab5c..276000243 100644 --- a/source/sw/src/sounds.cpp +++ b/source/sw/src/sounds.cpp @@ -51,7 +51,7 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms #include "menu/menu.h" #include "z_music.h" #include "sound/s_soundinternal.h" -#include "filesystem/filesystem.h" +#include "filesystem.h" #include "serializer.h" BEGIN_SW_NS