diff options
author | Andrey Nazarov <skuller@skuller.net> | 2010-07-03 16:01:48 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2010-07-03 16:01:48 +0000 |
commit | 7a914ef872a436adcdb36d21ceddba6bb24eb993 (patch) | |
tree | dafc86024742e7bbced8ef897754beff5160f1ae /source/cl_demo.c | |
parent | 1acd69e9a128e4f3abf06b5ae97c968c87663864 (diff) |
Yet another huge commit.
Implemented new error reporting framework based on errno and custom error codes.
Converted filesystem code, image and model managers, BSP loader to use the new framework and report errors more accurately.
Replaced fileHandle_t with qhandle_t.
Removed INVALID_LENGTH definition.
Killed USE_LOADBUF code.
Defined FS_FileExists(Ex) macro, implemented FS_EasyOpenFile and FS_WriteFile helper functions.
When testing for free screenshot slots, open the file with O_EXCL flag to avoid race conditions (works only on glibc yet).
Don't allow quake paths with high bits set.
Don't tolerate any fatal errors encountered when searching for files and pass errors back to the caller.
FS_Seek() now fails on files from packs instead of returning an invalid position.
Fixed ‘mvdskip’ command not working properly.
Avoid inefficient usage of MakeColor macro in image loading functions.
Prevent memory leak in JPEG and PNG image functions after calling longjmp() by marking some local variables volatile.
Added support for loading monochrome JPEG images.
Fixed signed integer overflow in GetWavinfo().
Fixed missing return statement in BSP_LoadSurfEdges() causing out of range edge indices to be left uncaught.
Fixed possible access to uninitialized memory in BSP_LoadLeafs() for maps with no leafs.
Properly NUL terminate the buffer in SCR_ScoreDump_f(), also check for being in a level.
Always free latched_string when cvar is set back to current value.
Fixed a crash in ‘mvdplay’ command possible when demo file is invalid.
Diffstat (limited to 'source/cl_demo.c')
-rw-r--r-- | source/cl_demo.c | 220 |
1 files changed, 109 insertions, 111 deletions
diff --git a/source/cl_demo.c b/source/cl_demo.c index 1f33655..f8fc6f2 100644 --- a/source/cl_demo.c +++ b/source/cl_demo.c @@ -215,6 +215,7 @@ stop recording a demo */ void CL_Stop_f( void ) { uint32_t msglen; + ssize_t pos; if( !cls.demo.recording ) { Com_Printf( "Not recording a demo.\n" ); @@ -234,17 +235,17 @@ void CL_Stop_f( void ) { FS_Write( &msglen, 4, cls.demo.recording ); FS_Flush( cls.demo.recording ); - msglen = FS_Tell( cls.demo.recording ); + pos = FS_Tell( cls.demo.recording ); // close demofile FS_FCloseFile( cls.demo.recording ); cls.demo.recording = 0; cls.demo.paused = qfalse; - if( msglen == INVALID_LENGTH ) { + if( pos < 0 ) { Com_Printf( "Stopped demo.\n" ); } else { - Com_Printf( "Stopped demo (%u bytes written).\n", msglen ); + Com_Printf( "Stopped demo (%d bytes written).\n", (int)pos ); } } @@ -263,8 +264,8 @@ static void CL_Record_f( void ) { size_t len; entity_state_t *ent; char *string; - fileHandle_t demofile; - qboolean gzip = qfalse; + qhandle_t f; + unsigned mode = FS_MODE_WRITE; if( cls.demo.recording ) { Com_Printf( "Already recording.\n" ); @@ -284,7 +285,7 @@ static void CL_Record_f( void ) { Cmd_PrintHelp( o_record ); return; case 'z': - gzip = qtrue; + mode |= FS_FLAG_GZIP; break; default: return; @@ -300,26 +301,15 @@ static void CL_Record_f( void ) { // // open the demo file // - len = Q_concat( name, sizeof( name ), "demos/", cmd_optarg, - gzip ? ".dm2.gz" : ".dm2", NULL ); - if( len >= sizeof( name ) ) { - Com_EPrintf( "Oversize filename specified.\n" ); - return; - } - - FS_FOpenFile( name, &demofile, FS_MODE_WRITE ); - if( !demofile ) { - Com_EPrintf( "Couldn't open %s for writing.\n", name ); + f = FS_EasyOpenFile( name, sizeof( name ), mode, + "demos/", cmd_optarg, ".dm2" ); + if( !f ) { return; } Com_Printf( "Recording client demo to %s.\n", name ); - if( gzip ) { - FS_FilterFile( demofile ); - } - - cls.demo.recording = demofile; + cls.demo.recording = f; cls.demo.paused = qfalse; SZ_Init( &cls.demo.buffer, demo_buffer, sizeof( demo_buffer ) ); @@ -446,118 +436,117 @@ static void CL_Suspend_f( void ) { memset( cl.dcs, 0, sizeof( cl.dcs ) ); } -static int CL_ReadFirstDemoMessage( fileHandle_t f ) { +static int read_first_message( qhandle_t f ) { uint32_t ul; uint16_t us; size_t msglen; + ssize_t read; + qerror_t ret; int type; // read magic/msglen - if( FS_Read( &ul, 4, f ) != 4 ) { - Com_DPrintf( "%s: short read of msglen\n", __func__ ); - return -1; + read = FS_Read( &ul, 4, f ); + if( read != 4 ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } + // check for gzip header if( ( ( LittleLong( ul ) & 0xe0ffffff ) == 0x00088b1f ) ) { - Com_DPrintf( "%s: looks like gzip file\n", __func__ ); - if( !FS_FilterFile( f ) ) { - Com_DPrintf( "%s: couldn't install gzip filter\n", __func__ ); - return -1; + ret = FS_FilterFile( f ); + if( ret ) { + return ret; } - if( FS_Read( &ul, 4, f ) != 4 ) { - Com_DPrintf( "%s: short read of msglen\n", __func__ ); - return -1; + read = FS_Read( &ul, 4, f ); + if( read != 4 ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } } + // determine demo type if( ul == MVD_MAGIC ) { - if( FS_Read( &us, 2, f ) != 2 ) { - Com_DPrintf( "%s: short read of msglen\n", __func__ ); - return -1; + read = FS_Read( &us, 2, f ); + if( read != 2 ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } - if( us == ( uint16_t )-1 ) { - Com_DPrintf( "%s: end of demo\n", __func__ ); - return -1; + if( !us ) { + return Q_ERR_UNEXPECTED_EOF; } msglen = LittleShort( us ); type = 1; } else { if( ul == ( uint32_t )-1 ) { - Com_DPrintf( "%s: end of demo\n", __func__ ); - return -1; + return Q_ERR_UNEXPECTED_EOF; } msglen = LittleLong( ul ); type = 0; } - if( msglen >= sizeof( msg_read_buffer ) ) { - Com_DPrintf( "%s: bad msglen\n", __func__ ); - return -1; + if( msglen < 64 || msglen > sizeof( msg_read_buffer ) ) { + return Q_ERR_INVALID_FORMAT; } SZ_Init( &msg_read, msg_read_buffer, sizeof( msg_read_buffer ) ); msg_read.cursize = msglen; // read packet data - if( FS_Read( msg_read.data, msglen, f ) != msglen ) { - Com_DPrintf( "%s: short read of data\n", __func__ ); - return -1; + read = FS_Read( msg_read.data, msglen, f ); + if( read != msglen ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } return type; } -/* -==================== -CL_ReadNextDemoMessage -==================== -*/ -static qboolean CL_ReadNextDemoMessage( fileHandle_t f ) { - uint32_t msglen; +static int read_next_message( qhandle_t f ) { + uint32_t msglen; + ssize_t read; // read msglen - if( FS_Read( &msglen, 4, f ) != 4 ) { - Com_DPrintf( "%s: short read of msglen\n", __func__ ); - return qfalse; + read = FS_Read( &msglen, 4, f ); + if( read != 4 ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } + // check for EOF packet if( msglen == ( uint32_t )-1 ) { - Com_DPrintf( "%s: end of demo\n", __func__ ); - return qfalse; + return 0; } msglen = LittleLong( msglen ); - if( msglen >= sizeof( msg_read_buffer ) ) { - Com_DPrintf( "%s: bad msglen\n", __func__ ); - return qfalse; + if( msglen > sizeof( msg_read_buffer ) ) { + return Q_ERR_INVALID_FORMAT; } SZ_Init( &msg_read, msg_read_buffer, sizeof( msg_read_buffer ) ); msg_read.cursize = msglen; // read packet data - if( FS_Read( msg_read.data, msglen, f ) != msglen ) { - Com_DPrintf( "%s: short read of data\n", __func__ ); - return qfalse; + read = FS_Read( msg_read.data, msglen, f ); + if( read != msglen ) { + return read < 0 ? read : Q_ERR_UNEXPECTED_EOF; } - return qtrue; + return 1; } -/* -==================== -CL_ParseNextDemoMessage -==================== -*/ -static void CL_ParseNextDemoMessage( void ) { - int pos; - char *s; +static void parse_next_message( void ) { + int ret; + + ret = read_next_message( cls.demo.playback ); + if( ret <= 0 ) { + char *s = Cvar_VariableString( "nextserver" ); - if( !CL_ReadNextDemoMessage( cls.demo.playback ) ) { - s = Cvar_VariableString( "nextserver" ); if( !s[0] ) { - Com_Error( ERR_SILENT, "Demo finished" ); + if( ret == 0 ) { + Com_Error( ERR_SILENT, "Demo finished" ); + } else { + Com_Error( ERR_DROP, "Couldn't read demo: %s", Q_ErrorString( ret ) ); + } } + + FS_FCloseFile( cls.demo.playback ); + memset( &cls.demo, 0, sizeof( cls.demo ) ); + Cbuf_AddText( &cmd_buffer, s ); Cbuf_AddText( &cmd_buffer, "\n" ); Cvar_Set( "nextserver", "" ); @@ -568,11 +557,11 @@ static void CL_ParseNextDemoMessage( void ) { CL_ParseServerMessage(); if( cls.demo.file_size ) { - pos = FS_Tell( cls.demo.playback ) - cls.demo.file_offset; - if( pos < 0 ) { - pos = 0; + ssize_t pos = FS_Tell( cls.demo.playback ); + + if( pos > cls.demo.file_offset ) { + cls.demo.file_percent = ( pos - cls.demo.file_offset ) * 100 / cls.demo.file_size; } - cls.demo.file_percent = pos * 100 / cls.demo.file_size; } } @@ -583,9 +572,9 @@ CL_PlayDemo_f */ static void CL_PlayDemo_f( void ) { char name[MAX_OSPATH]; - fileHandle_t demofile; + qhandle_t demofile; char *arg; - size_t length; + ssize_t len, ofs; int type, argc = Cmd_Argc(); if( argc < 2 ) { @@ -596,20 +585,33 @@ static void CL_PlayDemo_f( void ) { arg = Cmd_Argv( 1 ); if( arg[0] == '/' ) { // Assume full path is given - Q_strlcpy( name, arg + 1, sizeof( name ) ); - FS_FOpenFile( name, &demofile, FS_MODE_READ ); + len = Q_strlcpy( name, arg + 1, sizeof( name ) ); + if( len >= sizeof( name ) ) { + len = Q_ERR_NAMETOOLONG; + goto fail; + } + len = FS_FOpenFile( name, &demofile, FS_MODE_READ ); } else { // Search for matching extensions - Q_concat( name, sizeof( name ), "demos/", arg, NULL ); - FS_FOpenFile( name, &demofile, FS_MODE_READ ); + len = Q_concat( name, sizeof( name ), "demos/", arg, NULL ); + if( len >= sizeof( name ) ) { + len = Q_ERR_NAMETOOLONG; + goto fail; + } + len = FS_FOpenFile( name, &demofile, FS_MODE_READ ); if( !demofile ) { - COM_DefaultExtension( name, ".dm2", sizeof( name ) ); - FS_FOpenFile( name, &demofile, FS_MODE_READ ); + len = COM_DefaultExtension( name, ".dm2", sizeof( name ) ); + if( len >= sizeof( name ) ) { + len = Q_ERR_NAMETOOLONG; + goto fail; + } + len = FS_FOpenFile( name, &demofile, FS_MODE_READ ); } } if( !demofile ) { - Com_Printf( "Couldn't open %s\n", name ); +fail: + Com_Printf( "Couldn't open %s: %s\n", name, Q_ErrorString( len ) ); return; } @@ -623,15 +625,14 @@ static void CL_PlayDemo_f( void ) { } #endif - type = CL_ReadFirstDemoMessage( demofile ); - if( type == -1 ) { - Com_Printf( "%s is not a demo file\n", name ); + type = read_first_message( demofile ); + if( type < 0 ) { + Com_Printf( "Couldn't read %s: %s\n", name, Q_ErrorString( type ) ); FS_FCloseFile( demofile ); return; } if( type == 1 ) { - Com_DPrintf( "%s is a MVD file\n", name ); Cbuf_InsertText( &cmd_buffer, va( "mvdplay --replace @@ /%s\n", name ) ); FS_FCloseFile( demofile ); return; @@ -656,16 +657,13 @@ static void CL_PlayDemo_f( void ) { CL_ParseServerMessage(); while( cls.state == ca_connected ) { Cbuf_Execute( &cl_cmdbuf ); - CL_ParseNextDemoMessage(); + parse_next_message(); } - length = FS_GetFileLength( demofile ); - if( length == INVALID_LENGTH ) { - cls.demo.file_offset = 0; - cls.demo.file_size = 0; - } else { - cls.demo.file_offset = FS_Tell( demofile ); - cls.demo.file_size = length - cls.demo.file_offset; + ofs = FS_Tell( demofile ); + if( ofs > 0 ) { + cls.demo.file_offset = ofs; + cls.demo.file_size = len - ofs; } if( com_timedemo->integer ) { @@ -680,7 +678,7 @@ static void CL_Demo_c( genctx_t *ctx, int argnum ) { } } -static void CL_ParseInfoString( demoInfo_t *info, int clientNum, int index, const char *string ) { +static void parse_info_string( demoInfo_t *info, int clientNum, int index, const char *string ) { size_t len; char *p; @@ -707,7 +705,7 @@ CL_GetDemoInfo ==================== */ demoInfo_t *CL_GetDemoInfo( const char *path, demoInfo_t *info ) { - fileHandle_t f; + qhandle_t f; int c, index; char string[MAX_QPATH]; int clientNum, type; @@ -717,8 +715,8 @@ demoInfo_t *CL_GetDemoInfo( const char *path, demoInfo_t *info ) { return NULL; } - type = CL_ReadFirstDemoMessage( f ); - if( type == -1 ) { + type = read_first_message( f ); + if( type < 0 ) { goto fail; } @@ -738,7 +736,7 @@ demoInfo_t *CL_GetDemoInfo( const char *path, demoInfo_t *info ) { while( 1 ) { c = MSG_ReadByte(); if( c == -1 ) { - if( !CL_ReadNextDemoMessage( f ) ) { + if( read_next_message( f ) <= 0 ) { break; } continue; // parse new message @@ -751,7 +749,7 @@ demoInfo_t *CL_GetDemoInfo( const char *path, demoInfo_t *info ) { goto fail; } MSG_ReadString( string, sizeof( string ) ); - CL_ParseInfoString( info, clientNum, index, string ); + parse_info_string( info, clientNum, index, string ); } } else { if( MSG_ReadByte() != mvd_serverdata ) { @@ -774,7 +772,7 @@ demoInfo_t *CL_GetDemoInfo( const char *path, demoInfo_t *info ) { goto fail; } MSG_ReadString( string, sizeof( string ) ); - CL_ParseInfoString( info, clientNum, index, string ); + parse_info_string( info, clientNum, index, string ); } } @@ -800,19 +798,19 @@ void CL_DemoFrame( void ) { return; } if( cls.state != ca_active ) { - CL_ParseNextDemoMessage(); + parse_next_message(); return; } if( com_timedemo->integer ) { - CL_ParseNextDemoMessage(); + parse_next_message(); cl.time = cl.servertime; cls.demo.time_frames++; return; } while( cl.servertime < cl.time ) { - CL_ParseNextDemoMessage(); + parse_next_message(); if( cls.state != ca_active ) { break; } |