FileSystem cleanup.

* split off the Doom specific lookup with short 8 character names into its own class and cleaned up the interface a bit.
* get rid of all short name aliasing 'optimization' - modern compilers are capable of optimizing memcmp and memcpy to use equally efficient code so none of these hacks are needed anymore.
* added reader for Descent 3's HOG2 format - yet another of these endless uncompressed formats with just a different directory structure...
This commit is contained in:
Christoph Oelckers 2024-11-24 13:34:34 +01:00
parent 634a646c2d
commit a3475d3973
23 changed files with 1187 additions and 945 deletions

View file

@ -1096,6 +1096,7 @@ set (PCH_SOURCES
common/engine/cycler.cpp
common/engine/d_event.cpp
common/engine/date.cpp
common/engine/filesys_doom.cpp
common/engine/stats.cpp
common/engine/sc_man.cpp
common/engine/palettecontainer.cpp
@ -1230,6 +1231,7 @@ set( GAME_SOURCES
common/filesystem/source/file_whres.cpp
common/filesystem/source/file_ssi.cpp
common/filesystem/source/file_hog.cpp
common/filesystem/source/file_hog2.cpp
common/filesystem/source/file_mvl.cpp
common/filesystem/source/file_directory.cpp
common/filesystem/source/resourcefile.cpp

View file

@ -0,0 +1,648 @@
/*
** filesys_doom.cpp
**
** the very special lump name lookup code for Doom's short names.
** Not useful in a generic system.
**
**---------------------------------------------------------------------------
** Copyright 1998-2016 Randy Heit
** Copyright 2005-2024 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
**
*/
#include "filesystem.h"
#include "printf.h"
//==========================================================================
//
//
//
//==========================================================================
void FileSystem::InitHashChains()
{
Super::InitHashChains();
unsigned NumEntries = GetNumEntries();
for (unsigned i = 0; i < (unsigned)NumEntries; i++)
{
files[i].HashFirst = files[i].HashNext = NULL_INDEX;
}
// Now set up the chains
for (unsigned i = 0; i < (unsigned)NumEntries; i++)
{
if (files[i].Namespace == ns_hidden || files[i].ShortName[0] == 0) continue;
unsigned j = FileSys::MakeHash(files[i].ShortName, 8) % NumEntries;
files[i].HashNext = files[j].HashFirst;
files[j].HashFirst = i;
}
}
//==========================================================================
//
//
//
//==========================================================================
static void UpperCopy(char* to, const char* from)
{
int i;
for (i = 0; i < 8 && from[i]; i++)
to[i] = toupper(from[i]);
for (; i < 8; i++)
to[i] = 0;
to[8] = 0;
}
//==========================================================================
//
//
//
//==========================================================================
void FileSystem::SetupName(int fileindex)
{
const char* name = GetFileName(fileindex);
int containerflags = GetResourceFileFlags(GetFileContainer(fileindex));
int lflags = GetFileFlags(fileindex);
if ((containerflags & wadflags) == wadflags)
{
UpperCopy(files[fileindex].ShortName, name);
}
else if ((lflags & FileSys::RESFF_EMBEDDED) || !*name)
{
files[fileindex].Namespace = ns_hidden;
}
else
{
if (lflags & FileSys::RESFF_FULLPATH) files[fileindex].Flags |= LUMPF_FULLPATH; // copy for easier access in lookup function.
auto slash = strrchr(name, '/');
auto base = slash ? (slash + 1) : name;
UpperCopy(files[fileindex].ShortName, base);
auto dot = strrchr(files[fileindex].ShortName, '.');
if (dot) while (*dot) *dot++ = 0;
}
}
//==========================================================================
//
// IsMarker
//
// (from BOOM)
//
//==========================================================================
inline bool FileSystem::IsMarker(int lump, const char* marker) noexcept
{
auto name = files[lump].ShortName;
if (name[0] == marker[0])
{
return (!strcmp(name, marker) ||
(marker[1] == '_' && !strcmp(name + 1, marker)));
}
else return false;
}
//==========================================================================
//
// SetNameSpace
//
// Sets namespace information for the lumps. It always looks for the first
// x_START and the last x_END lump, except when loading flats. In this case
// F_START may be absent and if that is the case all lumps with a size of
// 4096 will be flagged appropriately.
//
//==========================================================================
// This class was supposed to be local in the function but GCC
// does not like that.
struct Marker
{
int markertype;
int index;
};
void FileSystem::SetNamespace(int filenum, const char* startmarker, const char* endmarker, namespace_t space, FileSys::FileSystemMessageFunc Printf, bool flathack)
{
using FileSys::FSMessageLevel;
bool warned = false;
int numstartmarkers = 0, numendmarkers = 0;
TArray<Marker> markers;
int FirstLump = GetFirstEntry(filenum);
int LastLump = GetLastEntry(filenum);
auto FileName = GetResourceFileName(filenum);
for (int i = FirstLump; i <= LastLump; i++)
{
if (IsMarker(i, startmarker))
{
Marker m = { 0, i };
markers.push_back(m);
numstartmarkers++;
}
else if (IsMarker(i, endmarker))
{
Marker m = { 1, i };
markers.push_back(m);
numendmarkers++;
}
}
if (numstartmarkers == 0)
{
if (numendmarkers == 0) return; // no markers found
if (Printf)
Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker);
if (flathack)
{
// We have found no F_START but one or more F_END markers.
// mark all lumps before the last F_END marker as potential flats.
unsigned int end = markers[markers.size() - 1].index;
for (int ii = FirstLump; ii <= LastLump; ii++)
{
if (FileLength(ii) == 4096)
{
// We can't add this to the flats namespace but
// it needs to be flagged for the texture manager.
if (Printf) Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName, files[ii].ShortName);
files[ii].Namespace = ns_maybeflat;
}
}
}
return;
}
size_t i = 0;
while (i < markers.size())
{
int start, end;
if (markers[i].markertype != 0)
{
if (Printf) Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker);
i++;
continue;
}
start = int(i++);
// skip over subsequent x_START markers
while (i < markers.size() && markers[i].markertype == 0)
{
if (Printf) Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, startmarker);
i++;
continue;
}
// same for x_END markers
while (i < markers.size() - 1 && (markers[i].markertype == 1 && markers[i + 1].markertype == 1))
{
if (Printf) Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, endmarker);
i++;
continue;
}
// We found a starting marker but no end marker. Ignore this block.
if (i >= markers.size())
{
if (Printf) Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, startmarker, endmarker);
end = LastLump + 1;
}
else
{
end = markers[i++].index;
}
// we found a marked block
if (Printf) Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName, startmarker, markers[start].index, end);
for (int j = markers[start].index + 1; j < end; j++)
{
if (files[j].Namespace != ns_global)
{
if (!warned && Printf)
{
Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName, j);
}
warned = true;
}
else if (space == ns_sprites && FileLength(j) < 8)
{
// sf 26/10/99:
// ignore sprite lumps smaller than 8 bytes (the smallest possible)
// in size -- this was used by some dmadds wads
// as an 'empty' graphics resource
if (Printf) Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName, files[j].ShortName, j);
}
else
{
files[j].Namespace = space;
}
}
}
}
//==========================================================================
//
// W_SkinHack
//
// Tests a wad file to see if it contains an S_SKIN marker. If it does,
// every lump in the wad is moved into a new namespace. Because skins are
// only supposed to replace player sprites, sounds, or faces, this should
// not be a problem. Yes, there are skins that replace more than that, but
// they are such a pain, and breaking them like this was done on purpose.
// This also renames any S_SKINxx lumps to just S_SKIN.
//
//==========================================================================
void FileSystem::SkinHack(int filenum, FileSys::FileSystemMessageFunc Printf)
{
using FileSys::FSMessageLevel;
// this being static is not a problem. The only relevant thing is that each skin gets a different number.
bool skinned = false;
bool hasmap = false;
int FirstLump = GetFirstEntry(filenum);
int LastLump = GetLastEntry(filenum);
auto FileName = GetResourceFileName(filenum);
for (int i = FirstLump; i <= LastLump; i++)
{
auto lump = &files[i];
if (!strnicmp(lump->ShortName, "S_SKIN", 6))
{ // Wad has at least one skin.
lump->ShortName[6] = 0;
lump->ShortName[7] = 0;
if (!skinned)
{
skinned = true;
for (int j = FirstLump; j <= LastLump; j++)
{
files[j].Namespace = skin_namespc;
}
skin_namespc++;
}
}
// needless to say, this check is entirely useless these days as map names can be more diverse..
if ((lump->ShortName[0] == 'M' &&
lump->ShortName[1] == 'A' &&
lump->ShortName[2] == 'P' &&
lump->ShortName[3] >= '0' && lump->ShortName[3] <= '9' &&
lump->ShortName[4] >= '0' && lump->ShortName[4] <= '9' &&
lump->ShortName[5] == '\0')
||
(lump->ShortName[0] == 'E' &&
lump->ShortName[1] >= '0' && lump->ShortName[1] <= '9' &&
lump->ShortName[2] == 'M' &&
lump->ShortName[3] >= '0' && lump->ShortName[3] <= '9' &&
lump->ShortName[4] == '\0'))
{
hasmap = true;
}
}
if (skinned && hasmap && Printf)
{
Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName);
Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n");
}
}
//==========================================================================
//
//
//
//==========================================================================
void FileSystem::SetupNamespace(int filenum, FileSys::FileSystemMessageFunc Printf)
{
int flags = GetResourceFileFlags(filenum);
// Set namespace for entries from WADs.
if ((flags & wadflags) == wadflags)
{
SetNamespace(filenum, "S_START", "S_END", ns_sprites, Printf);
SetNamespace(filenum, "F_START", "F_END", ns_flats, Printf, true);
SetNamespace(filenum, "C_START", "C_END", ns_colormaps, Printf);
SetNamespace(filenum, "A_START", "A_END", ns_acslibrary, Printf);
SetNamespace(filenum, "TX_START", "TX_END", ns_newtextures, Printf);
SetNamespace(filenum, "V_START", "V_END", ns_strifevoices, Printf);
SetNamespace(filenum, "HI_START", "HI_END", ns_hires, Printf);
SetNamespace(filenum, "VX_START", "VX_END", ns_voxels, Printf);
SkinHack(filenum, Printf);
}
else if (!(flags & FResourceFile::NO_FOLDERS))
{
int FirstLump = GetFirstEntry(filenum);
int LastLump = GetLastEntry(filenum);
auto FileName = GetResourceFileName(filenum);
for (int i = FirstLump; i <= LastLump; i++)
{
auto lump = &files[i];
auto LongName = GetFileName(i);
// Map some directories to WAD namespaces.
// Note that some of these namespaces don't exist in WADS.
// CheckNumForName will handle any request for these namespaces accordingly.
int Namespace = !strncmp(LongName, "flats/", 6) ? ns_flats :
!strncmp(LongName, "textures/", 9) ? ns_newtextures :
!strncmp(LongName, "hires/", 6) ? ns_hires :
!strncmp(LongName, "sprites/", 8) ? ns_sprites :
!strncmp(LongName, "voxels/", 7) ? ns_voxels :
!strncmp(LongName, "colormaps/", 10) ? ns_colormaps :
!strncmp(LongName, "acs/", 4) ? ns_acslibrary :
!strncmp(LongName, "voices/", 7) ? ns_strifevoices :
!strncmp(LongName, "patches/", 8) ? ns_patches :
!strncmp(LongName, "graphics/", 9) ? ns_graphics :
!strncmp(LongName, "sounds/", 7) ? ns_sounds :
!strncmp(LongName, "music/", 6) ? ns_music :
!strchr(LongName, '/') ? ns_global :
ns_hidden;
lump->Namespace = Namespace;
switch (Namespace)
{
case ns_hidden:
memset(lump->ShortName, 0, sizeof(lump->ShortName));
break;
case ns_sprites:
case ns_voxels:
case ns_hires:
// Since '\' can't be used as a file name's part inside a ZIP
// we have to work around this for sprites because it is a valid
// frame character.
for (auto& c : lump->ShortName)
{
if (c == '^') c = '\\';
}
break;
}
}
}
}
//==========================================================================
//
//
//
//==========================================================================
bool FileSystem::InitFiles(std::vector<std::string>& filenames, FileSys::FileSystemFilterInfo* filter, FileSys::FileSystemMessageFunc Printf, bool allowduplicates)
{
if (!Super::InitFiles(filenames, filter, Printf, allowduplicates)) return false;
files.Resize(GetNumEntries());
memset(files.Data(), 0, sizeof(files[0]) * files.size());
int numfiles = GetNumEntries();
for (int i = 0; i < numfiles; i++)
{
SetupName(i);
}
int numresfiles = GetNumWads();
for (int i = 0; i < numresfiles; i++)
{
SetupNamespace(i, Printf);
}
return true;
}
//==========================================================================
//
// CheckNumForName
//
// Returns -1 if name not found. The version with a third parameter will
// look exclusively in the specified wad for the lump.
//
// [RH] Changed to use hash lookup ala BOOM instead of a linear search
// and namespace parameter
//==========================================================================
int FileSystem::CheckNumForName(const char* name, int space) const
{
char uname[9];
uint32_t i;
if (name == nullptr)
{
return -1;
}
// Let's not search for names that are longer than 8 characters and contain path separators
// They are almost certainly full path names passed to this function.
if (strlen(name) > 8 && strpbrk(name, "/."))
{
return -1;
}
UpperCopy(uname, name);
i = files[FileSys::MakeHash(uname, 8) % files.Size()].HashFirst;
while (i != NULL_INDEX)
{
auto& lump = files[i];
if (!memcmp(lump.ShortName, uname, 8))
{
if (lump.Namespace == space) break;
// If the lump is from one of the special namespaces exclusive to Zips
// the check has to be done differently:
// If we find a lump with this name in the global namespace that does not come
// from a Zip return that. WADs don't know these namespaces and single lumps must
// work as well.
if (space > ns_specialzipdirectory && lump.Namespace == ns_global && !(lump.Flags & LUMPF_FULLPATH))
break;
}
i = lump.HashNext;
}
return i != NULL_INDEX ? i : -1;
}
int FileSystem::CheckNumForName(const char* name, int space, int rfnum, bool exact) const
{
char uname[9];
uint32_t i;
if (rfnum < 0)
{
return CheckNumForName(name, space);
}
UpperCopy(uname, name);
i = files[FileSys::MakeHash(uname, 8) % files.Size()].HashFirst;
// If exact is true if will only find lumps in the same WAD, otherwise
// also those in earlier WADs.
while (i != NULL_INDEX &&
(memcmp(files[i].ShortName, uname, 8) || files[i].Namespace != space ||
(exact ? (GetFileContainer(i) != rfnum) : (GetFileContainer(i) > rfnum))))
{
i = files[i].HashNext;
}
return i != NULL_INDEX ? i : -1;
}
//==========================================================================
//
// GetNumForName
//
// Calls CheckNumForName, but bombs out if not found.
//
//==========================================================================
int FileSystem::GetNumForName(const char* name, int space) const
{
int i;
i = CheckNumForName(name, space);
if (i == -1)
throw FileSys::FileSystemException("GetNumForName: %s not found!", name);
return i;
}
//==========================================================================
//
// returns a modifiable pointer to the short name
//
// should only be called before the hash chains are set up.
// If done later this needs rehashing.
//
// This is for custom setup through postprocessFunc
//
//==========================================================================
char* FileSystem::GetShortName(int i)
{
if ((unsigned)i >= files.Size())
throw FileSys::FileSystemException("GetShortName: Invalid index");
return files[i].ShortName;
}
//==========================================================================
//
// W_FindLump
//
// Find a named lump. Specifically allows duplicates for merging of e.g.
// SNDINFO lumps.
//
//==========================================================================
int FileSystem::FindLump(const char* name, int* lastlump, bool anyns)
{
if ((size_t)*lastlump >= files.size()) return -1;
char name8[9];
UpperCopy(name8, name);
assert(lastlump != nullptr && *lastlump >= 0);
const int last = (int)files.size();
for(int lump = *lastlump; lump < last; lump++)
{
const FileEntry* const lump_p = &files[lump];
if ((anyns || lump_p->Namespace == ns_global) && !memcmp(lump_p->ShortName, name8, 8))
{
*lastlump = lump + 1;
return lump;
}
}
*lastlump = last;
return -1;
}
//==========================================================================
//
// W_FindLumpMulti
//
// Find a named lump. Specifically allows duplicates for merging of e.g.
// SNDINFO lumps. Returns everything having one of the passed names.
//
//==========================================================================
int FileSystem::FindLumpMulti(const char** names, int* lastlump, bool anyns, int* nameindex)
{
assert(lastlump != nullptr && *lastlump >= 0);
int last = files.Size();
for (int lump = *lastlump; lump < last; lump++)
{
auto lump_p = &files[lump];
if (anyns || lump_p->Namespace == ns_global)
{
for (const char** name = names; *name != nullptr; name++)
{
if (!strnicmp(*name, lump_p->ShortName, 8))
{
*lastlump = lump + 1;
if (nameindex != nullptr) *nameindex = int(name - names);
return lump;
}
}
}
}
*lastlump = last;
return -1;
}
//==========================================================================
//
// This function combines lookup from regular lists and Doom's special one.
//
//==========================================================================
int FileSystem::CheckNumForAnyName(const char* name, namespace_t namespc) const
{
if (name != NULL)
{
// Check short names first to avoid interference from short names in the real file system.
if (strlen(name) <= 8 && !strpbrk(name, "./"))
{
return CheckNumForName(name, namespc);
}
int lookup = Super::CheckNumForFullName(name, false);
if (lookup >= 0) return lookup;
}
return -1;
}

