public: moved COM_ParseFileSafe to libpublic, added optional argument for length and overflow checking

This commit is contained in:
Alibek Omarov 2021-10-01 19:58:03 +03:00 committed by a1batross
parent a235bec5f1
commit 9e5d5e0ea3
11 changed files with 181 additions and 178 deletions

View File

@ -3078,9 +3078,7 @@ char *pfnParseFile( char *data, char *token )
{
char *out;
host.com_handlecolon = true;
out = COM_ParseFile( data, token );
host.com_handlecolon = false;
out = _COM_ParseFileSafe( data, token, -1, PFILE_HANDLECOLON, NULL );
return out;
}

View File

@ -1106,6 +1106,17 @@ static void GAME_EXPORT UI_ShellExecute( const char *path, const char *parms, in
Sys_Quit();
}
/*
==============
pfnParseFile
legacy wrapper
==============
*/
static char *pfnParseFile( char *buf, char *token )
{
return COM_ParseFile( buf, token );
}
// engine callbacks
static ui_enginefuncs_t gEngfuncs =
@ -1159,7 +1170,7 @@ static ui_enginefuncs_t gEngfuncs =
CL_Active,
pfnClientJoin,
COM_LoadFileForMe,
COM_ParseFile,
pfnParseFile,
COM_FreeFile,
Key_ClearStates,
Key_SetKeyDest,

View File

@ -861,9 +861,7 @@ void CL_QuakeExecStuff( void )
if( !*text ) break;
host.com_ignorebracket = true;
text = COM_ParseFile( text, token );
host.com_ignorebracket = false;
text = _COM_ParseFileSafe( text, token, sizeof( token ), PFILE_IGNOREBRACKET, NULL );
if( !text ) break;

View File

@ -335,7 +335,6 @@ static ref_api_t gEngfuncs =
COM_GetProcAddress,
FS_LoadFile,
COM_ParseFile,
FS_FileExists,
FS_AllowDirectPaths,

View File

@ -595,9 +595,7 @@ void Cmd_TokenizeString( const char *text )
if( cmd_argc == 1 )
cmd_args = text;
host.com_ignorebracket = true;
text = COM_ParseFile( (char*)text, cmd_token );
host.com_ignorebracket = false;
text = _COM_ParseFileSafe( (char*)text, cmd_token, sizeof( cmd_token ), PFILE_IGNOREBRACKET, NULL );
if( !text ) return;

View File

