- rework of the file system code.

Made more efficient by basing the lookup on names, not strings and some additions for acting as a stand-in for Blood's resource manager.
This commit is contained in:
Christoph Oelckers 2019-10-31 01:48:10 +01:00
parent 693095bffb
commit 261af9e401
10 changed files with 260 additions and 242 deletions

View file

@ -171,7 +171,7 @@ struct F7ZLump : public FResourceLump
{ {
int Position; int Position;
virtual int FillCache(); int ValidateCache() override;
}; };
@ -344,11 +344,10 @@ F7ZFile::~F7ZFile()
// //
//========================================================================== //==========================================================================
int F7ZLump::FillCache() int F7ZLump::ValidateCache()
{ {
Cache.Resize(LumpSize); Cache.Resize(LumpSize);
static_cast<F7ZFile*>(Owner)->Archive->Extract(Position, (char*)Cache.Data()); static_cast<F7ZFile*>(Owner)->Archive->Extract(Position, (char*)Cache.Data());
RefCount = 1;
return 1; return 1;
} }

View file

@ -57,7 +57,7 @@
struct FDirectoryLump : public FResourceLump struct FDirectoryLump : public FResourceLump
{ {
virtual FileReader NewReader(); virtual FileReader NewReader();
virtual int FillCache(); int ValidateCache() override;
FString mFullPath; FString mFullPath;
}; };
@ -300,7 +300,7 @@ FileReader FDirectoryLump::NewReader()
// //
//========================================================================== //==========================================================================
int FDirectoryLump::FillCache() int FDirectoryLump::ValidateCache()
{ {
FileReader fr; FileReader fr;
if (!fr.OpenFile(mFullPath)) if (!fr.OpenFile(mFullPath))
@ -311,7 +311,6 @@ int FDirectoryLump::FillCache()
LumpSize = fr.GetLength(); // keep this updated LumpSize = fr.GetLength(); // keep this updated
Cache.Resize(LumpSize); Cache.Resize(LumpSize);
fr.Read(Cache.Data(), LumpSize); fr.Read(Cache.Data(), LumpSize);
RefCount = 1;
return 1; return 1;
} }

View file

@ -73,18 +73,9 @@ bool FLumpFile::Open(bool quiet)
Lumps[0].Position = 0; Lumps[0].Position = 0;
Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].LumpSize = (int)Reader.GetLength();
Lumps[0].Flags = 0; Lumps[0].Flags = 0;
Lumps[0].FullName = FileName;
auto p = FileName.LastIndexOf('/'); auto p = FileName.LastIndexOf('/');
Lumps[0].PathLen = FileName.LastIndexOf('/') + 1; Lumps[0].LumpNameSetup(FileName.GetChars() + p);
Lumps[0].ExtStart = FileName.LastIndexOf('.');
NumLumps = 1; NumLumps = 1;
if (Lumps[0].ExtStart < Lumps[0].PathLen) Lumps[0].ExtStart = -1;
/*
if (!quiet)
{
Printf("\n");
}
*/
return true; return true;
} }

View file

