summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2022-12-08 19:20:48 +0100
committerMarc Mutz <marc.mutz@qt.io>2022-12-10 01:00:23 +0100
commitbbb01309b443054724713c2d72826535edc554d5 (patch)
tree8d25c12358f76a5c3359c95740d486a2388f65f7
parent9addd9a89d30135d8b917fe9e8d80212e48cf287 (diff)
downloadqtbase-bbb01309b443054724713c2d72826535edc554d5.tar.gz
QXmlStreamWriter: prepare for port to QAnyStringView
The UTF-8 support in Qt is still lacking, so QUtf8StringView doesn't, yet, have the likes of contains(), endsWith(), etc that the existing QString code uses in Q_ASSERTs. Provide free functions that work for UTF-8 haystacks and ASCII needles by falling back to QByteArrayView or QLatin1StringView. Also break a replace() use into a series of indexOf() + chunked write(). This is rather expensive for QString, so port the writeCDATA() function that uses this to QAnyStringView already, ahead of the bulk of the changes in Mate's follow-up patch. Task-number: QTBUG-103302 Change-Id: Ic66261740817ede2600b78a383cf667a31df7bfc Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Marc Mutz <marc.mutz@qt.io> Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Tatiana Borisova <tatiana.borisova@qt.io>
-rw-r--r--src/corelib/compat/removed_api.cpp11
-rw-r--r--src/corelib/serialization/qxmlstream.cpp92
-rw-r--r--src/corelib/serialization/qxmlstream.h3
3 files changed, 94 insertions, 12 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index aad7b58b36..62dc063072 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -368,6 +368,17 @@ void QXmlStreamReader::addData(const char *data)
#endif // QT_CONFIG(xmlstreamreader)
+#if QT_CONFIG(xmlstreamwriter)
+
+#include "qxmlstream.h"
+
+void QXmlStreamWriter::writeCDATA(const QString &text)
+{
+ writeCDATA(qToAnyStringViewIgnoringNull(text));
+}
+
+#endif // QT_CONFIG(xmlstreamwriter)
+
// inlined API
#include "qfloat16.h"
#include "qstring.h"
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index fb9317849c..792374a95a 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -44,8 +44,65 @@ auto reversed(Range &r)
template <typename Range>
void reversed(const Range &&) = delete;
+
+// implementation of missing QUtf8StringView methods for ASCII-only needles:
+auto transform(QLatin1StringView haystack, char needle)
+{
+ struct R { QLatin1StringView haystack; char16_t needle; };
+ return R{haystack, uchar(needle)};
+}
+
+auto transform(QStringView haystack, char needle)
+{
+ struct R { QStringView haystack; char16_t needle; };
+ return R{haystack, uchar(needle)};
+}
+
+auto transform(QUtf8StringView haystack, char needle)
+{
+ struct R { QByteArrayView haystack; char needle; };
+ return R{haystack, needle};
+}
+
+[[maybe_unused]]
+auto transform(QLatin1StringView haystack, QLatin1StringView needle)
+{
+ struct R { QLatin1StringView haystack; QLatin1StringView needle; };
+ return R{haystack, needle};
}
+[[maybe_unused]]
+auto transform(QStringView haystack, QLatin1StringView needle)
+{
+ struct R { QStringView haystack; QLatin1StringView needle; };
+ return R{haystack, needle};
+}
+
+[[maybe_unused]]
+auto transform(QUtf8StringView haystack, QLatin1StringView needle)
+{
+ struct R { QLatin1StringView haystack; QLatin1StringView needle; };
+ return R{QLatin1StringView{QByteArrayView{haystack}}, needle};
+}
+
+#define WRAP(method, Needle) \
+ auto method (QAnyStringView s, Needle needle) noexcept \
+ { \
+ return s.visit([needle](auto s) { \
+ auto r = transform(s, needle); \
+ return r.haystack. method (r.needle); \
+ }); \
+ } \
+ /*end*/
+
+WRAP(count, char)
+WRAP(contains, char)
+WRAP(contains, QLatin1StringView)
+WRAP(endsWith, char)
+WRAP(indexOf, QLatin1StringView)
+
+} // unnamed namespace
+
/*!
\enum QXmlStreamReader::TokenType
@@ -3216,7 +3273,7 @@ void QXmlStreamWriter::writeAttribute(const QString &qualifiedName, const QStrin
{
Q_D(QXmlStreamWriter);
Q_ASSERT(d->inStartElement);
- Q_ASSERT(qualifiedName.count(u':') <= 1);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
d->write(" ");
d->write(qualifiedName);
d->write("=\"");
@@ -3236,7 +3293,7 @@ void QXmlStreamWriter::writeAttribute(const QString &namespaceUri, const QString
{
Q_D(QXmlStreamWriter);
Q_ASSERT(d->inStartElement);
- Q_ASSERT(!name.contains(u':'));
+ Q_ASSERT(!contains(name, ':'));
QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri, true, true);
d->write(" ");
if (!namespaceDeclaration.prefix.isEmpty()) {
@@ -3295,15 +3352,26 @@ void QXmlStreamWriter::writeAttributes(const QXmlStreamAttributes& attributes)
This function mainly exists for completeness. Normally you should
not need use it, because writeCharacters() automatically escapes all
non-content characters.
+
+ \note In Qt versions prior to 6.5, this function took QString, not
+ QAnyStringView.
*/
-void QXmlStreamWriter::writeCDATA(const QString &text)
+void QXmlStreamWriter::writeCDATA(QAnyStringView text)
{
Q_D(QXmlStreamWriter);
d->finishStartElement();
- QString copy(text);
- copy.replace("]]>"_L1, "]]]]><![CDATA[>"_L1);
d->write("<![CDATA[");
- d->write(copy);
+ while (!text.isEmpty()) {
+ const auto idx = indexOf(text, "]]>"_L1);
+ if (idx < 0)
+ break; // no forbidden sequence found
+ d->write(text.first(idx));
+ d->write("]]" // text[idx, idx + 2)
+ "]]><![CDATA[" // escape sequence to separate ]] and >
+ ">"); // text[idx + 2, idx + 3)
+ text = text.sliced(idx + 3); // skip over "]]>"
+ }
+ d->write(text); // write remainder
d->write("]]>");
}
@@ -3329,7 +3397,7 @@ void QXmlStreamWriter::writeCharacters(const QString &text)
void QXmlStreamWriter::writeComment(const QString &text)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!text.contains("--"_L1) && !text.endsWith(u'-'));
+ Q_ASSERT(!contains(text, "--"_L1) && !endsWith(text, '-'));
if (!d->finishStartElement(false) && d->autoFormatting)
d->indent(d->tagStack.size());
d->write("<!--");
@@ -3362,7 +3430,7 @@ void QXmlStreamWriter::writeDTD(const QString &dtd)
void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(qualifiedName.count(u':') <= 1);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
d->writeStartElement(QString(), qualifiedName);
d->inEmptyElement = true;
}
@@ -3378,7 +3446,7 @@ void QXmlStreamWriter::writeEmptyElement(const QString &qualifiedName)
void QXmlStreamWriter::writeEmptyElement(const QString &namespaceUri, const QString &name)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!name.contains(u':'));
+ Q_ASSERT(!contains(name, ':'));
d->writeStartElement(namespaceUri, name);
d->inEmptyElement = true;
}
@@ -3544,7 +3612,7 @@ void QXmlStreamWriter::writeDefaultNamespace(const QString &namespaceUri)
void QXmlStreamWriter::writeProcessingInstruction(const QString &target, const QString &data)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!data.contains("?>"_L1));
+ Q_ASSERT(!contains(data, "?>"_L1));
if (!d->finishStartElement(false) && d->autoFormatting)
d->indent(d->tagStack.size());
d->write("<?");
@@ -3618,7 +3686,7 @@ void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalon
void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(qualifiedName.count(u':') <= 1);
+ Q_ASSERT(count(qualifiedName, ':') <= 1);
d->writeStartElement(QString(), qualifiedName);
}
@@ -3634,7 +3702,7 @@ void QXmlStreamWriter::writeStartElement(const QString &qualifiedName)
void QXmlStreamWriter::writeStartElement(const QString &namespaceUri, const QString &name)
{
Q_D(QXmlStreamWriter);
- Q_ASSERT(!name.contains(u':'));
+ Q_ASSERT(!contains(name, ':'));
d->writeStartElement(namespaceUri, name);
}
diff --git a/src/corelib/serialization/qxmlstream.h b/src/corelib/serialization/qxmlstream.h
index 8ba24f430e..c2f86b9a93 100644
--- a/src/corelib/serialization/qxmlstream.h
+++ b/src/corelib/serialization/qxmlstream.h
@@ -344,7 +344,9 @@ public:
void writeAttribute(const QXmlStreamAttribute& attribute);
void writeAttributes(const QXmlStreamAttributes& attributes);
+#if QT_CORE_REMOVED_SINCE(6,5)
void writeCDATA(const QString &text);
+#endif
void writeCharacters(const QString &text);
void writeComment(const QString &text);
@@ -355,6 +357,7 @@ public:
void writeTextElement(const QString &qualifiedName, const QString &text);
void writeTextElement(const QString &namespaceUri, const QString &name, const QString &text);
+ void writeCDATA(QAnyStringView text);
void writeEndDocument();
void writeEndElement();