From 9e5d5e0ea313f416522bfc127e58139945bf8919 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 1 Oct 2021 19:58:03 +0300 Subject: [PATCH] public: moved COM_ParseFileSafe to libpublic, added optional argument for length and overflow checking --- engine/client/cl_game.c | 4 +- engine/client/cl_gameui.c | 13 +++- engine/client/cl_qparse.c | 4 +- engine/client/ref_common.c | 1 - engine/common/cmd.c | 4 +- engine/common/common.c | 155 ------------------------------------- engine/common/common.h | 4 - engine/ref_api.h | 1 - public/crtlib.c | 150 +++++++++++++++++++++++++++++++++++ public/crtlib.h | 9 +++ ref_gl/gl_rmisc.c | 14 ++-- 11 files changed, 181 insertions(+), 178 deletions(-) diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 3ea9759b..88df0d1f 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -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; } diff --git a/engine/client/cl_gameui.c b/engine/client/cl_gameui.c index 05362add..87f9adf0 100644 --- a/engine/client/cl_gameui.c +++ b/engine/client/cl_gameui.c @@ -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, diff --git a/engine/client/cl_qparse.c b/engine/client/cl_qparse.c index 37b94930..be3015ad 100644 --- a/engine/client/cl_qparse.c +++ b/engine/client/cl_qparse.c @@ -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; diff --git a/engine/client/ref_common.c b/engine/client/ref_common.c index 4b602c0e..da474089 100644 --- a/engine/client/ref_common.c +++ b/engine/client/ref_common.c @@ -335,7 +335,6 @@ static ref_api_t gEngfuncs = COM_GetProcAddress, FS_LoadFile, - COM_ParseFile, FS_FileExists, FS_AllowDirectPaths, diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 481a78ff..e1cc7493 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -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; diff --git a/engine/common/common.c b/engine/common/common.c index f2307bd0..89192c3b 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -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 diff --git a/engine/common/common.h b/engine/common/common.h index 1407cf04..37ba3d54 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -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 ); diff --git a/engine/ref_api.h b/engine/ref_api.h index c8c66f06..6bcfaef1 100644 --- a/engine/ref_api.h +++ b/engine/ref_api.h @@ -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 ); diff --git a/public/crtlib.c b/public/crtlib.c index 7aa6646f..8e087bac 100644 --- a/public/crtlib.c +++ b/public/crtlib.c @@ -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 ); diff --git a/public/crtlib.h b/public/crtlib.h index 2dd7ad29..111c845d 100644 --- a/public/crtlib.h +++ b/public/crtlib.h @@ -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 ); diff --git a/ref_gl/gl_rmisc.c b/ref_gl/gl_rmisc.c index f687d15e..953c399c 100644 --- a/ref_gl/gl_rmisc.c +++ b/ref_gl/gl_rmisc.c @@ -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 )