View file

@ -1,7 +1,129 @@
#pragma once
#include "fs_filesystem.h"
using FileSys::FileSystem;
using FileSys::FResourceFile;
inline FileSys::FileSystem fileSystem;
// [RH] Namespaces from BOOM.
// These are needed here in the low level part so that WAD files can be properly set up.
enum namespace_t : int {
ns_hidden = -1,
ns_global = 0,
ns_sprites,
ns_flats,
ns_colormaps,
ns_acslibrary,
ns_newtextures,
ns_bloodraw, // no longer used - kept for ZScript.
ns_bloodsfx, // no longer used - kept for ZScript.
ns_bloodmisc, // no longer used - kept for ZScript.
ns_strifevoices,
ns_hires,
ns_voxels,
ns_maybeflat,
// These namespaces are only used to mark lumps in special subdirectories
// so that their contents doesn't interfere with the global namespace.
// searching for data in these namespaces works differently for lumps coming
// from Zips or other files.
ns_specialzipdirectory,
ns_sounds,
ns_patches,
ns_graphics,
ns_music,
ns_firstskin,
};
// extended class that adds Doom's very special short name lookup to the file system.
class FileSystem : public FileSys::FileSystem
{
private:
struct FileEntry
{
char ShortName[9];
uint8_t Namespace;
uint8_t Flags;
uint32_t HashFirst;
uint32_t HashNext;
};
const int wadflags = FileSys::FResourceFile::NO_EXTENSIONS | FileSys::FResourceFile::NO_FOLDERS | FileSys::FResourceFile::SHORTNAMES;
const uint32_t NULL_INDEX = 0xffffffff;
TArray<FileEntry> files;
int skin_namespc = ns_firstskin;
void Start(FileSys::FileSystemMessageFunc Printf);
void SetupName(int fileindex);
bool IsMarker(int lump, const char* marker) noexcept;
void SetNamespace(int filenum, const char* startmarker, const char* endmarker, namespace_t space, FileSys::FileSystemMessageFunc Printf, bool flathack = false);
void SkinHack(int filenum, FileSys::FileSystemMessageFunc Printf);
void SetupNamespace(int filenum, FileSys::FileSystemMessageFunc Printf);
using Super = FileSys::FileSystem;
public:
enum
{
LUMPF_MAYBEFLAT = 1,
LUMPF_FULLPATH = 2,
};
bool InitFiles(std::vector<std::string>& filenames, FileSys::FileSystemFilterInfo* filter = nullptr, FileSys::FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false) override;
void InitHashChains() override;
int CheckNumForAnyName(const char* cname, namespace_t namespc = ns_global) const;
int CheckNumForName(const char* name, int namespc) const;
int CheckNumForName(const char* name, int namespc, int wadfile, bool exact = true) const;
int GetNumForName(const char* name, int namespc) const;
inline int CheckNumForName(const uint8_t* name) const { return CheckNumForName((const char*)name, ns_global); }
inline int CheckNumForName(const char* name) const { return CheckNumForName(name, ns_global); }
inline int CheckNumForName(const uint8_t* name, int ns) const { return CheckNumForName((const char*)name, ns); }
inline int GetNumForName(const char* name) const { return GetNumForName(name, ns_global); }
inline int GetNumForName(const uint8_t* name) const { return GetNumForName((const char*)name); }
inline int GetNumForName(const uint8_t* name, int ns) const { return GetNumForName((const char*)name, ns); }
int FindLump(const char* name, int* lastlump, bool anyns = false); // [RH] Find lumps with duplication
int FindLumpMulti(const char** names, int* lastlump, bool anyns = false, int* nameindex = nullptr); // same with multiple possible names
bool CheckFileName(int lump, const char* name) const noexcept
{
if ((size_t)lump >= files.size())
return false;
return !strnicmp(files[lump].ShortName, name, 8);
}
const char* GetFileShortName(int lump) const noexcept
{
if ((size_t)lump >= files.size())
return nullptr;
else
return files[lump].ShortName;
}
int GetFileNamespace(int lump) const noexcept
{
if ((size_t)lump >= files.size())
return ns_global;
else
return files[lump].Namespace;
}
void SetFileNamespace(int lump, int ns) noexcept
{
if ((size_t)lump < files.size()) files[lump].Namespace = ns;
}
// This is only for code that wants to edit the names before the game starts.
char* GetShortName(int i);
};
inline FileSystem fileSystem;

View file

@ -13,15 +13,6 @@
namespace FileSys {
union LumpShortName
{
char String[9];
uint32_t dword; // These are for accessing the first 4 or 8 chars of
uint64_t qword; // Name as a unit without breaking strict aliasing rules
};
struct FolderEntry
{
const char *name;
@ -32,7 +23,12 @@ class FileSystem
{
public:
FileSystem();
~FileSystem ();
virtual ~FileSystem ();
// do not copy!
FileSystem(const FileSystem& other) = delete;
FileSystem& operator =(const FileSystem& other) = delete;
bool Initialize(std::vector<std::string>& filenames, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false);
// The wadnum for the IWAD
int GetIwadNum() { return IwadIndex; }
@ -41,9 +37,6 @@ public:
int GetMaxIwadNum() { return MaxIwadIndex; }
void SetMaxIwadNum(int x) { MaxIwadIndex = x; }
bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr);
bool InitMultipleFiles (std::vector<std::string>& filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false);
void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf);
int CheckIfResourceFileLoaded (const char *name) noexcept;
void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {}
@ -53,31 +46,17 @@ public:
int GetFirstEntry(int wadnum) const noexcept;
int GetLastEntry(int wadnum) const noexcept;
int GetEntryCount(int wadnum) const noexcept;
int GetResourceFileFlags(int wadnum) const noexcept;
int CheckNumForName (const char *name, int namespc) const;
int CheckNumForName (const char *name, int namespc, int wadfile, bool exact = true) const;
int GetNumForName (const char *name, int namespc) const;
inline int CheckNumForName (const uint8_t *name) const { return CheckNumForName ((const char *)name, ns_global); }
inline int CheckNumForName (const char *name) const { return CheckNumForName (name, ns_global); }
inline int CheckNumForName (const uint8_t *name, int ns) const { return CheckNumForName ((const char *)name, ns); }
inline int GetNumForName (const char *name) const { return GetNumForName (name, ns_global); }
inline int GetNumForName (const uint8_t *name) const { return GetNumForName ((const char *)name); }
inline int GetNumForName (const uint8_t *name, int ns) const { return GetNumForName ((const char *)name, ns); }
int CheckNumForFullName (const char *cname, bool trynormal = false, int namespc = ns_global, bool ignoreext = false) const;
int CheckNumForFullName (const char *cname, bool ignoreext = false) const;
int CheckNumForFullNameInFile (const char *name, int wadfile) const;
int GetNumForFullName (const char *name) const;
int CheckNumForAnyName(const char* cname, namespace_t namespc = ns_global) const
{
return CheckNumForFullName(cname, true, namespc);
}
int FindFile(const char* name) const
{
return CheckNumForFullName(name);
}
bool FileExists(const char* name) const
{
return FindFile(name) >= 0;
@ -88,14 +67,12 @@ public:
return FindFile(name.c_str()) >= 0;
}
LumpShortName& GetShortName(int i); // may only be called before the hash chains are set up.
void RenameFile(int num, const char* fn);
bool CreatePathlessCopy(const char* name, int id, int flags);
void ReadFile (int lump, void *dest);
// These should only be used if the file data really needs padding.
FileData ReadFile (int lump);
FileData ReadFile (const char *name) { return ReadFile (GetNumForName (name)); }
FileData ReadFileFullName(const char* name) { return ReadFile(GetNumForFullName(name)); }
FileReader OpenFileReader(int lump, int readertype, int readerflags); // opens a reader that redirects to the containing file's one.
@ -112,29 +89,21 @@ public:
}
int FindLump (const char *name, int *lastlump, bool anyns=false); // [RH] Find lumps with duplication
int FindLumpMulti (const char **names, int *lastlump, bool anyns = false, int *nameindex = NULL); // same with multiple possible names
int FindLumpFullName(const char* name, int* lastlump, bool noext = false);
bool CheckFileName (int lump, const char *name); // [RH] True if lump's name == name
int FindFileWithExtensions(const char* name, const char* const* exts, int count) const;
int FindResource(int resid, const char* type, int filenum = -1) const noexcept;
int GetResource(int resid, const char* type, int filenum = -1) const;
static uint32_t LumpNameHash (const char *name); // [RH] Create hash key from an 8-char name
ptrdiff_t FileLength (int lump) const;
ptrdiff_t FileLength(int lump) const;
int GetFileFlags (int lump); // Return the flags for this lump
const char* GetFileShortName(int lump) const;
const char *GetFileName (int lump, bool returnshort = true) const; // [RH] Returns the lump's full name
const char* GetFileName(int lump) const; // Gets uninterpreted name from the FResourceFile
std::string GetFileFullPath (int lump) const; // [RH] Returns wad's name + lump's full name
int GetFileContainer (int lump) const; // [RH] Returns wadnum for a specified lump
int GetFileNamespace (int lump) const; // [RH] Returns the namespace a lump belongs to
void SetFileNamespace(int lump, int ns);
int GetFileContainer (int lump) const;
// [RH] Returns wadnum for a specified lump
int GetResourceId(int lump) const; // Returns the RFF index number for this lump
const char* GetResourceType(int lump) const;
bool CheckFileName (int lump, const char *name) const; // [RH] Returns true if the names match
unsigned GetFilesInFolder(const char *path, std::vector<FolderEntry> &result, bool atomic) const;
int GetNumEntries() const
@ -149,18 +118,16 @@ public:
int AddFromBuffer(const char* name, char* data, int size, int id, int flags);
FileReader* GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD
void InitHashChains();
protected:
struct LumpRecord;
const uint32_t NULL_INDEX = 0xffffffff;
std::vector<FResourceFile *> Files;
std::vector<LumpRecord> FileInfo;
std::vector<uint32_t> Hashes; // one allocation for all hash lists.
uint32_t *FirstLumpIndex = nullptr; // [RH] Hashing stuff moved out of lumpinfo structure
uint32_t *NextLumpIndex = nullptr;
uint32_t *FirstLumpIndex_FullName = nullptr; // The same information for fully qualified paths from .zips
uint32_t *NextLumpIndex_FullName = nullptr;
@ -182,7 +149,24 @@ protected:
private:
void DeleteAll();
void MoveLumpsInFolder(const char *);
void AddFile(const char* filename, FileReader* wadinfo, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf);
protected:
// These two functions must be overridden by subclasses which want to extend the file system.
virtual bool InitFiles(std::vector<std::string>& filenames, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false);
public:
virtual void InitHashChains();
};
//djb2 hash algorithm with case insensitivity hack
inline static uint32_t MakeHash(const char* str, size_t length = SIZE_MAX)
{
uint32_t hash = 5381;
uint32_t c;
while (length-- > 0 && (c = *str++)) hash = hash * 33 + (c | 32);
return hash;
}
}

