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>
This commit is contained in:
parent
9addd9a89d
commit
bbb01309b4
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user