Add W_CheckNumForMarkers, clean up lump validation

Fixes many cases of invalid startlumps, so validation is now actually done
only when PARANOIA is defined
The W_CheckNumFor* functions allow startlump == numlumps, to make iteration
less frustrating
This commit is contained in:
GenericHeroGuy 2025-06-27 16:32:25 +02:00
parent 286dfc7a43
commit be35926843
6 changed files with 253 additions and 356 deletions

View file

@ -9027,11 +9027,14 @@ boolean P_RunSOC(const char *socfilename)
// Auxiliary function for PK3 loading - looks for sound replacements.
// NOTE: it does not really add any new sound entry or anything.
static void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 end, size_t *sreplaces)
static void P_LoadSoundsRange(UINT16 wadnum, size_t *sreplaces)
{
sfxenum_t j;
UINT16 i;
for (i = first; i < end; i++)
UINT16 i, end;
if (!W_CheckNumForMarkers((const char *[]){"Sounds/"}, 1, wadnum, &i, &end))
return;
for (; i < end; i++)
{
// Let's check whether it's replacing an existing sound or it's a brand new one.
const char *name = W_CheckNameForNumPwad(wadnum, i);
@ -9055,10 +9058,13 @@ static void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 end, size_t *s
// Auxiliary function for PK3 loading - looks for music and music replacements.
// NOTE: does nothing but print debug messages. The code is handled somewhere else.
static void P_LoadMusicsRange(UINT16 wadnum, UINT16 first, UINT16 end, size_t *digmreplaces, size_t *mreplaces)
static void P_LoadMusicsRange(UINT16 wadnum, size_t *digmreplaces, size_t *mreplaces)
{
UINT16 i;
for (i = first; i < end; i++)
UINT16 i, end;
if (!W_CheckNumForMarkers((const char *[]){"Music/"}, 1, wadnum, &i, &end))
return;
for (; i < end; i++)
{
const char *name = W_CheckNameForNumPwad(wadnum, i);
if (name[0] == 'O' && name[1] == '_')
@ -9236,12 +9242,6 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat)
size_t sreplaces = 0, mreplaces = 0, digmreplaces = 0;
UINT16 numlumps, wadnum;
// Vars to help us with the position start and amount of each resource type.
// Useful for PK3s since they use folders.
// WADs use markers for some resources, but others such as sounds are checked lump-by-lump anyway.
UINT16 sfxPos, sfxEnd;
UINT16 musPos, musEnd;
// Init file.
if ((numlumps = W_InitFile(wadfilename, false, false, compat)) == LUMPERROR)
{
@ -9261,23 +9261,8 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, wadcompat_t compat)
}
partadd_stage = 0;
switch(wadfiles[wadnum]->type)
{
case RET_PK3:
sfxPos = W_CheckNumForFolderStartPK3("Sounds/", wadnum, 0);
sfxEnd = W_CheckNumForFolderEndPK3("Sounds/", wadnum, sfxPos);
musPos = W_CheckNumForFolderStartPK3("Music/", wadnum, 0);
musEnd = W_CheckNumForFolderEndPK3("Music/", wadnum, musPos);
break;
default:
sfxPos = musPos = 0;
sfxEnd = musEnd = numlumps;
break;
}
P_LoadSoundsRange(wadnum, sfxPos, sfxEnd, &sreplaces);
P_LoadMusicsRange(wadnum, musPos, musEnd, &digmreplaces, &mreplaces);
P_LoadSoundsRange(wadnum, &sreplaces);
P_LoadMusicsRange(wadnum, &digmreplaces, &mreplaces);
if (!devparm && sreplaces)
CONS_Printf(M_GetText("%s sounds replaced\n"), sizeu1(sreplaces));

View file

@ -648,7 +648,7 @@ void R_AddSkins(UINT16 wadnum)
// search for all skin markers in pwad
//
while ((lump = W_CheckNumForNamePrefixPwad("S_SKIN", 6, wadnum, lastlump)) != LUMPERROR)
while (lastlump != LUMPERROR && (lump = W_CheckNumForNamePrefixPwad("S_SKIN", 6, wadnum, lastlump)) != LUMPERROR)
{
// advance by default
lastlump = lump + 1;
@ -820,7 +820,7 @@ void R_PatchSkins(UINT16 wadnum)
// search for all skin patch markers in pwad
//
while ((lump = W_CheckNumForNamePrefixPwad("P_SKIN", 6, wadnum, lastlump)) != LUMPERROR)
while (lastlump != LUMPERROR && (lump = W_CheckNumForNamePrefixPwad("P_SKIN", 6, wadnum, lastlump)) != LUMPERROR)
{
INT32 skinnum = 0;

View file

@ -1117,6 +1117,11 @@ void R_FlushTextureCache(void)
int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum);
void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index);
static const char *flatmarkers[] = {
"Flats/",
"F_START", "F_END",
};
static INT32
Rloadflats (INT32 i, INT32 w)
{
@ -1126,81 +1131,74 @@ Rloadflats (INT32 i, INT32 w)
texpatch_t *patch;
UINT8 header[PNG_HEADER_SIZE];
if (wadfiles[w]->type == RET_PK3)
{
texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart);
}
else
{
texstart = W_CheckNumForLongNamePwad("F_START", (UINT16)w, 0);
if (texstart != LUMPERROR) texstart++;
texend = W_CheckNumForLongNamePwad("F_END", (UINT16)w, texstart);
}
if (!W_CheckNumForMarkers(flatmarkers, sizeof(flatmarkers)/sizeof(*flatmarkers), (UINT16)w, &texstart, &texend))
return i;
if (!( texstart == LUMPERROR || texend == LUMPERROR ))
// Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); j++)
{
// Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); j++)
UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j;
if (wadfiles[w]->type == RET_PK3)
{
UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j;
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
}
if (wadfiles[w]->type == RET_PK3)
{
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
}
size_t lumplength = W_LumpLengthPwad(wadnum, lumpnum);
size_t flatsize = R_FlatDimensionsFromLumpSize(lumplength);
size_t lumplength = W_LumpLengthPwad(wadnum, lumpnum);
size_t flatsize = R_FlatDimensionsFromLumpSize(lumplength);
//CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
//CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
// Set texture properties.
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
texture->hash = quickncasehash(texture->name, 8);
// Set texture properties.
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
texture->hash = quickncasehash(texture->name, 8);
#ifndef NO_PNG_LUMPS
W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0);
W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0);
if (Picture_IsLumpPNG(header, lumplength))
{
UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(flatlump);
}
else
#endif
texture->width = texture->height = flatsize;
texture->type = TEXTURETYPE_FLAT;
texture->patchcount = 1;
texture->holes = false;
texture->flip = 0;
texture->terrainID = K_GetTerrainIDForTextureName(texture->name);
// Allocate information for the texture's patches.
patch = &texture->patches[0];
patch->originx = patch->originy = 0;
patch->wad = (UINT16)w;
patch->lump = texstart + j;
patch->flip = 0;
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
if (Picture_IsLumpPNG(header, lumplength))
{
UINT8 *flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(flatlump);
}
else
#endif
texture->width = texture->height = flatsize;
texture->type = TEXTURETYPE_FLAT;
texture->patchcount = 1;
texture->holes = false;
texture->flip = 0;
texture->terrainID = K_GetTerrainIDForTextureName(texture->name);
// Allocate information for the texture's patches.
patch = &texture->patches[0];
patch->originx = patch->originy = 0;
patch->wad = (UINT16)w;
patch->lump = texstart + j;
patch->flip = 0;
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
}
return i;
}
static const char *texturemarkers[] = {
"Textures/",
"TX_START", "TX_END",
};
static INT32
Rloadtextures (INT32 i, INT32 w)
{
@ -1211,136 +1209,108 @@ Rloadtextures (INT32 i, INT32 w)
softwarepatch_t patchlump;
// Get the lump numbers for the markers in the WAD, if they exist.
if (!W_CheckNumForMarkers(texturemarkers, sizeof(texturemarkers)/sizeof(*texturemarkers), (UINT16)w, &texstart, &texend))
return i;
if (wadfiles[w]->type == RET_PK3)
{
texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0);
texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart);
texturesLumpPos = W_CheckNumForLongNamePwad("TEXTURES", (UINT16)w, 0);
while (texturesLumpPos != LUMPERROR)
{
for (texturesLumpPos = 0; (texturesLumpPos = W_CheckNumForLongNamePwad("TEXTURES", (UINT16)w, texturesLumpPos)) != LUMPERROR; texturesLumpPos++)
R_ParseTEXTURESLump(w, texturesLumpPos, &i);
texturesLumpPos = W_CheckNumForLongNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1);
}
}
else
{
texstart = W_CheckNumForLongNamePwad("TX_START", (UINT16)w, 0);
if (texstart != LUMPERROR) texstart++;
texend = W_CheckNumForLongNamePwad("TX_END", (UINT16)w, 0);
texturesLumpPos = W_CheckNumForLongNamePwad("TEXTURES", (UINT16)w, 0);
if (texturesLumpPos != LUMPERROR)
R_ParseTEXTURESLump(w, texturesLumpPos, &i);
}
if (!( texstart == LUMPERROR || texend == LUMPERROR ))
// Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); j++)
{
// Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); j++)
UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j;
#ifndef NO_PNG_LUMPS
size_t lumplength;
#endif
if (wadfiles[w]->type == RET_PK3)
{
UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j;
#ifndef NO_PNG_LUMPS
size_t lumplength;
#endif
if (wadfiles[w]->type == RET_PK3)
{
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
}
W_ReadLumpHeaderPwad(wadnum, lumpnum, &patchlump, PNG_HEADER_SIZE, 0);
#ifndef NO_PNG_LUMPS
lumplength = W_LumpLengthPwad(wadnum, lumpnum);
#endif
//CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
// Set texture properties.
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
texture->hash = quickncasehash(texture->name, 8);
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)&patchlump, lumplength))
{
UINT8 *png = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions(png, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(png);
}
else
#endif
{
texture->width = SHORT(patchlump.width);
texture->height = SHORT(patchlump.height);
}
texture->type = TEXTURETYPE_SINGLEPATCH;
texture->patchcount = 1;
texture->holes = false;
texture->flip = 0;
texture->terrainID = K_GetTerrainIDForTextureName(texture->name);
// Allocate information for the texture's patches.
patch = &texture->patches[0];
patch->originx = patch->originy = 0;
patch->wad = (UINT16)w;
patch->lump = texstart + j;
patch->flip = 0;
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder
continue; // If it is then SKIP IT
}
W_ReadLumpHeaderPwad(wadnum, lumpnum, &patchlump, PNG_HEADER_SIZE, 0);
#ifndef NO_PNG_LUMPS
lumplength = W_LumpLengthPwad(wadnum, lumpnum);
#endif
//CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height);
texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);
// Set texture properties.
M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name));
texture->hash = quickncasehash(texture->name, 8);
#ifndef NO_PNG_LUMPS
if (Picture_IsLumpPNG((UINT8 *)&patchlump, lumplength))
{
UINT8 *png = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE);
INT32 width, height;
Picture_PNGDimensions(png, &width, &height, NULL, NULL, lumplength);
texture->width = (INT16)width;
texture->height = (INT16)height;
Z_Free(png);
}
else
#endif
{
texture->width = SHORT(patchlump.width);
texture->height = SHORT(patchlump.height);
}
texture->type = TEXTURETYPE_SINGLEPATCH;
texture->patchcount = 1;
texture->holes = false;
texture->flip = 0;
texture->terrainID = K_GetTerrainIDForTextureName(texture->name);
// Allocate information for the texture's patches.
patch = &texture->patches[0];
patch->originx = patch->originy = 0;
patch->wad = (UINT16)w;
patch->lump = texstart + j;
patch->flip = 0;
texturewidth[i] = texture->width;
textureheight[i] = texture->height << FRACBITS;
i++;
}
return i;
}
static INT32
count_range
( const char * marker_start,
const char * marker_end,
const char * folder,
UINT16 wadnum)
static INT32 count_range(const char *markers[], size_t nummarkers, UINT16 wadnum)
{
UINT16 j;
UINT16 texstart, texend;
INT32 count = 0;
// Count flats
if (!W_CheckNumForMarkers(markers, nummarkers, wadnum, &texstart, &texend))
return count;
// PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[wadnum]->type == RET_PK3)
{
texstart = W_CheckNumForFolderStartPK3(folder, wadnum, 0);
texend = W_CheckNumForFolderEndPK3(folder, wadnum, texstart);
}
else
{
texstart = W_CheckNumForLongNamePwad(marker_start, wadnum, 0);
if (texstart != LUMPERROR) texstart++;
texend = W_CheckNumForLongNamePwad(marker_end, wadnum, texstart);
}
if (texstart != LUMPERROR && texend != LUMPERROR)
{
// PK3s have subfolders, so we can't just make a simple sum
if (wadfiles[wadnum]->type == RET_PK3)
for (j = texstart; j < texend; j++)
{
for (j = texstart; j < texend; j++)
{
if (!W_IsLumpFolder(wadnum, j)) // Check if lump is a folder; if not, then count it
count++;
}
}
else // Add all the textures between markers
{
count += (texend - texstart);
if (!W_IsLumpFolder(wadnum, j)) // Check if lump is a folder; if not, then count it
count++;
}
}
else // Add all the textures between markers
{
count += (texend - texstart);
}
return count;
}
@ -1358,14 +1328,14 @@ static INT32 R_CountTextures(UINT16 wadnum)
// This system will allocate memory for all duplicate/patched textures even if it never uses them,
// but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures.
count += count_range("F_START", "F_END", "flats/", wadnum);
count += count_range(flatmarkers, sizeof(flatmarkers)/sizeof(*flatmarkers), wadnum);
// Count the textures from TEXTURES lumps
for (texturesLumpPos = 0; (texturesLumpPos = W_CheckNumForLongNamePwad("TEXTURES", wadnum, texturesLumpPos)) != LUMPERROR; texturesLumpPos++)
count += R_CountTexturesInTEXTURESLump(wadnum, texturesLumpPos);
// Count single-patch textures
count += count_range("TX_START", "TX_END", "textures/", wadnum);
count += count_range(texturemarkers, sizeof(texturemarkers)/sizeof(*texturemarkers), wadnum);
return count;
}

