diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp index 692bd133521..2f0c54763b0 100644 --- a/core/crypto/crypto.cpp +++ b/core/crypto/crypto.cpp @@ -231,8 +231,7 @@ Error ResourceFormatSaverCrypto::save(const Ref &p_resource, const Str if (cert.is_valid()) { err = cert->save(p_path); } else if (key.is_valid()) { - String el = p_path.get_extension().to_lower(); - err = key->save(p_path, el == "pub"); + err = key->save(p_path, p_path.has_extension("pub")); } else { ERR_FAIL_V(ERR_INVALID_PARAMETER); } diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index d5222f7f315..c821f375b83 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -888,8 +888,7 @@ bool GDExtensionResourceLoader::handles_type(const String &p_type) const { } String GDExtensionResourceLoader::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "gdextension") { + if (p_path.has_extension("gdextension")) { return "GDExtension"; } return ""; diff --git a/core/io/json.cpp b/core/io/json.cpp index 4f6891af72f..5d58e49f198 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -1593,8 +1593,7 @@ bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const { } String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "json") { + if (p_path.has_extension("json")) { return "JSON"; } return ""; diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 6e267a62443..8456a5819a3 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -105,7 +105,6 @@ Error ResourceSaver::save(const Ref &p_resource, const String &p_path, } ERR_FAIL_COND_V_MSG(path.is_empty(), ERR_INVALID_PARAMETER, "Can't save resource to empty path. Provide non-empty path or a Resource with non-empty resource_path."); - String extension = path.get_extension(); Error err = ERR_FILE_UNRECOGNIZED; for (int i = 0; i < saver_count; i++) { diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 0f3cf852a49..8b970ba7e3e 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -368,7 +368,7 @@ bool TranslationLoaderPO::handles_type(const String &p_type) const { } String TranslationLoaderPO::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "po" || p_path.get_extension().to_lower() == "mo") { + if (p_path.has_extension("po") || p_path.has_extension("mo")) { return "Translation"; } return ""; diff --git a/core/string/ustring.h b/core/string/ustring.h index 8dbf593654f..eeedd3edfdb 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -519,6 +519,8 @@ public: String get_basename() const; String path_join(const String &p_path) const; char32_t unicode_at(int p_idx) const; + bool has_extension(const char *p_ext) const { return get_extension().to_lower() == p_ext; } + bool has_extension(const String &p_ext) const { return get_extension().to_lower() == p_ext; } CharString ascii(bool p_allow_extended = false) const; // Parse an ascii string. diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 541af413183..87cf9b86e42 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -1521,7 +1521,7 @@ Error EditorExportPlatform::export_project_files(const Ref & // Just store it as it comes. // Customization only happens if plugins did not take care of it before. - bool force_binary = convert_text_to_binary && (path.get_extension().to_lower() == "tres" || path.get_extension().to_lower() == "tscn"); + bool force_binary = convert_text_to_binary && (path.has_extension("tres") || path.has_extension("tscn")); String export_path = _export_customize(path, customize_resources_plugins, customize_scenes_plugins, export_cache, export_base_path, force_binary); if (export_path != path) { diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index 1f58b05d795..0fc79d6e0b2 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -2514,7 +2514,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, Listpush_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0)); diff --git a/editor/project_manager/project_manager.cpp b/editor/project_manager/project_manager.cpp index 9c1464351e2..42025f655ee 100644 --- a/editor/project_manager/project_manager.cpp +++ b/editor/project_manager/project_manager.cpp @@ -140,7 +140,7 @@ void ProjectManager::_notification(int p_what) { // Utility data. Ref ProjectManager::_file_dialog_get_icon(const String &p_path) { - if (p_path.get_extension().to_lower() == "godot") { + if (p_path.has_extension("godot")) { return singleton->icon_type_cache["GodotMonochrome"]; } @@ -148,7 +148,7 @@ Ref ProjectManager::_file_dialog_get_icon(const String &p_path) { } Ref ProjectManager::_file_dialog_get_thumbnail(const String &p_path) { - if (p_path.get_extension().to_lower() == "godot") { + if (p_path.has_extension("godot")) { return singleton->icon_type_cache["GodotFile"]; } diff --git a/editor/scene/3d/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/scene/3d/gpu_particles_collision_sdf_editor_plugin.cpp index 7b2226c6e83..f32e31b1089 100644 --- a/editor/scene/3d/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/scene/3d/gpu_particles_collision_sdf_editor_plugin.cpp @@ -42,7 +42,6 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_bake() { if (path.is_empty()) { path = "res://" + col_sdf->get_name() + "_data.exr"; } else { - String ext = path.get_extension(); path = path.get_basename() + "." + col_sdf->get_name() + "_data.exr"; } probe_file->set_current_path(path); diff --git a/editor/scene/3d/voxel_gi_editor_plugin.cpp b/editor/scene/3d/voxel_gi_editor_plugin.cpp index e8c97c44f8a..c4ff434f289 100644 --- a/editor/scene/3d/voxel_gi_editor_plugin.cpp +++ b/editor/scene/3d/voxel_gi_editor_plugin.cpp @@ -44,7 +44,6 @@ void VoxelGIEditorPlugin::_bake() { if (path.is_empty()) { path = "res://" + voxel_gi->get_name() + "_data.res"; } else { - String ext = path.get_extension(); path = path.get_basename() + "." + voxel_gi->get_name() + "_data.res"; } probe_file->set_current_path(path); diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 15ff5eac0d5..8cc3f54ae6a 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -735,7 +735,7 @@ bool ResourceFormatDDS::handles_type(const String &p_type) const { } String ResourceFormatDDS::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "dds") { + if (p_path.has_extension("dds")) { return "Texture"; } return ""; diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp index 48c2cbe5041..07273d99d1d 100644 --- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp +++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp @@ -94,7 +94,7 @@ Variant EditorSceneFormatImporterUFBX::get_option_visibility(const String &p_pat void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path, List *r_options) { // Returns all the options when path is empty because that means it's for the Project Settings. - if (p_path.is_empty() || p_path.get_extension().to_lower() == "fbx") { + if (p_path.is_empty() || p_path.has_extension("fbx")) { r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/importer", PROPERTY_HINT_ENUM, "ufbx,FBX2glTF"), FBX_IMPORTER_UFBX)); r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::BOOL, "fbx/allow_geometry_helper_nodes"), false)); r_options->push_back(ResourceImporterScene::ImportOption(PropertyInfo(Variant::INT, "fbx/embedded_image_handling", PROPERTY_HINT_ENUM, "Discard All Textures,Extract Textures,Embed as Basis Universal,Embed as Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), FBXState::HANDLE_BINARY_EXTRACT_TEXTURES)); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 3b7a994771a..08a6005faab 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -492,7 +492,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c } } else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) { const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name); - if (info.path.get_extension().to_lower() != GDScriptLanguage::get_singleton()->get_extension()) { + if (!info.path.has_extension(GDScriptLanguage::get_singleton()->get_extension())) { push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), id); return ERR_PARSE_ERROR; } diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 3e11c0060ee..3cbd817f993 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -76,7 +76,7 @@ Error GDScriptParserRef::raise_status(Status p_new_status) { get_parser()->clear(); status = PARSED; String remapped_path = ResourceLoader::path_remap(path); - if (remapped_path.get_extension().to_lower() == "gdc") { + if (remapped_path.has_extension("gdc")) { Vector tokens = GDScriptCache::get_binary_tokens(remapped_path); source_hash = hash_djb2_buffer(tokens.ptr(), tokens.size()); result = get_parser()->parse_binary(tokens, path); @@ -313,7 +313,7 @@ Ref GDScriptCache::get_shallow_script(const String &p_path, Error &r_e Ref script; script.instantiate(); script->set_path(p_path, true); - if (remapped_path.get_extension().to_lower() == "gdc") { + if (remapped_path.has_extension("gdc")) { Vector buffer = get_binary_tokens(remapped_path); if (buffer.is_empty()) { r_error = ERR_FILE_CANT_READ; @@ -364,7 +364,7 @@ Ref GDScriptCache::get_full_script(const String &p_path, Error &r_erro const String remapped_path = ResourceLoader::path_remap(p_path); if (p_update_from_disk) { - if (remapped_path.get_extension().to_lower() == "gdc") { + if (remapped_path.has_extension("gdc")) { Vector buffer = get_binary_tokens(remapped_path); if (buffer.is_empty()) { r_error = ERR_FILE_CANT_READ; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 66bcfe4b37f..38f710ae1a8 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1123,7 +1123,7 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio for (const KeyValue &E : autoloads) { const ProjectSettings::AutoloadInfo &info = E.value; - if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") { + if (!info.is_singleton || !info.path.has_extension("gd")) { continue; } ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index f46f7b4dfbc..be2a0d8a3c4 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -282,7 +282,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { } else if (binary_tokens && next.ends_with(".textonly.gd")) { next = dir->get_next(); continue; - } else if (next.get_extension().to_lower() == "gd") { + } else if (next.has_extension("gd")) { #ifndef DEBUG_ENABLED // On release builds, skip tests marked as debug only. Error open_err = OK; diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index af180ec16b5..89a01036163 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -344,7 +344,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, const String &p_scene_import_type, const String &p_option, const HashMap &p_options) { - if (p_path.get_extension().to_lower() != "blend") { + if (!p_path.has_extension("blend")) { return true; } @@ -358,7 +358,7 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List *r_options) { // Returns all the options when path is empty because that means it's for the Project Settings. - if (!p_path.is_empty() && p_path.get_extension().to_lower() != "blend") { + if (!p_path.is_empty() && !p_path.has_extension("blend")) { return; } #define ADD_OPTION_BOOL(PATH, VALUE) \ diff --git a/modules/jpg/movie_writer_mjpeg.cpp b/modules/jpg/movie_writer_mjpeg.cpp index e508796e38d..0114c13455f 100644 --- a/modules/jpg/movie_writer_mjpeg.cpp +++ b/modules/jpg/movie_writer_mjpeg.cpp @@ -40,7 +40,7 @@ AudioServer::SpeakerMode MovieWriterMJPEG::get_audio_speaker_mode() const { } bool MovieWriterMJPEG::handles_file(const String &p_path) const { - return p_path.get_extension().to_lower() == "avi"; + return p_path.has_extension("avi"); } void MovieWriterMJPEG::get_supported_extensions(List *r_extensions) const { diff --git a/modules/ktx/texture_loader_ktx.cpp b/modules/ktx/texture_loader_ktx.cpp index 83176e71ca5..f71444f7783 100644 --- a/modules/ktx/texture_loader_ktx.cpp +++ b/modules/ktx/texture_loader_ktx.cpp @@ -602,7 +602,7 @@ bool ResourceFormatKTX::handles_type(const String &p_type) const { } String ResourceFormatKTX::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "ktx" || p_path.get_extension().to_lower() == "ktx2") { + if (p_path.has_extension("ktx") || p_path.has_extension("ktx2")) { return "ImageTexture"; } return ""; diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index ef0f4945d06..2515c3062ef 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -2927,7 +2927,7 @@ bool ResourceFormatLoaderCSharpScript::handles_type(const String &p_type) const } String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path) const { - return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : ""; + return p_path.has_extension("cs") ? CSharpLanguage::get_singleton()->get_type() : ""; } Error ResourceFormatSaverCSharpScript::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) { diff --git a/modules/theora/editor/movie_writer_ogv.cpp b/modules/theora/editor/movie_writer_ogv.cpp index cfe6677300e..cbba4a88c93 100644 --- a/modules/theora/editor/movie_writer_ogv.cpp +++ b/modules/theora/editor/movie_writer_ogv.cpp @@ -101,7 +101,7 @@ AudioServer::SpeakerMode MovieWriterOGV::get_audio_speaker_mode() const { } bool MovieWriterOGV::handles_file(const String &p_path) const { - return p_path.get_extension().to_lower() == "ogv"; + return p_path.has_extension("ogv"); } void MovieWriterOGV::get_supported_extensions(List *r_extensions) const { diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 21a5f11815c..b610384496f 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -819,8 +819,7 @@ bool ResourceFormatLoaderTheora::handles_type(const String &p_type) const { } String ResourceFormatLoaderTheora::get_resource_type(const String &p_path) const { - String el = p_path.get_extension().to_lower(); - if (el == "ogv") { + if (p_path.has_extension("ogv")) { return "VideoStreamTheora"; } return ""; diff --git a/scene/resources/compressed_texture.cpp b/scene/resources/compressed_texture.cpp index e4d9c24326b..76bc95ebaba 100644 --- a/scene/resources/compressed_texture.cpp +++ b/scene/resources/compressed_texture.cpp @@ -486,7 +486,7 @@ bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) } String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "ctex") { + if (p_path.has_extension("ctex")) { return "CompressedTexture2D"; } return ""; @@ -670,7 +670,7 @@ bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) } String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "ctex3d") { + if (p_path.has_extension("ctex3d")) { return "CompressedTexture3D"; } return ""; @@ -844,15 +844,15 @@ CompressedTextureLayered::~CompressedTextureLayered() { Ref ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref ct; - if (p_path.get_extension().to_lower() == "ctexarray") { + if (p_path.has_extension("ctexarray")) { Ref c; c.instantiate(); ct = c; - } else if (p_path.get_extension().to_lower() == "ccube") { + } else if (p_path.has_extension("ccube")) { Ref c; c.instantiate(); ct = c; - } else if (p_path.get_extension().to_lower() == "ccubearray") { + } else if (p_path.has_extension("ccubearray")) { Ref c; c.instantiate(); ct = c; @@ -884,13 +884,13 @@ bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_ } String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "ctexarray") { + if (p_path.has_extension("ctexarray")) { return "CompressedTexture2DArray"; } - if (p_path.get_extension().to_lower() == "ccube") { + if (p_path.has_extension("ccube")) { return "CompressedCubemap"; } - if (p_path.get_extension().to_lower() == "ccubearray") { + if (p_path.has_extension("ccubearray")) { return "CompressedCubemapArray"; } return ""; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 4206d13ea97..7c608742e8b 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1488,7 +1488,7 @@ void ResourceFormatLoaderText::get_classes_used(const String &p_path, HashSet *r_extensions) con } bool MovieWriterPNGWAV::handles_file(const String &p_path) const { - return p_path.get_extension().to_lower() == "png"; + return p_path.has_extension("png"); } String MovieWriterPNGWAV::zeros_str(uint32_t p_index) { diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 70f4eaf6efa..1d91239ad4b 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -1783,6 +1783,13 @@ TEST_CASE("[String] Path functions") { CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path()); } + CHECK(String("res://test.png").has_extension("png")); + CHECK(String("res://test.PNG").has_extension("png")); + CHECK_FALSE(String("res://test.png").has_extension("jpg")); + CHECK_FALSE(String("res://test.png/README").has_extension("png")); + CHECK_FALSE(String("res://test.").has_extension("png")); + CHECK_FALSE(String("res://test").has_extension("png")); + static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" }; static const bool valid[3] = { true, false, false }; for (int i = 0; i < 3; i++) {