Merge branch 'futurepk3' into 'next'

Backport SRB2 2.2's PK3 loader code fixes

See merge request KartKrew/Kart-Public!289
This commit is contained in:
Sal 2022-08-28 09:23:16 +00:00
commit d9f4bd6111
4 changed files with 504 additions and 133 deletions

View file

@ -204,9 +204,9 @@ void LUA_LoadLump(UINT16 wad, UINT16 lump)
else // If it's not a .lua file, copy the lump name in too. else // If it's not a .lua file, copy the lump name in too.
{ {
lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump]; lumpinfo_t *lump_p = &wadfiles[wad]->lumpinfo[lump];
len += 1 + strlen(lump_p->name2); // length of file name, '|', and lump name len += 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
name = malloc(len+1); name = malloc(len+1);
sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->name2); sprintf(name, "%s|%s", wadfiles[wad]->filename, lump_p->fullname);
name[len] = '\0'; name[len] = '\0';
} }

View file

@ -428,16 +428,26 @@ void R_LoadTextures(void)
// Add all the textures between TX_START and TX_END // Add all the textures between TX_START and TX_END
if (texstart != INT16_MAX && texend != INT16_MAX) if (texstart != INT16_MAX && texend != INT16_MAX)
{
// PK3s have subfolders, so we can't just make a simple sum
if (W_FileHasFolders(wadfiles[w]))
{
for (j = texstart; j < texend; j++)
{
if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it
numtextures++;
}
}
else
{ {
numtextures += (UINT32)(texend - texstart); numtextures += (UINT32)(texend - texstart);
} }
}
}
// If no textures found by this point, bomb out // If no textures found by this point, bomb out
if (!numtextures && w == (numwadfiles - 1)) if (!numtextures)
{
I_Error("No textures detected in any WADs!\n"); I_Error("No textures detected in any WADs!\n");
}
}
// Allocate memory and initialize to 0 for all the textures we are initialising. // Allocate memory and initialize to 0 for all the textures we are initialising.
// There are actually 5 buffers allocated in one for convenience. // There are actually 5 buffers allocated in one for convenience.
@ -484,8 +494,13 @@ void R_LoadTextures(void)
continue; continue;
// Work through each lump between the markers in the WAD. // Work through each lump between the markers in the WAD.
for (j = 0; j < (texend - texstart); i++, j++) for (j = 0; j < (texend - texstart); j++)
{ {
if (W_FileHasFolders(wadfiles[w]))
{
if (W_IsLumpFolder(w, texstart + j)) // Check if lump is a folder
continue; // If it is then SKIP IT
}
patchlump = W_CacheLumpNumPwad((UINT16)w, texstart + j, PU_CACHE); patchlump = W_CacheLumpNumPwad((UINT16)w, texstart + j, PU_CACHE);
// Then, check the lump directly to see if it's a texture SOC, // Then, check the lump directly to see if it's a texture SOC,
@ -524,6 +539,7 @@ void R_LoadTextures(void)
texturewidthmask[i] = k - 1; texturewidthmask[i] = k - 1;
textureheight[i] = texture->height << FRACBITS; textureheight[i] = texture->height << FRACBITS;
} }
i++;
} }
} }
} }

View file