View file

@ -489,6 +489,12 @@ boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16
return true;
}
static const char *spritemarkers[] = {
"Sprites/",
"S_START", "S_END",
"SS_START", "SS_END", // deutex compatib.
};
//
// Search for sprites replacements in a wad whose names are in namelist
//
@ -498,47 +504,12 @@ void R_AddSpriteDefs(UINT16 wadnum)
UINT16 start, end;
char wadname[MAX_WADPATH];
// Find the sprites section in this resource file.
switch (wadfiles[wadnum]->type)
{
case RET_WAD:
start = W_CheckNumForLongNamePwad("S_START", wadnum, 0);
if (start == LUMPERROR)
start = W_CheckNumForLongNamePwad("SS_START", wadnum, 0); //deutex compatib.
if (start != LUMPERROR) start++;
end = W_CheckNumForLongNamePwad("S_END", wadnum, start);
if (end == LUMPERROR)
end = W_CheckNumForLongNamePwad("SS_END", wadnum, start); //deutex compatib.
break;
case RET_PK3:
start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
break;
default:
return;
}
if (start == LUMPERROR)
{
// ignore skin wads (we don't want skin sprites interfering with vanilla sprites)
// G: DON'T ignore skin wads. this check did nothing because it incorrectly checked for UINT16_MAX instead of INT16_MAX
// plus, this didn't exist in kart, so it might break old WADs...
/*
if (W_CheckNumForLongNamePwad("S_SKIN", wadnum, 0) != LUMPERROR)
return;
*/
start = 0; //let say S_START is lump 0
}
if (end == LUMPERROR || start >= end)
if (!W_CheckNumForMarkers(spritemarkers, sizeof(spritemarkers)/sizeof(*spritemarkers), wadnum, &start, &end))
{
CONS_Debug(DBG_SETUP, "no sprites in pwad %d\n", wadnum);
return;
}
//
// scan through lumps, for each sprite, find all the sprite frames
//