@ -60,7 +60,6 @@ struct RFFLump
uint8_t Flags; uint8_t Flags;
char Extension[3]; char Extension[3];
char Name[8]; char Name[8];
uint32_t IndexNum; // Used by .sfx, possibly others
}; };
//========================================================================== //==========================================================================
@ -72,11 +71,9 @@ struct RFFLump
struct FRFFLump : public FUncompressedLump struct FRFFLump : public FUncompressedLump
{ {
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual int FillCache(); int ValidataCache() override;
uint32_t IndexNum; uint32_t IndexNum;
int GetIndexNum() const { return IndexNum; }
}; };
//========================================================================== //==========================================================================
@ -159,7 +156,7 @@ bool FRFFFile::Open(bool quiet)
{ {
Lump.Flags |= LUMPF_BLOODCRYPT; Lump.Flags |= LUMPF_BLOODCRYPT;
} }
Lump.IndexNum = LittleLong(lumps[i].IndexNum); Lump.ResourceId = LittleLong(lumps[i].ResourceId);
// Rearrange the name and extension to construct the fullname. // Rearrange the name and extension to construct the fullname.
char name[13]; char name[13];
strncpy(name, lumps[i].Name, 8); strncpy(name, lumps[i].Name, 8);
@ -172,14 +169,6 @@ bool FRFFFile::Open(bool quiet)
name[len+3] = lumps[i].Extension[2]; name[len+3] = lumps[i].Extension[2];
name[len+4] = 0; name[len+4] = 0;
Lump.LumpNameSetup(name); Lump.LumpNameSetup(name);
if (Lump.IndexNum > 0)
{
// Create a second entry for looking up by index.
Lumps.Reserve(1);
auto& l = Lumps.Last();
l = Lumps[Lumps.Size() - 2];
snprintf(name, 13, "{%d}.%c%c%c", l.IndexNum, lumps[i].Extension[0], lumps[i].Extension[1], lumps[i].Extension[2]);
}
} }
delete[] lumps; delete[] lumps;
return true; return true;
@ -212,11 +201,11 @@ FileReader *FRFFLump::GetReader()
// //
//========================================================================== //==========================================================================
int FRFFLump::FillCache() int FRFFLump::ValidateCache()
{ {
int res = FUncompressedLump::FillCache(); int res = FUncompressedLump::ValidateCache();
if (Flags & LUMPF_BLOODCRYPT) if (res && )(Flags & LUMPF_BLOODCRYPT))
{ {
int cryptlen = std::min<int> (LumpSize, 256); int cryptlen = std::min<int> (LumpSize, 256);
uint8_t *data = Cache.Data(); uint8_t *data = Cache.Data();

View file

@ -356,14 +356,13 @@ FileReader *FZipLump::GetReader()
// //
//========================================================================== //==========================================================================
int FZipLump::FillCache() int FZipLump::ValidataCache()
{ {
if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress();
Owner->Reader.Seek(Position, FileReader::SeekSet); Owner->Reader.Seek(Position, FileReader::SeekSet);
Cache.Resize(LumpSize); Cache.Resize(LumpSize);
UncompressZipLump((char*)Cache.Data(), Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); UncompressZipLump((char*)Cache.Data(), Owner->Reader, Method, LumpSize, CompressedSize, GPFlags);
RefCount = 1;
return 1; return 1;
} }

View file

@ -23,7 +23,7 @@ struct FZipLump : public FResourceLump
unsigned CRC32; unsigned CRC32;
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual int FillCache(); virtual int ValidateCache() override;
private: private:
void SetLumpAddress(); void SetLumpAddress();
@ -50,4 +50,4 @@ public:
}; };
#endif #endif

View file

@ -43,6 +43,7 @@
#include "m_argv.h" #include "m_argv.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "printf.h" #include "printf.h"
#include "name.h"
//#include "c_dispatch.h" //#include "c_dispatch.h"
#include "filesystem.h" #include "filesystem.h"
#include "superfasthash.h" #include "superfasthash.h"
@ -120,15 +121,12 @@ int FileSystem::InitMultipleFiles (TArray<FString> &filenames, const TArray<FStr
} }
// [RH] Set up hash table // [RH] Set up hash table
Hashes.Resize(8 * NumEntries); Hashes.Resize(NumLookupModes * 2 * NumEntries);
FirstFileIndex_BaseName = &Hashes[0]; for (int i = 0; i < NumLookupModes; i++)
NextFileIndex_BaseName = &Hashes[NumEntries]; {
FirstFileIndex_FullName = &Hashes[NumEntries*2]; FirstFileIndex[i] = &Hashes[i * 2 * NumEntries];
NextFileIndex_FullName = &Hashes[NumEntries*3]; NextFileIndex[i] = &Hashes[(i+1) * 2 * NumEntries];
FirstFileIndex_NoExt = &Hashes[NumEntries*4]; }
NextFileIndex_NoExt = &Hashes[NumEntries*5];
FirstFileIndex_BaseExt = &Hashes[NumEntries*6];
NextFileIndex_BaseExt = &Hashes[NumEntries*7];
InitHashChains (); InitHashChains ();
FileInfo.ShrinkToFit(); FileInfo.ShrinkToFit();
Files.ShrinkToFit(); Files.ShrinkToFit();
@ -199,12 +197,12 @@ void FileSystem::AddFile (const char *filename, FileReader *filer)
//========================================================================== //==========================================================================
// //
// GetFileRecordCheckIfWadLoaded // CheckIfResourceFileLoaded
// //
// Returns true if the specified wad is loaded, false otherwise. // Returns true if the specified file is loaded, false otherwise.
// If a fully-qualified path is specified, then the wad must match exactly. // If a fully-qualified path is specified, then the file must match exactly.
// Otherwise, any wad with that name will work, whatever its path. // Otherwise, any file with that name will work, whatever its path.
// Returns the wads index if found, or -1 if not. // Returns the file's index if found, or -1 if not.
// //
//========================================================================== //==========================================================================
@ -237,11 +235,9 @@ int FileSystem::CheckIfResourceFileLoaded (const char *name) noexcept
//========================================================================== //==========================================================================
// //
// GetFileRecordFindFile // FindFile
// //
// Same as above but looks for a fully qualified name from a .zip // Looks up a file by name, either eith or without path and extension
// These don't care about namespaces though because those are part
// of the path.
// //
//========================================================================== //==========================================================================
@ -253,62 +249,28 @@ int FileSystem::FindFile (const char *name, ELookupMode lookupmode, int filenum)
{ {
return -1; return -1;
} }
uint32_t* fli; FName lname(name, true);
uint32_t* nli; if (lname == NAME_None) return -1;
switch (lookupmode) if (lookupmode == ELookupMode::IdWithType) return -1;
{ int lookupindex = (int)lookupmode;
case ELookupMode::FullName: uint32_t* fli = FirstFileIndex[lookupindex];
fli = FirstFileIndex_FullName; uint32_t* nli = NextFileIndex[lookupindex];
nli = NextFileIndex_FullName;
break; for (i = fli[int(lname) % NumEntries]; i != NULL_INDEX; i = nli[i])
case ELookupMode::NoExtension:
fli = FirstFileIndex_NoExt;
nli = NextFileIndex_NoExt;
break;
case ELookupMode::BaseName:
fli = FirstFileIndex_BaseName;
nli = NextFileIndex_BaseName;
break;
case ELookupMode::BaseWithExtension:
fli = FirstFileIndex_BaseExt;
nli = NextFileIndex_BaseExt;
break;
}
auto len = strlen(name);
for (i = fli[MakeKey(name) % NumEntries]; i != NULL_INDEX; i = nli[i])
{ {
if (filenum > 0 && FileInfo[i].rfnum != filenum) continue;
auto lump = FileInfo[i].lump; auto lump = FileInfo[i].lump;
if (FileInfo[i].rfnum != filenum) continue; if (lump->LumpName[lookupindex] == lname) return i;
const char* fn = lump->FullName.GetChars();
const char* fnstart, * fnend;
if (lookupmode == ELookupMode::BaseName || lookupmode == ELookupMode::BaseWithExtension) fnstart = fn + lump->PathLen;
else fnstart = fn;
if ((lookupmode == ELookupMode::NoExtension || lookupmode == ELookupMode::BaseName) && lump->ExtStart >= 0) fnend = fn + lump->ExtStart;
else fnend = fn + lump->FullName.Len();
if ((fnend - fnstart) == (ptrdiff_t)len)
{
if (!strnicmp(name, fnstart, len))
{
return i;
}
}
} }
return -1; return -1;
} }
//========================================================================== //==========================================================================
// //
// GetFileRecordGetFile // GetFile
// //
// Calls GetFileRecordFindFile, but bombs out if not found. // Calls FindFile, but bombs out if not found.
// //
//========================================================================== //==========================================================================
@ -328,7 +290,61 @@ int FileSystem::GetFile (const char *name, ELookupMode lookupmode, int filenum)
//========================================================================== //==========================================================================
// //
// GetFileRecordLumpLength // FindResource
//
// Looks for content based on Blood resource IDs.
//
//==========================================================================
int FileSystem::FindResource (int resid, const char *type, int filenum) const noexcept
{
uint32_t i;
if (type == NULL)
{
return -1;
}
FName lname(type, true);
if (lname == NAME_None) return -1;
const int lookuptype = (int)ELookupMode::IdWithType
uint32_t* fli = FirstFileIndex[lookuptype];
uint32_t* nli = NextFileIndex[lookuptype];
for (i = fli[int(resid) % NumEntries]; i != NULL_INDEX; i = nli[i])
{
if (filenum > 0 && FileInfo[i].rfnum != filenum) continue;
auto lump = FileInfo[i].lump;
if (lump->LumpName[lookuptype] == lname) return i;
}
return -1;
}
//==========================================================================
//
// GetResource
//
// Calls GetResource, but bombs out if not found.
//
//==========================================================================
int FileSystem::GetResource (int resid, const char *type, int filenum) const
{
int i;
i = FindResource (resid, type, lookupmode, filenum);
if (i == -1)
{
FStringf error("GetResource: %d of type %s not found!", resid, type);
throw FileSystemError(error.GetChars());
}
return i;
}
//==========================================================================
//
// LumpLength
// //
// Returns the buffer size needed to load the given lump. // Returns the buffer size needed to load the given lump.
// //
@ -379,7 +395,7 @@ int FileSystem::GetFileFlags (int lump)
//========================================================================== //==========================================================================
// //
// GetFileRecordInitHashChains // InitHashChains
// //
// Prepares the lumpinfos for hashing. // Prepares the lumpinfos for hashing.
// (Hey! This looks suspiciously like something from Boom! :-) // (Hey! This looks suspiciously like something from Boom! :-)
@ -388,68 +404,26 @@ int FileSystem::GetFileFlags (int lump)
void FileSystem::InitHashChains (void) void FileSystem::InitHashChains (void)
{ {
char name[8];
unsigned int i, j;
// Mark all buckets as empty // Mark all buckets as empty
memset(FirstFileIndex_BaseExt, 255, NumEntries * sizeof(FirstFileIndex_BaseExt[0])); memset(Hashes.Data(), 255, Hashes.Size() * sizeof(Hashes[0]));
memset(NextFileIndex_BaseExt, 255, NumEntries * sizeof(NextFileIndex_BaseExt[0]));
memset (FirstFileIndex_BaseName, 255, NumEntries*sizeof(FirstFileIndex_BaseName[0]));
memset (NextFileIndex_BaseName, 255, NumEntries*sizeof(NextFileIndex_BaseName[0]));
memset (FirstFileIndex_FullName, 255, NumEntries*sizeof(FirstFileIndex_FullName[0]));
memset (NextFileIndex_FullName, 255, NumEntries*sizeof(NextFileIndex_FullName[0]));
memset(FirstFileIndex_NoExt, 255, NumEntries * sizeof(FirstFileIndex_NoExt[0]));
memset(NextFileIndex_NoExt, 255, NumEntries * sizeof(NextFileIndex_NoExt[0]));
// Now set up the chains // Now set up the chains
for (i = 0; i < (unsigned)NumEntries; i++) for (int i = 0; i < (unsigned)NumEntries; i++)
{ {
// Do the same for the full paths
auto lump = FileInfo[i].lump; auto lump = FileInfo[i].lump;
auto& Name = lump->FullName; for (int l = 0; l < NumLookupModes; l++)
if (Name.IsNotEmpty())
{ {
j = MakeKey(Name) % NumEntries; int hash;
NextFileIndex_FullName[i] = FirstFileIndex_FullName[j]; if (l != (int)ELookupMode::IdWithType && lump->LumpName[l] != NAME_None)
FirstFileIndex_FullName[j] = i;
j = MakeKey(Name + lump->PathLen) % NumEntries;
NextFileIndex_BaseExt[i] = FirstFileIndex_BaseExt[j];
FirstFileIndex_BaseExt[j] = i;
j = MakeKey(Name, lump->ExtStart) % NumEntries;
NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j];
FirstFileIndex_NoExt[j] = i;
if (lump->ExtStart > lump->PathLen)
{ {
j = MakeKey(Name, lump->ExtStart) % NumEntries; hash = int(lump->LumpName[l]) % NumEntries;
NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j];
FirstFileIndex_NoExt[j] = i;
j = MakeKey(Name + lump->PathLen, lump->ExtStart - lump->PathLen) % NumEntries;
NextFileIndex_BaseName[i] = FirstFileIndex_BaseName[j];
FirstFileIndex_BaseName[j] = i;
} }
else else if (lump->ResourceId > 0)
{ {
NextFileIndex_NoExt[i] = NextFileIndex_FullName[i]; hash = int(lump->ResourceId) % NumEntries;
FirstFileIndex_NoExt[i] = FirstFileIndex_FullName[i];
NextFileIndex_BaseName[i] = NextFileIndex_BaseExt[i];
FirstFileIndex_BaseName[j] = FirstFileIndex_BaseExt[i];
} }
NextFileIndex[l][hash] = FirstFileIndex[l][hash];
FString nameNoExt = Name; FirstFileIndex[l][hash] = i;
auto dot = nameNoExt.LastIndexOf('.');
auto slash = nameNoExt.LastIndexOf('/');
if (dot > slash) nameNoExt.Truncate(dot);
j = MakeKey(nameNoExt) % NumEntries;
NextFileIndex_NoExt[i] = FirstFileIndex_NoExt[j];
FirstFileIndex_NoExt[j] = i;
} }
} }
} }
@ -466,36 +440,26 @@ void FileSystem::InitHashChains (void)
int FileSystem::Iterate (const char *name, int *lastlump, ELookupMode lookupmode) int FileSystem::Iterate (const char *name, int *lastlump, ELookupMode lookupmode)
{ {
union
{
char name8[8];
uint64_t qname;
};
FileRecord *lump_p; FileRecord *lump_p;
int lookupindex = static_cast<int>(lookupmode);
FName lname(name, true);
assert(lastlump != NULL && *lastlump >= 0); assert(lastlump != NULL && *lastlump >= 0);
if (lname == NAME_None)
{
*lastlump = NumEntries;
return -1;
}
lump_p = &FileInfo[*lastlump]; lump_p = &FileInfo[*lastlump];
auto len = strlen(name);
while (lump_p < &FileInfo[NumEntries]) while (lump_p < &FileInfo[NumEntries])
{ {
auto lump = lump_p->lump; auto lump = lump_p->lump;
const char* fn = lump->FullName.GetChars(); if (lump->LumpName[lookupindex] == lname)
const char* fnstart, * fnend;
if (lookupmode == ELookupMode::BaseName || lookupmode == ELookupMode::BaseWithExtension) fnstart = fn + lump->PathLen;
else fnstart = fn;
if ((lookupmode == ELookupMode::NoExtension || lookupmode == ELookupMode::BaseName) && lump->ExtStart >= 0) fnend = fn + lump->ExtStart;
else fnend = fn + lump->FullName.Len();
if ((fnend - fnstart) == (ptrdiff_t)len)
{ {
if (!strnicmp(name, fnstart, len)) int lump = int(lump_p - &FileInfo[0]);
{ *lastlump = lump + 1;
int lump = int(lump_p - &FileInfo[0]); return lump;
*lastlump = lump + 1;
return lump;
}
} }
lump_p++; lump_p++;
} }
@ -505,7 +469,7 @@ int FileSystem::Iterate (const char *name, int *lastlump, ELookupMode lookupmode
//========================================================================== //==========================================================================
// //
// GetFileRecordGetLumpName // GetLumpName
// //
//========================================================================== //==========================================================================
@ -514,12 +478,12 @@ const char *FileSystem::GetFileName (int lump) const
if ((size_t)lump >= NumEntries) if ((size_t)lump >= NumEntries)
return nullptr; return nullptr;
else else
return FileInfo[lump].lump->FullName; return FileInfo[lump].lump->FullName();
} }
//========================================================================== //==========================================================================
// //
// FileSystem :: GetLumpFullPath // FileSystem :: GetFilrFullPath
// //
// Returns the name of the lump's wad prefixed to the lump's full name. // Returns the name of the lump's wad prefixed to the lump's full name.
// //
@ -542,21 +506,21 @@ FString FileSystem::GetFileFullPath(int lump) const
// //
// Returns the index number for this lump. This is *not* the lump's position // Returns the index number for this lump. This is *not* the lump's position
// in the lump directory, but rather a special value that RFF can associate // in the lump directory, but rather a special value that RFF can associate
// with files. Other archive types will return 0, since they don't have it. // with files. Other archive types will return -1, since they don't have it.
// //
//========================================================================== //==========================================================================
int FileSystem::GetRFFIndexNum(int lump) const int FileSystem::GetResourceId(int lump) const
{ {
if ((size_t)lump >= NumEntries) if ((size_t)lump >= NumEntries)
return 0; return -1;
else else
return FileInfo[lump].lump->GetIndexNum(); return FileInfo[lump].lump->ResourceId;
} }
//========================================================================== //==========================================================================
// //
// GetFileRecordGetLumpFile // GetLumpFile
// //
//========================================================================== //==========================================================================
@ -599,12 +563,12 @@ unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray<FolderEntry> &r
result.Clear(); result.Clear();
for (unsigned i = 0; i < FileInfo.Size(); i++) for (unsigned i = 0; i < FileInfo.Size(); i++)
{ {
if (FileInfo[i].lump->FullName.IndexOf(path) == 0) if (!strncmp(FileInfo[i].lump->FullName(), path, path.Len()))
{ {
// Only if it hasn't been replaced. // Only if it hasn't been replaced.
if ((unsigned)FindFile(FileInfo[i].lump->FullName) == i) if ((unsigned)FindFile(FileInfo[i].lump->FullName()) == i)
{ {
result.Push({ FileInfo[i].lump->FullName.GetChars(), i }); result.Push({ FileInfo[i].lump->FullName(), i });
} }
} }
} }
@ -633,7 +597,7 @@ unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray<FolderEntry> &r
//========================================================================== //==========================================================================
// //
// GetFileRecordReadFile // ReadFile
// //
// Loads the lump into a TArray and returns it. // Loads the lump into a TArray and returns it.
// //
@ -641,6 +605,9 @@ unsigned FileSystem::GetFilesInFolder(const char *inpath, TArray<FolderEntry> &r
TArray<uint8_t> FileSystem::GetFileData(int lump, int pad) TArray<uint8_t> FileSystem::GetFileData(int lump, int pad)
{ {
if ((size_t)lump >= FileInfo.Size())
return TArray<<uint8_t>();
auto lumpr = OpenFileReader(lump); auto lumpr = OpenFileReader(lump);
auto size = lumpr.GetLength(); auto size = lumpr.GetLength();
TArray<uint8_t> data(size + pad, true); TArray<uint8_t> data(size + pad, true);
@ -655,6 +622,33 @@ TArray<uint8_t> FileSystem::GetFileData(int lump, int pad)
return data; return data;
} }
//==========================================================================
//
// Interface to the lump cache
//
//==========================================================================
const void *FileSystem::Lock(int lump)
{
if ((size_t)lump >= FileInfo.Size()) return nullptr;
auto lump = FileInfo[lump].lump;
return lump->Lock();
}
void FileSystem::Unlock(bool mayfree)
{
if ((size_t)lump >= FileInfo.Size()) return;
auto lump = FileInfo[lump].lump;
lump->Unlock(maxfree);
}
const void *FileSystem::Get(int lump)
{
if ((size_t)lump >= FileInfo.Size()) return nullptr;
auto lump = FileInfo[lump].lump;
return lump->Get();
}
//========================================================================== //==========================================================================
// //
// ReadFile - variant 2 // ReadFile - variant 2
@ -723,7 +717,7 @@ FileReader FileSystem::ReopenFileReader(int lump, bool alwayscache)
//========================================================================== //==========================================================================
// //
// GetFileRecordGetResourceFileName // GetResourceFileName
// //
// Returns the name of the given wad. // Returns the name of the given wad.
// //
@ -791,7 +785,7 @@ int FileSystem::GetEntryCount (int rfnum) const noexcept
//========================================================================== //==========================================================================
// //
// GetFileRecordGetResourceFileFullName // GetResourceFileFullName
// //
// Returns the name of the given wad, including any path // Returns the name of the given wad, including any path
// //

View file

@ -49,14 +49,22 @@ struct FolderEntry
unsigned lumpnum; unsigned lumpnum;
}; };
enum class ELookupMode enum class ELookupMode // Todo: Merge with FResourceLump::ENameType
{ {
FullName = 0, FullName,
NoExtension = 1, NoExtension,
BaseName = 2, BaseName,
BaseWithExtension = 3 BaseWithExtension,
IdWithType,
NumLookupModes
}; };
enum
{
NumLookupModes = (int)ELookupMode::NumLookupModes + 1
};
class FileSystem class FileSystem
{ {
public: public:
@ -83,9 +91,17 @@ public:
int FindFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.c_str(), lookupmode, filenum); } int FindFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const noexcept { return FindFile(name.c_str(), lookupmode, filenum); }
int GetFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.c_str(), lookupmode, filenum); } int GetFile (const std::string &name, ELookupMode lookupmode = ELookupMode::FullName, int filenum = -1) const { return GetFile(name.c_str(), lookupmode, filenum); }
int FindResource (int resid, const char *type, int filenum = -1) const noexcept;
int GetResource (int resid, const char *type, int filenum = -1) const; // Like FindFile, but throws an exception when it cannot find what it looks for.
TArray<uint8_t> GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!) TArray<uint8_t> GetFileData(int file, int pad = 0); // reads file into a writable buffer and optionally adds some padding at the end. (FileData isn't writable!)
FileData ReadFile (int file); FileData ReadFile (int file);
FileData ReadFile (const char *name) { return ReadFile (GetFile (name)); } FileData ReadFile (const char *name) { return ReadFile (GetFile (name)); }
const void *Lock(int lump);
void Unlock(bool mayfree = false);
void *Get(int lump);
FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one. FileReader OpenFileReader(int file); // opens a reader that redirects to the containing file's one.
FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader. FileReader ReopenFileReader(int file, bool alwayscache = false); // opens an independent reader.
@ -105,6 +121,7 @@ public:
unsigned GetFilesInFolder(const char *path, TArray<FolderEntry> &result, bool atomic) const; unsigned GetFilesInFolder(const char *path, TArray<FolderEntry> &result, bool atomic) const;
bool IsEncryptedFile(int file) const noexcept; bool IsEncryptedFile(int file) const noexcept;
int GetResourceId(int file) const;
int GetNumResourceFiles() const { return NumFiles; } int GetNumResourceFiles() const { return NumFiles; }
int GetNumEntries () const { return NumEntries; } int GetNumEntries () const { return NumEntries; }
@ -117,17 +134,8 @@ protected:
TArray<FileRecord> FileInfo; TArray<FileRecord> FileInfo;
TArray<uint32_t> Hashes; // one allocation for all hash lists. TArray<uint32_t> Hashes; // one allocation for all hash lists.
uint32_t *FirstFileIndex_BaseName; // Hash information for the base name (no path and no extension) uint32_t *FirstFileIndex[NumLookupModes]; // Hash information for the base name (no path and no extension)
uint32_t *NextFileIndex_BaseName; uint32_t *NextFileIndex[NumLookupModes];
uint32_t* FirstFileIndex_BaseExt; // Hash information for the base name (no path and no extension)
uint32_t* NextFileIndex_BaseExt;
uint32_t *FirstFileIndex_FullName; // The same information for fully qualified paths
uint32_t *NextFileIndex_FullName;
uint32_t *FirstFileIndex_NoExt; // The same information for fully qualified paths but without the extension
uint32_t *NextFileIndex_NoExt;
uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size() uint32_t NumFiles = 0; // Not necessarily the same as FileInfo.Size()
uint32_t NumEntries; uint32_t NumEntries;