@ -53,6 +53,7 @@
#include "fastcmp.h" #include "fastcmp.h"
#include "g_game.h" // G_LoadGameData #include "g_game.h" // G_LoadGameData
#include "d_main.h"
#include "filesrch.h" #include "filesrch.h"
#include "i_time.h" #include "i_time.h"
@ -97,7 +98,7 @@ typedef struct
typedef struct lumpnum_cache_s typedef struct lumpnum_cache_s
{ {
char lumpname[8]; char lumpname[32];
lumpnum_t lumpnum; lumpnum_t lumpnum;
} lumpnum_cache_t; } lumpnum_cache_t;
@ -119,12 +120,17 @@ void W_Shutdown(void)
{ {
while (numwadfiles--) while (numwadfiles--)
{ {
fclose(wadfiles[numwadfiles]->handle); wadfile_t *wad = wadfiles[numwadfiles];
Z_Free(wadfiles[numwadfiles]->filename);
while (wadfiles[numwadfiles]->numlumps--) if (wad->handle)
Z_Free(wadfiles[numwadfiles]->lumpinfo[wadfiles[numwadfiles]->numlumps].name2); fclose(wad->handle);
Z_Free(wadfiles[numwadfiles]->lumpinfo); Z_Free(wad->filename);
Z_Free(wadfiles[numwadfiles]); while (wad->numlumps--) {
Z_Free(wad->lumpinfo[wad->numlumps].longname);
Z_Free(wad->lumpinfo[wad->numlumps].fullname);
}
Z_Free(wad->lumpinfo);
Z_Free(wad);
} }
} }
@ -195,7 +201,6 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum)
if (posStart != INT16_MAX) if (posStart != INT16_MAX)
{ {
posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart); posEnd = W_CheckNumForFolderEndPK3("Lua/", wadnum, posStart);
posStart++;
for (; posStart < posEnd; posStart++) for (; posStart < posEnd; posStart++)
LUA_LoadLump(wadnum, posStart); LUA_LoadLump(wadnum, posStart);
} }
@ -205,13 +210,12 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum)
if (posStart != INT16_MAX) if (posStart != INT16_MAX)
{ {
posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart); posEnd = W_CheckNumForFolderEndPK3("SOC/", wadnum, posStart);
posStart++;
for(; posStart < posEnd; posStart++) for(; posStart < posEnd; posStart++)
{ {
lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart]; lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart];
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(length + 1); char *name = malloc(length + 1);
sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
name[length] = '\0'; name[length] = '\0';
CONS_Printf(M_GetText("Loading SOC from %s\n"), name); CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
DEH_LoadDehackedLumpPwad(wadnum, posStart); DEH_LoadDehackedLumpPwad(wadnum, posStart);
@ -240,9 +244,9 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum)
for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++) for (lump = 0; lump < wadfiles[wadnum]->numlumps; lump++, lump_p++)
if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump
{ // shameless copy+paste of code from LUA_LoadLump { // shameless copy+paste of code from LUA_LoadLump
size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->name2); // length of file name, '|', and lump name size_t length = strlen(wadfiles[wadnum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
char *name = malloc(length + 1); char *name = malloc(length + 1);
sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->name2); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname);
name[length] = '\0'; name[length] = '\0';
CONS_Printf(M_GetText("Loading SOC from %s\n"), name); CONS_Printf(M_GetText("Loading SOC from %s\n"), name);
@ -339,16 +343,16 @@ static restype_t ResourceFileDetect (const char* filename)
static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const char* lumpname) static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const char* lumpname)
{ {
lumpinfo_t* lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); lumpinfo_t* lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL);
lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL);
lumpinfo->position = 0; lumpinfo->position = 0;
fseek(handle, 0, SEEK_END); fseek(handle, 0, SEEK_END);
lumpinfo->size = ftell(handle); lumpinfo->size = ftell(handle);
fseek(handle, 0, SEEK_SET); fseek(handle, 0, SEEK_SET);
strcpy(lumpinfo->name, lumpname); strlcpy(lumpinfo->name, lumpname, 9);
// Allocate the lump's full name.
lumpinfo->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); // Allocate the lump's full and long name.
strcpy(lumpinfo->name2, lumpname); lumpinfo->fullname = Z_StrDup(lumpname);
lumpinfo->name2[8] = '\0'; lumpinfo->longname = Z_StrDup(lumpname);
*numlumps = 1; *numlumps = 1;
return lumpinfo; return lumpinfo;
} }
@ -435,10 +439,16 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen
lump_p->compression = CM_NOCOMPRESSION; lump_p->compression = CM_NOCOMPRESSION;
memset(lump_p->name, 0x00, 9); memset(lump_p->name, 0x00, 9);
strncpy(lump_p->name, fileinfo->name, 8); strncpy(lump_p->name, fileinfo->name, 8);
// Allocate the lump's long name.
lump_p->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->longname, fileinfo->name, 8);
lump_p->longname[8] = '\0';
// Allocate the lump's full name. // Allocate the lump's full name.
lump_p->name2 = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL);
strncpy(lump_p->name2, fileinfo->name, 8); strncpy(lump_p->fullname, fileinfo->name, 8);
lump_p->name2[8] = '\0'; lump_p->fullname[8] = '\0';
} }
free(fileinfov); free(fileinfov);
*nlmp = numlumps; *nlmp = numlumps;
@ -529,8 +539,8 @@ typedef struct zlentry_s
static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
{ {
zend_t zend; zend_t zend;
zentry_t* zentries; zentry_t zentry;
zentry_t* zentry; zlentry_t zlentry;
UINT16 numlumps = *nlmp; UINT16 numlumps = *nlmp;
lumpinfo_t* lumpinfo; lumpinfo_t* lumpinfo;
@ -558,40 +568,36 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
numlumps = zend.entries; numlumps = zend.entries;
lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL);
zentry = zentries = malloc(numlumps * sizeof (*zentries));
fseek(handle, zend.cdiroffset, SEEK_SET); fseek(handle, zend.cdiroffset, SEEK_SET);
for (i = 0; i < numlumps; i++, zentry++, lump_p++) for (i = 0; i < numlumps; i++, lump_p++)
{ {
char* fullname; char* fullname;
char* trimname; char* trimname;
char* dotpos; char* dotpos;
if (fread(zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t)) if (fread(&zentry, 1, sizeof(zentry_t), handle) < sizeof(zentry_t))
{ {
CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle));
Z_Free(lumpinfo); Z_Free(lumpinfo);
free(zentry);
return NULL; return NULL;
} }
if (memcmp(zentry->signature, pat_central, 4)) if (memcmp(zentry.signature, pat_central, 4))
{ {
CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); CONS_Alert(CONS_ERROR, "Central directory is corrupt\n");
Z_Free(lumpinfo); Z_Free(lumpinfo);
free(zentry);
return NULL; return NULL;
} }
lump_p->position = zentry->offset + zentry->namelen + zentry->xtralen + sizeof(zlentry_t); lump_p->position = zentry.offset; // NOT ACCURATE YET: we still need to read the local entry to find our true position
lump_p->disksize = zentry->compsize; lump_p->disksize = zentry.compsize;
lump_p->size = zentry->size; lump_p->size = zentry.size;
fullname = malloc(zentry->namelen + 1); fullname = malloc(zentry.namelen + 1);
if (fgets(fullname, zentry->namelen + 1, handle) != fullname) if (fgets(fullname, zentry.namelen + 1, handle) != fullname)
{ {
CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle));
Z_Free(lumpinfo); Z_Free(lumpinfo);
free(zentry);
free(fullname); free(fullname);
return NULL; return NULL;
} }
@ -608,10 +614,13 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary? memset(lump_p->name, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
strncpy(lump_p->name, trimname, min(8, dotpos - trimname)); strncpy(lump_p->name, trimname, min(8, dotpos - trimname));
lump_p->name2 = Z_Calloc(zentry->namelen + 1, PU_STATIC, NULL); lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL);
strncpy(lump_p->name2, fullname, zentry->namelen); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1);
switch(zentry->compression) lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL);
strncpy(lump_p->fullname, fullname, zentry.namelen);
switch(zentry.compression)
{ {
case 0: case 0:
lump_p->compression = CM_NOCOMPRESSION; lump_p->compression = CM_NOCOMPRESSION;
@ -629,14 +638,47 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp)
lump_p->compression = CM_UNSUPPORTED; lump_p->compression = CM_UNSUPPORTED;
break; break;
} }
free(fullname); free(fullname);
// skip and ignore comments/extra fields
if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
{
CONS_Alert(CONS_ERROR, "Central directory is corrupt\n");
Z_Free(lumpinfo);
return NULL;
}
}
// Adjust lump position values properly
for (i = 0, lump_p = lumpinfo; i < numlumps; i++, lump_p++)
{
// skip and ignore comments/extra fields
if ((fseek(handle, lump_p->position, SEEK_SET) != 0) || (fread(&zlentry, 1, sizeof(zlentry_t), handle) < sizeof(zlentry_t)))
{
CONS_Alert(CONS_ERROR, "Local headers for lump %s are corrupt\n", lump_p->fullname);
Z_Free(lumpinfo);
return NULL;
}
lump_p->position += sizeof(zlentry_t) + zlentry.namelen + zlentry.xtralen;
} }
*nlmp = numlumps; *nlmp = numlumps;
return lumpinfo; return lumpinfo;
} }
static void W_ReadFileShaders(wadfile_t *wadfile)
{
#ifdef HWRENDER
if (rendermode == render_opengl)
{
HWR_LoadShaders(numwadfiles - 1, W_FileHasFolders(wadfile));
}
#else
(void)wadfile;
#endif
}
// Allocate a wadfile, setup the lumpinfo (directory) and // Allocate a wadfile, setup the lumpinfo (directory) and
// lumpcache, add the wadfile to the current active wadfiles // lumpcache, add the wadfile to the current active wadfiles
// //
@ -768,10 +810,8 @@ UINT16 W_InitFile(const char *filename)
wadfiles[numwadfiles] = wadfile; wadfiles[numwadfiles] = wadfile;
numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded numwadfiles++; // must come BEFORE W_LoadDehackedLumps, so any addfile called by COM_BufInsertText called by Lua doesn't overwrite what we just loaded
#ifdef HWRENDER // Read shaders from file
if (rendermode == render_opengl) W_ReadFileShaders(wadfile);
HWR_LoadShaders(numwadfiles - 1, (wadfile->type == RET_PK3));
#endif
// TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now. // TODO: HACK ALERT - Load Lua & SOC stuff right here. I feel like this should be out of this place, but... Let's stick with this for now.
switch (wadfile->type) switch (wadfile->type)
@ -912,14 +952,13 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump)
UINT16 i; UINT16 i;
static char uname[9]; static char uname[9];
memset(uname, 0x00, sizeof uname);
strncpy(uname, name, 8);
uname[8] = 0;
strupr(uname);
if (!TestValidLump(wad,0)) if (!TestValidLump(wad,0))
return INT16_MAX; return INT16_MAX;
memset(uname, 0, sizeof uname);
strncpy(uname, name, sizeof(uname)-1);
strupr(uname);
// //
// scan forward // scan forward
// start at 'startlump', useful parameter when there are multiple // start at 'startlump', useful parameter when there are multiple
@ -929,26 +968,75 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump)
{ {
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{ if (memcmp(lump_p->name, uname, sizeof(uname) - 1) == 0)
if (memcmp(lump_p->name,uname,8) == 0)
return i; return i;
} }
}
// not found. // not found.
return INT16_MAX; return INT16_MAX;
} }
//
// Like W_CheckNumForNamePwad, but can find entries with long names
//
// Should be the only version, but that's not possible until we fix
// all the instances of non null-terminated strings in the codebase...
//
UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump)
{
UINT16 i;
static char uname[256 + 1];
if (!TestValidLump(wad,0))
return INT16_MAX;
strlcpy(uname, name, sizeof uname);
strupr(uname);
//
// 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 (!strcmp(lump_p->longname, uname))
return i;
}
// not found.
return INT16_MAX;
}
UINT16
W_CheckNumForMarkerStartPwad (const char *name, UINT16 wad, UINT16 startlump)
{
UINT16 marker;
marker = W_CheckNumForNamePwad(name, wad, startlump);
if (marker != INT16_MAX)
marker++; // Do not count the first marker
return marker;
}
// Look for the first lump from a folder. // Look for the first lump from a folder.
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump) UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump)
{ {
size_t name_length;
INT32 i; INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
name_length = strlen(name);
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{ {
if (strnicmp(name, lump_p->name2, strlen(name)) == 0) if (strnicmp(name, lump_p->fullname, name_length) == 0)
{
/* SLADE is special and puts a single directory entry. Skip that. */
if (strlen(lump_p->fullname) == name_length)
i++;
break; break;
} }
}
return i; return i;
} }
@ -959,9 +1047,10 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
{ {
INT32 i; INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
size_t name_length = strlen(name);
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{ {
if (strnicmp(name, lump_p->name2, strlen(name))) if (strnicmp(name, lump_p->fullname, name_length))
break; break;
} }
return i; return i;
@ -973,9 +1062,10 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump)
{ {
INT32 i; INT32 i;
lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump;
size_t name_length = strlen(name);
for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++)
{ {
if (!strnicmp(name, lump_p->name2, strlen(name))) if (!strnicmp(name, lump_p->fullname, name_length))
{ {
return i; return i;
} }
@ -993,11 +1083,15 @@ lumpnum_t W_CheckNumForName(const char *name)
INT32 i; INT32 i;
lumpnum_t check = INT16_MAX; lumpnum_t check = INT16_MAX;
if (!*name) // some doofus gave us an empty string?
return LUMPERROR;
// Check the lumpnumcache first. Loop backwards so that we check // Check the lumpnumcache first. Loop backwards so that we check
// most recent entries first // most recent entries first
for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
{ {
if (strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8]
&& strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0)
{ {
lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
return lumpnumcache[lumpnumcacheindex].lumpnum; return lumpnumcache[lumpnumcacheindex].lumpnum;
@ -1017,6 +1111,7 @@ lumpnum_t W_CheckNumForName(const char *name)
{ {
// Update the cache. // Update the cache.
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8); strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check; lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check;
@ -1024,6 +1119,58 @@ lumpnum_t W_CheckNumForName(const char *name)
} }
} }
//
// Like W_CheckNumForName, but can find entries with long names
//
// Should be the only version, but that's not possible until we fix
// all the instances of non null-terminated strings in the codebase...
//
lumpnum_t W_CheckNumForLongName(const char *name)
{
INT32 i;
lumpnum_t check = INT16_MAX;
if (!*name) // some doofus gave us an empty string?
return LUMPERROR;
// Check the lumpnumcache first. Loop backwards so that we check
// most recent entries first
for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--)
{
if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0)
{
lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1);
return lumpnumcache[lumpnumcacheindex].lumpnum;
}
}
if (check == INT16_MAX)
{
// scan wad files backwards so patch lump files take precedence
for (i = numwadfiles - 1; i >= 0; i--)
{
check = W_CheckNumForLongNamePwad(name,(UINT16)i,0);
if (check != INT16_MAX)
break; //found it
}
}
if (check == INT16_MAX) return LUMPERROR;
else
{
if (strlen(name) < 32)
{
// Update the cache.
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32);
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32);
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
}
return (i << 16) + check;
}
}
// Look for valid map data through all added files in descendant order. // Look for valid map data through all added files in descendant order.
// Get a map marker for WADs, and a standalone WAD file lump inside PK3s. // Get a map marker for WADs, and a standalone WAD file lump inside PK3s.
// TODO: Make it search through cache first, maybe...? // TODO: Make it search through cache first, maybe...?
@ -1047,11 +1194,15 @@ lumpnum_t W_CheckNumForMap(const char *name)
else else
continue; continue;
// Now look for the specified map. // Now look for the specified map.
for (++lumpNum; lumpNum < end; lumpNum++) for (; lumpNum < end; lumpNum++)
if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8)) if (!strnicmp(name, (wadfiles[i]->lumpinfo + lumpNum)->name, 8))
{
const char *extension = strrchr(wadfiles[i]->lumpinfo[lumpNum].fullname, '.');
if (!(extension && stricmp(extension, ".wad")))
return (i<<16) + lumpNum; return (i<<16) + lumpNum;
} }
} }
}
return LUMPERROR; return LUMPERROR;
} }
@ -1072,6 +1223,24 @@ lumpnum_t W_GetNumForName(const char *name)
return i; return i;
} }
//
// Like W_GetNumForName, but can find entries with long names
//
// Should be the only version, but that's not possible until we fix
// all the instances of non null-terminated strings in the codebase...
//
lumpnum_t W_GetNumForLongName(const char *name)
{
lumpnum_t i;
i = W_CheckNumForLongName(name);
if (i == LUMPERROR)
I_Error("W_GetNumForLongName: %s not found!\n", name);
return i;
}
// //
// W_CheckNumForNameInBlock // W_CheckNumForNameInBlock
// Checks only in blocks from blockstart lump to blockend lump // Checks only in blocks from blockstart lump to blockend lump
@ -1142,7 +1311,7 @@ boolean W_IsLumpWad(lumpnum_t lumpnum)
{ {
if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3) if (wadfiles[WADFILENUM(lumpnum)]->type == RET_PK3)
{ {
const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->name2; const char *lumpfullName = (wadfiles[WADFILENUM(lumpnum)]->lumpinfo + LUMPNUM(lumpnum))->fullname;
if (strlen(lumpfullName) < 4) if (strlen(lumpfullName) < 4)
return false; // can't possibly be a WAD can it? return false; // can't possibly be a WAD can it?
@ -1152,6 +1321,22 @@ boolean W_IsLumpWad(lumpnum_t lumpnum)
return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned return false; // WADs should never be inside non-PK3s as far as SRB2 is concerned
} }
//
// W_IsLumpFolder
// Is the lump a folder? (not in a WAD obviously)
//
boolean W_IsLumpFolder(UINT16 wad, UINT16 lump)
{
if (W_FileHasFolders(wadfiles[wad]))
{
const char *name = wadfiles[wad]->lumpinfo[lump].fullname;
return (name[strlen(name)-1] == '/'); // folders end in '/'
}
return false; // WADs don't have folders
}
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
/* report a zlib or i/o error */ /* report a zlib or i/o error */
void zerr(int ret) void zerr(int ret)
@ -1238,7 +1423,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
#ifdef NO_PNG_LUMPS #ifdef NO_PNG_LUMPS
{ {
size_t bytesread = fread(dest, 1, size, handle); size_t bytesread = fread(dest, 1, size, handle);
ErrorIfPNG(dest, bytesread, wadfiles[wad]->filename, l->name2); ErrorIfPNG(dest, bytesread, wadfiles[wad]->filename, l->fullname);
return bytesread; return bytesread;
} }
#else #else
@ -1279,7 +1464,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
Z_Free(rawData); Z_Free(rawData);
Z_Free(decData); Z_Free(decData);
#ifdef NO_PNG_LUMPS #ifdef NO_PNG_LUMPS
ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->name2); ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->fullname);
#endif #endif
return size; return size;
#else #else
@ -1341,7 +1526,7 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si
Z_Free(decData); Z_Free(decData);
#ifdef NO_PNG_LUMPS #ifdef NO_PNG_LUMPS
ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->name2); ErrorIfPNG(dest, size, wadfiles[wad]->filename, l->fullname);
#endif #endif
return size; return size;
} }
@ -1525,6 +1710,9 @@ void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag)
void W_UnlockCachedPatch(void *patch) void W_UnlockCachedPatch(void *patch)
{ {
if (!patch)
return;
// The hardware code does its own memory management, as its patches // The hardware code does its own memory management, as its patches
// have different lifetimes from software's. // have different lifetimes from software's.
#ifdef HWRENDER #ifdef HWRENDER
@ -1618,41 +1806,39 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5)
#endif #endif
} }
// Note: This never opens lumps themselves and therefore doesn't have to // Verify versions for different archive
// deal with compressed lumps. // formats. checklist assumed to be valid.
static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
boolean status) static int
W_VerifyName (const char *name, lumpchecklist_t *checklist, boolean status)
{
size_t j;
for (j = 0; checklist[j].len && checklist[j].name; ++j)
{
if (( strncasecmp(name, checklist[j].name,
checklist[j].len) != false ) == status)
{
return true;
}
}
return false;
}
static int W_VerifyWAD(FILE *fp, lumpchecklist_t *checklist, boolean status)
{ {
FILE *handle;
size_t i, j; size_t i, j;
int goodfile = false; // if we're here it's a WAD file
if (!checklist)
I_Error("No checklist for %s\n", filename);
// open wad file
if ((handle = W_OpenWadFile(&filename, false)) == NULL)
return -1;
// detect wad file by the absence of the other supported extensions
if (stricmp(&filename[strlen(filename) - 4], ".soc")
#ifdef HAVE_BLUA
&& stricmp(&filename[strlen(filename) - 4], ".lua")
#endif
&& stricmp(&filename[strlen(filename) - 4], ".pk3"))
{
// assume wad file
wadinfo_t header; wadinfo_t header;
filelump_t lumpinfo; filelump_t lumpinfo;
// read the header // read the header
if (fread(&header, 1, sizeof header, handle) == sizeof header if (fread(&header, 1, sizeof header, fp) == sizeof header
&& header.numlumps < INT16_MAX && header.numlumps < INT16_MAX
&& strncmp(header.identification, "ZWAD", 4) && strncmp(header.identification, "ZWAD", 4)
&& strncmp(header.identification, "IWAD", 4) && strncmp(header.identification, "IWAD", 4)
&& strncmp(header.identification, "PWAD", 4) && strncmp(header.identification, "PWAD", 4)
&& strncmp(header.identification, "SDLL", 4)) && strncmp(header.identification, "SDLL", 4))
{ {
fclose(handle);
return true; return true;
} }
@ -1660,21 +1846,14 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
header.infotableofs = LONG(header.infotableofs); header.infotableofs = LONG(header.infotableofs);
// let seek to the lumpinfo list // let seek to the lumpinfo list
if (fseek(handle, header.infotableofs, SEEK_SET) == -1) if (fseek(fp, header.infotableofs, SEEK_SET) == -1)
{ return true;
fclose(handle);
return false;
}
goodfile = true;
for (i = 0; i < header.numlumps; i++) for (i = 0; i < header.numlumps; i++)
{ {
// fill in lumpinfo for this wad file directory // fill in lumpinfo for this wad file directory
if (fread(&lumpinfo, sizeof (lumpinfo), 1 , handle) != 1) if (fread(&lumpinfo, sizeof (lumpinfo), 1 , fp) != 1)
{
fclose(handle);
return -1; return -1;
}
lumpinfo.filepos = LONG(lumpinfo.filepos); lumpinfo.filepos = LONG(lumpinfo.filepos);
lumpinfo.size = LONG(lumpinfo.size); lumpinfo.size = LONG(lumpinfo.size);
@ -1683,16 +1862,182 @@ static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
continue; continue;
for (j = 0; j < NUMSPRITES; j++) for (j = 0; j < NUMSPRITES; j++)
if (sprnames[j][0] && !strncmp(lumpinfo.name, sprnames[j], 4)) // Sprites if (sprnames[j] && !strncmp(lumpinfo.name, sprnames[j], 4)) // Sprites
continue; continue;
goodfile = false; if (! W_VerifyName(lumpinfo.name, checklist, status))
for (j = 0; checklist[j].len && checklist[j].name && !goodfile; j++) return false;
if ((strncmp(lumpinfo.name, checklist[j].name, checklist[j].len) != false) == status) }
goodfile = true; return true;
}
if (!goodfile) // List of blacklisted folders to use when checking the PK3
break; static lumpchecklist_t folderblacklist[] =
{
{"Lua/", 4},
{"SOC/", 4},
{"Sprites/", 8},
{"Textures/", 9},
{"Patches/", 8},
{"Flats/", 6},
{"Fades/", 6},
{NULL, 0},
};
static int
W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status)
{
int verified = true;
zend_t zend;
zentry_t zentry;
zlentry_t zlentry;
long file_size;/* size of zip file */
long data_size;/* size of data inside zip file */
long old_position;
UINT16 numlumps;
size_t i;
char pat_central[] = {0x50, 0x4b, 0x01, 0x02, 0x00};
char pat_end[] = {0x50, 0x4b, 0x05, 0x06, 0x00};
char lumpname[9];
// Haha the ResGetLumpsZip function doesn't
// check for file errors, so neither will I.
// Central directory bullshit
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
if (!ResFindSignature(fp, pat_end, max(0, ftell(fp) - (22 + 65536))))
return true;
fseek(fp, -4, SEEK_CUR);
if (fread(&zend, 1, sizeof zend, fp) < sizeof zend)
return true;
data_size = sizeof zend;
numlumps = zend.entries;
fseek(fp, zend.cdiroffset, SEEK_SET);
for (i = 0; i < numlumps; i++)
{
char* fullname;
char* trimname;
char* dotpos;
if (fread(&zentry, 1, sizeof(zentry_t), fp) < sizeof(zentry_t))
return true;
if (memcmp(zentry.signature, pat_central, 4))
return true;
if (verified == true)
{
fullname = malloc(zentry.namelen + 1);
if (fgets(fullname, zentry.namelen + 1, fp) != fullname)
{
free(fullname);
return true;
}
// Strip away file address and extension for the 8char name.
if ((trimname = strrchr(fullname, '/')) != 0)
trimname++;
else
trimname = fullname; // Care taken for root files.
if (*trimname) // Ignore directories, well kinda
{
if ((dotpos = strrchr(trimname, '.')) == 0)
dotpos = fullname + strlen(fullname); // Watch for files without extension.
memset(lumpname, '\0', 9); // Making sure they're initialized to 0. Is it necessary?
strncpy(lumpname, trimname, min(8, dotpos - trimname));
if (! W_VerifyName(lumpname, checklist, status))
verified = false;
// Check for directories next, if it's blacklisted it will return false
else if (W_VerifyName(fullname, folderblacklist, status))
verified = false;
}
free(fullname);
// skip and ignore comments/extra fields
if (fseek(fp, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
return true;
}
else
{
if (fseek(fp, zentry.namelen + zentry.xtralen + zentry.commlen, SEEK_CUR) != 0)
return true;
}
data_size +=
sizeof zentry + zentry.namelen + zentry.xtralen + zentry.commlen;
old_position = ftell(fp);
if (fseek(fp, zentry.offset, SEEK_SET) != 0)
return true;
if (fread(&zlentry, 1, sizeof(zlentry_t), fp) < sizeof (zlentry_t))
return true;
data_size +=
sizeof zlentry + zlentry.namelen + zlentry.xtralen + zlentry.compsize;
fseek(fp, old_position, SEEK_SET);
}
if (data_size < file_size)
{
const char * error = "ZIP file has holes (%ld extra bytes)\n";
CONS_Alert(CONS_ERROR, error, (file_size - data_size));
return -1;
}
else if (data_size > file_size)
{
const char * error = "Reported size of ZIP file contents exceeds file size (%ld extra bytes)\n";
CONS_Alert(CONS_ERROR, error, (data_size - file_size));
return -1;
}
else
{
return verified;
}
}
// Note: This never opens lumps themselves and therefore doesn't have to
// deal with compressed lumps.
static int W_VerifyFile(const char *filename, lumpchecklist_t *checklist,
boolean status)
{
FILE *handle;
int goodfile = false;
if (!checklist)
I_Error("No checklist for %s\n", filename);
// open wad file
if ((handle = W_OpenWadFile(&filename, false)) == NULL)
return -1;
if (stricmp(&filename[strlen(filename) - 4], ".pk3") == 0)
goodfile = W_VerifyPK3(handle, checklist, status);
else
{
// detect wad file by the absence of the other supported extensions
if (stricmp(&filename[strlen(filename) - 4], ".soc")
&& stricmp(&filename[strlen(filename) - 4], ".lua"))
{
goodfile = W_VerifyWAD(handle, checklist, status);
} }
} }
fclose(handle); fclose(handle);

View file

@ -66,8 +66,9 @@ typedef struct
{ {
unsigned long position; // filelump_t filepos unsigned long position; // filelump_t filepos
unsigned long disksize; // filelump_t size unsigned long disksize; // filelump_t size
char name[9]; // filelump_t name[] char name[9]; // filelump_t name[] e.g. "LongEntr"
char *name2; // Used by PK3s. Dynamically allocated name. char *longname; // e.g. "LongEntryName"
char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension"
size_t size; // real (uncompressed) size size_t size; // real (uncompressed) size
compmethod compression; // lump compression method compmethod compression; // lump compression method
} lumpinfo_t; } lumpinfo_t;
@ -137,10 +138,16 @@ void W_UnloadWadFile(UINT16 num);
// so that it stops with a message if a file was not found, but not if all is okay. // so that it stops with a message if a file was not found, but not if all is okay.
INT32 W_InitMultipleFiles(char **filenames, boolean addons); INT32 W_InitMultipleFiles(char **filenames, boolean addons);
#define W_FileHasFolders(wadfile) ((wadfile)->type == RET_PK3)
const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump);
const char *W_CheckNameForNum(lumpnum_t lumpnum); const char *W_CheckNameForNum(lumpnum_t lumpnum);
UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump); // checks only in one pwad
UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump);
/* Find the first lump after F_START for instance. */
UINT16 W_CheckNumForMarkerStartPwad(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump);
UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump);
@ -148,7 +155,9 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump)
lumpnum_t W_CheckNumForMap(const char *name); lumpnum_t W_CheckNumForMap(const char *name);
lumpnum_t W_CheckNumForName(const char *name); lumpnum_t W_CheckNumForName(const char *name);
lumpnum_t W_CheckNumForLongName(const char *name);
lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR
lumpnum_t W_GetNumForLongName(const char *name);
lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend); lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend);
UINT8 W_LumpExists(const char *name); // Lua uses this. UINT8 W_LumpExists(const char *name); // Lua uses this.
@ -156,6 +165,7 @@ size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump);
size_t W_LumpLength(lumpnum_t lumpnum); size_t W_LumpLength(lumpnum_t lumpnum);
boolean W_IsLumpWad(lumpnum_t lumpnum); // for loading maps from WADs in PK3s boolean W_IsLumpWad(lumpnum_t lumpnum); // for loading maps from WADs in PK3s
boolean W_IsLumpFolder(UINT16 wad, UINT16 lump); // for detecting folder "lumps"
#ifdef HAVE_ZLIB #ifdef HAVE_ZLIB
void zerr(int ret); // zlib error checking void zerr(int ret); // zlib error checking