summaryrefslogtreecommitdiff
path: root/source/r_models.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2010-07-03 16:01:48 +0000
committerAndrey Nazarov <skuller@skuller.net>2010-07-03 16:01:48 +0000
commit7a914ef872a436adcdb36d21ceddba6bb24eb993 (patch)
treedafc86024742e7bbced8ef897754beff5160f1ae /source/r_models.c
parent1acd69e9a128e4f3abf06b5ae97c968c87663864 (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/r_models.c')
-rw-r--r--source/r_models.c222
1 files changed, 110 insertions, 112 deletions
diff --git a/source/r_models.c b/source/r_models.c
index 9d9cd21..f862fd3 100644
--- a/source/r_models.c
+++ b/source/r_models.c
@@ -132,86 +132,72 @@ void MOD_FreeAll( void ) {
r_numModels = 0;
}
-qboolean MOD_ValidateMD2( model_t *model, dmd2header_t *header, size_t length ) {
+qerror_t MOD_ValidateMD2( model_t *model, dmd2header_t *header, size_t length ) {
size_t end;
// check ident and version
- if( header->ident != MD2_IDENT ) {
- Com_WPrintf( "%s is not an MD2 file\n", model->name );
- return qfalse;
- }
- if( header->version != MD2_VERSION ) {
- Com_WPrintf( "%s has bad version: %d instead of %d\n",
- model->name, header->version, MD2_VERSION );
- return qfalse;
- }
+ if( header->ident != MD2_IDENT )
+ return Q_ERR_UNKNOWN_FORMAT;
+ if( header->version != MD2_VERSION )
+ return Q_ERR_UNKNOWN_FORMAT;
// check triangles
- if( header->num_tris < 1 || header->num_tris > MD2_MAX_TRIANGLES ) {
- Com_WPrintf( "%s has bad number of triangles\n", model->name );
- return qfalse;
- }
+ if( header->num_tris < 1 )
+ return Q_ERR_TOO_FEW;
+ if( header->num_tris > MD2_MAX_TRIANGLES )
+ return Q_ERR_TOO_MANY;
+
end = header->ofs_tris + sizeof( dmd2triangle_t ) * header->num_tris;
- if( header->ofs_tris < sizeof( header ) || end < header->ofs_tris || end > length ) {
- Com_WPrintf( "%s has bad triangles offset\n", model->name );
- return qfalse;
- }
+ if( header->ofs_tris < sizeof( header ) || end < header->ofs_tris || end > length )
+ return Q_ERR_BAD_EXTENT;
// check st
- if( header->num_st < 3 || header->num_st > MD2_MAX_VERTS ) {
- Com_WPrintf( "%s has bad number of st\n", model->name );
- return qfalse;
- }
+ if( header->num_st < 3 )
+ return Q_ERR_TOO_FEW;
+ if( header->num_st > MD2_MAX_VERTS )
+ return Q_ERR_TOO_MANY;
+
end = header->ofs_st + sizeof( dmd2stvert_t ) * header->num_st;
- if( header->ofs_st < sizeof( header ) || end < header->ofs_st || end > length ) {
- Com_WPrintf( "%s has bad st offset\n", model->name );
- return qfalse;
- }
+ if( header->ofs_st < sizeof( header ) || end < header->ofs_st || end > length )
+ return Q_ERR_BAD_EXTENT;
// check xyz and frames
- if( header->num_xyz < 3 || header->num_xyz > MD2_MAX_VERTS ) {
- Com_WPrintf( "%s has bad number of xyz\n", model->name );
- return qfalse;
- }
- if( header->num_frames < 1 || header->num_frames > MD2_MAX_FRAMES ) {
- Com_WPrintf( "%s has bad number of frames\n", model->name );
- return qfalse;
- }
+ if( header->num_xyz < 3 )
+ return Q_ERR_TOO_FEW;
+ if( header->num_xyz > MD2_MAX_VERTS )
+ return Q_ERR_TOO_MANY;
+ if( header->num_frames < 1 )
+ return Q_ERR_TOO_FEW;
+ if( header->num_frames > MD2_MAX_FRAMES )
+ return Q_ERR_TOO_MANY;
+
end = sizeof( dmd2frame_t ) + ( header->num_xyz - 1 ) * sizeof( dmd2trivertx_t );
- if( header->framesize < end || header->framesize > MD2_MAX_FRAMESIZE ) {
- Com_WPrintf( "%s has bad frame size\n", model->name );
- return qfalse;
- }
- end = header->ofs_frames + header->framesize * header->num_frames;
- if( header->ofs_frames < sizeof( header ) || end < header->ofs_frames || end > length ) {
- Com_WPrintf( "%s has bad frames offset\n", model->name );
- return qfalse;
- }
+ if( header->framesize < end || header->framesize > MD2_MAX_FRAMESIZE )
+ return Q_ERR_BAD_EXTENT;
+
+ end = header->ofs_frames + ( size_t )header->framesize * header->num_frames;
+ if( header->ofs_frames < sizeof( header ) || end < header->ofs_frames || end > length )
+ return Q_ERR_BAD_EXTENT;
// check skins
- if( header->num_skins > MAX_ALIAS_SKINS ) {
- Com_WPrintf( "%s has bad number of skins\n", model->name );
- return qfalse;
- }
if( header->num_skins ) {
- end = header->ofs_skins + MD2_MAX_SKINNAME * header->num_skins;
- if( header->ofs_skins < sizeof( header ) || end < header->ofs_skins || end > length ) {
- Com_WPrintf( "%s has bad skins offset\n", model->name );
- return qfalse;
- }
- }
- if( header->skinwidth < 1 || header->skinwidth > MD2_MAX_SKINWIDTH ) {
- Com_WPrintf( "%s has bad skin width\n", model->name );
- return qfalse;
- }
- if( header->skinheight < 1 || header->skinheight > MD2_MAX_SKINHEIGHT ) {
- Com_WPrintf( "%s has bad skin height\n", model->name );
- return qfalse;
+ if( header->num_skins > MAX_ALIAS_SKINS )
+ return Q_ERR_TOO_MANY;
+
+ end = header->ofs_skins + ( size_t )MD2_MAX_SKINNAME * header->num_skins;
+ if( header->ofs_skins < sizeof( header ) || end < header->ofs_skins || end > length )
+ return Q_ERR_BAD_EXTENT;
}
- return qtrue;
+
+ if( header->skinwidth < 1 || header->skinwidth > MD2_MAX_SKINWIDTH )
+ return Q_ERR_INVALID_FORMAT;
+ if( header->skinheight < 1 || header->skinheight > MD2_MAX_SKINHEIGHT )
+ return Q_ERR_INVALID_FORMAT;
+
+ return Q_ERR_SUCCESS;
}
-static qboolean MOD_LoadSP2( model_t *model, const void *rawdata, size_t length ) {
+static qerror_t MOD_LoadSP2( model_t *model, const void *rawdata, size_t length ) {
dsp2header_t header;
dsp2frame_t *src_frame;
mspriteframe_t *dst_frame;
@@ -220,10 +206,8 @@ static qboolean MOD_LoadSP2( model_t *model, const void *rawdata, size_t length
image_t *image;
int i;
- if( length < sizeof( header ) ) {
- Com_EPrintf( "%s is too small\n", model->name );
- return qfalse;
- }
+ if( length < sizeof( header ) )
+ return Q_ERR_FILE_TOO_SMALL;
// byte swap the header
header = *( dsp2header_t * )rawdata;
@@ -231,24 +215,16 @@ static qboolean MOD_LoadSP2( model_t *model, const void *rawdata, size_t length
(( uint32_t * )&header)[i] = LittleLong( (( uint32_t * )&header)[i] );
}
- if( header.ident != SP2_IDENT ) {
- Com_EPrintf( "%s is not an SP2 file\n", model->name );
- return qfalse;
- }
- if( header.version != SP2_VERSION ) {
- Com_EPrintf( "%s has bad version: %d instead of %d\n",
- model->name, header.version, SP2_VERSION );
- return qfalse;
- }
- if( header.numframes < 1 || header.numframes > SP2_MAX_FRAMES ) {
- Com_EPrintf( "%s has bad number of frames: %d\n",
- model->name, header.numframes );
- return qfalse;
- }
- if( sizeof( dsp2header_t ) + sizeof( dsp2frame_t ) * header.numframes > length ) {
- Com_EPrintf( "%s has frames out of bounds\n", model->name );
- return qfalse;
- }
+ if( header.ident != SP2_IDENT )
+ return Q_ERR_UNKNOWN_FORMAT;
+ if( header.version != SP2_VERSION )
+ return Q_ERR_UNKNOWN_FORMAT;
+ if( header.numframes < 1 )
+ return Q_ERR_TOO_FEW;
+ if( header.numframes > SP2_MAX_FRAMES )
+ return Q_ERR_TOO_MANY;
+ if( sizeof( dsp2header_t ) + sizeof( dsp2frame_t ) * header.numframes > length )
+ return Q_ERR_BAD_EXTENT;
Hunk_Begin( &model->pool, 0x10000 );
@@ -292,17 +268,18 @@ static qboolean MOD_LoadSP2( model_t *model, const void *rawdata, size_t length
Hunk_End( &model->pool );
- return qtrue;
+ return Q_ERR_SUCCESS;
}
-
qhandle_t R_RegisterModel( const char *name ) {
int index;
size_t namelen, filelen;
model_t *model;
byte *rawdata;
uint32_t ident;
- qboolean success;
+ mod_load_t load;
+ const char *truename;
+ qerror_t ret;
if( name[0] == '*' ) {
// inline bsp model
@@ -318,12 +295,9 @@ qhandle_t R_RegisterModel( const char *name ) {
model = MOD_Find( name );
if( model ) {
MOD_Reference( model );
- goto finish;
+ goto success;
}
- filelen = 0;
- rawdata = NULL;
-
#if USE_MD3
if( r_override_models->integer ) {
char buffer[MAX_QPATH];
@@ -331,55 +305,79 @@ qhandle_t R_RegisterModel( const char *name ) {
if( namelen > 4 && !Q_stricmp( name + namelen - 4, ".md2" ) ) {
memcpy( buffer, name, namelen + 1 );
buffer[namelen - 1] = '3';
- filelen = FS_LoadFile( buffer, ( void ** )&rawdata );
+ truename = buffer;
+
+ filelen = FS_LoadFile( truename, ( void ** )&rawdata );
+ if( rawdata ) {
+ goto found;
+ }
+ if( filelen != Q_ERR_NOENT ) {
+ ret = filelen;
+ goto fail1;
+ }
}
}
- if( !rawdata )
#endif
- {
- filelen = FS_LoadFile( name, ( void ** )&rawdata );
- if( !rawdata ) {
- Com_DPrintf( "Couldn't load %s\n", name );
- return 0;
- }
+
+ truename = name;
+
+ filelen = FS_LoadFile( truename, ( void ** )&rawdata );
+ if( rawdata ) {
+ goto found;
}
+ if( filelen != Q_ERR_NOENT ) {
+ ret = filelen;
+ goto fail1;
+ }
+
+ // don't spam about missing models
+ return 0;
+found:
if( filelen < 4 ) {
- Com_WPrintf( "%s: %s: file too short\n", __func__, name );
- return 0;
+ ret = Q_ERR_FILE_TOO_SMALL;
+ goto fail2;
}
- model = MOD_Alloc( name );
-
+ // check ident
ident = LittleLong( *( uint32_t * )rawdata );
switch( ident ) {
case MD2_IDENT:
- success = MOD_LoadMD2( model, rawdata, filelen );
+ load = MOD_LoadMD2;
break;
#if USE_MD3
case MD3_IDENT:
- success = MOD_LoadMD3( model, rawdata, filelen );
+ load = MOD_LoadMD3;
break;
#endif
case SP2_IDENT:
- success = MOD_LoadSP2( model, rawdata, filelen );
+ load = MOD_LoadSP2;
break;
default:
- Com_WPrintf( "%s: %s: unknown ident: %x\n", __func__, name, ident );
- success = qfalse;
- break;
+ ret = Q_ERR_UNKNOWN_FORMAT;
+ goto fail2;
}
+ model = MOD_Alloc( name );
+
+ ret = load( model, rawdata, filelen );
+
FS_FreeFile( rawdata );
- if( !success ) {
+ if( ret ) {
memset( model, 0, sizeof( *model ) );
- return 0;
+ goto fail1;
}
-finish:
+success:
index = ( model - r_models ) + 1;
return index;
+
+fail2:
+ FS_FreeFile( rawdata );
+fail1:
+ Com_EPrintf( "Couldn't load %s: %s\n", truename, Q_ErrorString( ret ) );
+ return 0;
}
model_t *MOD_ForHandle( qhandle_t h ) {