diff --git a/engine/common/common.h b/engine/common/common.h index fa8140a77..1a1b14089 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -812,7 +812,8 @@ void FS_FreeFile(void *file); qbyte *COM_LoadFile (const char *path, unsigned int locateflags, int usehunk, size_t *filesize); -qboolean COM_LoadMapPackFile(const char *name, qofs_t offset); +qboolean FS_LoadMapPackFile (const char *filename, searchpathfuncs_t *archive); +void FS_CloseMapPackFile (searchpathfuncs_t *archive); void COM_FlushTempoaryPacks(void); void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm); diff --git a/engine/common/fs.c b/engine/common/fs.c index 962836159..65f95391d 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2793,14 +2793,14 @@ searchpathfuncs_t *COM_EnumerateFilesPackage (char *matches, const char *package if (com_homepathenabled) { //try the homedir Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, package); - handle = FS_OpenPackByExtension(VFSOS_Open(package, "rb"), NULL, package, package); + handle = FS_OpenPackByExtension(VFSOS_Open(syspath, "rb"), NULL, package, package); } else handle = NULL; if (!handle) { //now go for the basedir to see if ther. Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, package); - handle = FS_OpenPackByExtension(VFSOS_Open(package, "rb"), NULL, package, package); + handle = FS_OpenPackByExtension(VFSOS_Open(syspath, "rb"), NULL, package, package); } if (handle) @@ -2835,17 +2835,20 @@ void COM_EnumerateFiles (const char *match, int (QDECL *func)(const char *, qofs } } -void COM_FlushTempoaryPacks(void) +void COM_FlushTempoaryPacks(void) //flush all temporary packages { -#if 0 searchpath_t *sp, **link; + + COM_WorkerLock(); //make sure no workers are poking files... + Sys_LockMutex(fs_thread_mutex); + link = &com_searchpaths; while (*link) { sp = *link; if (sp->flags & SPF_TEMPORARY) { - FS_FlushFSHashReally(); + FS_FlushFSHashFull(); *link = sp->next; @@ -2856,15 +2859,52 @@ void COM_FlushTempoaryPacks(void) link = &sp->next; } com_purepaths = NULL; -#endif -} - -qboolean COM_LoadMapPackFile (const char *filename, qofs_t ofs) -{ - return false; + Sys_UnlockMutex(fs_thread_mutex); + COM_WorkerUnlock(); //workers can continue now } static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *probablepath, searchpathfuncs_t *handle, const char *prefix, unsigned int flags, unsigned int loadstuff); +qboolean FS_LoadMapPackFile (const char *filename, searchpathfuncs_t *archive) +{ + if (!archive->AddReference) + return false; //nope... + archive->AddReference(archive); + if (FS_AddPathHandle(NULL, filename, filename, archive, "", SPF_TEMPORARY, 0)) + return true; + return false; +} +void FS_CloseMapPackFile (searchpathfuncs_t *archive) +{ + searchpath_t *sp, **link; + + COM_WorkerLock(); //make sure no workers are poking files... + Sys_LockMutex(fs_thread_mutex); + + link = &com_searchpaths; + while (*link) + { + sp = *link; + if (sp->handle == archive) + { + FS_FlushFSHashFull(); + + *link = sp->next; + + sp->handle->ClosePath(sp->handle); + Z_Free (sp); + break; + } + else + link = &sp->next; + } + com_purepaths = NULL; + + Sys_UnlockMutex(fs_thread_mutex); + COM_WorkerUnlock(); //workers can continue now + + archive->ClosePath(archive); +} + static searchpathfuncs_t *FS_GetOldPath(searchpath_t **oldpaths, const char *dir, unsigned int *keepflags) { searchpath_t *p; @@ -3356,7 +3396,7 @@ static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purep flags &= ~SPF_WRITABLE; //temp packages also do not nest -// if (!(flags & SPF_TEMPORARY)) + if (!(flags & SPF_TEMPORARY)) FS_AddDataFiles(oldpaths, purepath, logicalpath, search, flags&(SPF_COPYPROTECTED|SPF_UNTRUSTED|SPF_TEMPORARY|SPF_PRIVATE|SPF_QSHACK), loadstuff); if (flags & SPF_TEMPORARY) diff --git a/engine/common/fs.h b/engine/common/fs.h index a0f2e8e89..86c861581 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -8,7 +8,7 @@ Files may be shared between threads, but not simultaneously. The filesystem driver is responsible for closing the pak/pk3 once all files are closed, and must ensure that opens+reads+closes as well as archive closure are thread safe. */ -#define FSVER 2 +#define FSVER 3 #define FF_NOTFOUND (0u) //file wasn't found @@ -32,7 +32,8 @@ struct searchpath_s; struct searchpathfuncs_s { int fsver; - void (QDECL *ClosePath)(searchpathfuncs_t *handle); + void (QDECL *ClosePath)(searchpathfuncs_t *handle); //removes a reference, kills it when it reaches 0. the package can only actually be killed once all contained files are closed. + void (QDECL *AddReference)(searchpathfuncs_t *handle); //adds an extra reference, so we survive closes better. void (QDECL *GetPathDetails)(searchpathfuncs_t *handle, char *outdetails, size_t sizeofdetails); void (QDECL *BuildHash)(searchpathfuncs_t *handle, int depth, void (QDECL *FS_AddFileHash)(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)); diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index 3c02e6b65..842a98330 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -596,6 +596,14 @@ static void QDECL FSZIP_GetPathDetails(searchpathfuncs_t *handle, char *out, siz else *out = '\0'; } +static void QDECL FSZIP_UnclosePath(searchpathfuncs_t *handle) +{ + zipfile_t *zip = (void*)handle; + if (!Sys_LockMutex(zip->mutex)) + return; //ohnoes + zip->references++; + Sys_UnlockMutex(zip->mutex); +} static void QDECL FSZIP_ClosePath(searchpathfuncs_t *handle) { size_t s; @@ -2105,6 +2113,7 @@ searchpathfuncs_t *QDECL FSZIP_LoadArchive (vfsfile_t *packhandle, searchpathfun zip->pub.fsver = FSVER; zip->pub.GetPathDetails = FSZIP_GetPathDetails; zip->pub.ClosePath = FSZIP_ClosePath; + zip->pub.AddReference = FSZIP_UnclosePath; zip->pub.BuildHash = FSZIP_BuildHash; zip->pub.FindFile = FSZIP_FLocate; zip->pub.ReadFile = FSZIP_ReadFile; diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index f6fdfdf7d..4e49b4987 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -4914,6 +4914,7 @@ static cmodel_t *CM_LoadMap (model_t *mod, qbyte *filein, size_t filelen, qboole Q_snprintfz (name, sizeof(name), "*%i:%s", i, wmod->publicname); mod = Mod_FindName (name); *mod = *wmod; + mod->archive = NULL; mod->entities_raw = NULL; mod->submodelof = wmod; Q_strncpyz(mod->publicname, name, sizeof(mod->publicname)); diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index a224bbf5f..5759870e9 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -2201,6 +2201,7 @@ Init stuff BSPX Stuff */ +#include "fs.h" typedef struct { char lumpname[24]; // up to 23 chars, zero-padded @@ -2240,10 +2241,10 @@ void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, i } return NULL; } -bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps) +bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, size_t filelen, lump_t *lumps, size_t numlumps) { - int i; - int offs = 0; + size_t i; + size_t offs = 0; bspx_header_t *h; for (i = 0; i < numlumps; i++, lumps++) @@ -2253,22 +2254,45 @@ bspx_header_t *BSPX_Setup(model_t *mod, char *filebase, unsigned int filelen, lu } offs = (offs + 3) & ~3; if (offs + sizeof(*h) > filelen) - return NULL; /*no space for it*/ - h = (bspx_header_t*)(filebase + offs); - - i = LittleLong(h->numlumps); - /*verify the header*/ - if (*(int*)h->id != (('B'<<0)|('S'<<8)|('P'<<16)|('X'<<24)) || - i < 0 || - offs + sizeof(*h) + sizeof(h->lumps[0])*(i-1) > filelen) - return NULL; - h->numlumps = i; - while(i-->0) + h = NULL; /*no space for it*/ + else { - h->lumps[i].fileofs = LittleLong(h->lumps[i].fileofs); - h->lumps[i].filelen = LittleLong(h->lumps[i].filelen); - if (h->lumps[i].fileofs + h->lumps[i].filelen > filelen) - return NULL; + h = (bspx_header_t*)(filebase + offs); + + i = LittleLong(h->numlumps); + /*verify the header*/ + if (*(int*)h->id != (('B'<<0)|('S'<<8)|('P'<<16)|('X'<<24)) || + i < 0 || + offs + sizeof(*h) + sizeof(h->lumps[0])*(i-1) > filelen) + h = NULL; + else + { + h->numlumps = i; + while(i-->0) + { + h->lumps[i].fileofs = LittleLong(h->lumps[i].fileofs); + h->lumps[i].filelen = LittleLong(h->lumps[i].filelen); + if (h->lumps[i].fileofs + h->lumps[i].filelen > filelen) + return NULL; //some sort of corruption/truncation. + + if (offs < lumps->fileofs + lumps->filelen) + offs = lumps->fileofs + lumps->filelen; + } + } + } + + if (offs < filelen && !mod->archive) + { //we have some sort of trailing junk... is it a zip?... + vfsfile_t *f = VFSPIPE_Open(1,true); + if (f) + { + VFS_WRITE(f, filebase+offs, filelen-offs); + mod->archive = FSZIP_LoadArchive(f, NULL, mod->name, mod->name, NULL); + if (mod->archive) + FS_LoadMapPackFile(mod->name, mod->archive); //give it to the filesystem to use. + else + VFS_CLOSE(f); //give up. + } } return h; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 86ad6e380..6d06f9a2e 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // on the same machine. #include "quakedef.h" - +#include "fs.h" #include "com_bih.h" #if 1//ndef SERVERONLY //FIXME #include "glquake.h" @@ -541,8 +541,13 @@ qboolean Mod_PurgeModel(model_t *mod, enum mod_purge_e ptype) #endif //and obliterate anything else remaining in memory. - ZG_FreeGroup(&mod->memgroup); mod->meshinfo = NULL; + if (mod->archive) + { + FS_CloseMapPackFile(mod->archive); + mod->archive = NULL; + } + ZG_FreeGroup(&mod->memgroup); mod->loadstate = MLS_NOTLOADED; mod->submodelof = NULL; @@ -5496,7 +5501,10 @@ TRACE(("LoadBrushModel %i\n", __LINE__)); submod->pvsbytes = ((submod->numclusters+31)>>3)&~3; if (i) + { submod->entities_raw = NULL; + submod->archive = NULL; + } memset(&submod->batches, 0, sizeof(submod->batches)); submod->vbos = NULL; diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 6221b803d..02ea44c62 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -585,7 +585,7 @@ void Q1BSP_Init(void); void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base); void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize); -bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, unsigned int filelen, lump_t *lumps, int numlumps); +bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, size_t filelen, lump_t *lumps, size_t numlumps); typedef struct fragmentdecal_s fragmentdecal_t; void Fragment_ClipPoly(fragmentdecal_t *dec, int numverts, float *inverts, shader_t *surfshader); @@ -1084,6 +1084,7 @@ typedef struct model_s // additional model data // void *meshinfo; //data allocated within the memgroup allocations, will be nulled out when the model is flushed + searchpathfuncs_t *archive; //some bsp formats have an embedded zip... zonegroup_t memgroup; } model_t;