diff --git a/libs/os/path.h b/libs/os/path.h index aef9ce14..6a8852da 100644 --- a/libs/os/path.h +++ b/libs/os/path.h @@ -185,6 +185,12 @@ inline bool extension_equal( const char* extension, const char* other ){ return string_equal_nocase( extension, other ); } +/// \brief Returns true if \p extension equals one of \p path. \p extension without period. +/// O(n) +inline bool path_extension_is( const char* path, const char* extension ){ + return extension_equal( path_get_extension( path ), extension ); +} + template class MatchFileExtension { diff --git a/plugins/assmodel/model.cpp b/plugins/assmodel/model.cpp index bb496ca1..d7f5dc84 100644 --- a/plugins/assmodel/model.cpp +++ b/plugins/assmodel/model.cpp @@ -693,10 +693,9 @@ scene::Node& loadPicoModel( Assimp::Importer& importer, ArchiveFile& file ){ if( scene != nullptr ){ if( scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE ) globalWarningStream() << "AI_SCENE_FLAGS_INCOMPLETE\n"; - const char *ext = path_get_extension( file.getName() ); const auto rootPath = StringOutputStream()( PathFilenameless( file.getName() ) ); const auto matName = StringOutputStream()( PathExtensionless( file.getName() ) ); - return ( new PicoModelNode( AssScene{ scene, rootPath, string_equal_nocase( ext, "mdl" )? matName.c_str() : nullptr } ) )->node(); + return ( new PicoModelNode( AssScene{ scene, rootPath, path_extension_is( file.getName(), "mdl" )? matName.c_str() : nullptr } ) )->node(); } else{ return ( new PicoModelNode() )->node(); diff --git a/plugins/shaders/shaders.cpp b/plugins/shaders/shaders.cpp index 9c8acff1..f12bf8e3 100644 --- a/plugins/shaders/shaders.cpp +++ b/plugins/shaders/shaders.cpp @@ -1580,7 +1580,7 @@ void BuildShaderList( TextInputStream& shaderlist ){ { // each token should be a shader filename shaderFile << token; - if( !string_equal_nocase( path_get_extension( token ), g_shadersExtension ) ) + if( !path_extension_is( token, g_shadersExtension ) ) shaderFile << "." << g_shadersExtension; ShaderList_addShaderFile( shaderFile.c_str() ); diff --git a/plugins/vfspk3/vfs.cpp b/plugins/vfspk3/vfs.cpp index 7576fd69..c16f7672 100644 --- a/plugins/vfspk3/vfs.cpp +++ b/plugins/vfspk3/vfs.cpp @@ -187,7 +187,7 @@ public: if ( subname[0] == '/' ) { ++subname; } - if ( m_extension[0] == '*' || extension_equal( path_get_extension( subname ), m_extension ) ) { + if ( m_extension[0] == '*' || path_extension_is( subname, m_extension ) ) { pathlist_append_unique( m_matches, subname ); } } diff --git a/radiant/environment.cpp b/radiant/environment.cpp index d37941f2..da39ca9c 100644 --- a/radiant/environment.cpp +++ b/radiant/environment.cpp @@ -199,7 +199,7 @@ CopiedString g_openMapByCmd; void cmdMap(){ for ( int i = 1; i < g_argc; ++i ) - if( extension_equal( path_get_extension( g_argv[i] ), "map" ) ){ + if( path_extension_is( g_argv[i], "map" ) ){ g_openMapByCmd = StringOutputStream( 256 )( PathCleaned( g_argv[i] ) ).c_str(); return; } diff --git a/radiant/map.cpp b/radiant/map.cpp index 84b2230c..b7e29c3b 100644 --- a/radiant/map.cpp +++ b/radiant/map.cpp @@ -1677,7 +1677,7 @@ bool Map_ImportFile( const char* filename ){ bool success = false; - if ( extension_equal( path_get_extension( filename ), "bsp" ) ) { + if ( path_extension_is( filename, "bsp" ) ) { goto tryDecompile; } @@ -1713,37 +1713,25 @@ bool Map_ImportFile( const char* filename ){ tryDecompile: const char *type = GlobalRadiant().getGameDescriptionKeyValue( "q3map2_type" ); - int n = string_length( path_get_extension( filename ) ); - if ( n && ( extension_equal( path_get_extension( filename ), "bsp" ) || extension_equal( path_get_extension( filename ), "map" ) ) ) { - StringBuffer output; - output.push_string( AppPath_get() ); - output.push_string( "q3map2." ); - output.push_string( RADIANT_EXECUTABLE ); - output.push_string( " -v -game " ); - output.push_string( ( type && *type ) ? type : "quake3" ); - output.push_string( " -fs_basepath \"" ); - output.push_string( EnginePath_get() ); - output.push_string( "\" -fs_homepath \"" ); - output.push_string( g_qeglobals.m_userEnginePath.c_str() ); - output.push_string( "\" -fs_game " ); - output.push_string( gamename_get() ); - output.push_string( " -convert -format " ); - output.push_string( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ) == TEXDEFTYPEID_QUAKE ? "map" : "map_bp" ); - if ( extension_equal( path_get_extension( filename ), "map" ) ) { - output.push_string( " -readmap " ); + if ( path_extension_is( filename, "bsp" ) || path_extension_is( filename, "map" ) ) { + StringOutputStream str( 256 ); + str << AppPath_get() << "q3map2." << RADIANT_EXECUTABLE; + str << " -v -game " << ( ( type && *type ) ? type : "quake3" ); + str << " -fs_basepath " << makeQuoted( EnginePath_get() ); + str << " -fs_homepath " << makeQuoted( g_qeglobals.m_userEnginePath.c_str() ); + str << " -fs_game " << gamename_get(); + str << " -convert -format " << ( BrushType_getTexdefType( GlobalBrushCreator().getFormat() ) == TEXDEFTYPEID_QUAKE ? "map" : "map_bp" ); + if ( path_extension_is( filename, "map" ) ) { + str << " -readmap "; } - output.push_string( " \"" ); - output.push_string( filename ); - output.push_string( "\"" ); + str << ' ' << makeQuoted( filename ); // run - Q_Exec( NULL, output.c_str(), NULL, false, true ); + Q_Exec( NULL, str.c_str(), NULL, false, true ); // rebuild filename as "filenamewithoutext_converted.map" - output.clear(); - output.push_range( filename, filename + string_length( filename ) - ( n + 1 ) ); - output.push_string( "_converted.map" ); - filename = output.c_str(); + str( PathExtensionless( filename ), "_converted.map" ); + filename = str.c_str(); EBrushType brush_type = GlobalBrushCreator().getFormat(); // open diff --git a/radiant/modelwindow.cpp b/radiant/modelwindow.cpp index 6b0edd1b..a678412b 100644 --- a/radiant/modelwindow.cpp +++ b/radiant/modelwindow.cpp @@ -1192,7 +1192,7 @@ public: : m_modelExtensions( modelExtensions ), m_modelFS( modelFS ), m_modelFoldersMap( modelFoldersMap ){ } void visit( const char* name ) override { - if( m_modelExtensions.find( path_get_extension( name ) ) != m_modelExtensions.end() && ( !m_avoid_pk3dir || !string_in_string_nocase( name, ".pk3dir/" ) ) ){ + if( m_modelExtensions.count( path_get_extension( name ) ) && ( !m_avoid_pk3dir || !string_in_string_nocase( name, ".pk3dir/" ) ) ){ m_modelFS.insert( name ); //% globalOutputStream() << name << " name\n"; } diff --git a/radiant/preferences.cpp b/radiant/preferences.cpp index 1b2f7876..328ae584 100644 --- a/radiant/preferences.cpp +++ b/radiant/preferences.cpp @@ -311,7 +311,7 @@ public: LoadGameFile( std::list& games, const char* path ) : mGames( games ), mPath( path ){ } void operator()( const char* name ) const { - if ( !extension_equal( path_get_extension( name ), "game" ) ) { + if ( !path_extension_is( name, "game" ) ) { return; } StringOutputStream strPath( 256 ); diff --git a/radiant/referencecache.cpp b/radiant/referencecache.cpp index 603745c7..430370c6 100644 --- a/radiant/referencecache.cpp +++ b/radiant/referencecache.cpp @@ -115,11 +115,10 @@ bool MapResource_saveFile( const MapFormat& format, scene::Node& root, GraphTrav bool file_saveBackup( const char* path ){ if ( file_writeable( path ) ) { - StringOutputStream backup( 256 ); - backup << StringRange( path, path_get_extension( path ) ) << "bak"; + const auto backup = StringOutputStream( 256 )( PathExtensionless( path ), ".bak" ); - return ( !file_exists( backup.c_str() ) || file_remove( backup.c_str() ) ) // remove backup - && file_move( path, backup.c_str() ); // rename current to backup + return ( !file_exists( backup ) || file_remove( backup ) ) // remove backup + && file_move( path, backup ); // rename current to backup } globalErrorStream() << "map path is not writeable: " << makeQuoted( path ) << "\n"; diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index 51cd8221..2f1144cb 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -91,7 +91,7 @@ bool string_equal_start( const char* string, StringRange start ){ typedef std::set TextureGroups; void TextureGroups_addWad( TextureGroups& groups, const char* archive ){ - if ( extension_equal( path_get_extension( archive ), "wad" ) ) { + if ( path_extension_is( archive, "wad" ) ) { #if 1 groups.insert( archive ); #else diff --git a/tools/quake3/common/imagelib.cpp b/tools/quake3/common/imagelib.cpp index 792a55b3..fc257325 100644 --- a/tools/quake3/common/imagelib.cpp +++ b/tools/quake3/common/imagelib.cpp @@ -820,9 +820,7 @@ void LoadBMP( const char *filename, byte **pic, byte **palette, int *width, int ============== */ void Load256Image( const char *name, byte **pixels, byte **palette, int *width, int *height ){ - const char *ext = path_get_extension( name ); - - if ( striEqual( ext, "lbm" ) ) { + if ( path_extension_is( name, "lbm" ) ) { LoadLBM( name, pixels, palette ); if ( width ) { *width = bmhd.w; @@ -831,10 +829,10 @@ void Load256Image( const char *name, byte **pixels, byte **palette, int *width, *height = bmhd.h; } } - else if ( striEqual( ext, "pcx" ) ) { + else if ( path_extension_is( name, "pcx" ) ) { LoadPCX( name, pixels, palette, width, height ); } - else if ( striEqual( ext, "bmp" ) ) { + else if ( path_extension_is( name, "bmp" ) ) { LoadBMP( name, pixels, palette, width, height ); } else{ @@ -852,12 +850,11 @@ void Load256Image( const char *name, byte **pixels, byte **palette, int *width, */ void Save256Image( const char *name, byte *pixels, byte *palette, int width, int height ){ - const char *ext = path_get_extension( name ); - if ( striEqual( ext, "lbm" ) ) { + if ( path_extension_is( name, "lbm" ) ) { WriteLBMfile( name, pixels, width, height, palette ); } - else if ( striEqual( ext, "pcx" ) ) { + else if ( path_extension_is( name, "pcx" ) ) { WritePCXfile( name, pixels, width, height, palette ); } else{ @@ -1203,7 +1200,7 @@ void Load32BitImage( const char *name, unsigned **pixels, int *width, int *heig int i; int v; - if ( striEqual( path_get_extension( name ), "tga" ) ) { + if ( path_extension_is( name, "tga" ) ) { LoadTGA( name, (byte **)pixels, width, height ); } else { diff --git a/tools/quake3/common/vfs.cpp b/tools/quake3/common/vfs.cpp index de105909..6a6894c2 100644 --- a/tools/quake3/common/vfs.cpp +++ b/tools/quake3/common/vfs.cpp @@ -192,12 +192,10 @@ void vfsInitDirectory( const char *path ){ if ( path_is_forbidden( name ) ) continue; - const char *ext = path_get_filename_base_end( name ); - - if ( striEqual( ext, ".pk3" ) ) { + if ( path_extension_is( name, "pk3" ) ) { paks.push_back( StringOutputStream( 256 )( pathCleaned, name ) ); } - else if ( striEqual( ext, ".pk3dir" ) ) { + else if ( path_extension_is( name, "pk3dir" ) ) { g_strDirs.emplace_back( StringOutputStream( 256 )( pathCleaned, name, '/' ) ); } } @@ -235,7 +233,7 @@ std::vector vfsListShaderFiles( const char *shaderPath ){ const char* name; while ( ( name = g_dir_read_name( dir ) ) ) { - if ( striEqual( path_get_filename_base_end( name ), ".shader" ) ) { + if ( path_extension_is( name, "shader" ) ) { insert( name ); } } @@ -246,7 +244,7 @@ std::vector vfsListShaderFiles( const char *shaderPath ){ for ( const VFS_PAKFILE& file : g_pakFiles ) { const char *name = file.name.c_str(); - if ( striEqual( path_get_filename_base_end( name ), ".shader" ) + if ( path_extension_is( name, "shader" ) && strniEqual( name, shaderPath, path_get_last_separator( name ) - name ) ) { insert( path_get_filename_start( name ) ); } diff --git a/tools/quake3/q3data/polyset.cpp b/tools/quake3/q3data/polyset.cpp index c03dd8be..469aca1b 100644 --- a/tools/quake3/q3data/polyset.cpp +++ b/tools/quake3/q3data/polyset.cpp @@ -84,7 +84,7 @@ polyset_t *Polyset_LoadSets( const char *file, int *numpolysets, int maxTrisPerS // // load the frame // - if ( striEqual( path_get_filename_base_end( file ), ".3ds" ) ) { + if ( path_extension_is( file, "3ds" ) ) { _3DS_LoadPolysets( file, &psets, numpolysets, g_verbose ); } else{ diff --git a/tools/quake3/q3data/q3data.cpp b/tools/quake3/q3data/q3data.cpp index 39b8f683..684de75f 100644 --- a/tools/quake3/q3data/q3data.cpp +++ b/tools/quake3/q3data/q3data.cpp @@ -576,7 +576,7 @@ int main( int argc, char **argv ){ } else if ( !strcmp( argv[i], "-dump" ) ) { printf( "Dumping contents of: '%s'\n", argv[i + 1] ); - if ( striEqual( path_get_filename_base_end( argv[i + 1] ), ".md3" ) ) { + if ( path_extension_is( argv[i + 1], "md3" ) ) { MD3_Dump( argv[i + 1] ); } else diff --git a/tools/quake3/q3map2/autopk3.cpp b/tools/quake3/q3map2/autopk3.cpp index 64cb1db3..da684efa 100644 --- a/tools/quake3/q3map2/autopk3.cpp +++ b/tools/quake3/q3map2/autopk3.cpp @@ -788,7 +788,7 @@ int repackBSPMain( Args& args ){ std::vector bspList; // absolute bsp paths - if ( striEqual( path_get_filename_base_end( fileName ), ".bsp" ) ){ + if ( path_extension_is( fileName, "bsp" ) ){ while( !args.empty() ){ // handle multiple bsps input bspList.emplace_back( stream( PathExtensionless( ExpandArg( args.takeFront() ) ), ".bsp" ) ); } diff --git a/tools/quake3/q3map2/bsp.cpp b/tools/quake3/q3map2/bsp.cpp index 37357e96..0936a1dd 100644 --- a/tools/quake3/q3map2/bsp.cpp +++ b/tools/quake3/q3map2/bsp.cpp @@ -885,10 +885,10 @@ int BSPMain( Args& args ){ /* expand mapname */ strcpy( name, ExpandArg( fileName ) ); - if ( !striEqual( path_get_filename_base_end( name ), ".reg" ) ) { /* not .reg */ + if ( !path_extension_is( name, "reg" ) ) { /* not .reg */ /* if we are doing a full map, delete the last saved region map */ remove( StringOutputStream( 256 )( source, ".reg" ) ); - if ( !onlyents || !striEqual( path_get_filename_base_end( name ), ".ent" ) ) { + if ( !onlyents || !path_extension_is( name, "ent" ) ) { path_set_extension( name, ".map" ); /* .reg and .ent are ok too */ } } diff --git a/tools/quake3/q3map2/convert_bsp.cpp b/tools/quake3/q3map2/convert_bsp.cpp index 10fbf8c1..c81a49e0 100644 --- a/tools/quake3/q3map2/convert_bsp.cpp +++ b/tools/quake3/q3map2/convert_bsp.cpp @@ -879,7 +879,7 @@ int ConvertBSPMain( Args& args ){ force_bsp = true; } - if ( force_map || ( !force_bsp && striEqual( path_get_extension( source ), "map" ) && map_allowed ) ) { + if ( force_map || ( !force_bsp && path_extension_is( source, "map" ) && map_allowed ) ) { if ( !map_allowed ) { Sys_Warning( "the requested conversion should not be done from .map files. Compile a .bsp first.\n" ); } diff --git a/tools/quake3/q3map2/light.cpp b/tools/quake3/q3map2/light.cpp index 39ada471..004ad443 100644 --- a/tools/quake3/q3map2/light.cpp +++ b/tools/quake3/q3map2/light.cpp @@ -2677,7 +2677,7 @@ int LightMain( Args& args ){ path_set_extension( source, ".bsp" ); strcpy( name, ExpandArg( fileName ) ); - if ( !striEqual( path_get_filename_base_end( name ), ".reg" ) ) { /* not .reg */ + if ( !path_extension_is( name, "reg" ) ) { /* not .reg */ path_set_extension( name, ".map" ); } diff --git a/tools/quake3/q3map2/map.cpp b/tools/quake3/q3map2/map.cpp index 5198d236..9a04619f 100644 --- a/tools/quake3/q3map2/map.cpp +++ b/tools/quake3/q3map2/map.cpp @@ -1381,7 +1381,7 @@ void LoadEntityIndexMap( entity_t *e ){ Sys_FPrintf( SYS_VRB, "Entity %d (%s) has shader index map \"%s\"\n", mapEnt->mapEntityNum, e->classname(), indexMapFilename ); /* handle tga image */ - if ( striEqual( path_get_extension( indexMapFilename ), "tga" ) ) { + if ( path_extension_is( indexMapFilename, "tga" ) ) { /* load it */ Load32BitImage( indexMapFilename, &pixels32, &w, &h ); diff --git a/tools/quake3/q3map2/shaders.cpp b/tools/quake3/q3map2/shaders.cpp index 4bd4d180..d53f54a5 100644 --- a/tools/quake3/q3map2/shaders.cpp +++ b/tools/quake3/q3map2/shaders.cpp @@ -2012,7 +2012,7 @@ void LoadShaderInfo( void ){ return false; }; - if( !striEqual( path_get_extension( token ), "shader" ) ) + if( !path_extension_is( token , "shader" ) ) strcatQ( token, ".shader", sizeof( token ) ); /* new shader file */ if ( !contains( token ) ) {