View file

@ -16,7 +16,7 @@ std::string ExtractBaseName(const char* path, bool include_extension = false);
void strReplace(std::string& str, const char* from, const char* to);
// user context in which the file system gets opened. This also contains a few callbacks to avoid direct dependencies on the engine.
struct LumpFilterInfo
struct FileSystemFilterInfo
{
std::vector<std::string> gameTypeFilter; // this can contain multiple entries
@ -45,45 +45,10 @@ using FileSystemMessageFunc = int(*)(FSMessageLevel msglevel, const char* format
class FResourceFile;
}
// [RH] Namespaces from BOOM.
// These are needed here in the low level part so that WAD files can be properly set up.
typedef enum {
ns_hidden = -1,
ns_global = 0,
ns_sprites,
ns_flats,
ns_colormaps,
ns_acslibrary,
ns_newtextures,
ns_bloodraw, // no longer used - kept for ZScript.
ns_bloodsfx, // no longer used - kept for ZScript.
ns_bloodmisc, // no longer used - kept for ZScript.
ns_strifevoices,
ns_hires,
ns_voxels,
// These namespaces are only used to mark lumps in special subdirectories
// so that their contents doesn't interfere with the global namespace.
// searching for data in these namespaces works differently for lumps coming
// from Zips or other files.
ns_specialzipdirectory,
ns_sounds,
ns_patches,
ns_graphics,
ns_music,
ns_firstskin,
} namespace_t;
namespace FileSys {
enum ELumpFlags
{
RESFF_MAYBEFLAT = 1, // might be a flat inside a WAD outside F_START/END
RESFF_FULLPATH = 2, // contains a full path. This will trigger extended namespace checks when looking up short names.
RESFF_FULLPATH = 2, // contains a full path.
RESFF_EMBEDDED = 4, // marks an embedded resource file for later processing.
RESFF_SHORTNAME = 8, // the stored name is a short extension-less name
RESFF_COMPRESSED = 16, // compressed or encrypted, i.e. cannot be read with the container file's reader.
@ -104,11 +69,10 @@ struct FResourceEntry
size_t CompressedSize;
const char* FileName;
size_t Position;
int ResourceID;
int ResourceID; // Only Blood RFF uses this natively.
uint32_t CRC32;
uint16_t Flags;
uint16_t Method;
int16_t Namespace;
};
void SetMainThread();
@ -116,17 +80,25 @@ void SetMainThread();
class FResourceFile
{
public:
FResourceFile(const char* filename, StringPool* sp);
FResourceFile(const char* filename, FileReader& r, StringPool* sp);
const char* NormalizeFileName(const char* fn, int fallbackcp = 0);
enum
{
// descibes which kind of limitations this file type has.
NO_FOLDERS = 1, // no paths - only one rpot folder (e.g. Build GRP, Blood RFF, Descent HOG
NO_EXTENSIONS = 2, // no extensions for file names (e.g. Doom WADs.)
SHORTNAMES = 4, // Name is (at most) 8.3 DOS ASCII format, (8.0 in case of WAD)
};
FResourceFile(const char* filename, StringPool* sp, int flags);
FResourceFile(const char* filename, FileReader& r, StringPool* sp, int flags);
const char* NormalizeFileName(const char* fn, int fallbackcp = 0, bool allowbackslash = false);
FResourceEntry* AllocateEntries(int count);
void GenerateHash();
void PostProcessArchive(LumpFilterInfo* filter);
void PostProcessArchive(FileSystemFilterInfo* filter);
protected:
FileReader Reader;
const char* FileName;
FResourceEntry* Entries = nullptr;
uint32_t NumLumps;
int flags = 0;
char Hash[48];
StringPool* stringpool;
@ -136,7 +108,7 @@ protected:
Entries[entry].Flags &= ~RESFF_NEEDFILESTART;
}
bool IsFileInFolder(const char* const resPath);
void CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi);
void CheckEmbedded(uint32_t entry, FileSystemFilterInfo* lfi);
private:
uint32_t FirstLump;
@ -144,18 +116,19 @@ private:
int FilterLumps(const std::string& filtername, uint32_t max);
bool FindPrefixRange(const char* filter, uint32_t max, uint32_t &start, uint32_t &end);
void JunkLeftoverFilters(uint32_t max);
void FindCommonFolder(LumpFilterInfo* filter);
static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
void FindCommonFolder(FileSystemFilterInfo* filter);
static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
public:
static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
static FResourceFile *OpenDirectory(const char *filename, FileSystemFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, StringPool* sp = nullptr);
virtual ~FResourceFile();
// If this FResourceFile represents a directory, the Reader object is not usable so don't return it.
FileReader *GetContainerReader() { return Reader.isOpen()? &Reader : nullptr; }
const char* GetFileName() const { return FileName; }
uint32_t GetFirstEntry() const { return FirstLump; }
int GetFlags() const noexcept { return flags; }
void SetFirstLump(uint32_t f) { FirstLump = f; }
const char* GetHash() const { return Hash; }
@ -179,11 +152,6 @@ public:
return (entry < NumLumps) ? Entries[entry].Flags : 0;
}
int GetEntryNamespace(uint32_t entry)
{
return (entry < NumLumps) ? Entries[entry].Namespace : (int)ns_hidden;
}
int GetEntryResourceID(uint32_t entry)
{
return (entry < NumLumps) ? Entries[entry].ResourceID : -1;

View file

@ -177,7 +177,7 @@ class F7ZFile : public FResourceFile
public:
F7ZFile(const char * filename, FileReader &filer, StringPool* sp);
bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf);
bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf);
virtual ~F7ZFile();
FileData Read(uint32_t entry) override;
FileReader GetEntryReader(uint32_t entry, int, int) override;
@ -192,7 +192,7 @@ public:
//==========================================================================
F7ZFile::F7ZFile(const char * filename, FileReader &filer, StringPool* sp)
: FResourceFile(filename, filer, sp)
: FResourceFile(filename, filer, sp, 0)
{
Archive = nullptr;
}
@ -204,7 +204,7 @@ F7ZFile::F7ZFile(const char * filename, FileReader &filer, StringPool* sp)
//
//==========================================================================
bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf)
bool F7ZFile::Open(FileSystemFilterInfo *filter, FileSystemMessageFunc Printf)
{
Archive = new C7zArchive(Reader);
int skipped = 0;
@ -268,7 +268,6 @@ bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf)
Entries[j].Length = SzArEx_GetFileSize(archPtr, i);
Entries[j].Flags = RESFF_FULLPATH|RESFF_COMPRESSED;
Entries[j].ResourceID = -1;
Entries[j].Namespace = ns_global;
Entries[j].Method = METHOD_INVALID;
Entries[j].Position = i;
j++;
@ -351,7 +350,7 @@ FileReader F7ZFile::GetEntryReader(uint32_t entry, int, int)
//
//==========================================================================
FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *Check7Z(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[k7zSignatureSize];

View file

@ -57,11 +57,11 @@ class FDirectory : public FResourceFile
const char** SystemFilePath;
int AddDirectory(const char* dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf);
int AddDirectory(const char* dirpath, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf);
public:
FDirectory(const char * dirname, StringPool* sp, bool nosubdirflag = false);
bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf);
bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf);
FileReader GetEntryReader(uint32_t entry, int, int) override;
};
@ -74,7 +74,7 @@ public:
//==========================================================================
FDirectory::FDirectory(const char * directory, StringPool* sp, bool nosubdirflag)
: FResourceFile("", sp), nosubdir(nosubdirflag)
: FResourceFile("", sp, 0), nosubdir(nosubdirflag)
{
auto fn = FS_FullPath(directory);
if (fn.back() != '/') fn += '/';
@ -87,7 +87,7 @@ FDirectory::FDirectory(const char * directory, StringPool* sp, bool nosubdirflag
//
//==========================================================================
int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSystemMessageFunc Printf)
int FDirectory::AddDirectory(const char *dirpath, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf)
{
int count = 0;
@ -141,7 +141,6 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy
Entries[count].Flags = RESFF_FULLPATH;
Entries[count].ResourceID = -1;
Entries[count].Method = METHOD_STORED;
Entries[count].Namespace = ns_global;
Entries[count].Position = count;
count++;
}
@ -157,7 +156,7 @@ int FDirectory::AddDirectory(const char *dirpath, LumpFilterInfo* filter, FileSy
//
//==========================================================================
bool FDirectory::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf)
bool FDirectory::Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf)
{
NumLumps = AddDirectory(FileName, filter, Printf);
PostProcessArchive(filter);
@ -193,7 +192,7 @@ FileReader FDirectory::GetEntryReader(uint32_t entry, int readertype, int)
//
//==========================================================================
FResourceFile *CheckDir(const char *filename, bool nosubdirflag, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckDir(const char *filename, bool nosubdirflag, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
auto rf = new FDirectory(filename, sp, nosubdirflag);
if (rf->Open(filter, Printf)) return rf;

View file

@ -71,7 +71,7 @@ struct GrpLump
//
//==========================================================================
static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter)
static bool OpenGrp(FResourceFile* file, FileSystemFilterInfo* filter)
{
GrpHeader header;
@ -91,7 +91,6 @@ static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter)
Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].Size);
Position += fileinfo[i].Size;
Entries[i].Flags = 0;
Entries[i].Namespace = ns_global;
fileinfo[i].NameWithZero[12] = '\0'; // Be sure filename is null-terminated
Entries[i].ResourceID = -1;
Entries[i].Method = METHOD_STORED;
@ -109,7 +108,7 @@ static bool OpenGrp(FResourceFile* file, LumpFilterInfo* filter)
//
//==========================================================================
FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckGRP(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[12];
@ -120,7 +119,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo*
file.Seek(0, FileReader::SeekSet);
if (!memcmp(head, "KenSilverman", 12))
{
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES);
if (OpenGrp(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -44,7 +44,7 @@ namespace FileSys {
static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter)
static bool OpenHog(FResourceFile* rf, FileSystemFilterInfo* filter)
{
auto Reader = rf->GetContainerReader();
FileReader::Size length = Reader->GetLength();
@ -66,7 +66,6 @@ static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter)
Entry.CompressedSize = Entry.Length = elength;
Entry.Flags = 0;
Entry.CRC32 = 0;
Entry.Namespace = ns_global;
Entry.ResourceID = -1;
Entry.Method = METHOD_STORED;
Entry.FileName = rf->NormalizeFileName(name);
@ -86,7 +85,7 @@ static bool OpenHog(FResourceFile* rf, LumpFilterInfo* filter)
//
//==========================================================================
FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile* CheckHog(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[3];
@ -96,7 +95,7 @@ FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo*
file.Read(&head, 3);
if (!memcmp(head, "DHF", 3))
{
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES);
if (OpenHog(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -0,0 +1,107 @@
/*
** file_hog.cpp
**
** reads Descent 3 .hog2 files
**
**---------------------------------------------------------------------------
** Copyright 2024 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
**
*/
#include "resourcefile.h"
#include "fs_swap.h"
namespace FileSys {
using namespace byteswap;
static bool OpenHog2(FResourceFile* rf, FileSystemFilterInfo* filter)
{
auto Reader = rf->GetContainerReader();
FileReader::Size length = Reader->GetLength();
uint32_t numfiles = Reader->ReadUInt32();
uint32_t offset = Reader->ReadUInt32(); // offset to first file (end of file list)
Reader->Seek(56, FileReader::SeekEnd); // filled with FF
auto Entries = rf->AllocateEntries((int)numfiles);
for(uint32_t i = 0; i < numfiles; i++)
{
char name[37];
Reader->Read(name, 36);
name[36] = 0;
Reader->ReadUInt32();
uint32_t size = Reader->ReadUInt32();;
Reader->ReadUInt32();
FResourceEntry& Entry = Entries[i];
Entry.Position = offset;
Entry.CompressedSize = Entry.Length = size;
Entry.Flags = RESFF_FULLPATH;
Entry.CRC32 = 0;
Entry.ResourceID = -1;
Entry.Method = METHOD_STORED;
Entry.FileName = rf->NormalizeFileName(name);
offset += size;
}
rf->GenerateHash();
return true;
}
//==========================================================================
//
// File open
//
//==========================================================================
FResourceFile* CheckHog2(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];
if (file.GetLength() >= 68)
{
file.Seek(0, FileReader::SeekSet);
file.Read(&head, 4);
if (!memcmp(head, "HOG2", 4))
{
auto rf = new FResourceFile(filename, file, sp, 0);
if (OpenHog2(rf, filter)) return rf;
file = rf->Destroy();
}
file.Seek(0, FileReader::SeekSet);
}
return nullptr;
}
}

View file

@ -41,11 +41,10 @@ namespace FileSys {
//
//==========================================================================
static bool OpenLump(FResourceFile* file, LumpFilterInfo*)
static bool OpenLump(FResourceFile* file, FileSystemFilterInfo*)
{
auto Entries = file->AllocateEntries(1);
Entries[0].FileName = file->NormalizeFileName(ExtractBaseName(file->GetFileName(), true).c_str());
Entries[0].Namespace = ns_global;
Entries[0].ResourceID = -1;
Entries[0].Position = 0;
Entries[0].CompressedSize = Entries[0].Length = file->GetContainerReader()->GetLength();
@ -60,10 +59,10 @@ static bool OpenLump(FResourceFile* file, LumpFilterInfo*)
//
//==========================================================================
FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckLump(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
// always succeeds
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS);
if (OpenLump(rf, filter)) return rf;
file = rf->Destroy();
return NULL;

View file

@ -43,7 +43,7 @@ namespace FileSys {
static bool OpenMvl(FResourceFile* rf, LumpFilterInfo* filter)
static bool OpenMvl(FResourceFile* rf, FileSystemFilterInfo* filter)
{
auto Reader = rf->GetContainerReader();
auto count = Reader->ReadUInt32();
@ -75,7 +75,7 @@ static bool OpenMvl(FResourceFile* rf, LumpFilterInfo* filter)
//
//==========================================================================
FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile* CheckMvl(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];
@ -85,7 +85,7 @@ FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo*
file.Read(&head, 4);
if (!memcmp(head, "DMVL", 4))
{
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES);
if (OpenMvl(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -63,7 +63,7 @@ struct dpackheader_t
//
//==========================================================================
static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter)
static bool OpenPak(FResourceFile* file, FileSystemFilterInfo* filter)
{
dpackheader_t header;
@ -82,7 +82,6 @@ static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter)
Entries[i].Position = LittleLong(fileinfo[i].filepos);
Entries[i].CompressedSize = Entries[i].Length = LittleLong(fileinfo[i].filelen);
Entries[i].Flags = RESFF_FULLPATH;
Entries[i].Namespace = ns_global;
Entries[i].ResourceID = -1;
Entries[i].Method = METHOD_STORED;
Entries[i].FileName = file->NormalizeFileName(fileinfo[i].name);
@ -99,7 +98,7 @@ static bool OpenPak(FResourceFile* file, LumpFilterInfo* filter)
//
//==========================================================================
FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckPak(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];
@ -110,7 +109,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo*
file.Seek(0, FileReader::SeekSet);
if (!memcmp(head, "PACK", 4))
{
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, 0);
if (OpenPak(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -91,7 +91,7 @@ void BloodCrypt (void *data, int key, int len)
//
//==========================================================================
static bool OpenRFF(FResourceFile* file, LumpFilterInfo*)
static bool OpenRFF(FResourceFile* file, FileSystemFilterInfo*)
{
RFFLump *lumps;
RFFInfo header;
@ -123,7 +123,6 @@ static bool OpenRFF(FResourceFile* file, LumpFilterInfo*)
Entries[i].Flags = 0;
Entries[i].Method = METHOD_STORED;
}
Entries[i].Namespace = ns_global;
Entries[i].ResourceID = LittleLong(lumps[i].IndexNum);
// Rearrange the name and extension to construct the fullname.
@ -150,7 +149,7 @@ static bool OpenRFF(FResourceFile* file, LumpFilterInfo*)
//
//==========================================================================
FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckRFF(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];
@ -161,7 +160,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo*
file.Seek(0, FileReader::SeekSet);
if (!memcmp(head, "RFF\x1a", 4))
{
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES);
if (OpenRFF(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -44,7 +44,7 @@ namespace FileSys {
//
//==========================================================================
static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilterInfo*)
static bool OpenSSI(FResourceFile* file, int version, int EntryCount, FileSystemFilterInfo*)
{
uint32_t NumLumps = EntryCount * 2;
auto Entries = file->AllocateEntries(NumLumps);
@ -65,7 +65,6 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter
Entries[i].Position = j;
Entries[i].CompressedSize = Entries[i].Length = flength;
Entries[i].Flags = 0;
Entries[i].Namespace = ns_global;
Entries[i].Method = METHOD_STORED;
Entries[i].ResourceID = -1;
Entries[i].FileName = file->NormalizeFileName(fn);
@ -78,7 +77,6 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter
Entries[i + 1].Position = j;
Entries[i + 1].CompressedSize = Entries[i + 1].Length = flength;
Entries[i + 1].Flags = 0;
Entries[i + 1].Namespace = ns_global;
Entries[i + 1].ResourceID = -1;
Entries[i + 1].FileName = file->NormalizeFileName(fn);
Entries[i + 1].Method = METHOD_STORED;
@ -99,7 +97,7 @@ static bool OpenSSI(FResourceFile* file, int version, int EntryCount, LumpFilter
//
//==========================================================================
FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile* CheckSSI(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char zerobuf[72];
char buf[72];
@ -129,7 +127,7 @@ FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo*
{
if (!skipstring(70)) return nullptr;
}
auto ssi = new FResourceFile(filename, file, sp);
auto ssi = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::SHORTNAMES);
if (OpenSSI(ssi, version, numfiles, filter)) return ssi;
file = ssi->Destroy();
}

View file

@ -58,52 +58,22 @@ struct wadlump_t
char Name[8];
};
//==========================================================================
//
// Wad file
//
//==========================================================================
class FWadFile : public FResourceFile
{
bool IsMarker(int lump, const char *marker);
void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack=false);
void SkinHack (FileSystemMessageFunc Printf);
public:
FWadFile(const char * filename, FileReader &file, StringPool* sp);
bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf);
};
//==========================================================================
//
// FWadFile::FWadFile
//
// Initializes a WAD file
//
//==========================================================================
FWadFile::FWadFile(const char *filename, FileReader &file, StringPool* sp)
: FResourceFile(filename, file, sp)
{
}
//==========================================================================
//
// Open it
//
//==========================================================================
bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf)
static bool OpenWAD(FResourceFile* file, FileSystemFilterInfo*, FileSystemMessageFunc Printf)
{
wadinfo_t header;
uint32_t InfoTableOfs;
bool isBigEndian = false; // Little endian is assumed until proven otherwise
auto wadSize = Reader.GetLength();
auto Reader = file->GetContainerReader();
auto wadSize = Reader->GetLength();
Reader.Read(&header, sizeof(header));
NumLumps = LittleLong(header.NumLumps);
Reader->Read(&header, sizeof(header));
uint32_t NumLumps = LittleLong(header.NumLumps);
InfoTableOfs = LittleLong(header.InfoTableOfs);
// Check to see if the little endian interpretation is valid
@ -117,16 +87,16 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf)
// Check again to detect broken wads
if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize)
{
Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", FileName);
Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", file->GetFileName());
return false;
}
}
Reader.Seek(InfoTableOfs, FileReader::SeekSet);
auto fd = Reader.Read(NumLumps * sizeof(wadlump_t));
Reader->Seek(InfoTableOfs, FileReader::SeekSet);
auto fd = Reader->Read(NumLumps * sizeof(wadlump_t));
auto fileinfo = (const wadlump_t*)fd.data();
AllocateEntries(NumLumps);
auto Entries = file->AllocateEntries(NumLumps);
for(uint32_t i = 0; i < NumLumps; i++)
{
@ -143,17 +113,17 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf)
else if (ishigh > 1)
{
// This may not end up printing something proper because we do not know what encoding might have been used.
Printf(FSMessageLevel::Warning, "%s: Lump name %.8s contains invalid characters\n", FileName, fileinfo[i].Name);
Printf(FSMessageLevel::Warning, "%s: Lump name %.8s contains invalid characters\n", file->GetFileName(), fileinfo[i].Name);
n[0] = 0;
}
Entries[i].FileName = nullptr;
Entries[i].Position = isBigEndian ? BigLong(fileinfo[i].FilePos) : LittleLong(fileinfo[i].FilePos);
Entries[i].CompressedSize = Entries[i].Length = isBigEndian ? BigLong(fileinfo[i].Size) : LittleLong(fileinfo[i].Size);
Entries[i].Namespace = ns_global;
Entries[i].Flags = ishigh? RESFF_SHORTNAME | RESFF_COMPRESSED : RESFF_SHORTNAME;
Entries[i].Method = ishigh == 1? METHOD_LZSS : METHOD_STORED;
Entries[i].FileName = stringpool->Strdup(n);
Entries[i].FileName = file->NormalizeFileName(n, 0, true);
// This doesn't set up the namespace yet.
}
for (uint32_t i = 0; i < NumLumps; i++)
@ -161,250 +131,21 @@ bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf)
if (Entries[i].Method == METHOD_LZSS)
{
// compressed size is implicit.
Entries[i].CompressedSize = (i == NumLumps - 1 ? Reader.GetLength() : Entries[i + 1].Position) - Entries[i].Position;
Entries[i].CompressedSize = (i == NumLumps - 1 ? Reader->GetLength() : Entries[i + 1].Position) - Entries[i].Position;
}
}
GenerateHash(); // Do this before the lump processing below.
SetNamespace("s_start", "s_end", ns_sprites, Printf);
SetNamespace("f_start", "f_end", ns_flats, Printf, true);
SetNamespace("c_start", "c_end", ns_colormaps, Printf);
SetNamespace("a_start", "a_end", ns_acslibrary, Printf);
SetNamespace("tx_start", "tx_end", ns_newtextures, Printf);
SetNamespace("v_start", "v_end", ns_strifevoices, Printf);
SetNamespace("hi_start", "hi_end", ns_hires, Printf);
SetNamespace("vx_start", "vx_end", ns_voxels, Printf);
SkinHack(Printf);
file->GenerateHash(); // Do this before the lump processing below.
return true;
}
//==========================================================================
//
// IsMarker
//
// (from BOOM)
//
//==========================================================================
inline bool FWadFile::IsMarker(int lump, const char *marker)
{
if (Entries[lump].FileName[0] == marker[0])
{
return (!strcmp(Entries[lump].FileName, marker) ||
(marker[1] == '_' && !strcmp(Entries[lump].FileName +1, marker)));
}
else return false;
}
//==========================================================================
//
// SetNameSpace
//
// Sets namespace information for the lumps. It always looks for the first
// x_START and the last x_END lump, except when loading flats. In this case
// F_START may be absent and if that is the case all lumps with a size of
// 4096 will be flagged appropriately.
//
//==========================================================================
// This class was supposed to be local in the function but GCC
// does not like that.
struct Marker
{
int markertype;
unsigned int index;
};
void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack)
{
bool warned = false;
int numstartmarkers = 0, numendmarkers = 0;
unsigned int i;
std::vector<Marker> markers;
for(i = 0; i < NumLumps; i++)
{
if (IsMarker(i, startmarker))
{
Marker m = { 0, i };
markers.push_back(m);
numstartmarkers++;
}
else if (IsMarker(i, endmarker))
{
Marker m = { 1, i };
markers.push_back(m);
numendmarkers++;
}
}
if (numstartmarkers == 0)
{
if (numendmarkers == 0) return; // no markers found
Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker);
if (flathack)
{
// We have found no F_START but one or more F_END markers.
// mark all lumps before the last F_END marker as potential flats.
unsigned int end = markers[markers.size()-1].index;
for(unsigned int ii = 0; ii < end; ii++)
{
if (Entries[ii].Length == 4096)
{
// We can't add this to the flats namespace but
// it needs to be flagged for the texture manager.
Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName, Entries[ii].FileName);
Entries[ii].Flags |= RESFF_MAYBEFLAT;
}
}
}
return;
}
i = 0;
while (i < markers.size())
{
int start, end;
if (markers[i].markertype != 0)
{
Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, endmarker, startmarker);
i++;
continue;
}
start = i++;
// skip over subsequent x_START markers
while (i < markers.size() && markers[i].markertype == 0)
{
Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, startmarker);
i++;
continue;
}
// same for x_END markers
while (i < markers.size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1))
{
Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName, endmarker);
i++;
continue;
}
// We found a starting marker but no end marker. Ignore this block.
if (i >= markers.size())
{
Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName, startmarker, endmarker);
end = NumLumps;
}
else
{
end = markers[i++].index;
}
// we found a marked block
Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName, startmarker, markers[start].index, end);
for(int j = markers[start].index + 1; j < end; j++)
{
if (Entries[j].Namespace != ns_global)
{
if (!warned)
{
Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName, j);
}
warned = true;
}
else if (space == ns_sprites && Entries[j].Length < 8)
{
// sf 26/10/99:
// ignore sprite lumps smaller than 8 bytes (the smallest possible)
// in size -- this was used by some dmadds wads
// as an 'empty' graphics resource
Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName, Entries[j].FileName, j);
}
else
{
Entries[j].Namespace = space;
}
}
}
}
//==========================================================================
//
// W_SkinHack
//
// Tests a wad file to see if it contains an S_SKIN marker. If it does,
// every lump in the wad is moved into a new namespace. Because skins are
// only supposed to replace player sprites, sounds, or faces, this should
// not be a problem. Yes, there are skins that replace more than that, but
// they are such a pain, and breaking them like this was done on purpose.
// This also renames any S_SKINxx lumps to just S_SKIN.
//
//==========================================================================
void FWadFile::SkinHack (FileSystemMessageFunc Printf)
{
// this being static is not a problem. The only relevant thing is that each skin gets a different number.
static int namespc = ns_firstskin;
bool skinned = false;
bool hasmap = false;
uint32_t i;
for (i = 0; i < NumLumps; i++)
{
auto lump = &Entries[i];
if (!strnicmp(lump->FileName, "S_SKIN", 6))
{ // Wad has at least one skin.
lump->FileName = "S_SKIN";
if (!skinned)
{
skinned = true;
uint32_t j;
for (j = 0; j < NumLumps; j++)
{
Entries[j].Namespace = namespc;
}
namespc++;
}
}
// needless to say, this check is entirely useless these days as map names can be more diverse..
if ((lump->FileName[0] == 'M' &&
lump->FileName[1] == 'A' &&
lump->FileName[2] == 'P' &&
lump->FileName[3] >= '0' && lump->FileName[3] <= '9' &&
lump->FileName[4] >= '0' && lump->FileName[4] <= '9' &&
lump->FileName[5] == '\0')
||
(lump->FileName[0] == 'E' &&
lump->FileName[1] >= '0' && lump->FileName[1] <= '9' &&
lump->FileName[2] == 'M' &&
lump->FileName[3] >= '0' && lump->FileName[3] <= '9' &&
lump->FileName[4] == '\0'))
{
hasmap = true;
}
}
if (skinned && hasmap)
{
Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName);
Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n");
}
}
//==========================================================================
//
// File open
//
//==========================================================================
FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckWad(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];
@ -415,8 +156,8 @@ FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo*
file.Seek(0, FileReader::SeekSet);
if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4))
{
auto rf = new FWadFile(filename, file, sp);
if (rf->Open(filter, Printf)) return rf;
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_FOLDERS | FResourceFile::NO_EXTENSIONS | FResourceFile::SHORTNAMES);
if (OpenWAD(rf, filter, Printf)) return rf;
file = rf->Destroy();
}