View file

@ -36,6 +36,7 @@
#include <zlib.h> #include <zlib.h>
#include "resourcefile.h" #include "resourcefile.h"
#include "name.h"
extern FString LumpFilter; extern FString LumpFilter;
@ -78,16 +79,26 @@ FResourceLump::~FResourceLump()
//========================================================================== //==========================================================================
// //
// Sets up the lump name information for anything not coming from a WAD file. // Sets up the file name information
// This is stored as FNames for various formats.
// //
//========================================================================== //==========================================================================
void FResourceLump::LumpNameSetup(FString iname) void FResourceLump::LumpNameSetup(FString iname)
{ {
PathLen = iname.LastIndexOf('/') + 1; auto pathLen = iname.LastIndexOf('/') + 1;
ExtStart = iname.LastIndexOf('.'); LumpName[FullNameType] = iname.GetChars();
if (ExtStart <= PathLen) ExtStart = -1; LumpName[BaseNameType] = iname.GetChars() + pathLen;
FullName = iname;
auto extStart = iname.LastIndexOf('.');
if (extStart <= pathLen) extStart = -1;
if (extStart > 0)
{
LumpName[ExtensionType] = iname.GetChars() + extStart + 1;
iname.Truncate(extStart);
}
LumpName[FullNameNoExtType] = iname.GetChars();
LumpName[BaseNameNoExtType] = iname.GetChars() + pathLen;
} }
//========================================================================== //==========================================================================
@ -100,9 +111,9 @@ void FResourceLump::LumpNameSetup(FString iname)
FCompressedBuffer FResourceLump::GetRawData() FCompressedBuffer FResourceLump::GetRawData()
{ {
FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)LumpSize, METHOD_STORED, 0, 0, new char[LumpSize] }; FCompressedBuffer cbuf = { (unsigned)LumpSize, (unsigned)LumpSize, METHOD_STORED, 0, 0, new char[LumpSize] };
memcpy(cbuf.mBuffer, CacheLump(), LumpSize); memcpy(cbuf.mBuffer, Lock(), LumpSize);
cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize); cbuf.mCRC32 = crc32(0, (uint8_t*)cbuf.mBuffer, LumpSize);
ReleaseCache(); Unlock(true);
return cbuf; return cbuf;
} }
@ -135,7 +146,7 @@ FileReader FResourceLump::NewReader()
// //
//========================================================================== //==========================================================================
void *FResourceLump::CacheLump() void *FResourceLump::Lock()
{ {
if (Cache.Size()) if (Cache.Size())
{ {
@ -143,7 +154,23 @@ void *FResourceLump::CacheLump()
} }
else if (LumpSize > 0) else if (LumpSize > 0)
{ {
FillCache(); ValidateCache()
RefCount++;
}
return Cache.Data();
}
//==========================================================================
//
// Caches a lump's content without increasing the reference counter
//
//==========================================================================
void *FResourceLump::Get()
{
if (Cache.Size() == 0)
{
ValidateCache()
} }
return Cache.Data(); return Cache.Data();
} }
@ -154,13 +181,13 @@ void *FResourceLump::CacheLump()
// //
//========================================================================== //==========================================================================
int FResourceLump::ReleaseCache() int FResourceLump::Unlock(bool mayfree)
{ {
if (LumpSize > 0 && RefCount > 0) if (LumpSize > 0 && RefCount > 0)
{ {
if (--RefCount == 0) if (--RefCount == 0)
{ {
Cache.Reset(); if (mayfree) Cache.Reset();
} }
} }
return RefCount; return RefCount;
@ -246,8 +273,7 @@ int lumpcmp(const void * a, const void * b)
{ {
FResourceLump * rec1 = (FResourceLump *)a; FResourceLump * rec1 = (FResourceLump *)a;
FResourceLump * rec2 = (FResourceLump *)b; FResourceLump * rec2 = (FResourceLump *)b;
return stricmp(rec1->LumpName[FResourceLump::FullNameType].GetChars(), rec2->LumpName[FResourceLump::FullNameType].GetChars());
return rec1->FullName.CompareNoCase(rec2->FullName);
} }
//========================================================================== //==========================================================================
@ -323,8 +349,8 @@ int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize,
for (uint32_t i = start; i < end; ++i, lump_p = (uint8_t *)lump_p + lumpsize) for (uint32_t i = start; i < end; ++i, lump_p = (uint8_t *)lump_p + lumpsize)
{ {
FResourceLump *lump = (FResourceLump *)lump_p; FResourceLump *lump = (FResourceLump *)lump_p;
assert(lump->FullName.CompareNoCase(filter, (int)filter.Len()) == 0); assert(filter.CompareNoCase(lump->FullName(), (int)filter.Len()) == 0);
lump->LumpNameSetup(lump->FullName.Mid(filter.Len())); lump->LumpNameSetup(lump->FullName() + filter.Len());
} }
// Move filtered lumps to the end of the lump list. // Move filtered lumps to the end of the lump list.
@ -370,7 +396,8 @@ void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t m
for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize) for (void *p = (uint8_t *)lumps + start * lumpsize; p < stop; p = (uint8_t *)p + lumpsize)
{ {
FResourceLump *lump = (FResourceLump *)p; FResourceLump *lump = (FResourceLump *)p;
lump->FullName = ""; for (auto &ln : lump->LumpName)
ln = NAME_None;
} }
} }
} }
@ -403,10 +430,11 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize
{ {
mid = min + (max - min) / 2; mid = min + (max - min) / 2;
lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize);
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len());
if (cmp == 0) if (cmp == 0)
break; break;
else if (cmp < 0) else if (cmp > 0)
min = mid + 1; min = mid + 1;
else else
max = mid - 1; max = mid - 1;
@ -423,7 +451,7 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize
{ {
mid = min + (max - min) / 2; mid = min + (max - min) / 2;
lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize);
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len());
// Go left on matches and right on misses. // Go left on matches and right on misses.
if (cmp == 0) if (cmp == 0)
max = mid - 1; max = mid - 1;
@ -438,7 +466,7 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize
{ {
mid = min + (max - min) / 2; mid = min + (max - min) / 2;
lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize); lump = (FResourceLump *)((uint8_t *)lumps + mid * lumpsize);
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len()); cmp = filter.CompareNoCase(lump->FullName(), (int)filter.Len());
// Go right on matches and left on misses. // Go right on matches and left on misses.
if (cmp == 0) if (cmp == 0)
min = mid + 1; min = mid + 1;
@ -457,10 +485,12 @@ bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize
FResourceLump *FResourceFile::FindLump(const char *name) FResourceLump *FResourceFile::FindLump(const char *name)
{ {
FName lname(name, true);
if (lname == NAME_None) return nullptr;
for (unsigned i = 0; i < NumLumps; i++) for (unsigned i = 0; i < NumLumps; i++)
{ {
FResourceLump *lump = GetLump(i); FResourceLump *lump = GetLump(i);
if (!stricmp(name, lump->FullName)) if (lump->LumpName[FResourceLump::FullNameType] == lname)
{ {
return lump; return lump;
} }
@ -486,12 +516,11 @@ FileReader *FUncompressedLump::GetReader()
// //
//========================================================================== //==========================================================================
int FUncompressedLump::FillCache() int FUncompressedLump::ValidateCache()
{ {
Owner->Reader.Seek(Position, FileReader::SeekSet); Owner->Reader.Seek(Position, FileReader::SeekSet);
Cache.Resize(LumpSize); Cache.Resize(LumpSize);
Owner->Reader.Read(Cache.Data(), LumpSize); Owner->Reader.Read(Cache.Data(), LumpSize);
RefCount = 1;
return 1; return 1;
} }
@ -546,7 +575,7 @@ FExternalLump::FExternalLump(const char *_filename, int filesize)
// //
//========================================================================== //==========================================================================
int FExternalLump::FillCache() int FExternalLump::ValidateCache()
{ {
Cache.Resize(LumpSize); Cache.Resize(LumpSize);
FileReader f; FileReader f;
@ -559,6 +588,5 @@ int FExternalLump::FillCache()
{ {
memset(Cache.Data(), 0, LumpSize); memset(Cache.Data(), 0, LumpSize);
} }
RefCount = 1;
return 1; return 1;
} }

View file

@ -42,17 +42,26 @@ struct FCompressedBuffer
} }
}; };
struct FResourceLump struct FResourceLump
{ {
enum ENameType
{
FullNameType,
FullNameNoExtType,
BaseNameType,
BaseNameNoExtType,
ExtensionType,
NUMNAMETYPES
};
friend class FResourceFile; friend class FResourceFile;
unsigned LumpSize = 0; unsigned LumpSize = 0;
int RefCount = 0; int RefCount = 0;
int Flags = 0; int Flags = 0;
int PathLen = 0;
int ExtStart = -1;
int ResourceId = -1; int ResourceId = -1;
FString FullName; // Name with extension and path FName LumpName[NUMNAMETYPES] = {};
FResourceFile * Owner = nullptr; FResourceFile * Owner = nullptr;
TArray<uint8_t> Cache; TArray<uint8_t> Cache;
@ -62,20 +71,22 @@ struct FResourceLump
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual FileReader NewReader(); virtual FileReader NewReader();
virtual int GetFileOffset() { return -1; } virtual int GetFileOffset() { return -1; }
virtual int GetIndexNum() const { return 0; }
void LumpNameSetup(FString iname); void LumpNameSetup(FString iname);
virtual FCompressedBuffer GetRawData(); virtual FCompressedBuffer GetRawData();
void *CacheLump(); void *Lock(); // validates the cache and increases the refcount.
int ReleaseCache(); void Unlock(bool freeunrefd = false); // recreases the refcount and optionally frees the buffer
void *Get(); // validates the cache and returns a pointer without locking
// Wrappers for emulating Blood's resource system
unsigned Size() const{ return LumpSize; } unsigned Size() const{ return LumpSize; }
int LockCount() const { return RefCount; } int LockCount() const { return RefCount; }
FString BaseName(); // don't know if these will be needed const char *ResName() const { return LumpName[BaseNameNoExtType]; } needed
FString Type(); const char *ResType() { return LumpName[ExtensionType]; }
const char *FullName() const { return LumpName[FullNameType]; } needed
protected: protected:
virtual int FillCache() { return -1; } virtual int ValidateCache() { return -1; }
}; };
@ -127,7 +138,7 @@ struct FUncompressedLump : public FResourceLump
int Position; int Position;
virtual FileReader *GetReader(); virtual FileReader *GetReader();
virtual int FillCache(); int ValidateCache() override;
virtual int GetFileOffset() { return Position; } virtual int GetFileOffset() { return Position; }
}; };
@ -150,7 +161,7 @@ struct FExternalLump : public FResourceLump
FString Filename; FString Filename;
FExternalLump(const char *_filename, int filesize = -1); FExternalLump(const char *_filename, int filesize = -1);
virtual int FillCache(); virtual int ValidateCache() override;
}; };