summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/qcommon/files.c671
-rw-r--r--src/qcommon/qcommon.h12
-rw-r--r--src/qcommon/vm.c88
-rw-r--r--src/qcommon/vm_local.h3
-rw-r--r--src/renderer/tr_public.h2
-rw-r--r--src/sys/sys_main.c32
6 files changed, 510 insertions, 298 deletions
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 76cc6075..66cef9a3 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -193,6 +193,7 @@ typedef struct fileInPack_s {
} fileInPack_t;
typedef struct {
+ char pakPathname[MAX_OSPATH]; // /tremulous/baseq3
char pakFilename[MAX_OSPATH]; // /tremulous/base/pak0.pk3
char pakBasename[MAX_OSPATH]; // pak0
char pakGamename[MAX_OSPATH]; // base
@@ -208,6 +209,7 @@ typedef struct {
typedef struct {
char path[MAX_OSPATH];
+ char fullpath[MAX_OSPATH]; // /tremulous/base
char gamedir[MAX_OSPATH]; // base
} directory_t;
@@ -371,7 +373,7 @@ static fileHandle_t FS_HandleForFile(void) {
}
static FILE *FS_FileForHandle( fileHandle_t f ) {
- if ( f < 0 || f > MAX_FILE_HANDLES ) {
+ if ( f < 1 || f > MAX_FILE_HANDLES ) {
Com_Error( ERR_DROP, "FS_FileForHandle: out of range" );
}
if (fsh[f].zipFile == qtrue) {
@@ -393,6 +395,25 @@ void FS_ForceFlush( fileHandle_t f ) {
/*
================
+FS_fplength
+================
+*/
+
+long FS_fplength(FILE *h)
+{
+ long pos;
+ long end;
+
+ pos = ftell(h);
+ fseek(h, 0, SEEK_END);
+ end = ftell(h);
+ fseek(h, pos, SEEK_SET);
+
+ return end;
+}
+
+/*
+================
FS_filelength
If this is called on a non-unique FILE (from a pak file),
@@ -400,18 +421,16 @@ it will return the size of the pak file, not the expected
size of the file.
================
*/
-int FS_filelength( fileHandle_t f ) {
- int pos;
- int end;
- FILE* h;
+long FS_filelength(fileHandle_t f)
+{
+ FILE *h;
h = FS_FileForHandle(f);
- pos = ftell (h);
- fseek (h, 0, SEEK_END);
- end = ftell (h);
- fseek (h, pos, SEEK_SET);
-
- return end;
+
+ if(h == NULL)
+ return -1;
+ else
+ return FS_fplength(h);
}
/*
@@ -550,6 +569,28 @@ void FS_HomeRemove( const char *homePath ) {
/*
================
+FS_FileInPathExists
+
+Tests if path and file exists
+================
+*/
+qboolean FS_FileInPathExists(const char *testpath)
+{
+ FILE *filep;
+
+ filep = fopen(testpath, "rb");
+
+ if(filep)
+ {
+ fclose(filep);
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+================
FS_FileExists
Tests if the file exists in the current gamedir, this DOES NOT
@@ -558,19 +599,9 @@ search the paths. This is to determine if opening a file to write
NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards
================
*/
-qboolean FS_FileExists( const char *file )
+qboolean FS_FileExists(const char *file)
{
- FILE *f;
- char *testpath;
-
- testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
-
- f = fopen( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
+ return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file));
}
/*
@@ -582,18 +613,12 @@ Tests if the file exists
*/
qboolean FS_SV_FileExists( const char *file )
{
- FILE *f;
char *testpath;
testpath = FS_BuildOSPath( fs_homepath->string, file, "");
testpath[strlen(testpath)-1] = '\0';
- f = fopen( testpath, "rb" );
- if (f) {
- fclose( f );
- return qtrue;
- }
- return qfalse;
+ return FS_FileInPathExists(testpath);
}
@@ -647,7 +672,8 @@ Search for a file somewhere below the home path then base path
in that order
===========
*/
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
+long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp)
+{
char *ospath;
fileHandle_t f = 0;
@@ -1020,243 +1046,381 @@ qboolean FS_IsDemoExt(const char *filename, int namelen)
/*
===========
-FS_FOpenFileRead
+FS_FOpenFileReadDir
-Finds the file in the search path.
+Tries opening file "filename" in searchpath "search"
Returns filesize and an open FILE pointer.
-Used for streaming data out of either a
-separate file or a ZIP file.
===========
*/
extern qboolean com_fullyInitialized;
-int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {
- searchpath_t *search;
- char *netpath;
- pack_t *pak;
- fileInPack_t *pakFile;
- directory_t *dir;
+long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_t *file, qboolean uniqueFILE)
+{
long hash;
- FILE *temp;
- int l;
+ pack_t *pak;
+ fileInPack_t *pakFile;
+ directory_t *dir;
+ char *netpath;
+ FILE *filep;
+ int len;
- hash = 0;
+ if(filename == NULL)
+ Com_Error(ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed");
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
+ // qpaths are not supposed to have a leading slash
+ if(filename[0] == '/' || filename[0] == '\\')
+ filename++;
+
+ // make absolutely sure that it can't back up the path.
+ // The searchpaths do guarantee that something will always
+ // be prepended, so we don't need to worry about "c:" or "//limbo"
+ if(strstr(filename, ".." ) || strstr(filename, "::"))
+ {
+ if(file == NULL)
+ return qfalse;
+
+ *file = 0;
+ return -1;
}
- if ( file == NULL ) {
+ if(file == NULL)
+ {
// just wants to see if file is there
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
+
+ // is the element a pak file?
+ if(search->pack)
+ {
+ hash = FS_HashFileName(filename, search->pack->hashSize);
+
+ if(search->pack->hashTable[hash])
+ {
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
- do {
+
+ do
+ {
// case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
+ if(!FS_FilenameCompare(pakFile->name, filename))
+ {
// found it!
- return qtrue;
+ if(pakFile->len)
+ return pakFile->len;
+ else
+ {
+ // It's not nice, but legacy code depends
+ // on positive value if file exists no matter
+ // what size
+ return 1;
+ }
}
+
pakFile = pakFile->next;
} while(pakFile != NULL);
- } else if ( search->dir ) {
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- temp = fopen (netpath, "rb");
- if ( !temp ) {
- continue;
- }
- fclose(temp);
- return qtrue;
}
}
- return qfalse;
- }
-
- if ( !filename ) {
- Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed" );
- }
-
- // qpaths are not supposed to have a leading slash
- if ( filename[0] == '/' || filename[0] == '\\' ) {
- filename++;
- }
+ else if(search->dir)
+ {
+ dir = search->dir;
+
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = fopen (netpath, "rb");
- // make absolutely sure that it can't back up the path.
- // The searchpaths do guarantee that something will always
- // be prepended, so we don't need to worry about "c:" or "//limbo"
- if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
- *file = 0;
- return -1;
+ if(filep)
+ {
+ len = FS_fplength(filep);
+ fclose(filep);
+
+ if(len)
+ return len;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
}
- //
- // search through the path, one element at a time
- //
-
*file = FS_HandleForFile();
fsh[*file].handleFiles.unique = uniqueFILE;
+
+ // is the element a pak file?
+ if(search->pack)
+ {
+ hash = FS_HashFileName(filename, search->pack->hashSize);
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- //
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
+ if(search->pack->hashTable[hash])
+ {
// disregard if it doesn't match one of the allowed pure pak files
- if ( !FS_PakIsPure(search->pack) ) {
- continue;
+ if(!FS_PakIsPure(search->pack))
+ {
+ *file = 0;
+ return -1;
}
// look through all the pak file elements
pak = search->pack;
pakFile = pak->hashTable[hash];
- do {
+
+ do
+ {
// case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
+ if(!FS_FilenameCompare(pakFile->name, filename))
+ {
// found it!
// mark the pak as having been referenced and mark specifics on cgame and ui
// shaders, txt, arena files by themselves do not count as a reference as
// these are loaded from all pk3s
// from every pk3 file..
- l = strlen(filename);
-
+ len = strlen(filename);
+
if (!(pak->referenced & FS_GENERAL_REF))
{
- if(!FS_IsExt(filename, ".shader", l) &&
- !FS_IsExt(filename, ".txt", l) &&
- !FS_IsExt(filename, ".cfg", l) &&
- !FS_IsExt(filename, ".config", l) &&
- !FS_IsExt(filename, ".bot", l) &&
- !FS_IsExt(filename, ".arena", l) &&
- !FS_IsExt(filename, ".menu", l) &&
+ if(!FS_IsExt(filename, ".shader", len) &&
+ !FS_IsExt(filename, ".txt", len) &&
+ !FS_IsExt(filename, ".cfg", len) &&
+ !FS_IsExt(filename, ".config", len) &&
+ !FS_IsExt(filename, ".bot", len) &&
+ !FS_IsExt(filename, ".arena", len) &&
+ !FS_IsExt(filename, ".menu", len) &&
!strstr(filename, "levelshots"))
{
pak->referenced |= FS_GENERAL_REF;
}
}
- if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "game.qvm")) {
+ if(strstr(filename, "game.qvm"))
pak->referenced |= FS_QAGAME_REF;
- }
- if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) {
+ if(strstr(filename, "cgame.qvm"))
pak->referenced |= FS_CGAME_REF;
- }
- if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) {
+ if(strstr(filename, "ui.qvm"))
pak->referenced |= FS_UI_REF;
- }
- if ( uniqueFILE ) {
+ if(uniqueFILE)
+ {
// open a new file on the pakfile
- fsh[*file].handleFiles.file.z = unzOpen (pak->pakFilename);
- if (fsh[*file].handleFiles.file.z == NULL) {
- Com_Error (ERR_FATAL, "Couldn't open %s", pak->pakFilename);
- }
- } else {
- fsh[*file].handleFiles.file.z = pak->handle;
+ fsh[*file].handleFiles.file.z = unzOpen(pak->pakFilename);
+
+ if(fsh[*file].handleFiles.file.z == NULL)
+ Com_Error(ERR_FATAL, "Couldn't open %s", pak->pakFilename);
}
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
+ else
+ fsh[*file].handleFiles.file.z = pak->handle;
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
fsh[*file].zipFile = qtrue;
+
// set the file position in the zip file (also sets the current file info)
unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos);
+
// open the file in the zip
- unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
+ unzOpenCurrentFile(fsh[*file].handleFiles.file.z);
fsh[*file].zipFilePos = pakFile->pos;
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
- filename, pak->pakFilename );
+ if(fs_debug->integer)
+ {
+ Com_Printf("FS_FOpenFileRead: %s (found in '%s')\n",
+ filename, pak->pakFilename);
}
+
return pakFile->len;
}
+
pakFile = pakFile->next;
} while(pakFile != NULL);
- } else if ( search->dir ) {
- // check a file in the directory tree
-
- // if we are running restricted, the only files we
- // will allow to come from the directory are .cfg files
- l = strlen( filename );
- // FIXME TTimo I'm not sure about the fs_numServerPaks test
- // if you are using FS_ReadFile to find out if a file exists,
- // this test can make the search fail although the file is in the directory
- // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
- // turned out I used FS_FileExists instead
- if(fs_numServerPaks)
+ }
+ }
+ else if(search->dir)
+ {
+ // check a file in the directory tree
+
+ // if we are running restricted, the only files we
+ // will allow to come from the directory are .cfg files
+ len = strlen(filename);
+ // FIXME TTimo I'm not sure about the fs_numServerPaks test
+ // if you are using FS_ReadFile to find out if a file exists,
+ // this test can make the search fail although the file is in the directory
+ // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8
+ // turned out I used FS_FileExists instead
+ if(fs_numServerPaks)
+ {
+ if(!FS_IsExt(filename, ".cfg", len) && // for config files
+ !FS_IsExt(filename, ".menu", len) && // menu files
+ !FS_IsExt(filename, ".game", len) && // menu files
+ !FS_IsExt(filename, ".dat", len) && // for journal files
+ !FS_IsDemoExt(filename, len)) // demos
{
- if(!FS_IsExt(filename, ".cfg", l) && // for config files
- !FS_IsExt(filename, ".menu", l) && // menu files
- !FS_IsExt(filename, ".game", l) && // menu files
- !FS_IsExt(filename, ".dat", l) && // for journal files
- !FS_IsDemoExt(filename, l)) // demos
- {
- continue;
- }
+ *file = 0;
+ return -1;
}
+ }
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- fsh[*file].handleFiles.file.o = fopen (netpath, "rb");
- if ( !fsh[*file].handleFiles.file.o ) {
- continue;
- }
+ dir = search->dir;
- Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
- fsh[*file].zipFile = qfalse;
- if ( fs_debug->integer ) {
- Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
- dir->path, dir->gamedir );
- }
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+ filep = fopen(netpath, "rb");
- return FS_filelength (*file);
- }
+ if (filep == NULL)
+ {
+ *file = 0;
+ return -1;
+ }
+
+ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name));
+ fsh[*file].zipFile = qfalse;
+
+ if(fs_debug->integer)
+ {
+ Com_Printf("FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
+ dir->path, dir->gamedir);
+ }
+
+ fsh[*file].handleFiles.file.o = filep;
+ return FS_fplength(filep);
+ }
+
+ return -1;
+}
+
+/*
+===========
+FS_FOpenFileRead
+
+Finds the file in the search path.
+Returns filesize and an open FILE pointer.
+Used for streaming data out of either a
+separate file or a ZIP file.
+===========
+*/
+long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE)
+{
+ searchpath_t *search;
+ long len;
+
+ if(!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ for(search = fs_searchpaths; search; search = search->next)
+ {
+ len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE);
+
+ if(file == NULL)
+ {
+ if(len > 0)
+ return len;
+ }
+ else
+ {
+ if(len >= 0 && *file)
+ return len;
+ }
+
}
#ifdef FS_MISSING
- if (missingFiles) {
+ if(missingFiles)
fprintf(missingFiles, "%s\n", filename);
- }
#endif
- *file = 0;
+
+ if(file)
+ *file = 0;
+
return -1;
}
+/*
+=================
+FS_FindVM
-char *FS_FindDll( const char *filename ) {
- searchpath_t *search;
- directory_t *dir;
+Find a suitable VM file in search path order.
- if ( !fs_searchpaths ) {
- Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
- }
+In each searchpath try:
+ - open DLL file if DLL loading enabled
+ - open QVM file
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- if ( search->dir ) {
- FILE *f;
- char *netpath;
+Enable search for DLL by setting enableDll to FSVM_ENABLEDLL
+write found DLL or QVM to "found" and return VMI_NATIVE if DLL, VMI_COMPILED if QVM
+Return the searchpath in "startSearch".
+=================
+*/
+
+vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll)
+{
+ searchpath_t *search, *lastSearch;
+ directory_t *dir;
+ pack_t *pack;
+ char dllName[MAX_OSPATH], qvmName[MAX_OSPATH];
+ char *netpath;
+
+ if(!fs_searchpaths)
+ Com_Error(ERR_FATAL, "Filesystem call made without initialization");
+
+ if(enableDll)
+ Com_sprintf(dllName, sizeof(dllName), "%s" ARCH_STRING DLL_EXT, name);
+
+ Com_sprintf(qvmName, sizeof(dllName), "vm/%s.qvm", name);
+
+ lastSearch = *startSearch;
+ if(*startSearch == NULL)
+ search = fs_searchpaths;
+ else
+ search = lastSearch->next;
+
+ while(search)
+ {
+ if(search->dir)
+ {
dir = search->dir;
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- f = fopen( netpath, "rb" );
- if (f) {
- fclose( f );
- return netpath;
+
+ if(enableDll)
+ {
+ netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
+
+ if(FS_FileInPathExists(netpath))
+ {
+ Q_strncpyz(found, netpath, foundlen);
+ *startSearch = search;
+
+ return VMI_NATIVE;
+ }
+ }
+
+ if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0)
+ {
+ *startSearch = search;
+ return VMI_COMPILED;
+ }
+ }
+ else if(search->pack)
+ {
+ pack = search->pack;
+
+ if(lastSearch && lastSearch->pack)
+ {
+ // make sure we only try loading one VM file per game dir
+ // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3
+
+ if(!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname))
+ {
+ search = search->next;
+ continue;
+ }
+ }
+
+ if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse) > 0)
+ {
+ *startSearch = search;
+
+ return VMI_COMPILED;
}
}
+
+ search = search->next;
}
- return NULL;
+ return -1;
}
/*
@@ -1543,17 +1707,20 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ) {
/*
============
-FS_ReadFile
+FS_ReadFileDir
Filename are relative to the quake search path
a null buffer will just return the file length without loading
+If searchPath is non-NULL search only in that specific search path
============
*/
-int FS_ReadFile( const char *qpath, void **buffer ) {
+long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer)
+{
fileHandle_t h;
+ searchpath_t *search;
byte* buf;
qboolean isConfig;
- int len;
+ long len;
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
@@ -1610,8 +1777,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
isConfig = qfalse;
}
- // look for it in the filesystem or pack files
- len = FS_FOpenFileRead( qpath, &h, qfalse );
+ search = searchPath;
+
+ if(search == NULL)
+ {
+ // look for it in the filesystem or pack files
+ len = FS_FOpenFileRead(qpath, &h, qfalse);
+ }
+ else
+ {
+ // look for it in a specific search path only
+ len = FS_FOpenFileReadDir(qpath, search, &h, qfalse);
+ }
+
if ( h == 0 ) {
if ( buffer ) {
*buffer = NULL;
@@ -1659,6 +1837,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
}
/*
+============
+FS_ReadFile
+
+Filename are relative to the quake search path
+a null buffer will just return the file length without loading
+============
+*/
+long FS_ReadFile(const char *qpath, void **buffer)
+{
+ return FS_ReadFileDir(qpath, NULL, buffer);
+}
+
+/*
=============
FS_FreeFile
=============
@@ -2514,21 +2705,40 @@ void FS_TouchFile_f( void ) {
/*
============
+FS_Which
+============
+*/
+
+qboolean FS_Which(const char *filename, void *searchPath)
+{
+ searchpath_t *search = searchPath;
+
+ if(FS_FOpenFileReadDir(filename, search, NULL, qfalse) > 0)
+ {
+ if(search->pack)
+ {
+ Com_Printf("File \"%s\" found in \"%s\"\n", filename, search->pack->pakFilename);
+ return qtrue;
+ }
+ else if(search->dir)
+ {
+ Com_Printf( "File \"%s\" found at \"%s\"\n", filename, search->dir->fullpath);
+ return qtrue;
+ }
+ }
+
+ return qfalse;
+}
+
+/*
+============
FS_Which_f
============
*/
void FS_Which_f( void ) {
searchpath_t *search;
- char *netpath;
- pack_t *pak;
- fileInPack_t *pakFile;
- directory_t *dir;
- long hash;
- FILE *temp;
- char *filename;
- char buf[ MAX_OSPATH ];
+ char *filename;
- hash = 0;
filename = Cmd_Argv(1);
if ( !filename[0] ) {
@@ -2542,40 +2752,13 @@ void FS_Which_f( void ) {
}
// just wants to see if file is there
- for ( search = fs_searchpaths ; search ; search = search->next ) {
- if ( search->pack ) {
- hash = FS_HashFileName(filename, search->pack->hashSize);
- }
- // is the element a pak file?
- if ( search->pack && search->pack->hashTable[hash] ) {
- // look through all the pak file elements
- pak = search->pack;
- pakFile = pak->hashTable[hash];
- do {
- // case and separator insensitive comparisons
- if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
- // found it!
- Com_Printf( "File \"%s\" found in \"%s\"\n", filename, pak->pakFilename );
- return;
- }
- pakFile = pakFile->next;
- } while(pakFile != NULL);
- } else if ( search->dir ) {
- dir = search->dir;
-
- netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
- temp = fopen (netpath, "rb");
- if ( !temp ) {
- continue;
- }
- fclose(temp);
- Com_sprintf( buf, sizeof( buf ), "%s/%s", dir->path, dir->gamedir );
- FS_ReplaceSeparators( buf );
- Com_Printf( "File \"%s\" found at \"%s\"\n", filename, buf );
+ for(search = fs_searchpaths; search; search = search->next)
+ {
+ if(FS_Which(filename, search))
return;
- }
}
- Com_Printf( "File not found: \"%s\"\n", filename );
+
+ Com_Printf("File not found: \"%s\"\n", filename);
return;
}
@@ -2605,7 +2788,7 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
int i;
searchpath_t *search;
pack_t *pak;
- char *pakfile;
+ char curpath[MAX_OSPATH + 1], *pakfile;
int numfiles;
char **pakfiles;
@@ -2618,22 +2801,11 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );
- //
- // add the directory to the search path
- //
- search = Z_Malloc (sizeof(searchpath_t));
- search->dir = Z_Malloc( sizeof( *search->dir ) );
-
- Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) );
- Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) );
- search->next = fs_searchpaths;
- fs_searchpaths = search;
-
// find all pak files in this directory
- pakfile = FS_BuildOSPath( path, dir, "" );
- pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash
+ Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath));
+ curpath[strlen(curpath) - 1] = '\0'; // strip the trailing slash
- pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse );
+ pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse);
qsort( pakfiles, numfiles, sizeof(char*), paksort );
@@ -2641,8 +2813,10 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
pakfile = FS_BuildOSPath( path, dir, pakfiles[i] );
if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 )
continue;
+
+ Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname));
// store the game name for downloading
- strcpy(pak->pakGamename, dir);
+ Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename));
fs_packFiles += pak->numfiles;
@@ -2654,6 +2828,19 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
// done
Sys_FreeFileList( pakfiles );
+
+ //
+ // add the directory to the search path
+ //
+ search = Z_Malloc (sizeof(searchpath_t));
+ search->dir = Z_Malloc( sizeof( *search->dir ) );
+
+ Q_strncpyz(search->dir->path, path, sizeof(search->dir->path));
+ Q_strncpyz(search->dir->fullpath, curpath, sizeof(search->dir->fullpath));
+ Q_strncpyz(search->dir->gamedir, dir, sizeof(search->dir->gamedir));
+
+ search->next = fs_searchpaths;
+ fs_searchpaths = search;
}
/*
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index d09ee299..2cf2b27b 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -602,7 +602,7 @@ qboolean FS_FileExists( const char *file );
qboolean FS_CreatePath (char *OSPath);
-char *FS_FindDll( const char *filename );
+vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll);
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
qboolean FS_CompareZipChecksum(const char *zipfile);
@@ -618,9 +618,9 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename );
// will properly create any needed paths and deal with seperater character issues
fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
-int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
+long FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
void FS_SV_Rename( const char *from, const char *to );
-int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
+long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE );
// if uniqueFILE is true, then a new FILE will be fopened even if the file
// is found in an already open pak file. If uniqueFILE is false, you must call
// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed
@@ -639,7 +639,8 @@ int FS_Read( void *buffer, int len, fileHandle_t f );
void FS_FCloseFile( fileHandle_t f );
// note: you can't just fclose from another DLL, due to MS libc issues
-int FS_ReadFile( const char *qpath, void **buffer );
+long FS_ReadFileDir(const char *qpath, void *searchPath, void **buffer);
+long FS_ReadFile(const char *qpath, void **buffer);
// returns the length of the file
// a null buffer will just return the file length without loading
// as a quick check for existance. -1 length == not present
@@ -656,7 +657,7 @@ void FS_FreeFile( void *buffer );
void FS_WriteFile( const char *qpath, const void *buffer, int size );
// writes a complete file, creating any subdirectories needed
-int FS_filelength( fileHandle_t f );
+long FS_filelength(fileHandle_t f);
// doesn't work for files that are opened from a pack file
int FS_FTell( fileHandle_t f );
@@ -713,6 +714,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext,
qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
const char *FS_GetCurrentGameDir(void);
+qboolean FS_Which(const char *filename, void *searchPath);
/*
==============================================================
diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c
index 5476a085..c53d8067 100644
--- a/src/qcommon/vm.c
+++ b/src/qcommon/vm.c
@@ -378,15 +378,20 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
// load the image
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
Com_Printf( "Loading vm file %s...\n", filename );
- length = FS_ReadFile( filename, &header.v );
+
+ length = FS_ReadFileDir(filename, vm->searchPath, &header.v);
+
if ( !header.h ) {
Com_Printf( "Failed.\n" );
VM_Free( vm );
+
+ Com_Printf(S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename);
+
return NULL;
}
// show where the qvm was loaded from
- Cmd_ExecuteString( va( "which %s\n", filename ) );
+ FS_Which(filename, vm->searchPath);
if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
@@ -401,9 +406,13 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
|| header.h->bssLength < 0
|| header.h->dataLength < 0
|| header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
}
} else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
// byte swap the header
@@ -416,14 +425,21 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
if ( header.h->bssLength < 0
|| header.h->dataLength < 0
|| header.h->litLength < 0
- || header.h->codeLength <= 0 ) {
- VM_Free( vm );
- Com_Error( ERR_FATAL, "%s has bad header", filename );
+ || header.h->codeLength <= 0 )
+ {
+ VM_Free(vm);
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
+ return NULL;
}
} else {
VM_Free( vm );
- Com_Error( ERR_FATAL, "%s does not have a recognisable "
- "magic number in its header", filename );
+ FS_FreeFile(header.v);
+
+ Com_Printf(S_COLOR_YELLOW "Warning: %s does not have a recognisable "
+ "magic number in its header\n", filename);
+ return NULL;
}
// round up to next power of 2 so all data operations can
@@ -525,7 +541,9 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
vmInterpret_t interpret ) {
vm_t *vm;
vmHeader_t *header;
- int i, remaining;
+ int i, remaining, retval;
+ char filename[MAX_OSPATH];
+ void *startSearch = NULL;
if ( !module || !module[0] || !systemCalls ) {
Com_Error( ERR_FATAL, "VM_Create: bad parms" );
@@ -554,25 +572,41 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
vm = &vmTable[i];
- Q_strncpyz( vm->name, module, sizeof( vm->name ) );
- vm->systemCall = systemCalls;
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
- if ( interpret == VMI_NATIVE ) {
- // try to load as a system dll
- Com_Printf( "Loading dll file %s.\n", vm->name );
- vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall );
- if ( vm->dllHandle ) {
- return vm;
+ do
+ {
+ retval = FS_FindVM(&startSearch, filename, sizeof(filename), module, (interpret == VMI_NATIVE));
+
+ if(retval == VMI_NATIVE)
+ {
+ Com_Printf("Try loading dll file %s\n", filename);
+
+ vm->dllHandle = Sys_LoadDll(filename, &vm->entryPoint, VM_DllSyscall);
+
+ if(vm->dllHandle)
+ {
+ vm->systemCall = systemCalls;
+ return vm;
+ }
+
+ Com_Printf("Failed loading dll, trying next\n");
}
-
- Com_Printf( "Failed to load dll, looking for qvm.\n" );
- interpret = VMI_COMPILED;
- }
-
- // load the image
- if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
+ else if(retval == VMI_COMPILED)
+ {
+ vm->searchPath = startSearch;
+ if((header = VM_LoadQVM(vm, qtrue)))
+ break;
+
+ // VM_Free overwrites the name on failed load
+ Q_strncpyz(vm->name, module, sizeof(vm->name));
+ }
+ } while(retval >= 0);
+
+ if(retval < 0)
return NULL;
- }
+
+ vm->systemCall = systemCalls;
// allocate space for the jump targets, which will be filled in by the compile/prep functions
vm->instructionCount = header->instructionCount;
diff --git a/src/qcommon/vm_local.h b/src/qcommon/vm_local.h
index c7270600..ee44133a 100644
--- a/src/qcommon/vm_local.h
+++ b/src/qcommon/vm_local.h
@@ -142,7 +142,8 @@ struct vm_s {
//------------------------------------
- char name[MAX_QPATH];
+ char name[MAX_QPATH];
+ void *searchPath; // hint for FS_ReadFileDir()
// for dynamic linked modules
void *dllHandle;
diff --git a/src/renderer/tr_public.h b/src/renderer/tr_public.h
index 5126ab49..1a7d93c2 100644
--- a/src/renderer/tr_public.h
+++ b/src/renderer/tr_public.h
@@ -149,7 +149,7 @@ typedef struct {
// a -1 return means the file does not exist
// NULL can be passed for buf to just determine existance
int (*FS_FileIsInPAK)( const char *name, int *pCheckSum );
- int (*FS_ReadFile)( const char *name, void **buf );
+ long (*FS_ReadFile)( const char *name, void **buf );
void (*FS_FreeFile)( void *buf );
char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
void (*FS_FreeFileList)( char **filelist );
diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c
index 07e8e395..5036009e 100644
--- a/src/sys/sys_main.c
+++ b/src/sys/sys_main.c
@@ -413,35 +413,23 @@ void Sys_UnloadDll( void *dllHandle )
Sys_LoadDll
Used to load a development dll instead of a virtual machine
-#1 look in fs_homepath
-#2 look in fs_basepath
=================
*/
-void * QDECL Sys_LoadDll( const char *name,
+void *Sys_LoadDll(const char *name,
intptr_t (QDECL **entryPoint)(int, ...),
- intptr_t (*systemcalls)(intptr_t, ...) )
+ intptr_t (*systemcalls)(intptr_t, ...))
{
- void *libHandle;
- void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
- char fname[MAX_OSPATH];
- char *netpath;
+ void *libHandle;
+ void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...));
- assert( name );
+ assert(name);
- Com_sprintf(fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name);
+ Com_Printf( "Loading DLL file: %s\n", name);
+ libHandle = Sys_LoadLibrary(name);
- netpath = FS_FindDll(fname);
-
- if(!netpath) {
- Com_Printf( "Sys_LoadDll(%s) could not find it\n", fname );
- return NULL;
- }
-
- Com_Printf( "Loading DLL file: %s\n", netpath);
- libHandle = Sys_LoadLibrary(netpath);
-
- if(!libHandle) {
- Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", netpath, Sys_LibraryError() );
+ if(!libHandle)
+ {
+ Com_Printf("Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
return NULL;
}