@ -429,31 +429,6 @@ uint LZSS_Decompress( const byte *pInput, byte *pOutput )
return totalBytes;
}
/*
==============
COM_IsSingleChar
interpert this character as single
==============
*/
static int COM_IsSingleChar( char c )
{
if( c == '{' || c == '}' || c == '\'' || c == ',' )
return true;
if( !host.com_ignorebracket && ( c == ')' || c == '(' ))
return true;
if( host.com_handlecolon && c == ':' )
return true;
return false;
}
/*
==============
COM_IsWhiteSpace
@ -469,136 +444,6 @@ static int COM_IsWhiteSpace( char space )
return 0;
}
/*
==============
COM_ParseFile
text parser
==============
*/
char *COM_ParseFileSafe( char *data, char *token, const size_t size )
{
int c, len;
if( !token || !size )
return NULL;
len = 0;
token[0] = 0;
if( !data )
return NULL;
// skip whitespace
skipwhite:
while(( c = ((byte)*data)) <= ' ' )
{
if( c == 0 )
return NULL; // end of file;
data++;
}
// skip // comments
if( c == '/' && data[1] == '/' )
{
while( *data && *data != '\n' )
data++;
goto skipwhite;
}
// handle quoted strings specially
if( c == '\"' )
{
data++;
while( 1 )
{
c = (byte)*data;
// unexpected line end
if( !c )
{
token[len] = 0;
return data;
}
data++;
if( c == '\\' && *data == '"' )
{
if( len + 1 < size )
{
token[len] = (byte)*data;
len++;
}
data++;
continue;
}
if( c == '\"' )
{
token[len] = 0;
return data;
}
if( len + 1 < size )
{
token[len] = c;
len++;
}
}
}
// parse single characters
if( COM_IsSingleChar( c ))
{
if( size >= 2 ) // char and \0
{
token[len] = c;
len++;
token[len] = 0;
return data + 1;
}
else
{
// couldn't pass anything
token[0] = 0;
return data;
}
}
// parse a regular word
do
{
if( len + 1 < size )
{
token[len] = c;
len++;
}
data++;
c = ((byte)*data);
if( COM_IsSingleChar( c ))
break;
} while( c > 32 );
token[len] = 0;
return data;
}
/*
================
COM_ParseFile
old unsafe version of ParseFile, deprecated
only for API compatibility
================
*/
char *COM_ParseFile( char *data, char *token )
{
return COM_ParseFileSafe( data, token, -1 );
}
/*
================
COM_ParseVector

View File

@ -422,8 +422,6 @@ typedef struct host_parm_s
qboolean stuffcmds_pending; // should execute stuff commands
qboolean allow_cheats; // this host will allow cheating
qboolean con_showalways; // show console always (developer and dedicated)
qboolean com_handlecolon; // allow COM_ParseFile to handle colon as single char
qboolean com_ignorebracket; // allow COM_ParseFile to ignore () as single char
qboolean change_game; // initialize when game is changed
qboolean mouse_visible; // vgui override cursor control
qboolean shutdown_issued; // engine is shutting down
@ -854,8 +852,6 @@ void CL_LegacyUpdateInfo( void );
void CL_CharEvent( int key );
qboolean CL_DisableVisibility( void );
int CL_PointContents( const vec3_t point );
char *COM_ParseFile( char *data, char *token );
char *COM_ParseFileSafe( char *data, char *token, const size_t size );
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength );
int CL_GetDemoComment( const char *demoname, char *comment );
void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appName );

View File

@ -369,7 +369,6 @@ typedef struct ref_api_s
// filesystem
byte* (*COM_LoadFile)( const char *path, fs_offset_t *pLength, qboolean gamedironly );
char* (*COM_ParseFile)( char *data, char *token );
// use Mem_Free instead
// void (*COM_FreeFile)( void *buffer );
int (*FS_FileExists)( const char *filename, int gamedironly );

View File

@ -967,6 +967,156 @@ void COM_Hex2String( uint8_t hex, char *str )
*str = '\0';
}
/*
==============
COM_IsSingleChar
interpert this character as single
==============
*/
static int COM_IsSingleChar( unsigned int flags, char c )
{
if( c == '{' || c == '}' || c == '\'' || c == ',' )
return true;
if( !FBitSet( flags, PFILE_IGNOREBRACKET ) && ( c == ')' || c == '(' ))
return true;
if( FBitSet( flags, PFILE_HANDLECOLON ) && c == ':' )
return true;
return false;
}
/*
==============
COM_ParseFile
text parser
==============
*/
const char *_COM_ParseFileSafe( const char *data, char *token, const int size, unsigned int flags, int *plen )
{
int c, len = 0;
qboolean overflow = false;
if( !token || !size )
{
if( plen ) *plen = 0;
return NULL;
}
token[0] = 0;
if( !data )
return NULL;
// skip whitespace
skipwhite:
while(( c = ((byte)*data)) <= ' ' )
{
if( c == 0 )
{
if( plen ) *plen = overflow ? -1 : len;
return NULL; // end of file;
}
data++;
}
// skip // comments
if( c == '/' && data[1] == '/' )
{
while( *data && *data != '\n' )
data++;
goto skipwhite;
}
// handle quoted strings specially
if( c == '\"' )
{
data++;
while( 1 )
{
c = (byte)*data;
// unexpected line end
if( !c )
{
token[len] = 0;
if( plen ) *plen = overflow ? -1 : len;
return data;
}
data++;
if( c == '\\' && *data == '"' )
{
if( len + 1 < size )
{
token[len] = (byte)*data;
len++;
}
data++;
continue;
}
if( c == '\"' )
{
token[len] = 0;
if( plen ) *plen = overflow ? -1 : len;
return data;
}
if( len + 1 < size )
{
token[len] = c;
len++;
}
}
}
// parse single characters
if( COM_IsSingleChar( flags, c ))
{
if( size >= 2 ) // char and \0
{
token[len] = c;
len++;
token[len] = 0;
if( plen ) *plen = overflow ? -1 : len;
return data + 1;
}
else
{
// couldn't pass anything
token[0] = 0;
if( plen ) *plen = overflow ? -1 : len;
return data;
}
}
// parse a regular word
do
{
if( len + 1 < size )
{
token[len] = c;
len++;
}
data++;
c = ((byte)*data);
if( COM_IsSingleChar( flags, c ))
break;
} while( c > 32 );
token[len] = 0;
if( plen ) *plen = overflow ? -1 : len;
return data;
}
int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive )
{
return matchpattern_with_separator( in, pattern, caseinsensitive, "/\\:", false );

View File

@ -38,6 +38,12 @@ enum
TIME_FILENAME,
};
enum
{
PFILE_IGNOREBRACKET = BIT( 0 ),
PFILE_HANDLECOLON = BIT( 1 )
};
//
// crtlib.c
//
@ -89,6 +95,9 @@ char COM_Hex2Char( uint8_t hex );
void COM_Hex2String( uint8_t hex, char *str );
#define COM_CheckString( string ) ( ( !string || !*string ) ? 0 : 1 )
#define COM_CheckStringEmpty( string ) ( ( !*string ) ? 0 : 1 )
const char *_COM_ParseFileSafe( const char *data, char *token, const int size, unsigned int flags, int *len );
#define COM_ParseFileSafe( data, token, size ) _COM_ParseFileSafe( data, token, size, 0, NULL )
#define COM_ParseFile( data, token ) COM_ParseFileSafe( data, token, -1 )
int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive );
int matchpattern_with_separator( const char *in, const char *pattern, qboolean caseinsensitive, const char *separators, qboolean wildcard_least_one );