View file

@ -47,7 +47,7 @@ namespace FileSys {
//
//==========================================================================
bool OpenWHRes(FResourceFile* file, LumpFilterInfo*)
bool OpenWHRes(FResourceFile* file, FileSystemFilterInfo*)
{
uint32_t directory[1024];
@ -83,7 +83,6 @@ bool OpenWHRes(FResourceFile* file, LumpFilterInfo*)
Entries[i].Position = offset;
Entries[i].CompressedSize = Entries[i].Length = length;
Entries[i].Flags = RESFF_FULLPATH;
Entries[i].Namespace = ns_global;
Entries[i].ResourceID = -1;
Entries[i].Method = METHOD_STORED;
Entries[i].FileName = file->NormalizeFileName(synthname.c_str());
@ -99,7 +98,7 @@ bool OpenWHRes(FResourceFile* file, LumpFilterInfo*)
//
//==========================================================================
FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckWHRes(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
if (file.GetLength() >= 8192) // needs to be at least 8192 to contain one file and the directory.
{
@ -119,7 +118,7 @@ FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo
if (offset != checkpos || length == 0 || offset + length >= (size_t)size - 4096 ) return nullptr;
checkpos += (length+4095) / 4096;
}
auto rf = new FResourceFile(filename, file, sp);
auto rf = new FResourceFile(filename, file, sp, FResourceFile::NO_EXTENSIONS);
if (OpenWHRes(rf, filter)) return rf;
file = rf->Destroy();
}

View file

@ -113,7 +113,7 @@ class FZipFile : public FResourceFile
public:
FZipFile(const char* filename, FileReader& file, StringPool* sp);
bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf);
bool Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf);
FCompressedBuffer GetRawData(uint32_t entry) override;
};
@ -124,11 +124,11 @@ public:
//==========================================================================
FZipFile::FZipFile(const char * filename, FileReader &file, StringPool* sp)
: FResourceFile(filename, file, sp)
: FResourceFile(filename, file, sp, 0)
{
}
bool FZipFile::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf)
bool FZipFile::Open(FileSystemFilterInfo* filter, FileSystemMessageFunc Printf)
{
bool zip64 = false;
uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64);
@ -376,7 +376,7 @@ void FZipFile::SetEntryAddress(uint32_t entry)
//
//==========================================================================
FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *CheckZip(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
char head[4];

View file

@ -52,28 +52,6 @@ namespace FileSys {
// MACROS ------------------------------------------------------------------
#define NULL_INDEX (0xffffffff)
static void UpperCopy(char* to, const char* from)
{
int i;
for (i = 0; i < 8 && from[i]; i++)
to[i] = toupper(from[i]);
for (; i < 8; i++)
to[i] = 0;
}
//djb2
static uint32_t MakeHash(const char* str, size_t length = SIZE_MAX)
{
uint32_t hash = 5381;
uint32_t c;
while (length-- > 0 && (c = *str++)) hash = hash * 33 + (c | 32);
return hash;
}
static void md5Hash(FileReader& reader, uint8_t* digest)
{
using namespace md5;
@ -92,11 +70,9 @@ static void md5Hash(FileReader& reader, uint8_t* digest)
struct FileSystem::LumpRecord
{
FResourceFile *resfile;
LumpShortName shortName;
const char* LongName;
const char* Name;
int resindex;
int16_t rfnum; // this is not necessarily the same as resfile's index!
int16_t Namespace;
int resourceId;
int flags;
@ -109,52 +85,24 @@ struct FileSystem::LumpRecord
auto lflags = file->GetEntryFlags(fileindex);
if (!name) name = file->getName(fileindex);
if (lflags & RESFF_SHORTNAME)
if ((lflags & RESFF_EMBEDDED) || !name || !*name)
{
UpperCopy(shortName.String, name);
shortName.String[8] = 0;
LongName = "";
Namespace = file->GetEntryNamespace(fileindex);
resourceId = -1;
}
else if ((lflags & RESFF_EMBEDDED) || !name || !*name)
{
shortName.qword = 0;
LongName = "";
Namespace = ns_hidden;
Name = "";
resourceId = -1;
}
else
{
LongName = name;
Name = name;
resourceId = file->GetEntryResourceID(fileindex);
// Map some directories to WAD namespaces.
// Note that some of these namespaces don't exist in WADS.
// CheckNumForName will handle any request for these namespaces accordingly.
Namespace = !strncmp(LongName, "flats/", 6) ? ns_flats :
!strncmp(LongName, "textures/", 9) ? ns_newtextures :
!strncmp(LongName, "hires/", 6) ? ns_hires :
!strncmp(LongName, "sprites/", 8) ? ns_sprites :
!strncmp(LongName, "voxels/", 7) ? ns_voxels :
!strncmp(LongName, "colormaps/", 10) ? ns_colormaps :
!strncmp(LongName, "acs/", 4) ? ns_acslibrary :
!strncmp(LongName, "voices/", 7) ? ns_strifevoices :
!strncmp(LongName, "patches/", 8) ? ns_patches :
!strncmp(LongName, "graphics/", 9) ? ns_graphics :
!strncmp(LongName, "sounds/", 7) ? ns_sounds :
!strncmp(LongName, "music/", 6) ? ns_music :
!strchr(LongName, '/') ? ns_global :
ns_hidden;
if (Namespace == ns_hidden) shortName.qword = 0;
else if (strstr(LongName, ".{"))
// allow embedding a resource ID in the name - we need to strip that out here.
if (strstr(Name, ".{"))
{
std::string longName = LongName;
std::string longName = Name;
ptrdiff_t encodedResID = longName.find_last_of(".{");
if (resourceId == -1 && (size_t)encodedResID != std::string::npos)
{
const char* p = LongName + encodedResID;
const char* p = Name + encodedResID;
char* q;
int id = (int)strtoull(p + 2, &q, 10); // only decimal numbers allowed here.
if (q[0] == '}' && (q[1] == '.' || q[1] == 0))
@ -162,27 +110,13 @@ struct FileSystem::LumpRecord
longName.erase(longName.begin() + encodedResID, longName.begin() + (q - p) + 1);
resourceId = id;
}
LongName = sp->Strdup(longName.c_str());
Name = sp->Strdup(longName.c_str());
}
}
auto slash = strrchr(LongName, '/');
std::string base = slash ? (slash + 1) : LongName;
auto slash = strrchr(Name, '/');
std::string base = slash ? (slash + 1) : Name;
auto dot = base.find_last_of('.');
if (dot != std::string::npos) base.resize(dot);
UpperCopy(shortName.String, base.c_str());
// Since '\' can't be used as a file name's part inside a ZIP
// we have to work around this for sprites because it is a valid
// frame character.
if (Namespace == ns_sprites || Namespace == ns_voxels || Namespace == ns_hires)
{
char* c;
while ((c = (char*)memchr(shortName.String, '^', 8)))
{
*c = '\\';
}
}
}
}
};
@ -223,22 +157,16 @@ void FileSystem::DeleteAll ()
//==========================================================================
//
// InitMultipleFiles
// Initialize
//
// Pass a null terminated list of files to use. All files are optional,
// Pass a vector of files to use. All files are optional,
// but at least one file must be found. File names can appear multiple
// times. The name searcher looks backwards, so a later file can
// override an earlier one.
//
//==========================================================================
bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Printf)
{
std::vector<std::string> filenames = { filename };
return InitMultipleFiles(filenames, nullptr, Printf);
}
bool FileSystem::InitMultipleFiles (std::vector<std::string>& filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates)
bool FileSystem::InitFiles(std::vector<std::string>& filenames, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates)
{
int numfiles;
@ -254,9 +182,9 @@ bool FileSystem::InitMultipleFiles (std::vector<std::string>& filenames, LumpFil
// first, check for duplicates
if (!allowduplicates)
{
for (size_t i=0;i<filenames.size(); i++)
for (size_t i = 0; i < filenames.size(); i++)
{
for (size_t j=i+1;j<filenames.size(); j++)
for (size_t j = i + 1; j < filenames.size(); j++)
{
if (filenames[i] == filenames[j])
{
@ -267,7 +195,7 @@ bool FileSystem::InitMultipleFiles (std::vector<std::string>& filenames, LumpFil
}
}
for(size_t i=0;i<filenames.size(); i++)
for (size_t i = 0; i < filenames.size(); i++)
{
AddFile(filenames[i].c_str(), nullptr, filter, Printf);
@ -282,6 +210,12 @@ bool FileSystem::InitMultipleFiles (std::vector<std::string>& filenames, LumpFil
{
return false;
}
return true;
}
bool FileSystem::Initialize(std::vector<std::string>& filenames, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates)
{
if (!InitFiles(filenames, filter, Printf, allowduplicates)) return false;
if (filter && filter->postprocessFunc) filter->postprocessFunc();
// [RH] Set up hash table
@ -304,7 +238,7 @@ int FileSystem::AddFromBuffer(const char* name, char* data, int size, int id, in
fr.OpenMemoryArray(blob);
// wrap this into a single lump resource file (should be done a little better later.)
auto rf = new FResourceFile(name, fr, stringpool);
auto rf = new FResourceFile(name, fr, stringpool, 0);
auto Entries = rf->AllocateEntries(1);
Entries[0].FileName = rf->NormalizeFileName(ExtractBaseName(name, true).c_str());
Entries[0].ResourceID = -1;
@ -327,7 +261,7 @@ int FileSystem::AddFromBuffer(const char* name, char* data, int size, int id, in
// [RH] Removed reload hack
//==========================================================================
void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInfo* filter, FileSystemMessageFunc Printf)
void FileSystem::AddFile (const char *filename, FileReader *filer, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf)
{
int startlump;
bool isdir = false;
@ -443,114 +377,6 @@ int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept
return -1;
}
//==========================================================================
//
// CheckNumForName
//
// Returns -1 if name not found. The version with a third parameter will
// look exclusively in the specified wad for the lump.
//
// [RH] Changed to use hash lookup ala BOOM instead of a linear search
// and namespace parameter
//==========================================================================
int FileSystem::CheckNumForName (const char *name, int space) const
{
union
{
char uname[8];
uint64_t qname;
};
uint32_t i;
if (name == NULL)
{
return -1;
}
// Let's not search for names that are longer than 8 characters and contain path separators
// They are almost certainly full path names passed to this function.
if (strlen(name) > 8 && strpbrk(name, "/."))
{
return -1;
}
UpperCopy (uname, name);
i = FirstLumpIndex[MakeHash(uname, 8) % NumEntries];
while (i != NULL_INDEX)
{
if (FileInfo[i].shortName.qword == qname)
{
auto &lump = FileInfo[i];
if (lump.Namespace == space) break;
// If the lump is from one of the special namespaces exclusive to Zips
// the check has to be done differently:
// If we find a lump with this name in the global namespace that does not come
// from a Zip return that. WADs don't know these namespaces and single lumps must
// work as well.
auto lflags = lump.resfile->GetEntryFlags(lump.resindex);
if (space > ns_specialzipdirectory && lump.Namespace == ns_global &&
!((lflags ^lump.flags) & RESFF_FULLPATH)) break;
}
i = NextLumpIndex[i];
}
return i != NULL_INDEX ? i : -1;
}
int FileSystem::CheckNumForName (const char *name, int space, int rfnum, bool exact) const
{
union
{
char uname[8];
uint64_t qname;
};
uint32_t i;
if (rfnum < 0)
{
return CheckNumForName (name, space);
}
UpperCopy (uname, name);
i = FirstLumpIndex[MakeHash (uname, 8) % NumEntries];
// If exact is true if will only find lumps in the same WAD, otherwise
// also those in earlier WADs.
while (i != NULL_INDEX &&
(FileInfo[i].shortName.qword != qname || FileInfo[i].Namespace != space ||
(exact? (FileInfo[i].rfnum != rfnum) : (FileInfo[i].rfnum > rfnum)) ))
{
i = NextLumpIndex[i];
}
return i != NULL_INDEX ? i : -1;
}
//==========================================================================
//
// GetNumForName
//
// Calls CheckNumForName, but bombs out if not found.
//
//==========================================================================
int FileSystem::GetNumForName (const char *name, int space) const
{
int i;
i = CheckNumForName (name, space);
if (i == -1)
throw FileSystemException("GetNumForName: %s not found!", name);
return i;
}
//==========================================================================
//
// CheckNumForFullName
@ -561,7 +387,7 @@ int FileSystem::GetNumForName (const char *name, int space) const
//
//==========================================================================
int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int namespc, bool ignoreext) const
int FileSystem::CheckNumForFullName (const char *name, bool ignoreext) const
{
uint32_t i;
@ -576,21 +402,16 @@ int FileSystem::CheckNumForFullName (const char *name, bool trynormal, int names
for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i])
{
if (strnicmp(name, FileInfo[i].LongName, len)) continue;
if (FileInfo[i].LongName[len] == 0) break; // this is a full match
if (ignoreext && FileInfo[i].LongName[len] == '.')
if (strnicmp(name, FileInfo[i].Name, len)) continue;
if (FileInfo[i].Name[len] == 0) break; // this is a full match
if (ignoreext && FileInfo[i].Name[len] == '.')
{
// is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension?
if (strpbrk(FileInfo[i].LongName + len + 1, "./") == nullptr) break;
if (strpbrk(FileInfo[i].Name + len + 1, "./") == nullptr) break;
}
}
if (i != NULL_INDEX) return i;
if (trynormal && strlen(name) <= 8 && !strpbrk(name, "./"))
{
return CheckNumForName(name, namespc);
}
return -1;
}
@ -606,7 +427,7 @@ int FileSystem::CheckNumForFullNameInFile (const char *name, int rfnum) const
i = FirstLumpIndex_FullName[MakeHash (name) % NumEntries];
while (i != NULL_INDEX &&
(stricmp(name, FileInfo[i].LongName) || FileInfo[i].rfnum != rfnum))
(stricmp(name, FileInfo[i].Name) || FileInfo[i].rfnum != rfnum))
{
i = NextLumpIndex_FullName[i];
}
@ -657,10 +478,10 @@ int FileSystem::FindFileWithExtensions(const char* name, const char *const *exts
for (i = fli[MakeHash(name) % NumEntries]; i != NULL_INDEX; i = nli[i])
{
if (strnicmp(name, FileInfo[i].LongName, len)) continue;
if (FileInfo[i].LongName[len] != '.') continue; // we are looking for extensions but this file doesn't have one.
if (strnicmp(name, FileInfo[i].Name, len)) continue;
if (FileInfo[i].Name[len] != '.') continue; // we are looking for extensions but this file doesn't have one.
auto cp = FileInfo[i].LongName + len + 1;
auto cp = FileInfo[i].Name + len + 1;
// is this the last '.' in the last path element, indicating that the remaining part of the name is only an extension?
if (strpbrk(cp, "./") != nullptr) continue; // No, so it cannot be a valid entry.
@ -696,7 +517,7 @@ int FileSystem::FindResource (int resid, const char *type, int filenum) const no
{
if (filenum > 0 && FileInfo[i].rfnum != filenum) continue;
if (FileInfo[i].resourceId != resid) continue;
auto extp = strrchr(FileInfo[i].LongName, '.');
auto extp = strrchr(FileInfo[i].Name, '.');
if (!extp) continue;
if (!stricmp(extp + 1, type)) return i;
}
@ -773,34 +594,28 @@ void FileSystem::InitHashChains (void)
unsigned int i, j;
NumEntries = (uint32_t)FileInfo.size();
Hashes.resize(8 * NumEntries);
Hashes.resize(6 * NumEntries);
// Mark all buckets as empty
memset(Hashes.data(), -1, Hashes.size() * sizeof(Hashes[0]));
FirstLumpIndex = &Hashes[0];
NextLumpIndex = &Hashes[NumEntries];
FirstLumpIndex_FullName = &Hashes[NumEntries * 2];
NextLumpIndex_FullName = &Hashes[NumEntries * 3];
FirstLumpIndex_NoExt = &Hashes[NumEntries * 4];
NextLumpIndex_NoExt = &Hashes[NumEntries * 5];
FirstLumpIndex_ResId = &Hashes[NumEntries * 6];
NextLumpIndex_ResId = &Hashes[NumEntries * 7];
FirstLumpIndex_FullName = &Hashes[NumEntries * 0];
NextLumpIndex_FullName = &Hashes[NumEntries * 1];
FirstLumpIndex_NoExt = &Hashes[NumEntries * 2];
NextLumpIndex_NoExt = &Hashes[NumEntries * 3];
FirstLumpIndex_ResId = &Hashes[NumEntries * 4];
NextLumpIndex_ResId = &Hashes[NumEntries * 5];
// Now set up the chains
for (i = 0; i < (unsigned)NumEntries; i++)
{
j = MakeHash (FileInfo[i].shortName.String, 8) % NumEntries;
NextLumpIndex[i] = FirstLumpIndex[j];
FirstLumpIndex[j] = i;
// Do the same for the full paths
if (FileInfo[i].LongName[0] != 0)
if (FileInfo[i].Name[0] != 0)
{
j = MakeHash(FileInfo[i].LongName) % NumEntries;
j = MakeHash(FileInfo[i].Name) % NumEntries;
NextLumpIndex_FullName[i] = FirstLumpIndex_FullName[j];
FirstLumpIndex_FullName[j] = i;
std::string nameNoExt = FileInfo[i].LongName;
std::string nameNoExt = FileInfo[i].Name;
auto dot = nameNoExt.find_last_of('.');
auto slash = nameNoExt.find_last_of('/');
if ((dot > slash || slash == std::string::npos) && dot != std::string::npos) nameNoExt.resize(dot);
@ -819,24 +634,10 @@ void FileSystem::InitHashChains (void)
Files.shrink_to_fit();
}
//==========================================================================
//
// should only be called before the hash chains are set up.
// If done later this needs rehashing.
//
//==========================================================================
LumpShortName& FileSystem::GetShortName(int i)
{
if ((unsigned)i >= NumEntries) throw FileSystemException("GetShortName: Invalid index");
return FileInfo[i].shortName;
}
void FileSystem::RenameFile(int num, const char* newfn)
{
if ((unsigned)num >= NumEntries) throw FileSystemException("RenameFile: Invalid index");
FileInfo[num].LongName = stringpool->Strdup(newfn);
// This does not alter the short name - call GetShortname to do that!
FileInfo[num].Name = stringpool->Strdup(newfn);
}
//==========================================================================
@ -867,14 +668,13 @@ void FileSystem::MoveLumpsInFolder(const char *path)
{
auto& li = FileInfo[i];
if (li.rfnum >= GetIwadNum()) break;
if (strnicmp(li.LongName, path, len) == 0)
if (strnicmp(li.Name, path, len) == 0)
{
auto lic = li; // make a copy before pushing.
FileInfo.push_back(lic);
li.LongName = ""; //nuke the name of the old record.
li.shortName.qword = 0;
li.Name = ""; //nuke the name of the old record.
auto &ln = FileInfo.back();
ln.SetFromLump(li.resfile, li.resindex, rfnum, stringpool, ln.LongName + len);
ln.SetFromLump(li.resfile, li.resindex, rfnum, stringpool, ln.Name + len);
}
}
}
@ -888,87 +688,6 @@ void FileSystem::MoveLumpsInFolder(const char *path)
//
//==========================================================================
int FileSystem::FindLump (const char *name, int *lastlump, bool anyns)
{
if ((size_t)*lastlump >= FileInfo.size()) return -1;
union
{
char name8[8];
uint64_t qname;
};
UpperCopy (name8, name);
assert(lastlump != NULL && *lastlump >= 0);
const LumpRecord * last = FileInfo.data() + FileInfo.size();
LumpRecord * lump_p = FileInfo.data() + *lastlump;
while (lump_p < last)
{
if ((anyns || lump_p->Namespace == ns_global) && lump_p->shortName.qword == qname)
{
int lump = int(lump_p - FileInfo.data());
*lastlump = lump + 1;
return lump;
}
lump_p++;
}
*lastlump = NumEntries;
return -1;
}
//==========================================================================
//
// W_FindLumpMulti
//
// Find a named lump. Specifically allows duplicates for merging of e.g.
// SNDINFO lumps. Returns everything having one of the passed names.
//
//==========================================================================
int FileSystem::FindLumpMulti (const char **names, int *lastlump, bool anyns, int *nameindex)
{
assert(lastlump != NULL && *lastlump >= 0);
const LumpRecord * last = FileInfo.data() + FileInfo.size();
LumpRecord * lump_p = FileInfo.data() + *lastlump;
while (lump_p < last)
{
if (anyns || lump_p->Namespace == ns_global)
{
for(const char **name = names; *name != NULL; name++)
{
if (!strnicmp(*name, lump_p->shortName.String, 8))
{
int lump = int(lump_p - FileInfo.data());
*lastlump = lump + 1;
if (nameindex != NULL) *nameindex = int(name - names);
return lump;
}
}
}
lump_p++;
}
*lastlump = NumEntries;
return -1;
}
//==========================================================================
//
// W_FindLump
//
// Find a named lump. Specifically allows duplicates for merging of e.g.
// SNDINFO lumps.
//
//==========================================================================
int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext)
{
assert(lastlump != NULL && *lastlump >= 0);
@ -981,7 +700,7 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext)
{
while (lump_p < last)
{
if (!stricmp(name, lump_p->LongName))
if (!stricmp(name, lump_p->Name))
{
int lump = int(lump_p - FileInfo.data());
*lastlump = lump + 1;
@ -995,10 +714,10 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext)
auto len = strlen(name);
while (lump_p <= &FileInfo.back())
{
auto res = strnicmp(name, lump_p->LongName, len);
auto res = strnicmp(name, lump_p->Name, len);
if (res == 0)
{
auto p = lump_p->LongName + len;
auto p = lump_p->Name + len;
if (*p == 0 || (*p == '.' && strpbrk(p + 1, "./") == 0))
{
int lump = int(lump_p - FileInfo.data());
@ -1017,49 +736,17 @@ int FileSystem::FindLumpFullName(const char* name, int* lastlump, bool noext)
//==========================================================================
//
// W_CheckLumpName
// FileSystem :: GetFileName
//
// Returns the lump's internal name
//
//==========================================================================
bool FileSystem::CheckFileName (int lump, const char *name)
{
if ((size_t)lump >= NumEntries)
return false;
return !strnicmp (FileInfo[lump].shortName.String, name, 8);
}
//==========================================================================
//
// GetLumpName
//
//==========================================================================
const char* FileSystem::GetFileShortName(int lump) const
{
if ((size_t)lump >= NumEntries)
return nullptr;
else
return FileInfo[lump].shortName.String;
}
//==========================================================================
//
// FileSystem :: GetFileFullName
//
// Returns the lump's full name if it has one or its short name if not.
//
//==========================================================================
const char *FileSystem::GetFileName (int lump, bool returnshort) const
const char* FileSystem::GetFileName(int lump) const
{
if ((size_t)lump >= NumEntries)
return NULL;
else if (FileInfo[lump].LongName[0] != 0)
return FileInfo[lump].LongName;
else if (returnshort)
return FileInfo[lump].shortName.String;
else return nullptr;
else return FileInfo[lump].Name;
}
//==========================================================================
@ -1083,25 +770,6 @@ std::string FileSystem::GetFileFullPath(int lump) const
return foo;
}
//==========================================================================
//
// GetFileNamespace
//
//==========================================================================
int FileSystem::GetFileNamespace (int lump) const
{
if ((size_t)lump >= NumEntries)
return ns_global;
else
return FileInfo[lump].Namespace;
}
void FileSystem::SetFileNamespace(int lump, int ns)
{
if ((size_t)lump < NumEntries) FileInfo[lump].Namespace = ns;
}
//==========================================================================
//
// FileSystem :: GetResourceId
@ -1134,7 +802,7 @@ const char *FileSystem::GetResourceType(int lump) const
return nullptr;
else
{
auto p = strrchr(FileInfo[lump].LongName, '.');
auto p = strrchr(FileInfo[lump].Name, '.');
if (!p) return ""; // has no extension
if (strchr(p, '/')) return ""; // the '.' is part of a directory.
return p + 1;
@ -1186,12 +854,12 @@ unsigned FileSystem::GetFilesInFolder(const char *inpath, std::vector<FolderEntr
result.clear();
for (size_t i = 0; i < FileInfo.size(); i++)
{
if (strncmp(FileInfo[i].LongName, path.c_str(), path.length()) == 0)
if (strncmp(FileInfo[i].Name, path.c_str(), path.length()) == 0)
{
// Only if it hasn't been replaced.
if ((unsigned)CheckNumForFullName(FileInfo[i].LongName) == i)
if ((unsigned)CheckNumForFullName(FileInfo[i].Name) == i)
{
FolderEntry fe{ FileInfo[i].LongName, (uint32_t)i };
FolderEntry fe{ FileInfo[i].Name, (uint32_t)i };
result.push_back(fe);
}
}
@ -1235,7 +903,7 @@ void FileSystem::ReadFile (int lump, void *dest)
if (numread != size)
{
throw FileSystemException("W_ReadFile: only read %td of %td on '%s'\n",
numread, size, FileInfo[lump].LongName);
numread, size, FileInfo[lump].Name);
}
}
@ -1354,6 +1022,21 @@ int FileSystem::GetFirstEntry (int rfnum) const noexcept
//
//==========================================================================
int FileSystem::GetResourceFileFlags(int rfnum) const noexcept
{
if ((uint32_t)rfnum >= Files.size())
{
return 0;
}
return Files[rfnum]->GetFlags();
}
//==========================================================================
//
//
//==========================================================================
int FileSystem::GetLastEntry (int rfnum) const noexcept
{
if ((uint32_t)rfnum >= Files.size())
@ -1415,7 +1098,7 @@ bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/)
if (lump < 0) return false; // Does not exist.
auto oldlump = FileInfo[lump];
auto slash = strrchr(oldlump.LongName, '/');
auto slash = strrchr(oldlump.Name, '/');
if (slash == nullptr)
{
@ -1425,7 +1108,7 @@ bool FileSystem::CreatePathlessCopy(const char *name, int id, int /*flags*/)
// just create a new reference to the original data with a different name.
oldlump.LongName = slash + 1;
oldlump.Name = slash + 1;
oldlump.resourceId = id;
oldlump.flags = RESFF_FULLPATH;
FileInfo.push_back(oldlump);

View file

@ -113,7 +113,7 @@ bool FResourceFile::IsFileInFolder(const char* const resPath)
return 0 == stricmp(filePath.c_str(), resPath);
}
void FResourceFile::CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi)
void FResourceFile::CheckEmbedded(uint32_t entry, FileSystemFilterInfo* lfi)
{
// Checks for embedded archives
auto FullName = Entries[entry].FileName;
@ -138,29 +138,30 @@ void FResourceFile::CheckEmbedded(uint32_t entry, LumpFilterInfo* lfi)
//
//==========================================================================
typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckHog(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckMvl(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckWHRes(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckLump(const char *filename,FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckDir(const char *filename, bool nosub, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckWad(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckGRP(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckRFF(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckPak(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckZip(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *Check7Z(const char *filename, FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckSSI(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckHog(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckHog2(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckMvl(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile* CheckWHRes(const char* filename, FileReader& file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckLump(const char *filename,FileReader &file, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
FResourceFile *CheckDir(const char *filename, bool nosub, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp);
static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckSSI, CheckHog, CheckMvl, CheckWHRes, CheckLump };
static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckHog, CheckMvl, CheckHog2, CheckSSI, CheckWHRes, CheckLump };
static int nulPrintf(FSMessageLevel msg, const char* fmt, ...)
{
return 0;
}
FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
if (!file.isOpen()) return nullptr;
if (Printf == nullptr) Printf = nulPrintf;
@ -173,20 +174,20 @@ FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReade
return NULL;
}
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp);
}
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
FileReader file;
if (!file.OpenFile(filename)) return nullptr;
return DoOpenResourceFile(filename, file, containeronly, filter, Printf, sp);
}
FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
FResourceFile *FResourceFile::OpenDirectory(const char *filename, FileSystemFilterInfo* filter, FileSystemMessageFunc Printf, StringPool* sp)
{
if (Printf == nullptr) Printf = nulPrintf;
return CheckDir(filename, false, filter, Printf, sp);
@ -198,14 +199,15 @@ FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo
//
//==========================================================================
FResourceFile::FResourceFile(const char *filename, StringPool* sp)
FResourceFile::FResourceFile(const char *filename, StringPool* sp, int flags_)
:flags(flags_)
{
stringpool = sp ? sp : new StringPool(false);
FileName = stringpool->Strdup(filename);
}
FResourceFile::FResourceFile(const char *filename, FileReader &r, StringPool* sp)
: FResourceFile(filename,sp)
FResourceFile::FResourceFile(const char *filename, FileReader &r, StringPool* sp, int flags)
: FResourceFile(filename,sp, flags)
{
Reader = std::move(r);
}
@ -250,7 +252,7 @@ FCompressedBuffer FResourceFile::GetRawData(uint32_t entry)
//
//==========================================================================
const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp)
const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp, bool allowbackslash)
{
if (!fn || !*fn) return "";
auto norm = tolower_normalize(fn);
@ -274,7 +276,8 @@ const char* FResourceFile::NormalizeFileName(const char* fn, int fallbackcp)
norm = tolower_normalize(&ffn.front());
}
}
FixPathSeparator(norm);
// The WAD format can have legal backslashes in its names so this must be optional.
if (!allowbackslash) FixPathSeparator(norm);
auto pooled = stringpool->Strdup(norm);
free(norm);
return pooled;
@ -354,7 +357,7 @@ void FResourceFile::GenerateHash()
//
//==========================================================================
void FResourceFile::PostProcessArchive(LumpFilterInfo *filter)
void FResourceFile::PostProcessArchive(FileSystemFilterInfo *filter)
{
// only do this for archive types which contain full file names. All others are assumed to be pre-sorted.
if (NumLumps == 0 || !(Entries[0].Flags & RESFF_FULLPATH)) return;
@ -416,7 +419,7 @@ void FResourceFile::PostProcessArchive(LumpFilterInfo *filter)
//
//==========================================================================
void FResourceFile::FindCommonFolder(LumpFilterInfo* filter)
void FResourceFile::FindCommonFolder(FileSystemFilterInfo* filter)
{
std::string name0, name1;
bool foundspeciallump = false;

View file

@ -50,7 +50,6 @@
#include "basics.h"
#include "cmdlib.h"
using namespace FileSys;
FTextureManager TexMan;
@ -585,7 +584,7 @@ void FTextureManager::AddGroup(int wadnum, int ns, ETextureType usetype)
}
progressFunc();
}
else if (ns == ns_flats && fileSystem.GetFileFlags(firsttx) & RESFF_MAYBEFLAT)
else if (ns == ns_flats && fileSystem.GetFileNamespace(firsttx) == ns_maybeflat)
{
if (fileSystem.CheckNumForName(Name, ns) < firsttx)
{
@ -1421,12 +1420,11 @@ int FTextureManager::GuesstimateNumTextures ()
case ns_hires:
case ns_patches:
case ns_graphics:
case ns_maybeflat:
numtex++;
break;
default:
if (fileSystem.GetFileFlags(i) & RESFF_MAYBEFLAT) numtex++;
break;
}
}

View file

@ -314,7 +314,7 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize,
// Look for IWAD definition lump
//
//==========================================================================
void GetReserved(FileSys::LumpFilterInfo& lfi);
void GetReserved(FileSys::FileSystemFilterInfo& lfi);
FIWadManager::FIWadManager(const char *firstfn, const char *optfn)
{
@ -322,10 +322,10 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn)
std::vector<std::string> fns;
fns.push_back(firstfn);
if (optfn) fns.push_back(optfn);
FileSys::LumpFilterInfo lfi;
FileSys::FileSystemFilterInfo lfi;
GetReserved(lfi);
if (check.InitMultipleFiles(fns, &lfi, nullptr))
if (check.Initialize(fns, &lfi, nullptr))
{
// this is for the IWAD picker. As we have a filesystem open here that contains the base files, it is the easiest place to load the strings early.
GStrings.LoadStrings(check, language);
@ -350,7 +350,8 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn)
int FIWadManager::ScanIWAD (const char *iwad)
{
FileSystem check;
check.InitSingleFile(iwad, nullptr);
std::vector<std::string> list({ iwad });
check.Initialize(list, nullptr);
mLumpsFound.Resize(mIWadInfos.Size());
@ -373,14 +374,13 @@ int FIWadManager::ScanIWAD (const char *iwad)
memset(&mLumpsFound[0], 0, mLumpsFound.Size() * sizeof(mLumpsFound[0]));
for(int ii = 0; ii < check.GetNumEntries(); ii++)
{
CheckFileName(check.GetFileShortName(ii));
auto full = check.GetFileName(ii, false);
auto full = check.GetFileName(ii);
if (full && strnicmp(full, "maps/", 5) == 0)
{
FString mapname(&full[5], strcspn(&full[5], "."));
CheckFileName(mapname.GetChars());
}
else CheckFileName(full);
}
}
for (unsigned i = 0; i< mIWadInfos.Size(); i++)
@ -404,11 +404,11 @@ int FIWadManager::CheckIWADInfo(const char* fn)
{
FileSystem check;
FileSys::LumpFilterInfo lfi;
FileSys::FileSystemFilterInfo lfi;
GetReserved(lfi);
std::vector<std::string> filenames = { fn };
if (check.InitMultipleFiles(filenames, &lfi, nullptr))
if (check.Initialize(filenames, &lfi, nullptr))
{
int num = check.CheckNumForName("IWADINFO");
if (num >= 0)

View file

@ -123,8 +123,6 @@
#include "i_system.h" // for SHARE_DIR
#endif // __unix__
using namespace FileSys;
EXTERN_CVAR(Bool, hud_althud)
EXTERN_CVAR(Int, vr_mode)
EXTERN_CVAR(Bool, cl_customizeinvulmap)
@ -1265,7 +1263,7 @@ void D_DoomLoop ()
}
D_ErrorCleanup ();
}
catch (const FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error.
catch (const FileSys::FileSystemException& error) // in case this propagates up to here it should be treated as a recoverable error.
{
if (error.what())
{
@ -1945,7 +1943,7 @@ static FString ParseGameInfo(std::vector<std::string> &pwads, const char *fn, co
return iwad;
}
void GetReserved(LumpFilterInfo& lfi)
void GetReserved(FileSys::FileSystemFilterInfo& lfi)
{
lfi.reservedFolders = { "flats/", "textures/", "hires/", "sprites/", "voxels/", "colormaps/", "acs/", "maps/", "voices/", "patches/", "graphics/", "sounds/", "music/",
"materials/", "models/", "fonts/", "brightmaps/" };
@ -1957,11 +1955,11 @@ static FString CheckGameInfo(std::vector<std::string> & pwads)
{
FileSystem check;
LumpFilterInfo lfi;
FileSys::FileSystemFilterInfo lfi;
GetReserved(lfi);
// Open the entire list as a temporary file system and look for a GAMEINFO lump. The last one will automatically win.
if (check.InitMultipleFiles(pwads, &lfi, nullptr))
if (check.Initialize(pwads, &lfi, nullptr))
{
int num = check.CheckNumForName("GAMEINFO");
if (num >= 0)
@ -2250,48 +2248,48 @@ static void RenameSprites(FileSystem &fileSystem, const TArray<FString>& deletel
bool MNTRZfound = false;
const char* altbigfont = gameinfo.gametype == GAME_Strife ? "SBIGFONT" : (gameinfo.gametype & GAME_Raven) ? "HBIGFONT" : "DBIGFONT";
static const uint32_t HereticRenames[] =
{ MAKE_ID('H','E','A','D'), MAKE_ID('L','I','C','H'), // Ironlich
static const char HereticRenames[][4] =
{ {'H','E','A','D'}, {'L','I','C','H'}, // Ironlich
};
static const uint32_t HexenRenames[] =
{ MAKE_ID('B','A','R','L'), MAKE_ID('Z','B','A','R'), // ZBarrel
MAKE_ID('A','R','M','1'), MAKE_ID('A','R','_','1'), // MeshArmor
MAKE_ID('A','R','M','2'), MAKE_ID('A','R','_','2'), // FalconShield
MAKE_ID('A','R','M','3'), MAKE_ID('A','R','_','3'), // PlatinumHelm
MAKE_ID('A','R','M','4'), MAKE_ID('A','R','_','4'), // AmuletOfWarding
MAKE_ID('S','U','I','T'), MAKE_ID('Z','S','U','I'), // ZSuitOfArmor and ZArmorChunk
MAKE_ID('T','R','E','1'), MAKE_ID('Z','T','R','E'), // ZTree and ZTreeDead
MAKE_ID('T','R','E','2'), MAKE_ID('T','R','E','S'), // ZTreeSwamp150
MAKE_ID('C','A','N','D'), MAKE_ID('B','C','A','N'), // ZBlueCandle
MAKE_ID('R','O','C','K'), MAKE_ID('R','O','K','K'), // rocks and dirt in a_debris.cpp
MAKE_ID('W','A','T','R'), MAKE_ID('H','W','A','T'), // Strife also has WATR
MAKE_ID('G','I','B','S'), MAKE_ID('P','O','L','5'), // RealGibs
MAKE_ID('E','G','G','M'), MAKE_ID('P','R','K','M'), // PorkFX
MAKE_ID('I','N','V','U'), MAKE_ID('D','E','F','N'), // Icon of the Defender
static const char HexenRenames[][4] =
{ {'B','A','R','L'}, {'Z','B','A','R'}, // ZBarrel
{'A','R','M','1'}, {'A','R','_','1'}, // MeshArmor
{'A','R','M','2'}, {'A','R','_','2'}, // FalconShield
{'A','R','M','3'}, {'A','R','_','3'}, // PlatinumHelm
{'A','R','M','4'}, {'A','R','_','4'}, // AmuletOfWarding
{'S','U','I','T'}, {'Z','S','U','I'}, // ZSuitOfArmor and ZArmorChunk
{'T','R','E','1'}, {'Z','T','R','E'}, // ZTree and ZTreeDead
{'T','R','E','2'}, {'T','R','E','S'}, // ZTreeSwamp150
{'C','A','N','D'}, {'B','C','A','N'}, // ZBlueCandle
{'R','O','C','K'}, {'R','O','K','K'}, // rocks and dirt in a_debris.cpp
{'W','A','T','R'}, {'H','W','A','T'}, // Strife also has WATR
{'G','I','B','S'}, {'P','O','L','5'}, // RealGibs
{'E','G','G','M'}, {'P','R','K','M'}, // PorkFX
{'I','N','V','U'}, {'D','E','F','N'}, // Icon of the Defender
};
static const uint32_t StrifeRenames[] =
{ MAKE_ID('M','I','S','L'), MAKE_ID('S','M','I','S'), // lots of places
MAKE_ID('A','R','M','1'), MAKE_ID('A','R','M','3'), // MetalArmor
MAKE_ID('A','R','M','2'), MAKE_ID('A','R','M','4'), // LeatherArmor
MAKE_ID('P','M','A','P'), MAKE_ID('S','M','A','P'), // StrifeMap
MAKE_ID('T','L','M','P'), MAKE_ID('T','E','C','H'), // TechLampSilver and TechLampBrass
MAKE_ID('T','R','E','1'), MAKE_ID('T','R','E','T'), // TreeStub
MAKE_ID('B','A','R','1'), MAKE_ID('B','A','R','C'), // BarricadeColumn
MAKE_ID('S','H','T','2'), MAKE_ID('M','P','U','F'), // MaulerPuff
MAKE_ID('B','A','R','L'), MAKE_ID('B','B','A','R'), // StrifeBurningBarrel
MAKE_ID('T','R','C','H'), MAKE_ID('T','R','H','L'), // SmallTorchLit
MAKE_ID('S','H','R','D'), MAKE_ID('S','H','A','R'), // glass shards
MAKE_ID('B','L','S','T'), MAKE_ID('M','A','U','L'), // Mauler
MAKE_ID('L','O','G','G'), MAKE_ID('L','O','G','W'), // StickInWater
MAKE_ID('V','A','S','E'), MAKE_ID('V','A','Z','E'), // Pot and Pitcher
MAKE_ID('C','N','D','L'), MAKE_ID('K','N','D','L'), // Candle
MAKE_ID('P','O','T','1'), MAKE_ID('M','P','O','T'), // MetalPot
MAKE_ID('S','P','I','D'), MAKE_ID('S','T','L','K'), // Stalker
static const char StrifeRenames[][4] =
{ {'M','I','S','L'}, {'S','M','I','S'}, // lots of places
{'A','R','M','1'}, {'A','R','M','3'}, // MetalArmor
{'A','R','M','2'}, {'A','R','M','4'}, // LeatherArmor
{'P','M','A','P'}, {'S','M','A','P'}, // StrifeMap
{'T','L','M','P'}, {'T','E','C','H'}, // TechLampSilver and TechLampBrass
{'T','R','E','1'}, {'T','R','E','T'}, // TreeStub
{'B','A','R','1'}, {'B','A','R','C'}, // BarricadeColumn
{'S','H','T','2'}, {'M','P','U','F'}, // MaulerPuff
{'B','A','R','L'}, {'B','B','A','R'}, // StrifeBurningBarrel
{'T','R','C','H'}, {'T','R','H','L'}, // SmallTorchLit
{'S','H','R','D'}, {'S','H','A','R'}, // glass shards
{'B','L','S','T'}, {'M','A','U','L'}, // Mauler
{'L','O','G','G'}, {'L','O','G','W'}, // StickInWater
{'V','A','S','E'}, {'V','A','Z','E'}, // Pot and Pitcher
{'C','N','D','L'}, {'K','N','D','L'}, // Candle
{'P','O','T','1'}, {'M','P','O','T'}, // MetalPot
{'S','P','I','D'}, {'S','T','L','K'}, // Stalker
};
const uint32_t* renames;
const char (*renames)[4];
int numrenames;
switch (gameinfo.gametype)
@ -2327,8 +2325,8 @@ static void RenameSprites(FileSystem &fileSystem, const TArray<FString>& deletel
// some frames need to be renamed.
if (fileSystem.GetFileNamespace(i) == ns_sprites)
{
auto& shortName = fileSystem.GetShortName(i);
if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R') && shortName.String[4] == 'Z')
auto shortName = fileSystem.GetShortName(i);
if (!memcmp(shortName, "MNTRZ", 5))
{
MNTRZfound = true;
break;
@ -2340,7 +2338,7 @@ static void RenameSprites(FileSystem &fileSystem, const TArray<FString>& deletel
for (uint32_t i = 0; i < NumFiles; i++)
{
auto& shortName = fileSystem.GetShortName(i);
auto shortName = fileSystem.GetShortName(i);
if (fileSystem.GetFileNamespace(i) == ns_sprites)
{
// Only sprites in the IWAD normally get renamed
@ -2348,30 +2346,30 @@ static void RenameSprites(FileSystem &fileSystem, const TArray<FString>& deletel
{
for (int j = 0; j < numrenames; ++j)
{
if (shortName.dword == renames[j * 2])
if (!memcmp(shortName, &renames[j * 8], 4))
{
shortName.dword = renames[j * 2 + 1];
memcpy(shortName, renames[j * 8 + 4], 4);
}
}
if (gameinfo.gametype == GAME_Hexen)
{
if (fileSystem.CheckFileName(i, "ARTIINVU"))
{
shortName.String[4] = 'D'; shortName.String[5] = 'E';
shortName.String[6] = 'F'; shortName.String[7] = 'N';
shortName[4] = 'D'; shortName[5] = 'E';
shortName[6] = 'F'; shortName[7] = 'N';
}
}
}
if (!MNTRZfound)
{
if (shortName.dword == MAKE_ID('M', 'N', 'T', 'R'))
if (!memcmp(shortName, "MNTR", 4))
{
for (size_t fi : {4, 6})
{
if (shortName.String[fi] >= 'F' && shortName.String[fi] <= 'K')
if (shortName[fi] >= 'F' && shortName[fi] <= 'K')
{
shortName.String[fi] += 'U' - 'F';
shortName[fi] += 'U' - 'F';
}
}
}
@ -2381,23 +2379,23 @@ static void RenameSprites(FileSystem &fileSystem, const TArray<FString>& deletel
// the same blood states can be used everywhere
if (!(gameinfo.gametype & GAME_DoomChex))
{
if (shortName.dword == MAKE_ID('B', 'L', 'O', 'D'))
if (!memcmp(shortName, "BLOD", 4))
{
shortName.dword = MAKE_ID('B', 'L', 'U', 'D');
memcpy(shortName, "BLUD", 4);
}
}
}
else if (fileSystem.GetFileNamespace(i) == ns_global)
{
int fn = fileSystem.GetFileContainer(i);
if (fn >= fileSystem.GetIwadNum() && fn <= fileSystem.GetMaxIwadNum() && deletelumps.Find(shortName.String) < deletelumps.Size())
if (fn >= fileSystem.GetIwadNum() && fn <= fileSystem.GetMaxIwadNum() && deletelumps.Find(shortName) < deletelumps.Size())
{
shortName.String[0] = 0; // Lump must be deleted from directory.
shortName[0] = 0; // Lump must be deleted from directory.
}
// Rename the game specific big font lumps so that the font manager does not have to do problematic special checks for them.
else if (!strcmp(shortName.String, altbigfont))
else if (!strcmp(shortName, altbigfont))
{
strcpy(shortName.String, "BIGFONT");
strcpy(shortName, "BIGFONT");
}
}
}
@ -2467,18 +2465,16 @@ void RenameNerve(FileSystem& fileSystem)
for (int i = fileSystem.GetFirstEntry(w); i <= fileSystem.GetLastEntry(w); i++)
{
auto& shortName = fileSystem.GetShortName(i);
auto shortName = fileSystem.GetShortName(i);
// Only rename the maps from NERVE.WAD
if (shortName.dword == MAKE_ID('C', 'W', 'I', 'L'))
if (!memcmp(shortName, "CWILV", 5))
{
shortName.String[0] = 'N';
shortName[0] = 'N';
}
else if (shortName.dword == MAKE_ID('M', 'A', 'P', '0'))
else if (!memcmp(shortName, "MAP0", 4))
{
shortName.String[6] = shortName.String[4];
shortName.String[5] = '0';
shortName.String[4] = 'L';
shortName.dword = MAKE_ID('L', 'E', 'V', 'E');
shortName[6] = shortName[4];
memcpy(shortName, "LEVEL0", 6);
}
}
}
@ -2560,8 +2556,8 @@ void FixMacHexen(FileSystem& fileSystem)
for (int i = lastLump - EXTRA_LUMPS + 1; i <= lastLump; ++i)
{
auto& shortName = fileSystem.GetShortName(i);
shortName.String[0] = '\0';
auto shortName = fileSystem.GetShortName(i);
memcpy(shortName, "\0\0\0\0\0\0\0", 8); // these get compared with memcmp so all 8 bytes need to get cleared.
}
}
@ -2572,21 +2568,21 @@ static void FindStrifeTeaserVoices(FileSystem& fileSystem)
unsigned NumFiles = fileSystem.GetNumEntries();
for (uint32_t i = 0; i < NumFiles; i++)
{
auto& shortName = fileSystem.GetShortName(i);
auto shortName = fileSystem.GetShortName(i);
if (fileSystem.GetFileNamespace(i) == ns_global)
{
// Only sprites in the IWAD normally get renamed
// Strife teaser voices are not in the expected namespace.
if (fileSystem.GetFileContainer(i) == fileSystem.GetIwadNum())
{
if (shortName.String[0] == 'V' &&
shortName.String[1] == 'O' &&
shortName.String[2] == 'C')
if (shortName[0] == 'V' &&
shortName[1] == 'O' &&
shortName[2] == 'C')
{
int j;
for (j = 3; j < 8; ++j)
{
if (shortName.String[j] != 0 && !isdigit(shortName.String[j]))
if (shortName[j] != 0 && !isdigit(shortName[j]))
break;
}
if (j == 8)
@ -3048,7 +3044,7 @@ static bool FileNameCheck(const char* base, const char* path)
return true;
}
static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...)
static int FileSystemPrintf(FileSys::FSMessageLevel level, const char* fmt, ...)
{
va_list arg;
va_start(arg, fmt);
@ -3056,22 +3052,22 @@ static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...)
text.VFormat(fmt, arg);
switch (level)
{
case FSMessageLevel::Error:
case FileSys::FSMessageLevel::Error:
return Printf(TEXTCOLOR_RED "%s", text.GetChars());
break;
case FSMessageLevel::Warning:
case FileSys::FSMessageLevel::Warning:
Printf(TEXTCOLOR_YELLOW "%s", text.GetChars());
break;
case FSMessageLevel::Attention:
case FileSys::FSMessageLevel::Attention:
Printf(TEXTCOLOR_BLUE "%s", text.GetChars());
break;
case FSMessageLevel::Message:
case FileSys::FSMessageLevel::Message:
Printf("%s", text.GetChars());
break;
case FSMessageLevel::DebugWarn:
case FileSys::FSMessageLevel::DebugWarn:
DPrintf(DMSG_WARNING, "%s", text.GetChars());
break;
case FSMessageLevel::DebugNotify:
case FileSys::FSMessageLevel::DebugNotify:
DPrintf(DMSG_NOTIFY, "%s", text.GetChars());
break;
}
@ -3143,7 +3139,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector<std::string>& allw
if (!batchrun) Printf ("W_Init: Init WADfiles.\n");
LumpFilterInfo lfi;
FileSys::FileSystemFilterInfo lfi;
static const struct { int match; const char* name; } blanket[] =
{
@ -3184,7 +3180,7 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector<std::string>& allw
);
bool allowduplicates = Args->CheckParm("-allowduplicates");
if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates))
if (!fileSystem.Initialize(allwads, &lfi, FileSystemPrintf, allowduplicates))
{
I_FatalError("FileSystem: no files found");
}