_qt_internal_process_resource: Properly escape XML
XML requires escaping for certain characters, and we need to consider this when writing out qrc files (which use XML). This commit introduces a helper function, _qt_internal_escape_xml_characters, to take care of the escaping. It uses regular expressions to process the input strings. We take care to start with '&', as '&' needs to be escaped, too. We minimize the amount of escaping we're doing (the exact rules differing between attributes and text), to avoid unnecessary work that needs to be done when configuring a project. This is achieved by a SUBSET option which can be passed to _qt_internal_escape_xml_characters. Task-number: QTBUG-131916 Change-Id: Ic1bd0eedee0343c3d70b6954842e21b3c550b092 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> (cherry picked from commit e4fbbdea05540723d4c4429d673d25efa3201d7a) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit 6e35353c83925d7c0d5f90db320ef9621f1ffb94)
This commit is contained in:
parent
b9206f1843
commit
238868c518
@ -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)
|
||||
|
||||
# <RCC><qresource ...>
|
||||
set(qrcContents "<RCC>\n <qresource")
|
||||
string(APPEND qrcContents " prefix=\"${rcc_PREFIX}\"")
|
||||
_qt_internal_escape_xml_characters("${rcc_PREFIX}" escaped_rcc_PREFIX SUBSET [[&<"]])
|
||||
|
||||
string(APPEND qrcContents " prefix=\"${escaped_rcc_PREFIX}\"")
|
||||
|
||||
# we assume that a valid language can't contain a character which needs
|
||||
# XML escaping
|
||||
if (rcc_LANG)
|
||||
string(APPEND qrcContents " lang=\"${rcc_LANG}\"")
|
||||
endif()
|
||||
@ -2331,13 +2376,24 @@ function(_qt_internal_process_resource target resourceName)
|
||||
|
||||
get_property(is_empty SOURCE ${file} PROPERTY QT_DISCARD_FILE_CONTENTS)
|
||||
|
||||
### FIXME: escape file paths to be XML conform
|
||||
# <file ...>...</file>
|
||||
string(APPEND qrcContents " <file alias=\"${file_resource_path}\"")
|
||||
# We need XML escaping; alias is a quote enclosed attribute, file is text
|
||||
_qt_internal_escape_xml_characters(
|
||||
"${file_resource_path}"
|
||||
escaped_file_resource_path
|
||||
SUBSET [[&<"]]
|
||||
)
|
||||
_qt_internal_escape_xml_characters(
|
||||
"${file}"
|
||||
escaped_file
|
||||
SUBSET [[&<]]
|
||||
)
|
||||
|
||||
string(APPEND qrcContents " <file alias=\"${escaped_file_resource_path}\"")
|
||||
if(is_empty)
|
||||
string(APPEND qrcContents " empty=\"true\"")
|
||||
endif()
|
||||
string(APPEND qrcContents ">${file}</file>\n")
|
||||
string(APPEND qrcContents ">${escaped_file}</file>\n")
|
||||
list(APPEND files "${file}")
|
||||
|
||||
set(scope_args)
|
||||
|
1
tests/auto/cmake/test_add_resource_prefix/&'.txt
Normal file
1
tests/auto/cmake/test_add_resource_prefix/&'.txt
Normal file
@ -0,0 +1 @@
|
||||
This is a test
|
@ -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)
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user