From c46231ede9a9b48cbbaac01b997b4e11bcf75cfa Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 28 Aug 2023 03:52:05 -0700 Subject: [PATCH 1/5] Convert w_wad.c to w_wad.cpp --- src/CMakeLists.txt | 2 +- src/r_picformats.h | 1 + src/{w_wad.c => w_wad.cpp} | 73 ++++++++++++++++++++------------------ 3 files changed, 41 insertions(+), 35 deletions(-) rename src/{w_wad.c => w_wad.cpp} (95%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8063f7c4..81599a21f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,7 +92,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 v_video.cpp s_sound.c sounds.c - w_wad.c + w_wad.cpp filesrch.c mserv.c http-mserv.c diff --git a/src/r_picformats.h b/src/r_picformats.h index eb40b790a..6dd3f1bbe 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -46,6 +46,7 @@ typedef enum typedef enum { + PICFLAGS_NONE = 0, PICFLAGS_XFLIP = 1, PICFLAGS_YFLIP = 1<<1 } pictureflags_t; diff --git a/src/w_wad.c b/src/w_wad.cpp similarity index 95% rename from src/w_wad.c rename to src/w_wad.cpp index 96fe606be..6eb0dc1ff 100644 --- a/src/w_wad.c +++ b/src/w_wad.cpp @@ -40,6 +40,9 @@ #include "lzf.h" #endif +#include +#include + #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" @@ -227,7 +230,7 @@ static inline void W_LoadDehackedLumpsPK3(UINT16 wadnum, boolean mainfile) { lumpinfo_t *lump_p = &wadfiles[wadnum]->lumpinfo[posStart]; 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 = static_cast(malloc(length + 1)); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname); name[length] = '\0'; CONS_Printf(M_GetText("Loading SOC from %s\n"), name); @@ -256,7 +259,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) if (memcmp(lump_p->name,"SOC_",4)==0) // Check for generic SOC lump { // shameless copy+paste of code from LUA_LoadLump 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 = static_cast(malloc(length + 1)); sprintf(name, "%s|%s", wadfiles[wadnum]->filename, lump_p->fullname); name[length] = '\0'; @@ -337,7 +340,7 @@ static restype_t ResourceFileDetect (const char* filename) */ static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const char* lumpname) { - lumpinfo_t* lumpinfo = Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL); + lumpinfo_t* lumpinfo = static_cast(Z_Calloc(sizeof (*lumpinfo), PU_STATIC, NULL)); lumpinfo->position = 0; fseek(handle, 0, SEEK_END); lumpinfo->size = ftell(handle); @@ -346,12 +349,12 @@ static lumpinfo_t* ResGetLumpsStandalone (FILE* handle, UINT16* numlumps, const lumpinfo->hash = quickncasehash(lumpname, 8); // Allocate the lump's long name. - lumpinfo->longname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + lumpinfo->longname = static_cast(Z_Malloc(9 * sizeof(char), PU_STATIC, NULL)); strcpy(lumpinfo->longname, lumpname); lumpinfo->longname[8] = '\0'; // Allocate the lump's full name. - lumpinfo->fullname = Z_Malloc(9 * sizeof(char), PU_STATIC, NULL); + lumpinfo->fullname = static_cast(Z_Malloc(9 * sizeof(char), PU_STATIC, NULL)); strcpy(lumpinfo->fullname, lumpname); lumpinfo->fullname[8] = '\0'; @@ -395,7 +398,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen // read wad file directory i = header.numlumps * sizeof (*fileinfo); - fileinfov = fileinfo = malloc(i); + fileinfov = fileinfo = static_cast(malloc(i)); if (fseek(handle, header.infotableofs, SEEK_SET) == -1 || fread(fileinfo, 1, i, handle) < i) { @@ -407,7 +410,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen numlumps = header.numlumps; // fill in lumpinfo for this wad - lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); + lump_p = lumpinfo = static_cast(Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL)); for (i = 0; i < numlumps; i++, lump_p++, fileinfo++) { lump_p->position = LONG(fileinfo->filepos); @@ -488,7 +491,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen namelen = strlen(trimname); // Allocate the lump's long and full name (save on memory). - lump_p->longname = lump_p->fullname = Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL); + lump_p->longname = lump_p->fullname = static_cast(Z_Calloc(namelen * sizeof(char), PU_STATIC, NULL)); strncpy(lump_p->longname, trimname, namelen); lump_p->longname[namelen-1] = '\0'; @@ -505,7 +508,7 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen lump_p->hash = quickncasehash(lump_p->name, 8); // 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); + lump_p->longname = lump_p->fullname = static_cast(Z_Malloc(9 * sizeof(char), PU_STATIC, NULL)); strncpy(lump_p->longname, fileinfo->name, 8); lump_p->longname[8] = '\0'; } @@ -613,7 +616,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) // Look for central directory end signature near end of file. // Contains entry number (number of lumps), and central directory start offset. fseek(handle, 0, SEEK_END); - if (!ResFindSignature(handle, pat_end, max(0, ftell(handle) - (22 + 65536)))) + if (!ResFindSignature(handle, pat_end, std::max(0l, ftell(handle) - (22 + 65536)))) { CONS_Alert(CONS_ERROR, "Missing central directory\n"); return NULL; @@ -627,7 +630,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) } numlumps = zend.entries; - lump_p = lumpinfo = Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL); + lump_p = lumpinfo = static_cast(Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL)); fseek(handle, zend.cdiroffset, SEEK_SET); for (i = 0; i < numlumps; i++, lump_p++) @@ -653,7 +656,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->disksize = zentry.compsize; lump_p->size = zentry.size; - fullname = malloc(zentry.namelen + 1); + fullname = static_cast(malloc(zentry.namelen + 1)); if (fgets(fullname, zentry.namelen + 1, handle) != fullname) { CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); @@ -672,13 +675,13 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) dotpos = fullname + strlen(fullname); // Watch for files without extension. 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, std::min(static_cast(8), dotpos - trimname)); lump_p->hash = quickncasehash(lump_p->name, 8); - lump_p->longname = Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL); + lump_p->longname = static_cast(Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL)); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); - lump_p->fullname = Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL); + lump_p->fullname = static_cast(Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL)); strncpy(lump_p->fullname, fullname, zentry.namelen); switch(zentry.compression) @@ -867,7 +870,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) // // link wad file to search files // - wadfile = Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL); + wadfile = static_cast(Z_Malloc(sizeof (*wadfile), PU_STATIC, NULL)); wadfile->filename = Z_StrDup(filename); wadfile->type = type; wadfile->handle = handle; @@ -1596,8 +1599,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si char *decData; // Lump's decompressed real data. size_t retval; // Helper var, lzf_decompress returns 0 when an error occurs. - rawData = Z_Malloc(l->disksize, PU_STATIC, NULL); - decData = Z_Malloc(l->size, PU_STATIC, NULL); + rawData = static_cast(Z_Malloc(l->disksize, PU_STATIC, NULL)); + decData = static_cast(Z_Malloc(l->size, PU_STATIC, NULL)); if (fread(rawData, 1, l->disksize, handle) < l->disksize) I_Error("wad %d, lump %d: cannot read compressed data", wad, lump); @@ -1645,8 +1648,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si unsigned long rawSize = l->disksize; unsigned long decSize = size; - rawData = Z_Malloc(rawSize, PU_STATIC, NULL); - decData = dest; + rawData = static_cast(Z_Malloc(rawSize, PU_STATIC, NULL)); + decData = static_cast(dest); if (fread(rawData, 1, rawSize, handle) < rawSize) I_Error("wad %d, lump %d: cannot read compressed data", wad, lump); @@ -1861,13 +1864,13 @@ static void *MakePatch(void *lumpdata, size_t size, INT32 tag, void *cache) #ifndef NO_PNG_LUMPS if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) { - ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, 0); + ptr = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_DOOMPATCH, NULL, NULL, NULL, NULL, len, &len, PICFLAGS_NONE); } #endif dest = Z_Calloc(sizeof(patch_t), tag, cache); - Patch_Create(ptr, len, dest); + Patch_Create(static_cast(ptr), len, dest); return dest; } @@ -1910,7 +1913,7 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) if (!TestValidLump(wad, lump)) return NULL; - patch = W_CacheSoftwarePatchNumPwad(wad, lump, tag); + patch = static_cast(W_CacheSoftwarePatchNumPwad(wad, lump, tag)); #ifdef HWRENDER // Software-only compile cache the data without conversion @@ -2145,7 +2148,7 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) fseek(fp, 0, SEEK_END); file_size = ftell(fp); - if (!ResFindSignature(fp, pat_end, max(0, ftell(fp) - (22 + 65536)))) + if (!ResFindSignature(fp, pat_end, std::max(0l, ftell(fp) - (22 + 65536)))) return true; fseek(fp, -4, SEEK_CUR); @@ -2170,7 +2173,7 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) if (verified == true) { - fullname = malloc(zentry.namelen + 1); + fullname = static_cast(malloc(zentry.namelen + 1)); if (fgets(fullname, zentry.namelen + 1, fp) != fullname) return true; @@ -2186,7 +2189,7 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) 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)); + strncpy(lumpname, trimname, std::min(static_cast(8), dotpos - trimname)); if (! W_VerifyName(lumpname, checklist, status)) verified = false; @@ -2366,11 +2369,11 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) size_t *vsizecache; // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. - UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL); + UINT8 *wadData = static_cast(W_CacheLumpNum(lumpnum, PU_LEVEL)); filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); i = ((wadinfo_t *)wadData)->numlumps; - vsizecache = Z_Malloc(sizeof(size_t)*i, PU_LEVEL, NULL); + vsizecache = static_cast(Z_Malloc(sizeof(size_t)*i, PU_LEVEL, NULL)); for (realentry = 0; realentry < i; realentry++) { @@ -2382,7 +2385,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) numlumps++; } - vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + vlumps = static_cast(Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL)); // Build the lumps, skipping over empty entries. for (i = 0, realentry = 0; i < numlumps; realentry++) @@ -2393,7 +2396,9 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) // Play it safe with the name in this case. memcpy(vlumps[i].name, (fileinfo + realentry)->name, 8); vlumps[i].name[8] = '\0'; - vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that. + vlumps[i].data = static_cast( + Z_Malloc(vlumps[i].size, PU_LEVEL, NULL) // This is memory inefficient, sorry about that. + ); memcpy(vlumps[i].data, wadData + (fileinfo + realentry)->filepos, vlumps[i].size); i++; } @@ -2414,16 +2419,16 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) } numlumps++; - vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL); + vlumps = static_cast(Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL)); for (i = 0; i < numlumps; i++, lumpnum++) { vlumps[i].size = W_LumpLength(lumpnum); memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8); vlumps[i].name[8] = '\0'; - vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL); + vlumps[i].data = static_cast(W_CacheLumpNum(lumpnum, PU_LEVEL)); } } - vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL); + vres = static_cast(Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL)); vres->vlumps = vlumps; vres->numlumps = numlumps; @@ -2493,7 +2498,7 @@ void *vres_GetPatch(virtlump_t *vlump, INT32 tag) if (!vlump) return NULL; - patch = MakePatch(vlump->data, vlump->size, tag, NULL); + patch = static_cast(MakePatch(vlump->data, vlump->size, tag, NULL)); #ifdef HWRENDER // Software-only compile cache the data without conversion From 331a6ea41e4471ee42ab8a8bff34b6df1049f871 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Tue, 23 Aug 2022 10:09:53 +1000 Subject: [PATCH 2/5] wad: Fixes for big-endian platforms --- src/r_patch.cpp | 2 +- src/w_wad.cpp | 50 ++++++++++++++++++++++++------------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/r_patch.cpp b/src/r_patch.cpp index b09416969..8165e9a90 100644 --- a/src/r_patch.cpp +++ b/src/r_patch.cpp @@ -40,7 +40,7 @@ patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest) patch->topoffset = SHORT(source->topoffset); patch->columnofs = static_cast(Z_Calloc(size, PU_PATCH_DATA, NULL)); - for (col = 0; col < source->width; col++) + for (col = 0; col < patch->width; col++) { // This makes the column offsets relative to the column data itself, // instead of the entire patch data diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 6eb0dc1ff..c78787791 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -628,11 +628,11 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) CONS_Alert(CONS_ERROR, "Corrupt central directory (%s)\n", M_FileError(handle)); return NULL; } - numlumps = zend.entries; + numlumps = SHORT(zend.entries); lump_p = lumpinfo = static_cast(Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL)); - fseek(handle, zend.cdiroffset, SEEK_SET); + fseek(handle, LONG(zend.cdiroffset), SEEK_SET); for (i = 0; i < numlumps; i++, lump_p++) { char* fullname; @@ -652,12 +652,12 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) return NULL; } - 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->size = zentry.size; + lump_p->position = LONG(zentry.offset); // NOT ACCURATE YET: we still need to read the local entry to find our true position + lump_p->disksize = LONG(zentry.compsize); + lump_p->size = LONG(zentry.size); - fullname = static_cast(malloc(zentry.namelen + 1)); - if (fgets(fullname, zentry.namelen + 1, handle) != fullname) + fullname = static_cast(malloc(SHORT(zentry.namelen) + 1)); + if (fgets(fullname, SHORT(zentry.namelen) + 1, handle) != fullname) { CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); Z_Free(lumpinfo); @@ -681,10 +681,10 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->longname = static_cast(Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL)); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); - lump_p->fullname = static_cast(Z_Calloc(zentry.namelen + 1, PU_STATIC, NULL)); - strncpy(lump_p->fullname, fullname, zentry.namelen); + lump_p->fullname = static_cast(Z_Calloc(SHORT(zentry.namelen) + 1, PU_STATIC, NULL)); + strncpy(lump_p->fullname, fullname, SHORT(zentry.namelen)); - switch(zentry.compression) + switch(SHORT(zentry.compression)) { case 0: lump_p->compression = CM_NOCOMPRESSION; @@ -706,7 +706,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) free(fullname); // skip and ignore comments/extra fields - if (fseek(handle, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) + if (fseek(handle, SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) { CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); Z_Free(lumpinfo); @@ -725,7 +725,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) return NULL; } - lump_p->position += sizeof(zlentry_t) + zlentry.namelen + zlentry.xtralen; + lump_p->position += sizeof(zlentry_t) + SHORT(zlentry.namelen) + SHORT(zlentry.xtralen); } *nlmp = numlumps; @@ -2157,9 +2157,9 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) data_size = sizeof zend; - numlumps = zend.entries; + numlumps = SHORT(zend.entries); - fseek(fp, zend.cdiroffset, SEEK_SET); + fseek(fp, LONG(zend.cdiroffset), SEEK_SET); for (i = 0; i < numlumps; i++) { char* fullname; @@ -2173,8 +2173,8 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) if (verified == true) { - fullname = static_cast(malloc(zentry.namelen + 1)); - if (fgets(fullname, zentry.namelen + 1, fp) != fullname) + fullname = static_cast(malloc(SHORT(zentry.namelen) + 1)); + if (fgets(fullname, SHORT(zentry.namelen) + 1, fp) != fullname) return true; // Strip away file address and extension for the 8char name. @@ -2202,28 +2202,28 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) free(fullname); // skip and ignore comments/extra fields - if (fseek(fp, zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) + if (fseek(fp, SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) return true; } else { - if (fseek(fp, zentry.namelen + zentry.xtralen + zentry.commlen, SEEK_CUR) != 0) + if (fseek(fp, SHORT(zentry.namelen) + SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) return true; } data_size += - sizeof zentry + zentry.namelen + zentry.xtralen + zentry.commlen; + sizeof zentry + SHORT(zentry.namelen) + SHORT(zentry.xtralen) + SHORT(zentry.commlen); old_position = ftell(fp); - if (fseek(fp, zentry.offset, SEEK_SET) != 0) + if (fseek(fp, LONG(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; + sizeof zlentry + SHORT(zlentry.namelen) + SHORT(zlentry.xtralen) + LONG(zlentry.compsize); fseek(fp, old_position, SEEK_SET); } @@ -2370,14 +2370,14 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) // Remember that we're assuming that the WAD will have a specific set of lumps in a specific order. UINT8 *wadData = static_cast(W_CacheLumpNum(lumpnum, PU_LEVEL)); - filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); + filelump_t *fileinfo = (filelump_t *)(wadData + LONG(((wadinfo_t *)wadData)->infotableofs)); - i = ((wadinfo_t *)wadData)->numlumps; + i = LONG(((wadinfo_t *)wadData)->numlumps); vsizecache = static_cast(Z_Malloc(sizeof(size_t)*i, PU_LEVEL, NULL)); for (realentry = 0; realentry < i; realentry++) { - vsizecache[realentry] = (size_t)(((filelump_t *)(fileinfo + realentry))->size); + vsizecache[realentry] = (size_t)(LONG(((filelump_t *)(fileinfo + realentry))->size)); if (!vsizecache[realentry]) continue; @@ -2399,7 +2399,7 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) vlumps[i].data = static_cast( Z_Malloc(vlumps[i].size, PU_LEVEL, NULL) // This is memory inefficient, sorry about that. ); - memcpy(vlumps[i].data, wadData + (fileinfo + realentry)->filepos, vlumps[i].size); + memcpy(vlumps[i].data, wadData + LONG((fileinfo + realentry)->filepos), vlumps[i].size); i++; } From 8ca2dc77e75b1ba8c511380257f0bbaf6d21c27b Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Tue, 23 Aug 2022 12:32:07 +1000 Subject: [PATCH 3/5] wad: Cache pk3 central directory Massive improvments from seeking less, allows file buffering to work better too Co-authored-by: James R --- src/w_wad.cpp | 93 +++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index c78787791..0e39070d3 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -602,7 +602,6 @@ typedef struct zlentry_s static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) { zend_t zend; - zentry_t zentry; zlentry_t zlentry; UINT16 numlumps = *nlmp; @@ -633,37 +632,39 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p = lumpinfo = static_cast(Z_Malloc(numlumps * sizeof (*lumpinfo), PU_STATIC, NULL)); fseek(handle, LONG(zend.cdiroffset), SEEK_SET); + + char *cdir = static_cast(Z_MallocAlign(LONG(zend.cdirsize), PU_STATIC, &cdir, 7)); + auto cdir_finally = srb2::finally([cdir] { Z_Free(cdir); }); + + if (fread(cdir, 1, LONG(zend.cdirsize), handle) < static_cast(LONG(zend.cdirsize))) + { + CONS_Alert(CONS_ERROR, "Failed to read central directory (%s)\n", M_FileError(handle)); + Z_Free(lumpinfo); + return NULL; + } + + size_t offset = 0; + for (i = 0; i < numlumps; i++, lump_p++) { + zentry_t *zentry = reinterpret_cast(cdir + offset); char* fullname; char* trimname; char* dotpos; - 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)); - Z_Free(lumpinfo); - 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"); Z_Free(lumpinfo); return NULL; } - lump_p->position = LONG(zentry.offset); // NOT ACCURATE YET: we still need to read the local entry to find our true position - lump_p->disksize = LONG(zentry.compsize); - lump_p->size = LONG(zentry.size); + lump_p->position = LONG(zentry->offset); // NOT ACCURATE YET: we still need to read the local entry to find our true position + lump_p->disksize = LONG(zentry->compsize); + lump_p->size = LONG(zentry->size); - fullname = static_cast(malloc(SHORT(zentry.namelen) + 1)); - if (fgets(fullname, SHORT(zentry.namelen) + 1, handle) != fullname) - { - CONS_Alert(CONS_ERROR, "Unable to read lumpname (%s)\n", M_FileError(handle)); - Z_Free(lumpinfo); - free(fullname); - return NULL; - } + fullname = static_cast(malloc(SHORT(zentry->namelen) + 1)); + strlcpy(fullname, (char*)(zentry + 1), SHORT(zentry->namelen) + 1); // Strip away file address and extension for the 8char name. if ((trimname = strrchr(fullname, '/')) != 0) @@ -681,10 +682,10 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) lump_p->longname = static_cast(Z_Calloc(dotpos - trimname + 1, PU_STATIC, NULL)); strlcpy(lump_p->longname, trimname, dotpos - trimname + 1); - lump_p->fullname = static_cast(Z_Calloc(SHORT(zentry.namelen) + 1, PU_STATIC, NULL)); - strncpy(lump_p->fullname, fullname, SHORT(zentry.namelen)); + lump_p->fullname = static_cast(Z_Calloc(SHORT(zentry->namelen) + 1, PU_STATIC, NULL)); + strncpy(lump_p->fullname, fullname, SHORT(zentry->namelen)); - switch(SHORT(zentry.compression)) + switch(SHORT(zentry->compression)) { case 0: lump_p->compression = CM_NOCOMPRESSION; @@ -706,12 +707,7 @@ static lumpinfo_t* ResGetLumpsZip (FILE* handle, UINT16* nlmp) free(fullname); // skip and ignore comments/extra fields - if (fseek(handle, SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) - { - CONS_Alert(CONS_ERROR, "Central directory is corrupt\n"); - Z_Free(lumpinfo); - return NULL; - } + offset += sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); } // Adjust lump position values properly @@ -2124,14 +2120,11 @@ 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; @@ -2160,22 +2153,29 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) numlumps = SHORT(zend.entries); fseek(fp, LONG(zend.cdiroffset), SEEK_SET); + + char *cdir = static_cast(malloc(LONG(zend.cdirsize))); + auto cdir_finally = srb2::finally([cdir] { free(cdir); }); + + if (fread(cdir, 1, LONG(zend.cdirsize), fp) < static_cast(LONG(zend.cdirsize))) + return true; + + size_t offset = 0; + for (i = 0; i < numlumps; i++) { + zentry_t *zentry = reinterpret_cast(cdir + offset); 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)) + if (memcmp(zentry->signature, pat_central, 4) != 0) return true; if (verified == true) { - fullname = static_cast(malloc(SHORT(zentry.namelen) + 1)); - if (fgets(fullname, SHORT(zentry.namelen) + 1, fp) != fullname) - return true; + fullname = static_cast(malloc(SHORT(zentry->namelen) + 1)); + strlcpy(fullname, (char*)(zentry + 1), SHORT(zentry->namelen) + 1); // Strip away file address and extension for the 8char name. if ((trimname = strrchr(fullname, '/')) != 0) @@ -2200,23 +2200,14 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) } free(fullname); + } - // skip and ignore comments/extra fields - if (fseek(fp, SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) - return true; - } - else - { - if (fseek(fp, SHORT(zentry.namelen) + SHORT(zentry.xtralen) + SHORT(zentry.commlen), SEEK_CUR) != 0) - return true; - } + offset += sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); data_size += - sizeof zentry + SHORT(zentry.namelen) + SHORT(zentry.xtralen) + SHORT(zentry.commlen); + sizeof *zentry + SHORT(zentry->namelen) + SHORT(zentry->xtralen) + SHORT(zentry->commlen); - old_position = ftell(fp); - - if (fseek(fp, LONG(zentry.offset), SEEK_SET) != 0) + if (fseek(fp, LONG(zentry->offset), SEEK_SET) != 0) return true; if (fread(&zlentry, 1, sizeof(zlentry_t), fp) < sizeof (zlentry_t)) @@ -2224,8 +2215,6 @@ W_VerifyPK3 (FILE *fp, lumpchecklist_t *checklist, boolean status) data_size += sizeof zlentry + SHORT(zlentry.namelen) + SHORT(zlentry.xtralen) + LONG(zlentry.compsize); - - fseek(fp, old_position, SEEK_SET); } if (data_size < file_size) From dedd0047bd8f9f73aba4defc19c429af7c987983 Mon Sep 17 00:00:00 2001 From: Ash Logan Date: Tue, 23 Aug 2022 12:32:50 +1000 Subject: [PATCH 4/5] wad: Refactor ResFindSignature to work in chunks kinda mucky but it works --- src/w_wad.cpp | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 0e39070d3..d2ea6c2ac 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -522,24 +522,49 @@ static lumpinfo_t* ResGetLumpsWad (FILE* handle, UINT16* nlmp, const char* filen */ static boolean ResFindSignature (FILE* handle, char endPat[], UINT32 startpos) { + //the Wii U has rather slow filesystem access, and fgetc is *unbearable* + //so I reimplemented this function to buffer 128k chunks char *s; int c; + fseek(handle, 0, SEEK_END); + size_t len = ftell(handle); + fseek(handle, startpos, SEEK_SET); + size_t remaining = len - startpos; + size_t chunkpos = startpos; + s = endPat; - while((c = fgetc(handle)) != EOF) - { - if (*s != c && s > endPat) // No match? - s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array. - if (*s == c) - { - s++; - if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature. + + //128k buffers + size_t buffer_size = std::min(128 * 1024 * sizeof(char), remaining); + char* buffer = static_cast(malloc(buffer_size)); + + size_t bytes_read = 0; + while ((bytes_read = fread(buffer, 1, buffer_size, handle)) > 0) { + for (size_t i = 0; i < bytes_read; i++) { + c = (int)buffer[i]; + + if (*s != c && s > endPat) // No match? + s = endPat; // We "reset" the counter by sending the s pointer back to the start of the array. + if (*s == c) { - return true; + s++; + if (*s == 0x00) // The array pointer has reached the key char which marks the end. It means we have matched the signature. + { + //the original function would leave the FILE* seeked to the end of the match + size_t foundpos = chunkpos + i + 1; + fseek(handle, foundpos, SEEK_SET); + + free(buffer); + return true; + } } } + chunkpos += bytes_read; } + + free(buffer); return false; } From 28f26593428aee6ed3fd9526eba25a5ec5b80efd Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 28 Aug 2023 18:20:02 -0700 Subject: [PATCH 5/5] W_InitFile: calculate md5sum on background thread, for startup wads Add W_GetFileMD5, blocks calling thread until md5 is calculated. --- src/d_netcmd.c | 2 +- src/d_netfil.c | 6 +- src/filesrch.c | 2 +- src/g_demo.c | 6 +- src/typedef.h | 1 + src/w_wad.cpp | 90 ++++++++++++++-------- src/w_wad.h | 6 +- src/wad_private.hpp | 183 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 256 insertions(+), 40 deletions(-) create mode 100644 src/wad_private.hpp diff --git a/src/d_netcmd.c b/src/d_netcmd.c index faa8c4b16..41c6c4fda 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -4308,7 +4308,7 @@ static void Command_Addfile(void) for (i = 0; i < numwadfiles; i++) { - if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) + if (!memcmp(W_GetFileMD5(wadfiles[i]), md5sum, 16)) { CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), fn); valid = false; diff --git a/src/d_netfil.c b/src/d_netfil.c index cb6897a8e..a010ffb1a 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -208,7 +208,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile) count++; WRITEUINT32(p, wadfiles[i]->filesize); WRITESTRINGN(p, wadfilename, MAX_WADPATH); - WRITEMEM(p, wadfiles[i]->md5sum, 16); + WRITEMEM(p, W_GetFileMD5(wadfiles[i]), 16); } if (netbuffer->packettype == PT_MOREFILESNEEDED) netbuffer->u.filesneededcfg.num = count; @@ -576,7 +576,7 @@ INT32 CL_CheckFiles(void) return 2; // For the sake of speed, only bother with a md5 check - if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16)) + if (memcmp(W_GetFileMD5(wadfiles[j]), fileneeded[i].md5sum, 16)) return 2; // It's accounted for! let's keep going. @@ -611,7 +611,7 @@ INT32 CL_CheckFiles(void) { nameonly(strcpy(wadfilename, wadfiles[j]->filename)); if (!stricmp(wadfilename, fileneeded[i].filename) && - !memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16)) + !memcmp(W_GetFileMD5(wadfiles[j]), fileneeded[i].md5sum, 16)) { CONS_Debug(DBG_NETPLAY, "already loaded\n"); fileneeded[i].status = FS_OPEN; diff --git a/src/filesrch.c b/src/filesrch.c index 78232c26e..609f408c9 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -837,7 +837,7 @@ boolean preparefilemenu(boolean samedepth, boolean replayhut) if (strcmp(dent->d_name, filenamebuf[i])) continue; - if (cv_addons_md5.value && !checkfilemd5(menupath, wadfiles[i]->md5sum)) + if (cv_addons_md5.value && !checkfilemd5(menupath, W_GetFileMD5(wadfiles[i]))) continue; ext |= EXT_LOADED; diff --git a/src/g_demo.c b/src/g_demo.c index 95f5a0ac3..da30fe68c 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2053,7 +2053,7 @@ static void G_SaveDemoExtraFiles(UINT8 **pp) { nameonly(( filename = va("%s", wadfiles[i]->filename) )); WRITESTRINGL((*pp), filename, MAX_WADPATH); - WRITEMEM((*pp), wadfiles[i]->md5sum, 16); + WRITEMEM((*pp), W_GetFileMD5(wadfiles[i]), 16); totalfiles++; } @@ -2089,7 +2089,7 @@ static void G_LoadDemoExtraFiles(UINT8 **pp) for (j = 0; j < numwadfiles; ++j) { - if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + if (memcmp(md5sum, W_GetFileMD5(wadfiles[j]), 16) == 0) { alreadyloaded = true; break; @@ -2192,7 +2192,7 @@ static UINT8 G_CheckDemoExtraFiles(savebuffer_t *info, boolean quick) else continue; - if (memcmp(md5sum, wadfiles[j]->md5sum, 16) == 0) + if (memcmp(md5sum, W_GetFileMD5(wadfiles[j]), 16) == 0) { alreadyloaded = true; diff --git a/src/typedef.h b/src/typedef.h index 746a234b1..735728ae9 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -443,6 +443,7 @@ TYPEDEF (lumpinfo_t); TYPEDEF (virtlump_t); TYPEDEF (virtres_t); TYPEDEF (wadfile_t); +TYPEDEF (wadfile_private_t); #undef TYPEDEF #undef TYPEDEF2 diff --git a/src/w_wad.cpp b/src/w_wad.cpp index d2ea6c2ac..096916c65 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -42,6 +42,10 @@ #include #include +#include + +#include "cxxutil.hpp" +#include "wad_private.hpp" #include "doomdef.h" #include "doomstat.h" @@ -85,6 +89,14 @@ #define O_BINARY 0 #endif +using namespace srb2::wad; + +namespace srb2::wad +{ + +std::mutex g_wadfiles_mutex; + +}; // namespace srb2::wad typedef struct { @@ -123,6 +135,8 @@ void W_Shutdown(void) { wadfile_t *wad = wadfiles[numwadfiles]; + delete wad->internal_state; + fclose(wad->handle); Z_Free(wad->filename); while (wad->numlumps--) @@ -289,7 +303,7 @@ static inline void W_LoadDehackedLumps(UINT16 wadnum, boolean mainfile) * \param resblock resulting MD5 checksum * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found */ -static inline INT32 W_MakeFileMD5(const char *filename, void *resblock) +INT32 W_MakeFileMD5(const char *filename, void *resblock) { #ifdef NOMD5 (void)filename; @@ -790,6 +804,7 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) size_t i; #endif UINT8 md5sum[16]; + const boolean md5_in_background = startup; int important; if (!(refreshdirmenu & REFRESHDIR_ADDFILE)) @@ -831,21 +846,24 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) important = !important; #ifndef NOMD5 - // - // w-waiiiit! - // Let's not add a wad file if the MD5 matches - // an MD5 of an already added WAD file! - // - W_MakeFileMD5(filename, md5sum); - - for (i = 0; i < numwadfiles; i++) + if (!md5_in_background) { - if (!memcmp(wadfiles[i]->md5sum, md5sum, 16)) + // + // w-waiiiit! + // Let's not add a wad file if the MD5 matches + // an MD5 of an already added WAD file! + // + W_MakeFileMD5(filename, md5sum); + + for (i = 0; i < numwadfiles; i++) { - CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); - if (handle) - fclose(handle); - return W_InitFileError(filename, false); + if (!memcmp(W_GetFileMD5(wadfiles[i]), md5sum, 16)) + { + CONS_Alert(CONS_ERROR, M_GetText("%s is already loaded\n"), filename); + if (handle) + fclose(handle); + return W_InitFileError(filename, false); + } } } #endif @@ -902,21 +920,35 @@ UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup) wadfile->filesize = (unsigned)ftell(handle); wadfile->type = type; - // already generated, just copy it over - M_Memcpy(&wadfile->md5sum, &md5sum, 16); - // // set up caching // Z_Calloc(numlumps * sizeof (*wadfile->lumpcache), PU_STATIC, &wadfile->lumpcache); Z_Calloc(numlumps * sizeof (*wadfile->patchcache), PU_STATIC, &wadfile->patchcache); + wadfile->internal_state = new wadfile_private_t(wadfile); + + if (md5_in_background) + { + wadfile->internal_state->md5sum_.request(); + } + else + { + // already generated, just copy it over + wadfile->internal_state->md5sum_.fill(md5sum); + } + // // add the wadfile // CONS_Printf(M_GetText("Added file %s (%u lumps)\n"), filename, numlumps); - 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 + + { + std::lock_guard _(g_wadfiles_mutex); + + 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 + } #ifdef HWRENDER // Read shaders from file @@ -2001,7 +2033,8 @@ void *W_CachePatchLongName(const char *name, INT32 tag) */ #define MD5_FORMAT \ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" -static void PrintMD5String(const UINT8 *md5, char *buf) +void PrintMD5String(const UINT8 *md5, char *buf); +void PrintMD5String(const UINT8 *md5, char *buf) { snprintf(buf, 2*MD5_LEN+1, MD5_FORMAT, md5[0], md5[1], md5[2], md5[3], @@ -2048,20 +2081,15 @@ void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5) else realmd5[ix>>1] = (UINT8)(n<<4); } - if (memcmp(realmd5, wadfiles[wadfilenum]->md5sum, 16)) - { - char actualmd5text[2*MD5_LEN+1]; - PrintMD5String(wadfiles[wadfilenum]->md5sum, actualmd5text); -#ifdef _DEBUG - CONS_Printf -#else - I_Error -#endif - (M_GetText("File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n"), wadfiles[wadfilenum]->filename, actualmd5text, matchmd5); - } + wadfiles[wadfilenum]->internal_state->md5sum_.expect(realmd5); #endif } +const UINT8* W_GetFileMD5(const wadfile_t* wadfile) +{ + return wadfile->internal_state->md5sum_.get(); +} + // Verify versions for different archive // formats. checklist assumed to be valid. diff --git a/src/w_wad.h b/src/w_wad.h index 31ca26e69..ed7bb15b0 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -130,7 +130,7 @@ struct wadfile_t UINT16 numlumps; // this wad's number of resources FILE *handle; UINT32 filesize; // for network - UINT8 md5sum[16]; + wadfile_private_t *internal_state; boolean important; // also network - !W_VerifyNMUSlumps }; @@ -150,6 +150,8 @@ FILE *W_OpenWadFile(const char **filename, boolean useerrors); // Load and add a wadfile to the active wad files, returns numbers of lumps, INT16_MAX on error UINT16 W_InitFile(const char *filename, boolean mainfile, boolean startup); +wadfile_private_t *W_InitPrivate(wadfile_t *wadfile); + // W_InitMultipleFiles returns 1 if all is okay, 0 otherwise, // so that it stops with a message if a file was not found, but not if all is okay. // W_InitMultipleFiles exits if a file was not found, but not if all is okay. @@ -218,6 +220,8 @@ void *W_CacheSoftwarePatchNum(lumpnum_t lumpnum, INT32 tag); void W_UnlockCachedPatch(void *patch); void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5); +INT32 W_MakeFileMD5(const char *filename, void *resblock); +const UINT8 *W_GetFileMD5(const wadfile_t *wadfile); // this function may block! int W_VerifyNMUSlumps(const char *filename, boolean exit_on_error); diff --git a/src/wad_private.hpp b/src/wad_private.hpp new file mode 100644 index 000000000..5d50e9dc3 --- /dev/null +++ b/src/wad_private.hpp @@ -0,0 +1,183 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2023 by Kart Krew. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- + +#ifndef WAD_PRIVATE_HPP +#define WAD_PRIVATE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxxutil.hpp" + +#include "doomtype.h" +#include "typedef.h" +#include "w_wad.h" + +extern "C" void PrintMD5String(const UINT8 *md5, char *buf); + +namespace srb2::wad +{ + +// Mutex for accessing wadfiles and numwadfiles from other +// threads. WARNING: this doesn't cover the lumpcache. +extern std::mutex g_wadfiles_mutex; + +}; // namespace srb2::wad::detail + +struct wadfile_private_t +{ + struct ChecksumState + { + explicit ChecksumState(wadfile_t* wad) : wad_(wad) {} + + const std::uint8_t* get() const + { + std::unique_lock lock(mutex_); + cv_.wait(lock, [this]() -> bool { return valid_; }); + return md5sum_; + } + + void fill(const std::uint8_t chk[16]) + { + SRB2_ASSERT(!valid_ && !thread_.joinable()); + + std::memcpy(md5sum_, chk, 16); + valid_ = true; + } + + void request() + { + SRB2_ASSERT(!valid_ && !thread_.joinable()); + + thread_ = std::thread(&ChecksumState::worker, this); + } + + void expect(const std::uint8_t chk[16]) + { + std::lock_guard _(mutex_); + + expected_md5sum_ = std::array(); + std::memcpy(expected_md5sum_->data(), chk, 16); + + if (valid_) + { + check_expected(); + } + } + + void join() + { + if (thread_.joinable()) + { + thread_.join(); + } + } + + private: + wadfile_t* wad_; + std::uint8_t md5sum_[16]; + std::optional> expected_md5sum_; + std::atomic_bool valid_ = false; + std::thread thread_; + mutable std::mutex mutex_; + mutable std::condition_variable cv_; + + void worker() + { + W_MakeFileMD5(wad_->filename, md5sum_); + + { + std::lock_guard _(mutex_); + check_expected(); + valid_ = true; + } + + cv_.notify_all(); + + check_collisions(); + } + + void check_collisions() + { + std::lock_guard _(srb2::wad::g_wadfiles_mutex); + + for (UINT16 i = 0; i < numwadfiles; ++i) + { + const ChecksumState& other = wadfiles[i]->internal_state->md5sum_; + + // That's us! + if (&other == this) + { + continue; + } + + // Don't block for threads in progress, + // because they'll do their own check when + // they're done. + if (!other.valid_) + { + continue; + } + + if (!std::memcmp(other.md5sum_, md5sum_, 16)) + { + // FIXME: I_Error from a thread other than + // main kind of messes up the program + // state. It gets the message to the user, + // but should ideally be replaced by some + // communication with the main thread. + I_Error( + "MD5 checksum for '%s' matches a file already loaded.\n" + "Was this file added twice? Check the command line parameters.\n", + wad_->filename + ); + } + } + } + + void check_expected() const + { + if (!expected_md5sum_ || !std::memcmp(md5sum_, expected_md5sum_->data(), 16)) + { + return; + } + + char got[33]; + char wanted[33]; + + PrintMD5String(md5sum_, got); + PrintMD5String(expected_md5sum_->data(), wanted); + + I_Error( + "File is old, is corrupt or has been modified: %s (found md5: %s, wanted: %s)\n", + wad_->filename, + got, + wanted + ); + } + }; + + ChecksumState md5sum_; + + explicit wadfile_private_t(wadfile_t* wad) : md5sum_(wad) {} + + ~wadfile_private_t() + { + md5sum_.join(); + } +}; + +#endif // WAD_PRIVATE_HPP