[quake3-commits] r2029 - in trunk/code: qcommon renderer sys

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Jun 15 18:09:27 EDT 2011


Author: thilo
Date: 2011-06-15 18:09:26 -0400 (Wed, 15 Jun 2011)
New Revision: 2029

Modified:
   trunk/code/qcommon/files.c
   trunk/code/qcommon/qcommon.h
   trunk/code/qcommon/vm.c
   trunk/code/qcommon/vm_local.h
   trunk/code/renderer/tr_public.h
   trunk/code/sys/sys_main.c
Log:
- Small change to search path order - local files not in .pk3s take precedence over files in pk3s. Should make life easier for modders/mappers wanting to override textures that are already contained in some older pk3
- Make VM loading more robust, change loading order: when vm_* == 0 first try loading DLL, then QVM in *each* search directory/path
- Fix FS_FileForHandle that would return a FILE pointer to invalid file handle 0


Modified: trunk/code/qcommon/files.c
===================================================================
--- trunk/code/qcommon/files.c	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/qcommon/files.c	2011-06-15 22:09:26 UTC (rev 2029)
@@ -215,6 +215,7 @@
 } fileInPack_t;
 
 typedef struct {
+        char			pakPathname[MAX_OSPATH];	// c:\quake3\baseq3
 	char			pakFilename[MAX_OSPATH];	// c:\quake3\baseq3\pak0.pk3
 	char			pakBasename[MAX_OSPATH];	// pak0
 	char			pakGamename[MAX_OSPATH];	// baseq3
@@ -230,6 +231,7 @@
 
 typedef struct {
 	char		path[MAX_OSPATH];		// c:\quake3
+	char		fullpath[MAX_OSPATH];		// c:\quake3\baseq3
 	char		gamedir[MAX_OSPATH];	// baseq3
 } directory_t;
 
@@ -393,7 +395,7 @@
 }
 
 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) {
@@ -415,6 +417,25 @@
 
 /*
 ================
+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),
@@ -422,18 +443,16 @@
 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);
 }
 
 /*
@@ -572,6 +591,28 @@
 
 /*
 ================
+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
@@ -580,19 +621,9 @@
 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));
 }
 
 /*
@@ -604,18 +635,12 @@
 */
 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);
 }
 
 
@@ -669,7 +694,8 @@
 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;
 
