summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTim Angus <tim@ngus.net>2006-08-14 21:11:20 +0000
committerTim Angus <tim@ngus.net>2006-08-14 21:11:20 +0000
commit77c1837c789c50ed8fa80f6a862d33387e432125 (patch)
tree215051df23ce8287de47aba48fc685d009ffefe9 /src
parent46c7999840ac513d69b98e3ded8d59869dbb2fb2 (diff)
* Merged ioq3-r838
- OS X Universal Binary creation script - OS X x86 support - OS X vm support - SDL video mode selection bug fix - "Home directory" support on windows - Windows SMP deadlock fix - Improved JPEG quality (screenshots/video) - AVIs recorded with \video command are now actually AVIs - Usual assortment of ioq3 tweaks and fixes
Diffstat (limited to 'src')
-rw-r--r--src/client/cl_avi.c19
-rw-r--r--src/client/cl_input.c2
-rw-r--r--src/client/cl_main.c13
-rw-r--r--src/client/cl_parse.c26
-rw-r--r--src/client/client.h2
-rw-r--r--src/client/snd_openal.c31
-rwxr-xr-xsrc/libs/macosx/libSDL-1.2.0.dylibbin1506244 -> 4469500 bytes
-rw-r--r--src/qcommon/cvar.c20
-rw-r--r--src/qcommon/files.c23
-rw-r--r--src/qcommon/q_shared.h3
-rw-r--r--src/qcommon/qcommon.h4
-rw-r--r--src/qcommon/vm_interpreted.c2
-rw-r--r--src/renderer/tr_image.c10
-rw-r--r--src/renderer/tr_init.c20
-rw-r--r--src/server/sv_snapshot.c4
-rw-r--r--src/unix/sdl_glimp.c8
-rw-r--r--src/unix/unix_net.c4
-rw-r--r--src/win32/win_glimp.c4
-rw-r--r--src/win32/win_local.h1
-rw-r--r--src/win32/win_shared.c21
20 files changed, 166 insertions, 51 deletions
diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c
index 1806b4fa..463f873c 100644
--- a/src/client/cl_avi.c
+++ b/src/client/cl_avi.c
@@ -168,7 +168,7 @@ static ID_INLINE void END_CHUNK( void )
afd.chunkStackTop--;
bufIndex = afd.chunkStack[ afd.chunkStackTop ];
bufIndex += 4;
- WRITE_4BYTES( endIndex - bufIndex - 1 );
+ WRITE_4BYTES( endIndex - bufIndex - 4 );
bufIndex = endIndex;
bufIndex = PAD( bufIndex, 2 );
}
@@ -223,7 +223,7 @@ void CL_WriteAVIHeader( void )
if( afd.motionJpeg )
WRITE_STRING( "MJPG" );
else
- WRITE_STRING( " BGR" );
+ WRITE_4BYTES( 0 ); // BI_RGB
WRITE_4BYTES( 0 ); //dwFlags
WRITE_4BYTES( 0 ); //dwPriority
@@ -250,13 +250,16 @@ void CL_WriteAVIHeader( void )
WRITE_2BYTES( 1 ); //biPlanes
WRITE_2BYTES( 24 ); //biBitCount
- if( afd.motionJpeg ) //biCompression
+ if( afd.motionJpeg ) { //biCompression
WRITE_STRING( "MJPG" );
- else
- WRITE_STRING( " BGR" );
-
- WRITE_4BYTES( afd.width *
+ WRITE_4BYTES( afd.width *
afd.height ); //biSizeImage
+ } else {
+ WRITE_4BYTES( 0 ); // BI_RGB
+ WRITE_4BYTES( afd.width *
+ afd.height*3 ); //biSizeImage
+ }
+
WRITE_4BYTES( 0 ); //biXPelsPetMeter
WRITE_4BYTES( 0 ); //biYPelsPetMeter
WRITE_4BYTES( 0 ); //biClrUsed
@@ -485,7 +488,7 @@ void CL_WriteAVIVideoFrame( const byte *imageBuffer, int size )
// Index
bufIndex = 0;
WRITE_STRING( "00dc" ); //dwIdentifier
- WRITE_4BYTES( 0 ); //dwFlags
+ WRITE_4BYTES( 0x00000010 ); //dwFlags (all frames are KeyFrames)
WRITE_4BYTES( chunkOffset ); //dwOffset
WRITE_4BYTES( size ); //dwLength
SafeFS_Write( buffer, 16, afd.idxF );
diff --git a/src/client/cl_input.c b/src/client/cl_input.c
index 11839729..6faec21c 100644
--- a/src/client/cl_input.c
+++ b/src/client/cl_input.c
@@ -646,7 +646,7 @@ qboolean CL_ReadyToSendPacket( void ) {
}
// send every frame for LAN
- if ( Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
+ if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
return qtrue;
}
diff --git a/src/client/cl_main.c b/src/client/cl_main.c
index 3390ead5..808553b9 100644
--- a/src/client/cl_main.c
+++ b/src/client/cl_main.c
@@ -73,6 +73,8 @@ cvar_t *cl_inGameVideo;
cvar_t *cl_serverStatusResendTime;
cvar_t *cl_trn;
+cvar_t *cl_lanForcePackets;
+
clientActive_t cl;
clientConnection_t clc;
clientStatic_t cls;
@@ -230,10 +232,8 @@ CL_DemoFilename
void CL_DemoFilename( int number, char *fileName ) {
int a,b,c,d;
- if ( number < 0 || number > 9999 ) {
- Com_sprintf( fileName, MAX_OSPATH, "demo9999.tga" );
- return;
- }
+ if(number < 0 || number > 9999)
+ number = 9999;
a = number / 1000;
number -= a*1000;
@@ -301,10 +301,8 @@ void CL_Record_f( void ) {
CL_DemoFilename( number, demoName );
Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", demoName, PROTOCOL_VERSION );
- len = FS_ReadFile( name, NULL );
- if ( len <= 0 ) {
+ if (!FS_FileExists(name))
break; // file doesn't exist
- }
}
}
@@ -2436,6 +2434,7 @@ void CL_Init( void ) {
Cvar_Get( "cl_maxPing", "800", CVAR_ARCHIVE );
+ cl_lanForcePackets = Cvar_Get ("cl_lanForcePackets", "1", CVAR_ARCHIVE);
// userinfo
playerName = getenv( "USER" ); // Unixy stuff
diff --git a/src/client/cl_parse.c b/src/client/cl_parse.c
index dc14cd66..7de07e91 100644
--- a/src/client/cl_parse.c
+++ b/src/client/cl_parse.c
@@ -369,16 +369,38 @@ void CL_SystemInfoChanged( void ) {
// scan through all the variables in the systeminfo and locally set cvars to match
s = systemInfo;
while ( s ) {
+ int cvar_flags;
+
Info_NextPair( &s, key, value );
if ( !key[0] ) {
break;
}
+
// ehw!
- if ( !Q_stricmp( key, "fs_game" ) ) {
+ if (!Q_stricmp(key, "fs_game"))
+ {
+ if(FS_CheckDirTraversal(value))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value);
+ continue;
+ }
+
gameSet = qtrue;
}
- Cvar_Set( key, value );
+ if((cvar_flags = Cvar_Flags(key)) == CVAR_NONEXISTENT)
+ Cvar_Get(key, value, CVAR_SERVER_CREATED | CVAR_ROM);
+ else
+ {
+ // If this cvar may not be modified by a server discard the value.
+ if(!(cvar_flags & (CVAR_SYSTEMINFO | CVAR_SERVER_CREATED)))
+ {
+ Com_Printf(S_COLOR_YELLOW "WARNING: server is not allowed to set %s=%s\n", key, value);
+ continue;
+ }
+
+ Cvar_Set(key, value);
+ }
}
// if game folder should not be set and it is set at the client side
if ( !gameSet && *Cvar_VariableString("fs_game") ) {
diff --git a/src/client/client.h b/src/client/client.h
index e5f5d596..ae5915db 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -355,6 +355,8 @@ extern cvar_t *cl_allowDownload;
extern cvar_t *cl_conXOffset;
extern cvar_t *cl_inGameVideo;
+extern cvar_t *cl_lanForcePackets;
+
//=================================================
//
diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c
index c71a58ee..39a04179 100644
--- a/src/client/snd_openal.c
+++ b/src/client/snd_openal.c
@@ -466,7 +466,11 @@ typedef struct src_s
qboolean local; // Is this local (relative to the cam)
} src_t;
-#define MAX_SRC 128
+#ifdef MACOS_X
+ #define MAX_SRC 64
+#else
+ #define MAX_SRC 128
+#endif
static src_t srcList[MAX_SRC];
static int srcCount = 0;
static qboolean alSourcesInitialised = qfalse;
@@ -1370,6 +1374,9 @@ void S_AL_MusicProcess(ALuint b)
int l;
ALuint format;
+ if(!mus_stream)
+ return;
+
l = S_CodecReadStream(mus_stream, MUSIC_BUFFER_SIZE, decode_buffer);
// Run out data to read, start at the beginning again
@@ -1444,6 +1451,13 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
if(musicSourceHandle == -1)
return;
+ mus_stream = S_CodecOpenStream(s_backgroundLoop);
+ if(!mus_stream)
+ {
+ S_AL_MusicSourceFree();
+ return;
+ }
+
// Generate the musicBuffers
qalGenBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
@@ -1451,19 +1465,6 @@ void S_AL_StartBackgroundTrack( const char *intro, const char *loop )
for(i = 0; i < NUM_MUSIC_BUFFERS; i++)
{
S_AL_MusicProcess(musicBuffers[i]);
-
- // check whether our stream still exists.
- if(!mus_stream)
- {
- // there was an error in reading which resulted in a
- // closed stream. We must bail out or we'll crash.
-
- // deallocate everything we allocated so far:
- qalDeleteBuffers(NUM_MUSIC_BUFFERS, musicBuffers);
- S_AL_MusicSourceFree();
-
- return;
- }
}
qalSourceQueueBuffers(musicSource, NUM_MUSIC_BUFFERS, musicBuffers);
@@ -1525,6 +1526,8 @@ static ALCcontext *alContext;
#ifdef _WIN32
#define ALDRIVER_DEFAULT "OpenAL32.dll"
+#elif defined(MACOS_X)
+#define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL"
#else
#define ALDRIVER_DEFAULT "libopenal.so.0"
#endif
diff --git a/src/libs/macosx/libSDL-1.2.0.dylib b/src/libs/macosx/libSDL-1.2.0.dylib
index dce61848..3c510544 100755
--- a/src/libs/macosx/libSDL-1.2.0.dylib
+++ b/src/libs/macosx/libSDL-1.2.0.dylib
Binary files differ
diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c
index a306d887..a4af1af0 100644
--- a/src/qcommon/cvar.c
+++ b/src/qcommon/cvar.c
@@ -162,6 +162,20 @@ void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize
}
}
+/*
+============
+Cvar_Flags
+============
+*/
+int Cvar_Flags(const char *var_name)
+{
+ cvar_t *var;
+
+ if(! (var = Cvar_FindVar(var_name)) )
+ return CVAR_NONEXISTENT;
+ else
+ return var->flags;
+}
/*
============
@@ -318,7 +332,11 @@ cvar_t *Cvar_Set2( const char *var_name, const char *value, qboolean force ) {
value = var->resetString;
}
- if (!strcmp(value,var->string)) {
+ if((var->flags & CVAR_LATCH) && var->latchedString) {
+ if(!strcmp(value,var->latchedString))
+ return var;
+ }
+ else if (!strcmp(value,var->string)) {
return var;
}
// note what types of cvars have been modified (userinfo, archive, serverinfo, systeminfo)
diff --git a/src/qcommon/files.c b/src/qcommon/files.c
index 9e9d21d0..15e183a4 100644
--- a/src/qcommon/files.c
+++ b/src/qcommon/files.c
@@ -2564,6 +2564,23 @@ qboolean FS_idPak( char *pak, char *base ) {
/*
================
+FS_idPak
+
+Check whether the string contains stuff like "../" to prevent directory traversal bugs
+and return qtrue if it does.
+================
+*/
+
+qboolean FS_CheckDirTraversal(const char *checkdir)
+{
+ if(strstr(checkdir, "../") || strstr(checkdir, "..\\"))
+ return qtrue;
+
+ return qfalse;
+}
+
+/*
+================
FS_ComparePaks
----------------
@@ -2611,7 +2628,7 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
}
// Make sure the server cannot make us write to non-quake3 directories.
- if(strstr(fs_serverReferencedPakNames[i], "../") || strstr(fs_serverReferencedPakNames[i], "..\\"))
+ if(FS_CheckDirTraversal(fs_serverReferencedPakNames[i]))
{
Com_Printf("WARNING: Invalid download name %s\n", fs_serverReferencedPakNames[i]);
continue;
@@ -2802,6 +2819,10 @@ static void FS_Startup( const char *gameName ) {
if (fs_basepath->string[0]) {
FS_AddGameDirectory( fs_basepath->string, gameName );
}
+#ifdef MACOS_X
+ // allow .app bundles to be placed along side base dir
+ FS_AddGameDirectory( ".", gameName );
+#endif
// fs_homepath is somewhat particular to *nix systems, only add if relevant
// NOTE: same filtering below for mods and basegame
if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h
index 9ade94b5..8d84b3f7 100644
--- a/src/qcommon/q_shared.h
+++ b/src/qcommon/q_shared.h
@@ -810,6 +810,9 @@ default values.
#define CVAR_CHEAT 512 // can not be changed if cheats are disabled
#define CVAR_NORESTART 1024 // do not clear when a cvar_restart is issued
+#define CVAR_SERVER_CREATED 2048 // cvar was created by a server the client connected to.
+#define CVAR_NONEXISTENT 0xFFFFFFFF // Cvar doesn't exist.
+
// nothing outside the Cvar_*() functions should modify these fields!
typedef struct cvar_s {
char *name;
diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h
index 9cb03b6f..bf20536d 100644
--- a/src/qcommon/qcommon.h
+++ b/src/qcommon/qcommon.h
@@ -474,6 +474,9 @@ char *Cvar_VariableString( const char *var_name );
void Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
// returns an empty string if not defined
+int Cvar_Flags(const char *var_name);
+// returns CVAR_NONEXISTENT if cvar doesn't exist or the flags of that particular CVAR.
+
void Cvar_CommandCompletion( void(*callback)(const char *s) );
// callback with each valid string
@@ -644,6 +647,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames );
// separated checksums will be checked for files, with the
// sole exception of .cfg files.
+qboolean FS_CheckDirTraversal(const char *checkdir);
qboolean FS_idPak( char *pak, char *base );
qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring );
diff --git a/src/qcommon/vm_interpreted.c b/src/qcommon/vm_interpreted.c
index 44b6e5d3..3c52f421 100644
--- a/src/qcommon/vm_interpreted.c
+++ b/src/qcommon/vm_interpreted.c
@@ -853,7 +853,7 @@ nextInstruction2:
opStack--;
goto nextInstruction;
case OP_BCOM:
- opStack[-1] = ~ ((unsigned)r0);
+ *opStack = ~ ((unsigned)r0);
goto nextInstruction;
case OP_LSH:
diff --git a/src/renderer/tr_image.c b/src/renderer/tr_image.c
index d4beacd8..bd51ff2d 100644
--- a/src/renderer/tr_image.c
+++ b/src/renderer/tr_image.c
@@ -1817,6 +1817,11 @@ void SaveJPG(char * filename, int quality, int image_width, int image_height, un
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+ /* If quality is set high, disable chroma subsampling */
+ if (quality >= 85) {
+ cinfo.comp_info[0].h_samp_factor = 1;
+ cinfo.comp_info[0].v_samp_factor = 1;
+ }
/* Step 4: Start compressor */
@@ -1891,6 +1896,11 @@ int SaveJPGToBuffer( byte *buffer, int quality,
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+ /* If quality is set high, disable chroma subsampling */
+ if (quality >= 85) {
+ cinfo.comp_info[0].h_samp_factor = 1;
+ cinfo.comp_info[0].v_samp_factor = 1;
+ }
/* Step 4: Start compressor */
jpeg_start_compress(&cinfo, TRUE);
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c
index b027a3c8..96fa5b4d 100644
--- a/src/renderer/tr_init.c
+++ b/src/renderer/tr_init.c
@@ -511,7 +511,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName
}
ri.FS_WriteFile( fileName, buffer, 1 ); // create path
- SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer);
+ SaveJPG( fileName, 90, glConfig.vidWidth, glConfig.vidHeight, buffer);
ri.Hunk_FreeTempMemory( buffer );
}
@@ -815,23 +815,23 @@ const void *RB_TakeVideoFrameCmd( const void *data )
if( cmd->motionJpeg )
{
- frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95,
+ frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 90,
cmd->width, cmd->height, cmd->captureBuffer );
+ ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
}
else
{
- frameSize = cmd->width * cmd->height * 4;
+ frameSize = cmd->width * cmd->height;
- // Vertically flip the image
- for( i = 0; i < cmd->height; i++ )
+ for( i = 0; i < frameSize; i++) // Pack to 24bpp and swap R and B
{
- Com_Memcpy( &cmd->encodeBuffer[ i * ( cmd->width * 4 ) ],
- &cmd->captureBuffer[ ( cmd->height - i - 1 ) * ( cmd->width * 4 ) ],
- cmd->width * 4 );
+ cmd->encodeBuffer[ i*3 ] = cmd->captureBuffer[ i*4 + 2 ];
+ cmd->encodeBuffer[ i*3 + 1 ] = cmd->captureBuffer[ i*4 + 1 ];
+ cmd->encodeBuffer[ i*3 + 2 ] = cmd->captureBuffer[ i*4 ];
}
- }
- ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize );
+ ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize * 3 );
+ }
return (const void *)(cmd + 1);
}
diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c
index dd483f17..75da32b0 100644
--- a/src/server/sv_snapshot.c
+++ b/src/server/sv_snapshot.c
@@ -584,11 +584,11 @@ void SV_SendMessageToClient( msg_t *msg, client_t *client ) {
// set nextSnapshotTime based on rate and requested number of updates
- // local clients get snapshots every frame
+ // local clients get snapshots every server frame
// TTimo - https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491
// added sv_lanForceRate check
if ( client->netchan.remoteAddress.type == NA_LOOPBACK || (sv_lanForceRate->integer && Sys_IsLANAddress (client->netchan.remoteAddress)) ) {
- client->nextSnapshotTime = svs.time - 1;
+ client->nextSnapshotTime = svs.time + (1000/sv_fps->integer);
return;
}
diff --git a/src/unix/sdl_glimp.c b/src/unix/sdl_glimp.c
index fcab7125..b2cc13a4 100644
--- a/src/unix/sdl_glimp.c
+++ b/src/unix/sdl_glimp.c
@@ -68,7 +68,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#if USE_SDL_VIDEO
+#include "SDL.h"
+#include "SDL_loadso.h"
+#else
#include <dlfcn.h>
+#endif
#include "../renderer/tr_local.h"
#include "../client/client.h"
@@ -555,7 +560,7 @@ static qboolean GLW_StartDriverAndSetMode( const char *drivername,
static int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
{
const char* glstring; // bk001130 - from cvs1.17 (mkv)
- int sdlcolorbits = 4;
+ int sdlcolorbits;
int colorbits, depthbits, stencilbits;
int tcolorbits, tdepthbits, tstencilbits;
int i = 0;
@@ -651,6 +656,7 @@ static int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen )
tstencilbits = 0;
}
+ sdlcolorbits = 4;
if (tcolorbits == 24)
sdlcolorbits = 8;
diff --git a/src/unix/unix_net.c b/src/unix/unix_net.c
index a7d8a088..d89e766a 100644
--- a/src/unix/unix_net.c
+++ b/src/unix/unix_net.c
@@ -26,6 +26,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include "../qcommon/qcommon.h"
#include <unistd.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED == 1020
+ // needed for socket_t on OSX 10.2
+ #define _BSD_SOCKLEN_T_
+#endif
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
diff --git a/src/win32/win_glimp.c b/src/win32/win_glimp.c
index 22e98e5f..ef8651dd 100644
--- a/src/win32/win_glimp.c
+++ b/src/win32/win_glimp.c
@@ -1562,13 +1562,13 @@ void *GLimp_RendererSleep( void ) {
wglErrors++;
}
- ResetEvent( renderActiveEvent );
-
// after this, the front end can exit GLimp_FrontEndSleep
SetEvent( renderCompletedEvent );
WaitForSingleObject( renderCommandsEvent, INFINITE );
+ ResetEvent( renderActiveEvent );
+
if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) ) {
wglErrors++;
}
diff --git a/src/win32/win_local.h b/src/win32/win_local.h
index b0e85a15..9d599730 100644
--- a/src/win32/win_local.h
+++ b/src/win32/win_local.h
@@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#include <dsound.h>
#include <winsock.h>
#include <wsipx.h>
+#include <shlobj.h>
void IN_MouseEvent (int mstate);
diff --git a/src/win32/win_shared.c b/src/win32/win_shared.c
index 318d9418..003254d9 100644
--- a/src/win32/win_shared.c
+++ b/src/win32/win_shared.c
@@ -286,7 +286,26 @@ char *Sys_GetCurrentUser( void )
}
char *Sys_DefaultHomePath(void) {
- return NULL;
+ TCHAR szPath[MAX_PATH];
+ static char path[MAX_OSPATH];
+
+ if( !SUCCEEDED( SHGetFolderPath( NULL, CSIDL_LOCAL_APPDATA,
+ NULL, 0, szPath ) ) )
+ {
+
+ return NULL;
+ }
+ Q_strncpyz( path, szPath, sizeof(path) );
+ Q_strcat( path, sizeof(path), "\\Quake3" );
+ if( !CreateDirectory( path, NULL ) )
+ {
+ if( GetLastError() != ERROR_ALREADY_EXISTS )
+ {
+ Com_Printf("Unable to create directory \"%s\"\n", path);
+ return NULL;
+ }
+ }
+ return path;
}
char *Sys_DefaultInstallPath(void)