View File

@ -35,7 +35,7 @@ static void R_ParseDetailTextures( const char *filename )
pfile = (char *)afile;
// format: 'texturename' 'detailtexture' 'xScale' 'yScale'
while(( pfile = gEngfuncs.COM_ParseFile( pfile, token )) != NULL )
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
{
texname[0] = '\0';
detail_texname[0] = '\0';
@ -45,26 +45,26 @@ static void R_ParseDetailTextures( const char *filename )
{
// NOTE: COM_ParseFile handled some symbols seperately
// this code will be fix it
pfile = gEngfuncs.COM_ParseFile( pfile, token );
pfile = COM_ParseFile( pfile, token );
Q_strncat( texname, "{", sizeof( texname ));
Q_strncat( texname, token, sizeof( texname ));
}
else Q_strncpy( texname, token, sizeof( texname ));
// read detailtexture name
pfile = gEngfuncs.COM_ParseFile( pfile, token );
pfile = COM_ParseFile( pfile, token );
Q_strncat( detail_texname, token, sizeof( detail_texname ));
// trying the scales or '{'
pfile = gEngfuncs.COM_ParseFile( pfile, token );
pfile = COM_ParseFile( pfile, token );
// read second part of detailtexture name
if( token[0] == '{' )
{
Q_strncat( detail_texname, token, sizeof( detail_texname ));
pfile = gEngfuncs.COM_ParseFile( pfile, token ); // read scales
pfile = COM_ParseFile( pfile, token ); // read scales
Q_strncat( detail_texname, token, sizeof( detail_texname ));
pfile = gEngfuncs.COM_ParseFile( pfile, token ); // parse scales
pfile = COM_ParseFile( pfile, token ); // parse scales
}
Q_snprintf( detail_path, sizeof( detail_path ), "gfx/%s", detail_texname );
@ -72,7 +72,7 @@ static void R_ParseDetailTextures( const char *filename )
// read scales
xScale = Q_atof( token );
pfile = gEngfuncs.COM_ParseFile( pfile, token );
pfile = COM_ParseFile( pfile, token );
yScale = Q_atof( token );
if( xScale <= 0.0f || yScale <= 0.0f )