@@ -1042,250 +1068,392 @@
 
 /*
 ===========
-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;
+long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_t *file, qboolean uniqueFILE)
+{
+	long			hash;
+	pack_t		*pak;
 	fileInPack_t	*pakFile;
-	directory_t		*dir;
-	long			hash;
-	FILE			*temp;
-	int				l;
+	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;
 	}
+        
+	// make sure the q3key file is only readable by the quake3.exe at initialization
+	// any other time the key should only be accessed in memory using the provided functions
+	if(com_fullyInitialized && strstr(filename, "q3key"))
+	{
+	        if(file == NULL)
+	                return qfalse;
 
-	if ( file == NULL ) {
+		*file = 0;
+		return -1;
+	}
+
+	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;
-	}
+		else if(search->dir)
+		{
+			dir = search->dir;
+		
+			netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
+			filep = fopen (netpath, "rb");
 
-	if ( !filename ) {
-		Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed" );
+			if(filep)
+			{
+			        len = FS_fplength(filep);
+				fclose(filep);
+				
+				if(len)
+        				return len;
+                                else
+                                        return 1;
+			}
+		}
+		
+		return 0;
 	}
 
-	// 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, "::" ) ) {
-		*file = 0;
-		return -1;
-	}
-
-	// make sure the q3key file is only readable by the quake3.exe at initialization
-	// any other time the key should only be accessed in memory using the provided functions
-	if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
-		*file = 0;
-		return -1;
-	}
-
-	//
-	// 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, "qagame.qvm")) {
+					if(strstr(filename, "qagame.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 = 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;
-					}
-					Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
+
+					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
+		}
+	}
+	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)
+		// 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, ".cfg", 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, ".cfg", 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;
 }
 
 /*
@@ -1572,17 +1740,20 @@
 
 /*
 ============
-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" );
@@ -1639,8 +1810,19 @@
 		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;
@@ -1688,6 +1870,19 @@
 }
 
 /*
+============
+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
 =============
@@ -2543,21 +2738,40 @@
 
 /*
 ============
+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] ) {
@@ -2571,40 +2785,13 @@
 	}
 
 	// 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;
 }
 
@@ -2634,7 +2821,7 @@
 	int				i;
 	searchpath_t	*search;
 	pack_t			*pak;
-	char			*pakfile;
+	char			curpath[MAX_OSPATH + 1], *pakfile;
 	int				numfiles;
 	char			**pakfiles;
 
@@ -2647,22 +2834,11 @@
 	
 	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 );
 
@@ -2670,8 +2846,10 @@
 		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;
 
@@ -2683,6 +2861,19 @@
 
 	// 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;
 }
 
 /*
@@ -2768,7 +2959,7 @@
 		// never autodownload any of the id paks
 		if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS)
 #ifndef STANDALONE
-	           || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS)
+		   || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS)
 #endif
 		  )
 		{
@@ -3803,7 +3994,7 @@
 const char *FS_GetCurrentGameDir(void)
 {
 	if(fs_gamedirvar->string[0])
-	        return fs_gamedirvar->string;
+		return fs_gamedirvar->string;
 
-        return com_basegame->string;
+	return com_basegame->string;
 }

Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/qcommon/qcommon.h	2011-06-15 22:09:26 UTC (rev 2029)
@@ -614,7 +614,7 @@
 
 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);
@@ -630,9 +630,9 @@
 // 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
@@ -651,7 +651,8 @@
 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
@@ -668,7 +669,7 @@
 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 );
@@ -726,6 +727,7 @@
 		qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
 
 const char *FS_GetCurrentGameDir(void);
+qboolean FS_Which(const char *filename, void *searchPath);
 
 /*
 ==============================================================

Modified: trunk/code/qcommon/vm.c
===================================================================
--- trunk/code/qcommon/vm.c	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/qcommon/vm.c	2011-06-15 22:09:26 UTC (rev 2029)
@@ -377,15 +377,20 @@
 	// 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" );
@@ -400,9 +405,13 @@
 			|| 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
@@ -415,14 +424,21 @@
 		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
@@ -524,7 +540,9 @@
 				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" );
@@ -553,26 +571,42 @@
 
 	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");
 		}
+		else if(retval == VMI_COMPILED)
+		{
+			vm->searchPath = startSearch;
+			if((header = VM_LoadQVM(vm, qtrue)))
+				break;
 
-		Com_Printf( "Failed to load dll, looking for qvm.\n" );
-		interpret = VMI_COMPILED;
-	}
-
-	// load the image
-	if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
+			// 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;
 	vm->instructionPointers = Hunk_Alloc(vm->instructionCount * sizeof(*vm->instructionPointers), h_high);

Modified: trunk/code/qcommon/vm_local.h
===================================================================
--- trunk/code/qcommon/vm_local.h	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/qcommon/vm_local.h	2011-06-15 22:09:26 UTC (rev 2029)
@@ -141,7 +141,8 @@
 
 	//------------------------------------
    
-    char		name[MAX_QPATH];
+	char		name[MAX_QPATH];
+	void	*searchPath;				// hint for FS_ReadFileDir()
 
 	// for dynamic linked modules
 	void		*dllHandle;

Modified: trunk/code/renderer/tr_public.h
===================================================================
--- trunk/code/renderer/tr_public.h	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/renderer/tr_public.h	2011-06-15 22:09:26 UTC (rev 2029)
@@ -147,7 +147,7 @@
 	// 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 );

Modified: trunk/code/sys/sys_main.c
===================================================================
--- trunk/code/sys/sys_main.c	2011-06-15 16:26:51 UTC (rev 2028)
+++ trunk/code/sys/sys_main.c	2011-06-15 22:09:26 UTC (rev 2029)
@@ -412,38 +412,26 @@
 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 );
+	if(!libHandle)
+	{
+		Com_Printf("Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
 		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() );
-		return NULL;
-	}
-
 	dllEntry = Sys_LoadFunction( libHandle, "dllEntry" );
 	*entryPoint = Sys_LoadFunction( libHandle, "vmMain" );
 



More information about the quake3-commits mailing list