2005-08-26 22:52:26 +00:00
# include "quakedef.h"
2007-08-20 02:24:43 +00:00
# include "netinc.h"
2005-08-26 22:52:26 +00:00
2005-12-21 03:07:33 +00:00
//#define com_gamedir com__gamedir
2005-08-26 22:52:26 +00:00
# include <ctype.h>
2009-04-01 22:03:56 +00:00
# include <limits.h>
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
# include "fs.h"
2011-03-12 13:51:40 +00:00
# include "shader.h"
2013-06-23 02:17:02 +00:00
# ifdef _WIN32
# include "winquake.h"
# endif
2005-08-26 22:52:26 +00:00
2015-09-07 14:34:39 +00:00
void FS_BeginManifestUpdates ( void ) ;
2015-04-21 04:12:00 +00:00
static void QDECL fs_game_callback ( cvar_t * var , char * oldvalue ) ;
2005-08-26 22:52:26 +00:00
hashtable_t filesystemhash ;
qboolean com_fschanged = true ;
2015-04-14 23:12:17 +00:00
qboolean com_installer = false ;
2014-03-30 08:55:06 +00:00
qboolean fs_readonly ;
2015-05-16 15:51:39 +00:00
int waitingformanifest ;
2010-07-11 02:22:39 +00:00
static unsigned int fs_restarts ;
2014-10-05 20:04:11 +00:00
void * fs_thread_mutex ;
2014-02-11 17:51:29 +00:00
cvar_t com_fs_cache = CVARF ( " fs_cache " , IFMINIMAL ( " 2 " , " 1 " ) , CVAR_ARCHIVE ) ;
cvar_t cfg_reload_on_gamedir = CVAR ( " cfg_reload_on_gamedir " , " 1 " ) ;
cvar_t fs_game = CVARFDC ( " game " , " " , CVAR_NOSAVE | CVAR_NORESET , " Provided for Q2 compat. " , fs_game_callback ) ;
cvar_t fs_gamedir = CVARFD ( " fs_gamedir " , " " , CVAR_NOUNSAFEEXPAND | CVAR_NOSET | CVAR_NOSAVE , " Provided for Q2 compat. " ) ;
cvar_t fs_basedir = CVARFD ( " fs_basedir " , " " , CVAR_NOUNSAFEEXPAND | CVAR_NOSET | CVAR_NOSAVE , " Provided for Q2 compat. " ) ;
2005-08-26 22:52:26 +00:00
int active_fs_cachetype ;
2011-12-05 15:23:40 +00:00
static int fs_referencetype ;
2012-02-27 12:23:15 +00:00
int fs_finds ;
2013-09-26 09:24:52 +00:00
void COM_CheckRegistered ( void ) ;
2005-08-26 22:52:26 +00:00
2015-04-21 04:12:00 +00:00
static void QDECL fs_game_callback ( cvar_t * var , char * oldvalue )
2014-02-11 17:51:29 +00:00
{
static qboolean runaway = false ;
char buf [ MAX_OSPATH ] ;
if ( ! strcmp ( var - > string , oldvalue ) )
return ; //no change here.
if ( runaway )
return ; //ignore that
runaway = true ;
2016-08-25 00:12:14 +00:00
Cmd_ExecuteString ( va ( " gamedir %s \n " , COM_QuotedString ( var - > string , buf , sizeof ( buf ) , false ) ) , RESTRICT_LOCAL ) ;
2014-02-11 17:51:29 +00:00
runaway = false ;
}
2009-06-03 09:09:35 +00:00
struct
2005-08-26 22:52:26 +00:00
{
2013-05-03 04:28:08 +00:00
void * module ;
2009-04-01 22:03:56 +00:00
const char * extension ;
2016-07-12 00:40:13 +00:00
searchpathfuncs_t * ( QDECL * OpenNew ) ( vfsfile_t * file , const char * desc , const char * prefix ) ;
2012-01-28 10:30:44 +00:00
qboolean loadscan ;
2009-04-01 22:03:56 +00:00
} searchpathformats [ 64 ] ;
2005-12-21 03:07:33 +00:00
2016-07-12 00:40:13 +00:00
int FS_RegisterFileSystemType ( void * module , const char * extension , searchpathfuncs_t * ( QDECL * OpenNew ) ( vfsfile_t * file , const char * desc , const char * prefix ) , qboolean loadscan )
2005-08-26 22:52:26 +00:00
{
2009-04-01 22:03:56 +00:00
unsigned int i ;
for ( i = 0 ; i < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; i + + )
2005-08-26 22:52:26 +00:00
{
2009-04-01 22:03:56 +00:00
if ( searchpathformats [ i ] . extension & & ! strcmp ( searchpathformats [ i ] . extension , extension ) )
break ; //extension match always replaces
2013-06-23 02:17:02 +00:00
if ( ! searchpathformats [ i ] . extension & & ! searchpathformats [ i ] . OpenNew )
2009-04-01 22:03:56 +00:00
break ;
2005-08-26 22:52:26 +00:00
}
2009-04-01 22:03:56 +00:00
if ( i = = sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) )
return 0 ;
2005-08-26 22:52:26 +00:00
2013-05-03 04:28:08 +00:00
searchpathformats [ i ] . module = module ;
2009-04-01 22:03:56 +00:00
searchpathformats [ i ] . extension = extension ;
2013-06-23 02:17:02 +00:00
searchpathformats [ i ] . OpenNew = OpenNew ;
2012-01-28 10:30:44 +00:00
searchpathformats [ i ] . loadscan = loadscan ;
2009-04-01 22:03:56 +00:00
com_fschanged = true ;
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
return i + 1 ;
2005-08-26 22:52:26 +00:00
}
2009-04-01 22:03:56 +00:00
void FS_UnRegisterFileSystemType ( int idx )
2005-08-26 22:52:26 +00:00
{
2009-04-01 22:03:56 +00:00
if ( ( unsigned int ) ( idx - 1 ) > = sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) )
2005-08-26 22:52:26 +00:00
return ;
2013-06-23 02:17:02 +00:00
searchpathformats [ idx - 1 ] . OpenNew = NULL ;
2013-05-03 04:28:08 +00:00
searchpathformats [ idx - 1 ] . module = NULL ;
2009-04-01 22:03:56 +00:00
com_fschanged = true ;
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
//FS_Restart will be needed
2005-08-26 22:52:26 +00:00
}
2013-05-03 04:28:08 +00:00
void FS_UnRegisterFileSystemModule ( void * module )
{
int i ;
qboolean found = false ;
2015-06-14 08:16:15 +00:00
if ( ! fs_thread_mutex | | Sys_LockMutex ( fs_thread_mutex ) )
2013-05-03 04:28:08 +00:00
{
2014-10-05 20:04:11 +00:00
for ( i = 0 ; i < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; i + + )
2013-05-03 04:28:08 +00:00
{
2014-10-05 20:04:11 +00:00
if ( searchpathformats [ i ] . module = = module )
{
searchpathformats [ i ] . OpenNew = NULL ;
searchpathformats [ i ] . module = NULL ;
found = true ;
}
}
2015-06-14 08:16:15 +00:00
if ( fs_thread_mutex )
2014-10-05 20:04:11 +00:00
{
2015-06-14 08:16:15 +00:00
Sys_UnlockMutex ( fs_thread_mutex ) ;
if ( found )
{
Cmd_ExecuteString ( " fs_restart " , RESTRICT_LOCAL ) ;
}
2013-05-03 04:28:08 +00:00
}
}
}
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
char * VFS_GETS ( vfsfile_t * vf , char * buffer , int buflen )
2005-08-26 22:52:26 +00:00
{
2009-04-01 22:03:56 +00:00
char in ;
char * out = buffer ;
int len ;
len = buflen - 1 ;
if ( len = = 0 )
return NULL ;
while ( len > 0 )
2005-08-26 22:52:26 +00:00
{
2010-03-25 22:56:11 +00:00
if ( VFS_READ ( vf , & in , 1 ) ! = 1 )
2005-08-26 22:52:26 +00:00
{
2009-04-01 22:03:56 +00:00
if ( len = = buflen - 1 )
return NULL ;
* out = ' \0 ' ;
return buffer ;
2005-08-26 22:52:26 +00:00
}
2009-04-01 22:03:56 +00:00
if ( in = = ' \n ' )
break ;
* out + + = in ;
len - - ;
2005-08-26 22:52:26 +00:00
}
2009-04-01 22:03:56 +00:00
* out = ' \0 ' ;
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
//if there's a trailing \r, strip it.
if ( out > buffer )
if ( out [ - 1 ] = = ' \r ' )
out [ - 1 ] = 0 ;
2009-04-01 22:03:56 +00:00
return buffer ;
2005-08-26 22:52:26 +00:00
}
2009-04-06 00:34:32 +00:00
void VARGS VFS_PRINTF ( vfsfile_t * vf , char * format , . . . )
2005-12-21 03:07:33 +00:00
{
2009-04-01 22:03:56 +00:00
va_list argptr ;
char string [ 1024 ] ;
2005-12-21 03:07:33 +00:00
2009-04-01 22:03:56 +00:00
va_start ( argptr , format ) ;
vsnprintf ( string , sizeof ( string ) - 1 , format , argptr ) ;
va_end ( argptr ) ;
2005-12-21 03:07:33 +00:00
2009-04-01 22:03:56 +00:00
VFS_PUTS ( vf , string ) ;
2005-12-21 03:07:33 +00:00
}
2006-03-15 20:05:25 +00:00
2005-12-21 03:07:33 +00:00
2006-03-15 20:05:25 +00:00
2009-04-01 22:03:56 +00:00
char gamedirfile [ MAX_OSPATH ] ;
2014-03-30 08:55:06 +00:00
char pubgamedirfile [ MAX_OSPATH ] ; //like gamedirfile, but not set to the fte-only paths
2006-03-15 20:05:25 +00:00
2005-12-21 03:07:33 +00:00
2014-03-30 08:55:06 +00:00
char com_gamepath [ MAX_OSPATH ] ; //c:\games\quake
char com_homepath [ MAX_OSPATH ] ; //c:\users\foo\my docs\fte\quake
qboolean com_homepathenabled ;
2014-12-23 15:26:42 +00:00
qboolean com_homepathusable ; //com_homepath is safe, even if not enabled.
2006-03-15 20:05:25 +00:00
2009-04-01 22:03:56 +00:00
char com_configdir [ MAX_OSPATH ] ; //homedir/fte/configs
2006-03-15 20:05:25 +00:00
2009-04-01 22:03:56 +00:00
int fs_hash_dups ;
int fs_hash_files ;
2005-12-21 03:07:33 +00:00
2006-03-15 20:05:25 +00:00
2005-12-21 03:07:33 +00:00
2006-01-02 22:53:29 +00:00
2005-12-21 03:07:33 +00:00
2015-05-14 03:06:58 +00:00
const char * FS_GetCleanPath ( const char * pattern , char * outbuf , int outlen ) ;
2009-04-01 22:03:56 +00:00
void FS_RegisterDefaultFileSystems ( void ) ;
2010-07-18 08:42:59 +00:00
static void COM_CreatePath ( char * path ) ;
2014-10-29 05:03:03 +00:00
ftemanifest_t * FS_ReadDefaultManifest ( char * newbasedir , size_t newbasedirsize , qboolean fixedbasedir ) ;
2005-12-21 03:07:33 +00:00
2009-04-01 22:03:56 +00:00
# define ENFORCEFOPENMODE(mode) {if (strcmp(mode, "r") && strcmp(mode, "w") /* && strcmp(mode, "rw")*/ )Sys_Error("fs mode %s is not permitted here\n");}
2005-12-21 03:07:33 +00:00
2006-03-15 20:05:25 +00:00
2005-12-21 03:07:33 +00:00
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
//forget a manifest entirely.
void FS_Manifest_Free ( ftemanifest_t * man )
{
int i , j ;
if ( ! man )
return ;
Z_Free ( man - > updateurl ) ;
2014-03-30 08:55:06 +00:00
Z_Free ( man - > updatefile ) ;
2013-06-23 02:17:02 +00:00
Z_Free ( man - > installation ) ;
Z_Free ( man - > formalname ) ;
2016-07-21 19:27:59 +00:00
Z_Free ( man - > downloadsurl ) ;
2016-08-25 00:12:14 +00:00
Z_Free ( man - > installupd ) ;
2013-06-23 02:17:02 +00:00
Z_Free ( man - > protocolname ) ;
2015-04-14 23:12:17 +00:00
Z_Free ( man - > eula ) ;
2013-06-23 02:17:02 +00:00
Z_Free ( man - > defaultexec ) ;
for ( i = 0 ; i < sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) ; i + + )
{
Z_Free ( man - > gamepath [ i ] . path ) ;
}
for ( i = 0 ; i < sizeof ( man - > package ) / sizeof ( man - > package [ 0 ] ) ; i + + )
{
Z_Free ( man - > package [ i ] . path ) ;
2016-07-12 00:40:13 +00:00
Z_Free ( man - > package [ i ] . prefix ) ;
2015-09-07 14:34:39 +00:00
Z_Free ( man - > package [ i ] . condition ) ;
2013-06-23 02:17:02 +00:00
for ( j = 0 ; j < sizeof ( man - > package [ i ] . mirrors ) / sizeof ( man - > package [ i ] . mirrors [ 0 ] ) ; j + + )
Z_Free ( man - > package [ i ] . mirrors [ j ] ) ;
}
Z_Free ( man ) ;
}
//clone a manifest, so we can hack at it.
static ftemanifest_t * FS_Manifest_Clone ( ftemanifest_t * oldm )
{
ftemanifest_t * newm ;
int i , j ;
newm = Z_Malloc ( sizeof ( * newm ) ) ;
if ( oldm - > updateurl )
newm - > updateurl = Z_StrDup ( oldm - > updateurl ) ;
if ( oldm - > installation )
newm - > installation = Z_StrDup ( oldm - > installation ) ;
if ( oldm - > formalname )
newm - > formalname = Z_StrDup ( oldm - > formalname ) ;
2016-07-21 19:27:59 +00:00
if ( oldm - > downloadsurl )
newm - > downloadsurl = Z_StrDup ( oldm - > downloadsurl ) ;
2016-08-25 00:12:14 +00:00
if ( oldm - > installupd )
newm - > installupd = Z_StrDup ( oldm - > installupd ) ;
2013-06-23 02:17:02 +00:00
if ( oldm - > protocolname )
newm - > protocolname = Z_StrDup ( oldm - > protocolname ) ;
2015-04-14 23:12:17 +00:00
if ( oldm - > eula )
newm - > eula = Z_StrDup ( oldm - > eula ) ;
2013-08-07 14:13:18 +00:00
if ( oldm - > defaultexec )
newm - > defaultexec = Z_StrDup ( oldm - > defaultexec ) ;
2014-03-30 08:55:06 +00:00
newm - > disablehomedir = oldm - > disablehomedir ;
2013-06-23 02:17:02 +00:00
for ( i = 0 ; i < sizeof ( newm - > gamepath ) / sizeof ( newm - > gamepath [ 0 ] ) ; i + + )
{
if ( oldm - > gamepath [ i ] . path )
newm - > gamepath [ i ] . path = Z_StrDup ( oldm - > gamepath [ i ] . path ) ;
newm - > gamepath [ i ] . base = oldm - > gamepath [ i ] . base ;
}
for ( i = 0 ; i < sizeof ( newm - > package ) / sizeof ( newm - > package [ 0 ] ) ; i + + )
{
if ( oldm - > package [ i ] . path )
newm - > package [ i ] . path = Z_StrDup ( oldm - > package [ i ] . path ) ;
2016-07-12 00:40:13 +00:00
if ( oldm - > package [ i ] . prefix )
newm - > package [ i ] . prefix = Z_StrDup ( oldm - > package [ i ] . prefix ) ;
2015-09-07 14:34:39 +00:00
if ( oldm - > package [ i ] . condition )
newm - > package [ i ] . condition = Z_StrDup ( oldm - > package [ i ] . condition ) ;
2013-06-23 02:17:02 +00:00
for ( j = 0 ; j < sizeof ( newm - > package [ i ] . mirrors ) / sizeof ( newm - > package [ i ] . mirrors [ 0 ] ) ; j + + )
if ( oldm - > package [ i ] . mirrors [ j ] )
newm - > package [ i ] . mirrors [ j ] = Z_StrDup ( oldm - > package [ i ] . mirrors [ j ] ) ;
}
return newm ;
}
void FS_Manifest_Print ( ftemanifest_t * man )
{
2013-08-07 14:13:18 +00:00
char buffer [ 1024 ] ;
2013-06-23 02:17:02 +00:00
int i , j ;
if ( man - > updateurl )
2015-01-02 05:20:56 +00:00
Con_Printf ( " updateurl %s \n " , COM_QuotedString ( man - > updateurl , buffer , sizeof ( buffer ) , false ) ) ;
2015-04-14 23:12:17 +00:00
if ( man - > eula )
Con_Printf ( " eula %s \n " , COM_QuotedString ( man - > eula , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
if ( man - > installation )
2015-01-02 05:20:56 +00:00
Con_Printf ( " game %s \n " , COM_QuotedString ( man - > installation , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
if ( man - > formalname )
2015-01-02 05:20:56 +00:00
Con_Printf ( " name %s \n " , COM_QuotedString ( man - > formalname , buffer , sizeof ( buffer ) , false ) ) ;
2016-07-21 19:27:59 +00:00
if ( man - > downloadsurl )
Con_Printf ( " downloadsurl %s \n " , COM_QuotedString ( man - > downloadsurl , buffer , sizeof ( buffer ) , false ) ) ;
2016-08-25 00:12:14 +00:00
if ( man - > installupd )
Con_Printf ( " install %s \n " , COM_QuotedString ( man - > installupd , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
if ( man - > protocolname )
2015-01-02 05:20:56 +00:00
Con_Printf ( " protocolname %s \n " , COM_QuotedString ( man - > protocolname , buffer , sizeof ( buffer ) , false ) ) ;
2013-08-07 14:13:18 +00:00
if ( man - > defaultexec )
2015-01-02 05:20:56 +00:00
Con_Printf ( " defaultexec %s \n " , COM_QuotedString ( man - > defaultexec , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
for ( i = 0 ; i < sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) ; i + + )
{
if ( man - > gamepath [ i ] . path )
{
if ( man - > gamepath [ i ] . base )
2015-01-02 05:20:56 +00:00
Con_Printf ( " basegame %s \n " , COM_QuotedString ( man - > gamepath [ i ] . path , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
else
2015-01-02 05:20:56 +00:00
Con_Printf ( " gamedir %s \n " , COM_QuotedString ( man - > gamepath [ i ] . path , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 02:17:02 +00:00
}
}
for ( i = 0 ; i < sizeof ( man - > package ) / sizeof ( man - > package [ 0 ] ) ; i + + )
{
if ( man - > package [ i ] . path )
{
2015-09-07 14:34:39 +00:00
if ( man - > package [ i ] . type = = mdt_installation )
Con_Printf ( " library " ) ;
2013-08-06 02:19:06 +00:00
else
2015-09-07 14:34:39 +00:00
Con_Printf ( " package " ) ;
Con_Printf ( " %s " , COM_QuotedString ( man - > package [ i ] . path , buffer , sizeof ( buffer ) , false ) ) ;
if ( man - > package [ i ] . condition )
2016-07-12 00:40:13 +00:00
Con_Printf ( " prefix %s " , COM_QuotedString ( man - > package [ i ] . condition , buffer , sizeof ( buffer ) , false ) ) ;
if ( man - > package [ i ] . condition )
Con_Printf ( " condition %s " , COM_QuotedString ( man - > package [ i ] . condition , buffer , sizeof ( buffer ) , false ) ) ;
2015-09-07 14:34:39 +00:00
if ( man - > package [ i ] . crcknown )
2016-07-12 00:40:13 +00:00
Con_Printf ( " crc 0x%x " , man - > package [ i ] . crc ) ;
2013-06-23 02:17:02 +00:00
for ( j = 0 ; j < sizeof ( man - > package [ i ] . mirrors ) / sizeof ( man - > package [ i ] . mirrors [ 0 ] ) ; j + + )
if ( man - > package [ i ] . mirrors [ j ] )
2015-01-02 05:20:56 +00:00
Con_Printf ( " %s " , COM_QuotedString ( man - > package [ i ] . mirrors [ j ] , buffer , sizeof ( buffer ) , false ) ) ;
2013-06-23 03:59:48 +00:00
Con_Printf ( " \n " ) ;
2013-06-23 02:17:02 +00:00
}
}
}
//forget any mod dirs.
static void FS_Manifest_PurgeGamedirs ( ftemanifest_t * man )
{
int i ;
for ( i = 0 ; i < sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) ; i + + )
{
if ( man - > gamepath [ i ] . path & & ! man - > gamepath [ i ] . base )
{
Z_Free ( man - > gamepath [ i ] . path ) ;
man - > gamepath [ i ] . path = NULL ;
2014-10-29 05:03:03 +00:00
//FIXME: remove packages from the removed paths.
2013-06-23 02:17:02 +00:00
}
}
}
//create a new empty manifest with default values.
2014-03-30 08:55:06 +00:00
static ftemanifest_t * FS_Manifest_Create ( const char * syspath )
2013-06-23 02:17:02 +00:00
{
ftemanifest_t * man = Z_Malloc ( sizeof ( * man ) ) ;
man - > formalname = Z_StrDup ( FULLENGINENAME ) ;
2014-03-30 08:55:06 +00:00
2015-09-07 14:34:39 +00:00
# ifdef _DEBUG //FOR TEMPORARY TESTING ONLY.
// man->doinstall = true;
# endif
2014-03-30 08:55:06 +00:00
if ( syspath )
man - > updatefile = Z_StrDup ( syspath ) ; //this should be a system path.
2013-06-23 02:17:02 +00:00
return man ;
}
2015-04-14 23:12:17 +00:00
2015-09-07 14:34:39 +00:00
static qboolean FS_Manifest_ParsePackage ( ftemanifest_t * man , int type )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
char * path = " " ;
unsigned int crc = 0 ;
qboolean crcknown = false ;
char * legacyextractname = NULL ;
char * condition = NULL ;
2016-07-12 00:40:13 +00:00
char * prefix = NULL ;
2015-09-07 14:34:39 +00:00
char * arch = NULL ;
unsigned int arg = 1 ;
unsigned int mirrors = 0 ;
char * mirror [ countof ( man - > package [ 0 ] . mirrors ) ] ;
2015-04-14 23:12:17 +00:00
size_t i , j ;
2015-09-07 14:34:39 +00:00
char * a ;
a = Cmd_Argv ( 0 ) ;
if ( ! Q_strcasecmp ( a , " filedependancies " ) | | ! Q_strcasecmp ( a , " archiveddependancies " ) )
arch = Cmd_Argv ( arg + + ) ;
path = Cmd_Argv ( arg + + ) ;
# ifndef NOLEGACY
a = Cmd_Argv ( arg ) ;
if ( ! strcmp ( a , " - " ) )
{
arg + + ;
}
else if ( * a )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
crc = strtoul ( a , & a , 0 ) ;
if ( ! * a )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
crcknown = true ;
arg + + ;
2015-04-14 23:12:17 +00:00
}
}
2015-09-07 14:34:39 +00:00
if ( ! strncmp ( Cmd_Argv ( 0 ) , " archived " , 8 ) )
legacyextractname = Cmd_Argv ( arg + + ) ;
# endif
while ( arg < Cmd_Argc ( ) )
{
a = Cmd_Argv ( arg + + ) ;
if ( ! strcmp ( a , " crc " ) )
{
crcknown = true ;
crc = strtoul ( Cmd_Argv ( arg + + ) , NULL , 0 ) ;
}
else if ( ! strcmp ( a , " condition " ) )
condition = Cmd_Argv ( arg + + ) ;
2016-07-12 00:40:13 +00:00
else if ( ! strcmp ( a , " prefix " ) )
prefix = Cmd_Argv ( arg + + ) ;
2015-09-07 14:34:39 +00:00
else if ( ! strcmp ( a , " arch " ) )
arch = Cmd_Argv ( arg + + ) ;
else if ( ! strcmp ( a , " mirror " ) )
{
a = Cmd_Argv ( arg + + ) ;
goto mirror ; //oo evil.
}
else if ( strchr ( a , ' : ' ) | | man - > parsever < 1 )
{
mirror :
if ( mirrors = = countof ( mirror ) )
Con_Printf ( " too many mirrors for package %s \n " , path ) ;
else if ( legacyextractname )
{
if ( ! strcmp ( legacyextractname , " xz " ) | | ! strcmp ( legacyextractname , " gz " ) )
mirror [ mirrors + + ] = Z_StrDup ( va ( " %s:%s " , legacyextractname , a ) ) ;
else
mirror [ mirrors + + ] = Z_StrDup ( va ( " unzip:%s,%s " , legacyextractname , a ) ) ;
}
else
mirror [ mirrors + + ] = Z_StrDup ( a ) ;
}
else if ( man - > parsever < = MANIFEST_CURRENTVER )
Con_Printf ( " unknown mirror / property %s for package %s \n " , a , path ) ;
}
for ( i = 0 ; i < countof ( man - > package ) ; i + + )
2015-04-14 23:12:17 +00:00
{
if ( ! man - > package [ i ] . path )
{
2015-09-07 14:34:39 +00:00
if ( type = = mdt_singlepackage & & ( ! strchr ( path , ' / ' ) | | strchr ( path , ' : ' ) | | strchr ( path , ' \\ ' ) ) )
{
Con_Printf ( " invalid package path specified in manifest (%s) \n " , path ) ;
break ;
}
if ( arch )
{
# ifdef PLATFORM
if ( Q_strcasecmp ( PLATFORM , arch ) )
# endif
break ;
}
2015-04-14 23:12:17 +00:00
man - > package [ i ] . type = type ;
man - > package [ i ] . path = Z_StrDup ( path ) ;
2016-07-12 00:40:13 +00:00
man - > package [ i ] . prefix = prefix ? Z_StrDup ( prefix ) : NULL ;
2015-09-07 14:34:39 +00:00
man - > package [ i ] . condition = condition ? Z_StrDup ( condition ) : NULL ;
2015-04-14 23:12:17 +00:00
man - > package [ i ] . crcknown = crcknown ;
man - > package [ i ] . crc = crc ;
2015-09-07 14:34:39 +00:00
for ( j = 0 ; j < mirrors ; j + + )
man - > package [ i ] . mirrors [ j ] = mirror [ j ] ;
2015-04-14 23:12:17 +00:00
return true ;
}
}
2015-09-07 14:34:39 +00:00
if ( i = = countof ( man - > package ) )
Con_Printf ( " Too many packages specified in manifest \n " ) ;
for ( j = 0 ; j < mirrors ; j + + )
Z_Free ( mirror [ j ] ) ;
2015-04-14 23:12:17 +00:00
return false ;
}
2013-06-23 02:17:02 +00:00
//parse Cmd_Argv tokens into the manifest.
2014-03-30 08:55:06 +00:00
static qboolean FS_Manifest_ParseTokens ( ftemanifest_t * man )
2013-06-23 02:17:02 +00:00
{
2014-03-30 08:55:06 +00:00
qboolean result = true ;
2015-04-14 23:12:17 +00:00
char * cmd = Cmd_Argv ( 0 ) ;
if ( ! * cmd )
2014-03-30 08:55:06 +00:00
return result ;
2013-06-23 02:17:02 +00:00
2015-04-14 23:12:17 +00:00
if ( * cmd = = ' * ' )
cmd + + ;
if ( ! Q_strcasecmp ( cmd , " ftemanifestver " ) | | ! Q_strcasecmp ( cmd , " ftemanifest " ) )
man - > parsever = atoi ( Cmd_Argv ( 1 ) ) ;
else if ( ! Q_strcasecmp ( cmd , " minver " ) )
2014-03-30 08:55:06 +00:00
{
//ignore minimum versions for other engines.
if ( ! strcmp ( Cmd_Argv ( 2 ) , DISTRIBUTION ) )
man - > minver = atoi ( Cmd_Argv ( 3 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " maxver " ) )
2014-03-30 08:55:06 +00:00
{
//ignore minimum versions for other engines.
if ( ! strcmp ( Cmd_Argv ( 2 ) , DISTRIBUTION ) )
man - > maxver = atoi ( Cmd_Argv ( 3 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " game " ) )
2013-06-23 02:17:02 +00:00
{
Z_Free ( man - > installation ) ;
man - > installation = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " name " ) )
2013-06-23 02:17:02 +00:00
{
Z_Free ( man - > formalname ) ;
man - > formalname = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " eula " ) )
{
Z_Free ( man - > eula ) ;
man - > eula = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2016-07-21 19:27:59 +00:00
else if ( ! Q_strcasecmp ( cmd , " downloadsurl " ) )
{
Z_Free ( man - > downloadsurl ) ;
man - > downloadsurl = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2016-08-25 00:12:14 +00:00
else if ( ! Q_strcasecmp ( cmd , " install " ) )
{
Z_Free ( man - > installupd ) ;
man - > installupd = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " protocolname " ) )
2013-06-23 02:17:02 +00:00
{
Z_Free ( man - > protocolname ) ;
man - > protocolname = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " defaultexec " ) )
2013-08-07 14:13:18 +00:00
{
Z_Free ( man - > defaultexec ) ;
man - > defaultexec = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " updateurl " ) )
2014-03-30 08:55:06 +00:00
{
Z_Free ( man - > updateurl ) ;
man - > updateurl = Z_StrDup ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " disablehomedir " ) )
2014-03-30 08:55:06 +00:00
{
man - > disablehomedir = ! ! atoi ( Cmd_Argv ( 1 ) ) ;
}
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " basegame " ) | | ! Q_strcasecmp ( cmd , " gamedir " ) )
2013-06-23 02:17:02 +00:00
{
int i ;
char * newdir = Cmd_Argv ( 1 ) ;
//reject various evil path arguments.
2013-10-29 17:38:22 +00:00
if ( ! * newdir | | strchr ( newdir , ' \n ' ) | | strchr ( newdir , ' \r ' ) | | ! strcmp ( newdir , " . " ) | | ! strcmp ( newdir , " .. " ) | | strchr ( newdir , ' : ' ) | | strchr ( newdir , ' / ' ) | | strchr ( newdir , ' \\ ' ) | | strchr ( newdir , ' $ ' ) )
2013-06-23 02:17:02 +00:00
{
Con_Printf ( " Illegal path specified: %s \n " , newdir ) ;
}
else
{
for ( i = 0 ; i < sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) ; i + + )
{
if ( ! man - > gamepath [ i ] . path )
{
2015-04-14 23:12:17 +00:00
man - > gamepath [ i ] . base = ! Q_strcasecmp ( cmd , " basegame " ) ;
2013-06-23 02:17:02 +00:00
man - > gamepath [ i ] . path = Z_StrDup ( newdir ) ;
break ;
}
}
if ( i = = sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) )
{
Con_Printf ( " Too many game paths specified in manifest \n " ) ;
}
}
}
2015-09-07 14:34:39 +00:00
# ifndef NOLEGACY
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " filedependancies " ) | | ! Q_strcasecmp ( cmd , " archiveddependancies " ) )
2015-09-07 14:34:39 +00:00
FS_Manifest_ParsePackage ( man , mdt_installation ) ;
else if ( ! Q_strcasecmp ( cmd , " archivedpackage " ) )
FS_Manifest_ParsePackage ( man , mdt_singlepackage ) ;
2015-04-14 23:12:17 +00:00
# endif
2015-09-07 14:34:39 +00:00
else if ( ! Q_strcasecmp ( cmd , " library " ) )
FS_Manifest_ParsePackage ( man , mdt_installation ) ;
2015-04-14 23:12:17 +00:00
else if ( ! Q_strcasecmp ( cmd , " package " ) | | ! Q_strcasecmp ( cmd , " archivedpackage " ) )
2015-09-07 14:34:39 +00:00
FS_Manifest_ParsePackage ( man , mdt_singlepackage ) ;
2014-03-30 08:55:06 +00:00
else
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
Con_Printf ( " Unknown token: %s \n " , cmd ) ;
2014-03-30 08:55:06 +00:00
result = false ;
2015-04-14 23:12:17 +00:00
}
2014-03-30 08:55:06 +00:00
return result ;
2013-06-23 02:17:02 +00:00
}
//read a manifest file
2014-03-30 08:55:06 +00:00
ftemanifest_t * FS_Manifest_Parse ( const char * fname , const char * data )
2013-06-23 02:17:02 +00:00
{
ftemanifest_t * man ;
if ( ! data )
return NULL ;
while ( * data = = ' ' | | * data = = ' \t ' | | * data = = ' \r ' | | * data = = ' \n ' )
data + + ;
if ( ! * data )
return NULL ;
2005-08-26 22:52:26 +00:00
2014-03-30 08:55:06 +00:00
man = FS_Manifest_Create ( fname ) ;
2013-06-23 02:17:02 +00:00
while ( data & & * data )
{
data = Cmd_TokenizeString ( ( char * ) data , false , false ) ;
2015-04-14 23:12:17 +00:00
if ( ! FS_Manifest_ParseTokens ( man ) & & man - > parsever < = 1 )
{
2014-03-30 08:55:06 +00:00
FS_Manifest_Free ( man ) ;
return NULL ;
}
2013-06-23 02:17:02 +00:00
}
2013-08-06 02:19:06 +00:00
if ( ! man - > installation )
2014-03-30 08:55:06 +00:00
{ //every manifest should have an internal name specified, so we can guess the correct basedir
2013-08-06 02:19:06 +00:00
//if we don't recognise it, then we'll typically prompt (or just use the working directory), but always assuming a default at least ensures things are sane.
//fixme: we should probably fill in the basegame here (and share that logic with the legacy manifest generation code)
2014-10-05 20:04:11 +00:00
# ifdef BRANDING_NAME
data = Cmd_TokenizeString ( ( char * ) " game " STRINGIFY ( BRANDING_NAME ) , false , false ) ;
# else
2013-08-06 02:19:06 +00:00
data = Cmd_TokenizeString ( ( char * ) " game quake " , false , false ) ;
2014-10-05 20:04:11 +00:00
# endif
2013-08-06 02:19:06 +00:00
FS_Manifest_ParseTokens ( man ) ;
}
2014-03-30 08:55:06 +00:00
# ifdef SVNREVISION
//svnrevision is often '-', which means we can't just use it as a constant.
{
int ver = atoi ( STRINGIFY ( SVNREVISION ) ) ;
if ( man - > minver > ver | | ( man - > maxver & & man - > maxver < ver ) )
{
FS_Manifest_Free ( man ) ;
return NULL ;
}
}
# endif
2013-06-23 02:17:02 +00:00
return man ;
}
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
//======================================================================================================
2005-08-26 22:52:26 +00:00
2016-07-12 00:40:13 +00:00
char * fs_loadedcommand ; //execed once all packages are (down)loaded
2015-04-14 23:12:17 +00:00
ftemanifest_t * fs_manifest ; //currently active manifest.
2013-06-23 02:17:02 +00:00
static searchpath_t * com_searchpaths ;
static searchpath_t * com_purepaths ;
static searchpath_t * com_base_searchpaths ; // without gamedirs
static int fs_puremode ; //0=deprioritise pure, 1=prioritise pure, 2=pure only.
2014-06-12 23:08:42 +00:00
static char * fs_refnames ; //list of allowed packages
static char * fs_refcrcs ; //list of crcs for those packages. one token per package.
2013-06-23 02:17:02 +00:00
static char * fs_purenames ; //list of allowed packages
static char * fs_purecrcs ; //list of crcs for those packages. one token per package.
static unsigned int fs_pureseed ; //used as a key so the server knows we're obeying. completely unreliable/redundant in an open source project, but needed for q3 network compat.
2005-08-26 22:52:26 +00:00
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
int QDECL COM_FileSize ( const char * path )
2005-08-26 22:52:26 +00:00
{
2005-12-21 03:07:33 +00:00
flocation_t loc ;
2015-10-11 11:34:58 +00:00
if ( FS_FLocateFile ( path , FSLF_IFFOUND , & loc ) )
return loc . len ;
else
return - 1 ;
2005-08-26 22:52:26 +00:00
}
2013-06-23 02:17:02 +00:00
//appends a / on the end of the directory if it does not already have one.
void FS_CleanDir ( char * out , int outlen )
{
int olen = strlen ( out ) ;
if ( ! olen | | olen > = outlen - 1 )
return ;
if ( out [ olen - 1 ] = = ' \\ ' )
out [ olen - 1 ] = ' / ' ;
else if ( out [ olen - 1 ] ! = ' / ' )
{
out [ olen + 1 ] = ' \0 ' ;
out [ olen ] = ' / ' ;
}
}
2005-08-26 22:52:26 +00:00
/*
= = = = = = = = = = = =
COM_Path_f
= = = = = = = = = = = =
*/
2013-12-17 22:45:37 +00:00
static void COM_PathLine ( searchpath_t * s )
{
2016-08-25 00:12:14 +00:00
Con_Printf ( U8 ( " %s " ) " %s%s%s%s%s%s%s \n " , s - > logicalpath ,
2013-12-17 22:45:37 +00:00
( s - > flags & SPF_REFERENCED ) ? " ^[(ref) \\ tip \\ Referenced \\ desc \\ Package will auto-download to clients^] " : " " ,
( s - > flags & SPF_TEMPORARY ) ? " ^[(temp) \\ tip \\ Temporary \\ desc \\ Flushed on map change^] " : " " ,
( s - > flags & SPF_COPYPROTECTED ) ? " ^[(c) \\ tip \\ Copyrighted \\ desc \\ Copy-Protected and is not downloadable^] " : " " ,
( s - > flags & SPF_EXPLICIT ) ? " ^[(e) \\ tip \\ Explicit \\ desc \\ Loaded explicitly by the gamedir^] " : " " ,
2015-04-27 06:19:33 +00:00
( s - > flags & SPF_UNTRUSTED ) ? " ^[(u) \\ tip \\ Untrusted \\ desc \\ Configs and scripts will not be given access to passwords^] " : " " ,
2016-08-25 00:12:14 +00:00
( s - > flags & SPF_WRITABLE ) ? " ^[(w) \\ tip \\ Writable \\ desc \\ We can probably write here^] " : " " ,
2015-04-27 06:19:33 +00:00
( s - > handle - > GeneratePureCRC ) ? va ( " ^[(h) \\ tip \\ Hash: %x^] " , s - > handle - > GeneratePureCRC ( s - > handle , 0 , 0 ) ) : " " ) ;
2013-12-17 22:45:37 +00:00
}
2005-08-26 22:52:26 +00:00
void COM_Path_f ( void )
{
searchpath_t * s ;
2005-11-21 21:09:11 +00:00
2013-11-29 14:36:47 +00:00
Con_TPrintf ( " Current search path: \n " ) ;
2005-11-21 21:09:11 +00:00
2013-06-23 02:17:02 +00:00
if ( com_purepaths | | fs_puremode )
2005-08-26 22:52:26 +00:00
{
2007-09-17 20:35:39 +00:00
Con_Printf ( " Pure paths: \n " ) ;
2005-08-26 22:52:26 +00:00
for ( s = com_purepaths ; s ; s = s - > nextpure )
{
2013-12-17 22:45:37 +00:00
COM_PathLine ( s ) ;
2005-08-26 22:52:26 +00:00
}
Con_Printf ( " ---------- \n " ) ;
2013-06-23 02:17:02 +00:00
if ( fs_puremode = = 2 )
Con_Printf ( " Inactive paths: \n " ) ;
else
Con_Printf ( " Impure paths: \n " ) ;
2005-08-26 22:52:26 +00:00
}
for ( s = com_searchpaths ; s ; s = s - > next )
{
if ( s = = com_base_searchpaths )
Con_Printf ( " ---------- \n " ) ;
2013-12-17 22:45:37 +00:00
COM_PathLine ( s ) ;
2005-08-26 22:52:26 +00:00
}
}
/*
= = = = = = = = = = = =
COM_Dir_f
= = = = = = = = = = = =
*/
2015-02-02 08:01:53 +00:00
static int QDECL COM_Dir_List ( const char * name , qofs_t size , time_t mtime , void * parm , searchpathfuncs_t * spath )
2005-08-26 22:52:26 +00:00
{
2013-03-31 04:21:08 +00:00
searchpath_t * s ;
2016-07-12 00:40:13 +00:00
char link [ 512 ] ;
char * colour ;
flocation_t loc ;
2013-03-31 04:21:08 +00:00
for ( s = com_searchpaths ; s ; s = s - > next )
{
if ( s - > handle = = spath )
break ;
}
2016-07-12 00:40:13 +00:00
if ( * name & & name [ strlen ( name ) - 1 ] = = ' / ' )
{
colour = " ^7 " ; //superseeded
Q_snprintfz ( link , sizeof ( link ) , " \\ dir \\ %s* " , name ) ;
}
else if ( ! FS_FLocateFile ( name , FSLF_IFFOUND , & loc ) )
{
colour = " ^1 " ; //superseeded
Q_snprintfz ( link , sizeof ( link ) , " \\ tip \\ flocate error " ) ;
}
else if ( loc . search - > handle = = spath )
{
colour = " ^2 " ;
COM_FileExtension ( name , link , sizeof ( link ) ) ;
if ( ( ! Q_strcasecmp ( link , " bsp " ) | | ! Q_strcasecmp ( link , " map " ) | | ! Q_strcasecmp ( link , " hmp " ) ) & & ! strncmp ( name , " maps/ " , 5 ) & & strncmp ( name , " maps/b_ " , 7 ) )
{
Q_snprintfz ( link , sizeof ( link ) , " \\ map \\ %s " , name ) ;
colour = " ^4 " ; //disconnects
}
2016-12-13 11:50:15 +00:00
else if ( ! Q_strcasecmp ( link , " bsp " ) | | ! Q_strcasecmp ( link , " spr " ) | | ! Q_strcasecmp ( link , " mdl " ) | | ! Q_strcasecmp ( link , " md3 " ) | | ! Q_strcasecmp ( link , " iqm " ) | | ! Q_strcasecmp ( link , " psk " ) | | ! Q_strcasecmp ( link , " dpm " ) | | ! Q_strcasecmp ( link , " zym " ) | | ! Q_strcasecmp ( link , " md5mesh " ) | | ! Q_strcasecmp ( link , " md5anim " ) )
2016-07-12 00:40:13 +00:00
Q_snprintfz ( link , sizeof ( link ) , " \\ modelviewer \\ %s " , name ) ;
else if ( ! Q_strcasecmp ( link , " qc " ) | | ! Q_strcasecmp ( link , " src " ) | | ! Q_strcasecmp ( link , " qh " ) | | ! Q_strcasecmp ( link , " h " ) | | ! Q_strcasecmp ( link , " c " )
| | ! Q_strcasecmp ( link , " cfg " ) | | ! Q_strcasecmp ( link , " rc " )
| | ! Q_strcasecmp ( link , " txt " ) | | ! Q_strcasecmp ( link , " log " )
| | ! Q_strcasecmp ( link , " ent " ) | | ! Q_strcasecmp ( link , " rtlights " )
| | ! Q_strcasecmp ( link , " shader " ) | | ! Q_strcasecmp ( link , " framegroups " ) )
Q_snprintfz ( link , sizeof ( link ) , " \\ edit \\ %s " , name ) ;
2017-01-13 00:39:50 +00:00
else if ( ! Q_strcasecmp ( link , " tga " ) | | ! Q_strcasecmp ( link , " png " ) | | ! Q_strcasecmp ( link , " jpg " ) | | ! Q_strcasecmp ( link , " jpeg " ) | | ! Q_strcasecmp ( link , " lmp " ) | | ! Q_strcasecmp ( link , " pcx " ) | | ! Q_strcasecmp ( link , " bmp " ) )
2016-07-12 00:40:13 +00:00
{
//FIXME: image replacements are getting in the way here.
Q_snprintfz ( link , sizeof ( link ) , " \\ tiprawimg \\ %s \\ tip \\ (note: image replacement rules are context-dependant, including base path, sub path, extension, or complete replacement via a shader) " , name ) ;
colour = " ^6 " ; //shown on mouseover
}
else if ( ! Q_strcasecmp ( link , " qwd " ) | | ! Q_strcasecmp ( link , " dem " ) | | ! Q_strcasecmp ( link , " mvd " ) | | ! Q_strcasecmp ( link , " dm2 " ) )
{
Q_snprintfz ( link , sizeof ( link ) , " \\ demo \\ %s " , name ) ;
colour = " ^4 " ; //disconnects
}
else if ( ! Q_strcasecmp ( link , " roq " ) | | ! Q_strcasecmp ( link , " cin " ) | | ! Q_strcasecmp ( link , " avi " ) | | ! Q_strcasecmp ( link , " mp4 " ) | | ! Q_strcasecmp ( link , " mkv " ) )
Q_snprintfz ( link , sizeof ( link ) , " \\ film \\ %s " , name ) ;
else
{
colour = " ^3 " ; //nothing
* link = 0 ;
}
}
else
{
char * gah ;
colour = " ^1 " ; //superseeded
Q_snprintfz ( link , sizeof ( link ) , " \\ tip \\ overriden by file from %s " , loc . search - > logicalpath ) ;
gah = link + 20 ; //whatever
while ( ( gah = strchr ( gah , ' \\ ' ) ) )
* gah = ' / ' ;
}
2014-02-07 08:38:40 +00:00
if ( size > 1.0 * 1024 * 1024 * 1024 )
2016-07-12 00:40:13 +00:00
Con_Printf ( U8 ( " ^[%s%s%s^] \t (%#.3ggb) (%s) \n " ) , colour , name , link , size / ( 1024.0 * 1024 * 1024 ) , s ? s - > logicalpath : " ?? " ) ;
2014-02-07 08:38:40 +00:00
else if ( size > 1.0 * 1024 * 1024 )
2016-07-12 00:40:13 +00:00
Con_Printf ( U8 ( " ^[%s%s%s^] \t (%#.3gmb) (%s) \n " ) , colour , name , link , size / ( 1024.0 * 1024 ) , s ? s - > logicalpath : " ?? " ) ;
2014-02-07 08:38:40 +00:00
else if ( size > 1.0 * 1024 )
2016-07-12 00:40:13 +00:00
Con_Printf ( U8 ( " ^[%s%s%s^] \t (%#.3gkb) (%s) \n " ) , colour , name , link , size / 1024.0 , s ? s - > logicalpath : " ?? " ) ;
2014-02-07 08:38:40 +00:00
else
2016-07-12 00:40:13 +00:00
Con_Printf ( U8 ( " ^[%s%s%s^] \t (%ub) (%s) \n " ) , colour , name , link , ( unsigned int ) size , s ? s - > logicalpath : " ?? " ) ;
2005-08-26 22:52:26 +00:00
return 1 ;
}
void COM_Dir_f ( void )
{
char match [ MAX_QPATH ] ;
2016-07-12 00:40:13 +00:00
if ( Cmd_Argc ( ) > 1 )
Q_strncpyz ( match , Cmd_Argv ( 1 ) , sizeof ( match ) ) ;
else
Q_strncpyz ( match , " * " , sizeof ( match ) ) ;
2005-08-26 22:52:26 +00:00
if ( Cmd_Argc ( ) > 2 )
{
strncat ( match , " /*. " , sizeof ( match ) - 1 ) ;
match [ sizeof ( match ) - 1 ] = ' \0 ' ;
strncat ( match , Cmd_Argv ( 2 ) , sizeof ( match ) - 1 ) ;
match [ sizeof ( match ) - 1 ] = ' \0 ' ;
}
2013-05-03 04:28:08 +00:00
// else
// strncat(match, "/*", sizeof(match)-1);
2005-08-26 22:52:26 +00:00
COM_EnumerateFiles ( match , COM_Dir_List , NULL ) ;
}
/*
= = = = = = = = = = = =
COM_Locate_f
= = = = = = = = = = = =
*/
void COM_Locate_f ( void )
{
flocation_t loc ;
2015-06-04 06:15:14 +00:00
char * f = Cmd_Argv ( 1 ) ;
if ( strchr ( f , ' ^ ' ) ) //fte's filesystem is assumed to be utf-8, but that doesn't mean that console input is. and I'm too lazy to utf-8ify the string (in part because markup can be used to exploit ascii assumptions).
Con_Printf ( " Warning: filename contains markup. If this is because of unicode, set com_parseutf8 1 \n " ) ;
2015-10-11 11:34:58 +00:00
if ( FS_FLocateFile ( f , FSLF_IFFOUND , & loc ) )
2005-08-26 22:52:26 +00:00
{
if ( ! * loc . rawname )
2005-10-16 03:47:26 +00:00
{
2015-06-04 06:15:14 +00:00
Con_Printf ( " File is %u bytes compressed inside " U8 ( " %s " ) " \n " , ( unsigned ) loc . len , loc . search - > logicalpath ) ;
2005-10-16 03:47:26 +00:00
}
2005-08-26 22:52:26 +00:00
else
2006-01-02 22:53:29 +00:00
{
2015-06-04 06:15:14 +00:00
Con_Printf ( " Inside " U8 ( " %s " ) " (%u bytes) \n " U8 ( " %s " ) " \n " , loc . rawname , ( unsigned ) loc . len , loc . search - > logicalpath ) ;
2006-01-02 22:53:29 +00:00
}
2005-08-26 22:52:26 +00:00
}
else
Con_Printf ( " Not found \n " ) ;
}
/*
= = = = = = = = = = = =
COM_WriteFile
The filename will be prefixed by the current game directory
= = = = = = = = = = = =
*/
2015-06-04 06:15:14 +00:00
void COM_WriteFile ( const char * filename , enum fs_relative fsroot , const void * data , int len )
2005-08-26 22:52:26 +00:00
{
2006-03-11 03:12:10 +00:00
vfsfile_t * vfs ;
2005-08-26 22:52:26 +00:00
2006-03-11 03:12:10 +00:00
Sys_Printf ( " COM_WriteFile: %s \n " , filename ) ;
2005-11-21 21:09:11 +00:00
2015-06-04 06:15:14 +00:00
FS_CreatePath ( filename , fsroot ) ;
vfs = FS_OpenVFS ( filename , " wb " , fsroot ) ;
2006-03-11 03:12:10 +00:00
if ( vfs )
2005-08-26 22:52:26 +00:00
{
2006-03-11 03:12:10 +00:00
VFS_WRITE ( vfs , data , len ) ;
VFS_CLOSE ( vfs ) ;
2005-11-21 21:09:11 +00:00
2017-02-19 00:15:42 +00:00
if ( fsroot > = FS_GAME )
FS_FlushFSHashWritten ( filename ) ;
else
com_fschanged = true ;
}
2005-08-26 22:52:26 +00:00
}
/*
= = = = = = = = = = = =
COM_CreatePath
Only used for CopyFile and download
= = = = = = = = = = = =
*/
2010-07-18 08:42:59 +00:00
static void COM_CreatePath ( char * path )
2005-08-26 22:52:26 +00:00
{
char * ofs ;
2005-11-21 21:09:11 +00:00
2014-03-30 08:55:06 +00:00
if ( fs_readonly )
return ;
2005-08-26 22:52:26 +00:00
for ( ofs = path + 1 ; * ofs ; ofs + + )
{
if ( * ofs = = ' / ' )
{ // create the directory
* ofs = 0 ;
Sys_mkdir ( path ) ;
* ofs = ' / ' ;
}
}
}
/*
= = = = = = = = = = =
COM_CopyFile
Copies a file over from the net to the local cache , creating any directories
needed . This is for the convenience of developers using ISDN from home .
= = = = = = = = = = =
*/
2009-03-03 01:52:30 +00:00
/*
static void COM_CopyFile ( char * netpath , char * cachepath )
2005-08-26 22:52:26 +00:00
{
FILE * in , * out ;
int remaining , count ;
char buf [ 4096 ] ;
2005-11-21 21:09:11 +00:00
remaining = COM_FileOpenRead ( netpath , & in ) ;
2005-08-26 22:52:26 +00:00
COM_CreatePath ( cachepath ) ; // create directories up to the cache file
out = fopen ( cachepath , " wb " ) ;
if ( ! out )
Sys_Error ( " Error opening %s " , cachepath ) ;
2005-11-21 21:09:11 +00:00
2005-08-26 22:52:26 +00:00
while ( remaining )
{
if ( remaining < sizeof ( buf ) )
count = remaining ;
else
count = sizeof ( buf ) ;
fread ( buf , 1 , count , in ) ;
fwrite ( buf , 1 , count , out ) ;
remaining - = count ;
}
fclose ( in ) ;
fclose ( out ) ;
}
2009-03-03 01:52:30 +00:00
//*/
2005-08-26 22:52:26 +00:00
int fs_hash_dups ;
int fs_hash_files ;
2014-02-07 08:38:40 +00:00
//normally the filesystem drivers pass a pre-allocated bucket and static strings to us
//the OS driver can't really be expected to track things that reliably however, so it just gives names via the stack.
//these files are grouped up to avoid excessive memory allocations.
struct fsbucketblock
{
struct fsbucketblock * prev ;
int used ;
int total ;
qbyte data [ 1 ] ;
} ;
static struct fsbucketblock * fs_hash_filebuckets ;
2017-02-19 00:15:42 +00:00
static void FS_FlushFSHashReally ( qboolean domutexes )
2005-08-26 22:52:26 +00:00
{
2014-10-05 20:04:11 +00:00
COM_AssertMainThread ( " FS_FlushFSHashReally " ) ;
if ( ! domutexes | | Sys_LockMutex ( fs_thread_mutex ) )
2005-08-26 22:52:26 +00:00
{
2014-10-05 20:04:11 +00:00
com_fschanged = true ;
2014-02-07 08:38:40 +00:00
2014-10-05 20:04:11 +00:00
if ( filesystemhash . numbuckets )
{
int i ;
for ( i = 0 ; i < filesystemhash . numbuckets ; i + + )
filesystemhash . bucket [ i ] = NULL ;
}
2005-08-26 22:52:26 +00:00
2014-10-05 20:04:11 +00:00
while ( fs_hash_filebuckets )
{
struct fsbucketblock * n = fs_hash_filebuckets - > prev ;
Z_Free ( fs_hash_filebuckets ) ;
fs_hash_filebuckets = n ;
}
if ( domutexes )
Sys_UnlockMutex ( fs_thread_mutex ) ;
}
2005-08-26 22:52:26 +00:00
}
2012-05-09 15:30:53 +00:00
2013-05-03 04:28:08 +00:00
static void QDECL FS_AddFileHash ( int depth , const char * fname , fsbucket_t * filehandle , void * pathhandle )
2012-05-09 15:30:53 +00:00
{
fsbucket_t * old ;
2014-03-30 08:55:06 +00:00
old = Hash_GetInsensitiveBucket ( & filesystemhash , fname ) ;
2012-05-09 15:30:53 +00:00
if ( old )
{
fs_hash_dups + + ;
2014-02-07 08:38:40 +00:00
if ( depth > = old - > depth )
2012-05-09 15:30:53 +00:00
{
return ;
}
//remove the old version
Hash_RemoveBucket ( & filesystemhash , fname , & old - > buck ) ;
}
if ( ! filehandle )
{
2014-02-07 08:38:40 +00:00
int nlen = strlen ( fname ) + 1 ;
if ( ! fs_hash_filebuckets | | fs_hash_filebuckets - > used + sizeof ( * filehandle ) + nlen > fs_hash_filebuckets - > total )
{
void * o = fs_hash_filebuckets ;
fs_hash_filebuckets = Z_Malloc ( 65536 ) ;
fs_hash_filebuckets - > total = 65536 - sizeof ( * fs_hash_filebuckets ) ;
fs_hash_filebuckets - > prev = o ;
}
filehandle = ( fsbucket_t * ) ( fs_hash_filebuckets - > data + fs_hash_filebuckets - > used ) ;
fs_hash_filebuckets - > used + = sizeof ( * filehandle ) + nlen ;
2012-05-09 15:30:53 +00:00
if ( ! filehandle )
return ; //eep!
2014-02-07 08:38:40 +00:00
memcpy ( ( char * ) ( filehandle + 1 ) , fname , nlen ) ;
2012-05-09 15:30:53 +00:00
fname = ( char * ) ( filehandle + 1 ) ;
}
2014-02-07 08:38:40 +00:00
filehandle - > depth = depth ;
2012-05-09 15:30:53 +00:00
2014-03-30 08:55:06 +00:00
Hash_AddInsensitive ( & filesystemhash , fname , pathhandle , & filehandle - > buck ) ;
2012-05-09 15:30:53 +00:00
fs_hash_files + + ;
}
2005-08-26 22:52:26 +00:00
2017-02-19 00:15:42 +00:00
static void FS_RebuildFSHash ( qboolean domutex )
2005-08-26 22:52:26 +00:00
{
2012-05-09 15:30:53 +00:00
int depth = 1 ;
2005-08-26 22:52:26 +00:00
searchpath_t * search ;
2014-02-07 08:38:40 +00:00
if ( ! com_fschanged )
return ;
2014-10-05 20:04:11 +00:00
COM_AssertMainThread ( " FS_RebuildFSHash " ) ;
if ( domutex & & ! Sys_LockMutex ( fs_thread_mutex ) )
return ; //amg!
2005-08-26 22:52:26 +00:00
if ( ! filesystemhash . numbuckets )
{
filesystemhash . numbuckets = 1024 ;
2008-05-25 01:06:37 +00:00
filesystemhash . bucket = ( bucket_t * * ) Z_Malloc ( Hash_BytesForBuckets ( filesystemhash . numbuckets ) ) ;
2005-08-26 22:52:26 +00:00
}
else
{
2014-10-05 20:04:11 +00:00
FS_FlushFSHashReally ( false ) ;
2005-08-26 22:52:26 +00:00
}
Hash_InitTable ( & filesystemhash , filesystemhash . numbuckets , filesystemhash . bucket ) ;
fs_hash_dups = 0 ;
fs_hash_files = 0 ;
if ( com_purepaths )
{ //go for the pure paths first.
for ( search = com_purepaths ; search ; search = search - > nextpure )
{
2013-06-23 02:17:02 +00:00
search - > handle - > BuildHash ( search - > handle , depth + + , FS_AddFileHash ) ;
2005-08-26 22:52:26 +00:00
}
}
2013-06-23 02:17:02 +00:00
if ( fs_puremode < 2 )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
{
search - > handle - > BuildHash ( search - > handle , depth + + , FS_AddFileHash ) ;
}
2005-08-26 22:52:26 +00:00
}
com_fschanged = false ;
2014-10-05 20:04:11 +00:00
if ( domutex )
Sys_UnlockMutex ( fs_thread_mutex ) ;
2010-11-02 23:17:25 +00:00
Con_DPrintf ( " %i unique files, %i duplicates \n " , fs_hash_files , fs_hash_dups ) ;
2005-08-26 22:52:26 +00:00
}
2017-02-19 00:15:42 +00:00
static void FS_RebuildFSHash_Update ( const char * fname )
{
flocation_t loc ;
searchpath_t * search ;
int depth = 0 ;
fsbucket_t * old ;
if ( com_fschanged )
return ;
COM_WorkerFullSync ( ) ;
if ( ! Sys_LockMutex ( fs_thread_mutex ) )
return ; //amg!
old = Hash_GetInsensitiveBucket ( & filesystemhash , fname ) ;
if ( old )
{
Hash_RemoveBucket ( & filesystemhash , fname , & old - > buck ) ;
fs_hash_files - - ;
}
if ( com_purepaths )
{ //go for the pure paths first.
for ( search = com_purepaths ; search ; search = search - > nextpure )
{
if ( search - > handle - > FindFile ( search - > handle , & loc , fname , NULL ) )
{
FS_AddFileHash ( depth , fname , NULL , loc . fhandle ) ;
return ;
}
depth + + ;
}
}
if ( fs_puremode < 2 )
{
for ( search = com_searchpaths ; search ; search = search - > next )
{
if ( search - > handle - > FindFile ( search - > handle , & loc , fname , NULL ) )
{
FS_AddFileHash ( depth , fname , NULL , loc . fhandle ) ;
return ;
}
depth + + ;
}
}
Sys_UnlockMutex ( fs_thread_mutex ) ;
}
void FS_FlushFSHashWritten ( const char * fname )
{
FS_RebuildFSHash_Update ( fname ) ;
}
void FS_FlushFSHashRemoved ( const char * fname )
{
FS_RebuildFSHash_Update ( fname ) ;
}
void FS_FlushFSHashFull ( void )
{ //any calls to this are typically a bug...
//that said, figuring out if the file was actually within quake's filesystem isn't easy.
com_fschanged = true ;
//for safety we would need to sync with all threads, so lets just not bother.
//FS_FlushFSHashReally(true);
}
2005-08-26 22:52:26 +00:00
/*
= = = = = = = = = = =
COM_FindFile
Finds the file in the search path .
Sets com_filesize and one of handle or file
= = = = = = = = = = =
*/
//if loc is valid, loc->search is always filled in, the others are filled on success.
2016-07-12 00:40:13 +00:00
//returns 0 if couldn't find.
2015-10-11 11:34:58 +00:00
int FS_FLocateFile ( const char * filename , unsigned int lflags , flocation_t * loc )
2005-08-26 22:52:26 +00:00
{
2014-01-13 02:42:25 +00:00
int depth = 0 ;
2005-08-26 22:52:26 +00:00
searchpath_t * search ;
2015-06-04 06:15:14 +00:00
char cleanpath [ MAX_OSPATH ] ;
2014-01-13 02:42:25 +00:00
flocation_t allownoloc ;
2005-08-26 22:52:26 +00:00
void * pf ;
2014-01-13 02:42:25 +00:00
unsigned int found = FF_NOTFOUND ;
if ( ! loc )
loc = & allownoloc ;
2017-02-19 00:15:42 +00:00
loc - > fhandle = NULL ;
2014-01-13 02:42:25 +00:00
loc - > offset = 0 ;
* loc - > rawname = 0 ;
loc - > search = NULL ;
loc - > len = - 1 ;
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
filename = FS_GetCleanPath ( filename , cleanpath , sizeof ( cleanpath ) ) ;
if ( ! filename )
2009-03-03 01:52:30 +00:00
{
pf = NULL ;
goto fail ;
}
2015-10-11 11:34:58 +00:00
if ( com_fs_cache . ival & & ! com_fschanged & & ! ( lflags & FSLF_IGNOREPURE ) )
2005-08-26 22:52:26 +00:00
{
2014-03-30 08:55:06 +00:00
pf = Hash_GetInsensitive ( & filesystemhash , filename ) ;
2005-08-26 22:52:26 +00:00
if ( ! pf )
goto fail ;
}
else
pf = NULL ;
2015-10-11 11:34:58 +00:00
if ( com_purepaths & & found = = FF_NOTFOUND & & ! ( lflags & FSLF_IGNOREPURE ) )
2005-08-26 22:52:26 +00:00
{
2014-01-13 02:42:25 +00:00
//check if its in one of the 'pure' packages. these override the default ones.
2005-08-26 22:52:26 +00:00
for ( search = com_purepaths ; search ; search = search - > nextpure )
{
2015-10-11 11:34:58 +00:00
if ( ( lflags & FSLF_SECUREONLY ) & & ! ( search - > flags & SPF_UNTRUSTED ) )
continue ;
2016-07-12 00:40:13 +00:00
if ( ! ( ( lflags & FSLF_IGNOREBASEDEPTH ) & & ( search - > flags & SPF_BASEPATH ) ) )
depth + = ( ( search - > flags & SPF_EXPLICIT ) | | ( lflags & FSLF_DEPTH_INEXPLICIT ) ) ;
2012-02-27 12:23:15 +00:00
fs_finds + + ;
2014-01-13 02:42:25 +00:00
found = search - > handle - > FindFile ( search - > handle , loc , filename , pf ) ;
if ( found )
2005-08-26 22:52:26 +00:00
{
2015-10-11 11:34:58 +00:00
if ( ! ( lflags & FSLF_DONTREFERENCE ) )
2014-07-01 07:10:10 +00:00
{
if ( ( search - > flags & fs_referencetype ) ! = fs_referencetype )
Con_DPrintf ( " %s became referenced due to %s \n " , search - > purepath , filename ) ;
search - > flags | = fs_referencetype ;
}
2014-01-13 02:42:25 +00:00
loc - > search = search ;
break ;
2005-08-26 22:52:26 +00:00
}
}
}
2015-10-11 11:34:58 +00:00
if ( ( ( lflags & FSLF_IGNOREPURE ) | | fs_puremode < 2 ) & & found = = FF_NOTFOUND )
2013-06-23 02:17:02 +00:00
{
2014-01-13 02:42:25 +00:00
// optionally check the non-pure paths too.
2013-06-23 02:17:02 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
2005-08-26 22:52:26 +00:00
{
2015-10-27 15:20:15 +00:00
if ( ( lflags & FSLF_SECUREONLY ) & & ( search - > flags & SPF_UNTRUSTED ) )
2015-10-11 11:34:58 +00:00
continue ;
2016-07-12 00:40:13 +00:00
if ( ! ( ( lflags & FSLF_IGNOREBASEDEPTH ) & & ( search - > flags & SPF_BASEPATH ) ) )
depth + = ( ( search - > flags & SPF_EXPLICIT ) | | ( lflags & FSLF_DEPTH_INEXPLICIT ) ) ;
2013-06-23 02:17:02 +00:00
fs_finds + + ;
2014-01-13 02:42:25 +00:00
found = search - > handle - > FindFile ( search - > handle , loc , filename , pf ) ;
if ( found )
2005-12-21 03:07:33 +00:00
{
2015-10-11 11:34:58 +00:00
if ( ! ( lflags & FSLF_DONTREFERENCE ) )
2014-07-01 07:10:10 +00:00
{
if ( ( search - > flags & fs_referencetype ) ! = fs_referencetype )
Con_DPrintf ( " %s became referenced due to %s \n " , search - > purepath , filename ) ;
search - > flags | = fs_referencetype ;
}
2014-01-13 02:42:25 +00:00
loc - > search = search ;
break ;
2005-12-21 03:07:33 +00:00
}
2005-08-26 22:52:26 +00:00
}
}
fail :
2015-10-11 11:34:58 +00:00
if ( found = = FF_SYMLINK & & ! ( lflags & FSLF_IGNORELINKS ) )
2014-01-13 02:42:25 +00:00
{
static int blocklink ;
if ( blocklink < 4 & & loc - > len < MAX_QPATH )
{
//read the link target
char * s , * b ;
char targname [ MAX_QPATH ] ;
char mergedname [ MAX_QPATH ] ;
targname [ loc - > len ] = 0 ;
loc - > search - > handle - > ReadFile ( loc - > search - > handle , loc , targname ) ;
//properlyish unixify
2014-02-13 23:54:57 +00:00
while ( ( s = strchr ( targname , ' \\ ' ) ) )
2014-01-13 02:42:25 +00:00
* s = ' / ' ;
if ( * targname = = ' / ' )
Q_strncpyz ( mergedname , targname + 1 , sizeof ( mergedname ) ) ;
else
{
Q_strncpyz ( mergedname , filename , sizeof ( mergedname ) ) ;
2014-02-13 23:54:57 +00:00
while ( ( s = strchr ( mergedname , ' \\ ' ) ) )
2014-01-13 02:42:25 +00:00
* s = ' / ' ;
b = COM_SkipPath ( mergedname ) ;
* b = 0 ;
for ( s = targname ; ! strncmp ( s , " ../ " , 3 ) & & b > mergedname ; )
{
s + = 3 ;
if ( b [ - 1 ] = = ' / ' )
* - - b = 0 ;
* b = 0 ;
b = strrchr ( mergedname , ' / ' ) ;
if ( b )
* + + b = 0 ;
else
{
//no prefix left.
* mergedname = 0 ;
break ;
}
}
b = mergedname + strlen ( mergedname ) ;
Q_strncpyz ( b , s , sizeof ( mergedname ) - ( b - mergedname ) ) ;
}
//and locate that instead.
blocklink + + ;
2015-10-11 11:34:58 +00:00
depth = FS_FLocateFile ( mergedname , lflags , loc ) ;
2014-01-13 02:42:25 +00:00
blocklink - - ;
if ( ! loc - > search )
Con_Printf ( " Symlink %s -> %s (%s) is dead \n " , filename , targname , mergedname ) ;
return depth ;
}
}
2005-08-26 22:52:26 +00:00
/* if (len>=0)
{
if ( loc )
Con_Printf ( " Found %s:%i \n " , loc - > rawname , loc - > len ) ;
else
Con_Printf ( " Found %s \n " , filename ) ;
}
else
Con_Printf ( " Failed \n " ) ;
2006-03-04 20:43:48 +00:00
*/
2016-07-12 00:40:13 +00:00
if ( found = = FF_NOTFOUND | | loc - > len = = - 1 )
2014-01-13 02:42:25 +00:00
{
2016-07-12 00:40:13 +00:00
if ( lflags & FSLF_DEEPONFAILURE )
return 0x7fffffff ; //if we're asking for depth, the file is reported to be so far into the filesystem as to be irrelevant.
return 0 ;
2014-01-13 02:42:25 +00:00
}
2016-07-12 00:40:13 +00:00
return depth + 1 ;
2005-08-26 22:52:26 +00:00
}
2006-01-02 22:53:29 +00:00
2017-01-13 00:39:50 +00:00
//returns the package/'gamedir/foo.pk3' filename to tell the client to download
//unfortunately foo.pk3 may contain a 'bar.pk3' and downloading dir/foo.pk3/bar.pk3 won't work
//so if loc->search is dir/foo.pk3/bar.pk3 find dir/foo.pk3 instead
2016-07-12 00:40:13 +00:00
char * FS_GetPackageDownloadFilename ( flocation_t * loc )
{
searchpath_t * sp , * search ;
for ( sp = loc - > search ; ; )
{
for ( search = com_searchpaths ; search ; search = search - > next )
{
2017-01-13 00:39:50 +00:00
if ( search ! = sp )
if ( search - > handle - > GeneratePureCRC ) //only consider files that have a pure hash. this excludes system paths
if ( ! strncmp ( search - > purepath , sp - > purepath , strlen ( search - > purepath ) ) )
if ( sp - > purepath [ strlen ( search - > purepath ) ] = = ' / ' ) //also ensures that the path gets shorter, avoiding infinite loops as it fights between base+home dirs.
break ;
2016-07-12 00:40:13 +00:00
}
if ( search )
sp = search ;
else
break ;
}
2017-01-13 00:39:50 +00:00
if ( sp & & strchr ( sp - > purepath , ' / ' ) ) //never allow any packages that are directly sitting in the basedir.
2016-07-12 00:40:13 +00:00
return sp - > purepath ;
return NULL ;
}
2013-12-17 22:45:37 +00:00
char * FS_WhichPackForLocation ( flocation_t * loc , qboolean makereferenced )
2008-11-09 22:29:28 +00:00
{
char * ret ;
if ( ! loc - > search )
return NULL ; //huh? not a valid location.
ret = strchr ( loc - > search - > purepath , ' / ' ) ;
2013-12-17 22:45:37 +00:00
if ( ret )
{
ret + + ;
if ( ! strchr ( ret , ' / ' ) )
{
if ( makereferenced )
loc - > search - > flags | = SPF_REFERENCED ;
return ret ;
}
}
return NULL ;
2008-11-09 22:29:28 +00:00
}
2011-12-05 15:23:40 +00:00
/*requires extension*/
2012-01-24 04:24:14 +00:00
qboolean FS_GetPackageDownloadable ( const char * package )
2011-12-05 15:23:40 +00:00
{
searchpath_t * search ;
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
2011-12-05 15:23:40 +00:00
{
2014-06-24 03:02:32 +00:00
if ( ! Q_strcasecmp ( package , search - > purepath ) )
2013-06-23 02:17:02 +00:00
return ! ( search - > flags & SPF_COPYPROTECTED ) ;
2011-12-05 15:23:40 +00:00
}
return false ;
}
2006-01-02 22:53:29 +00:00
char * FS_GetPackHashes ( char * buffer , int buffersize , qboolean referencedonly )
{
searchpath_t * search ;
buffersize - - ;
* buffer = 0 ;
if ( com_purepaths )
{
for ( search = com_purepaths ; search ; search = search - > nextpure )
{
Q_strncatz ( buffer , va ( " %i " , search - > crc_check ) , buffersize ) ;
}
return buffer ;
}
else
{
for ( search = com_searchpaths ; search ; search = search - > next )
{
2013-06-23 02:17:02 +00:00
if ( ! search - > crc_check & & search - > handle - > GeneratePureCRC )
search - > crc_check = search - > handle - > GeneratePureCRC ( search - > handle , 0 , 0 ) ;
2006-01-02 22:53:29 +00:00
if ( search - > crc_check )
{
Q_strncatz ( buffer , va ( " %i " , search - > crc_check ) , buffersize ) ;
}
}
return buffer ;
}
}
2011-12-05 15:23:40 +00:00
/*
referencedonly = 0 : show all paks
referencedonly = 1 : show only paks that are referenced ( q3 - compat )
referencedonly = 2 : show all paks , but paks that are referenced are prefixed with a star
ext = 0 : hide extensions ( q3 - compat )
ext = 1 : show extensions .
*/
char * FS_GetPackNames ( char * buffer , int buffersize , int referencedonly , qboolean ext )
2006-01-02 22:53:29 +00:00
{
2010-11-10 03:32:47 +00:00
char temp [ MAX_OSPATH ] ;
2008-11-09 22:29:28 +00:00
searchpath_t * search ;
buffersize - - ;
* buffer = 0 ;
2009-06-03 09:09:35 +00:00
2008-11-09 22:29:28 +00:00
if ( com_purepaths )
{
for ( search = com_purepaths ; search ; search = search - > nextpure )
{
2013-06-23 02:17:02 +00:00
if ( referencedonly = = 0 & & ! ( search - > flags & SPF_REFERENCED ) )
2011-12-05 15:23:40 +00:00
continue ;
2013-06-23 02:17:02 +00:00
if ( referencedonly = = 2 & & ( search - > flags & SPF_REFERENCED ) )
2011-12-05 15:23:40 +00:00
Q_strncatz ( buffer , " * " , buffersize ) ;
2011-10-27 16:16:29 +00:00
if ( ! ext )
{
COM_StripExtension ( search - > purepath , temp , sizeof ( temp ) ) ;
Q_strncatz ( buffer , va ( " %s " , temp ) , buffersize ) ;
}
else
{
Q_strncatz ( buffer , va ( " %s " , search - > purepath ) , buffersize ) ;
}
2008-11-09 22:29:28 +00:00
}
return buffer ;
}
else
{
for ( search = com_searchpaths ; search ; search = search - > next )
{
2013-06-23 02:17:02 +00:00
if ( ! search - > crc_check & & search - > handle - > GeneratePureCRC )
search - > crc_check = search - > handle - > GeneratePureCRC ( search - > handle , 0 , 0 ) ;
2008-11-09 22:29:28 +00:00
if ( search - > crc_check )
{
2013-06-23 02:17:02 +00:00
if ( referencedonly = = 0 & & ! ( search - > flags & SPF_REFERENCED ) )
2011-12-05 15:23:40 +00:00
continue ;
2013-06-23 02:17:02 +00:00
if ( referencedonly = = 2 & & ( search - > flags & SPF_REFERENCED ) )
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
{
// '*' prefix is meant to mean 'referenced'.
//really all that means to the client is that it definitely wants to download it.
//if its copyrighted, the client shouldn't try to do so, as it won't be allowed.
2013-06-23 02:17:02 +00:00
if ( ! ( search - > flags & SPF_COPYPROTECTED ) )
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
Q_strncatz ( buffer , " * " , buffersize ) ;
}
2011-12-05 15:23:40 +00:00
2011-10-27 16:16:29 +00:00
if ( ! ext )
{
COM_StripExtension ( search - > purepath , temp , sizeof ( temp ) ) ;
Q_strncatz ( buffer , va ( " %s " , temp ) , buffersize ) ;
}
else
{
Q_strncatz ( buffer , va ( " %s " , search - > purepath ) , buffersize ) ;
}
2008-11-09 22:29:28 +00:00
}
}
return buffer ;
}
2006-01-02 22:53:29 +00:00
}
2011-12-05 15:23:40 +00:00
void FS_ReferenceControl ( unsigned int refflag , unsigned int resetflags )
{
searchpath_t * s ;
2013-06-23 02:17:02 +00:00
refflag & = SPF_REFERENCED ;
resetflags & = SPF_REFERENCED ;
2011-12-05 15:23:40 +00:00
if ( resetflags )
{
for ( s = com_searchpaths ; s ; s = s - > next )
{
2013-06-23 02:17:02 +00:00
s - > flags & = ~ resetflags ;
2011-12-05 15:23:40 +00:00
}
}
fs_referencetype = refflag ;
}
2009-04-01 22:03:56 +00:00
//outbuf might not be written into
2015-05-14 03:06:58 +00:00
const char * FS_GetCleanPath ( const char * pattern , char * outbuf , int outlen )
2005-12-21 03:07:33 +00:00
{
2014-12-23 15:26:42 +00:00
const char * s ;
char * o ;
char * seg ;
2015-04-14 23:12:17 +00:00
char * end = outbuf + outlen ;
2009-04-01 22:03:56 +00:00
2014-12-23 15:26:42 +00:00
s = pattern ;
seg = o = outbuf ;
2016-09-09 18:46:08 +00:00
if ( ! pattern )
{
Con_Printf ( " Error: Empty filename \n " ) ;
return NULL ;
}
2014-12-23 15:26:42 +00:00
for ( ; ; )
2005-12-21 03:07:33 +00:00
{
2015-04-14 23:12:17 +00:00
if ( o = = end )
{
Con_Printf ( " Error: filename too long \n " ) ;
return NULL ;
}
2014-12-23 15:26:42 +00:00
if ( * s = = ' : ' )
2009-04-01 22:03:56 +00:00
{
2014-12-23 15:26:42 +00:00
if ( s = = pattern + 1 & & ( s [ 1 ] = = ' / ' | | s [ 1 ] = = ' \\ ' ) )
Con_Printf ( " Error: absolute path in filename %s \n " , pattern ) ;
else
Con_Printf ( " Error: alternative data stream in filename %s \n " , pattern ) ;
return NULL ;
2009-04-01 22:03:56 +00:00
}
2014-12-23 15:26:42 +00:00
else if ( * s = = ' \\ ' | | * s = = ' / ' | | ! * s )
{ //end of segment
2015-04-14 23:12:17 +00:00
if ( o = = seg )
2009-03-03 01:52:30 +00:00
{
2014-12-23 15:26:42 +00:00
if ( o = = outbuf )
{
Con_Printf ( " Error: absolute path in filename %s \n " , pattern ) ;
return NULL ;
}
2015-05-14 03:06:58 +00:00
if ( ! * s )
{
* o + + = ' \0 ' ;
break ;
}
2014-12-23 15:26:42 +00:00
Con_Printf ( " Error: empty directory name (%s) \n " , pattern ) ;
2009-03-03 01:52:30 +00:00
s + + ;
2014-12-23 15:26:42 +00:00
continue ;
}
//ignore any leading spaces in the name segment
//it should just make more stuff invalid
while ( * seg = = ' ' )
seg + + ;
2016-09-09 18:46:08 +00:00
if ( ! seg [ 0 ] )
{
Con_Printf ( " Error: No filename (%s) \n " , pattern ) ;
return NULL ;
}
2014-12-23 15:26:42 +00:00
if ( seg [ 0 ] = = ' . ' )
{
if ( o = = seg + 1 )
Con_Printf ( " Error: source directory (%s) \n " , pattern ) ;
else if ( seg [ 1 ] = = ' . ' )
Con_Printf ( " Error: parent directory (%s) \n " , pattern ) ;
else
Con_Printf ( " Error: hidden name (%s) \n " , pattern ) ;
return NULL ;
}
# if defined(_WIN32) || defined(__CYGWIN__)
//in win32, we use the //?/ trick to get around filename length restrictions.
//4-letter reserved paths: comX, lptX
//we'll allow this elsewhere to save cycles, just try to avoid running it on a fat32 or ntfs filesystem from linux
if ( ( ( seg [ 0 ] = = ' c ' | | seg [ 0 ] = = ' C ' ) & &
( seg [ 1 ] = = ' o ' | | seg [ 1 ] = = ' O ' ) & &
( seg [ 2 ] = = ' m ' | | seg [ 2 ] = = ' M ' ) & &
( seg [ 3 ] > = ' 0 ' & & seg [ 3 ] < = ' 9 ' ) ) | |
( ( seg [ 0 ] = = ' l ' | | seg [ 0 ] = = ' L ' ) & &
( seg [ 1 ] = = ' p ' | | seg [ 1 ] = = ' P ' ) & &
( seg [ 2 ] = = ' t ' | | seg [ 2 ] = = ' T ' ) & &
( seg [ 3 ] > = ' 0 ' & & seg [ 3 ] < = ' 9 ' ) ) )
{
if ( o = = seg + 4 | | seg [ 4 ] = = ' ' | | seg [ 4 ] = = ' \t ' | | seg [ 4 ] = = ' . ' )
{
Con_Printf ( " Error: reserved name in path (%c%c%c%c in %s) \n " , seg [ 0 ] , seg [ 1 ] , seg [ 2 ] , seg [ 3 ] , pattern ) ;
return NULL ;
}
2009-03-03 01:52:30 +00:00
}
2014-12-23 15:26:42 +00:00
//3 letter reserved paths: con, nul, prn
if ( ( ( seg [ 0 ] = = ' c ' | | seg [ 0 ] = = ' C ' ) & &
( seg [ 1 ] = = ' o ' | | seg [ 1 ] = = ' O ' ) & &
( seg [ 2 ] = = ' n ' | | seg [ 2 ] = = ' N ' ) ) | |
( ( seg [ 0 ] = = ' p ' | | seg [ 0 ] = = ' P ' ) & &
( seg [ 1 ] = = ' r ' | | seg [ 1 ] = = ' R ' ) & &
( seg [ 2 ] = = ' n ' | | seg [ 2 ] = = ' N ' ) ) | |
( ( seg [ 0 ] = = ' n ' | | seg [ 0 ] = = ' N ' ) & &
( seg [ 1 ] = = ' u ' | | seg [ 1 ] = = ' U ' ) & &
( seg [ 2 ] = = ' l ' | | seg [ 2 ] = = ' L ' ) ) )
{
if ( o = = seg + 3 | | seg [ 3 ] = = ' ' | | seg [ 3 ] = = ' \t ' | | seg [ 3 ] = = ' . ' )
{
Con_Printf ( " Error: reserved name in path (%c%c%c in %s) \n " , seg [ 0 ] , seg [ 1 ] , seg [ 2 ] , pattern ) ;
return NULL ;
}
}
# endif
if ( * s + + )
* o + + = ' / ' ;
else
{
* o + + = ' \0 ' ;
break ;
}
seg = o ;
2009-03-03 01:52:30 +00:00
}
2014-12-23 15:26:42 +00:00
else
* o + + = * s + + ;
2010-12-18 17:02:47 +00:00
}
2009-03-03 01:52:30 +00:00
2014-12-23 15:26:42 +00:00
// Sys_Printf("%s changed to %s\n", pattern, outbuf);
return outbuf ;
2005-12-21 03:07:33 +00:00
}
2009-04-01 22:03:56 +00:00
vfsfile_t * VFS_Filter ( const char * filename , vfsfile_t * handle )
2006-02-11 02:09:43 +00:00
{
// char *ext;
if ( ! handle | | handle - > WriteBytes | | handle - > seekingisabadplan ) //only on readonly files
return handle ;
// ext = COM_FileExtension (filename);
2017-02-19 00:15:42 +00:00
# ifdef AVAIL_GZDEC
2014-02-07 08:38:40 +00:00
// if (!Q_strcasecmp(ext, ".gz"))
2006-02-11 02:09:43 +00:00
{
2013-06-23 02:17:02 +00:00
return FS_DecompressGZip ( handle , NULL ) ;
2006-02-11 02:09:43 +00:00
}
2009-04-01 22:03:56 +00:00
# endif
return handle ;
}
qboolean FS_NativePath ( const char * fname , enum fs_relative relativeto , char * out , int outlen )
{
2014-03-30 08:55:06 +00:00
char * last ;
int i ;
2009-04-01 22:03:56 +00:00
char cleanname [ MAX_QPATH ] ;
2014-03-30 08:55:06 +00:00
if ( relativeto = = FS_SYSTEM )
{
//system is already the native path. we can just pass it through. perhaps we should clean it up first however, although that's just making sure all \ are /
snprintf ( out , outlen , " %s " , fname ) ;
for ( ; * out ; out + + )
{
if ( * out = = ' \\ ' )
* out = ' / ' ;
}
return true ;
}
2015-04-14 23:12:17 +00:00
if ( * fname = = 0 )
{
//this is sometimes used to query the actual path.
//don't alow it for other stuff though.
if ( relativeto ! = FS_ROOT & & relativeto ! = FS_BINARYPATH )
return false ;
}
else
{
fname = FS_GetCleanPath ( fname , cleanname , sizeof ( cleanname ) ) ;
if ( ! fname )
return false ;
}
2009-04-01 22:03:56 +00:00
switch ( relativeto )
{
case FS_GAMEONLY :
case FS_GAME :
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
snprintf ( out , outlen , " %s%s/%s " , com_homepath , gamedirfile , fname ) ;
2009-04-01 22:03:56 +00:00
else
2014-03-30 08:55:06 +00:00
snprintf ( out , outlen , " %s%s/%s " , com_gamepath , gamedirfile , fname ) ;
2009-04-01 22:03:56 +00:00
break ;
2013-05-03 04:28:08 +00:00
case FS_BINARYPATH :
if ( host_parms . binarydir & & * host_parms . binarydir )
snprintf ( out , outlen , " %s%s " , host_parms . binarydir , fname ) ;
else
snprintf ( out , outlen , " %s%s " , host_parms . basedir , fname ) ;
break ;
2009-04-01 22:03:56 +00:00
case FS_ROOT :
2015-04-14 23:12:17 +00:00
if ( com_installer )
return false ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
snprintf ( out , outlen , " %s%s " , com_homepath , fname ) ;
2009-04-01 22:03:56 +00:00
else
2014-03-30 08:55:06 +00:00
snprintf ( out , outlen , " %s%s " , com_gamepath , fname ) ;
2009-04-01 22:03:56 +00:00
break ;
2014-03-30 08:55:06 +00:00
case FS_BASEGAMEONLY :
last = NULL ;
for ( i = 0 ; i < sizeof ( fs_manifest - > gamepath ) / sizeof ( fs_manifest - > gamepath [ 0 ] ) ; i + + )
{
if ( fs_manifest - > gamepath [ i ] . base & & fs_manifest - > gamepath [ i ] . path )
{
if ( ! strcmp ( fs_manifest - > gamepath [ i ] . path , " * " ) )
continue ;
last = fs_manifest - > gamepath [ i ] . path ;
if ( * last = = ' * ' )
last + + ;
}
}
if ( ! last )
return false ; //eep?
if ( com_homepathenabled )
snprintf ( out , outlen , " %s%s/%s " , com_homepath , last , fname ) ;
else
snprintf ( out , outlen , " %s%s/%s " , com_gamepath , last , fname ) ;
break ;
2015-06-12 14:44:50 +00:00
case FS_PUBGAMEONLY :
last = NULL ;
for ( i = 0 ; i < sizeof ( fs_manifest - > gamepath ) / sizeof ( fs_manifest - > gamepath [ 0 ] ) ; i + + )
{
if ( fs_manifest - > gamepath [ i ] . path )
{
if ( * fs_manifest - > gamepath [ i ] . path = = ' * ' )
continue ;
last = fs_manifest - > gamepath [ i ] . path ;
}
}
if ( ! last )
return false ; //eep?
if ( com_homepathenabled )
snprintf ( out , outlen , " %s%s/%s " , com_homepath , last , fname ) ;
else
snprintf ( out , outlen , " %s%s/%s " , com_gamepath , last , fname ) ;
break ;
2014-03-30 08:55:06 +00:00
case FS_PUBBASEGAMEONLY :
last = NULL ;
for ( i = 0 ; i < sizeof ( fs_manifest - > gamepath ) / sizeof ( fs_manifest - > gamepath [ 0 ] ) ; i + + )
{
2017-02-11 17:16:51 +00:00
if ( fs_manifest & & fs_manifest - > gamepath [ i ] . base & & fs_manifest - > gamepath [ i ] . path )
2014-03-30 08:55:06 +00:00
{
if ( * fs_manifest - > gamepath [ i ] . path = = ' * ' )
continue ;
last = fs_manifest - > gamepath [ i ] . path ;
}
}
if ( ! last )
return false ; //eep?
if ( com_homepathenabled )
snprintf ( out , outlen , " %s%s/%s " , com_homepath , last , fname ) ;
2009-04-01 22:03:56 +00:00
else
2014-03-30 08:55:06 +00:00
snprintf ( out , outlen , " %s%s/%s " , com_gamepath , last , fname ) ;
2009-04-01 22:03:56 +00:00
break ;
default :
2013-05-03 04:28:08 +00:00
Sys_Error ( " FS_NativePath case not handled \n " ) ;
2009-04-01 22:03:56 +00:00
}
return true ;
2006-02-11 02:09:43 +00:00
}
2015-06-14 01:28:01 +00:00
//returns false to stop the enumeration. check the return value of the fs enumerator to see if it was canceled by this return value.
static int QDECL FS_NullFSEnumerator ( const char * fname , qofs_t fsize , time_t mtime , void * parm , searchpathfuncs_t * spath )
{
2015-06-14 04:03:22 +00:00
return false ;
2015-06-14 01:28:01 +00:00
}
//opens a file in the same (writable) path that contains an existing version of the file or one of the other patterns listed
vfsfile_t * FS_OpenWithFriends ( const char * fname , char * sysname , size_t sysnamesize , int numfriends , . . . )
{
searchpath_t * search ;
searchpath_t * lastwritable = NULL ;
flocation_t loc ;
va_list ap ;
int i ;
char cleanname [ MAX_QPATH ] ;
fname = FS_GetCleanPath ( fname , cleanname , sizeof ( cleanname ) ) ;
if ( ! fname )
return NULL ;
for ( search = com_searchpaths ; search ; search = search - > next )
{
if ( ( search - > flags & SPF_EXPLICIT ) & & ( search - > flags & SPF_WRITABLE ) )
lastwritable = search ;
if ( search - > handle - > FindFile ( search - > handle , & loc , fname , NULL ) )
break ;
va_start ( ap , numfriends ) ;
for ( i = 0 ; i < numfriends ; i + + )
{
char * path = va_arg ( ap , char * ) ;
if ( ! search - > handle - > EnumerateFiles ( search - > handle , path , FS_NullFSEnumerator , NULL ) )
break ;
}
va_end ( ap ) ;
if ( i < numfriends )
break ;
}
if ( lastwritable )
{
//figure out the system path
Q_strncpyz ( sysname , lastwritable - > logicalpath , sysnamesize ) ;
FS_CleanDir ( sysname , sysnamesize ) ;
Q_strncatz ( sysname , fname , sysnamesize ) ;
//create the dir if needed and open the file.
COM_CreatePath ( sysname ) ;
return VFSOS_Open ( sysname , " wbp " ) ;
}
2015-06-16 23:53:58 +00:00
FS_NativePath ( fname , FS_GAMEONLY , sysname , sysnamesize ) ;
2015-06-14 01:28:01 +00:00
return NULL ;
}
2016-07-21 19:27:59 +00:00
//returns false if the string didn't fit. we're not trying to be clever and reallocate the buffer
qboolean try_snprintf ( char * buffer , size_t size , const char * format , . . . )
{
size_t ret ;
va_list argptr ;
va_start ( argptr , format ) ;
# ifdef _WIN32
# undef _vsnprintf
ret = _vsnprintf ( buffer , size , format , argptr ) ;
# define _vsnprintf unsafe_vsnprintf
# else
ret = vsnprintf ( buffer , size , format , argptr ) ;
# endif
va_end ( argptr ) ;
if ( ret > size - 1 ) //should cope with microsoft's -1s and linuxes total-length return values.
return false ;
return true ;
}
2015-06-14 01:28:01 +00:00
/*locates and opens a file
modes :
r = read
w = write
a = append
t = text mode ( because windows sucks ) . binary is otherwise assumed .
p = persist ( ie : saved games and configs , but not downloads or large content )
*/
2009-04-01 22:03:56 +00:00
vfsfile_t * FS_OpenVFS ( const char * filename , const char * mode , enum fs_relative relativeto )
2005-12-21 03:07:33 +00:00
{
2009-04-01 22:03:56 +00:00
char cleanname [ MAX_QPATH ] ;
2005-12-21 03:07:33 +00:00
char fullname [ MAX_OSPATH ] ;
flocation_t loc ;
vfsfile_t * vfs ;
//eventually, this function will be the *ONLY* way to get at files
2014-03-30 08:55:06 +00:00
if ( relativeto = = FS_SYSTEM )
return VFSOS_Open ( filename , mode ) ;
2005-12-21 03:07:33 +00:00
2014-03-30 08:55:06 +00:00
//blanket-bans
2009-06-03 09:09:35 +00:00
2009-04-01 22:03:56 +00:00
filename = FS_GetCleanPath ( filename , cleanname , sizeof ( cleanname ) ) ;
if ( ! filename )
2005-12-21 03:07:33 +00:00
return NULL ;
2014-08-27 08:41:31 +00:00
# ifdef _DEBUG
2006-01-02 22:53:29 +00:00
if ( strcmp ( mode , " rb " ) )
2010-07-11 02:22:39 +00:00
if ( strcmp ( mode , " r+b " ) )
if ( strcmp ( mode , " wb " ) )
if ( strcmp ( mode , " w+b " ) )
if ( strcmp ( mode , " ab " ) )
2014-08-27 08:41:31 +00:00
if ( strcmp ( mode , " wbp " ) )
return NULL ; //urm, unable to write/append
# endif
2006-01-02 22:53:29 +00:00
2008-11-09 22:29:28 +00:00
//if there can only be one file (eg: write access) find out where it is.
2005-12-21 03:07:33 +00:00
switch ( relativeto )
{
case FS_GAMEONLY : //OS access only, no paks
2017-02-19 00:15:42 +00:00
vfs = NULL ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
2005-12-21 03:07:33 +00:00
{
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %s%s/%s " , com_homepath , gamedirfile , filename ) )
return NULL ;
2013-05-07 19:37:00 +00:00
if ( * mode = = ' w ' )
COM_CreatePath ( fullname ) ;
2005-12-21 03:07:33 +00:00
vfs = VFSOS_Open ( fullname , mode ) ;
}
2017-02-19 00:15:42 +00:00
if ( ! vfs & & * gamedirfile )
2014-03-31 17:06:41 +00:00
{
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %s%s/%s " , com_gamepath , gamedirfile , filename ) )
return NULL ;
2014-03-31 17:06:41 +00:00
if ( * mode = = ' w ' )
COM_CreatePath ( fullname ) ;
2017-02-19 00:15:42 +00:00
vfs = VFSOS_Open ( fullname , mode ) ;
2014-03-31 17:06:41 +00:00
}
2017-02-19 00:15:42 +00:00
if ( vfs & & ! strcmp ( mode , " wb " ) )
return vfs ;
2015-06-12 14:44:50 +00:00
case FS_PUBGAMEONLY :
2016-07-21 19:27:59 +00:00
if ( ! FS_NativePath ( filename , relativeto , fullname , sizeof ( fullname ) ) )
return NULL ;
2015-06-12 14:44:50 +00:00
if ( * mode = = ' w ' )
COM_CreatePath ( fullname ) ;
return VFSOS_Open ( fullname , mode ) ;
2013-06-23 02:17:02 +00:00
case FS_GAME : //load from paks in preference to system paths. overwriting be damned.
2014-03-30 08:55:06 +00:00
case FS_PUBBASEGAMEONLY : //load from paks in preference to system paths. overwriting be damned.
2016-07-21 19:27:59 +00:00
if ( ! FS_NativePath ( filename , relativeto , fullname , sizeof ( fullname ) ) )
return NULL ;
2006-03-11 05:12:33 +00:00
break ;
2013-11-29 14:36:47 +00:00
case FS_BINARYPATH :
2016-07-21 19:27:59 +00:00
if ( ! FS_NativePath ( filename , relativeto , fullname , sizeof ( fullname ) ) )
return NULL ;
2013-11-29 14:36:47 +00:00
if ( * mode = = ' w ' )
COM_CreatePath ( fullname ) ;
return VFSOS_Open ( fullname , mode ) ;
2013-06-23 02:17:02 +00:00
case FS_ROOT : //always bypass packs and gamedirs
2015-04-14 23:12:17 +00:00
if ( com_installer )
return NULL ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
2005-12-21 03:07:33 +00:00
{
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %s%s " , com_homepath , filename ) )
return NULL ;
2005-12-21 03:07:33 +00:00
vfs = VFSOS_Open ( fullname , mode ) ;
if ( vfs )
return vfs ;
}
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %s%s " , com_gamepath , filename ) )
return NULL ;
2005-12-21 03:07:33 +00:00
return VFSOS_Open ( fullname , mode ) ;
2014-03-30 08:55:06 +00:00
case FS_BASEGAMEONLY : //always bypass packs+pure.
if ( com_homepathenabled )
2005-12-21 03:07:33 +00:00
{
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %sfte/%s " , com_homepath , filename ) )
return NULL ;
2005-12-21 03:07:33 +00:00
vfs = VFSOS_Open ( fullname , mode ) ;
if ( vfs )
return vfs ;
}
2016-07-21 19:27:59 +00:00
if ( ! try_snprintf ( fullname , sizeof ( fullname ) , " %sfte/%s " , com_gamepath , filename ) )
return NULL ;
2005-12-21 03:07:33 +00:00
return VFSOS_Open ( fullname , mode ) ;
default :
2006-03-11 05:12:33 +00:00
Sys_Error ( " FS_OpenVFS: Bad relative path (%i) " , relativeto ) ;
2005-12-21 03:07:33 +00:00
break ;
}
2015-10-11 11:34:58 +00:00
FS_FLocateFile ( filename , FSLF_IFFOUND , & loc ) ;
2005-12-21 03:07:33 +00:00
if ( loc . search )
{
2013-06-23 02:17:02 +00:00
return VFS_Filter ( filename , loc . search - > handle - > OpenVFS ( loc . search - > handle , & loc , mode ) ) ;
2005-12-21 03:07:33 +00:00
}
2006-01-02 23:46:44 +00:00
//if we're meant to be writing, best write to it.
2007-07-27 21:24:31 +00:00
if ( strchr ( mode , ' w ' ) | | strchr ( mode , ' a ' ) )
2011-02-25 04:22:14 +00:00
{
COM_CreatePath ( fullname ) ;
2006-01-02 23:46:44 +00:00
return VFSOS_Open ( fullname , mode ) ;
2011-02-25 04:22:14 +00:00
}
2005-12-21 03:07:33 +00:00
return NULL ;
}
2011-10-27 16:16:29 +00:00
/*opens a vfsfile from an already discovered location*/
2008-11-09 22:29:28 +00:00
vfsfile_t * FS_OpenReadLocation ( flocation_t * location )
{
if ( location - > search )
{
2013-06-23 02:17:02 +00:00
return VFS_Filter ( NULL , location - > search - > handle - > OpenVFS ( location - > search - > handle , location , " rb " ) ) ;
2008-11-09 22:29:28 +00:00
}
return NULL ;
}
2012-04-24 07:59:11 +00:00
qboolean FS_Rename2 ( const char * oldf , const char * newf , enum fs_relative oldrelativeto , enum fs_relative newrelativeto )
2006-01-21 00:06:49 +00:00
{
char oldfullname [ MAX_OSPATH ] ;
char newfullname [ MAX_OSPATH ] ;
2009-04-01 22:03:56 +00:00
if ( ! FS_NativePath ( oldf , oldrelativeto , oldfullname , sizeof ( oldfullname ) ) )
2012-04-24 07:59:11 +00:00
return false ;
2009-04-01 22:03:56 +00:00
if ( ! FS_NativePath ( newf , newrelativeto , newfullname , sizeof ( newfullname ) ) )
2012-04-24 07:59:11 +00:00
return false ;
2006-01-28 06:41:20 +00:00
FS_CreatePath ( newf , newrelativeto ) ;
2012-04-24 07:59:11 +00:00
return Sys_Rename ( oldfullname , newfullname ) ;
2006-01-21 00:06:49 +00:00
}
2012-04-24 07:59:11 +00:00
qboolean FS_Rename ( const char * oldf , const char * newf , enum fs_relative relativeto )
2005-12-21 03:07:33 +00:00
{
2009-04-01 22:03:56 +00:00
return FS_Rename2 ( oldf , newf , relativeto , relativeto ) ;
2005-12-21 03:07:33 +00:00
}
2012-04-24 07:59:11 +00:00
qboolean FS_Remove ( const char * fname , enum fs_relative relativeto )
2005-12-21 03:07:33 +00:00
{
2006-01-28 06:41:20 +00:00
char fullname [ MAX_OSPATH ] ;
2009-04-01 22:03:56 +00:00
if ( ! FS_NativePath ( fname , relativeto , fullname , sizeof ( fullname ) ) )
2012-04-24 07:59:11 +00:00
return false ;
2006-01-28 06:41:20 +00:00
2009-04-01 22:03:56 +00:00
return Sys_remove ( fullname ) ;
2005-12-21 03:07:33 +00:00
}
2009-04-01 22:03:56 +00:00
//create a path for the given filename (dir-only must have trailing slash)
void FS_CreatePath ( const char * pname , enum fs_relative relativeto )
2005-12-21 03:07:33 +00:00
{
char fullname [ MAX_OSPATH ] ;
2009-04-01 22:03:56 +00:00
if ( ! FS_NativePath ( pname , relativeto , fullname , sizeof ( fullname ) ) )
return ;
2009-06-03 09:09:35 +00:00
2005-12-21 03:07:33 +00:00
COM_CreatePath ( fullname ) ;
}
2005-08-26 22:52:26 +00:00
2014-06-30 21:57:35 +00:00
void * FS_MallocFile ( const char * filename , enum fs_relative relativeto , qofs_t * filesize )
{
vfsfile_t * f ;
qbyte * buf ;
qofs_t len ;
f = FS_OpenVFS ( filename , " rb " , relativeto ) ;
if ( ! f )
return NULL ;
len = VFS_GETLEN ( f ) ;
if ( filesize )
* filesize = len ;
buf = ( qbyte * ) BZ_Malloc ( len + 1 ) ;
if ( ! buf )
Sys_Error ( " FS_MallocFile: out of memory loading %s " , filename ) ;
( ( qbyte * ) buf ) [ len ] = 0 ;
VFS_READ ( f , buf , len ) ;
VFS_CLOSE ( f ) ;
return buf ;
}
2009-04-02 22:25:54 +00:00
qboolean FS_WriteFile ( const char * filename , const void * data , int len , enum fs_relative relativeto )
2006-01-02 22:53:29 +00:00
{
vfsfile_t * f ;
FS_CreatePath ( filename , relativeto ) ;
f = FS_OpenVFS ( filename , " wb " , relativeto ) ;
if ( ! f )
return false ;
VFS_WRITE ( f , data , len ) ;
VFS_CLOSE ( f ) ;
return true ;
}
2009-04-01 22:03:56 +00:00
qboolean FS_Copy ( const char * source , const char * dest , enum fs_relative relativesource , enum fs_relative relativedest )
{
vfsfile_t * d , * s ;
char buffer [ 8192 * 8 ] ;
int read ;
qboolean result = false ;
FS_CreatePath ( dest , relativedest ) ;
s = FS_OpenVFS ( source , " rb " , relativesource ) ;
if ( s )
{
2014-08-27 08:41:31 +00:00
d = FS_OpenVFS ( dest , " wbp " , relativedest ) ;
2009-04-01 22:03:56 +00:00
if ( d )
{
result = true ;
for ( ; ; )
{
read = VFS_READ ( s , buffer , sizeof ( buffer ) ) ;
if ( read < = 0 )
break ;
if ( VFS_WRITE ( d , buffer , read ) ! = read )
{
result = false ;
break ;
}
}
VFS_CLOSE ( d ) ;
if ( ! result )
FS_Remove ( dest , relativedest ) ;
}
VFS_CLOSE ( s ) ;
}
return result ;
}
2005-08-26 22:52:26 +00:00
static qbyte * loadbuf ;
static int loadsize ;
/*
= = = = = = = = = = = =
COM_LoadFile
Filename are reletive to the quake directory .
Always appends a 0 qbyte to the loaded data .
= = = = = = = = = = = =
*/
2014-10-05 20:04:11 +00:00
qbyte * COM_LoadFile ( const char * path , int usehunk , size_t * filesize )
2005-08-26 22:52:26 +00:00
{
2005-12-21 03:07:33 +00:00
vfsfile_t * f ;
2005-08-26 22:52:26 +00:00
qbyte * buf ;
2014-02-07 08:38:40 +00:00
qofs_t len ;
2005-08-26 22:52:26 +00:00
flocation_t loc ;
2015-10-11 11:34:58 +00:00
if ( ! FS_FLocateFile ( path , FSLF_IFFOUND , & loc ) | | ! loc . search )
2005-08-26 22:52:26 +00:00
return NULL ; //wasn't found
2014-02-07 08:38:40 +00:00
if ( loc . len > 0x7fffffff ) //don't malloc 5000gb sparse files or anything crazy on a 32bit system...
return NULL ;
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
f = loc . search - > handle - > OpenVFS ( loc . search - > handle , & loc , " rb " ) ;
2005-12-21 03:07:33 +00:00
if ( ! f )
return NULL ;
2014-10-05 20:04:11 +00:00
len = VFS_GETLEN ( f ) ;
if ( filesize )
* filesize = len ;
if ( usehunk = = 2 | | usehunk = = 4 | | usehunk = = 6 )
COM_AssertMainThread ( " COM_LoadFile+hunk " ) ;
2005-08-26 22:52:26 +00:00
if ( usehunk = = 0 )
buf = ( qbyte * ) Z_Malloc ( len + 1 ) ;
else if ( usehunk = = 2 )
buf = ( qbyte * ) Hunk_TempAlloc ( len + 1 ) ;
else if ( usehunk = = 4 )
{
if ( len + 1 > loadsize )
buf = ( qbyte * ) Hunk_TempAlloc ( len + 1 ) ;
else
buf = loadbuf ;
}
else if ( usehunk = = 5 )
buf = ( qbyte * ) BZ_Malloc ( len + 1 ) ;
else if ( usehunk = = 6 )
buf = ( qbyte * ) Hunk_TempAllocMore ( len + 1 ) ;
else
{
Sys_Error ( " COM_LoadFile: bad usehunk " ) ;
buf = NULL ;
}
if ( ! buf )
Sys_Error ( " COM_LoadFile: not enough space for %s " , path ) ;
( ( qbyte * ) buf ) [ len ] = 0 ;
2005-12-21 03:07:33 +00:00
VFS_READ ( f , buf , len ) ;
VFS_CLOSE ( f ) ;
2005-08-26 22:52:26 +00:00
return buf ;
}
2014-10-05 20:04:11 +00:00
qbyte * FS_LoadMallocFile ( const char * path , size_t * fsize )
2005-08-26 22:52:26 +00:00
{
2014-10-05 20:04:11 +00:00
return COM_LoadFile ( path , 5 , fsize ) ;
2005-08-26 22:52:26 +00:00
}
2014-10-05 20:04:11 +00:00
void * FS_LoadMallocGroupFile ( zonegroup_t * ctx , char * path , size_t * fsize )
2005-08-26 22:52:26 +00:00
{
2013-07-14 12:22:51 +00:00
char * mem = NULL ;
vfsfile_t * f = FS_OpenVFS ( path , " rb " , FS_GAME ) ;
if ( f )
{
int len = VFS_GETLEN ( f ) ;
mem = ZG_Malloc ( ctx , len + 1 ) ;
if ( mem )
{
mem [ len ] = 0 ;
if ( VFS_READ ( f , mem , len ) = = len )
2014-10-05 20:04:11 +00:00
* fsize = len ;
2013-07-14 12:22:51 +00:00
else
mem = NULL ;
}
VFS_CLOSE ( f ) ;
}
return mem ;
2005-08-26 22:52:26 +00:00
}
2014-10-05 20:04:11 +00:00
qbyte * COM_LoadTempFile ( const char * path , size_t * fsize )
2005-08-26 22:52:26 +00:00
{
2014-10-05 20:04:11 +00:00
return COM_LoadFile ( path , 2 , fsize ) ;
2005-08-26 22:52:26 +00:00
}
2014-10-05 20:04:11 +00:00
qbyte * COM_LoadTempMoreFile ( const char * path , size_t * fsize )
2005-08-26 22:52:26 +00:00
{
2014-10-05 20:04:11 +00:00
return COM_LoadFile ( path , 6 , fsize ) ;
2005-08-26 22:52:26 +00:00
}
// uses temp hunk if larger than bufsize
2014-10-05 20:04:11 +00:00
qbyte * QDECL COM_LoadStackFile ( const char * path , void * buffer , int bufsize , size_t * fsize )
2005-08-26 22:52:26 +00:00
{
qbyte * buf ;
2005-11-21 21:09:11 +00:00
2014-10-05 20:04:11 +00:00
COM_AssertMainThread ( " COM_LoadStackFile " ) ;
2005-08-26 22:52:26 +00:00
loadbuf = ( qbyte * ) buffer ;
loadsize = bufsize ;
2014-10-05 20:04:11 +00:00
buf = COM_LoadFile ( path , 4 , fsize ) ;
2005-11-21 21:09:11 +00:00
2005-08-26 22:52:26 +00:00
return buf ;
}
2009-05-24 10:11:17 +00:00
/*warning: at some point I'll change this function to return only read-only buffers*/
2014-03-30 08:55:06 +00:00
qofs_t FS_LoadFile ( const char * name , void * * file )
2009-03-03 01:52:30 +00:00
{
2014-10-05 20:04:11 +00:00
size_t fsz ;
* file = COM_LoadFile ( name , 5 , & fsz ) ;
2009-05-24 10:11:17 +00:00
if ( ! * file )
2014-02-07 08:38:40 +00:00
return ( qofs_t ) - 1 ;
2014-10-05 20:04:11 +00:00
return fsz ;
2009-03-03 01:52:30 +00:00
}
void FS_FreeFile ( void * file )
{
BZ_Free ( file ) ;
}
2015-02-02 08:01:53 +00:00
void COM_EnumerateFiles ( const char * match , int ( QDECL * func ) ( const char * , qofs_t , time_t mtime , void * , searchpathfuncs_t * ) , void * parm )
2005-08-26 22:52:26 +00:00
{
searchpath_t * search ;
for ( search = com_searchpaths ; search ; search = search - > next )
{
// is the element a pak file?
2013-06-23 02:17:02 +00:00
if ( ! search - > handle - > EnumerateFiles ( search - > handle , match , func , parm ) )
2005-08-26 22:52:26 +00:00
break ;
}
}
void COM_FlushTempoaryPacks ( void )
{
2014-06-12 23:08:42 +00:00
#if 0
2011-10-27 16:16:29 +00:00
searchpath_t * sp , * * link ;
link = & com_searchpaths ;
while ( * link )
2005-08-26 22:52:26 +00:00
{
2011-10-27 16:16:29 +00:00
sp = * link ;
2013-06-23 02:17:02 +00:00
if ( sp - > flags & SPF_TEMPORARY )
2011-10-27 16:16:29 +00:00
{
2012-05-09 15:30:53 +00:00
FS_FlushFSHashReally ( ) ;
2011-10-27 16:16:29 +00:00
* link = sp - > next ;
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
sp - > handle - > ClosePath ( sp - > handle ) ;
2011-10-27 16:16:29 +00:00
Z_Free ( sp ) ;
}
else
link = & sp - > next ;
2005-08-26 22:52:26 +00:00
}
2011-10-27 16:16:29 +00:00
com_purepaths = NULL ;
2014-06-12 23:08:42 +00:00
# endif
2005-08-26 22:52:26 +00:00
}
2014-02-07 08:38:40 +00:00
qboolean COM_LoadMapPackFile ( const char * filename , qofs_t ofs )
2005-08-26 22:52:26 +00:00
{
2005-12-21 03:07:33 +00:00
return false ;
2013-06-23 02:17:02 +00:00
}
2005-08-26 22:52:26 +00:00
2016-07-12 00:40:13 +00:00
static searchpath_t * FS_AddPathHandle ( searchpath_t * * oldpaths , const char * purepath , const char * probablepath , searchpathfuncs_t * handle , const char * prefix , unsigned int flags , unsigned int loadstuff ) ;
2013-12-17 22:45:37 +00:00
searchpathfuncs_t * FS_GetOldPath ( searchpath_t * * oldpaths , const char * dir , unsigned int * keepflags )
2013-06-23 02:17:02 +00:00
{
searchpath_t * p ;
searchpathfuncs_t * r = NULL ;
2013-12-17 22:45:37 +00:00
* keepflags = 0 ;
2013-06-23 02:17:02 +00:00
while ( * oldpaths )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
p = * oldpaths ;
2005-08-26 22:52:26 +00:00
2014-02-07 08:38:40 +00:00
if ( ! Q_strcasecmp ( p - > logicalpath , dir ) )
2013-06-23 02:17:02 +00:00
{
2013-12-17 22:45:37 +00:00
* keepflags | = p - > flags & ( SPF_REFERENCED | SPF_UNTRUSTED ) ;
2013-06-23 02:17:02 +00:00
* oldpaths = p - > next ;
r = p - > handle ;
Z_Free ( p ) ;
break ;
}
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
oldpaths = & ( * oldpaths ) - > next ;
2005-08-26 22:52:26 +00:00
}
2013-06-23 02:17:02 +00:00
return r ;
2005-08-26 22:52:26 +00:00
}
2005-12-21 03:07:33 +00:00
typedef struct {
2016-07-12 00:40:13 +00:00
searchpathfuncs_t * ( QDECL * OpenNew ) ( vfsfile_t * file , const char * desc , const char * prefix ) ;
2013-06-23 02:17:02 +00:00
searchpath_t * * oldpaths ;
2009-04-01 22:03:56 +00:00
const char * parentdesc ;
const char * puredesc ;
2016-07-12 00:40:13 +00:00
unsigned int inheritflags ;
2005-12-21 03:07:33 +00:00
} wildpaks_t ;
2015-02-02 08:01:53 +00:00
static int QDECL FS_AddWildDataFiles ( const char * descriptor , qofs_t size , time_t mtime , void * vparam , searchpathfuncs_t * funcs )
2005-08-26 22:52:26 +00:00
{
2005-12-21 03:07:33 +00:00
wildpaks_t * param = vparam ;
vfsfile_t * vfs ;
2005-08-26 22:52:26 +00:00
searchpath_t * search ;
2013-06-23 02:17:02 +00:00
searchpathfuncs_t * newpak ;
2005-08-26 22:52:26 +00:00
char pakfile [ MAX_OSPATH ] ;
2008-11-09 22:29:28 +00:00
char purefile [ MAX_OSPATH ] ;
2005-12-21 03:07:33 +00:00
flocation_t loc ;
2013-12-17 22:45:37 +00:00
unsigned int keptflags = 0 ;
2005-08-26 22:52:26 +00:00
2011-07-22 15:11:35 +00:00
Q_snprintfz ( pakfile , sizeof ( pakfile ) , " %s%s " , param - > parentdesc , descriptor ) ;
2005-08-26 22:52:26 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
{
2014-02-07 08:38:40 +00:00
if ( ! Q_strcasecmp ( search - > logicalpath , pakfile ) ) //assumption: first member of structure is a char array
2005-08-26 22:52:26 +00:00
return true ; //already loaded (base paths?)
}
2013-12-17 22:45:37 +00:00
newpak = FS_GetOldPath ( param - > oldpaths , pakfile , & keptflags ) ;
2013-06-23 02:17:02 +00:00
if ( ! newpak )
2012-07-05 19:42:36 +00:00
{
2013-10-29 17:38:22 +00:00
if ( param - > OpenNew = = VFSOS_OpenPath )
{
vfs = NULL ;
}
else
{
fs_finds + + ;
if ( ! funcs - > FindFile ( funcs , & loc , descriptor , NULL ) )
return true ; //not found..
vfs = funcs - > OpenVFS ( funcs , & loc , " rb " ) ;
if ( ! vfs )
return true ;
}
2016-07-12 00:40:13 +00:00
newpak = param - > OpenNew ( vfs , pakfile , " " ) ;
2013-06-23 02:17:02 +00:00
if ( ! newpak )
{
VFS_CLOSE ( vfs ) ;
return true ;
}
2012-07-05 19:42:36 +00:00
}
2005-12-21 03:07:33 +00:00
2013-06-23 02:17:02 +00:00
Q_snprintfz ( pakfile , sizeof ( pakfile ) , " %s%s " , param - > parentdesc , descriptor ) ;
2008-11-09 22:29:28 +00:00
if ( * param - > puredesc )
snprintf ( purefile , sizeof ( purefile ) , " %s/%s " , param - > puredesc , descriptor ) ;
else
Q_strncpyz ( purefile , descriptor , sizeof ( purefile ) ) ;
2016-07-12 00:40:13 +00:00
FS_AddPathHandle ( param - > oldpaths , purefile , pakfile , newpak , " " , ( ( ! Q_strncasecmp ( descriptor , " pak " , 3 ) ) ? SPF_COPYPROTECTED : 0 ) | keptflags | param - > inheritflags , ( unsigned int ) - 1 ) ;
2005-08-26 22:52:26 +00:00
return true ;
}
2014-03-30 08:55:06 +00:00
searchpathfuncs_t * FS_OpenPackByExtension ( vfsfile_t * f , const char * pakname )
{
searchpathfuncs_t * pak ;
int j ;
2014-10-05 20:04:11 +00:00
char ext [ 8 ] ;
COM_FileExtension ( pakname , ext , sizeof ( ext ) ) ;
2014-03-30 08:55:06 +00:00
for ( j = 0 ; j < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; j + + )
{
if ( ! searchpathformats [ j ] . extension | | ! searchpathformats [ j ] . OpenNew )
continue ;
if ( ! strcmp ( ext , searchpathformats [ j ] . extension ) )
{
2016-07-12 00:40:13 +00:00
pak = searchpathformats [ j ] . OpenNew ( f , pakname , " " ) ;
2014-03-30 08:55:06 +00:00
if ( pak )
return pak ;
Con_Printf ( " Unable to open %s - corrupt? \n " , pakname ) ;
break ;
}
}
VFS_CLOSE ( f ) ;
return NULL ;
}
2005-12-21 03:07:33 +00:00
2016-08-25 00:12:14 +00:00
//
void FS_AddHashedPackage ( searchpath_t * * oldpaths , const char * parentpath , const char * logicalpaths , searchpath_t * search , unsigned int loadstuff , const char * pakpath , const char * qhash , const char * pakprefix )
2015-05-14 03:06:58 +00:00
{
searchpathfuncs_t * handle ;
2016-08-25 00:12:14 +00:00
searchpath_t * oldp ;
char pname [ MAX_OSPATH ] ;
char lname [ MAX_OSPATH ] ;
char lname2 [ MAX_OSPATH ] ;
2015-05-14 03:06:58 +00:00
unsigned int keptflags ;
flocation_t loc ;
2016-08-25 00:12:14 +00:00
int fmt ;
char ext [ 8 ] ;
int ptlen = strlen ( parentpath ) ;
COM_FileExtension ( pakpath , ext , sizeof ( ext ) ) ;
//figure out which file format its meant to be.
for ( fmt = 0 ; fmt < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; fmt + + )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
if ( ! searchpathformats [ fmt ] . extension | | ! searchpathformats [ fmt ] . OpenNew ) // || !searchpathformats[i].loadscan)
continue ;
if ( ( loadstuff & ( 1 < < fmt ) ) & & ! Q_strcasecmp ( ext , searchpathformats [ fmt ] . extension ) )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
//figure out the logical path names
if ( ! FS_GenCachedPakName ( pakpath , qhash , pname , sizeof ( pname ) ) )
return ; //file name was invalid, panic.
snprintf ( lname , sizeof ( lname ) , " %s%s " , logicalpaths , pname + ptlen + 1 ) ;
snprintf ( lname2 , sizeof ( lname ) , " %s%s " , logicalpaths , pakpath + ptlen + 1 ) ;
//see if we already added it
for ( oldp = com_searchpaths ; oldp ; oldp = oldp - > next )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
if ( strcmp ( oldp - > prefix , pakprefix ? pakprefix : " " ) ) //probably will only happen from typos, but should be correct.
2015-05-14 03:06:58 +00:00
continue ;
2016-08-25 00:12:14 +00:00
if ( ! Q_strcasecmp ( oldp - > purepath , pakpath ) )
break ;
if ( ! Q_strcasecmp ( oldp - > logicalpath , lname ) )
break ;
if ( ! Q_strcasecmp ( oldp - > logicalpath , lname2 ) )
break ;
}
if ( ! oldp )
{
//see if we can get an old archive handle from before whatever fs_restart
handle = FS_GetOldPath ( oldpaths , lname2 , & keptflags ) ;
if ( handle )
snprintf ( lname , sizeof ( lname ) , " %s " , lname2 ) ;
else
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
handle = FS_GetOldPath ( oldpaths , lname , & keptflags ) ;
2016-07-16 13:21:23 +00:00
2016-08-25 00:12:14 +00:00
//seems new, load it.
if ( ! handle )
{
vfsfile_t * vfs = NULL ;
if ( search )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
if ( search - > handle - > FindFile ( search - > handle , & loc , pakpath + ptlen + 1 , NULL ) )
2016-07-16 13:21:23 +00:00
{
2016-08-25 00:12:14 +00:00
vfs = search - > handle - > OpenVFS ( search - > handle , & loc , " r " ) ;
snprintf ( lname , sizeof ( lname ) , " %s " , lname2 ) ;
2016-07-16 13:21:23 +00:00
}
2016-08-25 00:12:14 +00:00
else if ( search - > handle - > FindFile ( search - > handle , & loc , pname + ptlen + 1 , NULL ) )
vfs = search - > handle - > OpenVFS ( search - > handle , & loc , " r " ) ;
}
else
{
vfs = FS_OpenVFS ( pakpath , " rb " , FS_ROOT ) ;
2016-07-16 13:21:23 +00:00
if ( vfs )
2016-08-25 00:12:14 +00:00
snprintf ( lname , sizeof ( lname ) , " %s " , lname2 ) ;
else
vfs = FS_OpenVFS ( pname , " rb " , FS_ROOT ) ;
2016-07-16 13:21:23 +00:00
}
2016-08-25 00:12:14 +00:00
if ( vfs )
handle = searchpathformats [ fmt ] . OpenNew ( vfs , lname , pakprefix ? pakprefix : " " ) ;
if ( ! handle & & vfs )
VFS_CLOSE ( vfs ) ; //erk
2015-05-14 03:06:58 +00:00
}
2016-08-25 00:12:14 +00:00
}
//insert it into our path lists.
if ( handle & & qhash )
{
int truecrc = handle - > GeneratePureCRC ( handle , 0 , false ) ;
if ( truecrc ! = ( int ) strtoul ( qhash , NULL , 0 ) )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
Con_Printf ( CON_ERROR " File \" %s \" has hash %#x (required: %s). Please delete it or move it away \n " , lname , truecrc , qhash ) ;
handle - > ClosePath ( handle ) ;
handle = NULL ;
2015-05-14 03:06:58 +00:00
}
}
2016-08-25 00:12:14 +00:00
if ( handle )
FS_AddPathHandle ( oldpaths , pakpath , lname , handle , pakprefix , SPF_COPYPROTECTED | SPF_UNTRUSTED | keptflags , ( unsigned int ) - 1 ) ;
2015-05-14 03:06:58 +00:00
}
2016-08-25 00:12:14 +00:00
return ;
2015-05-14 03:06:58 +00:00
}
}
}
2016-08-25 00:12:14 +00:00
static void FS_AddManifestPackages ( searchpath_t * * oldpaths , const char * purepath , const char * logicalpaths , searchpath_t * search , unsigned int loadstuff )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
int i ;
int ptlen , palen ;
ptlen = strlen ( purepath ) ;
for ( i = 0 ; i < sizeof ( fs_manifest - > package ) / sizeof ( fs_manifest - > package [ 0 ] ) ; i + + )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
char qhash [ 16 ] ;
if ( ! fs_manifest - > package [ i ] . path )
2015-05-14 03:06:58 +00:00
continue ;
2016-08-25 00:12:14 +00:00
palen = strlen ( fs_manifest - > package [ i ] . path ) ;
if ( palen > ptlen & & ( fs_manifest - > package [ i ] . path [ ptlen ] = = ' / ' | | fs_manifest - > package [ i ] . path [ ptlen ] = = ' \\ ' ) & & ! strncmp ( purepath , fs_manifest - > package [ i ] . path , ptlen ) )
2015-05-14 03:06:58 +00:00
{
2016-08-25 00:12:14 +00:00
Q_snprintfz ( qhash , sizeof ( qhash ) , " %#x " , fs_manifest - > package [ i ] . crc ) ;
FS_AddHashedPackage ( oldpaths , purepath , logicalpaths , search , loadstuff , fs_manifest - > package [ i ] . path , fs_manifest - > package [ i ] . crcknown ? qhash : NULL , fs_manifest - > package [ i ] . prefix ) ;
2015-05-14 03:06:58 +00:00
}
}
}
2016-08-25 00:12:14 +00:00
static void FS_AddDownloadManifestPackages ( searchpath_t * * oldpaths , unsigned int loadstuff ) //, const char *purepath, searchpath_t *search, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc))
{
char logicalroot [ MAX_OSPATH ] ;
FS_NativePath ( " downloads/ " , FS_ROOT , logicalroot , sizeof ( logicalroot ) ) ;
FS_AddManifestPackages ( oldpaths , " downloads " , logicalroot , NULL , loadstuff ) ;
}
2016-07-12 00:40:13 +00:00
static void FS_AddDataFiles ( searchpath_t * * oldpaths , const char * purepath , const char * logicalpath , searchpath_t * search , unsigned int pflags , unsigned int loadstuff )
2005-08-26 22:52:26 +00:00
{
2005-12-21 03:07:33 +00:00
//search is the parent
2016-07-12 00:40:13 +00:00
int i , j ;
2016-07-16 13:21:23 +00:00
searchpath_t * existing ;
2013-06-23 02:17:02 +00:00
searchpathfuncs_t * handle ;
2005-08-26 22:52:26 +00:00
char pakfile [ MAX_OSPATH ] ;
2013-06-23 02:17:02 +00:00
char logicalpaths [ MAX_OSPATH ] ; //with a slash
2008-11-09 22:29:28 +00:00
char purefile [ MAX_OSPATH ] ;
2013-12-17 22:45:37 +00:00
unsigned int keptflags ;
2005-12-21 03:07:33 +00:00
vfsfile_t * vfs ;
flocation_t loc ;
wildpaks_t wp ;
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
Q_strncpyz ( logicalpaths , logicalpath , sizeof ( logicalpaths ) ) ;
FS_CleanDir ( logicalpaths , sizeof ( logicalpaths ) ) ;
2016-07-12 00:40:13 +00:00
wp . parentdesc = logicalpaths ;
wp . puredesc = purepath ;
wp . oldpaths = oldpaths ;
wp . inheritflags = pflags ;
2013-06-23 02:17:02 +00:00
2016-07-12 00:40:13 +00:00
//read pak.lst to get some sort of official ordering of pak files
if ( search - > handle - > FindFile ( search - > handle , & loc , " pak.lst " , NULL ) = = FF_FOUND )
{
char filename [ MAX_QPATH ] ;
char * buffer = BZ_Malloc ( loc . len + 1 ) ;
char * names = buffer ;
search - > handle - > ReadFile ( search - > handle , & loc , buffer ) ;
buffer [ loc . len ] = 0 ;
while ( names & & * names )
2013-06-23 02:17:02 +00:00
{
2016-07-12 00:40:13 +00:00
names = COM_ParseOut ( names , filename , sizeof ( filename ) ) ;
if ( * filename )
{
char extension [ MAX_QPATH ] ;
COM_FileExtension ( filename , extension , sizeof ( extension ) ) ;
//I dislike that this is tied to extensions, but whatever.
for ( j = 0 ; j < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; j + + )
{
if ( ! searchpathformats [ j ] . extension | | ! searchpathformats [ j ] . OpenNew | | ! searchpathformats [ j ] . loadscan )
continue ;
if ( ! stricmp ( extension , searchpathformats [ j ] . extension ) )
{
if ( loadstuff & ( 1 < < j ) )
{
wp . OpenNew = searchpathformats [ j ] . OpenNew ;
FS_AddWildDataFiles ( filename , 0 , 0 , & wp , search - > handle ) ;
}
break ;
}
}
}
2013-06-23 02:17:02 +00:00
}
2016-07-12 00:40:13 +00:00
BZ_Free ( buffer ) ;
2005-08-26 22:52:26 +00:00
}
2016-08-25 00:12:14 +00:00
PM_LoadPackages ( oldpaths , purepath , logicalpaths , search , loadstuff , 0x80000000 , - 1 ) ;
2016-07-16 13:21:23 +00:00
for ( j = 0 ; j < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; j + + )
{
if ( ! searchpathformats [ j ] . extension | | ! searchpathformats [ j ] . OpenNew | | ! searchpathformats [ j ] . loadscan )
continue ;
if ( loadstuff & ( 1 < < j ) )
{
const char * extension = searchpathformats [ j ] . extension ;
//first load all the numbered pak files
for ( i = 0 ; ; i + + )
{
snprintf ( pakfile , sizeof ( pakfile ) , " pak%i.%s " , i , extension ) ;
fs_finds + + ;
if ( ! search - > handle - > FindFile ( search - > handle , & loc , pakfile , NULL ) )
break ; //not found..
snprintf ( pakfile , sizeof ( pakfile ) , " %spak%i.%s " , logicalpaths , i , extension ) ;
snprintf ( purefile , sizeof ( purefile ) , " %s/pak%i.%s " , purepath , i , extension ) ;
for ( existing = com_searchpaths ; existing ; existing = existing - > next )
{
if ( ! Q_strcasecmp ( existing - > logicalpath , pakfile ) ) //assumption: first member of structure is a char array
break ; //already loaded (base paths?)
}
if ( ! existing )
{
handle = FS_GetOldPath ( oldpaths , pakfile , & keptflags ) ;
if ( ! handle )
{
vfs = search - > handle - > OpenVFS ( search - > handle , & loc , " r " ) ;
if ( ! vfs )
break ;
handle = searchpathformats [ j ] . OpenNew ( vfs , pakfile , " " ) ;
if ( ! handle )
break ;
}
FS_AddPathHandle ( oldpaths , purefile , pakfile , handle , " " , SPF_COPYPROTECTED | pflags | keptflags , ( unsigned int ) - 1 ) ;
}
}
}
}
//now load ones from the manifest
2016-08-25 00:12:14 +00:00
FS_AddManifestPackages ( oldpaths , purepath , logicalpaths , search , loadstuff ) ;
2016-07-16 13:21:23 +00:00
2016-08-25 00:12:14 +00:00
PM_LoadPackages ( oldpaths , purepath , logicalpaths , search , loadstuff , 0x0 , 1000 - 1 ) ;
2016-07-16 13:21:23 +00:00
2008-11-09 22:29:28 +00:00
//now load the random ones
2016-07-12 00:40:13 +00:00
for ( j = 0 ; j < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; j + + )
{
if ( ! searchpathformats [ j ] . extension | | ! searchpathformats [ j ] . OpenNew | | ! searchpathformats [ j ] . loadscan )
continue ;
if ( loadstuff & ( 1 < < j ) )
{
const char * extension = searchpathformats [ j ] . extension ;
wp . OpenNew = searchpathformats [ j ] . OpenNew ;
2016-07-16 13:21:23 +00:00
2016-07-12 00:40:13 +00:00
Q_snprintfz ( pakfile , sizeof ( pakfile ) , " *.%s " , extension ) ;
search - > handle - > EnumerateFiles ( search - > handle , pakfile , FS_AddWildDataFiles , & wp ) ;
}
}
2016-08-25 00:12:14 +00:00
PM_LoadPackages ( oldpaths , purepath , logicalpaths , search , loadstuff , 1000 , 0x7fffffff ) ;
2009-04-01 22:03:56 +00:00
}
2016-07-12 00:40:13 +00:00
static searchpath_t * FS_AddPathHandle ( searchpath_t * * oldpaths , const char * purepath , const char * logicalpath , searchpathfuncs_t * handle , const char * prefix , unsigned int flags , unsigned int loadstuff )
2009-04-01 22:03:56 +00:00
{
2011-10-27 16:16:29 +00:00
searchpath_t * search , * * link ;
2009-04-01 22:03:56 +00:00
2013-06-23 02:17:02 +00:00
if ( ! handle )
{
Con_Printf ( " COM_AddPathHandle: not a valid handle (%s) \n " , logicalpath ) ;
return NULL ;
}
if ( handle - > fsver ! = FSVER )
2009-04-01 22:03:56 +00:00
{
2013-06-23 02:17:02 +00:00
Con_Printf ( " %s: file system driver is outdated (%u should be %u) \n " , logicalpath , handle - > fsver , FSVER ) ;
handle - > ClosePath ( handle ) ;
2009-04-01 22:03:56 +00:00
return NULL ;
}
search = ( searchpath_t * ) Z_Malloc ( sizeof ( searchpath_t ) ) ;
2013-06-23 02:17:02 +00:00
search - > flags = flags ;
2009-04-01 22:03:56 +00:00
search - > handle = handle ;
2013-06-23 02:17:02 +00:00
Q_strncpyz ( search - > purepath , purepath , sizeof ( search - > purepath ) ) ;
Q_strncpyz ( search - > logicalpath , logicalpath , sizeof ( search - > logicalpath ) ) ;
2016-07-12 00:40:13 +00:00
if ( prefix )
Q_strncpyz ( search - > prefix , prefix , sizeof ( search - > prefix ) ) ;
2009-04-01 22:03:56 +00:00
2015-06-14 01:28:01 +00:00
flags & = ~ SPF_WRITABLE ;
2013-03-12 22:35:33 +00:00
//temp packages also do not nest
2016-07-12 00:40:13 +00:00
// if (!(flags & SPF_TEMPORARY))
FS_AddDataFiles ( oldpaths , purepath , logicalpath , search , flags & ( SPF_COPYPROTECTED | SPF_UNTRUSTED | SPF_TEMPORARY | SPF_PRIVATE ) , loadstuff ) ;
2013-03-12 22:35:33 +00:00
2013-06-23 02:17:02 +00:00
if ( flags & SPF_TEMPORARY )
2011-10-27 16:16:29 +00:00
{
//add at end. pureness will reorder if needed.
link = & com_searchpaths ;
while ( * link )
{
link = & ( * link ) - > next ;
}
* link = search ;
}
else
{
search - > next = com_searchpaths ;
com_searchpaths = search ;
}
2009-04-01 22:03:56 +00:00
com_fschanged = true ;
return search ;
2005-08-26 22:52:26 +00:00
}
2017-02-19 00:15:42 +00:00
static void COM_RefreshFSCache_f ( void )
2005-08-26 22:52:26 +00:00
{
com_fschanged = true ;
}
2014-10-05 20:04:11 +00:00
//optionally purges the cache and rebuilds it
void COM_FlushFSCache ( qboolean purge , qboolean domutex )
2005-08-26 22:52:26 +00:00
{
2012-05-09 15:30:53 +00:00
searchpath_t * search ;
2013-10-29 17:38:22 +00:00
if ( com_fs_cache . ival & & com_fs_cache . ival ! = 2 )
2012-05-09 15:30:53 +00:00
{
for ( search = com_searchpaths ; search ; search = search - > next )
{
2013-06-23 02:17:02 +00:00
if ( search - > handle - > PollChanges )
com_fschanged | = search - > handle - > PollChanges ( search - > handle ) ;
2012-05-09 15:30:53 +00:00
}
}
2014-02-07 08:38:40 +00:00
2014-08-27 08:41:31 +00:00
# ifdef FTE_TARGET_WEB
//web target doesn't support filesystem enumeration, so make sure the cache is kept invalid and disabled.
com_fschanged = true ;
# else
if ( com_fs_cache . ival & & com_fschanged )
2014-04-03 02:16:21 +00:00
{
//rebuild it if needed
2014-10-05 20:04:11 +00:00
FS_RebuildFSHash ( domutex ) ;
2014-04-03 02:16:21 +00:00
}
2014-08-27 08:41:31 +00:00
# endif
2005-08-26 22:52:26 +00:00
}
2010-07-11 02:22:39 +00:00
/*since should start as 0, otherwise this can be used to poll*/
qboolean FS_Restarted ( unsigned int * since )
{
if ( * since < fs_restarts )
{
* since = fs_restarts ;
return true ;
}
return false ;
}
2005-08-26 22:52:26 +00:00
/*
= = = = = = = = = = = = = = = =
2009-04-01 22:03:56 +00:00
FS_AddGameDirectory
2005-08-26 22:52:26 +00:00
Sets com_gamedir , adds the directory to the head of the path ,
2005-11-21 21:09:11 +00:00
then loads and adds pak1 . pak pak2 . pak . . .
2005-08-26 22:52:26 +00:00
= = = = = = = = = = = = = = = =
*/
2014-03-30 08:55:06 +00:00
void FS_AddGameDirectory ( searchpath_t * * oldpaths , const char * puredir , const char * dir , unsigned int loadstuff , unsigned int flags )
2005-08-26 22:52:26 +00:00
{
2013-12-17 22:45:37 +00:00
unsigned int keptflags ;
2005-08-26 22:52:26 +00:00
searchpath_t * search ;
char * p ;
2012-05-09 15:30:53 +00:00
void * handle ;
2005-08-26 22:52:26 +00:00
2010-07-11 02:22:39 +00:00
fs_restarts + + ;
2005-08-26 22:52:26 +00:00
for ( search = com_searchpaths ; search ; search = search - > next )
{
2014-02-07 08:38:40 +00:00
if ( ! Q_strcasecmp ( search - > logicalpath , dir ) )
2016-08-25 00:12:14 +00:00
{
search - > flags | = flags & SPF_WRITABLE ;
2005-08-26 22:52:26 +00:00
return ; //already loaded (base paths?)
2016-08-25 00:12:14 +00:00
}
2005-08-26 22:52:26 +00:00
}
2014-03-30 08:55:06 +00:00
if ( ! ( flags & SPF_PRIVATE ) )
{
if ( ( p = strrchr ( dir , ' / ' ) ) ! = NULL )
2016-08-25 00:12:14 +00:00
Q_strncpyz ( pubgamedirfile , + + p , sizeof ( pubgamedirfile ) ) ;
2014-03-30 08:55:06 +00:00
else
2016-08-25 00:12:14 +00:00
Q_strncpyz ( pubgamedirfile , dir , sizeof ( pubgamedirfile ) ) ;
2014-03-30 08:55:06 +00:00
}
if ( ( p = strrchr ( dir , ' / ' ) ) ! = NULL )
2016-08-25 00:12:14 +00:00
Q_strncpyz ( gamedirfile , + + p , sizeof ( gamedirfile ) ) ;
2014-03-30 08:55:06 +00:00
else
2016-08-25 00:12:14 +00:00
Q_strncpyz ( gamedirfile , dir , sizeof ( gamedirfile ) ) ;
2014-03-30 08:55:06 +00:00
2005-08-26 22:52:26 +00:00
//
// add the directory to the search path
//
2013-12-17 22:45:37 +00:00
handle = FS_GetOldPath ( oldpaths , dir , & keptflags ) ;
2013-06-23 02:17:02 +00:00
if ( ! handle )
2016-07-12 00:40:13 +00:00
handle = VFSOS_OpenPath ( NULL , dir , " " ) ;
2005-10-31 00:52:03 +00:00
2016-07-12 00:40:13 +00:00
FS_AddPathHandle ( oldpaths , puredir , dir , handle , " " , flags | keptflags , loadstuff ) ;
2005-08-26 22:52:26 +00:00
}
2014-09-20 04:11:39 +00:00
//if syspath, something like c:\quake\baseq2
//otherwise just baseq2. beware of dupes.
searchpathfuncs_t * COM_IteratePaths ( void * * iterator , char * pathbuffer , int pathbuffersize , char * dirname , int dirnamesize )
2005-08-26 22:52:26 +00:00
{
searchpath_t * s ;
2013-06-23 02:17:02 +00:00
void * prev ;
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
prev = NULL ;
2005-08-26 22:52:26 +00:00
for ( s = com_searchpaths ; s ; s = s - > next )
{
2013-06-23 02:17:02 +00:00
if ( ! ( s - > flags & SPF_EXPLICIT ) )
2005-08-26 22:52:26 +00:00
continue ;
2013-06-23 02:17:02 +00:00
if ( * iterator = = prev )
{
* iterator = s - > handle ;
2014-09-20 04:11:39 +00:00
if ( ! strchr ( s - > purepath , ' / ' ) )
{
if ( pathbuffer )
{
Q_strncpyz ( pathbuffer , s - > logicalpath , pathbuffersize - 1 ) ;
FS_CleanDir ( pathbuffer , pathbuffersize ) ;
}
if ( dirname )
{
Q_strncpyz ( dirname , s - > purepath , dirnamesize - 1 ) ;
}
return s - > handle ;
}
2013-06-23 02:17:02 +00:00
}
prev = s - > handle ;
2005-08-26 22:52:26 +00:00
}
2013-06-23 02:17:02 +00:00
* iterator = NULL ;
2014-09-20 04:11:39 +00:00
if ( pathbuffer )
* pathbuffer = 0 ;
if ( dirname )
* dirname = 0 ;
2005-08-26 22:52:26 +00:00
return NULL ;
}
2014-03-30 08:55:06 +00:00
char * FS_GetGamedir ( qboolean publicpathonly )
2005-08-26 22:52:26 +00:00
{
2014-03-30 08:55:06 +00:00
if ( publicpathonly )
return pubgamedirfile ;
else
return gamedirfile ;
}
//returns the commandline arguments required to duplicate the fs details
char * FS_GetManifestArgs ( void )
{
2014-09-02 02:44:43 +00:00
char * homearg = com_homepathenabled ? " -usehome " : " -nohome " ;
2014-03-30 08:55:06 +00:00
if ( fs_manifest - > updatefile )
2016-07-12 00:40:13 +00:00
return va ( " %s-manifest %s -basedir %s " , homearg , fs_manifest - > updatefile , com_gamepath ) ;
2014-03-30 08:55:06 +00:00
2016-07-12 00:40:13 +00:00
return va ( " %s-game %s -basedir %s " , homearg , pubgamedirfile , com_gamepath ) ;
}
int FS_GetManifestArgv ( char * * argv , int maxargs )
{
int c = 0 ;
if ( maxargs < 5 )
return c ;
argv [ c + + ] = com_homepathenabled ? " -usehome " : " -nohome " ;
if ( fs_manifest - > updatefile )
{
argv [ c + + ] = " -manifest " ;
argv [ c + + ] = fs_manifest - > updatefile ;
}
else
{
argv [ c + + ] = " -game " ;
argv [ c + + ] = pubgamedirfile ;
}
argv [ c + + ] = " -basedir " ;
argv [ c + + ] = com_gamepath ;
return c ;
2009-04-01 22:03:56 +00:00
}
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
2013-06-23 02:17:02 +00:00
//given a 'c:/foo/bar/' path, will extract 'bar'.
void FS_ExtractDir ( char * in , char * out , int outlen )
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
{
char * end ;
if ( ! outlen )
return ;
end = in + strlen ( in ) ;
//skip over any trailing slashes
while ( end > in )
{
if ( end [ - 1 ] = = ' / ' | | end [ - 1 ] = = ' \\ ' )
end - - ;
else
break ;
}
//skip over the path
while ( end > in )
{
if ( end [ - 1 ] ! = ' / ' & & end [ - 1 ] ! = ' \\ ' )
end - - ;
else
break ;
}
//copy string into the dest
while ( - - outlen )
{
if ( * end = = ' / ' | | * end = = ' \\ ' | | ! * end )
break ;
* out + + = * end + + ;
}
* out = 0 ;
}
2013-06-23 02:17:02 +00:00
2015-05-14 03:06:58 +00:00
qboolean FS_PathURLCache ( const char * url , char * path , size_t pathsize )
{
const char * FS_GetCleanPath ( const char * pattern , char * outbuf , int outlen ) ;
char tmp [ MAX_QPATH ] ;
2016-02-15 06:01:17 +00:00
char * o = tmp ;
2015-05-14 03:06:58 +00:00
const char * i = url ;
strcpy ( o , " downloads/ " ) ;
o + = strlen ( o ) ;
while ( * i )
{
if ( * i = = ' : ' | | * i = = ' ? ' | | * i = = ' * ' | | * i = = ' & ' )
{
if ( i [ 0 ] = = ' : ' & & i [ 1 ] = = ' / ' & & i [ 2 ] = = ' / ' )
{
i + = 2 ;
continue ;
}
* o + + = ' _ ' ;
i + + ;
continue ;
}
if ( * i = = ' \\ ' )
{
* o + + = ' / ' ;
i + + ;
continue ;
}
* o + + = * i + + ;
}
* o = 0 ;
if ( ! FS_GetCleanPath ( tmp , path , pathsize ) )
return false ;
return true ;
}
2005-08-26 22:52:26 +00:00
/*
= = = = = = = = = = = = = = = =
COM_Gamedir
Sets the gamedir and path to a different directory .
= = = = = = = = = = = = = = = =
*/
2015-05-14 03:06:58 +00:00
void COM_Gamedir ( const char * dir , const struct gamepacks * packagespaths )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
ftemanifest_t * man ;
if ( ! fs_manifest )
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( NULL , true , false ) ;
2013-06-23 02:17:02 +00:00
2013-11-29 14:36:47 +00:00
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
2015-05-14 03:06:58 +00:00
if ( * dir = = ' . ' | | ! strcmp ( dir , " . " ) | | strstr ( dir , " .. " ) | | strstr ( dir , " / " )
2016-08-25 00:12:14 +00:00
| | strstr ( dir , " \\ " ) | | strstr ( dir , " : " ) | | strstr ( dir , " \" " ) )
2013-11-29 14:36:47 +00:00
{
Con_Printf ( " Gamedir should be a single filename, not a path \n " ) ;
return ;
}
2014-10-29 05:03:03 +00:00
man = NULL ;
if ( ! man )
2013-06-23 02:17:02 +00:00
{
2015-05-14 03:06:58 +00:00
vfsfile_t * f = * dir ? VFSOS_Open ( va ( " %s%s.fmf " , com_gamepath , dir ) , " rb " ) : NULL ;
2014-10-29 05:03:03 +00:00
if ( f )
2013-06-23 02:17:02 +00:00
{
2014-10-29 05:03:03 +00:00
size_t len = VFS_GETLEN ( f ) ;
char * fdata = BZ_Malloc ( len + 1 ) ;
if ( fdata )
{
VFS_READ ( f , fdata , len ) ;
fdata [ len ] = 0 ;
man = FS_Manifest_Parse ( NULL , fdata ) ;
BZ_Free ( fdata ) ;
}
VFS_CLOSE ( f ) ;
}
}
2013-06-23 02:17:02 +00:00
2014-10-29 05:03:03 +00:00
if ( ! man )
{
//generate a new manifest based upon the current one.
man = FS_ReadDefaultManifest ( com_gamepath , sizeof ( com_gamepath ) , true ) ;
if ( man & & strcmp ( man - > installation , fs_manifest - > installation ) )
{
FS_Manifest_Free ( man ) ;
man = NULL ;
}
if ( ! man )
man = FS_Manifest_Clone ( fs_manifest ) ;
FS_Manifest_PurgeGamedirs ( man ) ;
if ( * dir )
{
2015-05-14 03:06:58 +00:00
char token [ MAX_QPATH ] , quot [ MAX_QPATH ] ;
2014-10-29 05:03:03 +00:00
char * dup = Z_StrDup ( dir ) ; //FIXME: is this really needed?
dir = dup ;
while ( ( dir = COM_ParseStringSet ( dir , token , sizeof ( token ) ) ) )
{
if ( ! strcmp ( dir , " ; " ) )
continue ;
if ( ! * token )
continue ;
2015-05-14 03:06:58 +00:00
Cmd_TokenizeString ( va ( " gamedir %s " , COM_QuotedString ( token , quot , sizeof ( quot ) , false ) ) , false , false ) ;
2014-10-29 05:03:03 +00:00
FS_Manifest_ParseTokens ( man ) ;
}
Z_Free ( dup ) ;
2013-06-23 02:17:02 +00:00
}
2015-05-14 03:06:58 +00:00
while ( packagespaths & & packagespaths - > path )
{
char quot [ MAX_QPATH ] ;
char quot2 [ MAX_OSPATH ] ;
2016-07-12 00:40:13 +00:00
char quot3 [ MAX_OSPATH ] ;
Cmd_TokenizeString ( va ( " package %s prefix %s %s " , COM_QuotedString ( packagespaths - > path , quot , sizeof ( quot ) , false ) , COM_QuotedString ( packagespaths - > subpath ? packagespaths - > subpath : " " , quot3 , sizeof ( quot3 ) , false ) , COM_QuotedString ( packagespaths - > url , quot2 , sizeof ( quot2 ) , false ) ) , false , false ) ;
2015-05-14 03:06:58 +00:00
FS_Manifest_ParseTokens ( man ) ;
packagespaths + + ;
}
2013-06-23 02:17:02 +00:00
}
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( man , cfg_reload_on_gamedir . ival , false ) ;
2005-08-26 22:52:26 +00:00
}
2016-12-09 09:09:12 +00:00
# ifdef NOLEGACY
# define ZFIXHACK
# elif defined(ANDROID) //on android, these numbers seem to be generating major weirdness, so disable these.
# define ZFIXHACK
# elif defined(FTE_TARGET_WEB) //on firefox (but not chrome or ie), these numbers seem to be generating major weirdness, so tone them down significantly by default.
# define ZFIXHACK "r_polygonoffset_submodel_offset 1\nr_polygonoffset_submodel_factor 0.05\n"
# else //many quake maps have hideous z-fighting. this provides a way to work around it, although the exact numbers are gpu and bitdepth dependant, and trying to fix it can actually break other things.
# define ZFIXHACK "r_polygonoffset_submodel_offset 25\nr_polygonoffset_submodel_factor 0.05\n"
# endif
2016-01-18 05:22:07 +00:00
/*quake requires a few settings for compatibility*/
2016-12-09 09:09:12 +00:00
# define EZQUAKECOMPETITIVE "set ruleset_allow_fbmodels 1\n"
# define QCFG "set com_parseutf8 0\nset allow_download_refpackages 0\nset sv_bigcoords \"\"\nmap_autoopenportals 1\n" "sv_port "STRINGIFY(PORT_QWSERVER)" "STRINGIFY(PORT_NQSERVER)"\n" ZFIXHACK EZQUAKECOMPETITIVE
2011-06-29 18:39:11 +00:00
/*stuff that makes dp-only mods work a bit better*/
2014-04-24 01:53:01 +00:00
# define DPCOMPAT QCFG "set _cl_playermodel \"\"\n set dpcompat_set 1\nset dpcompat_corruptglobals 1\nset vid_pixelheight 1\n"
2012-11-27 03:23:19 +00:00
/*nexuiz/xonotic has a few quirks/annoyances...*/
2015-04-14 23:12:17 +00:00
# define NEXCFG DPCOMPAT "cl_loopbackprotocol dpp7\nset sv_listen_dp 1\nset sv_listen_qw 0\nset sv_listen_nq 0\nset sv_listen_q3 0\nset dpcompat_nopreparse 1\nset r_particlesdesc effectinfo\nset sv_bigcoords 1\nset sv_maxairspeed \"400\"\nset sv_jumpvelocity 270\nset sv_mintic \"0.01\"\ncl_nolerp 0\npr_enable_uriget 0\n"
2011-06-29 18:39:11 +00:00
/*some modern non-compat settings*/
2011-08-16 04:12:15 +00:00
# define DMFCFG "set com_parseutf8 1\npm_airstep 1\nsv_demoExtensions 1\n"
2014-04-12 03:31:59 +00:00
/*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/
2016-07-12 00:40:13 +00:00
# define HEX2CFG "set com_parseutf8 -1\nset gl_font gfx / hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc / hith2o.wav\"\nsv_sound_land \"fx / thngland.wav\"\n"
2013-03-12 23:13:39 +00:00
/*yay q2!*/
2015-09-06 03:30:28 +00:00
# define Q2CFG "set com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\n"
2011-06-29 18:39:11 +00:00
/*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/
2015-09-06 03:30:28 +00:00
# define Q3CFG "set com_parseutf8 0\ngl_overbright 2\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_nogamedirnativecode 0\n"
2014-10-29 05:03:03 +00:00
//#define RMQCFG "sv_bigcoords 1\n"
2005-08-26 22:52:26 +00:00
typedef struct {
2009-04-01 22:03:56 +00:00
const char * argname ; //used if this was used as a parameter.
2012-07-05 19:42:36 +00:00
const char * exename ; //used if the exe name contains this
const char * protocolname ; //sent to the master server when this is the current gamemode (Typically set for DP compat).
const char * auniquefile [ 4 ] ; //used if this file is relative from the gamedir. needs just one file
2005-08-26 22:52:26 +00:00
2009-04-01 22:03:56 +00:00
const char * customexec ;
2007-06-20 00:02:54 +00:00
2009-04-01 22:03:56 +00:00
const char * dir [ 4 ] ;
2009-04-12 16:57:30 +00:00
const char * poshname ; //Full name for the game.
2016-07-21 19:27:59 +00:00
const char * downloadsurl ;
2013-06-23 02:17:02 +00:00
const char * manifestfile ;
2005-08-26 22:52:26 +00:00
} gamemode_info_t ;
2009-04-01 22:03:56 +00:00
const gamemode_info_t gamemode_info [ ] = {
2017-02-19 00:15:42 +00:00
# ifdef GAME_SHORTNAME
# ifndef GAME_PROTOCOL
# define GAME_PROTOCOL DISTRIBUTION
# endif
# ifndef GAME_IDENTIFYINGFILES
# define GAME_IDENTIFYINGFILES NULL //
# endif
# ifndef GAME_DEFAULTCMDS
# define GAME_DEFAULTCMDS NULL //doesn't need anything
# endif
# ifndef GAME_BASEGAMES
# define GAME_BASEGAMES "data"
# endif
# ifndef GAME_FULLNAME
# define GAME_FULLNAME FULLENGINENAME
# endif
# ifndef GAME_MANIFESTUPDATE
# define GAME_MANIFESTUPDATE NULL
# endif
{ " - " GAME_SHORTNAME , GAME_SHORTNAME , GAME_PROTOCOL , { GAME_IDENTIFYINGFILES } , GAME_DEFAULTCMDS , { GAME_BASEGAMES } , GAME_FULLNAME , GAME_MANIFESTUPDATE } ,
# endif
2005-08-26 22:52:26 +00:00
//note that there is no basic 'fte' gamemode, this is because we aim for network compatability. Darkplaces-Quake is the closest we get.
//this is to avoid having too many gamemodes anyway.
2007-06-20 00:02:54 +00:00
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
//mission packs should generally come after the main game to avoid prefering the main game. we violate this for hexen2 as the mission pack is mostly a superset.
//whereas the quake mission packs replace start.bsp making the original episodes unreachable.
//for quake, we also allow extracting all files from paks. some people think it loads faster that way or something.
2017-02-19 00:15:42 +00:00
# ifndef NOLEGACY
2016-01-18 05:22:07 +00:00
//cmdline switch exename protocol name(dpmaster) identifying file exec dir1 dir2 dir3 dir(fte) full name
2017-01-24 10:27:39 +00:00
{ " -quake " , " q1 " , " FTE-Quake DarkPlaces-Quake " , { " id1/pak0.pak " , " id1/quake.rc " } , QCFG , { " id1 " , " qw " , " *fte " } , " Quake " , " https://fte.triptohell.info/downloadables.php " /*,"id1/pak0.pak|http://quakeservers.nquake.com/qsw106.zip|http://nquake.localghost.net/qsw106.zip|http://qw.quakephil.com/nquake/qsw106.zip|http://fnu.nquake.com/qsw106.zip"*/ } ,
2016-01-18 05:22:07 +00:00
//quake's mission packs should not be favoured over the base game nor autodetected
//third part mods also tend to depend upon the mission packs for their huds, even if they don't use any other content.
//and q2 also has a rogue/pak0.pak file that we don't want to find and cause quake2 to look like dissolution of eternity
//so just make these require the same files as good ol' quake.
2017-01-24 10:27:39 +00:00
{ " -hipnotic " , " hipnotic " , " FTE-Hipnotic " , { " id1/pak0.pak " , " id1/quake.rc " } , QCFG , { " id1 " , " qw " , " hipnotic " , " *fte " } , " Quake: Scourge of Armagon " } ,
{ " -rogue " , " rogue " , " FTE-Rogue " , { " id1/pak0.pak " , " id1/quake.rc " } , QCFG , { " id1 " , " qw " , " rogue " , " *fte " } , " Quake: Dissolution of Eternity " } ,
2016-01-18 05:22:07 +00:00
//various quake-based standalone mods.
{ " -nexuiz " , " nexuiz " , " Nexuiz " , { " nexuiz.exe " } , NEXCFG , { " data " , " *ftedata " } , " Nexuiz " } ,
{ " -xonotic " , " xonotic " , " Xonotic " , { " xonotic.exe " } , NEXCFG , { " data " , " *ftedata " } , " Xonotic " } ,
2014-10-29 05:03:03 +00:00
// {"-spark", "spark", "Spark", {"base/src/progs.src",
// "base/qwprogs.dat",
2016-01-18 05:22:07 +00:00
// "base/pak0.pak"}, DMFCFG, {"base", }, "Spark"},
2014-10-29 05:03:03 +00:00
// {"-scouts", "scouts", "FTE-SJ", {"basesj/src/progs.src",
// "basesj/progs.dat",
2016-01-18 05:22:07 +00:00
// "basesj/pak0.pak"}, NULL, {"basesj", }, "Scouts Journey"},
// {"-rmq", "rmq", "RMQ", {NULL}, RMQCFG, {"id1", "qw", "rmq", "*fte"}, "Remake Quake"},
2005-08-26 22:52:26 +00:00
2014-10-05 20:04:11 +00:00
# ifdef HEXEN2
//hexen2's mission pack generally takes precedence if both are installed.
2012-07-05 19:42:36 +00:00
{ " -portals " , " h2mp " , " FTE-H2MP " , { " portals/hexen.rc " ,
2016-01-18 05:22:07 +00:00
" portals/pak3.pak " } , HEX2CFG , { " data1 " , " portals " , " *fteh2 " } , " Hexen II MP " } ,
{ " -hexen2 " , " hexen2 " , " FTE-Hexen2 " , { " data1/pak0.pak " } , HEX2CFG , { " data1 " , " *fteh2 " } , " Hexen II " } ,
2014-10-05 20:04:11 +00:00
# endif
# if defined(Q2CLIENT) || defined(Q2SERVER)
2016-01-18 05:22:07 +00:00
{ " -quake2 " , " q2 " , " FTE-Quake2 " , { " baseq2/pak0.pak " } , Q2CFG , { " baseq2 " , " *fteq2 " } , " Quake II " } ,
2014-03-30 08:55:06 +00:00
//mods of the above that should generally work.
2016-01-18 05:22:07 +00:00
{ " -dday " , " dday " , " FTE-Quake2 " , { " dday/pak0.pak " } , Q2CFG , { " baseq2 " , " dday " , " *fteq2 " } , " D-Day: Normandy " } ,
2014-10-05 20:04:11 +00:00
# endif
2011-07-30 14:14:56 +00:00
2014-10-05 20:04:11 +00:00
# if defined(Q3CLIENT) || defined(Q3SERVER)
2016-01-18 05:22:07 +00:00
{ " -quake3 " , " q3 " , " FTE-Quake3 " , { " baseq3/pak0.pk3 " } , Q3CFG , { " baseq3 " , " *fteq3 " } , " Quake III Arena " } ,
2012-07-05 19:42:36 +00:00
//the rest are not supported in any real way. maps-only mostly, if that
2016-01-18 05:22:07 +00:00
// {"-quake4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "*fteq4"}, "Quake 4"},
// {"-et", NULL, "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "*fteet"}, "Wolfenstein - Enemy Territory"},
2005-08-26 22:52:26 +00:00
2016-01-18 05:22:07 +00:00
// {"-jk2", "jk2", "FTE-JK2", {"base/assets0.pk3"}, NULL, {"base", "*ftejk2"}, "Jedi Knight II: Jedi Outcast"},
// {"-warsow", "warsow", "FTE-Warsow", {"basewsw/pak0.pk3"}, NULL, {"basewsw", "*ftewsw"}, "Warsow"},
2014-10-05 20:04:11 +00:00
# endif
# if !defined(QUAKETC) && !defined(MINIMAL)
2016-01-18 05:22:07 +00:00
// {"-doom", "doom", "FTE-Doom", {"doom.wad"}, NULL, {"*", "*ftedoom"}, "Doom"},
// {"-doom2", "doom2", "FTE-Doom2", {"doom2.wad"}, NULL, {"*", "*ftedoom"}, "Doom2"},
// {"-doom3", "doom3", "FTE-Doom3", {"doom3.wad"}, NULL, {"based3", "*ftedoom3"},"Doom3"},
2009-03-03 01:52:30 +00:00
2013-10-29 17:38:22 +00:00
//for the luls
2016-01-18 05:22:07 +00:00
// {"-diablo2", NULL, "FTE-Diablo2", {"d2music.mpq"}, NULL, {"*", "*fted2"}, "Diablo 2"},
2014-10-29 05:03:03 +00:00
# endif
# if defined(HLSERVER) || defined(HLCLIENT)
//can run in windows, needs hl gamecode enabled. maps can always be viewed, but meh.
2016-01-18 05:22:07 +00:00
{ " -halflife " , " halflife " , " FTE-HalfLife " , { " valve/liblist.gam " } , NULL , { " valve " , " *ftehl " } , " Half-Life " } ,
2017-02-19 00:15:42 +00:00
# endif
2014-10-05 20:04:11 +00:00
# endif
2005-08-26 22:52:26 +00:00
{ NULL }
} ;
2016-08-25 00:12:14 +00:00
qboolean FS_GenCachedPakName ( const char * pname , const char * crc , char * local , int llen )
2011-10-27 16:16:29 +00:00
{
2016-08-25 00:12:14 +00:00
const char * fn ;
2013-06-23 02:17:02 +00:00
char hex [ 16 ] ;
2011-10-27 16:16:29 +00:00
if ( strstr ( pname , " dlcache " ) )
{
2013-06-23 02:17:02 +00:00
* local = 0 ;
return false ;
2011-10-27 16:16:29 +00:00
}
2016-07-12 00:40:13 +00:00
if ( ! strncmp ( pname , " downloads/ " , 10 ) )
{
Q_snprintfz ( local , llen , " %s " , pname ) ;
return true ;
}
2015-05-14 03:06:58 +00:00
for ( fn = pname ; * fn ; fn + + )
{
if ( * fn = = ' \\ ' | | * fn = = ' / ' )
{
fn + + ;
break ;
}
}
// fn = COM_SkipPath(pname);
2013-06-23 02:17:02 +00:00
if ( fn = = pname )
{ //only allow it if it has some game path first.
* local = 0 ;
return false ;
}
2011-10-27 16:16:29 +00:00
Q_strncpyz ( local , pname , min ( ( fn - pname ) + 1 , llen ) ) ;
Q_strncatz ( local , " dlcache/ " , llen ) ;
Q_strncatz ( local , fn , llen ) ;
2016-08-25 00:12:14 +00:00
if ( crc & & * crc )
2011-10-27 16:16:29 +00:00
{
Q_strncatz ( local , " . " , llen ) ;
2013-06-23 03:59:48 +00:00
snprintf ( hex , sizeof ( hex ) , " %x " , ( unsigned int ) strtoul ( crc , NULL , 0 ) ) ;
2013-06-23 02:17:02 +00:00
Q_strncatz ( local , hex , llen ) ;
2011-10-27 16:16:29 +00:00
}
2013-06-23 02:17:02 +00:00
return true ;
2011-10-27 16:16:29 +00:00
}
2013-06-23 02:17:02 +00:00
#if 0
qboolean FS_LoadPackageFromFile ( vfsfile_t * vfs , char * pname , char * localname , int * crc , unsigned int flags )
2013-03-12 23:01:08 +00:00
{
int i ;
2015-05-14 03:06:58 +00:00
char * ext = " zip " ; //(pname);
2013-06-23 02:17:02 +00:00
searchpathfuncs_t * handle ;
searchpath_t * oldlist = NULL ;
2013-03-12 23:01:08 +00:00
searchpath_t * sp ;
2015-05-14 03:06:58 +00:00
com_fschanged = true ;
2013-03-12 23:01:08 +00:00
for ( i = 0 ; i < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; i + + )
{
2013-06-23 02:17:02 +00:00
if ( ! searchpathformats [ i ] . extension | | ! searchpathformats [ i ] . OpenNew )
2013-03-12 23:01:08 +00:00
continue ;
if ( ! strcmp ( ext , searchpathformats [ i ] . extension ) )
{
2013-06-23 02:17:02 +00:00
handle = searchpathformats [ i ] . OpenNew ( vfs , localname ) ;
2013-03-12 23:01:08 +00:00
if ( ! handle )
2013-03-12 23:09:25 +00:00
{
Con_Printf ( " file %s isn't a %s after all \n " , pname , searchpathformats [ i ] . extension ) ;
2013-03-12 23:01:08 +00:00
break ;
2013-03-12 23:09:25 +00:00
}
2013-03-12 23:01:08 +00:00
if ( crc )
{
2013-06-23 02:17:02 +00:00
int truecrc = handle - > GeneratePureCRC ( handle , 0 , false ) ;
2013-03-12 23:01:08 +00:00
if ( truecrc ! = * crc )
{
* crc = truecrc ;
2014-03-30 08:55:06 +00:00
handle - > ClosePath ( handle ) ;
2013-03-12 23:01:08 +00:00
return false ;
}
}
2013-06-23 02:17:02 +00:00
sp = FS_AddPathHandle ( & oldlist , pname , localname , handle , flags , ( unsigned int ) - 1 ) ;
2013-03-12 23:01:08 +00:00
if ( sp )
{
2015-05-14 03:06:58 +00:00
com_fschanged = true ;
2013-03-12 23:01:08 +00:00
return true ;
}
}
}
VFS_CLOSE ( vfs ) ;
return false ;
}
2013-06-23 02:17:02 +00:00
# endif
2014-03-30 08:55:06 +00:00
//'small' wrapper to open foo.zip/bar to read files within zips that are not part of the gamedir.
//name needs to be null terminated. recursive. pass null for search.
vfsfile_t * CL_OpenFileInPackage ( searchpathfuncs_t * search , char * name )
{
int found ;
vfsfile_t * f ;
flocation_t loc ;
char e , * n ;
2014-10-05 20:04:11 +00:00
char ext [ 8 ] ;
2014-03-30 08:55:06 +00:00
char * end ;
int i ;
end = name + strlen ( name ) ;
while ( end > name )
{
e = * end ;
* end = 0 ;
if ( ! e )
{
//always open the last file properly.
loc . search = NULL ;
if ( search )
found = search - > FindFile ( search , & loc , name , NULL ) ;
else
2015-10-11 11:34:58 +00:00
found = FS_FLocateFile ( name , FSLF_IFFOUND , & loc ) ;
2014-03-30 08:55:06 +00:00
if ( found )
{
f = ( search ? search : loc . search - > handle ) - > OpenVFS ( search ? search : loc . search - > handle , & loc , " rb " ) ;
if ( f )
return f ;
}
}
else
{
2014-10-05 20:04:11 +00:00
COM_FileExtension ( name , ext , sizeof ( ext ) ) ;
2014-03-30 08:55:06 +00:00
for ( i = 0 ; i < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; i + + )
{
if ( ! searchpathformats [ i ] . extension | | ! searchpathformats [ i ] . OpenNew )
continue ;
if ( ! strcmp ( ext , searchpathformats [ i ] . extension ) )
{
loc . search = NULL ;
if ( search )
found = search - > FindFile ( search , & loc , name , NULL ) ;
else
2015-10-11 11:34:58 +00:00
found = FS_FLocateFile ( name , FSLF_IFFOUND , & loc ) ;
2014-03-30 08:55:06 +00:00
if ( found )
{
f = ( search ? search : loc . search - > handle ) - > OpenVFS ( search ? search : loc . search - > handle , & loc , " rb " ) ;
if ( f )
{
2016-07-12 00:40:13 +00:00
searchpathfuncs_t * newsearch = searchpathformats [ i ] . OpenNew ( f , name , " " ) ;
2014-03-30 08:55:06 +00:00
if ( newsearch )
{
f = CL_OpenFileInPackage ( newsearch , end + 1 ) ;
newsearch - > ClosePath ( newsearch ) ;
if ( f )
{
* end = e ;
return f ;
}
}
else
VFS_CLOSE ( f ) ;
}
break ;
}
}
}
}
n = COM_SkipPath ( name ) ;
* end = e ;
end = n - 1 ;
}
return NULL ;
}
2014-06-12 23:08:42 +00:00
void FS_PureMode ( int puremode , char * purenamelist , char * purecrclist , char * refnamelist , char * refcrclist , int pureseed )
2013-06-23 02:17:02 +00:00
{
qboolean pureflush ;
2015-08-11 09:14:33 +00:00
# ifndef CLIENTONLY
2015-08-10 18:28:23 +00:00
//if we're the server, we can't be impure.
if ( sv . state )
return ;
2015-08-11 09:14:33 +00:00
# endif
2015-08-10 18:28:23 +00:00
2014-03-31 17:06:41 +00:00
if ( puremode = = fs_puremode & & fs_pureseed = = pureseed )
{
2014-06-12 23:08:42 +00:00
if ( ( ! purenamelist & & ! fs_purenames ) | | ! strcmp ( fs_purenames ? fs_purenames : " " , purenamelist ? purenamelist : " " ) )
if ( ( ! purecrclist & & ! fs_purecrcs ) | | ! strcmp ( fs_purecrcs ? fs_purecrcs : " " , purecrclist ? purecrclist : " " ) )
if ( ( ! refnamelist & & ! fs_refnames ) | | ! strcmp ( fs_refnames ? fs_refnames : " " , refnamelist ? refnamelist : " " ) )
if ( ( ! refcrclist & & ! fs_refcrcs ) | | ! strcmp ( fs_refcrcs ? fs_refcrcs : " " , refcrclist ? refcrclist : " " ) )
return ;
2014-03-31 17:06:41 +00:00
}
2013-06-23 02:17:02 +00:00
Z_Free ( fs_purenames ) ;
Z_Free ( fs_purecrcs ) ;
2014-06-12 23:08:42 +00:00
Z_Free ( fs_refnames ) ;
Z_Free ( fs_refcrcs ) ;
2013-06-23 02:17:02 +00:00
pureflush = ( fs_puremode ! = 2 & & puremode = = 2 ) ;
fs_puremode = puremode ;
2014-06-12 23:08:42 +00:00
fs_purenames = purenamelist ? Z_StrDup ( purenamelist ) : NULL ;
fs_purecrcs = purecrclist ? Z_StrDup ( purecrclist ) : NULL ;
2013-06-23 02:17:02 +00:00
fs_pureseed = pureseed ;
2014-06-12 23:08:42 +00:00
fs_refnames = refnamelist ? Z_StrDup ( refnamelist ) : NULL ;
fs_refcrcs = refcrclist ? Z_StrDup ( refcrclist ) : NULL ;
2013-06-23 02:17:02 +00:00
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( fs_manifest , false , false ) ;
2013-06-23 02:17:02 +00:00
if ( pureflush )
{
# ifndef SERVERONLY
Shader_NeedReload ( true ) ;
# endif
Mod_ClearAll ( ) ;
Cache_Flush ( ) ;
}
}
2013-03-12 23:01:08 +00:00
2009-04-01 22:03:56 +00:00
char * FSQ3_GenerateClientPacksList ( char * buffer , int maxlen , int basechecksum )
{ //this is for q3 compatibility.
2005-08-26 22:52:26 +00:00
flocation_t loc ;
int numpaks = 0 ;
searchpath_t * sp ;
2015-10-11 11:34:58 +00:00
if ( FS_FLocateFile ( " vm/cgame.qvm " , FSLF_IFFOUND , & loc ) )
{
Q_strncatz ( buffer , va ( " %i " , loc . search - > crc_reply ) , maxlen ) ;
basechecksum ^ = loc . search - > crc_reply ;
}
else Q_strncatz ( buffer , va ( " %i " , 0 ) , maxlen ) ;
2005-08-26 22:52:26 +00:00
2015-10-11 11:34:58 +00:00
if ( FS_FLocateFile ( " vm/ui.qvm " , FSLF_IFFOUND , & loc ) )
{
Q_strncatz ( buffer , va ( " %i " , loc . search - > crc_reply ) , maxlen ) ;
basechecksum ^ = loc . search - > crc_reply ;
}
else Q_strncatz ( buffer , va ( " %i " , 0 ) , maxlen ) ;
2005-08-26 22:52:26 +00:00
Q_strncatz ( buffer , " @ " , maxlen ) ;
for ( sp = com_purepaths ; sp ; sp = sp - > nextpure )
{
if ( sp - > crc_reply )
{
Q_strncatz ( buffer , va ( " %i " , sp - > crc_reply ) , maxlen ) ;
basechecksum ^ = sp - > crc_reply ;
numpaks + + ;
}
}
basechecksum ^ = numpaks ;
Q_strncatz ( buffer , va ( " %i " , basechecksum ) , maxlen ) ;
return buffer ;
}
2005-10-16 12:49:15 +00:00
/*
= = = = = = = = = = = = = = = =
FS_ReloadPackFiles
= = = = = = = = = = = = = = = =
Called when the client has downloaded a new pak / pk3 file
*/
2005-10-31 00:52:03 +00:00
void FS_ReloadPackFilesFlags ( unsigned int reloadflags )
2005-10-16 12:49:15 +00:00
{
searchpath_t * oldpaths ;
searchpath_t * next ;
2013-06-23 02:17:02 +00:00
int i ;
2014-10-05 20:04:11 +00:00
int orderkey ;
char syspath [ MAX_OSPATH ] ;
2005-10-16 12:49:15 +00:00
2014-10-05 20:04:11 +00:00
COM_AssertMainThread ( " FS_ReloadPackFilesFlags " ) ;
COM_WorkerFullSync ( ) ;
orderkey = 0 ;
if ( com_purepaths )
for ( next = com_purepaths ; next ; next = next - > nextpure )
next - > orderkey = + + orderkey ;
if ( fs_puremode < 2 )
for ( next = com_purepaths ; next ; next = next - > nextpure )
next - > orderkey = + + orderkey ;
2005-10-16 12:49:15 +00:00
oldpaths = com_searchpaths ;
com_searchpaths = NULL ;
com_purepaths = NULL ;
com_base_searchpaths = NULL ;
2014-03-30 08:55:06 +00:00
i = COM_CheckParm ( " -basepack " ) ;
while ( i & & i < com_argc - 1 )
{
const char * pakname = com_argv [ i + 1 ] ;
searchpathfuncs_t * pak ;
vfsfile_t * vfs = VFSOS_Open ( pakname , " rb " ) ;
pak = FS_OpenPackByExtension ( vfs , pakname ) ;
if ( pak )
2016-07-12 00:40:13 +00:00
FS_AddPathHandle ( & oldpaths , " " , pakname , pak , " " , SPF_COPYPROTECTED | SPF_EXPLICIT , reloadflags ) ;
2014-03-30 08:55:06 +00:00
i = COM_CheckNextParm ( " -basepack " , i ) ;
}
2013-06-23 02:17:02 +00:00
for ( i = 0 ; i < sizeof ( fs_manifest - > gamepath ) / sizeof ( fs_manifest - > gamepath [ 0 ] ) ; i + + )
2005-10-16 12:49:15 +00:00
{
2013-11-29 14:36:47 +00:00
char * dir = fs_manifest - > gamepath [ i ] . path ;
if ( dir & & fs_manifest - > gamepath [ i ] . base )
2013-06-23 02:17:02 +00:00
{
2013-11-29 14:36:47 +00:00
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
if ( ! * dir | | * dir = = ' . ' | | ! strcmp ( dir , " . " ) | | strstr ( dir , " .. " ) | | strstr ( dir , " / " )
| | strstr ( dir , " \\ " ) | | strstr ( dir , " : " ) )
{
Con_Printf ( " Gamedir should be a single filename, not a path \n " ) ;
continue ;
}
2014-03-30 08:55:06 +00:00
//paths equal to '*' actually result in loading packages without an actual gamedir. note that this does not imply that we can write anything.
if ( ! strcmp ( dir , " * " ) )
2013-10-29 17:38:22 +00:00
{
2016-07-12 00:40:13 +00:00
searchpathfuncs_t * handle = VFSOS_OpenPath ( NULL , com_gamepath , " " ) ;
2013-10-29 17:38:22 +00:00
searchpath_t * search = ( searchpath_t * ) Z_Malloc ( sizeof ( searchpath_t ) ) ;
search - > flags = 0 ;
search - > handle = handle ;
Q_strncpyz ( search - > purepath , " " , sizeof ( search - > purepath ) ) ;
2014-03-30 08:55:06 +00:00
Q_strncpyz ( search - > logicalpath , com_gamepath , sizeof ( search - > logicalpath ) ) ;
2013-10-29 17:38:22 +00:00
2016-07-12 00:40:13 +00:00
FS_AddDataFiles ( & oldpaths , search - > purepath , search - > logicalpath , search , SPF_EXPLICIT , reloadflags ) ;
2013-10-29 17:38:22 +00:00
handle - > ClosePath ( handle ) ;
Z_Free ( search ) ;
}
2014-03-30 08:55:06 +00:00
else if ( * dir = = ' * ' )
{
//paths with a leading * are private, and not announced to clients that ask what the current gamedir is.
2014-10-05 20:04:11 +00:00
Q_snprintfz ( syspath , sizeof ( syspath ) , " %s%s " , com_gamepath , dir + 1 ) ;
2015-06-14 01:28:01 +00:00
FS_AddGameDirectory ( & oldpaths , dir + 1 , syspath , reloadflags , SPF_EXPLICIT | SPF_PRIVATE | ( com_homepathenabled ? 0 : SPF_WRITABLE ) ) ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
2014-10-05 20:04:11 +00:00
{
Q_snprintfz ( syspath , sizeof ( syspath ) , " %s%s " , com_homepath , dir + 1 ) ;
2015-06-14 01:28:01 +00:00
FS_AddGameDirectory ( & oldpaths , dir + 1 , syspath , reloadflags , SPF_EXPLICIT | SPF_PRIVATE | SPF_WRITABLE ) ;
2014-10-05 20:04:11 +00:00
}
2014-03-30 08:55:06 +00:00
}
2013-10-29 17:38:22 +00:00
else
{
2014-10-05 20:04:11 +00:00
Q_snprintfz ( syspath , sizeof ( syspath ) , " %s%s " , com_gamepath , dir ) ;
2015-06-14 01:28:01 +00:00
FS_AddGameDirectory ( & oldpaths , dir , syspath , reloadflags , SPF_EXPLICIT | ( com_homepathenabled ? 0 : SPF_WRITABLE ) ) ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
2014-10-05 20:04:11 +00:00
{
Q_snprintfz ( syspath , sizeof ( syspath ) , " %s%s " , com_homepath , dir ) ;
2015-06-14 01:28:01 +00:00
FS_AddGameDirectory ( & oldpaths , dir , syspath , reloadflags , SPF_EXPLICIT | SPF_WRITABLE ) ;
2014-10-05 20:04:11 +00:00
}
2013-10-29 17:38:22 +00:00
}
2013-06-23 02:17:02 +00:00
}
2005-10-16 12:49:15 +00:00
}
2016-07-12 00:40:13 +00:00
//now mark the depth values
if ( com_searchpaths )
for ( next = com_searchpaths - > next ; next ; next = next - > next )
next - > flags | = SPF_BASEPATH ;
2013-06-23 02:17:02 +00:00
com_base_searchpaths = com_searchpaths ;
2016-07-12 00:40:13 +00:00
2013-06-23 02:17:02 +00:00
for ( i = 0 ; i < sizeof ( fs_manifest - > gamepath ) / sizeof ( fs_manifest - > gamepath [ 0 ] ) ; i + + )
2005-10-16 12:49:15 +00:00
{
2013-11-29 14:36:47 +00:00
char * dir = fs_manifest - > gamepath [ i ] . path ;
if ( dir & & ! fs_manifest - > gamepath [ i ] . base )
2013-06-23 02:17:02 +00:00
{
2013-11-29 14:36:47 +00:00
//don't allow leading dots, hidden files are evil.
//don't allow complex paths. those are evil too.
if ( ! * dir | | * dir = = ' . ' | | ! strcmp ( dir , " . " ) | | strstr ( dir , " .. " ) | | strstr ( dir , " / " )
| | strstr ( dir , " \\ " ) | | strstr ( dir , " : " ) )
{
Con_Printf ( " Gamedir should be a single filename, not a path \n " ) ;
continue ;
}
if ( * dir = = ' * ' )
2013-10-29 17:38:22 +00:00
{
}
else
{
2015-06-16 23:53:58 +00:00
FS_AddGameDirectory ( & oldpaths , dir , va ( " %s%s " , com_gamepath , dir ) , reloadflags , SPF_EXPLICIT | ( com_homepathenabled ? 0 : SPF_WRITABLE ) ) ;
2014-03-30 08:55:06 +00:00
if ( com_homepathenabled )
2015-06-16 23:53:58 +00:00
FS_AddGameDirectory ( & oldpaths , dir , va ( " %s%s " , com_homepath , dir ) , reloadflags , SPF_EXPLICIT | SPF_WRITABLE ) ;
2013-10-29 17:38:22 +00:00
}
2013-06-23 02:17:02 +00:00
}
}
2005-10-16 12:49:15 +00:00
2015-05-14 03:06:58 +00:00
FS_AddDownloadManifestPackages ( & oldpaths , reloadflags ) ;
2013-06-23 02:17:02 +00:00
/*sv_pure: Reload pure paths*/
if ( fs_purenames & & fs_purecrcs )
{
char crctok [ 64 ] ;
char nametok [ MAX_QPATH ] ;
2014-06-12 23:08:42 +00:00
char nametok2 [ MAX_QPATH ] ;
2013-06-23 02:17:02 +00:00
searchpath_t * sp , * lastpure = NULL ;
char * names = fs_purenames , * pname ;
char * crcs = fs_purecrcs ;
int crc ;
2005-10-16 12:49:15 +00:00
2013-06-23 02:17:02 +00:00
for ( sp = com_searchpaths ; sp ; sp = sp - > next )
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
{
2013-06-23 02:17:02 +00:00
if ( sp - > handle - > GeneratePureCRC )
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
{
2013-06-23 02:17:02 +00:00
sp - > nextpure = ( void * ) 0x1 ;
sp - > crc_check = sp - > handle - > GeneratePureCRC ( sp - > handle , fs_pureseed , 0 ) ;
sp - > crc_reply = sp - > handle - > GeneratePureCRC ( sp - > handle , fs_pureseed , 1 ) ;
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
}
else
2013-06-23 02:17:02 +00:00
{
sp - > nextpure = NULL ;
sp - > crc_check = 0 ;
sp - > crc_reply = 0 ;
}
}
while ( names & & crcs )
{
crcs = COM_ParseOut ( crcs , crctok , sizeof ( crctok ) ) ;
names = COM_ParseOut ( names , nametok , sizeof ( nametok ) ) ;
crc = strtoul ( crctok , NULL , 0 ) ;
if ( ! crc )
continue ;
pname = nametok ;
2014-06-12 23:08:42 +00:00
if ( fs_refnames & & fs_refcrcs )
{ //q3 is annoying as hell
int crc2 ;
char * rc = fs_refcrcs ;
char * rn = fs_refnames ;
pname = " " ;
for ( ; rc & & rn ; )
{
rc = COM_ParseOut ( rc , crctok , sizeof ( crctok ) ) ;
rn = COM_ParseOut ( rn , nametok2 , sizeof ( nametok2 ) ) ;
crc2 = strtoul ( crctok , NULL , 0 ) ;
if ( crc2 = = crc )
{
COM_DefaultExtension ( nametok2 , " .pk3 " , sizeof ( nametok2 ) ) ;
pname = nametok2 ;
break ;
}
}
}
2013-06-23 02:17:02 +00:00
if ( * pname = = ' * ' ) // * means that its 'referenced' (read: actually useful) thus should be downloaded, which is not relevent here.
pname + + ;
for ( sp = com_searchpaths ; sp ; sp = sp - > next )
{
if ( sp - > nextpure = = ( void * ) 0x1 ) //don't add twice.
if ( sp - > crc_check = = crc )
{
if ( fs_puremode )
{
if ( lastpure )
lastpure - > nextpure = sp ;
else
com_purepaths = sp ;
sp - > nextpure = NULL ;
lastpure = sp ;
}
break ;
}
}
if ( ! fs_puremode & & ! sp )
{ //if we're not pure, we don't care if the version differs. don't load the server's version.
//this works around 1.01 vs 1.06 issues.
for ( sp = com_searchpaths ; sp ; sp = sp - > next )
{
2014-02-07 08:38:40 +00:00
if ( ! Q_strcasecmp ( pname , sp - > purepath ) )
2013-06-23 02:17:02 +00:00
break ;
}
}
//if its not already loaded (via wildcards), load it from the download cache, if we can
2014-06-12 23:08:42 +00:00
if ( ! sp & & * pname )
2013-06-23 02:17:02 +00:00
{
char local [ MAX_OSPATH ] ;
vfsfile_t * vfs ;
2014-10-05 20:04:11 +00:00
char ext [ 8 ] ;
2013-06-23 02:17:02 +00:00
void * handle ;
int i ;
2014-10-05 20:04:11 +00:00
COM_FileExtension ( pname , ext , sizeof ( ext ) ) ;
2013-06-23 02:17:02 +00:00
if ( FS_GenCachedPakName ( pname , va ( " %i " , crc ) , local , sizeof ( local ) ) )
2014-06-12 23:08:42 +00:00
{
unsigned int keptflags ;
handle = FS_GetOldPath ( & oldpaths , local , & keptflags ) ;
if ( handle )
{
2016-07-12 00:40:13 +00:00
sp = FS_AddPathHandle ( & oldpaths , pname , local , handle , " " , SPF_COPYPROTECTED | SPF_UNTRUSTED | SPF_TEMPORARY | keptflags , ( unsigned int ) - 1 ) ;
2014-06-12 23:08:42 +00:00
if ( sp - > crc_check = = crc )
{
if ( fs_puremode )
{
if ( lastpure )
lastpure - > nextpure = sp ;
else
com_purepaths = sp ;
sp - > nextpure = NULL ;
lastpure = sp ;
}
}
continue ;
}
2013-06-23 02:17:02 +00:00
vfs = FS_OpenVFS ( local , " rb " , FS_ROOT ) ;
2014-06-12 23:08:42 +00:00
}
2013-06-23 02:17:02 +00:00
else
vfs = NULL ;
if ( vfs )
{
for ( i = 0 ; i < sizeof ( searchpathformats ) / sizeof ( searchpathformats [ 0 ] ) ; i + + )
{
if ( ! searchpathformats [ i ] . extension | | ! searchpathformats [ i ] . OpenNew )
continue ;
if ( ! strcmp ( ext , searchpathformats [ i ] . extension ) )
{
2016-07-12 00:40:13 +00:00
handle = searchpathformats [ i ] . OpenNew ( vfs , local , " " ) ;
2013-06-23 02:17:02 +00:00
if ( ! handle )
break ;
2016-07-12 00:40:13 +00:00
sp = FS_AddPathHandle ( & oldpaths , pname , local , handle , " " , SPF_COPYPROTECTED | SPF_UNTRUSTED | SPF_TEMPORARY , ( unsigned int ) - 1 ) ;
2013-06-23 02:17:02 +00:00
sp - > crc_check = sp - > handle - > GeneratePureCRC ( sp - > handle , fs_pureseed , 0 ) ;
sp - > crc_reply = sp - > handle - > GeneratePureCRC ( sp - > handle , fs_pureseed , 1 ) ;
if ( sp - > crc_check = = crc )
{
if ( fs_puremode )
{
if ( lastpure )
lastpure - > nextpure = sp ;
else
com_purepaths = sp ;
sp - > nextpure = NULL ;
lastpure = sp ;
}
}
break ;
}
}
}
if ( ! sp )
Con_DPrintf ( " Pure crc %i wasn't found \n " , crc ) ;
}
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
}
2005-10-16 12:49:15 +00:00
}
2013-06-23 02:17:02 +00:00
while ( oldpaths )
{
next = oldpaths - > next ;
2011-10-27 16:16:29 +00:00
2016-07-12 00:40:13 +00:00
Con_DPrintf ( " %s is no longer needed \n " , oldpaths - > logicalpath ) ;
2013-06-23 02:17:02 +00:00
oldpaths - > handle - > ClosePath ( oldpaths - > handle ) ;
Z_Free ( oldpaths ) ;
oldpaths = next ;
}
2014-06-21 17:58:17 +00:00
2014-10-05 20:04:11 +00:00
i = orderkey ;
orderkey = 0 ;
next = NULL ;
if ( com_purepaths )
for ( next = com_purepaths ; next ; next = next - > nextpure )
if ( next - > orderkey ! = + + orderkey )
break ;
if ( ! next & & fs_puremode < 2 )
for ( next = com_purepaths ; next ; next = next - > nextpure )
if ( next - > orderkey ! = + + orderkey )
break ;
if ( next | | i ! = orderkey ) //some path changed. make sure the fs cache is flushed.
FS_FlushFSHashReally ( false ) ;
2014-06-21 17:58:17 +00:00
# ifndef SERVERONLY
Shader_NeedReload ( true ) ;
# endif
// Mod_ClearAll();
// Cache_Flush();
2005-10-16 12:49:15 +00:00
}
2006-01-28 06:41:20 +00:00
void FS_UnloadPackFiles ( void )
{
2014-10-05 20:04:11 +00:00
if ( Sys_LockMutex ( fs_thread_mutex ) )
{
2016-08-25 00:12:14 +00:00
FS_ReloadPackFilesFlags ( 0 ) ;
2014-10-05 20:04:11 +00:00
Sys_UnlockMutex ( fs_thread_mutex ) ;
}
2006-01-28 06:41:20 +00:00
}
2005-10-31 00:52:03 +00:00
void FS_ReloadPackFiles ( void )
{
2016-07-12 00:40:13 +00:00
//extra junk is to ensure the palette is reloaded if that changed.
flocation_t paletteloc = { NULL } ;
flocation_t paletteloc2 = { NULL } ;
FS_FLocateFile ( " gfx/palette.lmp " , 0 , & paletteloc ) ;
2014-10-05 20:04:11 +00:00
if ( Sys_LockMutex ( fs_thread_mutex ) )
{
FS_ReloadPackFilesFlags ( ~ 0 ) ;
Sys_UnlockMutex ( fs_thread_mutex ) ;
}
2016-07-12 00:40:13 +00:00
FS_FLocateFile ( " gfx/palette.lmp " , 0 , & paletteloc2 ) ;
if ( paletteloc . search ! = paletteloc2 . search )
Cbuf_AddText ( " vid_reload \n " , RESTRICT_LOCAL ) ;
2005-10-31 00:52:03 +00:00
}
void FS_ReloadPackFiles_f ( void )
{
2014-10-05 20:04:11 +00:00
if ( Sys_LockMutex ( fs_thread_mutex ) )
{
2016-08-25 00:12:14 +00:00
if ( * Cmd_Argv ( 1 ) )
2014-10-05 20:04:11 +00:00
FS_ReloadPackFilesFlags ( atoi ( Cmd_Argv ( 1 ) ) ) ;
else
FS_ReloadPackFilesFlags ( ~ 0 ) ;
Sys_UnlockMutex ( fs_thread_mutex ) ;
}
2015-09-07 14:34:39 +00:00
if ( host_initialized )
FS_BeginManifestUpdates ( ) ;
2005-10-31 00:52:03 +00:00
}
2015-09-14 15:20:09 +00:00
# if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT)
2014-03-30 08:55:06 +00:00
# include "winquake.h"
2009-05-24 10:11:17 +00:00
# ifdef MINGW
# define byte BYTE //some versions of mingw headers are broken slightly. this lets it compile.
# endif
2010-08-16 02:03:02 +00:00
static qboolean Sys_SteamHasFile ( char * basepath , int basepathlen , char * steamdir , char * fname )
{
/*
Find where Valve ' s Steam distribution platform is installed .
Then take a look at that location for the relevent installed app .
*/
FILE * f ;
DWORD resultlen ;
HKEY key = NULL ;
2012-11-27 03:23:19 +00:00
2015-05-14 03:06:58 +00:00
if ( RegOpenKeyExW ( HKEY_CURRENT_USER , L " SOFTWARE \\ Valve \\ Steam " , 0 , STANDARD_RIGHTS_READ | KEY_QUERY_VALUE , & key ) = = ERROR_SUCCESS )
2010-08-16 02:03:02 +00:00
{
2015-05-14 03:06:58 +00:00
wchar_t suckysucksuck [ MAX_OSPATH ] ;
resultlen = sizeof ( suckysucksuck ) ;
RegQueryValueExW ( key , L " SteamPath " , NULL , NULL , ( void * ) suckysucksuck , & resultlen ) ;
2010-08-16 02:03:02 +00:00
RegCloseKey ( key ) ;
2015-05-14 03:06:58 +00:00
narrowen ( basepath , basepathlen , suckysucksuck ) ;
2010-08-16 02:03:02 +00:00
Q_strncatz ( basepath , va ( " /SteamApps/common/%s " , steamdir ) , basepathlen ) ;
2011-05-30 13:36:44 +00:00
if ( ( f = fopen ( va ( " %s/%s " , basepath , fname ) , " rb " ) ) )
2010-08-16 02:03:02 +00:00
{
fclose ( f ) ;
return true ;
}
}
return false ;
}
2015-04-14 23:12:17 +00:00
2015-06-04 07:03:08 +00:00
# ifndef SERVERONLY
2015-04-14 23:12:17 +00:00
static INT CALLBACK StupidBrowseCallbackProc ( HWND hwnd , UINT uMsg , LPARAM lp , LPARAM pData )
{ //'stolen' from microsoft's knowledge base.
//required to work around microsoft being annoying.
2015-05-14 03:06:58 +00:00
wchar_t szDir [ MAX_PATH ] ;
wchar_t * foo ;
2015-04-14 23:12:17 +00:00
switch ( uMsg )
{
case BFFM_INITIALIZED :
2015-05-14 03:06:58 +00:00
if ( GetCurrentDirectoryW ( sizeof ( szDir ) / sizeof ( TCHAR ) , szDir ) )
2015-04-14 23:12:17 +00:00
{
// foo = strrchr(szDir, '\\');
// if (foo)
// *foo = 0;
// foo = strrchr(szDir, '\\');
// if (foo)
// *foo = 0;
2015-05-14 03:06:58 +00:00
SendMessageW ( hwnd , BFFM_SETSELECTION , TRUE , ( LPARAM ) szDir ) ;
2015-04-14 23:12:17 +00:00
}
break ;
2015-05-14 03:06:58 +00:00
case BFFM_VALIDATEFAILEDW :
break ; //FIXME: validate that the gamedir contains what its meant to
2015-04-14 23:12:17 +00:00
case BFFM_SELCHANGED :
2016-08-25 00:12:14 +00:00
if ( SHGetPathFromIDListW ( ( LPITEMIDLIST ) lp , szDir ) )
2015-04-14 23:12:17 +00:00
{
2015-05-14 03:06:58 +00:00
wchar_t statustxt [ MAX_OSPATH ] ;
2016-07-12 00:40:13 +00:00
while ( ( foo = wcschr ( szDir , ' \\ ' ) ) )
2015-04-14 23:12:17 +00:00
* foo = ' / ' ;
2015-05-14 03:06:58 +00:00
if ( pData )
_snwprintf ( statustxt , countof ( statustxt ) , L " %s/%s " , szDir , pData ) ;
else
_snwprintf ( statustxt , countof ( statustxt ) , L " %s " , szDir ) ;
statustxt [ countof ( statustxt ) - 1 ] = 0 ; //ms really suck.
SendMessageW ( hwnd , BFFM_SETSTATUSTEXT , 0 , ( LPARAM ) statustxt ) ;
2015-04-14 23:12:17 +00:00
}
break ;
}
return 0 ;
}
2015-06-04 06:15:14 +00:00
int MessageBoxU ( HWND hWnd , char * lpText , char * lpCaption , UINT uType ) ;
2015-04-14 23:12:17 +00:00
# endif
qboolean Sys_DoDirectoryPrompt ( char * basepath , size_t basepathsize , const char * poshname , const char * savedname )
{
2015-04-21 21:49:08 +00:00
# ifndef SERVERONLY
2015-05-14 03:06:58 +00:00
wchar_t resultpath [ MAX_OSPATH ] ;
wchar_t title [ MAX_OSPATH ] ;
BROWSEINFOW bi ;
2015-04-14 23:12:17 +00:00
LPITEMIDLIST il ;
memset ( & bi , 0 , sizeof ( bi ) ) ;
bi . hwndOwner = mainwindow ; //note that this is usually still null
bi . pidlRoot = NULL ;
2015-05-14 03:06:58 +00:00
GetCurrentDirectoryW ( sizeof ( resultpath ) - 1 , resultpath ) ;
2015-04-14 23:12:17 +00:00
bi . pszDisplayName = resultpath ;
2015-05-14 03:06:58 +00:00
widen ( resultpath , sizeof ( resultpath ) , poshname ) ;
_snwprintf ( title , countof ( title ) , L " Please locate your existing %s installation " , resultpath ) ;
2015-06-04 06:15:14 +00:00
//force mouse to deactivate, so that we can actually see it.
INS_UpdateGrabs ( false , false ) ;
2015-05-14 03:06:58 +00:00
bi . lpszTitle = title ;
2015-04-14 23:12:17 +00:00
bi . ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT ;
bi . lpfn = StupidBrowseCallbackProc ;
bi . lParam = 0 ; //(LPARAM)poshname;
bi . iImage = 0 ;
2016-08-25 00:12:14 +00:00
il = SHBrowseForFolderW ( & bi ) ;
2015-04-14 23:12:17 +00:00
if ( il )
{
2016-08-25 00:12:14 +00:00
SHGetPathFromIDListW ( il , resultpath ) ;
2015-04-14 23:12:17 +00:00
CoTaskMemFree ( il ) ;
2015-05-14 03:06:58 +00:00
narrowen ( basepath , basepathsize , resultpath ) ;
2015-04-14 23:12:17 +00:00
if ( savedname )
{
Reworked client support for DPP5+. less code now, its much more graceful.
added waterfog command. waterfog overrides regular fog only when the view is in water.
fixed 64bit printf format specifiers. should work better on winxp64.
fixed some spec angle weirdness.
fixed viewsize 99.99 weirdness with ezhud.
fixed extra offset on the console (exhibited in 64bit builds, but not limited to).
fixed .avi playback, can now actually display frames again.
reimplemented line sparks.
fixed r_editlights_save flipping the light's pitch.
fixed issue with oggs failing to load.
fixed condump to cope with unicode properly.
made sv_bigcoords default except in quake. hexen2 kinda needs it for bsp angle precision.
fixed nq server to not stall weirdly on map changes.
fixed qwprogs svc_cdtrack not bugging out with nq clients on the server.
fixed restart command to load the last map run by the server, instead of start.bsp (when idle)
optimised d3d9 renderer a little. now uses less draw calls, especially with complex scenes. seems to get higher framerates than opengl now.
fixed d3d9 renderer to not bug out quite so much when run fullscreen (shader subsystem is now correctly initialised).
fixed a couple of bugs from font change. also now supports utf-8 in a few more places.
r_editlights_reload no longer generates rtlights inside the void. this resolves a few glitches (but should also help framerates a little).
fixed so corona-only lights won't generate shadowmaps and waste lots of time.
removed lots of #defines from qclib. I should never have made them in the first place, but I was lazy. obviously there's more left that I cba to remove yet.
fixed nested calls with variant-vectors. this fixes csaddon's light editor.
fixed qcc hc calling conventions using redundant stores.
disabled keywords can still be used by using __keyword instead.
fixed ftegccgui grep feature.
fixed motionless-dog qcc bug.
tweaked qcc warnings a little. -Wall is now a viable setting. you should be able to fix all those warnings.
fixed qw svc_intermission + dpp5+ clients bug.
fixed annoying spam about disconnecting in hexen2.
rewrote status command a little to cope with ipv6 addresses more gracefully
fixed significant stall when hibernating/debugging a server with a player sitting on it.
fixed truelightning.
fixed rocketlight overriding pflags.
fixed torches vanishing on vid_restart.
fixed issue with decal scaling.
fixed findentityfield builtin.
fixed fteqcc issue with ptr+1
fixed use of arrays inside class functions.
fixed/implemented fteqcc emulation of pointer opcodes.
added __inout keyword to fteqcc, so that it doesn't feel so horrendous.
fixed sizeof(*foo)
fixed *struct = struct;
fixed recursive structs.
fixed fteqcc warning report.
fixed sdl2 controller support, hopefully.
attempted to implement xinput, including per-player audio playback.
slightly fixed relaxed attitude to mouse focus when running fullscreen.
fixed weird warnings/errors with 'ent.arrayhead' terms. now generates sane errors.
implemented bindmaps (for csqc).
fixed crashing bug with eprint builtin.
implemented subset of music_playlist_* functionality. significant changes to music playback.
fixed some more dpcsqc compat.
fixed binds menu. now displays and accepts modifiers.
fixed issues with huge lightmaps.
fixed protocol determinism with dp clients connecting to fte servers. the initial getchallenge request now inhibits vanilla nq connection requests.
implemented support for 'dupe' userinfo key, allowing clients to request client->server packet duplication. should probably queue them tbh.
implemented sv_saveentfile command.
fixed resume after breaking inside a stepped-over function.
fixed erroneous footer after debugging.
(I wonder just how many things I broke with these fixes)
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4946 fc73d0e0-1445-4013-8a0c-d673dee63da5
2015-07-26 10:56:18 +00:00
if ( MessageBoxU ( mainwindow , va ( " Would you like to save the location of %s as: \n %s " , poshname , basepath ) , " Save Instaltion path " , MB_YESNO | MB_DEFBUTTON2 ) = = IDYES )
2015-06-04 06:15:14 +00:00
MyRegSetValue ( HKEY_CURRENT_USER , " SOFTWARE \\ " FULLENGINENAME " \\ GamePaths " , savedname , REG_SZ , basepath , strlen ( basepath ) ) ;
2015-04-14 23:12:17 +00:00
}
return true ;
}
2015-04-21 21:49:08 +00:00
# endif
2015-04-14 23:12:17 +00:00
return false ;
}
2015-05-14 03:06:58 +00:00
DWORD GetFileAttributesU ( const char * lpFileName )
{
wchar_t wide [ MAX_OSPATH ] ;
widen ( wide , sizeof ( wide ) , lpFileName ) ;
return GetFileAttributesW ( wide ) ;
}
2015-04-14 23:12:17 +00:00
qboolean Sys_FindGameData ( const char * poshname , const char * gamename , char * basepath , int basepathlen , qboolean allowprompts )
2009-03-03 01:52:30 +00:00
{
2009-04-12 16:57:30 +00:00
# ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
# endif
//first, try and find it in our game paths location
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_CURRENT_USER , " SOFTWARE \\ " FULLENGINENAME " \\ GamePaths " , gamename , basepath , basepathlen ) )
2009-04-12 16:57:30 +00:00
{
2015-05-14 03:06:58 +00:00
if ( GetFileAttributesU ( basepath ) ! = INVALID_FILE_ATTRIBUTES )
return true ;
2009-04-12 16:57:30 +00:00
}
2013-06-23 03:59:48 +00:00
if ( ! strcmp ( gamename , " quake " ) )
2009-03-03 01:52:30 +00:00
{
2013-10-29 17:38:22 +00:00
char * prefix [ ] =
{
" c:/quake/ " , //quite a lot of people have it in c:\quake, as that's the default install location from the quake cd.
" c:/games/quake/ " , //personally I use this
2015-05-14 03:06:58 +00:00
" c:/nquake/ " , //nquake seems to have moved out of programfiles now. woo.
2013-10-29 17:38:22 +00:00
# ifdef _WIN64
2015-05-14 03:06:58 +00:00
//quite a few people have nquake installed. FIXME: we need to an api function to read the directory for non-english-windows users.
2013-10-29 17:38:22 +00:00
va ( " %s/nQuake/ " , getenv ( " %ProgramFiles(x86)% " ) ) , //64bit builds should look in both places
va ( " %s/nQuake/ " , getenv ( " %ProgramFiles% " ) ) , //
# else
va ( " %s/nQuake/ " , getenv ( " %ProgramFiles% " ) ) , //32bit builds will get the x86 version anyway.
# endif
NULL
} ;
int i ;
2010-08-16 02:03:02 +00:00
2009-03-03 01:52:30 +00:00
//try and find it via steam
//reads HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam\InstallPath
//append SteamApps\common\quake
//use it if we find winquake.exe there
2010-08-16 02:03:02 +00:00
if ( Sys_SteamHasFile ( basepath , basepathlen , " quake " , " Winquake.exe " ) )
return true ;
2009-03-03 01:52:30 +00:00
//well, okay, so they don't have quake installed from steam.
2013-10-29 17:38:22 +00:00
//check various 'unadvertised' paths
for ( i = 0 ; prefix [ i ] ; i + + )
2009-03-03 01:52:30 +00:00
{
2013-10-29 17:38:22 +00:00
char syspath [ MAX_OSPATH ] ;
Q_snprintfz ( syspath , sizeof ( syspath ) , " %sid1/pak0.pak " , prefix [ i ] ) ;
2015-05-14 03:06:58 +00:00
if ( GetFileAttributesU ( syspath ) ! = INVALID_FILE_ATTRIBUTES )
{
2015-06-12 14:44:50 +00:00
Q_strncpyz ( basepath , prefix [ i ] , basepathlen ) ;
2015-05-14 03:06:58 +00:00
return true ;
}
Q_snprintfz ( syspath , sizeof ( syspath ) , " %squake.exe " , prefix [ i ] ) ;
if ( GetFileAttributesU ( syspath ) ! = INVALID_FILE_ATTRIBUTES )
2013-10-29 17:38:22 +00:00
{
2015-06-12 14:44:50 +00:00
Q_strncpyz ( basepath , prefix [ i ] , basepathlen ) ;
2013-10-29 17:38:22 +00:00
return true ;
}
2009-03-03 01:52:30 +00:00
}
}
2013-06-23 03:59:48 +00:00
if ( ! strcmp ( gamename , " quake2 " ) )
2009-03-03 01:52:30 +00:00
{
2010-08-16 02:03:02 +00:00
//look for HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Quake2_exe\Path
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Microsoft \\ Windows \\ CurrentVersion \\ App Paths \\ Quake2_exe " , " Path " , basepath , basepathlen ) )
2009-03-03 01:52:30 +00:00
{
2015-05-14 03:06:58 +00:00
if ( GetFileAttributesU ( va ( " %s/quake2.exe " , basepath ) ) ! = INVALID_FILE_ATTRIBUTES )
2009-03-03 01:52:30 +00:00
return true ;
}
2010-08-16 02:03:02 +00:00
if ( Sys_SteamHasFile ( basepath , basepathlen , " quake 2 " , " quake2.exe " ) )
return true ;
}
if ( ! strcmp ( gamename , " et " ) )
{
//reads HKEY_LOCAL_MACHINE\SOFTWARE\Activision\Wolfenstein - Enemy Territory
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Activision \\ Wolfenstein - Enemy Territory " , " InstallPath " , basepath , basepathlen ) )
2009-03-03 01:52:30 +00:00
{
2015-05-14 03:06:58 +00:00
// if (GetFileAttributesU(va("%s/ET.exe", basepath) != INVALID_FILE_ATTRIBUTES)
// return true;
2010-08-16 02:03:02 +00:00
return true ;
2009-03-03 01:52:30 +00:00
}
}
2013-06-23 03:59:48 +00:00
if ( ! strcmp ( gamename , " quake3 " ) )
2009-03-03 01:52:30 +00:00
{
//reads HKEY_LOCAL_MACHINE\SOFTWARE\id\Quake III Arena\InstallPath
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ id \\ Quake III Arena " , " InstallPath " , basepath , basepathlen ) )
2009-03-03 01:52:30 +00:00
{
2015-05-14 03:06:58 +00:00
if ( GetFileAttributesU ( va ( " %s/quake3.exe " , basepath ) ) ! = INVALID_FILE_ATTRIBUTES )
2010-08-16 02:03:02 +00:00
return true ;
2009-03-03 01:52:30 +00:00
}
2010-08-16 02:03:02 +00:00
if ( Sys_SteamHasFile ( basepath , basepathlen , " quake 3 arena " , " quake3.exe " ) )
return true ;
2009-03-03 01:52:30 +00:00
}
2010-03-14 14:35:56 +00:00
if ( ! strcmp ( gamename , " wop " ) )
{
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ World Of Padman " , " Path " , basepath , basepathlen ) )
2010-03-14 14:35:56 +00:00
return true ;
}
2009-03-03 01:52:30 +00:00
/*
if ( ! strcmp ( gamename , " d3 " ) )
{
//reads HKEY_LOCAL_MACHINE\SOFTWARE\id\Doom 3\InstallPath
2015-05-14 03:06:58 +00:00
if ( MyRegGetStringValue ( HKEY_LOCAL_MACHINE , L " SOFTWARE \\ id \\ Doom 3 " , " InstallPath " , basepath , basepathlen ) )
2009-03-03 01:52:30 +00:00
return true ;
}
*/
2013-06-23 02:17:02 +00:00
if ( ! strcmp ( gamename , " hexen2 " ) | | ! strcmp ( gamename , " h2mp " ) )
2009-03-03 01:52:30 +00:00
{
//append SteamApps\common\hexen 2
2011-03-09 03:42:30 +00:00
if ( Sys_SteamHasFile ( basepath , basepathlen , " hexen 2 " , " glh2.exe " ) )
2010-08-16 02:03:02 +00:00
return true ;
2009-03-03 01:52:30 +00:00
}
2011-09-16 05:56:54 +00:00
# if !defined(NPFTE) && !defined(SERVERONLY) //this is *really* unfortunate, but doing this crashes the browser
2015-04-14 23:12:17 +00:00
if ( allowprompts & & poshname & & * gamename & & ! COM_CheckParm ( " -manifest " ) )
{
if ( Sys_DoDirectoryPrompt ( basepath , basepathlen , poshname , gamename ) )
2009-04-12 16:57:30 +00:00
return true ;
}
2009-04-19 00:50:42 +00:00
# endif
2009-04-12 16:57:30 +00:00
2009-03-03 01:52:30 +00:00
return false ;
}
# else
2016-07-21 19:27:59 +00:00
# if defined(__linux__) || defined(__unix__) || defined(__apple__)
2012-11-30 02:50:50 +00:00
# include <sys/stat.h>
# endif
2015-04-14 23:12:17 +00:00
qboolean Sys_FindGameData ( const char * poshname , const char * gamename , char * basepath , int basepathlen , qboolean allowprompts )
2009-03-03 01:52:30 +00:00
{
2016-07-21 19:27:59 +00:00
# if defined(__linux__) || defined(__unix__) || defined(__apple__)
2012-11-30 02:50:50 +00:00
struct stat sb ;
2016-10-22 07:06:51 +00:00
char * s ;
if ( ! * gamename )
gamename = " quake " ; //just a paranoia fallback, shouldn't be needed.
2016-07-21 19:27:59 +00:00
if ( ! strcmp ( gamename , " quake " ) )
2012-11-30 02:50:50 +00:00
{
if ( stat ( " /usr/share/quake/ " , & sb ) = = 0 )
{
if ( S_ISDIR ( sb . st_mode ) )
{
Q_strncpyz ( basepath , " /usr/share/quake/ " , basepathlen ) ;
return true ;
}
}
}
2016-10-22 07:06:51 +00:00
s = va ( " /usr/share/games/%s/ " , gamename ) ;
if ( stat ( s , & sb ) = = 0 )
{
if ( S_ISDIR ( sb . st_mode ) )
{
Q_strncpyz ( basepath , s , basepathlen ) ;
return true ;
}
}
2012-11-27 03:23:19 +00:00
# endif
2009-03-03 01:52:30 +00:00
return false ;
}
2015-04-14 23:12:17 +00:00
# define Sys_DoDirectoryPrompt(bp,bps,game,savename) false
2009-03-03 01:52:30 +00:00
# endif
2014-10-05 20:04:11 +00:00
static void FS_FreePaths ( void )
2009-04-01 22:03:56 +00:00
{
searchpath_t * next ;
2014-10-05 20:04:11 +00:00
FS_FlushFSHashReally ( true ) ;
2009-04-01 22:03:56 +00:00
//
// free up any current game dir info
//
while ( com_searchpaths )
{
2013-06-23 02:17:02 +00:00
com_searchpaths - > handle - > ClosePath ( com_searchpaths - > handle ) ;
2009-04-01 22:03:56 +00:00
next = com_searchpaths - > next ;
Z_Free ( com_searchpaths ) ;
com_searchpaths = next ;
}
com_fschanged = true ;
2012-07-05 19:42:36 +00:00
if ( filesystemhash . numbuckets )
{
BZ_Free ( filesystemhash . bucket ) ;
filesystemhash . bucket = NULL ;
filesystemhash . numbuckets = 0 ;
}
2013-06-23 02:17:02 +00:00
FS_Manifest_Free ( fs_manifest ) ;
fs_manifest = NULL ;
2009-04-01 22:03:56 +00:00
}
2014-10-05 20:04:11 +00:00
void FS_Shutdown ( void )
{
2016-07-12 00:40:13 +00:00
if ( ! fs_thread_mutex )
return ;
2016-11-25 08:14:54 +00:00
PM_ManifestPackage ( NULL , false ) ;
2014-10-05 20:04:11 +00:00
FS_FreePaths ( ) ;
2016-07-12 00:40:13 +00:00
Sys_DestroyMutex ( fs_thread_mutex ) ;
fs_thread_mutex = NULL ;
2014-12-23 15:26:42 +00:00
2014-12-29 02:35:10 +00:00
Cvar_SetEngineDefault ( & fs_gamename , NULL ) ;
2017-01-24 10:27:39 +00:00
Cvar_SetEngineDefault ( & pm_downloads_url , NULL ) ;
2014-12-29 02:35:10 +00:00
Cvar_SetEngineDefault ( & com_protocolname , NULL ) ;
2014-10-05 20:04:11 +00:00
}
2009-04-01 22:03:56 +00:00
2014-04-12 03:31:59 +00:00
//returns false if the directory is not suitable.
//returns true if it contains a known package. if we don't actually know of any packages that it should have, we just have to assume that its okay.
2013-10-29 17:38:22 +00:00
static qboolean FS_DirHasAPackage ( char * basedir , ftemanifest_t * man )
{
2014-04-12 03:31:59 +00:00
qboolean defaultret = true ;
2013-10-29 17:38:22 +00:00
int j ;
vfsfile_t * f ;
2015-04-14 23:12:17 +00:00
f = VFSOS_Open ( va ( " %sdefault.fmf " , basedir ) , " rb " ) ;
if ( f )
{
VFS_CLOSE ( f ) ;
return true ;
}
2013-10-29 17:38:22 +00:00
for ( j = 0 ; j < sizeof ( fs_manifest - > package ) / sizeof ( fs_manifest - > package [ 0 ] ) ; j + + )
{
if ( ! man - > package [ j ] . path )
continue ;
2014-04-12 03:31:59 +00:00
defaultret = false ;
2013-10-29 17:38:22 +00:00
f = VFSOS_Open ( va ( " %s%s " , basedir , man - > package [ j ] . path ) , " rb " ) ;
if ( f )
{
VFS_CLOSE ( f ) ;
return true ;
}
}
2014-04-12 03:31:59 +00:00
return defaultret ;
2013-10-29 17:38:22 +00:00
}
2013-06-23 02:17:02 +00:00
//just check each possible file, see if one is there.
2016-11-20 20:52:41 +00:00
static qboolean FS_DirHasGame ( const char * basedir , int gameidx )
2012-07-05 19:42:36 +00:00
{
2013-06-23 02:17:02 +00:00
int j ;
vfsfile_t * f ;
2017-02-19 00:15:42 +00:00
//none listed, just assume its correct.
if ( ! gamemode_info [ gameidx ] . auniquefile [ 0 ] )
return true ;
2013-06-23 02:17:02 +00:00
for ( j = 0 ; j < 4 ; j + + )
2012-07-05 19:42:36 +00:00
{
2013-06-23 02:17:02 +00:00
if ( ! gamemode_info [ gameidx ] . auniquefile [ j ] )
continue ; //no more
f = VFSOS_Open ( va ( " %s%s " , basedir , gamemode_info [ gameidx ] . auniquefile [ j ] ) , " rb " ) ;
if ( f )
2012-07-05 19:42:36 +00:00
{
2013-06-23 02:17:02 +00:00
VFS_CLOSE ( f ) ;
return true ;
2012-07-05 19:42:36 +00:00
}
}
2013-06-23 02:17:02 +00:00
return false ;
2012-07-05 19:42:36 +00:00
}
2013-06-23 02:17:02 +00:00
//check em all
2016-11-20 20:52:41 +00:00
static int FS_IdentifyDefaultGameFromDir ( const char * basedir )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
int i ;
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
{
if ( FS_DirHasGame ( basedir , i ) )
return i ;
}
return - 1 ;
}
2009-04-01 22:03:56 +00:00
2013-06-23 02:17:02 +00:00
//attempt to work out which game we're meant to be trying to run based upon a few things
//1: fs_changegame console command override. fixme: needs to cope with manifests too.
//2: -quake3 argument implies that the user wants to run quake3.
//3: if we are ftequake3.exe then we always try to run quake3.
//4: identify characteristic files within the working directory (like id1/pak0.pak implies we're running quake)
//5: check where the exe actually is instead of simply where we're being run from.
2016-07-21 19:27:59 +00:00
//6: try the homedir, just in case.
//7: fallback to prompting. just returns -1 here.
2013-06-23 02:17:02 +00:00
//if autobasedir is not set, block gamedir changes/prompts.
static int FS_IdentifyDefaultGame ( char * newbase , int sizeof_newbase , qboolean fixedbase )
{
int i ;
int gamenum = - 1 ;
2005-10-16 12:49:15 +00:00
2013-06-23 02:17:02 +00:00
//use the game based on an exe name over the filesystem one (could easily have multiple fs path matches).
if ( gamenum = = - 1 )
2006-03-06 01:41:09 +00:00
{
2013-10-29 17:38:22 +00:00
char * ev , * v0 = COM_SkipPath ( com_argv [ 0 ] ) ;
2013-06-23 02:17:02 +00:00
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
2006-03-06 01:41:09 +00:00
{
2013-10-29 17:38:22 +00:00
if ( ! gamemode_info [ i ] . exename )
continue ;
ev = strstr ( v0 , gamemode_info [ i ] . exename ) ;
2013-06-23 02:17:02 +00:00
if ( ev & & ( ! strchr ( ev , ' \\ ' ) & & ! strchr ( ev , ' / ' ) ) )
gamenum = i ;
2006-03-06 01:41:09 +00:00
}
}
2013-06-23 02:17:02 +00:00
//identify the game from a telling file in the working directory
if ( gamenum = = - 1 )
gamenum = FS_IdentifyDefaultGameFromDir ( newbase ) ;
//identify the game from a telling file relative to the exe's directory. for when shortcuts don't set the working dir sensibly.
if ( gamenum = = - 1 & & host_parms . binarydir & & * host_parms . binarydir & & ! fixedbase )
{
gamenum = FS_IdentifyDefaultGameFromDir ( host_parms . binarydir ) ;
if ( gamenum ! = - 1 )
Q_strncpyz ( newbase , host_parms . binarydir , sizeof_newbase ) ;
}
2016-07-21 19:27:59 +00:00
if ( gamenum = = - 1 & & * com_homepath & & ! fixedbase )
{
gamenum = FS_IdentifyDefaultGameFromDir ( com_homepath ) ;
if ( gamenum ! = - 1 )
Q_strncpyz ( newbase , com_homepath , sizeof_newbase ) ;
}
2013-06-23 02:17:02 +00:00
return gamenum ;
}
//allowed to modify newbasedir if fixedbasedir isn't set
2014-10-29 05:03:03 +00:00
static ftemanifest_t * FS_GenerateLegacyManifest ( char * newbasedir , int sizeof_newbasedir , qboolean fixedbasedir , int game )
2013-06-23 02:17:02 +00:00
{
ftemanifest_t * man ;
if ( gamemode_info [ game ] . manifestfile )
2014-03-30 08:55:06 +00:00
man = FS_Manifest_Parse ( NULL , gamemode_info [ game ] . manifestfile ) ;
2013-06-23 02:17:02 +00:00
else
2012-11-27 03:23:19 +00:00
{
2014-03-30 08:55:06 +00:00
man = FS_Manifest_Create ( NULL ) ;
2013-06-23 02:17:02 +00:00
Cmd_TokenizeString ( va ( " game \" %s \" " , gamemode_info [ game ] . argname + 1 ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
if ( gamemode_info [ game ] . poshname )
{
Cmd_TokenizeString ( va ( " name \" %s \" " , gamemode_info [ game ] . poshname ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
}
2016-08-25 00:12:14 +00:00
}
return man ;
}
static void FS_AppendManifestGameArguments ( ftemanifest_t * man )
{
int i ;
if ( ! man )
return ;
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckParm ( " -basegame " ) ;
if ( i )
{
do
2012-11-27 03:23:19 +00:00
{
2016-08-25 00:12:14 +00:00
Cmd_TokenizeString ( va ( " basegame \" %s \" " , com_argv [ i + 1 ] ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckNextParm ( " -basegame " , i ) ;
2013-06-23 02:17:02 +00:00
}
2016-08-25 00:12:14 +00:00
while ( i & & i < com_argc - 1 ) ;
}
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckParm ( " -game " ) ;
if ( i )
{
do
2013-06-23 02:17:02 +00:00
{
2016-08-25 00:12:14 +00:00
Cmd_TokenizeString ( va ( " gamedir \" %s \" " , com_argv [ i + 1 ] ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckNextParm ( " -game " , i ) ;
2013-06-23 02:17:02 +00:00
}
2016-08-25 00:12:14 +00:00
while ( i & & i < com_argc - 1 ) ;
}
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckParm ( " +gamedir " ) ;
if ( i )
{
do
2013-06-23 02:17:02 +00:00
{
2016-08-25 00:12:14 +00:00
Cmd_TokenizeString ( va ( " gamedir \" %s \" " , com_argv [ i + 1 ] ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
2013-06-23 02:17:02 +00:00
2016-08-25 00:12:14 +00:00
i = COM_CheckNextParm ( " +gamedir " , i ) ;
2012-11-27 03:23:19 +00:00
}
2016-08-25 00:12:14 +00:00
while ( i & & i < com_argc - 1 ) ;
2012-11-27 03:23:19 +00:00
}
2013-06-23 02:17:02 +00:00
}
2016-02-15 06:01:17 +00:00
# ifdef WEBCLIENT
2013-06-23 02:17:02 +00:00
static char * FS_RelativeURL ( char * base , char * file , char * buffer , int bufferlen )
{
//fixme: cope with windows paths
2014-10-29 05:03:03 +00:00
qboolean baseisurl = base ? ! ! strchr ( base , ' : ' ) : false ;
2013-06-23 02:17:02 +00:00
qboolean fileisurl = ! ! strchr ( file , ' : ' ) ;
2013-06-23 03:59:48 +00:00
//qboolean baseisabsolute = (*base == '/' || *base == '\\');
2013-06-23 02:17:02 +00:00
qboolean fileisabsolute = ( * file = = ' / ' | | * file = = ' \\ ' ) ;
char * ebase ;
2014-10-29 05:03:03 +00:00
if ( fileisurl | | ! base )
2013-06-23 02:17:02 +00:00
return file ;
if ( fileisabsolute )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
if ( baseisurl )
{
ebase = strchr ( base , ' : ' ) ;
ebase + + ;
while ( * ebase = = ' / ' )
ebase + + ;
while ( * ebase & & * ebase ! = ' / ' )
ebase + + ;
}
else
ebase = base ;
2005-08-26 22:52:26 +00:00
}
2013-06-23 02:17:02 +00:00
else
ebase = COM_SkipPath ( base ) ;
memcpy ( buffer , base , ebase - base ) ;
strcpy ( buffer + ( ebase - base ) , file ) ;
return buffer ;
}
static struct dl_download * curpackagedownload ;
2015-04-14 23:12:17 +00:00
static enum manifestdeptype_e fspdl_type ;
2015-09-07 14:34:39 +00:00
static enum {
2016-02-15 06:01:17 +00:00
X_DLONLY , //simple pk3 file
X_COPY , //we copy it from an existing install (ie: special install path for total conversion)
X_MULTIUNZIP , //zip with multiple files that need extracting
X_UNZIP , //pull a single file from a zip
X_GZ , //dlonly+ungzip
X_XZ //dlonly+unxzip
2015-09-07 14:34:39 +00:00
} fspdl_extracttype ;
2014-10-29 05:03:03 +00:00
static char fspdl_internalname [ MAX_QPATH ] ;
2013-06-23 02:17:02 +00:00
static char fspdl_temppath [ MAX_OSPATH ] ;
static char fspdl_finalpath [ MAX_OSPATH ] ;
static void FS_BeginNextPackageDownload ( void ) ;
2015-04-14 23:12:17 +00:00
qboolean FS_DownloadingPackage ( void )
{
2016-11-25 08:14:54 +00:00
if ( PM_IsApplying ( ) )
return true ;
2015-04-14 23:12:17 +00:00
return ! fs_manifest | | ! ! curpackagedownload ;
}
//vfsfile_t *FS_DecompressXZip(vfsfile_t *infile, vfsfile_t *outfile);
vfsfile_t * FS_XZ_DecompressWriteFilter ( vfsfile_t * infile ) ;
vfsfile_t * FS_GZ_DecompressWriteFilter ( vfsfile_t * outfile , qboolean autoclosefile ) ;
static void FS_ExtractPackage ( searchpathfuncs_t * archive , flocation_t * loc , const char * origname , const char * finalname )
{
vfsfile_t * in = archive - > OpenVFS ( archive , loc , " rb " ) ;
if ( in )
{
vfsfile_t * out = VFSOS_Open ( finalname , " wb " ) ;
qofs_t remaining = VFS_GETLEN ( in ) ;
size_t count ;
if ( out )
{
char buf [ 65536 ] ;
while ( remaining )
{
if ( remaining < sizeof ( buf ) )
count = remaining ;
else
count = sizeof ( buf ) ;
VFS_READ ( in , buf , count ) ;
VFS_WRITE ( out , buf , count ) ;
remaining - = count ;
}
VFS_CLOSE ( out ) ;
}
else
Con_Printf ( " Unable to write %s \n " , finalname ) ;
VFS_CLOSE ( in ) ;
}
else
Con_Printf ( " Unable to read %s \n " , origname ) ;
}
static int QDECL FS_ExtractAllPackages ( const char * fname , qofs_t fsize , time_t mtime , void * parm , searchpathfuncs_t * spath )
{
//okay, this package naming thing is getting stupid.
flocation_t loc ;
int status = FF_NOTFOUND ;
status = spath - > FindFile ( spath , & loc , fname , NULL ) ;
//FIXME: symlinks?
if ( status = = FF_FOUND )
FS_ExtractPackage ( spath , & loc , fname , va ( " %s%s " , ( const char * ) parm , fname ) ) ;
return 1 ;
}
static void FS_PackagePrompt ( char * finalpath , char * filename , char * game )
{
static char existingbase [ MAX_OSPATH ] ;
static char prevgame [ 64 ] ;
vfsfile_t * in = NULL ;
const char * posh = NULL ;
int i ;
if ( game )
{
for ( i = 0 ; i < sizeof ( gamemode_info ) / sizeof ( gamemode_info [ 0 ] ) ; i + + )
{
if ( ! Q_strcasecmp ( gamemode_info [ i ] . poshname , gamemode_info [ i ] . argname + 1 ) )
{
posh = gamemode_info [ i ] . poshname ;
break ;
}
}
if ( * existingbase & & ! strcmp ( prevgame , game ) )
{
in = VFSOS_Open ( va ( " %s/%s " , existingbase , filename ) , " rb " ) ;
if ( ! in )
in = VFSOS_Open ( va ( " %s/%s " , existingbase , COM_SkipPath ( filename ) ) , " rb " ) ;
}
Q_strncpyz ( prevgame , game , sizeof ( prevgame ) ) ;
if ( ! posh )
posh = game ;
else if ( ! in & & Sys_FindGameData ( NULL , game , existingbase , sizeof ( existingbase ) , false ) )
{
in = VFSOS_Open ( va ( " %s/%s " , existingbase , filename ) , " rb " ) ;
if ( ! in )
in = VFSOS_Open ( va ( " %s/%s " , existingbase , COM_SkipPath ( filename ) ) , " rb " ) ;
}
}
while ( ! in & & Sys_DoDirectoryPrompt ( existingbase , sizeof ( existingbase ) , posh , NULL ) )
{
in = VFSOS_Open ( va ( " %s/%s " , existingbase , filename ) , " rb " ) ;
if ( ! in )
in = VFSOS_Open ( va ( " %s/%s " , existingbase , COM_SkipPath ( filename ) ) , " rb " ) ;
}
if ( in )
{
vfsfile_t * out = VFSOS_Open ( finalpath , " wb " ) ;
qofs_t remaining = VFS_GETLEN ( in ) ;
size_t count ;
if ( out )
{
char buf [ 65536 ] ;
while ( remaining )
{
if ( remaining < sizeof ( buf ) )
count = remaining ;
else
count = sizeof ( buf ) ;
VFS_READ ( in , buf , count ) ;
VFS_WRITE ( out , buf , count ) ;
remaining - = count ;
}
VFS_CLOSE ( out ) ;
}
else
Con_Printf ( " Unable to write %s \n " , finalpath ) ;
VFS_CLOSE ( in ) ;
}
else
Con_Printf ( " Unable to read %s%s \n " , existingbase , filename ) ;
}
2013-06-23 02:17:02 +00:00
static void FS_PackageDownloaded ( struct dl_download * dl )
{
curpackagedownload = NULL ;
2016-07-12 00:40:13 +00:00
2013-06-23 02:17:02 +00:00
if ( dl - > file )
2005-08-26 22:52:26 +00:00
{
2013-06-23 02:17:02 +00:00
VFS_CLOSE ( dl - > file ) ;
dl - > file = NULL ;
}
2015-04-14 23:12:17 +00:00
if ( dl - > status = = DL_FAILED )
Con_Printf ( " download for %s:%s failed \n " , fspdl_finalpath , fspdl_internalname ) ;
2013-06-23 02:17:02 +00:00
if ( dl - > status = = DL_FINISHED )
{
//rename the file as needed.
COM_CreatePath ( fspdl_finalpath ) ;
2014-10-29 05:03:03 +00:00
2015-09-07 14:34:39 +00:00
if ( fspdl_extracttype = = X_UNZIP | | fspdl_extracttype = = X_MULTIUNZIP ) //if zip...
2014-10-29 05:03:03 +00:00
{ //archive
2016-07-12 00:40:13 +00:00
searchpathfuncs_t * archive = FSZIP_LoadArchive ( VFSOS_Open ( fspdl_temppath , " rb " ) , dl - > url , " " ) ;
2014-10-29 05:03:03 +00:00
if ( archive )
{
flocation_t loc ;
2015-09-07 14:34:39 +00:00
if ( fspdl_extracttype = = X_MULTIUNZIP )
2014-10-29 05:03:03 +00:00
{
2015-04-14 23:12:17 +00:00
char * f = fspdl_internalname ;
char * e ;
for ( f = fspdl_internalname ; * f ; f = e )
2014-10-29 05:03:03 +00:00
{
2015-04-14 23:12:17 +00:00
e = strchr ( f , ' : ' ) ;
if ( e )
* e + + = 0 ;
else
e = f + strlen ( f ) ;
if ( strchr ( f , ' * ' ) )
archive - > EnumerateFiles ( archive , f , FS_ExtractAllPackages , fspdl_finalpath ) ;
else
2014-10-29 05:03:03 +00:00
{
2015-04-14 23:12:17 +00:00
int status = archive - > FindFile ( archive , & loc , f , NULL ) ;
if ( status = = FF_FOUND )
FS_ExtractPackage ( archive , & loc , f , va ( " %s%s " , fspdl_finalpath , f ) ) ;
2014-10-29 05:03:03 +00:00
}
}
}
else
{
2015-04-14 23:12:17 +00:00
flocation_t loc ;
int status = FF_NOTFOUND ;
//FIXME: loop through all other packages to extract all of them as appropriate
if ( status = = FF_NOTFOUND )
status = archive - > FindFile ( archive , & loc , fspdl_internalname , NULL ) ;
if ( status = = FF_NOTFOUND )
status = archive - > FindFile ( archive , & loc , COM_SkipPath ( fspdl_internalname ) , NULL ) ;
if ( status = = FF_FOUND )
FS_ExtractPackage ( archive , & loc , fspdl_internalname , fspdl_finalpath ) ;
else
{
Con_Printf ( " Unable to find %s in %s \n " , fspdl_internalname , fspdl_temppath ) ;
}
2014-10-29 05:03:03 +00:00
}
archive - > ClosePath ( archive ) ;
}
}
else
2009-03-03 01:52:30 +00:00
{
2014-10-29 05:03:03 +00:00
//direct file
if ( ! Sys_Rename ( fspdl_temppath , fspdl_finalpath ) )
{
Con_Printf ( " Unable to rename \" %s \" to \" %s \" \n " , fspdl_temppath , fspdl_finalpath ) ;
}
2016-11-25 08:14:54 +00:00
// else
// PM_AddDownloadedPackage(fspdl_finalpath);
2013-06-23 02:17:02 +00:00
}
}
Sys_remove ( fspdl_temppath ) ;
2014-09-02 02:44:43 +00:00
fs_restarts + + ;
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( fs_manifest , true , false ) ;
2013-06-23 02:17:02 +00:00
FS_BeginNextPackageDownload ( ) ;
}
2015-04-14 23:12:17 +00:00
static qboolean FS_BeginPackageDownload ( struct manpack_s * pack , char * baseurl , qboolean allownoncache )
2013-06-23 02:17:02 +00:00
{
2015-04-14 23:12:17 +00:00
char * crcstr = " " ;
2013-06-23 02:17:02 +00:00
vfsfile_t * check ;
2015-04-14 23:12:17 +00:00
vfsfile_t * tmpf ;
2013-06-23 02:17:02 +00:00
2015-04-14 23:12:17 +00:00
char buffer [ MAX_OSPATH ] , * url ;
2015-09-07 14:34:39 +00:00
qboolean multiex = false ;
//check this package's conditional
if ( pack - > condition )
2013-06-23 02:17:02 +00:00
{
2015-09-07 14:34:39 +00:00
if ( ! If_EvaluateBoolean ( pack - > condition , RESTRICT_LOCAL ) )
return false ;
}
if ( pack - > type = = mdt_installation )
{ //libraries are in the root directory. we allow extracting multiple of them from a zip, etc.
//they are not packages and thus do NOT support crcs.
2015-04-14 23:12:17 +00:00
char * s , * e ;
2015-09-07 14:34:39 +00:00
if ( ! allownoncache ) //don't even THINK about allowing the download unless its part of an initial install.
return false ;
2015-04-14 23:12:17 +00:00
for ( s = pack - > path ; * s ; s = e )
{
while ( * s = = ' : ' )
s + + ;
e = strchr ( s , ' : ' ) ;
if ( ! e )
e = s + strlen ( s ) ;
if ( e - s > = sizeof ( buffer ) )
continue ;
memcpy ( buffer , s , e - s ) ;
buffer [ e - s ] = 0 ;
2013-06-23 02:17:02 +00:00
2015-04-14 23:12:17 +00:00
check = FS_OpenVFS ( buffer , " rb " , FS_ROOT ) ;
if ( check )
{
VFS_CLOSE ( check ) ;
continue ;
}
break ;
}
if ( ! * s ) //all files were already present, apparently
return false ;
}
else
{
2014-03-30 08:55:06 +00:00
//check if we already have a version of the pak. if the user installed one, don't corrupt it with some unwanted pak. this may cause problems but whatever, user versitility wins.
//this matches the rules for loading packs too. double is utterly pointless.
2015-04-14 23:12:17 +00:00
check = FS_OpenVFS ( pack - > path , " rb " , FS_ROOT ) ;
2014-03-30 08:55:06 +00:00
if ( check )
{
VFS_CLOSE ( check ) ;
2015-04-14 23:12:17 +00:00
return false ;
2014-03-30 08:55:06 +00:00
}
//figure out what the cached name should be and see if we already have that or not
2015-04-14 23:12:17 +00:00
if ( pack - > crcknown )
crcstr = va ( " %#x " , pack - > crc ) ;
if ( ! pack - > crcknown & & allownoncache )
Q_strncpyz ( buffer , pack - > path , sizeof ( buffer ) ) ;
else if ( ! FS_GenCachedPakName ( pack - > path , crcstr , buffer , sizeof ( buffer ) ) )
return false ;
2013-06-23 02:17:02 +00:00
check = FS_OpenVFS ( buffer , " rb " , FS_ROOT ) ;
if ( check )
{
VFS_CLOSE ( check ) ;
2015-04-14 23:12:17 +00:00
return false ;
}
}
if ( pack - > type = = mdt_installation )
{
2015-09-07 14:34:39 +00:00
if ( ! strchr ( pack - > path , ' : ' ) )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
if ( ! FS_NativePath ( pack - > path , FS_ROOT , fspdl_finalpath , sizeof ( fspdl_finalpath ) ) | |
! FS_NativePath ( va ( " %s.tmp " , pack - > path ) , FS_ROOT , fspdl_temppath , sizeof ( fspdl_temppath ) ) )
return false ;
2015-04-14 23:12:17 +00:00
}
else
{
2015-09-07 14:34:39 +00:00
if ( ! FS_NativePath ( " " , FS_ROOT , fspdl_finalpath , sizeof ( fspdl_finalpath ) ) | |
! FS_NativePath ( va ( " %s.tmp " , fs_manifest - > installation ) , FS_ROOT , fspdl_temppath , sizeof ( fspdl_temppath ) ) )
return false ;
multiex = true ;
2015-04-14 23:12:17 +00:00
}
}
else
{
2014-03-30 08:55:06 +00:00
//figure out a temp name and figure out where we're going to get it from.
2015-09-07 14:34:39 +00:00
if ( ! FS_NativePath ( buffer , FS_ROOT , fspdl_finalpath , sizeof ( fspdl_finalpath ) ) )
return false ;
2015-04-14 23:12:17 +00:00
if ( ! pack - > crcknown & & allownoncache )
Q_strncpyz ( buffer , va ( " %s.tmp " , pack - > path ) , sizeof ( buffer ) ) ;
else if ( ! FS_GenCachedPakName ( va ( " %s.tmp " , pack - > path ) , crcstr , buffer , sizeof ( buffer ) ) )
return false ;
2015-09-07 14:34:39 +00:00
if ( ! FS_NativePath ( buffer , FS_ROOT , fspdl_temppath , sizeof ( fspdl_temppath ) ) )
return false ;
2015-04-14 23:12:17 +00:00
}
2013-06-23 02:17:02 +00:00
2015-04-14 23:12:17 +00:00
url = NULL ;
while ( ! url )
{
//ran out of mirrors?
if ( pack - > mirrornum = = ( sizeof ( pack - > mirrors ) / sizeof ( pack - > mirrors [ 0 ] ) ) )
break ;
if ( pack - > mirrors [ pack - > mirrornum ] )
url = FS_RelativeURL ( baseurl , pack - > mirrors [ pack - > mirrornum ] , buffer , sizeof ( buffer ) ) ;
pack - > mirrornum + + ;
}
//no valid mirrors
if ( ! url )
return false ;
2015-09-07 14:34:39 +00:00
fspdl_extracttype = X_DLONLY ;
if ( ! strncmp ( url , " gz: " , 3 ) )
{
url + = 3 ;
fspdl_extracttype = X_GZ ;
}
else if ( ! strncmp ( url , " xz: " , 3 ) )
{
url + = 3 ;
fspdl_extracttype = X_XZ ;
}
else if ( ! strncmp ( url , " unzip: " , 6 ) )
{
url + = 6 ;
fspdl_extracttype = X_UNZIP ;
}
else if ( ! strncmp ( url , " prompt: " , 7 ) )
{
url + = 7 ;
fspdl_extracttype = X_COPY ;
}
else
fspdl_extracttype = X_DLONLY ;
if ( fspdl_extracttype = = X_UNZIP | | fspdl_extracttype = = X_COPY )
{
char * o = fspdl_internalname ;
while ( o + 1 < fspdl_internalname + sizeof ( fspdl_internalname ) & & * url )
{
if ( * url = = ' , ' )
{
url + + ;
break ;
}
* o + + = * url + + ;
}
* o = 0 ;
}
else
* fspdl_internalname = 0 ;
2015-04-14 23:12:17 +00:00
2015-09-07 14:34:39 +00:00
if ( multiex )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
if ( fspdl_extracttype ! = X_UNZIP & & fspdl_extracttype ! = X_DLONLY )
return false ; //multiunzip is only supported with unzip urls... (or assumed if its a direct download
fspdl_extracttype = X_MULTIUNZIP ;
if ( ! * fspdl_internalname )
Q_strncpyz ( fspdl_internalname , pack - > path , sizeof ( fspdl_internalname ) ) ;
}
fspdl_type = pack - > type ;
2013-06-23 02:17:02 +00:00
2015-09-07 14:34:39 +00:00
if ( fspdl_extracttype = = X_COPY )
{
FS_PackagePrompt ( fspdl_finalpath , url , fspdl_internalname ) ;
2015-04-14 23:12:17 +00:00
return false ;
}
COM_CreatePath ( fspdl_temppath ) ;
tmpf = VFSOS_Open ( fspdl_temppath , " wb " ) ;
if ( tmpf )
{
2015-09-07 14:34:39 +00:00
switch ( fspdl_extracttype )
2015-04-14 23:12:17 +00:00
{
2015-09-07 14:34:39 +00:00
case X_XZ :
2015-04-14 23:12:17 +00:00
# ifdef AVAIL_XZDEC
tmpf = FS_XZ_DecompressWriteFilter ( tmpf ) ;
# else
VFS_CLOSE ( tmpf ) ;
tmpf = NULL ;
# endif
2015-09-07 14:34:39 +00:00
break ;
case X_GZ :
2017-02-19 00:15:42 +00:00
# ifdef AVAIL_GZDEC
2015-04-14 23:12:17 +00:00
tmpf = FS_GZ_DecompressWriteFilter ( tmpf , true ) ;
# else
VFS_CLOSE ( tmpf ) ;
tmpf = NULL ;
# endif
2015-09-07 14:34:39 +00:00
break ;
2016-02-15 06:01:17 +00:00
default :
break ;
2013-06-23 02:17:02 +00:00
}
2015-04-14 23:12:17 +00:00
if ( ! tmpf )
Sys_remove ( fspdl_temppath ) ;
}
if ( tmpf )
{
2014-03-30 08:55:06 +00:00
Con_Printf ( " Downloading %s from %s \n " , fspdl_finalpath , url ) ;
2013-06-23 02:17:02 +00:00
curpackagedownload = HTTP_CL_Get ( url , NULL , FS_PackageDownloaded ) ;
if ( curpackagedownload )
{
2015-04-14 23:12:17 +00:00
curpackagedownload - > file = tmpf ;
# ifdef MULTITHREAD
DL_CreateThread ( curpackagedownload , NULL , NULL ) ;
# endif
return true ;
}
VFS_CLOSE ( tmpf ) ;
Sys_remove ( fspdl_temppath ) ;
}
return false ;
}
static void FS_ManifestUpdated ( struct dl_download * dl ) ;
static void FS_BeginNextPackageDownload ( void )
{
int j ;
ftemanifest_t * man = fs_manifest ;
if ( curpackagedownload | | ! man | | com_installer )
return ;
if ( man - > doinstall )
{
for ( j = 0 ; j < sizeof ( fs_manifest - > package ) / sizeof ( fs_manifest - > package [ 0 ] ) ; j + + )
{
if ( man - > package [ j ] . type ! = mdt_installation )
continue ;
if ( FS_BeginPackageDownload ( & man - > package [ j ] , man - > updateurl , true ) )
return ;
}
}
if ( man - > updateurl & & ! man - > blockupdate )
{
man - > blockupdate = true ;
Con_Printf ( " Updating manifest from %s \n " , man - > updateurl ) ;
waitingformanifest + + ;
curpackagedownload = HTTP_CL_Get ( man - > updateurl , NULL , FS_ManifestUpdated ) ;
if ( curpackagedownload )
{
curpackagedownload - > user_ctx = man ;
2013-06-23 02:17:02 +00:00
return ;
}
}
2015-04-14 23:12:17 +00:00
for ( j = 0 ; j < sizeof ( fs_manifest - > package ) / sizeof ( fs_manifest - > package [ 0 ] ) ; j + + )
{
if ( man - > package [ j ] . type ! = mdt_singlepackage )
continue ;
if ( FS_BeginPackageDownload ( & man - > package [ j ] , man - > updateurl , false ) )
return ;
}
2013-06-23 02:17:02 +00:00
}
2014-03-30 08:55:06 +00:00
static void FS_ManifestUpdated ( struct dl_download * dl )
{
ftemanifest_t * man = fs_manifest ;
curpackagedownload = NULL ;
2015-04-14 23:12:17 +00:00
waitingformanifest - - ;
2014-03-30 08:55:06 +00:00
if ( dl - > file )
{
if ( dl - > user_ctx = = man )
{
size_t len = VFS_GETLEN ( dl - > file ) , len2 ;
char * fdata = BZ_Malloc ( len + 1 ) , * fdata2 = NULL ;
if ( fdata )
{
VFS_READ ( dl - > file , fdata , len ) ;
fdata [ len ] = 0 ;
man = FS_Manifest_Parse ( fs_manifest - > updatefile , fdata ) ;
if ( man )
{
//the updateurl MUST match the current one in order for the local version of the manifest to be saved (to avoid extra updates, and so it appears in the menu_mods)
//this is a paranoia measure to avoid too much damage from buggy/malicious proxies that return empty pages or whatever.
if ( man - > updateurl & & fs_manifest - > updateurl & & ! strcmp ( man - > updateurl , fs_manifest - > updateurl ) )
{
man - > blockupdate = true ; //don't download it multiple times. that's just crazy.
if ( man - > updatefile )
{
vfsfile_t * f2 = FS_OpenVFS ( fs_manifest - > updatefile , " rb " , FS_SYSTEM ) ;
if ( f2 )
{
len2 = VFS_GETLEN ( f2 ) ;
if ( len ! = len2 )
{
fdata2 = NULL ;
len2 = 0 ;
}
else
{
fdata2 = BZ_Malloc ( len2 ) ;
VFS_READ ( f2 , fdata2 , len2 ) ;
}
VFS_CLOSE ( f2 ) ;
if ( len = = len2 & & ! memcmp ( fdata , fdata2 , len ) )
{
//files match, no need to use this new manifest at all.
FS_Manifest_Free ( man ) ;
man = NULL ;
}
BZ_Free ( fdata2 ) ;
}
if ( man )
FS_WriteFile ( man - > updatefile , fdata , len , FS_SYSTEM ) ;
}
if ( man )
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( man , true , false ) ;
2014-03-30 08:55:06 +00:00
}
else
FS_Manifest_Free ( man ) ;
}
BZ_Free ( fdata ) ;
}
}
VFS_CLOSE ( dl - > file ) ;
dl - > file = NULL ;
}
FS_BeginNextPackageDownload ( ) ;
}
void FS_BeginManifestUpdates ( void )
{
ftemanifest_t * man = fs_manifest ;
2016-11-25 08:14:54 +00:00
PM_ManifestPackage ( man - > installupd , man - > doinstall ) ;
2014-03-30 08:55:06 +00:00
if ( curpackagedownload | | ! man )
return ;
if ( ! curpackagedownload )
FS_BeginNextPackageDownload ( ) ;
}
2013-06-23 02:17:02 +00:00
# else
2015-04-14 23:12:17 +00:00
qboolean FS_DownloadingPackage ( void )
{
return false ;
}
2014-03-30 08:55:06 +00:00
void FS_BeginManifestUpdates ( void )
2013-06-23 02:17:02 +00:00
{
}
# endif
2014-05-20 02:23:37 +00:00
qboolean FS_FoundManifest ( void * usr , ftemanifest_t * man )
{
if ( ! * ( ftemanifest_t * * ) usr )
{
* ( ftemanifest_t * * ) usr = man ;
return true ;
}
return false ;
}
2014-10-29 05:03:03 +00:00
//reads the default manifest based upon the basedir, the commandline arguments, the name of the exe, etc.
//may still fail if no game was identified.
//if fixedbasedir is true, stuff like -quake won't override/change the active basedir (ie: -basedir or gamedir switching without breaking gamedir)
ftemanifest_t * FS_ReadDefaultManifest ( char * newbasedir , size_t newbasedirsize , qboolean fixedbasedir )
{
2015-04-14 23:12:17 +00:00
int game = - 1 ;
2014-10-29 05:03:03 +00:00
ftemanifest_t * man = NULL ;
vfsfile_t * f ;
2015-04-14 23:12:17 +00:00
if ( ! man & & game = = - 1 )
{
2014-10-29 05:03:03 +00:00
# ifdef BRANDING_NAME
2015-04-14 23:12:17 +00:00
f = VFSOS_Open ( va ( " %s " STRINGIFY ( BRANDING_NAME ) " .fmf " , newbasedir ) , " rb " ) ;
if ( ! f )
2014-10-29 05:03:03 +00:00
# endif
2015-04-14 23:12:17 +00:00
f = VFSOS_Open ( va ( " %sdefault.fmf " , newbasedir ) , " rb " ) ;
if ( f )
{
size_t len = VFS_GETLEN ( f ) ;
char * fdata = BZ_Malloc ( len + 1 ) ;
if ( fdata )
{
VFS_READ ( f , fdata , len ) ;
fdata [ len ] = 0 ;
man = FS_Manifest_Parse ( NULL , fdata ) ;
BZ_Free ( fdata ) ;
}
VFS_CLOSE ( f ) ;
}
}
if ( ! man & & game = = - 1 )
2014-10-29 05:03:03 +00:00
{
2015-04-14 23:12:17 +00:00
int i ;
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
2014-10-29 05:03:03 +00:00
{
2015-04-14 23:12:17 +00:00
if ( COM_CheckParm ( gamemode_info [ i ] . argname ) )
{
game = i ;
break ;
}
2014-10-29 05:03:03 +00:00
}
2015-04-14 23:12:17 +00:00
}
if ( ! man & & game = = - 1 & & host_parms . manifest )
{
man = FS_Manifest_Parse ( va ( " %sdefault.fmf " , newbasedir ) , host_parms . manifest ) ;
if ( man )
man - > doinstall = true ;
2014-10-29 05:03:03 +00:00
}
if ( ! man )
{
2015-04-14 23:12:17 +00:00
if ( game = = - 1 )
game = FS_IdentifyDefaultGame ( newbasedir , newbasedirsize , fixedbasedir ) ;
2014-10-29 05:03:03 +00:00
if ( game ! = - 1 )
man = FS_GenerateLegacyManifest ( newbasedir , newbasedirsize , fixedbasedir , game ) ;
}
2016-08-25 00:12:14 +00:00
FS_AppendManifestGameArguments ( man ) ;
2014-10-29 05:03:03 +00:00
return man ;
}
2015-05-03 19:57:46 +00:00
qboolean FS_FixPath ( char * path , size_t pathsize )
{
size_t len = strlen ( path ) ;
if ( len )
{
if ( path [ len - 1 ] = = ' / ' )
return true ;
# ifdef _WIN32
if ( path [ len - 1 ] = = ' \\ ' )
return true ;
# endif
if ( len > = pathsize - 1 )
return false ;
path [ len ] = ' / ' ;
path [ len + 1 ] = 0 ;
}
return true ;
}
2013-06-23 02:17:02 +00:00
//this is potentially unsafe. needs lots of testing.
2015-04-14 23:12:17 +00:00
qboolean FS_ChangeGame ( ftemanifest_t * man , qboolean allowreloadconfigs , qboolean allowbasedirchange )
2013-06-23 02:17:02 +00:00
{
int i , j ;
char realpath [ MAX_OSPATH - 1 ] ;
char newbasedir [ MAX_OSPATH ] ;
2016-11-02 08:01:21 +00:00
char * olddownloadsurl ;
2013-06-23 02:17:02 +00:00
qboolean fixedbasedir ;
qboolean reloadconfigs = false ;
2013-10-29 17:38:22 +00:00
qboolean builtingame = false ;
2013-06-23 02:17:02 +00:00
flocation_t loc ;
2009-03-03 01:52:30 +00:00
2016-07-12 00:40:13 +00:00
char * vidfile [ ] = { " gfx.wad " , " gfx/conback.lmp " , //misc stuff
" gfx/palette.lmp " , " pics/colormap.pcx " } ; //palettes
2015-08-20 03:17:47 +00:00
searchpathfuncs_t * vidpath [ countof ( vidfile ) ] ;
2013-06-23 02:17:02 +00:00
//if any of these files change location, the configs will be re-execed.
//note that we reuse path handles if they're still valid, so we can just check the pointer to see if it got unloaded/replaced.
2015-08-20 03:17:47 +00:00
char * conffile [ ] = { " quake.rc " , " hexen.rc " , " default.cfg " , " server.cfg " } ;
searchpathfuncs_t * confpath [ countof ( conffile ) ] ;
for ( i = 0 ; i < countof ( vidfile ) ; i + + )
{
2015-10-11 11:34:58 +00:00
FS_FLocateFile ( vidfile [ i ] , FSLF_IFFOUND , & loc ) ; //q1
2015-08-20 03:17:47 +00:00
vidpath [ i ] = loc . search ? loc . search - > handle : NULL ;
}
for ( i = 0 ; i < countof ( conffile ) ; i + + )
2013-06-23 02:17:02 +00:00
{
2015-10-11 11:34:58 +00:00
FS_FLocateFile ( conffile [ i ] , FSLF_IFFOUND , & loc ) ; //q1
2013-12-19 16:36:17 +00:00
confpath [ i ] = loc . search ? loc . search - > handle : NULL ;
2013-06-23 02:17:02 +00:00
}
2015-04-21 04:12:00 +00:00
# if defined(NACL) || defined(FTE_TARGET_WEB) || defined(ANDROID) || defined(WINRT)
//these targets are considered to be sandboxed already, and have their own app-based base directory which they will always use.
Q_strncpyz ( newbasedir , host_parms . basedir , sizeof ( newbasedir ) ) ;
fixedbasedir = true ;
# else
2013-06-23 02:17:02 +00:00
i = COM_CheckParm ( " -basedir " ) ;
fixedbasedir = i & & i < com_argc - 1 ;
Q_strncpyz ( newbasedir , fixedbasedir ? com_argv [ i + 1 ] : host_parms . basedir , sizeof ( newbasedir ) ) ;
2015-04-21 04:12:00 +00:00
# endif
2013-06-23 02:17:02 +00:00
//make sure it has a trailing slash, or is empty. woo.
FS_CleanDir ( newbasedir , sizeof ( newbasedir ) ) ;
2015-04-14 23:12:17 +00:00
if ( ! allowreloadconfigs | | ! allowbasedirchange | | ( man & & fs_manifest & & ! Q_strcasecmp ( man - > installation , fs_manifest - > installation ) ) )
{
fixedbasedir = true ;
Q_strncpyz ( newbasedir , com_gamepath , sizeof ( newbasedir ) ) ;
}
2013-06-23 02:17:02 +00:00
if ( ! man )
{
//if we're already running a game, don't autodetect.
if ( fs_manifest )
return false ;
2014-10-29 05:03:03 +00:00
man = FS_ReadDefaultManifest ( newbasedir , sizeof ( newbasedir ) , fixedbasedir ) ;
2014-03-30 08:55:06 +00:00
2016-09-01 14:31:24 +00:00
if ( ! man )
{
int found = FS_EnumerateKnownGames ( FS_FoundManifest , & man ) ;
if ( found ! = 1 )
{
//we found more than 1 (or none)
//if we're a client, display a menu to pick between them (or display an error)
//servers can just use the first they find, they'd effectively just crash otherwise, but still give a warning.
if ( ! isDedicated )
man = NULL ;
else if ( found )
Con_Printf ( CON_WARNING " Warning: found multiple possible games. Using the first found. \n " ) ;
else
Con_Printf ( CON_ERROR " Error: unable to determine correct game/basedir. \n " ) ;
}
2014-05-20 02:23:37 +00:00
}
2014-03-30 08:55:06 +00:00
if ( ! man )
{
man = FS_Manifest_Parse ( NULL ,
2015-04-14 23:12:17 +00:00
" FTEManifestVer 1 \n "
2014-03-30 08:55:06 +00:00
" game \" \" \n "
" name \" " FULLENGINENAME " \" \n "
2014-08-27 08:41:31 +00:00
" defaultexec \\ \" vid_fullscreen 0; gl_font cour;vid_width 640; vid_height 480 \" \n "
2014-03-30 08:55:06 +00:00
) ;
}
2015-04-14 23:12:17 +00:00
if ( ! man )
Sys_Error ( " couldn't generate dataless manifest \n " ) ;
2013-06-23 02:17:02 +00:00
}
2016-11-02 08:01:21 +00:00
if ( fs_manifest & & fs_manifest - > downloadsurl )
olddownloadsurl = Z_StrDup ( fs_manifest - > downloadsurl ) ;
2016-11-25 08:14:54 +00:00
else if ( ! fs_manifest & & man - > downloadsurl )
olddownloadsurl = Z_StrDup ( man - > downloadsurl ) ;
2016-11-02 08:01:21 +00:00
else
olddownloadsurl = NULL ;
2013-06-23 02:17:02 +00:00
if ( man = = fs_manifest )
{
//don't close anything. theoretically nothing is changing, and we don't want to load new defaults either.
}
else if ( ! fs_manifest | | ! strcmp ( fs_manifest - > installation ? fs_manifest - > installation : " " , man - > installation ? man - > installation : " " ) )
{
if ( ! fs_manifest )
reloadconfigs = true ;
FS_Manifest_Free ( fs_manifest ) ;
}
else
{
2014-10-05 20:04:11 +00:00
FS_FreePaths ( ) ;
2013-06-23 02:17:02 +00:00
reloadconfigs = true ;
}
fs_manifest = man ;
2016-11-25 08:14:54 +00:00
if ( ! man - > doinstall & & strcmp ( man - > downloadsurl ? man - > downloadsurl : " " , olddownloadsurl ? olddownloadsurl : " " ) )
2016-11-02 08:01:21 +00:00
{ //make sure we only fuck over the user if this is a 'secure' manifest, and not hacked in some way.
Z_Free ( man - > downloadsurl ) ;
man - > downloadsurl = olddownloadsurl ;
}
else
Z_Free ( olddownloadsurl ) ;
2013-06-23 02:17:02 +00:00
if ( man - > installation & & * man - > installation )
{
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
{
if ( ! strcmp ( man - > installation , gamemode_info [ i ] . argname + 1 ) )
2009-03-03 01:52:30 +00:00
{
2013-06-23 02:17:02 +00:00
//if there's no base dirs, edit the manifest to give it its default ones.
for ( j = 0 ; j < sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) ; j + + )
2009-03-03 01:52:30 +00:00
{
2013-06-23 02:17:02 +00:00
if ( man - > gamepath [ j ] . path & & man - > gamepath [ j ] . base )
break ;
2012-11-27 03:23:19 +00:00
}
2013-06-23 02:17:02 +00:00
if ( j = = sizeof ( man - > gamepath ) / sizeof ( man - > gamepath [ 0 ] ) )
2012-11-27 03:23:19 +00:00
{
for ( j = 0 ; j < 4 ; j + + )
2013-06-23 02:17:02 +00:00
if ( gamemode_info [ i ] . dir [ j ] )
2010-11-02 23:17:25 +00:00
{
2013-06-23 02:17:02 +00:00
Cmd_TokenizeString ( va ( " basegame \" %s \" " , gamemode_info [ i ] . dir [ j ] ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
2010-11-02 23:17:25 +00:00
}
2012-11-27 03:23:19 +00:00
}
2013-06-23 02:17:02 +00:00
2016-07-21 19:27:59 +00:00
if ( ! man - > downloadsurl )
{
Cmd_TokenizeString ( va ( " downloadsurl \" %s \" " , gamemode_info [ i ] . downloadsurl ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
}
2014-12-23 15:26:42 +00:00
if ( ! man - > protocolname )
2012-11-27 03:23:19 +00:00
{
2013-06-23 02:17:02 +00:00
Cmd_TokenizeString ( va ( " protocolname \" %s \" " , gamemode_info [ i ] . protocolname ) , false , false ) ;
FS_Manifest_ParseTokens ( man ) ;
}
if ( ! man - > defaultexec & & gamemode_info [ i ] . customexec )
{
man - > defaultexec = Z_StrDup ( gamemode_info [ i ] . customexec ) ;
2009-03-03 01:52:30 +00:00
}
2013-06-23 02:17:02 +00:00
2013-10-29 17:38:22 +00:00
builtingame = true ;
2013-06-23 02:17:02 +00:00
if ( ! fixedbasedir & & ! FS_DirHasGame ( newbasedir , i ) )
2015-05-03 19:57:46 +00:00
if ( Sys_FindGameData ( man - > formalname , man - > installation , realpath , sizeof ( realpath ) , ! man - > doinstall ) & & FS_FixPath ( realpath , sizeof ( realpath ) ) & & FS_DirHasGame ( realpath , i ) )
2013-06-23 02:17:02 +00:00
Q_strncpyz ( newbasedir , realpath , sizeof ( newbasedir ) ) ;
break ;
2009-03-03 01:52:30 +00:00
}
}
2005-08-26 22:52:26 +00:00
}
2013-10-29 17:38:22 +00:00
2015-04-14 23:12:17 +00:00
if ( ! fixedbasedir )
2014-03-31 17:06:41 +00:00
{
if ( ! builtingame & & ! fixedbasedir & & ! FS_DirHasAPackage ( newbasedir , man ) )
2015-04-14 23:12:17 +00:00
{
2015-05-03 19:57:46 +00:00
if ( Sys_FindGameData ( man - > formalname , man - > installation , realpath , sizeof ( realpath ) , ! man - > doinstall ) & & FS_FixPath ( realpath , sizeof ( realpath ) ) & & FS_DirHasAPackage ( realpath , man ) )
2014-03-31 17:06:41 +00:00
Q_strncpyz ( newbasedir , realpath , sizeof ( newbasedir ) ) ;
2015-04-21 21:49:08 +00:00
# ifndef SERVERONLY
2015-04-14 23:12:17 +00:00
else
{
Z_Free ( man - > updatefile ) ;
man - > updatefile = NULL ;
com_installer = true ;
}
2015-04-21 21:49:08 +00:00
# endif
2015-04-14 23:12:17 +00:00
}
2014-03-31 17:06:41 +00:00
}
2015-04-14 23:12:17 +00:00
if ( ! fixedbasedir & & ! com_installer )
Q_strncpyz ( com_gamepath , newbasedir , sizeof ( com_gamepath ) ) ;
2013-06-23 02:17:02 +00:00
//make sure it has a trailing slash, or is empty. woo.
2014-03-30 08:55:06 +00:00
FS_CleanDir ( com_gamepath , sizeof ( com_gamepath ) ) ;
2014-12-23 15:26:42 +00:00
{
qboolean oldhome = com_homepathenabled ;
com_homepathenabled = com_homepathusable ;
if ( man - > disablehomedir & & ! COM_CheckParm ( " -usehome " ) )
com_homepathenabled = false ;
if ( com_homepathenabled ! = oldhome )
{
if ( com_homepathenabled )
Con_TPrintf ( " Using home directory \" %s \" \n " , com_homepath ) ;
else
Con_TPrintf ( " Disabled home directory suport \n " ) ;
}
}
2005-08-26 22:52:26 +00:00
2013-06-23 02:17:02 +00:00
# ifdef ANDROID
2005-08-26 22:52:26 +00:00
{
2016-02-10 23:23:43 +00:00
//write a .nomedia file to avoid people from getting random explosion sounds etc interspersed with their music
2013-06-23 02:17:02 +00:00
vfsfile_t * f ;
2016-02-10 23:23:43 +00:00
char nomedia [ MAX_OSPATH ] ;
//figure out the path we're going to end up writing to
if ( com_homepathenabled )
snprintf ( nomedia , sizeof ( nomedia ) , " %s%s " , com_homepath , " .nomedia " ) ;
else
snprintf ( nomedia , sizeof ( nomedia ) , " %s%s " , com_gamepath , " .nomedia " ) ;
//make sure it exists.
f = VFSOS_Open ( nomedia , " rb " ) ;
if ( ! f ) //don't truncate
{
COM_CreatePath ( nomedia ) ;
f = VFSOS_Open ( nomedia , " wb " ) ;
}
2013-06-23 02:17:02 +00:00
if ( f )
VFS_CLOSE ( f ) ;
}
# endif
2014-10-05 20:04:11 +00:00
if ( Sys_LockMutex ( fs_thread_mutex ) )
{
2016-07-12 00:40:13 +00:00
qboolean vidrestart = false ;
2014-10-05 20:04:11 +00:00
FS_ReloadPackFilesFlags ( ~ 0 ) ;
2013-06-23 02:17:02 +00:00
2016-02-15 06:01:17 +00:00
Sys_UnlockMutex ( fs_thread_mutex ) ;
2014-10-05 20:04:11 +00:00
FS_BeginManifestUpdates ( ) ;
2013-06-23 02:17:02 +00:00
2016-07-12 00:40:13 +00:00
# ifdef WEBCLIENT
if ( curpackagedownload & & fs_loadedcommand )
allowreloadconfigs = false ;
# endif
2014-10-05 20:04:11 +00:00
COM_CheckRegistered ( ) ;
2013-06-23 02:17:02 +00:00
2015-08-20 03:17:47 +00:00
2016-07-12 00:40:13 +00:00
if ( qrenderer ! = QR_NONE )
{
for ( i = 0 ; i < countof ( vidfile ) ; i + + )
2015-08-20 03:17:47 +00:00
{
2016-07-12 00:40:13 +00:00
FS_FLocateFile ( vidfile [ i ] , FSLF_IFFOUND , & loc ) ;
if ( vidpath [ i ] ! = ( loc . search ? loc . search - > handle : NULL ) )
2015-08-20 03:17:47 +00:00
{
2016-07-12 00:40:13 +00:00
vidrestart = true ;
Con_DPrintf ( " Restarting video because %s has changed \n " , vidfile [ i ] ) ;
2015-08-20 03:17:47 +00:00
}
}
2016-07-12 00:40:13 +00:00
}
2015-08-20 03:17:47 +00:00
2016-07-12 00:40:13 +00:00
if ( allowreloadconfigs )
{
2015-08-20 03:17:47 +00:00
for ( i = 0 ; i < countof ( conffile ) ; i + + )
2010-12-05 02:46:07 +00:00
{
2015-10-11 11:34:58 +00:00
FS_FLocateFile ( conffile [ i ] , FSLF_IFFOUND , & loc ) ;
2014-10-05 20:04:11 +00:00
if ( confpath [ i ] ! = ( loc . search ? loc . search - > handle : NULL ) )
{
reloadconfigs = true ;
Con_DPrintf ( " Reloading configs because %s has changed \n " , conffile [ i ] ) ;
}
2013-06-23 02:17:02 +00:00
}
2014-10-05 20:04:11 +00:00
if ( reloadconfigs )
2013-06-23 02:17:02 +00:00
{
2014-12-29 02:35:10 +00:00
Cvar_SetEngineDefault ( & fs_gamename , man - > formalname ? man - > formalname : " FTE " ) ;
2017-01-24 10:27:39 +00:00
Cvar_SetEngineDefault ( & pm_downloads_url , man - > downloadsurl ? man - > downloadsurl : " " ) ;
2014-12-29 02:35:10 +00:00
Cvar_SetEngineDefault ( & com_protocolname , man - > protocolname ? man - > protocolname : " FTE " ) ;
//FIXME: flag this instead and do it after a delay?
2014-12-23 15:26:42 +00:00
Cvar_ForceSet ( & fs_gamename , fs_gamename . enginevalue ) ;
2017-01-24 10:27:39 +00:00
Cvar_ForceSet ( & pm_downloads_url , pm_downloads_url . enginevalue ) ;
2014-12-23 15:26:42 +00:00
Cvar_ForceSet ( & com_protocolname , com_protocolname . enginevalue ) ;
2016-07-12 00:40:13 +00:00
vidrestart = false ;
2014-10-05 20:04:11 +00:00
if ( isDedicated )
{
# ifndef CLIENTONLY
SV_ExecInitialConfigs ( man - > defaultexec ? man - > defaultexec : " " ) ;
# endif
}
else
{
# ifndef SERVERONLY
CL_ExecInitialConfigs ( man - > defaultexec ? man - > defaultexec : " " ) ;
# endif
}
2013-06-23 02:17:02 +00:00
}
2015-08-20 03:17:47 +00:00
else if ( vidrestart )
2016-02-15 06:01:17 +00:00
{
# ifndef SERVERONLY
2015-08-20 03:17:47 +00:00
Cbuf_AddText ( " vid_reload \n " , RESTRICT_LOCAL ) ;
# endif
2016-07-12 00:40:13 +00:00
vidrestart = false ;
2016-02-15 06:01:17 +00:00
}
2016-07-12 00:40:13 +00:00
if ( fs_loadedcommand )
{
Cbuf_AddText ( fs_loadedcommand , RESTRICT_INSECURE ) ;
Z_Free ( fs_loadedcommand ) ;
fs_loadedcommand = NULL ;
}
}
if ( vidrestart )
{
# ifndef SERVERONLY
Cbuf_AddText ( " vid_reload \n " , RESTRICT_LOCAL ) ;
# endif
vidrestart = false ;
2013-06-23 02:17:02 +00:00
}
2014-02-07 08:38:40 +00:00
2014-10-05 20:04:11 +00:00
//rebuild the cache now, should be safe to waste some cycles on it
COM_FlushFSCache ( false , true ) ;
}
2010-12-05 02:46:07 +00:00
2013-06-23 02:17:02 +00:00
# ifndef SERVERONLY
Validation_FlushFileList ( ) ; //prevent previous hacks from making a difference.
# endif
2014-03-30 08:55:06 +00:00
{
2015-04-21 04:12:00 +00:00
void ( QDECL * callback ) ( struct cvar_s * var , char * oldvalue ) = fs_game . callback ;
2014-03-30 08:55:06 +00:00
fs_game . callback = NULL ;
Cvar_ForceSet ( & fs_game , FS_GetGamedir ( false ) ) ;
fs_game . callback = callback ;
}
2014-02-11 17:51:29 +00:00
# ifdef Q2SERVER
2014-03-30 08:55:06 +00:00
Cvar_ForceSet ( & fs_gamedir , va ( " %s%s " , com_gamepath , FS_GetGamedir ( false ) ) ) ;
Cvar_ForceSet ( & fs_basedir , com_gamepath ) ;
2014-02-11 17:51:29 +00:00
# endif
2013-06-23 02:17:02 +00:00
return true ;
}
2015-04-14 23:12:17 +00:00
void FS_CreateBasedir ( const char * path )
{
vfsfile_t * f ;
com_installer = false ;
Q_strncpyz ( com_gamepath , path , sizeof ( com_gamepath ) ) ;
COM_CreatePath ( com_gamepath ) ;
2016-11-25 08:14:54 +00:00
fs_manifest - > doinstall = true ;
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( fs_manifest , true , false ) ;
if ( host_parms . manifest )
{
f = FS_OpenVFS ( " default.fmf " , " wb " , FS_ROOT ) ;
if ( f )
{
VFS_WRITE ( f , host_parms . manifest , strlen ( host_parms . manifest ) ) ;
VFS_CLOSE ( f ) ;
}
}
}
2014-03-30 08:55:06 +00:00
typedef struct
{
int found ;
qboolean ( * callback ) ( void * usr , ftemanifest_t * man ) ;
void * usr ;
} fmfenums_t ;
2015-02-02 08:01:53 +00:00
static int QDECL FS_EnumerateFMFs ( const char * fname , qofs_t fsize , time_t mtime , void * inf , searchpathfuncs_t * spath )
2014-03-30 08:55:06 +00:00
{
fmfenums_t * e = inf ;
vfsfile_t * f = NULL ;
char * homem = va ( " %s%s " , com_homepathenabled ? com_homepath : com_gamepath , COM_SkipPath ( fname ) ) ;
if ( ! f ) //always try the homedir first, because that can be updated automagically.
f = VFSOS_Open ( fname , " rb " ) ;
if ( ! f )
{ //*then* try in packages or basedir etc.
if ( spath )
{
flocation_t loc ;
if ( spath - > FindFile ( spath , & loc , fname , NULL ) )
f = spath - > OpenVFS ( spath , & loc , " rb " ) ;
}
else
f = VFSOS_Open ( fname , " rb " ) ;
}
if ( f )
{
size_t l = VFS_GETLEN ( f ) ;
char * data = Z_Malloc ( l + 1 ) ;
if ( data )
{
ftemanifest_t * man ;
VFS_READ ( f , data , l ) ;
data [ l ] = 0 ; //just in case.
man = FS_Manifest_Parse ( homem , data ) ;
if ( man )
{
if ( e - > callback ( e - > usr , man ) )
e - > found + + ;
else
FS_Manifest_Free ( man ) ;
}
Z_Free ( data ) ;
}
VFS_CLOSE ( f ) ;
}
return true ;
}
2016-09-01 14:31:24 +00:00
int FS_EnumerateKnownGames ( qboolean ( * callback ) ( void * usr , ftemanifest_t * man ) , void * usr )
2014-03-30 08:55:06 +00:00
{
int i ;
char basedir [ MAX_OSPATH ] ;
fmfenums_t e ;
e . found = 0 ;
e . callback = callback ;
e . usr = usr ;
//-basepack is primarily an android feature, where the apk file is specified.
//this allows custom mods purely by customising the apk
i = COM_CheckParm ( " -basepack " ) ;
while ( i & & i < com_argc - 1 )
{
const char * pakname = com_argv [ i + 1 ] ;
searchpathfuncs_t * pak ;
vfsfile_t * vfs = VFSOS_Open ( pakname , " rb " ) ;
pak = FS_OpenPackByExtension ( vfs , pakname ) ;
if ( pak )
{
pak - > EnumerateFiles ( pak , " *.fmf " , FS_EnumerateFMFs , & e ) ;
pak - > ClosePath ( pak ) ;
}
i = COM_CheckNextParm ( " -basepack " , i ) ;
}
//okay, no manifests in the basepack, try looking in the basedir.
//this defaults to the working directory. perhaps try the exe's location instead?
if ( ! e . found )
Sys_EnumerateFiles ( host_parms . basedir , " *.fmf " , FS_EnumerateFMFs , & e , NULL ) ;
//right, no fmf files anywhere.
//just make stuff up from whatever games they may have installed on their system.
if ( ! e . found )
{
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
{
2015-04-14 23:12:17 +00:00
if ( gamemode_info [ i ] . manifestfile | | Sys_FindGameData ( NULL , gamemode_info [ i ] . argname + 1 , basedir , sizeof ( basedir ) , true ) )
2014-03-30 08:55:06 +00:00
{
ftemanifest_t * man = FS_GenerateLegacyManifest ( NULL , 0 , true , i ) ;
if ( e . callback ( e . usr , man ) )
e . found + + ;
else
FS_Manifest_Free ( man ) ;
}
}
}
2016-09-01 14:31:24 +00:00
return e . found ;
2014-03-30 08:55:06 +00:00
}
2014-10-11 19:39:45 +00:00
//attempts to find a new basedir for 'input', changing to it as appropriate
//returns fixed up filename relative to the new gamedir.
//input must be an absolute path.
qboolean FS_FixupGamedirForExternalFile ( char * input , char * filename , size_t fnamelen )
{
char syspath [ MAX_OSPATH ] ;
char gamepath [ MAX_OSPATH ] ;
void * iterator ;
char * sep , * bs ;
char * src = NULL ;
Q_strncpyz ( filename , input , fnamelen ) ;
iterator = NULL ;
while ( COM_IteratePaths ( & iterator , syspath , sizeof ( syspath ) , gamepath , sizeof ( gamepath ) ) )
{
if ( ! Q_strncasecmp ( syspath , filename , strlen ( syspath ) ) )
{
src = filename + strlen ( syspath ) ;
memmove ( filename , src , strlen ( src ) + 1 ) ;
break ;
}
}
if ( ! src )
{
for ( ; ; )
{
sep = strchr ( filename , ' \\ ' ) ;
if ( sep )
* sep = ' / ' ;
else
break ;
}
for ( sep = NULL ; ; )
{
bs = sep ;
sep = strrchr ( filename , ' / ' ) ;
if ( bs )
* bs = ' / ' ;
if ( sep )
{
int game ;
* sep = 0 ;
if ( strchr ( filename , ' / ' ) ) //make sure there's always at least one /
{
char temp [ MAX_OSPATH ] ;
Q_snprintfz ( temp , sizeof ( temp ) , " %s/ " , filename ) ;
game = FS_IdentifyDefaultGameFromDir ( temp ) ;
if ( game ! = - 1 )
{
static char newbase [ MAX_OSPATH ] ;
if ( ! host_parms . basedir | | strcmp ( host_parms . basedir , filename ) )
{
Con_Printf ( " switching basedir+game to %s for %s \n " , filename , input ) ;
Q_strncpyz ( newbase , filename , sizeof ( newbase ) ) ;
host_parms . basedir = newbase ;
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( FS_GenerateLegacyManifest ( NULL , 0 , true , game ) , true , true ) ;
2014-10-11 19:39:45 +00:00
}
* sep = ' / ' ;
sep = NULL ;
src = filename + strlen ( host_parms . basedir ) ;
memmove ( filename , src , strlen ( src ) + 1 ) ;
break ;
}
}
}
else
break ;
}
if ( sep )
* sep = ' / ' ;
}
if ( ! src & & host_parms . binarydir & & ! Q_strncasecmp ( host_parms . binarydir , filename , strlen ( host_parms . binarydir ) ) )
{
src = filename + strlen ( host_parms . binarydir ) ;
memmove ( filename , src , strlen ( src ) + 1 ) ;
}
if ( ! src & & host_parms . basedir & & ! Q_strncasecmp ( host_parms . basedir , filename , strlen ( host_parms . basedir ) ) )
{
src = filename + strlen ( host_parms . basedir ) ;
memmove ( filename , src , strlen ( src ) + 1 ) ;
}
if ( ! src )
{
Q_snprintfz ( filename , fnamelen , " #%s " , input ) ;
return false ;
}
if ( * filename = = ' / ' | | * filename = = ' \\ ' )
memmove ( filename , filename + 1 , strlen ( filename + 1 ) + 1 ) ;
sep = strchr ( filename , ' / ' ) ;
bs = strchr ( filename , ' \\ ' ) ;
if ( bs & & ( ! sep | | bs < sep ) )
sep = bs ;
if ( sep )
{
Con_Printf ( " switching gamedir for %s \n " , filename ) ;
* sep = 0 ;
2015-05-14 03:06:58 +00:00
COM_Gamedir ( filename , NULL ) ;
2014-10-11 19:39:45 +00:00
memmove ( filename , sep + 1 , strlen ( sep + 1 ) + 1 ) ;
return true ;
}
Q_snprintfz ( filename , fnamelen , " #%s " , input ) ;
return false ;
}
2013-06-23 02:17:02 +00:00
void FS_ChangeGame_f ( void )
{
int i ;
char * arg = Cmd_Argv ( 1 ) ;
2014-06-24 03:02:32 +00:00
//don't execute this if we're executing rcon commands, as this can change game directories.
if ( cmd_blockwait )
return ;
2013-06-23 02:17:02 +00:00
if ( ! * arg )
{
Con_Printf ( " Valid games are: \n " ) ;
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
{
Con_Printf ( " %s \n " , gamemode_info [ i ] . argname + 1 ) ;
}
}
else
{
for ( i = 0 ; gamemode_info [ i ] . argname ; i + + )
{
2014-02-07 08:38:40 +00:00
if ( ! Q_strcasecmp ( gamemode_info [ i ] . argname + 1 , arg ) )
2013-06-23 02:17:02 +00:00
{
Con_Printf ( " Switching to %s \n " , gamemode_info [ i ] . argname + 1 ) ;
2016-11-20 20:52:41 +00:00
PM_Shutdown ( ) ;
2015-04-14 23:12:17 +00:00
FS_ChangeGame ( FS_GenerateLegacyManifest ( NULL , 0 , true , i ) , true , true ) ;
2013-06-23 02:17:02 +00:00
return ;
2010-12-05 02:46:07 +00:00
}
2005-08-26 22:52:26 +00:00
}
2013-08-06 10:48:51 +00:00
2013-08-21 08:06:35 +00:00
# ifndef SERVERONLY
2013-08-06 10:48:51 +00:00
if ( ! Host_RunFile ( arg , strlen ( arg ) , NULL ) )
Con_Printf ( " Game unknown \n " ) ;
2013-08-21 08:06:35 +00:00
# endif
2005-08-26 22:52:26 +00:00
}
2013-06-23 02:17:02 +00:00
}
2016-07-12 00:40:13 +00:00
void FS_ChangeMod_f ( void )
{
char cachename [ 512 ] ;
struct gamepacks packagespaths [ 16 ] ;
int i ;
int packages = 0 ;
const char * arg = " ? " ;
qboolean okay = false ;
if ( Cmd_IsInsecure ( ) )
return ;
Z_Free ( fs_loadedcommand ) ;
fs_loadedcommand = NULL ;
memset ( packagespaths , 0 , sizeof ( packagespaths ) ) ;
for ( i = 1 ; ; )
{
if ( i = = Cmd_Argc ( ) )
{
okay = true ;
break ;
}
arg = Cmd_Argv ( i + + ) ;
if ( ! strcmp ( arg , " package " ) )
{
arg = Cmd_Argv ( i + + ) ;
2016-11-20 20:52:41 +00:00
if ( packages = = countof ( packagespaths ) ) //must leave space for one, as a terminator.
continue ;
if ( FS_PathURLCache ( arg , cachename , sizeof ( cachename ) ) )
{
packagespaths [ packages ] . url = Z_StrDup ( arg ) ;
packagespaths [ packages ] . path = Z_StrDup ( cachename ) ;
packages + + ;
}
2016-07-12 00:40:13 +00:00
}
else if ( ! strcmp ( arg , " prefix " ) )
{
if ( ! packages )
break ;
arg = Cmd_Argv ( i + + ) ;
packagespaths [ packages - 1 ] . subpath = Z_StrDup ( arg ) ;
}
else if ( ! strcmp ( arg , " map " ) )
{
Z_Free ( fs_loadedcommand ) ;
arg = va ( " map \" %s \" \n " , Cmd_Argv ( i + + ) ) ;
fs_loadedcommand = Z_StrDup ( arg ) ;
}
else if ( ! strcmp ( arg , " restart " ) )
{
Z_Free ( fs_loadedcommand ) ;
fs_loadedcommand = Z_StrDup ( " restart \n " ) ;
}
else
break ;
}
if ( okay )
COM_Gamedir ( " " , packagespaths ) ;
else
{
Con_Printf ( " unsupported args: %s \n " , arg ) ;
Z_Free ( fs_loadedcommand ) ;
fs_loadedcommand = NULL ;
}
for ( i = 0 ; i < packages ; i + + )
{
Z_Free ( packagespaths [ i ] . url ) ;
Z_Free ( packagespaths [ i ] . path ) ;
Z_Free ( packagespaths [ i ] . subpath ) ;
}
}
2013-06-23 02:17:02 +00:00
void FS_ShowManifest_f ( void )
{
if ( fs_manifest )
FS_Manifest_Print ( fs_manifest ) ;
else
Con_Printf ( " no manifest loaded... \n " ) ;
}
/*
= = = = = = = = = = = = = = = =
COM_InitFilesystem
note : does not actually load any packs , just makes sure the basedir + cvars + etc is set up . vfs_fopens will still fail .
= = = = = = = = = = = = = = = =
*/
void COM_InitFilesystem ( void )
{
int i ;
char * ev ;
qboolean usehome ;
FS_RegisterDefaultFileSystems ( ) ;
Cmd_AddCommand ( " fs_restart " , FS_ReloadPackFiles_f ) ;
2016-07-12 00:40:13 +00:00
Cmd_AddCommandD ( " fs_changegame " , FS_ChangeGame_f , " Switch between different manifests (or registered games) " ) ;
Cmd_AddCommandD ( " fs_changemod " , FS_ChangeMod_f , " Provides the backend functionality of a transient online installer. Eg, for quaddicted's map/mod database. " ) ;
2013-06-23 02:17:02 +00:00
Cmd_AddCommand ( " fs_showmanifest " , FS_ShowManifest_f ) ;
2017-02-19 00:15:42 +00:00
Cmd_AddCommand ( " fs_flush " , COM_RefreshFSCache_f ) ;
2013-06-23 02:17:02 +00:00
//
// -basedir <path>
// Overrides the system supplied base directory (under id1)
//
i = COM_CheckParm ( " -basedir " ) ;
if ( i & & i < com_argc - 1 )
2014-03-30 08:55:06 +00:00
strcpy ( com_gamepath , com_argv [ i + 1 ] ) ;
2013-06-23 02:17:02 +00:00
else
2014-03-30 08:55:06 +00:00
strcpy ( com_gamepath , host_parms . basedir ) ;
2013-06-23 02:17:02 +00:00
2014-03-30 08:55:06 +00:00
FS_CleanDir ( com_gamepath , sizeof ( com_gamepath ) ) ;
2013-06-23 02:17:02 +00:00
2014-02-11 17:51:29 +00:00
Cvar_Register ( & cfg_reload_on_gamedir , " Filesystem " ) ;
Cvar_Register ( & com_fs_cache , " Filesystem " ) ;
Cvar_Register ( & fs_gamename , " Filesystem " ) ;
2017-01-24 10:27:39 +00:00
Cvar_Register ( & pm_downloads_url , " Filesystem " ) ;
Cvar_Register ( & pm_autoupdate , " Filesystem " ) ;
2013-06-23 02:17:02 +00:00
Cvar_Register ( & com_protocolname , " Server Info " ) ;
2014-02-11 17:51:29 +00:00
Cvar_Register ( & fs_game , " Filesystem " ) ;
# ifdef Q2SERVER
Cvar_Register ( & fs_gamedir , " Filesystem " ) ;
Cvar_Register ( & fs_basedir , " Filesystem " ) ;
# endif
2009-03-03 01:52:30 +00:00
2008-06-13 05:03:54 +00:00
usehome = false ;
2005-08-26 22:52:26 +00:00
2016-08-25 00:12:14 +00:00
//assume the home directory is the working directory.
* com_homepath = ' \0 ' ;
2015-09-14 15:20:09 +00:00
# if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT)
2005-08-26 22:52:26 +00:00
{ //win32 sucks.
2015-05-14 03:06:58 +00:00
HRESULT ( WINAPI * dSHGetFolderPathW ) ( HWND hwndOwner , int nFolder , HANDLE hToken , DWORD dwFlags , wchar_t * pszPath ) = NULL ;
dllfunction_t funcs [ ] =
{
{ ( void * * ) & dSHGetFolderPathW , " SHGetFolderPathW " } ,
{ NULL , NULL }
} ;
2008-06-13 05:03:54 +00:00
DWORD winver = ( DWORD ) LOBYTE ( LOWORD ( GetVersion ( ) ) ) ;
2015-05-14 03:06:58 +00:00
/*HMODULE shfolder =*/ Sys_LoadLibrary ( " shfolder.dll " , funcs ) ;
2008-06-13 05:03:54 +00:00
2015-05-14 03:06:58 +00:00
if ( dSHGetFolderPathW )
2008-06-13 05:03:54 +00:00
{
2015-05-14 03:06:58 +00:00
wchar_t wfolder [ MAX_PATH ] ;
2016-07-12 00:40:13 +00:00
char folder [ MAX_OSPATH ] ;
2015-05-14 03:06:58 +00:00
// 0x5 == CSIDL_PERSONAL
if ( dSHGetFolderPathW ( NULL , 0x5 , NULL , 0 , wfolder ) = = S_OK )
2008-06-13 05:03:54 +00:00
{
2015-05-14 03:06:58 +00:00
narrowen ( folder , sizeof ( folder ) , wfolder ) ;
Q_snprintfz ( com_homepath , sizeof ( com_homepath ) , " %s/My Games/%s/ " , folder , FULLENGINENAME ) ;
2008-06-13 05:03:54 +00:00
}
}
2015-05-14 03:06:58 +00:00
// if (shfolder)
// FreeLibrary(shfolder);
2008-06-13 05:03:54 +00:00
2014-03-30 08:55:06 +00:00
if ( ! * com_homepath )
2009-04-01 22:03:56 +00:00
{
ev = getenv ( " USERPROFILE " ) ;
if ( ev )
2014-03-30 08:55:06 +00:00
Q_snprintfz ( com_homepath , sizeof ( com_homepath ) , " %s/My Documents/My Games/%s/ " , ev , FULLENGINENAME ) ;
2009-04-01 22:03:56 +00:00
}
2011-09-16 05:56:54 +00:00
# ifdef NPFTE
2014-03-30 08:55:06 +00:00
if ( ! * com_homepath )
Q_snprintfz ( com_homepath , sizeof ( com_homepath ) , " /%s/ " , FULLENGINENAME ) ;
2009-04-01 22:03:56 +00:00
//as a browser plugin, always use their home directory
usehome = true ;
# else
2010-08-16 02:03:02 +00:00
/*would it not be better to just check to see if we have write permission to the basedir?*/
2008-06-13 05:03:54 +00:00
if ( winver > = 0x6 ) // Windows Vista and above
usehome = true ; // always use home directory by default, as Vista+ mimics this behavior anyway
else if ( winver > = 0x5 ) // Windows 2000/XP/2003
{
2009-04-07 01:26:47 +00:00
HMODULE advapi32 ;
2015-05-14 03:06:58 +00:00
BOOL ( WINAPI * dCheckTokenMembership ) ( HANDLE TokenHandle , PSID SidToCheck , PBOOL IsMember ) = NULL ;
dllfunction_t funcs [ ] =
{
{ ( void * * ) & dCheckTokenMembership , " CheckTokenMembership " } ,
{ NULL , NULL }
} ;
advapi32 = Sys_LoadLibrary ( " advapi32.dll " , funcs ) ;
2008-06-13 07:24:11 +00:00
if ( advapi32 )
2009-06-03 09:09:35 +00:00
{
2008-06-13 07:24:11 +00:00
if ( dCheckTokenMembership )
{
2009-06-03 09:09:35 +00:00
// on XP systems, only use a home directory by default if we're a limited user or if we're on a network
2008-06-13 07:24:11 +00:00
BOOL isadmin , isonnetwork ;
2013-06-24 09:04:00 +00:00
SID_IDENTIFIER_AUTHORITY ntauth = { SECURITY_NT_AUTHORITY } ;
2008-06-13 07:24:11 +00:00
PSID adminSID , networkSID ;
isadmin = AllocateAndInitializeSid ( & ntauth ,
2 ,
SECURITY_BUILTIN_DOMAIN_RID ,
DOMAIN_ALIAS_RID_ADMINS ,
0 , 0 , 0 , 0 , 0 , 0 ,
2009-06-03 09:09:35 +00:00
& adminSID ) ;
2008-06-13 07:24:11 +00:00
// just checking the network rid should be close enough to matching domain logins
isonnetwork = AllocateAndInitializeSid ( & ntauth ,
1 ,
SECURITY_NETWORK_RID ,
0 , 0 , 0 , 0 , 0 , 0 , 0 ,
& networkSID ) ;
if ( isadmin & & ! dCheckTokenMembership ( 0 , adminSID , & isadmin ) )
isadmin = 0 ;
if ( isonnetwork & & ! dCheckTokenMembership ( 0 , networkSID , & isonnetwork ) )
isonnetwork = 0 ;
usehome = isonnetwork | | ! isadmin ;
FreeSid ( networkSID ) ;
FreeSid ( adminSID ) ;
}
2015-05-14 03:06:58 +00:00
Sys_CloseLibrary ( advapi32 ) ;
2008-06-13 07:24:11 +00:00
}
}
2009-04-01 22:03:56 +00:00
# endif
2005-08-26 22:52:26 +00:00
}
# else
//yay for unix!.
ev = getenv ( " HOME " ) ;
2009-02-03 00:12:50 +00:00
if ( ev & & * ev )
2008-06-13 05:03:54 +00:00
{
2009-02-03 00:12:50 +00:00
if ( ev [ strlen ( ev ) - 1 ] = = ' / ' )
2014-03-30 08:55:06 +00:00
Q_snprintfz ( com_homepath , sizeof ( com_homepath ) , " %s.fte/ " , ev ) ;
2009-02-03 00:12:50 +00:00
else
2014-03-30 08:55:06 +00:00
Q_snprintfz ( com_homepath , sizeof ( com_homepath ) , " %s/.fte/ " , ev ) ;
2008-06-13 05:03:54 +00:00
usehome = true ; // always use home on unix unless told not to
}
2005-08-26 22:52:26 +00:00
# endif
2014-12-23 15:26:42 +00:00
com_homepathusable = usehome ;
com_homepathenabled = false ;
2005-08-26 22:52:26 +00:00
2014-03-30 08:55:06 +00:00
if ( COM_CheckParm ( " -usehome " ) )
2014-12-23 15:26:42 +00:00
com_homepathusable = true ;
2005-11-30 01:20:53 +00:00
if ( COM_CheckParm ( " -nohome " ) )
2014-12-23 15:26:42 +00:00
com_homepathusable = false ;
2014-03-30 08:55:06 +00:00
if ( ! * com_homepath )
2014-12-23 15:26:42 +00:00
com_homepathusable = false ;
2014-03-30 08:55:06 +00:00
fs_readonly = COM_CheckParm ( " -readonly " ) ;
2005-11-30 01:20:53 +00:00
2014-10-05 20:04:11 +00:00
fs_thread_mutex = Sys_CreateMutex ( ) ;
2005-08-26 22:52:26 +00:00
}
2009-04-01 22:03:56 +00:00
//this is at the bottom of the file to ensure these globals are not used elsewhere
2016-07-12 00:40:13 +00:00
extern searchpathfuncs_t * ( QDECL VFSOS_OpenPath ) ( vfsfile_t * file , const char * desc , const char * prefix ) ;
2014-12-09 14:39:54 +00:00
# if 1 //def AVAIL_ZLIB
2016-07-12 00:40:13 +00:00
extern searchpathfuncs_t * ( QDECL FSZIP_LoadArchive ) ( vfsfile_t * packhandle , const char * desc , const char * prefix ) ;
2013-06-23 02:17:02 +00:00
# endif
2016-07-12 00:40:13 +00:00
extern searchpathfuncs_t * ( QDECL FSPAK_LoadArchive ) ( vfsfile_t * packhandle , const char * desc , const char * prefix ) ;
2017-02-19 00:15:42 +00:00
# ifdef PACKAGE_DOOMWAD
2016-07-12 00:40:13 +00:00
extern searchpathfuncs_t * ( QDECL FSDWD_LoadArchive ) ( vfsfile_t * packhandle , const char * desc , const char * prefix ) ;
2013-06-23 02:17:02 +00:00
# endif
2009-04-01 22:03:56 +00:00
void FS_RegisterDefaultFileSystems ( void )
{
2017-02-19 00:15:42 +00:00
# ifdef PACKAGE_Q1PAK
2013-06-23 02:17:02 +00:00
FS_RegisterFileSystemType ( NULL , " pak " , FSPAK_LoadArchive , true ) ;
2011-09-16 05:56:54 +00:00
# if !defined(_WIN32) && !defined(ANDROID)
2010-07-11 10:53:13 +00:00
/*for systems that have case sensitive paths, also include *.PAK */
2013-06-23 02:17:02 +00:00
FS_RegisterFileSystemType ( NULL , " PAK " , FSPAK_LoadArchive , true ) ;
2017-02-19 00:15:42 +00:00
# endif
2010-07-11 10:53:13 +00:00
# endif
2013-10-29 17:38:22 +00:00
FS_RegisterFileSystemType ( NULL , " pk3dir " , VFSOS_OpenPath , true ) ;
2017-02-19 00:15:42 +00:00
# ifdef PACKAGE_PK3
2013-06-23 02:17:02 +00:00
FS_RegisterFileSystemType ( NULL , " pk3 " , FSZIP_LoadArchive , true ) ;
FS_RegisterFileSystemType ( NULL , " pk4 " , FSZIP_LoadArchive , true ) ;
FS_RegisterFileSystemType ( NULL , " apk " , FSZIP_LoadArchive , false ) ;
FS_RegisterFileSystemType ( NULL , " zip " , FSZIP_LoadArchive , false ) ;
2009-04-01 22:03:56 +00:00
# endif
2017-02-19 00:15:42 +00:00
# ifdef PACKAGE_DOOMWAD
2013-06-23 02:17:02 +00:00
FS_RegisterFileSystemType ( NULL , " wad " , FSDWD_LoadArchive , true ) ;
2009-04-01 22:03:56 +00:00
# endif
2009-04-02 22:25:54 +00:00
}