diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake index 238ab7b3633..2468ed10d3e 100644 --- a/src/corelib/Qt6CoreMacros.cmake +++ b/src/corelib/Qt6CoreMacros.cmake @@ -2218,6 +2218,47 @@ function(_qt_internal_expose_deferred_files_to_ide target) ${scope_args} PROPERTIES HEADER_FILE_ONLY ON) endfunction() +# +# Takes a string, and writes its XML escaped form into output_variable +# If SUBSET is given, only the characters in it will be escaped. +# No validation is done whether the characters in SUBSET are actually +# characters that need to be replaced +function(_qt_internal_escape_xml_characters input output_variable) + set(no_value_options "") + set(single_value_options SUBSET) + set(multi_value_options "") + cmake_parse_arguments(PARSE_ARGV 2 arg + "${no_value_options}" + "${single_value_options}" + "${multi_value_options}" + ) + set(escaped "${input}") + # it is vital to start with & + # as later replacements add new & + set(chars & [["]] [[']] < >) + set(replacements & " &apos < >) + if (NOT arg_SUBSET) + set(subset [[&"'<>]]) + else() + set(subset "${arg_SUBSET}") + endif() + foreach(i RANGE 4) + list(GET chars ${i} char) + list(GET replacements ${i} replacement) + string(FIND "${subset}" "${char}" pos) + if (${pos} EQUAL -1) + continue() + endif() + string(REGEX REPLACE + "${char}" + "${replacement};" + escaped + "${escaped}" + ) + endforeach() + set(${output_variable} "${escaped}" PARENT_SCOPE) +endfunction() + # # Process resources via file path instead of QRC files. Behind the # scenes, it will generate a qrc file. @@ -2314,8 +2355,12 @@ function(_qt_internal_process_resource target resourceName) # set(qrcContents "\n ... - string(APPEND qrcContents " ${file}\n") + string(APPEND qrcContents ">${escaped_file}\n") list(APPEND files "${file}") set(scope_args) diff --git a/tests/auto/cmake/test_add_resource_prefix/&'.txt b/tests/auto/cmake/test_add_resource_prefix/&'.txt new file mode 100644 index 00000000000..0527e6bd2d7 --- /dev/null +++ b/tests/auto/cmake/test_add_resource_prefix/&'.txt @@ -0,0 +1 @@ +This is a test diff --git a/tests/auto/cmake/test_add_resource_prefix/CMakeLists.txt b/tests/auto/cmake/test_add_resource_prefix/CMakeLists.txt index 65faa4cb095..67f83822a17 100644 --- a/tests/auto/cmake/test_add_resource_prefix/CMakeLists.txt +++ b/tests/auto/cmake/test_add_resource_prefix/CMakeLists.txt @@ -22,4 +22,17 @@ qt_add_resources(test_add_resource_prefix "resources_with_prefix" PREFIX "/resources" FILES resource_file.txt) +# Test that we handle prefixes with XML meta-character's. +# Also use the opportunity to cover testing of the file path itself +# and of aliases, too + +set_source_files_properties([[&'.txt]] + PROPERTIES QT_RESOURCE_ALIAS [[&"'<>.alias]] +) + +qt_add_resources(test_add_resource_prefix "resources_with_tricky_xml" + PREFIX [[/&"'<>]] + ALIAS [[&"'<>.alias]] + FILES [[&'.txt]]) + target_link_libraries(test_add_resource_prefix PRIVATE Qt::Core Qt::Test) diff --git a/tests/auto/cmake/test_add_resource_prefix/main.cpp b/tests/auto/cmake/test_add_resource_prefix/main.cpp index 3cccf067e20..39a1951d801 100644 --- a/tests/auto/cmake/test_add_resource_prefix/main.cpp +++ b/tests/auto/cmake/test_add_resource_prefix/main.cpp @@ -10,6 +10,7 @@ class TestAddResourcePrefix : public QObject private slots: void resourceInDefaultPathExists(); void resourceInGivenPathExists(); + void xmlEscaping(); }; void TestAddResourcePrefix::resourceInDefaultPathExists() @@ -22,5 +23,11 @@ void TestAddResourcePrefix::resourceInGivenPathExists() QVERIFY(QFile::exists(":/resources/resource_file.txt")); } + +void TestAddResourcePrefix::xmlEscaping() +{ + QVERIFY(QFile::exists(":/&\"'<>/&\"'<>.alias")); +} + QTEST_MAIN(TestAddResourcePrefix) #include "main.moc"