From 7c8485e5328b74af1d6a31a855fd814fbd0a707d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Fri, 5 Dec 2025 22:13:48 +0200 Subject: [PATCH] [macOS/iOS] Escape .plist strings on export. --- .../editor_export_platform_apple_embedded.cpp | 26 +++--- platform/macos/export/export_plugin.cpp | 80 +++++++++---------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/editor/export/editor_export_platform_apple_embedded.cpp b/editor/export/editor_export_platform_apple_embedded.cpp index 0d670365b11..427c5d54248 100644 --- a/editor/export/editor_export_platform_apple_embedded.cpp +++ b/editor/export/editor_export_platform_apple_embedded.cpp @@ -401,7 +401,7 @@ String EditorExportPlatformAppleEmbedded::_process_config_file_line(const Refget("application/bundle_identifier")) + "\n"; } else if (p_line.contains("$short_version")) { @@ -593,13 +593,13 @@ String EditorExportPlatformAppleEmbedded::_process_config_file_line(const Refget("privacy/camera_usage_description"); - strnew += p_line.replace("$camera_usage_description", description) + "\n"; + strnew += p_line.replace("$camera_usage_description", description.xml_escape(true)) + "\n"; } else if (p_line.contains("$microphone_usage_description")) { String description = p_preset->get("privacy/microphone_usage_description"); - strnew += p_line.replace("$microphone_usage_description", description) + "\n"; + strnew += p_line.replace("$microphone_usage_description", description.xml_escape(true)) + "\n"; } else if (p_line.contains("$photolibrary_usage_description")) { String description = p_preset->get("privacy/photolibrary_usage_description"); - strnew += p_line.replace("$photolibrary_usage_description", description) + "\n"; + strnew += p_line.replace("$photolibrary_usage_description", description.xml_escape(true)) + "\n"; } else if (p_line.contains("$pbx_locale_file_reference")) { String locale_files; Vector translations = get_project_setting(p_preset, "internationalization/locale/translations"); @@ -1933,10 +1933,10 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Ref f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); - f->store_line("CFBundleDisplayName = \"" + project_name + "\";"); - f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String() + "\";"); - f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";"); - f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";"); + f->store_line("CFBundleDisplayName = \"" + project_name.xml_escape(true) + "\";"); + f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String().xml_escape(true) + "\";"); + f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String().xml_escape(true) + "\";"); + f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String().xml_escape(true) + "\";"); } for (const String &lang : locales) { @@ -1954,20 +1954,20 @@ Error EditorExportPlatformAppleEmbedded::_export_project_helper(const Refset_locale_override(lang); const String &name = domain->translate(project_name, String()); if (name != project_name) { - f->store_line("CFBundleDisplayName = \"" + name + "\";"); + f->store_line("CFBundleDisplayName = \"" + name.xml_escape(true) + "\";"); } } else if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String().xml_escape(true) + "\";"); } if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (photolibrary_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } } } diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index bf66150fa02..1d13af4a698 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -843,7 +843,7 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref &p_pres if (lines[i].contains("$binary")) { strnew += lines[i].replace("$binary", p_binary) + "\n"; } else if (lines[i].contains("$name")) { - strnew += lines[i].replace("$name", get_project_setting(p_preset, "application/config/name")) + "\n"; + strnew += lines[i].replace("$name", get_project_setting(p_preset, "application/config/name").operator String().xml_escape(true)) + "\n"; } else if (lines[i].contains("$bundle_identifier")) { strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n"; } else if (lines[i].contains("$short_version")) { @@ -856,7 +856,7 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref &p_pres String cat = p_preset->get("application/app_category"); strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n"; } else if (lines[i].contains("$copyright")) { - strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; + strnew += lines[i].replace("$copyright", p_preset->get("application/copyright").operator String().xml_escape(true)) + "\n"; } else if (lines[i].contains("$min_version_arm64")) { strnew += lines[i].replace("$min_version_arm64", p_preset->get("application/min_macos_version_arm64")) + "\n"; } else if (lines[i].contains("$min_version_x86_64")) { @@ -889,47 +889,47 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref &p_pres String descriptions; if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { descriptions += "\tNSMicrophoneUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/microphone_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/microphone_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/camera_usage_description")).is_empty()) { descriptions += "\tNSCameraUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/camera_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/camera_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/location_usage_description")).is_empty()) { descriptions += "\tNSLocationUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/location_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/location_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) { descriptions += "\tNSContactsUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/address_book_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/address_book_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) { descriptions += "\tNSCalendarsUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/calendar_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/calendar_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) { descriptions += "\tNSPhotoLibraryUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/photos_library_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/photos_library_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/desktop_folder_usage_description")).is_empty()) { descriptions += "\tNSDesktopFolderUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/desktop_folder_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/desktop_folder_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/documents_folder_usage_description")).is_empty()) { descriptions += "\tNSDocumentsFolderUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/documents_folder_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/documents_folder_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/downloads_folder_usage_description")).is_empty()) { descriptions += "\tNSDownloadsFolderUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/downloads_folder_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/downloads_folder_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/network_volumes_usage_description")).is_empty()) { descriptions += "\tNSNetworkVolumesUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/network_volumes_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/network_volumes_usage_description").operator String().xml_escape(true) + "\n"; } if (!((String)p_preset->get("privacy/removable_volumes_usage_description")).is_empty()) { descriptions += "\tNSRemovableVolumesUsageDescription\n"; - descriptions += "\t" + (String)p_preset->get("privacy/removable_volumes_usage_description") + "\n"; + descriptions += "\t" + p_preset->get("privacy/removable_volumes_usage_description").operator String().xml_escape(true) + "\n"; } if (!descriptions.is_empty()) { strnew += lines[i].replace("$usage_descriptions", descriptions); @@ -1784,41 +1784,41 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p Ref f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); - f->store_line("CFBundleDisplayName = \"" + project_name + "\";"); + f->store_line("CFBundleDisplayName = \"" + project_name.xml_escape(true) + "\";"); if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { - f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";"); + f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/camera_usage_description")).is_empty()) { - f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String() + "\";"); + f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/location_usage_description")).is_empty()) { - f->store_line("NSLocationUsageDescription = \"" + p_preset->get("privacy/location_usage_description").operator String() + "\";"); + f->store_line("NSLocationUsageDescription = \"" + p_preset->get("privacy/location_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) { - f->store_line("NSContactsUsageDescription = \"" + p_preset->get("privacy/address_book_usage_description").operator String() + "\";"); + f->store_line("NSContactsUsageDescription = \"" + p_preset->get("privacy/address_book_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) { - f->store_line("NSCalendarsUsageDescription = \"" + p_preset->get("privacy/calendar_usage_description").operator String() + "\";"); + f->store_line("NSCalendarsUsageDescription = \"" + p_preset->get("privacy/calendar_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photos_library_usage_description").operator String() + "\";"); + f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photos_library_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/desktop_folder_usage_description")).is_empty()) { - f->store_line("NSDesktopFolderUsageDescription = \"" + p_preset->get("privacy/desktop_folder_usage_description").operator String() + "\";"); + f->store_line("NSDesktopFolderUsageDescription = \"" + p_preset->get("privacy/desktop_folder_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/documents_folder_usage_description")).is_empty()) { - f->store_line("NSDocumentsFolderUsageDescription = \"" + p_preset->get("privacy/documents_folder_usage_description").operator String() + "\";"); + f->store_line("NSDocumentsFolderUsageDescription = \"" + p_preset->get("privacy/documents_folder_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/downloads_folder_usage_description")).is_empty()) { - f->store_line("NSDownloadsFolderUsageDescription = \"" + p_preset->get("privacy/downloads_folder_usage_description").operator String() + "\";"); + f->store_line("NSDownloadsFolderUsageDescription = \"" + p_preset->get("privacy/downloads_folder_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/network_volumes_usage_description")).is_empty()) { - f->store_line("NSNetworkVolumesUsageDescription = \"" + p_preset->get("privacy/network_volumes_usage_description").operator String() + "\";"); + f->store_line("NSNetworkVolumesUsageDescription = \"" + p_preset->get("privacy/network_volumes_usage_description").operator String().xml_escape(true) + "\";"); } if (!((String)p_preset->get("privacy/removable_volumes_usage_description")).is_empty()) { - f->store_line("NSRemovableVolumesUsageDescription = \"" + p_preset->get("privacy/removable_volumes_usage_description").operator String() + "\";"); + f->store_line("NSRemovableVolumesUsageDescription = \"" + p_preset->get("privacy/removable_volumes_usage_description").operator String().xml_escape(true) + "\";"); } - f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String() + "\";"); + f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String().xml_escape(true) + "\";"); } for (const String &lang : locales) { @@ -1836,47 +1836,47 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p domain->set_locale_override(lang); const String &name = domain->translate(project_name, String()); if (name != project_name) { - f->store_line("CFBundleDisplayName = \"" + name + "\";"); + f->store_line("CFBundleDisplayName = \"" + name.xml_escape(true) + "\";"); } } else if (appnames.has(lang)) { - f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";"); + f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String().xml_escape(true) + "\";"); } if (microphone_usage_descriptions.has(lang)) { - f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (camera_usage_descriptions.has(lang)) { - f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (location_usage_descriptions.has(lang)) { - f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (address_book_usage_descriptions.has(lang)) { - f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (calendar_usage_descriptions.has(lang)) { - f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (photos_library_usage_descriptions.has(lang)) { - f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (desktop_folder_usage_descriptions.has(lang)) { - f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (documents_folder_usage_descriptions.has(lang)) { - f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (downloads_folder_usage_descriptions.has(lang)) { - f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (network_volumes_usage_descriptions.has(lang)) { - f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (removable_volumes_usage_descriptions.has(lang)) { - f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";"); + f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String().xml_escape(true) + "\";"); } if (copyrights.has(lang)) { - f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";"); + f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String().xml_escape(true) + "\";"); } } }