mirror of
https://github.com/YGGverse/xash3d-fwgs.git
synced 2025-01-11 07:37:52 +00:00
utils: mdldec: better validation checks.
This commit is contained in:
parent
a8cbfb8dda
commit
7a795edeb5
@ -13,6 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -32,6 +33,168 @@ studiohdr_t *model_hdr;
|
||||
studiohdr_t *texture_hdr;
|
||||
studiohdr_t **anim_hdr;
|
||||
|
||||
/*
|
||||
============
|
||||
IsValidName
|
||||
============
|
||||
*/
|
||||
static qboolean IsValidName( char *name )
|
||||
{
|
||||
if( !( isalpha( *name ) || isdigit( *name )))
|
||||
return false;
|
||||
|
||||
while( *( ++name))
|
||||
{
|
||||
if( isalpha( *name ) || isdigit( *name )
|
||||
|| *name == '.' || *name == '-' || *name == '_'
|
||||
|| *name == ' ' || *name == '(' || *name == ')'
|
||||
|| *name == '[' || *name == ']')
|
||||
continue;
|
||||
// Found control character Ctrl+Shift+A(SOH|^A|0x1) in the end of name in some models.
|
||||
else if( name[1] == '\0' )
|
||||
{
|
||||
*name = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
TextureNameFix
|
||||
============
|
||||
*/
|
||||
static void TextureNameFix( void )
|
||||
{
|
||||
int i, j, len, counter, protected = 0;
|
||||
qboolean hasduplicates = false;
|
||||
mstudiotexture_t *texture = (mstudiotexture_t *)( (byte *)texture_hdr + texture_hdr->textureindex ), *texture1;
|
||||
|
||||
for( i = 0; i < texture_hdr->numtextures; ++i, ++texture )
|
||||
{
|
||||
ExtractFileName( texture->name, sizeof( texture->name ));
|
||||
if( !Q_strchr( texture->name, '.' ) )
|
||||
Q_strncat( texture->name, ".bmp", sizeof( texture->name ));
|
||||
}
|
||||
|
||||
texture -= i;
|
||||
|
||||
for( i = 0; i < texture_hdr->numtextures; ++i, ++texture )
|
||||
{
|
||||
if( !IsValidName( texture->name ))
|
||||
{
|
||||
Q_snprintf( texture->name, sizeof( texture->name ), "MDLDEC_Texture%i.bmp", ++protected );
|
||||
continue;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
|
||||
texture1 = (mstudiotexture_t *)( (byte *)texture_hdr + texture_hdr->textureindex );
|
||||
|
||||
for( j = 0; j < texture_hdr->numtextures; ++j, ++texture1 )
|
||||
{
|
||||
if( j != i && !Q_strncmp( texture1->name, texture->name, sizeof( texture1->name)))
|
||||
{
|
||||
len = Q_snprintf( texture1->name, sizeof( texture1->name ), "%s_%i.bmp", texture1->name, ++counter );
|
||||
|
||||
if( len == -1 )
|
||||
Q_snprintf( texture1->name, sizeof( texture1->name ), "MDLDEC_Texture%i_%i.bmp", j, counter );
|
||||
}
|
||||
}
|
||||
|
||||
if( counter > 0 )
|
||||
{
|
||||
printf( "WARNING: Texture name \"%s\" is repeated %i times.\n", texture->name, counter );
|
||||
|
||||
hasduplicates = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( protected )
|
||||
printf( "WARNING: Gived name to %i protected texture(s).\n", protected );
|
||||
|
||||
if( hasduplicates )
|
||||
puts( "WARNING: Added numeric suffix to repeated texture name(s)." );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
BodypartNameFix
|
||||
============
|
||||
*/
|
||||
static void BodypartNameFix( void )
|
||||
{
|
||||
int i, j, k, len, counter, protected = 0, protected_models = 0;
|
||||
qboolean hasduplicates = false;
|
||||
mstudiobodyparts_t *bodypart = (mstudiobodyparts_t *) ( (byte *)model_hdr + model_hdr->bodypartindex );
|
||||
mstudiomodel_t *model, *model1;
|
||||
|
||||
for( i = 0; i < model_hdr->numbodyparts; ++i, ++bodypart )
|
||||
ExtractFileName( bodypart->name, sizeof( bodypart->name ));
|
||||
|
||||
bodypart -= i;
|
||||
|
||||
for( i = 0; i < model_hdr->numbodyparts; ++i, ++bodypart )
|
||||
{
|
||||
if( !IsValidName( bodypart->name ))
|
||||
{
|
||||
Q_snprintf( bodypart->name, sizeof( bodypart->name ), "MDLDEC_Bodypart%i", ++protected );
|
||||
continue;
|
||||
}
|
||||
|
||||
model = (mstudiomodel_t *)( (byte *)model_hdr + bodypart->modelindex );
|
||||
|
||||
for( j = 0; j < bodypart->nummodels; ++j, ++model )
|
||||
ExtractFileName( model->name, sizeof( model->name ));
|
||||
|
||||
model -= j;
|
||||
|
||||
for( j = 0; j < bodypart->nummodels; ++j, ++model )
|
||||
{
|
||||
if( !IsValidName( model->name ))
|
||||
{
|
||||
Q_snprintf( model->name, sizeof( model->name ), "MDLDEC_Model%i", ++protected_models );
|
||||
continue;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
|
||||
model1 = (mstudiomodel_t *)( (byte *)model_hdr + bodypart->modelindex );
|
||||
|
||||
for( k = 0; k < bodypart->nummodels; ++k, ++model1 )
|
||||
{
|
||||
if( k != j && !Q_strncmp( model1->name, model->name, sizeof( model1->name )))
|
||||
{
|
||||
len = Q_snprintf( model1->name, sizeof( model1->name ), "%s_%i", model1->name, ++counter );
|
||||
|
||||
if( len == -1 )
|
||||
Q_snprintf( model1->name, sizeof( model1->name ), "MDLDEC_Model%i_%i", k, counter );
|
||||
}
|
||||
}
|
||||
|
||||
if( counter > 0 )
|
||||
{
|
||||
printf( "WARNING: Sequence name \"%s\" is repeated %i times.\n", model->name, counter );
|
||||
|
||||
hasduplicates = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( protected )
|
||||
printf( "WARNING: Gived name to %i protected bodypart(s).\n", protected );
|
||||
|
||||
if( protected_models )
|
||||
printf( "WARNING: Gived name to %i protected model(s).\n", protected_models );
|
||||
|
||||
if( hasduplicates )
|
||||
puts( "WARNING: Added numeric suffix to repeated bodypart name(s)." );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
SequenceNameFix
|
||||
@ -39,30 +202,49 @@ SequenceNameFix
|
||||
*/
|
||||
static void SequenceNameFix( void )
|
||||
{
|
||||
int i, j, counter;
|
||||
int i, j, len, counter, protected = 0;
|
||||
qboolean hasduplicates = false;
|
||||
mstudioseqdesc_t *seqdesc = (mstudioseqdesc_t *)( (byte *)model_hdr + model_hdr->seqindex ), *seqdesc1;
|
||||
|
||||
for( i = 0; i < model_hdr->numseq; ++i, ++seqdesc )
|
||||
ExtractFileName( seqdesc->label, sizeof( seqdesc->label ));
|
||||
|
||||
seqdesc -= i;
|
||||
|
||||
for( i = 0; i < model_hdr->numseq; ++i, ++seqdesc )
|
||||
{
|
||||
counter = 1;
|
||||
if( !IsValidName( seqdesc->label ))
|
||||
{
|
||||
Q_snprintf( seqdesc->label, sizeof( seqdesc->label ), "MDLDEC_Sequence%i", ++protected );
|
||||
continue;
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
|
||||
seqdesc1 = (mstudioseqdesc_t *)( (byte *)model_hdr + model_hdr->seqindex );
|
||||
|
||||
for( j = 0; j < model_hdr->numseq; ++j, ++seqdesc1 )
|
||||
if( j != i && !Q_strncmp( seqdesc1->label, seqdesc->label, sizeof( seqdesc1->label ) ) )
|
||||
Q_snprintf( seqdesc1->label, sizeof( seqdesc1->label ), "%s_%i", seqdesc1->label, ++counter );
|
||||
{
|
||||
if( j != i && !Q_strncmp( seqdesc1->label, seqdesc->label, sizeof( seqdesc1->label )))
|
||||
{
|
||||
len = Q_snprintf( seqdesc1->label, sizeof( seqdesc1->label ), "%s_%i", seqdesc1->label, ++counter );
|
||||
|
||||
if( counter > 1 )
|
||||
if( len == -1 )
|
||||
Q_snprintf( seqdesc1->label, sizeof( seqdesc1->label ), "MDLDEC_Sequence%i_%i", j, counter );
|
||||
}
|
||||
}
|
||||
|
||||
if( counter > 0 )
|
||||
{
|
||||
printf( "WARNING: Sequence name \"%s\" is repeated %i times.\n", seqdesc->label, counter );
|
||||
|
||||
Q_snprintf( seqdesc->label, sizeof( seqdesc->label ), "%s_1", seqdesc->label );
|
||||
|
||||
hasduplicates = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( protected )
|
||||
printf( "WARNING: Gived name to %i protected sequence(s).\n", protected );
|
||||
|
||||
if( hasduplicates )
|
||||
puts( "WARNING: Added numeric suffix to repeated sequence name(s)." );
|
||||
}
|
||||
@ -74,15 +256,19 @@ BoneNameFix
|
||||
*/
|
||||
static void BoneNameFix( void )
|
||||
{
|
||||
int i, counter = 0;
|
||||
int i, protected = 0;
|
||||
mstudiobone_t *bone = (mstudiobone_t *)( (byte *)model_hdr + model_hdr->boneindex );
|
||||
|
||||
for( i = 0; i < model_hdr->numbones; ++i, ++bone )
|
||||
if( bone->name[0] == '\0' )
|
||||
Q_snprintf( bone->name, sizeof( bone->name ), "MDLDEC_Bone%i", ++counter );
|
||||
{
|
||||
bone->name[sizeof( bone->name ) - 1] = '\0';
|
||||
|
||||
if( counter )
|
||||
printf( "WARNING: Gived name to %i unnamed bone(s).\n", counter );
|
||||
if( !IsValidName( bone->name ) )
|
||||
Q_snprintf( bone->name, sizeof( bone->name ), "MDLDEC_Bone%i", ++protected );
|
||||
}
|
||||
|
||||
if( protected )
|
||||
printf( "WARNING: Gived name to %i protected bone(s).\n", protected );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -94,6 +280,7 @@ static qboolean LoadMDL( const char *modelname )
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
off_t filesize;
|
||||
char texturename[MAX_SYSPATH];
|
||||
char seqgroupname[MAX_SYSPATH];
|
||||
const char *ext;
|
||||
@ -124,7 +311,13 @@ static qboolean LoadMDL( const char *modelname )
|
||||
return false;
|
||||
}
|
||||
|
||||
model_hdr = (studiohdr_t *)LoadFile( modelname );
|
||||
model_hdr = (studiohdr_t *)LoadFile( modelname, &filesize );
|
||||
|
||||
if( filesize < sizeof( studiohdr_t ) || filesize != model_hdr->length )
|
||||
{
|
||||
fprintf( stderr, "ERROR: Wrong file size! File %s may be corrupted!\n", modelname );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !model_hdr )
|
||||
{
|
||||
@ -144,7 +337,7 @@ static qboolean LoadMDL( const char *modelname )
|
||||
|
||||
if( model_hdr->version != STUDIO_VERSION )
|
||||
{
|
||||
fprintf( stderr, "ERROR: %s has unknown Studio MDL format version.\n", modelname );
|
||||
fprintf( stderr, "ERROR: %s has unknown Studio MDL format version %d.\n", modelname, model_hdr->version );
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -174,7 +367,7 @@ static qboolean LoadMDL( const char *modelname )
|
||||
Q_strncpy( texturename, modelname, sizeof( texturename ));
|
||||
Q_strncpy( &texturename[len], "t.mdl", sizeof( texturename ) - len );
|
||||
|
||||
texture_hdr = (studiohdr_t *)LoadFile( texturename );
|
||||
texture_hdr = (studiohdr_t *)LoadFile( texturename, &filesize );
|
||||
|
||||
if( !texture_hdr )
|
||||
{
|
||||
@ -182,7 +375,7 @@ static qboolean LoadMDL( const char *modelname )
|
||||
// dirty hack for casesensetive filesystems
|
||||
texturename[len] = 'T';
|
||||
|
||||
texture_hdr = (studiohdr_t *)LoadFile( texturename );
|
||||
texture_hdr = (studiohdr_t *)LoadFile( texturename, &filesize );
|
||||
|
||||
if( !texture_hdr )
|
||||
#endif
|
||||
@ -192,6 +385,12 @@ static qboolean LoadMDL( const char *modelname )
|
||||
}
|
||||
}
|
||||
|
||||
if( filesize < sizeof( studiohdr_t ) || filesize != model_hdr->length )
|
||||
{
|
||||
fprintf( stderr, "ERROR: Wrong file size! File %s may be corrupted!\n", texturename );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( memcmp( &texture_hdr->ident, id_mdlhdr, sizeof( id_mdlhdr ) )
|
||||
|| !texture_hdr->numtextures )
|
||||
{
|
||||
@ -220,7 +419,7 @@ static qboolean LoadMDL( const char *modelname )
|
||||
{
|
||||
Q_snprintf( &seqgroupname[len], sizeof( seqgroupname ) - len, "%02d.mdl", i );
|
||||
|
||||
anim_hdr[i] = (studiohdr_t *)LoadFile( seqgroupname );
|
||||
anim_hdr[i] = (studiohdr_t *)LoadFile( seqgroupname, &filesize );
|
||||
|
||||
if( !anim_hdr[i] )
|
||||
{
|
||||
@ -228,6 +427,12 @@ static qboolean LoadMDL( const char *modelname )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( filesize < sizeof( studiohdr_t ) || filesize != model_hdr->length )
|
||||
{
|
||||
fprintf( stderr, "ERROR: Wrong file size! File %s may be corrupted!\n", seqgroupname );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( memcmp( &anim_hdr[i]->ident, id_seqhdr, sizeof( id_seqhdr ) ) )
|
||||
{
|
||||
fprintf( stderr, "ERROR: %s is not a valid sequence file.\n", seqgroupname );
|
||||
@ -238,6 +443,22 @@ static qboolean LoadMDL( const char *modelname )
|
||||
|
||||
COM_FileBase( modelname, modelfile, sizeof( modelfile ));
|
||||
|
||||
// Some validation checks was found in mdldec-golang by Psycrow101
|
||||
if( model_hdr->numhitboxes > model_hdr->numbones * ( MAXSTUDIOSRCBONES / MAXSTUDIOBONES ))
|
||||
{
|
||||
printf( "WARNING: Invalid hitboxes number %d.\n", model_hdr->numhitboxes );
|
||||
model_hdr->numhitboxes = 0;
|
||||
}
|
||||
else if( model_hdr->hitboxindex + model_hdr->numhitboxes * ( sizeof( mstudiobbox_t ) + sizeof( mstudiohitboxset_t )) > model_hdr->length )
|
||||
{
|
||||
printf( "WARNING: Invalid hitboxes offset %d.\n", model_hdr->hitboxindex );
|
||||
model_hdr->numhitboxes = 0;
|
||||
}
|
||||
|
||||
TextureNameFix();
|
||||
|
||||
BodypartNameFix();
|
||||
|
||||
SequenceNameFix();
|
||||
|
||||
BoneNameFix();
|
||||
|
@ -321,7 +321,6 @@ static void WriteBodyGroupInfo( FILE *fp )
|
||||
int i, j;
|
||||
mstudiobodyparts_t *bodypart = (mstudiobodyparts_t *) ( (byte *)model_hdr + model_hdr->bodypartindex );
|
||||
mstudiomodel_t *model;
|
||||
char modelname[64];
|
||||
|
||||
fprintf( fp, "// %i reference mesh%s\n", model_hdr->numbodyparts, model_hdr->numbodyparts > 1 ? "es" : "" );
|
||||
|
||||
@ -331,9 +330,7 @@ static void WriteBodyGroupInfo( FILE *fp )
|
||||
|
||||
if( bodypart->nummodels == 1 )
|
||||
{
|
||||
COM_FileBase( model->name, modelname, sizeof( modelname ));
|
||||
|
||||
fprintf( fp, "$body \"%s\" \"%s\"\n", bodypart->name, modelname );
|
||||
fprintf( fp, "$body \"%s\" \"%s\"\n", bodypart->name, model->name );
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -349,9 +346,7 @@ static void WriteBodyGroupInfo( FILE *fp )
|
||||
continue;
|
||||
}
|
||||
|
||||
COM_FileBase( model->name, modelname, sizeof( modelname ));
|
||||
|
||||
fprintf( fp, "\tstudio \"%s\"\n", modelname );
|
||||
fprintf( fp, "\tstudio \"%s\"\n", model->name );
|
||||
}
|
||||
|
||||
fputs( "}\n", fp );
|
||||
|
@ -490,7 +490,6 @@ static void WriteReferences( void )
|
||||
FILE *fp;
|
||||
mstudiomodel_t *model;
|
||||
mstudiobodyparts_t *bodypart;
|
||||
char name[64];
|
||||
char filename[MAX_SYSPATH];
|
||||
|
||||
if( !CreateBoneTransformMatrices( &bonetransform ) )
|
||||
@ -517,13 +516,11 @@ static void WriteReferences( void )
|
||||
if( !Q_strncmp( model->name, "blank", 5 ) )
|
||||
continue;
|
||||
|
||||
COM_FileBase( model->name, name, sizeof( name ));
|
||||
|
||||
len = Q_snprintf( filename, MAX_SYSPATH, "%s%s.smd", destdir, name );
|
||||
len = Q_snprintf( filename, MAX_SYSPATH, "%s%s.smd", destdir, model->name );
|
||||
|
||||
if( len == -1 )
|
||||
{
|
||||
fprintf( stderr, "ERROR: Destination path is too long. Can't write %s.smd\n", name );
|
||||
fprintf( stderr, "ERROR: Destination path is too long. Can't write %s.smd\n", model->name );
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
|
@ -34,17 +34,16 @@ static void WriteBMP( mstudiotexture_t *texture )
|
||||
FILE *fp;
|
||||
const byte *p;
|
||||
byte *palette, *pic;
|
||||
char filename[MAX_SYSPATH], texturename[64];
|
||||
char filename[MAX_SYSPATH];
|
||||
rgba_t rgba_palette[256];
|
||||
bmp_t bmp_hdr = {0,};
|
||||
size_t texture_size;
|
||||
|
||||
COM_FileBase( texture->name, texturename, sizeof( texturename ));
|
||||
len = Q_snprintf( filename, MAX_SYSPATH, "%s%s.bmp", destdir, texturename );
|
||||
len = Q_snprintf( filename, MAX_SYSPATH, "%s%s", destdir, texture->name );
|
||||
|
||||
if( len == -1 )
|
||||
{
|
||||
fprintf( stderr, "ERROR: Destination path is too long. Can't write %s.bmp\n", texturename );
|
||||
fprintf( stderr, "ERROR: Destination path is too long. Can't write %s\n", texture->name );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,27 @@ qboolean MakeDirectory( const char *path )
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ExtractFileName
|
||||
============
|
||||
*/
|
||||
void ExtractFileName( char *name, size_t size )
|
||||
{
|
||||
char tmp[MAX_SYSPATH];
|
||||
|
||||
if( !( name && *name ) || size <= 0 )
|
||||
return;
|
||||
|
||||
name[size - 1] = '\0';
|
||||
|
||||
if( Q_strpbrk( name, "/\\" ))
|
||||
{
|
||||
COM_FileBase( name, tmp, sizeof( tmp ));
|
||||
Q_strncpy( name, tmp, size );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
GetFileSize
|
||||
@ -75,25 +96,24 @@ off_t GetSizeOfFile( FILE *fp )
|
||||
LoadFile
|
||||
============
|
||||
*/
|
||||
byte *LoadFile( const char *filename )
|
||||
byte *LoadFile( const char *filename, off_t *size )
|
||||
{
|
||||
FILE *fp;
|
||||
byte *buf;
|
||||
off_t size;
|
||||
|
||||
fp = fopen( filename, "rb" );
|
||||
|
||||
if( !fp )
|
||||
return NULL;
|
||||
|
||||
size = GetSizeOfFile( fp );
|
||||
*size = GetSizeOfFile( fp );
|
||||
|
||||
buf = malloc( size );
|
||||
buf = malloc( *size );
|
||||
|
||||
if( !buf )
|
||||
return NULL;
|
||||
|
||||
fread( buf, size, 1, fp );
|
||||
fread( buf, *size, 1, fp );
|
||||
fclose( fp );
|
||||
|
||||
return buf;
|
||||
|
@ -17,8 +17,9 @@ GNU General Public License for more details.
|
||||
#define UTILS_H
|
||||
|
||||
qboolean MakeDirectory( const char *path );
|
||||
void ExtractFileName( char *name, size_t size );
|
||||
off_t GetSizeOfFile( FILE *fp );
|
||||
byte *LoadFile( const char *filename );
|
||||
byte *LoadFile( const char *filename, off_t *size );
|
||||
|
||||
#endif // UTILS_H
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user