View file

@ -332,23 +332,15 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile)
{
LUA_LoadLump(wadnum, posStart, true);
}
else
else if (W_CheckNumForMarkers((const char *[]){"Lua/"}, 1, wadnum, &posStart, &posEnd))
{
posStart = W_CheckNumForFolderStartPK3("Lua/", wadnum, 0);
if (posStart != LUMPERROR)
{
posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart);
for (; posStart < posEnd; posStart++)
LUA_LoadLump(wadnum, posStart, true);
}
for (; posStart < posEnd; posStart++)
LUA_LoadLump(wadnum, posStart, true);
}
posStart = W_CheckNumForFolderStartPK3("SOC/", wadnum, 0);
if (posStart != LUMPERROR)
if (W_CheckNumForMarkers((const char *[]){"SOC/"}, 1, wadnum, &posStart, &posEnd))
{
posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart);
for(; posStart < posEnd; posStart++)
for (; posStart < posEnd; posStart++)
{
CONS_Printf(M_GetText("Loading SOC from %s|%s\n"), wadfiles[wadnum]->filename, W_CheckFullNameForNumPwad(wadnum, posStart));
DEH_LoadDehackedLumpPwad(wadnum, posStart, mainfile);
@ -1099,22 +1091,25 @@ INT32 W_InitMultipleFiles(char **filenames, boolean addons)
return overallrc;
}
// check for a valid lump number
// lump cannot be asserted because some callers pass LUMPERROR,
// and most W_ functions previously always passed 0 for lump...
static boolean TestValidLump(UINT16 wad, UINT16 lump)
{
I_Assert(wad < numwadfiles);
return lump < wadfiles[wad]->numlumps;
}
#ifdef PARANOIA
#define TESTVALID(wad, lump) \
if (wad >= numwadfiles || lump >= wadfiles[wad]->numlumps) \
I_Error("Invalid lump number %04x:%04x", wad, lump);
// allows one past the end of the lump array to make iteration less hellish
#define TESTVALIDEND(wad, lump) \
if (wad >= numwadfiles || lump > wadfiles[wad]->numlumps) \
I_Error("Invalid lump number %04x:%04x", wad, lump);
#else
#define TESTVALID(wad, lump)
#define TESTVALIDEND(wad, lump)
#endif
// NOTE: this actually returns the longname, but since nothing relies on
// the 8-char truncation, i thought i'd save some effort :^)
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump)
{
if (!TestValidLump(wad, lump))
return NULL;
TESTVALID(wad, lump)
return strbuf_get(lumpnamebuf, wadfiles[wad]->lumpinfo[lump].longname);
}
@ -1125,9 +1120,7 @@ const char *W_CheckNameForNum(lumpnum_t lumpnum)
const char *W_CheckFullNameForNumPwad(UINT16 wad, UINT16 lump)
{
if (!TestValidLump(wad, lump))
return NULL;
TESTVALID(wad, lump)
return strbuf_get(lumpnamebuf, wadfiles[wad]->lumpinfo[lump].fullname);
}
@ -1146,21 +1139,17 @@ UINT16 W_FindNextEmptyInPwad(UINT16 wad, UINT16 startlump)
{
UINT16 i;
if (!TestValidLump(wad, startlump))
return LUMPERROR;
TESTVALIDEND(wad, startlump)
//
// scan forward
// start at 'startlump', useful parameter when there are multiple
// resources with the same name
//
if (startlump < wadfiles[wad]->numlumps)
{
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
if (!lump_p->size)
return i;
}
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
if (!lump_p->size)
return i;
// not found.
return LUMPERROR;
@ -1202,8 +1191,7 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
UINT32 hash;
char *up = uname;
if (!TestValidLump(wad, startlump))
return LUMPERROR;
TESTVALIDEND(wad, startlump)
while (*name)
*up++ = toupper(*name++);
@ -1219,8 +1207,7 @@ UINT16 W_CheckNumForNamePrefixPwad(const char *name, size_t namelen, UINT16 wad,
UINT16 i;
lumpinfo_t *lump_p;
if (!TestValidLump(wad, startlump))
return LUMPERROR;
TESTVALIDEND(wad, startlump)
// scan forward, start at <startlump>
lump_p = wadfiles[wad]->lumpinfo + startlump;
@ -1238,8 +1225,7 @@ UINT16 W_CheckNumForNameMultiPrefixPwad(const lumpprefixes_t *prefixes, size_t n
size_t j;
lumpinfo_t *lump_p;
if (!TestValidLump(wad, startlump))
return LUMPERROR;
TESTVALIDEND(wad, startlump)
// scan forward, start at <startlump>
lump_p = wadfiles[wad]->lumpinfo + startlump;
@ -1251,39 +1237,50 @@ UINT16 W_CheckNumForNameMultiPrefixPwad(const lumpprefixes_t *prefixes, size_t n
return LUMPERROR; // not found
}
// Look for the first lump from a folder.
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump)
// finds the range [start:end) of lumps within the given PK3 folder or (optionally) WAD marker names
// if wadnum is a WAD but no markers are specified, yields 0 and wad->numlumps
// returns true and sets ostart/oend if lumps were found
// [0] = PK3 folder [1], [2] = WAD start/end markers [3], [4] = secondary WAD start/end markers etc...
boolean W_CheckNumForMarkers(const char *markers[], size_t nummarkers, UINT16 wad, UINT16 *ostart, UINT16 *oend)
{
size_t name_length;
INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
name_length = strlen(name);
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
INT32 start, end;
if (wadfiles[wad]->type == RET_PK3)
{
if (strnicmp(name, strbuf_get(lumpnamebuf, lump_p->fullname), name_length) == 0)
size_t name_length = strlen(markers[0]);
for (start = 0; start < wadfiles[wad]->numlumps; start++)
if (!strncasecmp(markers[0], W_CheckFullNameForNumPwad(wad, start), name_length))
break;
if (start == wadfiles[wad]->numlumps)
return false;
for (end = start + 1; end < wadfiles[wad]->numlumps; end++)
if (strncasecmp(markers[0], W_CheckFullNameForNumPwad(wad, end), name_length))
break;
}
else if (nummarkers == 1)
{
start = 0;
end = wadfiles[wad]->numlumps;
}
else
{
size_t i;
for (i = 1; i < nummarkers; i += 2)
{
/* SLADE is special and puts a single directory entry. Skip that. */
if (strlen(strbuf_get(lumpnamebuf, lump_p->fullname)) == name_length)
i++;
start = W_CheckNumForLongNamePwad(markers[i], wad, 0);
if (start == LUMPERROR || ++start == wadfiles[wad]->numlumps)
continue;
end = W_CheckNumForLongNamePwad(markers[i+1], wad, start);
if (end == LUMPERROR)
continue;
break;
}
if (i == nummarkers)
return false;
}
return i;
}
// In a PK3 type of resource file, it looks for the next lumpinfo entry that doesn't share the specified pathfile.
// Useful for finding folder ends.
// Returns the position of the lumpinfo entry.
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
{
INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{
if (strnicmp(name, strbuf_get(lumpnamebuf, lump_p->fullname), strlen(name)))
break;
}
return i;
*ostart = (UINT16)start;
*oend = (UINT16)end;
return true;
}
// In a PK3 type of resource file, it looks for an entry with the specified full name.
@ -1292,6 +1289,7 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
{
INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{
if (!strnicmp(name, strbuf_get(lumpnamebuf, lump_p->fullname), strlen(name)))
@ -1315,8 +1313,7 @@ lumpnum_t W_CheckNumForLongName(const char *name)
char uname[MAXLUMPNAME+1];
char *up = uname;
if (name == NULL)
return LUMPERROR;
I_Assert(name != NULL);
if (!*name) // some doofus gave us an empty string?
return LUMPERROR;
@ -1388,19 +1385,7 @@ lumpnum_t W_CheckNumForMap(const char *name)
for (i = numwadfiles - 1; i >= 0; i--)
{
UINT16 start, end;
switch (wadfiles[i]->type)
{
case RET_PK3:
start = W_CheckNumForFolderStartPK3("Maps/", i, 0);
end = W_CheckNumForFolderEndPK3("Maps/", i, start);
break;
default:
start = 0;
end = wadfiles[i]->numlumps;
break;
}
if (start == LUMPERROR || end == LUMPERROR)
if (!W_CheckNumForMarkers((const char *[]){"Maps/"}, 1, i, &start, &end))
continue;
retry:
@ -1454,31 +1439,22 @@ lumpnum_t W_GetNumForLongName(const char *name)
lumpnum_t W_CheckNumForNameInFolder(const char *lump, const char *folder)
{
INT32 i;
lumpnum_t fsid, feid;
UINT16 fsid, feid;
lumpnum_t check = LUMPERROR;
// scan wad files backwards so patch lump files take precedence
for (i = numwadfiles - 1; i >= 0; i--)
{
if (wadfiles[i]->type == RET_PK3)
if (wadfiles[i]->type != RET_PK3)
continue;
if (!W_CheckNumForMarkers(&folder, 1, i, &fsid, &feid))
continue;
check = W_CheckNumForLongNamePwad(lump, (UINT16)i, fsid);
if (check < feid)
{
fsid = W_CheckNumForFolderStartPK3(folder, (UINT16)i, 0);
if (fsid == LUMPERROR)
{
continue; // Start doesn't exist?
}
feid = W_CheckNumForFolderEndPK3(folder, (UINT16)i, fsid);
if (feid == LUMPERROR)
{
continue; // End doesn't exist?
}
check = W_CheckNumForLongNamePwad(lump, (UINT16)i, fsid);
if (check < feid)
{
return (i<<16) + check; // found it, in our constraints
}
return (i<<16) + check; // found it, in our constraints
}
}
@ -1502,8 +1478,7 @@ UINT8 W_LumpExists(const char *name)
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
{
if (!TestValidLump(wad, lump))
return 0;
TESTVALID(wad, lump)
return wadfiles[wad]->lumpinfo[lump].size;
}
@ -1617,8 +1592,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
lumpinfo_t *l;
FILE *handle;
if (!TestValidLump(wad,lump))
return 0;
TESTVALID(wad, lump)
lumpsize = wadfiles[wad]->lumpinfo[lump].size;
// empty resource (usually markers like S_START, F_END ..)
@ -1782,8 +1756,7 @@ void *W_CacheLumpNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
lumpcache_t *lumpcache;
if (!TestValidLump(wad,lump))
return NULL;
TESTVALID(wad, lump)
lumpcache = wadfiles[wad]->lumpcache;
if (!lumpcache[lump])
@ -1815,8 +1788,7 @@ void *W_CacheLumpNumForce(lumpnum_t lumpnum, INT32 tag)
wad = WADFILENUM(lumpnum);
lump = LUMPNUM(lumpnum);
if (!TestValidLump(wad,lump))
return NULL;
TESTVALID(wad, lump)
ptr = Z_Malloc(W_LumpLengthPwad(wad, lump), tag, NULL);
W_ReadLumpHeaderPwad(wad, lump, ptr, 0, 0); // read the lump in full
@ -1835,8 +1807,7 @@ static inline boolean W_IsLumpCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
{
void *lcache;
if (!TestValidLump(wad, lump))
return false;
TESTVALID(wad, lump)
lcache = wadfiles[wad]->lumpcache[lump];
@ -1867,8 +1838,7 @@ static inline boolean W_IsPatchCachedPWAD(UINT16 wad, UINT16 lump, void *ptr)
{
void *lcache;
if (!TestValidLump(wad, lump))
return false;
TESTVALID(wad, lump)
lcache = wadfiles[wad]->patchcache[lump];
@ -1929,8 +1899,7 @@ void *W_CacheSoftwarePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
lumpcache_t *lumpcache = NULL;
if (!TestValidLump(wad, lump))
return NULL;
TESTVALID(wad, lump)
lumpcache = wadfiles[wad]->patchcache;
@ -1960,8 +1929,7 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag)
{
patch_t *patch;
if (!TestValidLump(wad, lump))
return NULL;
TESTVALID(wad, lump)
patch = W_CacheSoftwarePatchNumPwad(wad, lump, tag);
@ -2405,17 +2373,20 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum)
{
// Count number of lumps until the end of resource OR up until next 0-length lump.
lumpnum_t lumppos = lumpnum + 1;
lumpnum_t lastlump = wadfiles[WADFILENUM(lumpnum)]->numlumps;
UINT16 wad = WADFILENUM(lumpnum);
UINT16 lastlump = wadfiles[wad]->numlumps;
// or the end of directory, for PK3 files
if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3)
{
const char *fullname = W_CheckFullNameForNum(lumpnum);
const char *dirend = strrchr(fullname, '/');
char *dirname = malloc(dirend - fullname + 2);
strlcpy(dirname, fullname, dirend - fullname + 2);
lastlump = W_CheckNumForFolderEndPK3(dirname, WADFILENUM(lumpnum), lumpnum);
free(dirname);
size_t dirlen = dirend - fullname + 1;
for (lastlump = LUMPNUM(lumppos); lastlump < wadfiles[wad]->numlumps; lastlump++)
if (strnicmp(fullname, W_CheckFullNameForNumPwad(wad, lastlump), dirlen))
break;
}
for (i = LUMPNUM(lumppos); i < lastlump; i++, lumppos++, numlumps++)
{
if (W_LumpLength(lumppos) > 0)

View file

@ -127,9 +127,9 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
UINT16 W_CheckNumForNamePrefixPwad(const char *name, size_t namelen, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForNameMultiPrefixPwad(const lumpprefixes_t *prefixes, size_t numprefixes, UINT16 wad, UINT16 startlump);
boolean W_CheckNumForMarkers(const char *markers[], size_t nummarkers, UINT16 wad, UINT16 *ostart, UINT16 *oend);
UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump);
lumpnum_t W_CheckNumForMap(const char *name);
lumpnum_t W_CheckNumForLongName(const char *name);