From d1510cc6823fef0f957878e0a5d2a5e61d632be1 Mon Sep 17 00:00:00 2001 From: NepDisk Date: Thu, 4 Dec 2025 00:02:23 -0500 Subject: [PATCH] Optimize lump searching Based on https://codeberg.org/srb2classic/srb2classic/commit/dc608f084c76cf72de9fc3f3f347752f04acae42 and further adapted by me and Alug (Thanks so much!) --- src/w_wad.c | 109 +++++++++++++++++++++++++++++++++++++++------------- src/w_wad.h | 13 ++++++- 2 files changed, 95 insertions(+), 27 deletions(-) diff --git a/src/w_wad.c b/src/w_wad.c index fa0fd329f..1bc876d40 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -438,6 +438,14 @@ static void W_InvalidateLumpnumCache(void) memset(lumpnumcache, 0, sizeof (lumpnumcache)); } +UINT32 W_HashLumpName(const char *name, size_t len) +{ + char uname[len + 1]; + strlcpy(uname, name, len + 1); + strupr(uname); + return HASH32(uname, len); +} + /** Detect a file type. * \todo Actually detect the wad/pkzip headers and whatnot, instead of just checking the extensions. */ @@ -462,18 +470,23 @@ static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const fseek(handle, 0, SEEK_END); lumpinfo->size = ftell(handle); fseek(handle, 0, SEEK_SET); - strcpy(lumpinfo->name, lumpname); - lumpinfo->hash = quickncasehash(lumpname, 8); + strlcpy(lumpinfo->name, lumpname, sizeof(lumpinfo->name)); + lumpinfo->namelength = strlen(lumpinfo->name); + lumpinfo->hash.name = W_HashLumpName(lumpname, lumpinfo->namelength); // Allocate the lump's long name. - lumpinfo->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + lumpinfo->longname = Z_Malloc((lumpinfo->namelength + 1) * sizeof(char), PU_STATIC, NULL); strcpy(lumpinfo->longname, lumpname); - lumpinfo->longname[8] = '\0'; + lumpinfo->longname[lumpinfo->namelength] = '\0'; + lumpinfo->longnamelength = lumpinfo->namelength; + lumpinfo->hash.longname = lumpinfo->hash.name; // Allocate the lump's full name. - lumpinfo->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + lumpinfo->fullname = Z_Malloc((lumpinfo->namelength + 1) * sizeof(char), PU_STATIC, NULL); strcpy(lumpinfo->fullname, lumpname); - lumpinfo->fullname[8] = '\0'; + lumpinfo->fullname[lumpinfo->namelength] = '\0'; + lumpinfo->fullnamelength = lumpinfo->namelength; + lumpinfo->hash.fullname = lumpinfo->hash.name; *numlumps = 1; return lumpinfo; @@ -612,22 +625,45 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen strncpy(lump_p->longname, trimname, namelen); lump_p->longname[namelen-1] = '\0'; - CONS_Debug(DBG_SETUP, "WADNAME handling:\n -- path %s\n -- interpreted lumpname %s\n", filename, lump_p->longname); + lump_p->namelength = strlen(lump_p->longname); + lump_p->hash.name = W_HashLumpName(lump_p->longname, lump_p->namelength); - // Grab the hash from the first part - lump_p->hash = quickncasehash(lump_p->longname, 8); + // Allocate the lump's long name. + lump_p->longname = Z_Malloc(namelen * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->longname, fileinfo->name, 8); + lump_p->longname[namelen-1] = '\0'; + lump_p->longnamelength = lump_p->namelength; + lump_p->hash.longname = lump_p->hash.name; + + // Allocate the lump's full name. + lump_p->fullname = Z_Malloc(namelen * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->fullname, fileinfo->name, 8); + lump_p->fullname[namelen-1] = '\0'; + lump_p->fullnamelength = lump_p->namelength; + lump_p->hash.fullname = lump_p->hash.name; + + CONS_Debug(DBG_SETUP, "WADNAME handling:\n -- path %s\n -- interpreted lumpname %s\n", filename, lump_p->longname); wadnamelump = i | (numwadfiles << 16); } else { - // Set up true hash - lump_p->hash = quickncasehash(lump_p->name, 8); + lump_p->namelength = strlen(lump_p->name); + lump_p->hash.name = W_HashLumpName(lump_p->name, lump_p->namelength); - // Allocate the lump's long and full name (save on memory). - lump_p->longname = lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + // 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'; + lump_p->longnamelength = lump_p->namelength; + lump_p->hash.longname = lump_p->hash.name; + + // Allocate the lump's full name. + lump_p->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + strncpy(lump_p->fullname, fileinfo->name, 8); + lump_p->fullname[8] = '\0'; + lump_p->fullnamelength = lump_p->namelength; + lump_p->hash.fullname = lump_p->hash.name; } } free(fileinfov); @@ -787,13 +823,18 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) 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)); - lump_p->hash = quickncasehash(lump_p->name, 8); + lump_p->namelength = strlen(lump_p->name); + lump_p->hash.name = W_HashLumpName(lump_p->name, lump_p->namelength); lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); + lump_p->longnamelength = strlen(lump_p->longname); + lump_p->hash.longname = W_HashLumpName(lump_p->longname, lump_p->longnamelength); lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL); strncpy(lump_p->fullname, fullname, zentry.namelen); + lump_p->fullnamelength = zentry.namelen; + lump_p->hash.fullname = W_HashLumpName(lump_p->fullname, lump_p->fullnamelength); switch(zentry.compression) { @@ -1176,7 +1217,7 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 st for (i = startlump; i < wadfiles[wad]->numlumps; i++) { // Not the hash? - if ((wadfiles[wad]->lumpinfo + i)->hash != hash) + if ((wadfiles[wad]->lumpinfo + i)->hash.longname != hash) continue; // Not the name? (always use longname, even in wads, to accomodate WADNAME) @@ -1202,7 +1243,7 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 st for (; i < end; i++) { // Not the hash? - if ((wadfiles[wad]->lumpinfo + i)->hash != hash) + if ((wadfiles[wad]->lumpinfo + i)->hash.longname != hash) continue; // Not the name? @@ -1233,11 +1274,15 @@ UINT16 W_CheckNumForMapPwad(const char *name, UINT32 hash, UINT16 wad, UINT16 st UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; - UINT32 hash = quickncasehash(name, 8); + UINT32 hash; + size_t namelen; - if (!TestValidLump(wad,0)) + if (!TestValidLump(wad, 0)) return INT16_MAX; + namelen = strlen(name); + hash = W_HashLumpName(name, namelen); // Not a mistake, legacy system for short lumpnames + // // scan forward // start at 'startlump', useful parameter when there are multiple @@ -1247,8 +1292,15 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) { lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) - if (lump_p->hash == hash && !strncasecmp(lump_p->name, name, 8)) - return i; + { + if (lump_p->namelength != namelen) + continue; + if (lump_p->hash.name != hash) + continue; + if (strncasecmp(lump_p->name, name, sizeof(name) - 1)) + continue; + return i; + } } // not found. @@ -1264,11 +1316,15 @@ UINT16 W_CheckNumForNamePwad(const char *name, UINT16 wad, UINT16 startlump) UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) { UINT16 i; - UINT32 hash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames + UINT32 hash; + size_t namelen; - if (!TestValidLump(wad,0)) + if (!TestValidLump(wad, 0)) return INT16_MAX; + namelen = strlen(name); + hash = W_HashLumpName(name, namelen); // Not a mistake, legacy system for short lumpnames + // // scan forward // start at 'startlump', useful parameter when there are multiple @@ -1279,13 +1335,14 @@ UINT16 W_CheckNumForLongNamePwad(const char *name, UINT16 wad, UINT16 startlump) lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo + startlump; for (i = startlump; i < wadfiles[wad]->numlumps; i++, lump_p++) { - if (lump_p->hash != hash) + if (lump_p->longnamelength != namelen) + continue; + if (lump_p->hash.longname != hash) continue; if (strcasecmp(lump_p->longname, name)) continue; return i; } - } // not found. @@ -1386,7 +1443,7 @@ lumpnum_t W_CheckNumForName(const char *name) // scan wad files backwards so patch lump files take precedence for (i = numwadfiles - 1; i >= 0; i--) { - check = W_CheckNumForNamePwad(name,(UINT16)i,0); + check = W_CheckNumForNamePwad(name, (UINT16)i, 0); if (check != INT16_MAX) break; //found it } @@ -1479,7 +1536,7 @@ lumpnum_t W_CheckNumForMap(const char *name, boolean checktofirst) } } - uhash = quickncasehash(name, 8); // Not a mistake, legacy system for short lumpnames + uhash = W_HashLumpName(name, strlen(name)); // Not a mistake, legacy system for short lumpnames for (i = numwadfiles - 1; i >= firstfile; i--) { diff --git a/src/w_wad.h b/src/w_wad.h index d64a90782..4eeea52eb 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -60,11 +60,20 @@ struct lumpinfo_t unsigned long position; // filelump_t filepos unsigned long disksize; // filelump_t size char name[9]; // filelump_t name[] e.g. "LongEntr" - UINT32 hash; char *longname; // e.g. "LongEntryName" char *fullname; // e.g. "Folder/Subfolder/LongEntryName.extension" size_t size; // real (uncompressed) size compmethod compression; // lump compression method + + size_t namelength; // length of name + size_t longnamelength; // length of longname + size_t fullnamelength; // length of fullname + + struct { + UINT32 name; // hash of name + UINT32 longname; // hash of longname + UINT32 fullname; // hash of fullname + } hash; }; // ========================================================================= @@ -155,6 +164,8 @@ boolean W_MakeFileHash(const char *filename, boolean openwad, UINT64 *ret); // W_InitMultipleFiles exits if a file was not found, but not if all is okay. INT32 W_InitMultipleFiles(char **filenames, boolean addons); +UINT32 W_HashLumpName(const char *name, size_t len); + const char *W_CheckNameForNumPwad(UINT16 wad, UINT16 lump); const char *W_CheckNameForNum(lumpnum_t lumpnum);