mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +00:00
Add lump filtering for archive resources
- Multi-directory archives (e.g. zips) now support filtering lumps depending on the loaded IWAD. The search rules are the same as for the Autoload entries in the user's ini. For instance, if you are playing Doom 2, the following filters will be applied: * "filter/doom2/*" * "filter/doom/*" They will be renamed to strip out the "filter/doom2/" and "filter/doom/" parts and will be ordered so they take precedence over any files not inside a filter/ directory. Any files inside another filter/ directory (e.g. "filter/hexen/*") will be ignored.
This commit is contained in:
parent
fc6f983c13
commit
7b4d6e2f87
7 changed files with 215 additions and 2 deletions
|
@ -1992,6 +1992,9 @@ static void D_DoomInit()
|
|||
|
||||
static void AddAutoloadFiles(const char *group, const char *autoname)
|
||||
{
|
||||
LumpFilterGroup = group;
|
||||
LumpFilterIWAD = autoname;
|
||||
|
||||
if (!(gameinfo.flags & GI_SHAREWARE) && !Args->CheckParm("-noautoload"))
|
||||
{
|
||||
FString file;
|
||||
|
|
|
@ -69,3 +69,4 @@ int SinglePlayerClass[MAXPLAYERS];
|
|||
bool ToggleFullscreen;
|
||||
int BorderTopRefresh;
|
||||
|
||||
FString LumpFilterGroup, LumpFilterIWAD;
|
||||
|
|
|
@ -250,4 +250,7 @@ EXTERN_CVAR (Int, compatflags);
|
|||
EXTERN_CVAR (Int, compatflags2);
|
||||
extern int i_compatflags, i_compatflags2, ii_compatflags, ii_compatflags2, ib_compatflags;
|
||||
|
||||
// Filters from AddAutoloadFiles(). Used to filter files from archives.
|
||||
extern FString LumpFilterGroup, LumpFilterIWAD;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
#include "cmdlib.h"
|
||||
#include "w_wad.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
#include "gi.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
|
@ -329,6 +330,9 @@ int STACK_ARGS lumpcmp(const void * a, const void * b)
|
|||
// FResourceFile :: PostProcessArchive
|
||||
//
|
||||
// Sorts files by name.
|
||||
// For files named "filter/<game>/*": Using the same filter rules as config
|
||||
// autoloading, move them to the end and rename them without the "filter/"
|
||||
// prefix. Filtered files that don't match are deleted.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
@ -336,6 +340,170 @@ void FResourceFile::PostProcessArchive(void *lumps, size_t lumpsize)
|
|||
{
|
||||
// Entries in archives are sorted alphabetically
|
||||
qsort(lumps, NumLumps, lumpsize, lumpcmp);
|
||||
|
||||
// Filter out lumps using the same names as the Autoload.* sections
|
||||
// in the ini file use. We reduce the maximum lump concidered after
|
||||
// each one so that we don't risk refiltering already filtered lumps.
|
||||
DWORD max = NumLumps;
|
||||
max -= FilterLumps(gameinfo.ConfigName, lumps, lumpsize, max);
|
||||
max -= FilterLumps(LumpFilterGroup, lumps, lumpsize, max);
|
||||
max -= FilterLumps(LumpFilterIWAD, lumps, lumpsize, max);
|
||||
JunkLeftoverFilters(lumps, lumpsize, max);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FResourceFile :: FilterLumps
|
||||
//
|
||||
// Finds any lumps between [0,<max>) that match the pattern
|
||||
// "filter/<filtername>/*" and moves them to the end of the lump list.
|
||||
// Returns the number of lumps moved.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int FResourceFile::FilterLumps(FString filtername, void *lumps, size_t lumpsize, DWORD max)
|
||||
{
|
||||
FString filter;
|
||||
DWORD start, end;
|
||||
|
||||
if (filtername.IsEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
filter << "filter/" << filtername << '/';
|
||||
if (FindPrefixRange(filter, lumps, lumpsize, max, start, end))
|
||||
{
|
||||
void *from = (BYTE *)lumps + start * lumpsize;
|
||||
|
||||
// Remove filter prefix from every name
|
||||
void *lump_p = from;
|
||||
for (DWORD i = start; i < end; ++i, lump_p = (BYTE *)lump_p + lumpsize)
|
||||
{
|
||||
FResourceLump *lump = (FResourceLump *)lump_p;
|
||||
assert(lump->FullName.CompareNoCase(filter, (int)filter.Len()) == 0);
|
||||
lump->LumpNameSetup(&lump->FullName[filter.Len()]);
|
||||
}
|
||||
|
||||
// Move filtered lumps to the end of the lump list.
|
||||
size_t count = (end - start) * lumpsize;
|
||||
void *to = (BYTE *)lumps + NumLumps * lumpsize - count;
|
||||
assert (to >= from);
|
||||
|
||||
if (from != to)
|
||||
{
|
||||
// Copy filtered lumps to a temporary buffer.
|
||||
BYTE *filteredlumps = new BYTE[count];
|
||||
memcpy(filteredlumps, from, count);
|
||||
|
||||
// Shift lumps left to make room for the filtered ones at the end.
|
||||
memmove(from, (BYTE *)from + count, (NumLumps - end) * lumpsize);
|
||||
|
||||
// Copy temporary buffer to newly freed space.
|
||||
memcpy(to, filteredlumps, count);
|
||||
|
||||
delete[] filteredlumps;
|
||||
}
|
||||
}
|
||||
return end - start;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FResourceFile :: JunkLeftoverFilters
|
||||
//
|
||||
// Deletes any lumps beginning with "filter/" that were not matched.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FResourceFile::JunkLeftoverFilters(void *lumps, size_t lumpsize, DWORD max)
|
||||
{
|
||||
DWORD start, end;
|
||||
if (FindPrefixRange("filter/", lumps, lumpsize, max, start, end))
|
||||
{
|
||||
// Since the resource lumps may contain non-POD data besides the
|
||||
// full name, we "delete" them by erasing their names so they
|
||||
// can't be found.
|
||||
void *stop = (BYTE *)lumps + end * lumpsize;
|
||||
for (void *p = (BYTE *)lumps + start * lumpsize; p < stop; p = (BYTE *)p + lumpsize)
|
||||
{
|
||||
FResourceLump *lump = (FResourceLump *)p;
|
||||
lump->FullName = 0;
|
||||
lump->Name[0] = '\0';
|
||||
lump->Namespace = ns_invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FResourceFile :: FindPrefixRange
|
||||
//
|
||||
// Finds a range of lumps that start with the prefix string. <start> is left
|
||||
// indicating the first matching one. <end> is left at one plus the last
|
||||
// matching one.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FResourceFile::FindPrefixRange(FString filter, void *lumps, size_t lumpsize, DWORD maxlump, DWORD &start, DWORD &end)
|
||||
{
|
||||
DWORD min, max, mid, inside;
|
||||
FResourceLump *lump;
|
||||
int cmp;
|
||||
|
||||
// Pretend that our range starts at 1 instead of 0 so that we can avoid
|
||||
// unsigned overflow if the range starts at the first lump.
|
||||
lumps = (BYTE *)lumps - lumpsize;
|
||||
|
||||
// Binary search to find any match at all.
|
||||
min = 1, max = maxlump;
|
||||
while (min <= max)
|
||||
{
|
||||
mid = min + (max - min) / 2;
|
||||
lump = (FResourceLump *)((BYTE *)lumps + mid * lumpsize);
|
||||
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len());
|
||||
if (cmp == 0)
|
||||
break;
|
||||
else if (cmp < 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
max = mid - 1;
|
||||
}
|
||||
if (max < min)
|
||||
{ // matched nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
// Binary search to find first match.
|
||||
inside = mid;
|
||||
min = 1, max = mid;
|
||||
while (min <= max)
|
||||
{
|
||||
mid = min + (max - min) / 2;
|
||||
lump = (FResourceLump *)((BYTE *)lumps + mid * lumpsize);
|
||||
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len());
|
||||
// Go left on matches and right on misses.
|
||||
if (cmp == 0)
|
||||
max = mid - 1;
|
||||
else
|
||||
min = mid + 1;
|
||||
}
|
||||
start = mid + (cmp != 0) - 1;
|
||||
|
||||
// Binary search to find last match.
|
||||
min = inside, max = maxlump;
|
||||
while (min <= max)
|
||||
{
|
||||
mid = min + (max - min) / 2;
|
||||
lump = (FResourceLump *)((BYTE *)lumps + mid * lumpsize);
|
||||
cmp = lump->FullName.CompareNoCase(filter, (int)filter.Len());
|
||||
// Go right on matches and left on misses.
|
||||
if (cmp == 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
max = mid - 1;
|
||||
}
|
||||
end = mid - (cmp != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -65,9 +65,16 @@ protected:
|
|||
|
||||
FResourceFile(const char *filename, FileReader *r);
|
||||
|
||||
// for archives that can contain directories
|
||||
void PostProcessArchive(void *lumps, size_t lumpsize);
|
||||
|
||||
private:
|
||||
DWORD FirstLump;
|
||||
|
||||
int FilterLumps(FString filtername, void *lumps, size_t lumpsize, DWORD max);
|
||||
bool FindPrefixRange(FString filter, void *lumps, size_t lumpsize, DWORD max, DWORD &start, DWORD &end);
|
||||
void JunkLeftoverFilters(void *lumps, size_t lumpsize, DWORD max);
|
||||
|
||||
public:
|
||||
static FResourceFile *OpenResourceFile(const char *filename, FileReader *file, bool quiet = false);
|
||||
static FResourceFile *OpenDirectory(const char *filename, bool quiet = false);
|
||||
|
@ -76,7 +83,6 @@ public:
|
|||
DWORD LumpCount() const { return NumLumps; }
|
||||
DWORD GetFirstLump() const { return FirstLump; }
|
||||
void SetFirstLump(DWORD f) { FirstLump = f; }
|
||||
void PostProcessArchive(void *lumps, size_t lumpsize); // for archives that can contain directories
|
||||
|
||||
virtual void FindStrifeTeaserVoices ();
|
||||
virtual bool Open(bool quiet) = 0;
|
||||
|
|
|
@ -1571,3 +1571,33 @@ static void PrintLastError ()
|
|||
Printf (TEXTCOLOR_RED " %s\n", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD LumpNum
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(lumpnum)
|
||||
{
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
Printf("%s: %d\n", argv[i], Wads.CheckNumForName(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD LumpNumFull
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(lumpnumfull)
|
||||
{
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
Printf("%s: %d\n", argv[i], Wads.CheckNumForFullName(argv[i]));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -52,6 +52,8 @@ struct wadlump_t
|
|||
|
||||
// [RH] Namespaces from BOOM.
|
||||
typedef enum {
|
||||
ns_invalid = -1,
|
||||
|
||||
ns_global = 0,
|
||||
ns_sprites,
|
||||
ns_flats,
|
||||
|
|
Loading…
Reference in a new issue