mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2024-11-10 14:41:42 +00:00
- 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
This commit is contained in:
parent
1ff28b3b2e
commit
9219cde4e8
6 changed files with 584 additions and 368 deletions
|
@ -215,6 +215,7 @@ typedef struct fileInPack_s {
|
||||||
} fileInPack_t;
|
} fileInPack_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
char pakPathname[MAX_OSPATH]; // c:\quake3\baseq3
|
||||||
char pakFilename[MAX_OSPATH]; // c:\quake3\baseq3\pak0.pk3
|
char pakFilename[MAX_OSPATH]; // c:\quake3\baseq3\pak0.pk3
|
||||||
char pakBasename[MAX_OSPATH]; // pak0
|
char pakBasename[MAX_OSPATH]; // pak0
|
||||||
char pakGamename[MAX_OSPATH]; // baseq3
|
char pakGamename[MAX_OSPATH]; // baseq3
|
||||||
|
@ -230,6 +231,7 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char path[MAX_OSPATH]; // c:\quake3
|
char path[MAX_OSPATH]; // c:\quake3
|
||||||
|
char fullpath[MAX_OSPATH]; // c:\quake3\baseq3
|
||||||
char gamedir[MAX_OSPATH]; // baseq3
|
char gamedir[MAX_OSPATH]; // baseq3
|
||||||
} directory_t;
|
} directory_t;
|
||||||
|
|
||||||
|
@ -393,7 +395,7 @@ static fileHandle_t FS_HandleForFile(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *FS_FileForHandle( fileHandle_t f ) {
|
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" );
|
Com_Error( ERR_DROP, "FS_FileForHandle: out of range" );
|
||||||
}
|
}
|
||||||
if (fsh[f].zipFile == qtrue) {
|
if (fsh[f].zipFile == qtrue) {
|
||||||
|
@ -413,6 +415,25 @@ void FS_ForceFlush( fileHandle_t f ) {
|
||||||
setvbuf( file, NULL, _IONBF, 0 );
|
setvbuf( file, NULL, _IONBF, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
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
|
FS_filelength
|
||||||
|
@ -422,18 +443,16 @@ it will return the size of the pak file, not the expected
|
||||||
size of the file.
|
size of the file.
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
int FS_filelength( fileHandle_t f ) {
|
long FS_filelength(fileHandle_t f)
|
||||||
int pos;
|
{
|
||||||
int end;
|
FILE *h;
|
||||||
FILE* h;
|
|
||||||
|
|
||||||
h = FS_FileForHandle(f);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -570,6 +589,28 @@ void FS_HomeRemove( const char *homePath ) {
|
||||||
fs_gamedir, homePath ) );
|
fs_gamedir, 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
|
FS_FileExists
|
||||||
|
@ -580,19 +621,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
|
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;
|
return FS_FileInPathExists(FS_BuildOSPath(fs_homepath->string, fs_gamedir, file));
|
||||||
char *testpath;
|
|
||||||
|
|
||||||
testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
|
|
||||||
|
|
||||||
f = fopen( testpath, "rb" );
|
|
||||||
if (f) {
|
|
||||||
fclose( f );
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
return qfalse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -604,18 +635,12 @@ Tests if the file exists
|
||||||
*/
|
*/
|
||||||
qboolean FS_SV_FileExists( const char *file )
|
qboolean FS_SV_FileExists( const char *file )
|
||||||
{
|
{
|
||||||
FILE *f;
|
|
||||||
char *testpath;
|
char *testpath;
|
||||||
|
|
||||||
testpath = FS_BuildOSPath( fs_homepath->string, file, "");
|
testpath = FS_BuildOSPath( fs_homepath->string, file, "");
|
||||||
testpath[strlen(testpath)-1] = '\0';
|
testpath[strlen(testpath)-1] = '\0';
|
||||||
|
|
||||||
f = fopen( testpath, "rb" );
|
return FS_FileInPathExists(testpath);
|
||||||
if (f) {
|
|
||||||
fclose( f );
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
return qfalse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -669,7 +694,8 @@ Search for a file somewhere below the home path then base path
|
||||||
in that order
|
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;
|
char *ospath;
|
||||||
fileHandle_t f = 0;
|
fileHandle_t f = 0;
|
||||||
|
|
||||||
|
@ -1040,6 +1066,256 @@ qboolean FS_IsDemoExt(const char *filename, int namelen)
|
||||||
return qfalse;
|
return qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===========
|
||||||
|
FS_FOpenFileReadDir
|
||||||
|
|
||||||
|
Tries opening file "filename" in searchpath "search"
|
||||||
|
Returns filesize and an open FILE pointer.
|
||||||
|
===========
|
||||||
|
*/
|
||||||
|
extern qboolean com_fullyInitialized;
|
||||||
|
|
||||||
|
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;
|
||||||
|
char *netpath;
|
||||||
|
FILE *filep;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if(filename == NULL)
|
||||||
|
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++;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
*file = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file == NULL)
|
||||||
|
{
|
||||||
|
// just wants to see if file is there
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// case and separator insensitive comparisons
|
||||||
|
if(!FS_FilenameCompare(pakFile->name, filename))
|
||||||
|
{
|
||||||
|
// found it!
|
||||||
|
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);
|
||||||
|
filep = fopen (netpath, "rb");
|
||||||
|
|
||||||
|
if(filep)
|
||||||
|
{
|
||||||
|
len = FS_fplength(filep);
|
||||||
|
fclose(filep);
|
||||||
|
|
||||||
|
if(len)
|
||||||
|
return len;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*file = FS_HandleForFile();
|
||||||
|
fsh[*file].handleFiles.unique = uniqueFILE;
|
||||||
|
|
||||||
|
// is the element a pak file?
|
||||||
|
if(search->pack)
|
||||||
|
{
|
||||||
|
hash = FS_HashFileName(filename, search->pack->hashSize);
|
||||||
|
|
||||||
|
if(search->pack->hashTable[hash])
|
||||||
|
{
|
||||||
|
// disregard if it doesn't match one of the allowed pure pak files
|
||||||
|
if(!FS_PakIsPure(search->pack))
|
||||||
|
{
|
||||||
|
*file = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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!
|
||||||
|
|
||||||
|
// 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..
|
||||||
|
len = strlen(filename);
|
||||||
|
|
||||||
|
if (!(pak->referenced & FS_GENERAL_REF))
|
||||||
|
{
|
||||||
|
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(strstr(filename, "qagame.qvm"))
|
||||||
|
pak->referenced |= FS_QAGAME_REF;
|
||||||
|
if(strstr(filename, "cgame.qvm"))
|
||||||
|
pak->referenced |= FS_CGAME_REF;
|
||||||
|
if(strstr(filename, "ui.qvm"))
|
||||||
|
pak->referenced |= FS_UI_REF;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
fsh[*file].zipFilePos = pakFile->pos;
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
{
|
||||||
|
*file = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = search->dir;
|
||||||
|
|
||||||
|
netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename);
|
||||||
|
filep = fopen(netpath, "rb");
|
||||||
|
|
||||||
|
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
|
FS_FOpenFileRead
|
||||||
|
@ -1050,242 +1326,134 @@ Used for streaming data out of either a
|
||||||
separate file or a ZIP file.
|
separate file or a ZIP file.
|
||||||
===========
|
===========
|
||||||
*/
|
*/
|
||||||
extern qboolean com_fullyInitialized;
|
long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueFILE)
|
||||||
|
{
|
||||||
int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {
|
|
||||||
searchpath_t *search;
|
searchpath_t *search;
|
||||||
char *netpath;
|
long len;
|
||||||
pack_t *pak;
|
|
||||||
fileInPack_t *pakFile;
|
|
||||||
directory_t *dir;
|
|
||||||
long hash;
|
|
||||||
FILE *temp;
|
|
||||||
int l;
|
|
||||||
|
|
||||||
hash = 0;
|
if(!fs_searchpaths)
|
||||||
|
Com_Error(ERR_FATAL, "Filesystem call made without initialization");
|
||||||
|
|
||||||
if ( !fs_searchpaths ) {
|
for(search = fs_searchpaths; search; search = search->next)
|
||||||
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
|
|
||||||
}
|
|
||||||
|
|
||||||
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] ) {
|
|
||||||
// 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!
|
|
||||||
return qtrue;
|
|
||||||
}
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
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] ) {
|
|
||||||
// disregard if it doesn't match one of the allowed pure pak files
|
|
||||||
if ( !FS_PakIsPure(search->pack) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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!
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (!(pak->referenced & FS_GENERAL_REF))
|
|
||||||
{
|
{
|
||||||
if(!FS_IsExt(filename, ".shader", l) &&
|
len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE);
|
||||||
!FS_IsExt(filename, ".txt", l) &&
|
|
||||||
!FS_IsExt(filename, ".cfg", l) &&
|
if(file == NULL)
|
||||||
!FS_IsExt(filename, ".config", l) &&
|
|
||||||
!FS_IsExt(filename, ".bot", l) &&
|
|
||||||
!FS_IsExt(filename, ".arena", l) &&
|
|
||||||
!FS_IsExt(filename, ".menu", l) &&
|
|
||||||
!strstr(filename, "levelshots"))
|
|
||||||
{
|
{
|
||||||
pak->referenced |= FS_GENERAL_REF;
|
if(len > 0)
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
if (!(pak->referenced & FS_QAGAME_REF) && strstr(filename, "qagame.qvm")) {
|
|
||||||
pak->referenced |= FS_QAGAME_REF;
|
|
||||||
}
|
|
||||||
if (!(pak->referenced & FS_CGAME_REF) && strstr(filename, "cgame.qvm")) {
|
|
||||||
pak->referenced |= FS_CGAME_REF;
|
|
||||||
}
|
|
||||||
if (!(pak->referenced & FS_UI_REF) && strstr(filename, "ui.qvm")) {
|
|
||||||
pak->referenced |= FS_UI_REF;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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 );
|
|
||||||
fsh[*file].zipFilePos = pakFile->pos;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if(!FS_IsExt(filename, ".cfg", l) && // for config files
|
if(len >= 0 && *file)
|
||||||
!FS_IsExt(filename, ".menu", l) && // menu files
|
return len;
|
||||||
!FS_IsExt(filename, ".game", l) && // menu files
|
|
||||||
!FS_IsExt(filename, ".cfg", l) && // for journal files
|
|
||||||
!FS_IsDemoExt(filename, l)) // demos
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return FS_filelength (*file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FS_MISSING
|
#ifdef FS_MISSING
|
||||||
if (missingFiles) {
|
if(missingFiles)
|
||||||
fprintf(missingFiles, "%s\n", filename);
|
fprintf(missingFiles, "%s\n", filename);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(file)
|
||||||
*file = 0;
|
*file = 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================
|
||||||
|
FS_FindVM
|
||||||
|
|
||||||
char *FS_FindDll( const char *filename ) {
|
Find a suitable VM file in search path order.
|
||||||
searchpath_t *search;
|
|
||||||
|
In each searchpath try:
|
||||||
|
- open DLL file if DLL loading enabled
|
||||||
|
- open QVM file
|
||||||
|
|
||||||
|
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;
|
directory_t *dir;
|
||||||
|
pack_t *pack;
|
||||||
if ( !fs_searchpaths ) {
|
char dllName[MAX_OSPATH], qvmName[MAX_OSPATH];
|
||||||
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( search = fs_searchpaths ; search ; search = search->next ) {
|
|
||||||
if ( search->dir ) {
|
|
||||||
FILE *f;
|
|
||||||
char *netpath;
|
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;
|
dir = search->dir;
|
||||||
netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
|
|
||||||
f = fopen( netpath, "rb" );
|
if(enableDll)
|
||||||
if (f) {
|
{
|
||||||
fclose( f );
|
netpath = FS_BuildOSPath(dir->path, dir->gamedir, dllName);
|
||||||
return netpath;
|
|
||||||
}
|
if(FS_FileInPathExists(netpath))
|
||||||
|
{
|
||||||
|
Q_strncpyz(found, netpath, foundlen);
|
||||||
|
*startSearch = search;
|
||||||
|
|
||||||
|
return VMI_NATIVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
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 -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1572,17 +1740,20 @@ int FS_FileIsInPAK(const char *filename, int *pChecksum ) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============
|
============
|
||||||
FS_ReadFile
|
FS_ReadFileDir
|
||||||
|
|
||||||
Filename are relative to the quake search path
|
Filename are relative to the quake search path
|
||||||
a null buffer will just return the file length without loading
|
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;
|
fileHandle_t h;
|
||||||
|
searchpath_t *search;
|
||||||
byte* buf;
|
byte* buf;
|
||||||
qboolean isConfig;
|
qboolean isConfig;
|
||||||
int len;
|
long len;
|
||||||
|
|
||||||
if ( !fs_searchpaths ) {
|
if ( !fs_searchpaths ) {
|
||||||
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
|
Com_Error( ERR_FATAL, "Filesystem call made without initialization" );
|
||||||
|
@ -1639,8 +1810,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
|
||||||
isConfig = qfalse;
|
isConfig = qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
search = searchPath;
|
||||||
|
|
||||||
|
if(search == NULL)
|
||||||
|
{
|
||||||
// look for it in the filesystem or pack files
|
// look for it in the filesystem or pack files
|
||||||
len = FS_FOpenFileRead( qpath, &h, qfalse );
|
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 ( h == 0 ) {
|
||||||
if ( buffer ) {
|
if ( buffer ) {
|
||||||
*buffer = NULL;
|
*buffer = NULL;
|
||||||
|
@ -1687,6 +1869,19 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
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
|
FS_FreeFile
|
||||||
|
@ -2541,6 +2736,33 @@ 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
|
FS_Which_f
|
||||||
|
@ -2548,16 +2770,8 @@ FS_Which_f
|
||||||
*/
|
*/
|
||||||
void FS_Which_f( void ) {
|
void FS_Which_f( void ) {
|
||||||
searchpath_t *search;
|
searchpath_t *search;
|
||||||
char *netpath;
|
|
||||||
pack_t *pak;
|
|
||||||
fileInPack_t *pakFile;
|
|
||||||
directory_t *dir;
|
|
||||||
long hash;
|
|
||||||
FILE *temp;
|
|
||||||
char *filename;
|
char *filename;
|
||||||
char buf[ MAX_OSPATH ];
|
|
||||||
|
|
||||||
hash = 0;
|
|
||||||
filename = Cmd_Argv(1);
|
filename = Cmd_Argv(1);
|
||||||
|
|
||||||
if ( !filename[0] ) {
|
if ( !filename[0] ) {
|
||||||
|
@ -2571,40 +2785,13 @@ void FS_Which_f( void ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// just wants to see if file is there
|
// just wants to see if file is there
|
||||||
for ( search = fs_searchpaths ; search ; search = search->next ) {
|
for(search = fs_searchpaths; search; search = search->next)
|
||||||
if ( search->pack ) {
|
{
|
||||||
hash = FS_HashFileName(filename, search->pack->hashSize);
|
if(FS_Which(filename, search))
|
||||||
}
|
|
||||||
// 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;
|
return;
|
||||||
}
|
}
|
||||||
pakFile = pakFile->next;
|
|
||||||
} while(pakFile != NULL);
|
|
||||||
} else if ( search->dir ) {
|
|
||||||
dir = search->dir;
|
|
||||||
|
|
||||||
netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
|
Com_Printf("File not found: \"%s\"\n", 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 );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Com_Printf( "File not found: \"%s\"\n", filename );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2634,7 +2821,7 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
|
||||||
int i;
|
int i;
|
||||||
searchpath_t *search;
|
searchpath_t *search;
|
||||||
pack_t *pak;
|
pack_t *pak;
|
||||||
char *pakfile;
|
char curpath[MAX_OSPATH + 1], *pakfile;
|
||||||
int numfiles;
|
int numfiles;
|
||||||
char **pakfiles;
|
char **pakfiles;
|
||||||
|
|
||||||
|
@ -2647,22 +2834,11 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
|
||||||
|
|
||||||
Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );
|
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
|
// find all pak files in this directory
|
||||||
pakfile = FS_BuildOSPath( path, dir, "" );
|
Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath));
|
||||||
pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash
|
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 );
|
qsort( pakfiles, numfiles, sizeof(char*), paksort );
|
||||||
|
|
||||||
|
@ -2670,8 +2846,10 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
|
||||||
pakfile = FS_BuildOSPath( path, dir, pakfiles[i] );
|
pakfile = FS_BuildOSPath( path, dir, pakfiles[i] );
|
||||||
if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 )
|
if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname));
|
||||||
// store the game name for downloading
|
// store the game name for downloading
|
||||||
strcpy(pak->pakGamename, dir);
|
Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename));
|
||||||
|
|
||||||
fs_packFiles += pak->numfiles;
|
fs_packFiles += pak->numfiles;
|
||||||
|
|
||||||
|
@ -2683,6 +2861,19 @@ void FS_AddGameDirectory( const char *path, const char *dir ) {
|
||||||
|
|
||||||
// done
|
// done
|
||||||
Sys_FreeFileList( pakfiles );
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -614,7 +614,7 @@ qboolean FS_FileExists( const char *file );
|
||||||
|
|
||||||
qboolean FS_CreatePath (char *OSPath);
|
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 );
|
char *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
|
||||||
qboolean FS_CompareZipChecksum(const char *zipfile);
|
qboolean FS_CompareZipChecksum(const char *zipfile);
|
||||||
|
@ -630,9 +630,9 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename );
|
||||||
// will properly create any needed paths and deal with seperater character issues
|
// will properly create any needed paths and deal with seperater character issues
|
||||||
|
|
||||||
fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
|
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 );
|
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
|
// 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
|
// 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
|
// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed
|
||||||
|
@ -651,7 +651,8 @@ int FS_Read( void *buffer, int len, fileHandle_t f );
|
||||||
void FS_FCloseFile( fileHandle_t f );
|
void FS_FCloseFile( fileHandle_t f );
|
||||||
// note: you can't just fclose from another DLL, due to MS libc issues
|
// 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
|
// returns the length of the file
|
||||||
// a null buffer will just return the file length without loading
|
// a null buffer will just return the file length without loading
|
||||||
// as a quick check for existance. -1 length == not present
|
// as a quick check for existance. -1 length == not present
|
||||||
|
@ -668,7 +669,7 @@ void FS_FreeFile( void *buffer );
|
||||||
void FS_WriteFile( const char *qpath, const void *buffer, int size );
|
void FS_WriteFile( const char *qpath, const void *buffer, int size );
|
||||||
// writes a complete file, creating any subdirectories needed
|
// 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
|
// doesn't work for files that are opened from a pack file
|
||||||
|
|
||||||
int FS_FTell( fileHandle_t f );
|
int FS_FTell( fileHandle_t f );
|
||||||
|
@ -726,6 +727,7 @@ void FS_FilenameCompletion( const char *dir, const char *ext,
|
||||||
qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
|
qboolean stripExt, void(*callback)(const char *s), qboolean allowNonPureFilesOnDisk );
|
||||||
|
|
||||||
const char *FS_GetCurrentGameDir(void);
|
const char *FS_GetCurrentGameDir(void);
|
||||||
|
qboolean FS_Which(const char *filename, void *searchPath);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==============================================================
|
==============================================================
|
||||||
|
|
|
@ -377,15 +377,20 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
|
||||||
// load the image
|
// load the image
|
||||||
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name );
|
||||||
Com_Printf( "Loading vm file %s...\n", filename );
|
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 ) {
|
if ( !header.h ) {
|
||||||
Com_Printf( "Failed.\n" );
|
Com_Printf( "Failed.\n" );
|
||||||
VM_Free( vm );
|
VM_Free( vm );
|
||||||
|
|
||||||
|
Com_Printf(S_COLOR_YELLOW "Warning: Couldn't open VM file %s\n", filename);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// show where the qvm was loaded from
|
// 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 ) {
|
if( LittleLong( header.h->vmMagic ) == VM_MAGIC_VER2 ) {
|
||||||
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
|
Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" );
|
||||||
|
@ -400,9 +405,13 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
|
||||||
|| header.h->bssLength < 0
|
|| header.h->bssLength < 0
|
||||||
|| header.h->dataLength < 0
|
|| header.h->dataLength < 0
|
||||||
|| header.h->litLength < 0
|
|| header.h->litLength < 0
|
||||||
|| header.h->codeLength <= 0 ) {
|
|| header.h->codeLength <= 0 )
|
||||||
VM_Free( vm );
|
{
|
||||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
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 ) {
|
} else if( LittleLong( header.h->vmMagic ) == VM_MAGIC ) {
|
||||||
// byte swap the header
|
// byte swap the header
|
||||||
|
@ -415,14 +424,21 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) {
|
||||||
if ( header.h->bssLength < 0
|
if ( header.h->bssLength < 0
|
||||||
|| header.h->dataLength < 0
|
|| header.h->dataLength < 0
|
||||||
|| header.h->litLength < 0
|
|| header.h->litLength < 0
|
||||||
|| header.h->codeLength <= 0 ) {
|
|| header.h->codeLength <= 0 )
|
||||||
VM_Free( vm );
|
{
|
||||||
Com_Error( ERR_FATAL, "%s has bad header", filename );
|
VM_Free(vm);
|
||||||
|
FS_FreeFile(header.v);
|
||||||
|
|
||||||
|
Com_Printf(S_COLOR_YELLOW "Warning: %s has bad header\n", filename);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VM_Free( vm );
|
VM_Free( vm );
|
||||||
Com_Error( ERR_FATAL, "%s does not have a recognisable "
|
FS_FreeFile(header.v);
|
||||||
"magic number in its header", filename );
|
|
||||||
|
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
|
// round up to next power of 2 so all data operations can
|
||||||
|
@ -524,7 +540,9 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
|
||||||
vmInterpret_t interpret ) {
|
vmInterpret_t interpret ) {
|
||||||
vm_t *vm;
|
vm_t *vm;
|
||||||
vmHeader_t *header;
|
vmHeader_t *header;
|
||||||
int i, remaining;
|
int i, remaining, retval;
|
||||||
|
char filename[MAX_OSPATH];
|
||||||
|
void *startSearch = NULL;
|
||||||
|
|
||||||
if ( !module || !module[0] || !systemCalls ) {
|
if ( !module || !module[0] || !systemCalls ) {
|
||||||
Com_Error( ERR_FATAL, "VM_Create: bad parms" );
|
Com_Error( ERR_FATAL, "VM_Create: bad parms" );
|
||||||
|
@ -553,25 +571,41 @@ vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *),
|
||||||
|
|
||||||
vm = &vmTable[i];
|
vm = &vmTable[i];
|
||||||
|
|
||||||
Q_strncpyz( vm->name, module, sizeof( vm->name ) );
|
Q_strncpyz(vm->name, module, sizeof(vm->name));
|
||||||
vm->systemCall = systemCalls;
|
|
||||||
|
|
||||||
if ( interpret == VMI_NATIVE ) {
|
do
|
||||||
// try to load as a system dll
|
{
|
||||||
Com_Printf( "Loading dll file %s.\n", vm->name );
|
retval = FS_FindVM(&startSearch, filename, sizeof(filename), module, (interpret == VMI_NATIVE));
|
||||||
vm->dllHandle = Sys_LoadDll( module, &vm->entryPoint, VM_DllSyscall );
|
|
||||||
if ( vm->dllHandle ) {
|
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;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
Com_Printf( "Failed to load dll, looking for qvm.\n" );
|
Com_Printf("Failed loading dll, trying next\n");
|
||||||
interpret = VMI_COMPILED;
|
|
||||||
}
|
}
|
||||||
|
else if(retval == VMI_COMPILED)
|
||||||
|
{
|
||||||
|
vm->searchPath = startSearch;
|
||||||
|
if((header = VM_LoadQVM(vm, qtrue)))
|
||||||
|
break;
|
||||||
|
|
||||||
// load the image
|
// VM_Free overwrites the name on failed load
|
||||||
if( !( header = VM_LoadQVM( vm, qtrue ) ) ) {
|
Q_strncpyz(vm->name, module, sizeof(vm->name));
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
} 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
|
// allocate space for the jump targets, which will be filled in by the compile/prep functions
|
||||||
vm->instructionCount = header->instructionCount;
|
vm->instructionCount = header->instructionCount;
|
||||||
|
|
|
@ -142,6 +142,7 @@ struct vm_s {
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
char name[MAX_QPATH];
|
char name[MAX_QPATH];
|
||||||
|
void *searchPath; // hint for FS_ReadFileDir()
|
||||||
|
|
||||||
// for dynamic linked modules
|
// for dynamic linked modules
|
||||||
void *dllHandle;
|
void *dllHandle;
|
||||||
|
|
|
@ -147,7 +147,7 @@ typedef struct {
|
||||||
// a -1 return means the file does not exist
|
// a -1 return means the file does not exist
|
||||||
// NULL can be passed for buf to just determine existance
|
// NULL can be passed for buf to just determine existance
|
||||||
int (*FS_FileIsInPAK)( const char *name, int *pCheckSum );
|
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 );
|
void (*FS_FreeFile)( void *buf );
|
||||||
char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
|
char ** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
|
||||||
void (*FS_FreeFileList)( char **filelist );
|
void (*FS_FreeFileList)( char **filelist );
|
||||||
|
|
|
@ -412,35 +412,23 @@ void Sys_UnloadDll( void *dllHandle )
|
||||||
Sys_LoadDll
|
Sys_LoadDll
|
||||||
|
|
||||||
Used to load a development dll instead of a virtual machine
|
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 (QDECL **entryPoint)(int, ...),
|
||||||
intptr_t (*systemcalls)(intptr_t, ...) )
|
intptr_t (*systemcalls)(intptr_t, ...))
|
||||||
{
|
{
|
||||||
void *libHandle;
|
void *libHandle;
|
||||||
void (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
|
void (*dllEntry)(intptr_t (*syscallptr)(intptr_t, ...));
|
||||||
char fname[MAX_OSPATH];
|
|
||||||
char *netpath;
|
|
||||||
|
|
||||||
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(!libHandle)
|
||||||
|
{
|
||||||
if(!netpath) {
|
Com_Printf("Sys_LoadDll(%s) failed:\n\"%s\"\n", name, Sys_LibraryError());
|
||||||
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() );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue