5#include "QtCore/qxmlstream.h"
7#if QT_CONFIG(xmlstream)
9#include "qxmlutils_p.h"
13#include <qstringconverter.h>
16#include <qscopeguard.h>
17#include <qcoreapplication.h>
18#include <QtCore/private/qduplicatetracker_p.h>
19#include <private/qoffsetstringarray_p.h>
20#include <private/qtools_p.h>
23#include "qxmlstream_p.h"
24#include "qxmlstreamparser_p.h"
25#include <private/qstringconverter_p.h>
26#include <private/qstringiterator_p.h>
30using namespace QtPrivate;
31using namespace Qt::StringLiterals;
32using namespace QtMiscUtils;
34constexpr uint StreamEOF = ~0U;
37template <
typename Range>
38auto reversed(Range &r)
42 auto begin() {
return std::make_reverse_iterator(std::end(*r)); }
43 auto end() {
return std::make_reverse_iterator(std::begin(*r)); }
49template <
typename Range>
50void reversed(
const Range &&) =
delete;
53auto transform(QLatin1StringView haystack,
char needle)
55 struct R { QLatin1StringView haystack;
char16_t needle; };
56 return R{haystack, uchar(needle)};
59auto transform(QStringView haystack,
char needle)
61 struct R { QStringView haystack;
char16_t needle; };
62 return R{haystack, uchar(needle)};
65auto transform(QUtf8StringView haystack,
char needle)
67 struct R { QByteArrayView haystack;
char needle; };
68 return R{haystack, needle};
71auto transform(QLatin1StringView haystack, QLatin1StringView needle)
73 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
74 return R{haystack, needle};
77auto transform(QStringView haystack, QLatin1StringView needle)
79 struct R { QStringView haystack; QLatin1StringView needle; };
80 return R{haystack, needle};
83auto transform(QUtf8StringView haystack, QLatin1StringView needle)
85 struct R { QLatin1StringView haystack; QLatin1StringView needle; };
86 return R{QLatin1StringView{QByteArrayView{haystack}}, needle};
89#define WRAP(method, Needle)
90 auto method (QAnyStringView s, Needle needle) noexcept
92 return s.visit([needle](auto s) {
93 auto r = transform(s, needle);
94 return r.haystack. method (r.needle);
101WRAP(contains, QLatin1StringView)
103WRAP(indexOf, QLatin1StringView)
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
157
158
159
160
161
162
163
164
165
166
167
168
169
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
254
255
256QXmlStreamEntityResolver::~QXmlStreamEntityResolver()
261
262
263
264
265QString QXmlStreamEntityResolver::resolveEntity(
const QString& ,
const QString& )
273
274
275
276
277
278
279
280
282QString QXmlStreamEntityResolver::resolveUndeclaredEntity(
const QString &)
287#if QT_CONFIG(xmlstreamreader)
289QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(
const QString &name)
292 return entityResolver->resolveUndeclaredEntity(name);
299
300
301
302
303
304
305
306
307
308
309
310void QXmlStreamReader::setEntityResolver(QXmlStreamEntityResolver *resolver)
312 Q_D(QXmlStreamReader);
313 d->entityResolver = resolver;
317
318
319
320
321
322
323QXmlStreamEntityResolver *QXmlStreamReader::entityResolver()
const
325 Q_D(
const QXmlStreamReader);
326 return d->entityResolver;
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
479
480
481
482
483QXmlStreamReader::QXmlStreamReader()
484 : d_ptr(
new QXmlStreamReaderPrivate(
this))
489
490
491
492QXmlStreamReader::QXmlStreamReader(QIODevice *device)
493 : d_ptr(
new QXmlStreamReaderPrivate(
this))
499
500
501
502
503
504
505
506
509
510
511
512
513
514
515
516
517
518void QXmlStreamReaderPrivate::appendDataWithEncoding(
const QByteArray &data,
519 QStringDecoder::Encoding enc)
525 if (!dataInfo.empty()) {
526 auto &last = dataInfo.last();
527 if (last.encoding == enc) {
528 last.buffer.append(data);
532 dataInfo.emplace_back(data, enc);
535void QXmlStreamReaderPrivate::addData(
const QByteArray &data, QStringDecoder::Encoding enc)
538 qWarning(
"QXmlStreamReader: addData() with device()");
541 appendDataWithEncoding(data, enc);
545
546
547
548
549
550
551
552QXmlStreamReader::QXmlStreamReader(QAnyStringView data)
553 : d_ptr(
new QXmlStreamReaderPrivate(
this))
555 Q_D(QXmlStreamReader);
556 data.visit([d](
auto data) {
557 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
558 d->appendDataWithEncoding(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
560 QStringDecoder::Utf16);
561 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
562 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
563 QStringDecoder::Latin1);
565 d->appendDataWithEncoding(QByteArray(data.data(), data.size()),
566 QStringDecoder::Utf8);
572
573
574
575
576
577QXmlStreamReader::QXmlStreamReader(
const QByteArray &data, PrivateConstructorTag)
578 : d_ptr(
new QXmlStreamReaderPrivate(
this))
580 Q_D(QXmlStreamReader);
581 d->appendDataWithEncoding(data, QStringDecoder::System);
585
586
587QXmlStreamReader::~QXmlStreamReader()
589 Q_D(QXmlStreamReader);
595
596
597
598
601
602
603
604
605
606void QXmlStreamReader::setDevice(QIODevice *device)
608 Q_D(QXmlStreamReader);
609 if (d->deleteDevice) {
611 d->deleteDevice =
false;
619
620
621
622
623
624QIODevice *QXmlStreamReader::device()
const
626 Q_D(
const QXmlStreamReader);
631
632
633
634
635
636
637
638
639
641static bool isDecoderForEncoding(
const QStringDecoder &dec, QStringDecoder::Encoding enc)
646 const auto decName = dec.name();
647 if (!decName || !*decName)
650 const auto encName = QStringConverter::nameForEncoding(enc);
651 return encName && strcmp(decName, encName) == 0;
655
656
657
658
659
660
661
662
663void QXmlStreamReader::addData(QAnyStringView data)
665 Q_D(QXmlStreamReader);
666 data.visit([d](
auto data) {
667 if constexpr (std::is_same_v<
decltype(data), QStringView>) {
668 d->addData(QByteArray(
reinterpret_cast<
const char *>(data.utf16()),
670 QStringDecoder::Utf16);
671 }
else if constexpr (std::is_same_v<
decltype(data), QLatin1StringView>) {
672 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Latin1);
674 d->addData(QByteArray(data.data(), data.size()), QStringDecoder::Utf8);
680
681
682
683
684
685void QXmlStreamReader::addDataImpl(
const QByteArray &data)
687 Q_D(QXmlStreamReader);
688 d->addData(data, QStringDecoder::System);
692
693
694
695
696
697void QXmlStreamReader::clear()
699 Q_D(QXmlStreamReader);
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723bool QXmlStreamReader::atEnd()
const
725 Q_D(
const QXmlStreamReader);
727 && ((d->type == QXmlStreamReader::Invalid && d->error == PrematureEndOfDocumentError)
728 || (d->type == QXmlStreamReader::EndDocument))) {
730 return d->device->atEnd();
732 return d->dataInfo.empty();
734 return (d->atEnd || d->type == QXmlStreamReader::Invalid);
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756QXmlStreamReader::TokenType QXmlStreamReader::readNext()
758 Q_D(QXmlStreamReader);
759 if (d->type != Invalid) {
760 if (!d->hasCheckedStartDocument)
761 if (!d->checkStartDocument())
764 if (d->atEnd && d->type != EndDocument && d->type != Invalid)
765 d->raiseError(PrematureEndOfDocumentError);
766 else if (!d->atEnd && d->type == EndDocument)
767 d->raiseWellFormedError(QXmlStream::tr(
"Extra content at end of document."));
768 }
else if (d->error == PrematureEndOfDocumentError) {
781
782
783
784
785
786
787
788
789
790QXmlStreamReader::TokenType QXmlStreamReader::tokenType()
const
792 Q_D(
const QXmlStreamReader);
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813bool QXmlStreamReader::readNextStartElement()
815 while (readNext() != Invalid) {
816 if (isEndElement() || isEndDocument())
818 else if (isStartElement())
825
826
827
828
829
830
831
832
833
834
835void QXmlStreamReader::skipCurrentElement()
838 while (depth && readNext() != Invalid) {
841 else if (isStartElement())
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865QString QXmlStreamReader::readRawInnerData()
867 Q_D(QXmlStreamReader);
870 auto specialToEntities = [](QStringView text, QString &output) {
872 QLatin1StringView replacement;
873 const qsizetype sz = text.size();
874 for (qsizetype i = 0; i < sz; ++i) {
875 switch (text[i].unicode()) {
877 replacement =
"<"_L1;
880 replacement =
">"_L1;
883 replacement =
"&"_L1;
886 replacement =
"""_L1;
889 replacement =
"'"_L1;
895 output += text.mid(chunk, i - chunk);
896 output += replacement;
899 if (chunk < text.size())
900 output += text.mid(chunk);
903 if (isStartElement()) {
905 while (!atEnd() && depth) {
906 switch (readNext()) {
908 raw +=
'<'_L1 + name();
909 const QXmlStreamAttributes attrs = attributes();
910 for (
auto it = attrs.begin(); it != attrs.end(); ++it) {
911 raw +=
' '_L1 + it->name() +
"=\""_L1;
912 specialToEntities(it->value(), raw);
922 raw +=
"</"_L1 + name() +
'>'_L1;
926 raw +=
"<![CDATA["_L1 + text() +
"]]>"_L1;
928 specialToEntities(text(), raw);
931 raw +=
"<!--"_L1 + text() +
"-->"_L1;
933 case EntityReference:
934 raw +=
'&'_L1 + name() +
';'_L1;
936 case ProcessingInstruction:
937 raw +=
"<?"_L1 + processingInstructionTarget()
938 +
' '_L1 + processingInstructionData()
944 d->raiseError(NotWellFormedError,
945 QXmlStream::tr(
"Unexpected token while "
946 "reading raw inner data."));
955static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
966 "ProcessingInstruction"
969static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
975
976
977
978
979
980
981
982
983
986void QXmlStreamReader::setNamespaceProcessing(
bool enable)
988 Q_D(QXmlStreamReader);
989 d->namespaceProcessing = enable;
992bool QXmlStreamReader::namespaceProcessing()
const
994 Q_D(
const QXmlStreamReader);
995 return d->namespaceProcessing;
999
1000
1001
1002QString QXmlStreamReader::tokenString()
const
1004 Q_D(
const QXmlStreamReader);
1005 return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
1009
1010
1011
1012static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
1014 return QLatin1StringView(QXmlStreamReader_XmlContextString.viewAt(
static_cast<
int>(ctxt)));
1019QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
1021 tagStack.reserve(16);
1022 tagStackStringStorageSize = 0;
1023 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1024 namespaceDeclaration.namespaceUri = addToStringStorage(u"http://www.w3.org/XML/1998/namespace");
1025 namespaceDeclaration.prefix = addToStringStorage(u"xml");
1026 initialTagStackStringStorageSize = tagStackStringStorageSize;
1030#if QT_CONFIG(xmlstreamreader)
1032QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
1036 deleteDevice =
false;
1038 sym_stack =
nullptr;
1039 state_stack =
nullptr;
1041 entityResolver =
nullptr;
1043#define ADD_PREDEFINED(n, v)
1045 Entity e = Entity::createLiteral(n##_L1, v##_L1);
1046 entityHash.insert(qToStringViewIgnoringNull(e.name), std::move(e));
1048 ADD_PREDEFINED(
"lt",
"<");
1049 ADD_PREDEFINED(
"gt",
">");
1050 ADD_PREDEFINED(
"amp",
"&");
1051 ADD_PREDEFINED(
"apos",
"'");
1052 ADD_PREDEFINED(
"quot",
"\"");
1053#undef ADD_PREDEFINED
1056void QXmlStreamReaderPrivate::init()
1059 lastAttributeIsCData =
false;
1062 isEmptyElement =
false;
1063 isWhitespace =
true;
1066 hasStandalone =
false;
1068 resumeReduction = 0;
1069 state_stack[tos++] = 0;
1070 state_stack[tos] = 0;
1072 putStack.reserve(32);
1074 textBuffer.reserve(256);
1078 attributes.reserve(16);
1079 lineNumber = lastLineStart = characterOffset = 0;
1082 decoder = QStringDecoder();
1083 attributeStack.clear();
1084 attributeStack.reserve(16);
1085 entityParser.reset();
1086 hasCheckedStartDocument =
false;
1087 normalizeLiterals =
false;
1090 inParseEntity =
false;
1091 referenceToUnparsedEntityDetected =
false;
1092 referenceToParameterEntityDetected =
false;
1093 hasExternalDtdSubset =
false;
1094 lockEncoding =
false;
1095 namespaceProcessing =
true;
1096 rawReadBuffer.clear();
1097 chunkDecoder = QStringDecoder();
1100 tagStackStringStorageSize = initialTagStackStringStorageSize;
1102 type = QXmlStreamReader::NoToken;
1103 error = QXmlStreamReader::NoError;
1104 currentContext = XmlContext::Prolog;
1109
1110
1111
1112void QXmlStreamReaderPrivate::parseEntity(
const QString &value)
1114 Q_Q(QXmlStreamReader);
1116 if (value.isEmpty())
1121 entityParser = std::make_unique<QXmlStreamReaderPrivate>(q);
1123 entityParser->init();
1124 entityParser->inParseEntity =
true;
1125 entityParser->readBuffer = value;
1126 entityParser->injectToken(PARSE_ENTITY);
1127 while (!entityParser->atEnd && entityParser->type != QXmlStreamReader::Invalid)
1128 entityParser->parse();
1129 if (entityParser->type == QXmlStreamReader::Invalid || entityParser->tagStack.size())
1130 raiseWellFormedError(QXmlStream::tr(
"Invalid entity value."));
1134inline void QXmlStreamReaderPrivate::reallocateStack()
1137 void *p = realloc(sym_stack, stack_size *
sizeof(Value));
1139 sym_stack =
static_cast<Value*>(p);
1140 p = realloc(state_stack, stack_size *
sizeof(
int));
1142 state_stack =
static_cast<
int*>(p);
1146QXmlStreamReaderPrivate::~QXmlStreamReaderPrivate()
1153inline uint QXmlStreamReaderPrivate::filterCarriageReturn()
1155 uint peekc = peekChar();
1156 if (peekc ==
'\n') {
1157 if (putStack.size())
1163 if (peekc == StreamEOF) {
1171
1172
1173
1174inline uint QXmlStreamReaderPrivate::getChar()
1177 if (putStack.size()) {
1178 c = atEnd ? StreamEOF : putStack.pop();
1180 if (readBufferPos < readBuffer.size())
1181 c = readBuffer.at(readBufferPos++).unicode();
1183 c = getChar_helper();
1189inline uint QXmlStreamReaderPrivate::peekChar()
1192 if (putStack.size()) {
1194 }
else if (readBufferPos < readBuffer.size()) {
1195 c = readBuffer.at(readBufferPos).unicode();
1197 if ((c = getChar_helper()) != StreamEOF)
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216bool QXmlStreamReaderPrivate::scanUntil(
const char *str,
short tokenToInject)
1218 const qsizetype pos = textBuffer.size();
1219 const auto oldLineNumber = lineNumber;
1222 while ((c = getChar()) != StreamEOF) {
1226 if ((c = filterCarriageReturn()) == 0)
1231 lastLineStart = characterOffset + readBufferPos;
1234 textBuffer += QChar(c);
1237 if (c < 0x20 || (c > 0xFFFD && c < 0x10000) || c > QChar::LastValidCodePoint ) {
1238 raiseWellFormedError(QXmlStream::tr(
"Invalid XML character."));
1239 lineNumber = oldLineNumber;
1242 textBuffer += QChar(c);
1247 if (c == uint(*str)) {
1249 if (tokenToInject >= 0)
1250 injectToken(tokenToInject);
1253 if (scanString(str + 1, tokenToInject,
false))
1258 putString(textBuffer, pos);
1259 textBuffer.resize(pos);
1260 lineNumber = oldLineNumber;
1264bool QXmlStreamReaderPrivate::scanString(
const char *str,
short tokenToInject,
bool requireSpace)
1269 if (c != ushort(str[n])) {
1273 putChar(ushort(str[n]));
1279 textBuffer += QLatin1StringView(str, n);
1281 const qsizetype s = fastScanSpace();
1283 qsizetype pos = textBuffer.size() - n - s;
1284 putString(textBuffer, pos);
1285 textBuffer.resize(pos);
1289 if (tokenToInject >= 0)
1290 injectToken(tokenToInject);
1294bool QXmlStreamReaderPrivate::scanAfterLangleBang()
1296 switch (peekChar()) {
1298 return scanString(spell[CDATA_START], CDATA_START,
false);
1300 return scanString(spell[DOCTYPE], DOCTYPE);
1302 return scanString(spell[ATTLIST], ATTLIST);
1304 return scanString(spell[NOTATION], NOTATION);
1306 if (scanString(spell[ELEMENT], ELEMENT))
1308 return scanString(spell[ENTITY], ENTITY);
1316bool QXmlStreamReaderPrivate::scanPublicOrSystem()
1318 switch (peekChar()) {
1320 return scanString(spell[SYSTEM], SYSTEM);
1322 return scanString(spell[PUBLIC], PUBLIC);
1329bool QXmlStreamReaderPrivate::scanNData()
1331 if (fastScanSpace()) {
1332 if (scanString(spell[NDATA], NDATA))
1339bool QXmlStreamReaderPrivate::scanAfterDefaultDecl()
1341 switch (peekChar()) {
1343 return scanString(spell[REQUIRED], REQUIRED,
false);
1345 return scanString(spell[IMPLIED], IMPLIED,
false);
1347 return scanString(spell[FIXED], FIXED,
false);
1354bool QXmlStreamReaderPrivate::scanAttType()
1356 switch (peekChar()) {
1358 return scanString(spell[CDATA], CDATA);
1360 if (scanString(spell[ID], ID))
1362 if (scanString(spell[IDREF], IDREF))
1364 return scanString(spell[IDREFS], IDREFS);
1366 if (scanString(spell[ENTITY], ENTITY))
1368 return scanString(spell[ENTITIES], ENTITIES);
1370 if (scanString(spell[NOTATION], NOTATION))
1372 if (scanString(spell[NMTOKEN], NMTOKEN))
1374 return scanString(spell[NMTOKENS], NMTOKENS);
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393inline qsizetype QXmlStreamReaderPrivate::fastScanLiteralContent()
1397 while ((c = getChar()) != StreamEOF) {
1398 switch (ushort(c)) {
1403
1407 if (filterCarriageReturn() == 0)
1412 lastLineStart = characterOffset + readBufferPos;
1416 if (normalizeLiterals)
1419 textBuffer += QChar(c);
1426 if (!(c & 0xff0000)) {
1436 textBuffer += QChar(ushort(c));
1443inline qsizetype QXmlStreamReaderPrivate::fastScanSpace()
1447 while ((c = getChar()) != StreamEOF) {
1450 if ((c = filterCarriageReturn()) == 0)
1455 lastLineStart = characterOffset + readBufferPos;
1459 textBuffer += QChar(c);
1471
1472
1473
1474
1475
1476inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
1480 while ((c = getChar()) != StreamEOF) {
1481 switch (ushort(c)) {
1488 isWhitespace =
false;
1489 const qsizetype pos = textBuffer.size();
1490 textBuffer += QChar(ushort(c));
1492 while ((c = getChar()) ==
']') {
1493 textBuffer += QChar(ushort(c));
1496 if (c == StreamEOF) {
1497 putString(textBuffer, pos);
1498 textBuffer.resize(pos);
1499 }
else if (c ==
'>' && textBuffer.at(textBuffer.size() - 2) == u']') {
1500 raiseWellFormedError(QXmlStream::tr(
"Sequence ']]>' not allowed in content."));
1508 if ((c = filterCarriageReturn()) == 0)
1513 lastLineStart = characterOffset + readBufferPos;
1517 textBuffer += QChar(ushort(c));
1522 if (!(c & 0xff0000)) {
1532 isWhitespace =
false;
1533 textBuffer += QChar(ushort(c));
1541inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
1545 while ((c = getChar()) != StreamEOF) {
1549 raiseNamePrefixTooLongError();
1550 return std::nullopt;
1579 if (val && val->prefix == n + 1) {
1587 if (val->prefix == 0) {
1588 val->prefix = qint16(n + 2);
1599 textBuffer += QChar(ushort(c));
1606 qsizetype pos = textBuffer.size() - n;
1607 putString(textBuffer, pos);
1608 textBuffer.resize(pos);
1612enum NameChar { NameBeginning, NameNotBeginning, NotName };
1614static const char Begi =
static_cast<
char>(NameBeginning);
1615static const char NtBg =
static_cast<
char>(NameNotBeginning);
1616static const char NotN =
static_cast<
char>(NotName);
1618static const char nameCharTable[128] =
1621 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1622 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1624 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1625 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1627 NotN, NotN, NotN, NotN, NotN, NotN, NotN, NotN,
1628 NotN, NotN, NotN, NotN, NotN, NtBg, NtBg, NotN,
1630 NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg, NtBg,
1631 NtBg, NtBg, Begi, NotN, NotN, NotN, NotN, NotN,
1633 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1634 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1636 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1637 Begi, Begi, Begi, NotN, NotN, NotN, NotN, Begi,
1639 NotN, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1640 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1642 Begi, Begi, Begi, Begi, Begi, Begi, Begi, Begi,
1643 Begi, Begi, Begi, NotN, NotN, NotN, NotN, NotN
1646static inline NameChar fastDetermineNameChar(QChar ch)
1648 ushort uc = ch.unicode();
1650 return static_cast<NameChar>(nameCharTable[uc]);
1652 QChar::Category cat = ch.category();
1654 if ((cat >= QChar::Letter_Uppercase && cat <= QChar::Letter_Other)
1655 || cat == QChar::Number_Letter)
1656 return NameBeginning;
1657 if ((cat >= QChar::Number_DecimalDigit && cat <= QChar::Number_Other)
1658 || (cat >= QChar::Mark_NonSpacing && cat <= QChar::Mark_Enclosing))
1659 return NameNotBeginning;
1663inline qsizetype QXmlStreamReaderPrivate::fastScanNMTOKEN()
1667 while ((c = getChar()) != StreamEOF) {
1668 if (fastDetermineNameChar(QChar(c)) == NotName) {
1673 textBuffer += QChar(c);
1677 qsizetype pos = textBuffer.size() - n;
1678 putString(textBuffer, pos);
1679 textBuffer.resize(pos);
1684void QXmlStreamReaderPrivate::putString(QStringView s, qsizetype from)
1687 putString(s.mid(from));
1690 putStack.reserve(s.size());
1691 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1692 putStack.rawPush() = it->unicode();
1695void QXmlStreamReaderPrivate::putStringLiteral(QStringView s)
1697 putStack.reserve(s.size());
1698 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it)
1699 putStack.rawPush() = ((LETTER << 16) | it->unicode());
1702void QXmlStreamReaderPrivate::putReplacement(QStringView s)
1704 putStack.reserve(s.size());
1705 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1706 char16_t c = it->unicode();
1707 if (c ==
'\n' || c ==
'\r')
1708 putStack.rawPush() = ((LETTER << 16) | c);
1710 putStack.rawPush() = c;
1713void QXmlStreamReaderPrivate::putReplacementInAttributeValue(QStringView s)
1715 putStack.reserve(s.size());
1716 for (
auto it = s.rbegin(), end = s.rend(); it != end; ++it) {
1717 char16_t c = it->unicode();
1718 if (c ==
'&' || c ==
';')
1719 putStack.rawPush() = c;
1720 else if (c ==
'\n' || c ==
'\r')
1721 putStack.rawPush() =
' ';
1723 putStack.rawPush() = ((LETTER << 16) | c);
1727uint QXmlStreamReaderPrivate::getChar_helper()
1729 constexpr qsizetype BUFFER_SIZE = 8192;
1730 characterOffset += readBufferPos;
1732 if (readBuffer.size())
1733 readBuffer.resize(0);
1734 if (decoder.isValid())
1737 auto tryDecodeWithGlobalDecoder = [
this]() ->
bool {
1738 if (!decoder.isValid()) {
1740 if (nbytesread < 4) {
1744 auto encoding = QStringDecoder::encodingForData(rawReadBuffer, u'<');
1746 encoding = QStringDecoder::Utf8;
1747 decoder = QStringDecoder(*encoding);
1750 readBuffer = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1752 if (lockEncoding && decoder.hasError()) {
1761 rawReadBuffer.resize(BUFFER_SIZE);
1762 qint64 nbytesreadOrMinus1 = device->read(rawReadBuffer.data() + nbytesread, BUFFER_SIZE - nbytesread);
1763 nbytesread += qMax(nbytesreadOrMinus1, qint64{0});
1770 if (!tryDecodeWithGlobalDecoder())
1772 }
else if (dataInfo.empty()) {
1776 const BufferAndEncoding bufAndEnc = dataInfo.takeFirst();
1783 if (bufAndEnc.encoding == QStringDecoder::System) {
1785 rawReadBuffer += bufAndEnc.buffer;
1787 rawReadBuffer = bufAndEnc.buffer;
1788 nbytesread = rawReadBuffer.size();
1790 if (!tryDecodeWithGlobalDecoder()) {
1792 bool hasError =
true;
1793 if (chunkDecoder.isValid() && !chunkDecoder.hasError()) {
1794 readBuffer = chunkDecoder(QByteArrayView(rawReadBuffer).first(nbytesread));
1795 hasError = chunkDecoder.hasError();
1798 raiseWellFormedError(
1799 QXmlStream::tr(
"Encountered incorrectly encoded content."));
1804 if (!isDecoderForEncoding(chunkDecoder, bufAndEnc.encoding))
1805 chunkDecoder = QStringDecoder(bufAndEnc.encoding);
1806 readBuffer = chunkDecoder(bufAndEnc.buffer);
1810 readBuffer.reserve(1);
1812 if (readBufferPos < readBuffer.size()) {
1813 ushort c = readBuffer.at(readBufferPos++).unicode();
1821XmlStringRef QXmlStreamReaderPrivate::namespaceForPrefix(QStringView prefix)
1823 for (
const NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
1824 if (namespaceDeclaration.prefix == prefix) {
1825 return namespaceDeclaration.namespaceUri;
1830 if (namespaceProcessing && !prefix.isEmpty())
1831 raiseWellFormedError(QXmlStream::tr(
"Namespace prefix '%1' not declared").arg(prefix));
1834 return XmlStringRef();
1840 QStringView namespaceUri;
1842 static AttributeName fromXmlAttribute(
const QXmlStreamAttribute &a,
bool nsProcessing)
1845 return {a.name(), a.namespaceUri()};
1847 return {a.qualifiedName(), a.namespaceUri()};
1850 friend bool operator==(
const AttributeName &lhs,
const AttributeName &rhs)
noexcept
1852 return lhs.name == rhs.name
1853 && lhs.namespaceUri == rhs.namespaceUri;
1855 friend size_t qHash(
const AttributeName &key, size_t seed = 0)
noexcept
1857 return qHashMulti(seed,
1864
1865
1866void QXmlStreamReaderPrivate::resolveTag()
1868 const auto attributeStackCleaner = qScopeGuard([
this](){ attributeStack.clear(); });
1869 const qsizetype n = attributeStack.size();
1871 if (namespaceProcessing) {
1872 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1873 if (!dtdAttribute.isNamespaceAttribute
1874 || dtdAttribute.defaultValue.isNull()
1875 || dtdAttribute.tagName != qualifiedName
1876 || dtdAttribute.attributeQualifiedName.isNull())
1879 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1883 if (dtdAttribute.attributePrefix.isEmpty() && dtdAttribute.attributeName ==
"xmlns"_L1) {
1884 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1885 namespaceDeclaration.prefix.clear();
1887 const XmlStringRef ns(dtdAttribute.defaultValue);
1888 if (ns ==
"http://www.w3.org/2000/xmlns/"_L1 ||
1889 ns ==
"http://www.w3.org/XML/1998/namespace"_L1)
1890 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1892 namespaceDeclaration.namespaceUri = ns;
1893 }
else if (dtdAttribute.attributePrefix ==
"xmlns"_L1) {
1894 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
1895 XmlStringRef namespacePrefix = dtdAttribute.attributeName;
1896 XmlStringRef namespaceUri = dtdAttribute.defaultValue;
1897 if (((namespacePrefix ==
"xml"_L1)
1898 ^ (namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1))
1899 || namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1
1900 || namespaceUri.isEmpty()
1901 || namespacePrefix ==
"xmlns"_L1)
1902 raiseWellFormedError(QXmlStream::tr(
"Illegal namespace declaration."));
1904 namespaceDeclaration.prefix = namespacePrefix;
1905 namespaceDeclaration.namespaceUri = namespaceUri;
1910 tagStack.top().namespaceDeclaration.namespaceUri = namespaceUri = namespaceForPrefix(prefix);
1912 attributes.resize(n);
1914 Q_DECL_UNINITIALIZED
1915 QDuplicateTracker<AttributeName, 13> names(n);
1917 for (qsizetype i = 0; i < n; ++i) {
1918 QXmlStreamAttribute &attribute = attributes[i];
1919 Attribute &attrib = attributeStack[i];
1920 XmlStringRef prefix(symPrefix(attrib.key));
1921 XmlStringRef name(symString(attrib.key));
1922 XmlStringRef qualifiedName(symName(attrib.key));
1923 XmlStringRef value(symString(attrib.value));
1925 attribute.m_name = name;
1926 attribute.m_qualifiedName = qualifiedName;
1927 attribute.m_value = value;
1929 if (!prefix.isEmpty()) {
1930 XmlStringRef attributeNamespaceUri = namespaceForPrefix(prefix);
1931 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1934 if (names.hasSeen(AttributeName::fromXmlAttribute(attribute, namespaceProcessing))) {
1935 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1940 for (
const DtdAttribute &dtdAttribute : dtdAttributes) {
1941 if (dtdAttribute.isNamespaceAttribute
1942 || dtdAttribute.defaultValue.isNull()
1943 || dtdAttribute.tagName != qualifiedName
1944 || dtdAttribute.attributeQualifiedName.isNull())
1947 while (i < n && symName(attributeStack[i].key) != dtdAttribute.attributeQualifiedName)
1954 QXmlStreamAttribute attribute;
1955 attribute.m_name = dtdAttribute.attributeName;
1956 attribute.m_qualifiedName = dtdAttribute.attributeQualifiedName;
1957 attribute.m_value = dtdAttribute.defaultValue;
1959 if (!dtdAttribute.attributePrefix.isEmpty()) {
1960 XmlStringRef attributeNamespaceUri = namespaceForPrefix(dtdAttribute.attributePrefix);
1961 attribute.m_namespaceUri = XmlStringRef(attributeNamespaceUri);
1970 if (namespaceProcessing && names.hasSeen(AttributeName::fromXmlAttribute(attribute,
true))) {
1971 raiseWellFormedError(QXmlStream::tr(
"Attribute '%1' redefined.").arg(attribute.qualifiedName()));
1975 attribute.m_isDefault =
true;
1976 attributes.append(std::move(attribute));
1980void QXmlStreamReaderPrivate::resolvePublicNamespaces()
1982 const Tag &tag = tagStack.top();
1983 qsizetype n = namespaceDeclarations.size() - tag.namespaceDeclarationsSize;
1984 publicNamespaceDeclarations.resize(n);
1985 for (qsizetype i = 0; i < n; ++i) {
1986 const NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.at(tag.namespaceDeclarationsSize + i);
1987 QXmlStreamNamespaceDeclaration &publicNamespaceDeclaration = publicNamespaceDeclarations[i];
1988 publicNamespaceDeclaration.m_prefix = namespaceDeclaration.prefix;
1989 publicNamespaceDeclaration.m_namespaceUri = namespaceDeclaration.namespaceUri;
1993void QXmlStreamReaderPrivate::resolveDtd()
1995 publicNotationDeclarations.resize(notationDeclarations.size());
1996 for (qsizetype i = 0; i < notationDeclarations.size(); ++i) {
1997 const QXmlStreamReaderPrivate::NotationDeclaration ¬ationDeclaration = notationDeclarations.at(i);
1998 QXmlStreamNotationDeclaration &publicNotationDeclaration = publicNotationDeclarations[i];
1999 publicNotationDeclaration.m_name = notationDeclaration.name;
2000 publicNotationDeclaration.m_systemId = notationDeclaration.systemId;
2001 publicNotationDeclaration.m_publicId = notationDeclaration.publicId;
2004 notationDeclarations.clear();
2005 publicEntityDeclarations.resize(entityDeclarations.size());
2006 for (qsizetype i = 0; i < entityDeclarations.size(); ++i) {
2007 const QXmlStreamReaderPrivate::EntityDeclaration &entityDeclaration = entityDeclarations.at(i);
2008 QXmlStreamEntityDeclaration &publicEntityDeclaration = publicEntityDeclarations[i];
2009 publicEntityDeclaration.m_name = entityDeclaration.name;
2010 publicEntityDeclaration.m_notationName = entityDeclaration.notationName;
2011 publicEntityDeclaration.m_systemId = entityDeclaration.systemId;
2012 publicEntityDeclaration.m_publicId = entityDeclaration.publicId;
2013 publicEntityDeclaration.m_value = entityDeclaration.value;
2015 entityDeclarations.clear();
2016 parameterEntityHash.clear();
2019uint QXmlStreamReaderPrivate::resolveCharRef(
int symbolIndex)
2024 if (sym(symbolIndex).c ==
'x')
2025 s = symString(symbolIndex).view().sliced(1).toUInt(&ok, 16);
2027 s = symString(symbolIndex).view().toUInt(&ok, 10);
2029 ok &= (s == 0x9 || s == 0xa || s == 0xd || (s >= 0x20 && s <= 0xd7ff)
2030 || (s >= 0xe000 && s <= 0xfffd) || (s >= 0x10000 && s <= QChar::LastValidCodePoint));
2036void QXmlStreamReaderPrivate::checkPublicLiteral(QStringView publicId)
2040 const char16_t *data = publicId.utf16();
2043 for (i = publicId.size() - 1; i >= 0; --i) {
2045 switch ((c = data[i])) {
2046 case ' ':
case '\n':
case '\r':
case '-':
case '(':
case ')':
2047 case '+':
case ',':
case '.':
case '/':
case ':':
case '=':
2048 case '?':
case ';':
case '!':
case '*':
case '#':
case '@':
2049 case '$':
case '_':
case '%':
case '\'':
case '\"':
2052 if (isAsciiLetterOrNumber(c))
2058 raiseWellFormedError(QXmlStream::tr(
"Unexpected character '%1' in public id literal.").arg(QChar(QLatin1Char(c))));
2062
2063
2064
2065
2066bool QXmlStreamReaderPrivate::checkStartDocument()
2068 hasCheckedStartDocument =
true;
2070 if (scanString(spell[XML], XML))
2073 type = QXmlStreamReader::StartDocument;
2075 hasCheckedStartDocument =
false;
2076 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2081void QXmlStreamReaderPrivate::startDocument()
2084 if (documentVersion !=
"1.0"_L1) {
2085 if (documentVersion.view().contains(u' '))
2086 err = QXmlStream::tr(
"Invalid XML version string.");
2088 err = QXmlStream::tr(
"Unsupported XML version.");
2090 qsizetype n = attributeStack.size();
2093
2094
2095
2097 for (qsizetype i = 0; err.isNull() && i < n; ++i) {
2098 Attribute &attrib = attributeStack[i];
2099 XmlStringRef prefix(symPrefix(attrib.key));
2100 XmlStringRef key(symString(attrib.key));
2101 XmlStringRef value(symString(attrib.value));
2103 if (prefix.isEmpty() && key ==
"encoding"_L1) {
2104 documentEncoding = value;
2107 err = QXmlStream::tr(
"The standalone pseudo attribute must appear after the encoding.");
2108 if (!QXmlUtils::isEncName(value))
2109 err = QXmlStream::tr(
"%1 is an invalid encoding name.").arg(value);
2111 QByteArray enc = value.toString().toUtf8();
2112 if (!lockEncoding) {
2113 decoder = QStringDecoder(enc.constData());
2114 if (!decoder.isValid()) {
2118 if (!chunkDecoder.isValid() || chunkDecoder.hasError())
2119 err = QXmlStream::tr(
"Encoding %1 is unsupported").arg(value);
2121 decoder = QStringDecoder(QStringDecoder::Utf8);
2122 }
else if (!rawReadBuffer.isEmpty() && nbytesread) {
2128 QString buf = decoder(QByteArrayView(rawReadBuffer).first(nbytesread));
2129 if (!decoder.hasError())
2130 readBuffer = std::move(buf);
2134 }
else if (prefix.isEmpty() && key ==
"standalone"_L1) {
2135 hasStandalone =
true;
2136 if (value ==
"yes"_L1)
2138 else if (value ==
"no"_L1)
2141 err = QXmlStream::tr(
"Standalone accepts only yes or no.");
2143 err = QXmlStream::tr(
"Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
2148 raiseWellFormedError(err);
2149 attributeStack.clear();
2153void QXmlStreamReaderPrivate::raiseError(QXmlStreamReader::Error error,
const QString& message)
2155 this->error = error;
2156 errorString = message;
2157 if (errorString.isNull()) {
2158 if (error == QXmlStreamReader::PrematureEndOfDocumentError)
2159 errorString = QXmlStream::tr(
"Premature end of document.");
2160 else if (error == QXmlStreamReader::CustomError)
2161 errorString = QXmlStream::tr(
"Invalid document.");
2164 type = QXmlStreamReader::Invalid;
2167void QXmlStreamReaderPrivate::raiseWellFormedError(
const QString &message)
2169 raiseError(QXmlStreamReader::NotWellFormedError, message);
2172void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
2175 raiseError(QXmlStreamReader::NotWellFormedError,
2176 QXmlStream::tr(
"Length of XML attribute name exceeds implementation limits (4KiB "
2180void QXmlStreamReaderPrivate::parseError()
2183 if (token == EOF_SYMBOL) {
2184 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2188 QString error_message;
2189 int ers = state_stack[tos];
2192 if (token != XML_ERROR)
2193 for (
int tk = 0; tk < TERMINAL_COUNT; ++tk) {
2194 int k = t_action(ers, tk);
2198 if (nexpected < nmax)
2199 expected[nexpected++] = tk;
2203 if (nexpected && nexpected < nmax) {
2205 QString exp_str = QXmlStream::tr(
"'%1'",
"expected")
2206 .arg(QLatin1StringView(spell[expected[0]]));
2207 if (nexpected == 2) {
2209 exp_str = QXmlStream::tr(
"%1 or '%2'",
"expected")
2210 .arg(exp_str, QLatin1StringView(spell[expected[1]]));
2211 }
else if (nexpected > 2) {
2213 for (; s < nexpected - 1; ++s) {
2215 exp_str = QXmlStream::tr(
"%1, '%2'",
"expected")
2216 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2219 exp_str = QXmlStream::tr(
"%1, or '%2'",
"expected")
2220 .arg(exp_str, QLatin1StringView(spell[expected[s]]));
2222 error_message = QXmlStream::tr(
"Expected %1, but got '%2'.")
2223 .arg(exp_str, QLatin1StringView(spell[token]));
2225 error_message = QXmlStream::tr(
"Unexpected '%1'.").arg(QLatin1StringView(spell[token]));
2228 raiseWellFormedError(error_message);
2231void QXmlStreamReaderPrivate::resume(
int rule) {
2232 resumeReduction = rule;
2233 if (error == QXmlStreamReader::NoError)
2234 raiseError(QXmlStreamReader::PrematureEndOfDocumentError);
2238
2239
2240
2241qint64 QXmlStreamReader::lineNumber()
const
2243 Q_D(
const QXmlStreamReader);
2244 return d->lineNumber + 1;
2248
2249
2250
2251qint64 QXmlStreamReader::columnNumber()
const
2253 Q_D(
const QXmlStreamReader);
2254 return d->characterOffset - d->lastLineStart + d->readBufferPos;
2258
2259
2260
2261qint64 QXmlStreamReader::characterOffset()
const
2263 Q_D(
const QXmlStreamReader);
2264 return d->characterOffset + d->readBufferPos;
2269
2270
2271QStringView QXmlStreamReader::text()
const
2273 Q_D(
const QXmlStreamReader);
2279
2280
2281
2282
2283
2284QXmlStreamNotationDeclarations QXmlStreamReader::notationDeclarations()
const
2286 Q_D(
const QXmlStreamReader);
2287 if (d->notationDeclarations.size())
2288 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2289 return d->publicNotationDeclarations;
2294
2295
2296
2297
2298
2299QXmlStreamEntityDeclarations QXmlStreamReader::entityDeclarations()
const
2301 Q_D(
const QXmlStreamReader);
2302 if (d->entityDeclarations.size())
2303 const_cast<QXmlStreamReaderPrivate *>(d)->resolveDtd();
2304 return d->publicEntityDeclarations;
2308
2309
2310
2311
2312
2313
2314QStringView QXmlStreamReader::dtdName()
const
2316 Q_D(
const QXmlStreamReader);
2317 if (d->type == QXmlStreamReader::DTD)
2319 return QStringView();
2323
2324
2325
2326
2327
2328
2329QStringView QXmlStreamReader::dtdPublicId()
const
2331 Q_D(
const QXmlStreamReader);
2332 if (d->type == QXmlStreamReader::DTD)
2333 return d->dtdPublicId;
2334 return QStringView();
2338
2339
2340
2341
2342
2343
2344QStringView QXmlStreamReader::dtdSystemId()
const
2346 Q_D(
const QXmlStreamReader);
2347 if (d->type == QXmlStreamReader::DTD)
2348 return d->dtdSystemId;
2349 return QStringView();
2353
2354
2355
2356
2357
2358
2359
2360
2361int QXmlStreamReader::entityExpansionLimit()
const
2363 Q_D(
const QXmlStreamReader);
2364 return d->entityExpansionLimit;
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382void QXmlStreamReader::setEntityExpansionLimit(
int limit)
2384 Q_D(QXmlStreamReader);
2385 d->entityExpansionLimit = limit;
2389
2390
2391
2392
2393
2394
2395
2396
2397QXmlStreamNamespaceDeclarations QXmlStreamReader::namespaceDeclarations()
const
2399 Q_D(
const QXmlStreamReader);
2400 if (d->publicNamespaceDeclarations.isEmpty() && d->type == StartElement)
2401 const_cast<QXmlStreamReaderPrivate *>(d)->resolvePublicNamespaces();
2402 return d->publicNamespaceDeclarations;
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416void QXmlStreamReader::addExtraNamespaceDeclaration(
const QXmlStreamNamespaceDeclaration &extraNamespaceDeclaration)
2418 Q_D(QXmlStreamReader);
2419 QXmlStreamReaderPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
2420 namespaceDeclaration.prefix = d->addToStringStorage(extraNamespaceDeclaration.prefix());
2421 namespaceDeclaration.namespaceUri = d->addToStringStorage(extraNamespaceDeclaration.namespaceUri());
2425
2426
2427
2428
2429
2430
2431void QXmlStreamReader::addExtraNamespaceDeclarations(
const QXmlStreamNamespaceDeclarations &extraNamespaceDeclarations)
2433 for (
const auto &extraNamespaceDeclaration : extraNamespaceDeclarations)
2434 addExtraNamespaceDeclaration(extraNamespaceDeclaration);
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455QString QXmlStreamReader::readElementText(ReadElementTextBehaviour behaviour)
2457 Q_D(QXmlStreamReader);
2458 if (isStartElement()) {
2461 switch (readNext()) {
2463 case EntityReference:
2464 result.insert(result.size(), d->text);
2468 case ProcessingInstruction:
2472 if (behaviour == SkipChildElements) {
2473 skipCurrentElement();
2475 }
else if (behaviour == IncludeChildElements) {
2476 result += readElementText(behaviour);
2481 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2483 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2493
2494
2495
2496void QXmlStreamReader::raiseError(
const QString& message)
2498 Q_D(QXmlStreamReader);
2499 d->raiseError(CustomError, message);
2503
2504
2505
2506
2507QString QXmlStreamReader::errorString()
const
2509 Q_D(
const QXmlStreamReader);
2510 if (d->type == QXmlStreamReader::Invalid)
2511 return d->errorString;
2516
2517
2518
2519QXmlStreamReader::Error QXmlStreamReader::error()
const
2521 Q_D(
const QXmlStreamReader);
2522 if (d->type == QXmlStreamReader::Invalid)
2528
2529
2530QStringView QXmlStreamReader::processingInstructionTarget()
const
2532 Q_D(
const QXmlStreamReader);
2533 return d->processingInstructionTarget;
2537
2538
2539QStringView QXmlStreamReader::processingInstructionData()
const
2541 Q_D(
const QXmlStreamReader);
2542 return d->processingInstructionData;
2548
2549
2550
2551
2552QStringView QXmlStreamReader::name()
const
2554 Q_D(
const QXmlStreamReader);
2559
2560
2561
2562
2563QStringView QXmlStreamReader::namespaceUri()
const
2565 Q_D(
const QXmlStreamReader);
2566 return d->namespaceUri;
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581QStringView QXmlStreamReader::qualifiedName()
const
2583 Q_D(
const QXmlStreamReader);
2584 return d->qualifiedName;
2590
2591
2592
2593
2594
2595
2596QStringView QXmlStreamReader::prefix()
const
2598 Q_D(
const QXmlStreamReader);
2603
2604
2605QXmlStreamAttributes QXmlStreamReader::attributes()
const
2607 Q_D(
const QXmlStreamReader);
2608 return d->attributes;
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2631
2632
2633QXmlStreamAttribute::QXmlStreamAttribute()
2635 m_isDefault =
false;
2639
2640
2641
2642
2643QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2644 : m_isDefault(
false)
2646 m_namespaceUri = namespaceUri;
2647 m_name = m_qualifiedName = name;
2652
2653
2654
2655
2656QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2657 : m_isDefault(
false)
2659 qsizetype colon = qualifiedName.indexOf(u':');
2660 m_name = qualifiedName.mid(colon + 1);
2661 m_qualifiedName = qualifiedName;
2666
2667
2668
2669
2671
2672
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2685
2686
2687
2688
2689
2690
2691
2694
2695
2698
2699
2700
2701
2702
2704
2705
2706
2707
2709
2710
2711
2712
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2737
2738
2739
2740
2743
2744
2745
2746
2747
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2765
2766
2767QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2772
2773
2774
2776
2777
2778
2780
2781
2782
2785
2786
2787
2788
2790
2791
2792
2793
2796
2797
2798
2799
2800
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2816
2817
2818
2819
2821
2822
2823
2824
2827
2828
2829QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2834
2835
2836
2837
2838QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2841 m_namespaceUri = namespaceUri;
2845
2846
2847
2849
2850
2851
2857
2858
2859
2860
2861
2864
2865
2866
2867
2868
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2885
2886
2887QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2892
2893
2894
2896
2897
2898
2900
2901
2902
2904
2905
2906
2908
2909
2910
2913
2914
2915
2916
2918
2919
2920
2921
2924
2925
2926
2927
2928
2929
2930QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2932 for (
const QXmlStreamAttribute &attribute : *
this) {
2933 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2934 return attribute.value();
2936 return QStringView();
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2957 for (
const QXmlStreamAttribute &attribute : *
this) {
2958 if (attribute.qualifiedName() == qualifiedName)
2959 return attribute.value();
2961 return QStringView();
2965
2966
2967
2968void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2970 append(QXmlStreamAttribute(namespaceUri, name, value));
2974
2975
2976
2977void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
2979 append(QXmlStreamAttribute(qualifiedName, value));
2982#if QT_CONFIG(xmlstreamreader)
2985
2986
2988
2989
2991
2992
2994
2995
2997
2998
2999
3000
3002
3003
3005
3006
3008
3009
3011
3012
3015
3016
3017
3018
3019bool QXmlStreamReader::isWhitespace()
const
3021 Q_D(
const QXmlStreamReader);
3022 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
3026
3027
3028
3029
3030bool QXmlStreamReader::isCDATA()
const
3032 Q_D(
const QXmlStreamReader);
3033 return d->type == QXmlStreamReader::Characters && d->isCDATA;
3039
3040
3041
3042
3043
3044
3045
3046bool QXmlStreamReader::isStandaloneDocument()
const
3048 Q_D(
const QXmlStreamReader);
3049 return d->standalone;
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062bool QXmlStreamReader::hasStandaloneDeclaration()
const
3064 Q_D(
const QXmlStreamReader);
3065 return d->hasStandalone;
3069
3070
3071
3072
3073
3074
3075QStringView QXmlStreamReader::documentVersion()
const
3077 Q_D(
const QXmlStreamReader);
3078 if (d->type == QXmlStreamReader::StartDocument)
3079 return d->documentVersion;
3080 return QStringView();
3084
3085
3086
3087
3088
3089
3090QStringView QXmlStreamReader::documentEncoding()
const
3092 Q_D(
const QXmlStreamReader);
3093 if (d->type == QXmlStreamReader::StartDocument)
3094 return d->documentEncoding;
3095 return QStringView();
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3216#if QT_CONFIG(xmlstreamwriter)
3218class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3220 QXmlStreamWriter *q_ptr;
3221 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3223 enum class StartElementOption {
3225 OmitNamespaceDeclarations = 1,
3228 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3229 ~QXmlStreamWriterPrivate() {
3234 void raiseError(QXmlStreamWriter::Error error);
3235 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3236 void write(QAnyStringView s);
3237 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3238 bool finishStartElement(
bool contents =
true);
3239 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3240 StartElementOption option = StartElementOption::KeepEverything);
3241 QIODevice *device =
nullptr;
3242 QString *stringDevice =
nullptr;
3243 uint deleteDevice :1;
3244 uint inStartElement :1;
3245 uint inEmptyElement :1;
3246 uint lastWasStartElement :1;
3247 uint wroteSomething :1;
3248 uint autoFormatting :1;
3249 uint didWriteStartDocument :1;
3250 uint didWriteAnyToken :1;
3251 uint stopWritingOnError :1;
3252 std::string autoFormattingIndent = std::string(4,
' ');
3253 NamespaceDeclaration emptyNamespace;
3254 qsizetype lastNamespaceDeclaration = 1;
3255 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3256 QString errorString;
3258 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3259 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3260 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3262 int namespacePrefixCount = 0;
3264 void indent(
int level);
3266 void doWriteToDevice(QStringView s);
3267 void doWriteToDevice(QUtf8StringView s);
3268 void doWriteToDevice(QLatin1StringView s);
3272QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3273 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3274 inEmptyElement(
false), lastWasStartElement(
false),
3275 wroteSomething(
false), autoFormatting(
false),
3276 didWriteStartDocument(
false), didWriteAnyToken(
false),
3277 stopWritingOnError(
false)
3281void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3285 case QXmlStreamWriter::Error::IO:
3286 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3288 case QXmlStreamWriter::Error::Encoding:
3289 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3291 case QXmlStreamWriter::Error::InvalidCharacter:
3292 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3294 case QXmlStreamWriter::Error::Custom:
3295 errorString = QXmlStream::tr(
"An error occurred while writing");
3297 case QXmlStreamWriter::Error::None:
3298 errorString.clear();
3303void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3306 errorString = message.toString();
3309void QXmlStreamWriterPrivate::write(QAnyStringView s)
3311 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3314 if (error == QXmlStreamWriter::Error::IO)
3317 s.visit([&] (
auto s) { doWriteToDevice(s); });
3318 }
else if (stringDevice) {
3319 s.visit([&] (
auto s) { stringDevice->append(s); });
3321 qWarning(
"QXmlStreamWriter: No device");
3325void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3332 NextResult operator()(
const char *&it,
const char *)
const
3333 {
return {uchar(*it++),
false}; }
3336 NextResult operator()(
const char *&it,
const char *end)
const
3340 constexpr char32_t invalidValue = 0xFFFFFFFF;
3341 static_assert(invalidValue > QChar::LastValidCodePoint);
3342 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3343 const auto old_i = i;
3344 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3345 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3347 return result == invalidValue ? NextResult{U'\0',
true}
3348 : NextResult{result,
false};
3352 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3354 QStringIterator decoder(it, end);
3357 constexpr char32_t invalidValue = 0xFFFFFFFF;
3358 static_assert(invalidValue > QChar::LastValidCodePoint);
3359 char32_t result = decoder.next(invalidValue);
3360 it = decoder.position();
3361 return result == invalidValue ? NextResult{U'\0',
true}
3362 : NextResult{result,
false};
3367 escaped.reserve(s.size());
3368 s.visit([&] (
auto s) {
3369 using View =
decltype(s);
3370 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3371 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3373 auto it = s.begin();
3374 const auto end = s.end();
3378 QLatin1StringView replacement;
3383 const auto decoded = decoder(next_it, end);
3384 switch (decoded.value) {
3386 replacement =
"<"_L1;
3389 replacement =
">"_L1;
3392 replacement =
"&"_L1;
3395 replacement =
"""_L1;
3398 if (escapeWhitespace)
3399 replacement =
"	"_L1;
3402 if (escapeWhitespace)
3403 replacement =
" "_L1;
3406 if (escapeWhitespace)
3407 replacement =
" "_L1;
3411 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3412 if (stopWritingOnError)
3414 replacement =
""_L1;
3415 Q_ASSERT(!replacement.isNull());
3418 if (decoded.value > 0x1F)
3424 raiseError(decoded.encodingError
3425 ? QXmlStreamWriter::Error::Encoding
3426 : QXmlStreamWriter::Error::InvalidCharacter);
3427 if (stopWritingOnError)
3429 replacement =
""_L1;
3430 Q_ASSERT(!replacement.isNull());
3433 if (!replacement.isNull())
3438 escaped.append(View{mark, it});
3439 escaped.append(replacement);
3448void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3449 if (namespaceDeclaration.prefix.isEmpty()) {
3451 write(namespaceDeclaration.namespaceUri);
3455 write(namespaceDeclaration.prefix);
3457 write(namespaceDeclaration.namespaceUri);
3460 didWriteAnyToken =
true;
3463bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3465 bool hadSomethingWritten = wroteSomething;
3466 wroteSomething = contents;
3467 if (!inStartElement)
3468 return hadSomethingWritten;
3470 if (inEmptyElement) {
3472 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3473 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3474 lastWasStartElement =
false;
3478 inStartElement = inEmptyElement =
false;
3479 lastNamespaceDeclaration = namespaceDeclarations.size();
3480 didWriteAnyToken =
true;
3481 return hadSomethingWritten;
3484QXmlStreamPrivateTagStack::NamespaceDeclaration &
3485QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3487 const bool prefixIsXml = prefix ==
"xml"_L1;
3488 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3489 if (prefixIsXml && !namespaceUriIsXml) {
3490 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3491 "than 'http://www.w3.org/XML/1998/namespace'");
3492 }
else if (!prefixIsXml && namespaceUriIsXml) {
3493 const QString prefixString = prefix.toString();
3494 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3495 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3496 qUtf16Printable(prefixString));
3498 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3499 const QString prefixString = prefix.toString();
3500 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3501 "'http://www.w3.org/2000/xmlns/'",
3502 qUtf16Printable(prefixString));
3504 auto &namespaceDeclaration = namespaceDeclarations.push();
3505 namespaceDeclaration.prefix = addToStringStorage(prefix);
3506 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3507 return namespaceDeclaration;
3510QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3512 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3513 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3514 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3515 return namespaceDeclaration;
3518 if (namespaceUri.isEmpty())
3519 return emptyNamespace;
3520 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3521 if (namespaceUri.isEmpty()) {
3522 namespaceDeclaration.prefix.clear();
3525 int n = ++namespacePrefixCount;
3527 s = u'n' + QString::number(n++);
3528 qsizetype j = namespaceDeclarations.size() - 2;
3529 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3534 namespaceDeclaration.prefix = addToStringStorage(s);
3536 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3537 if (writeDeclaration)
3538 writeNamespaceDeclaration(namespaceDeclaration);
3539 return namespaceDeclaration;
3544void QXmlStreamWriterPrivate::indent(
int level)
3546 if (didWriteStartDocument || didWriteAnyToken)
3548 for (
int i = 0; i < level; ++i)
3549 write(autoFormattingIndent);
3552void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3554 constexpr qsizetype MaxChunkSize = 512;
3555 char buffer [3 * MaxChunkSize];
3556 QStringEncoder::State state;
3557 while (!s.isEmpty()) {
3558 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3559 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3560 doWriteToDevice(QUtf8StringView{buffer, end});
3561 s = s.sliced(chunkSize);
3563 if (state.remainingChars > 0)
3564 raiseError(QXmlStreamWriter::Error::Encoding);
3567void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3569 QByteArrayView bytes = s;
3570 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3571 raiseError(QXmlStreamWriter::Error::IO);
3574void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3576 constexpr qsizetype MaxChunkSize = 512;
3577 char buffer [2 * MaxChunkSize];
3578 while (!s.isEmpty()) {
3579 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3580 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3581 doWriteToDevice(QUtf8StringView{buffer, end});
3582 s = s.sliced(chunkSize);
3587
3588
3589
3590
3591QXmlStreamWriter::QXmlStreamWriter()
3592 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3597
3598
3599QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3600 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3602 Q_D(QXmlStreamWriter);
3607
3608
3609
3610QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3611 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3613 Q_D(QXmlStreamWriter);
3614 d->device =
new QBuffer(array);
3615 d->device->open(QIODevice::WriteOnly);
3616 d->deleteDevice =
true;
3621
3622QXmlStreamWriter::QXmlStreamWriter(QString *string)
3623 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3625 Q_D(QXmlStreamWriter);
3626 d->stringDevice = string;
3630
3631
3632QXmlStreamWriter::~QXmlStreamWriter()
3638
3639
3640
3641
3642
3643void QXmlStreamWriter::setDevice(QIODevice *device)
3645 Q_D(QXmlStreamWriter);
3646 if (device == d->device)
3648 d->stringDevice =
nullptr;
3649 if (d->deleteDevice) {
3651 d->deleteDevice =
false;
3657
3658
3659
3660
3661
3662QIODevice *QXmlStreamWriter::device()
const
3664 Q_D(
const QXmlStreamWriter);
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3685
3686
3687
3688
3689
3690
3691
3692void QXmlStreamWriter::setAutoFormatting(
bool enable)
3694 Q_D(QXmlStreamWriter);
3695 d->autoFormatting = enable;
3699
3700
3701
3702
3703bool QXmlStreamWriter::autoFormatting()
const
3705 Q_D(
const QXmlStreamWriter);
3706 return d->autoFormatting;
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3723void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3725 Q_D(QXmlStreamWriter);
3726 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3729int QXmlStreamWriter::autoFormattingIndent()
const
3731 Q_D(
const QXmlStreamWriter);
3732 const QLatin1StringView indent(d->autoFormattingIndent);
3733 return indent.count(u' ') - indent.count(u'\t');
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753bool QXmlStreamWriter::stopWritingOnError()
const
3755 Q_D(
const QXmlStreamWriter);
3756 return d->stopWritingOnError;
3759void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3761 Q_D(QXmlStreamWriter);
3762 d->stopWritingOnError = stop;
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777bool QXmlStreamWriter::hasError()
const
3779 return error() != QXmlStreamWriter::Error::None;
3783
3784
3785
3786
3787
3788
3789
3790
3791QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3793 Q_D(
const QXmlStreamWriter);
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807QString QXmlStreamWriter::errorString()
const
3809 Q_D(
const QXmlStreamWriter);
3810 return d->errorString;
3814
3815
3816
3817
3818
3819
3820
3821
3822void QXmlStreamWriter::raiseError(QAnyStringView message)
3824 Q_D(QXmlStreamWriter);
3825 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3841 Q_D(QXmlStreamWriter);
3842 Q_ASSERT(d->inStartElement);
3843 Q_ASSERT(count(qualifiedName,
':') <= 1);
3845 d->write(qualifiedName);
3847 d->writeEscaped(value,
true);
3849 d->didWriteAnyToken =
true;
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3865 Q_D(QXmlStreamWriter);
3866 Q_ASSERT(d->inStartElement);
3867 Q_ASSERT(!contains(name,
':'));
3868 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3870 if (!namespaceDeclaration.prefix.isEmpty()) {
3871 d->write(namespaceDeclaration.prefix);
3876 d->writeEscaped(value,
true);
3878 d->didWriteAnyToken =
true;
3882
3883
3884
3885
3886
3887
3888
3889void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3891 if (attribute.namespaceUri().isEmpty())
3892 writeAttribute(attribute.qualifiedName(), attribute.value());
3894 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3899
3900
3901
3902
3903
3904
3905
3906
3907void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3909 Q_D(QXmlStreamWriter);
3910 Q_ASSERT(d->inStartElement);
3912 for (
const auto &attr : attributes)
3913 writeAttribute(attr);
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3930 Q_D(QXmlStreamWriter);
3931 d->finishStartElement();
3932 d->write(
"<![CDATA[");
3933 while (!text.isEmpty()) {
3934 const auto idx = indexOf(text,
"]]>"_L1);
3937 d->write(text.first(idx));
3941 text = text.sliced(idx + 3);
3949
3950
3951
3952
3953
3954
3955
3956
3957void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3959 Q_D(QXmlStreamWriter);
3960 d->finishStartElement();
3961 d->writeEscaped(text);
3966
3967
3968
3969
3970
3971
3972void QXmlStreamWriter::writeComment(QAnyStringView text)
3974 Q_D(QXmlStreamWriter);
3975 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
3976 if (!d->finishStartElement(
false) && d->autoFormatting)
3977 d->indent(d->tagStack.size());
3981 d->inStartElement = d->lastWasStartElement =
false;
3986
3987
3988
3989
3990
3991void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
3993 Q_D(QXmlStreamWriter);
3994 d->finishStartElement();
3995 if (d->autoFormatting)
3998 if (d->autoFormatting)
4005
4006
4007
4008
4009
4010
4011void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
4013 Q_D(QXmlStreamWriter);
4014 Q_ASSERT(count(qualifiedName,
':') <= 1);
4015 d->writeStartElement({}, qualifiedName);
4016 d->inEmptyElement =
true;
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
4032 Q_D(QXmlStreamWriter);
4033 Q_ASSERT(!contains(name,
':'));
4034 d->writeStartElement(namespaceUri, name);
4035 d->inEmptyElement =
true;
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
4051 writeStartElement(qualifiedName);
4052 writeCharacters(text);
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
4070 writeStartElement(namespaceUri, name);
4071 writeCharacters(text);
4077
4078
4079
4080
4081void QXmlStreamWriter::writeEndDocument()
4083 Q_D(QXmlStreamWriter);
4084 while (d->tagStack.size())
4086 if (d->didWriteStartDocument || d->didWriteAnyToken)
4091
4092
4093
4094
4095void QXmlStreamWriter::writeEndElement()
4097 Q_D(QXmlStreamWriter);
4098 Q_ASSERT(d->didWriteAnyToken);
4099 if (d->tagStack.isEmpty())
4103 if (d->inStartElement && !d->inEmptyElement) {
4105 d->lastWasStartElement = d->inStartElement =
false;
4106 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4107 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4111 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4112 d->indent(d->tagStack.size()-1);
4113 if (d->tagStack.isEmpty())
4115 d->lastWasStartElement =
false;
4116 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4117 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4119 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4120 d->write(tag.namespaceDeclaration.prefix);
4130
4131
4132
4133
4134
4135void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4137 Q_D(QXmlStreamWriter);
4138 d->finishStartElement();
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4164 Q_D(QXmlStreamWriter);
4165 Q_ASSERT(prefix !=
"xmlns"_L1);
4166 if (prefix.isEmpty()) {
4167 d->findNamespace(namespaceUri, d->inStartElement);
4169 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4170 if (d->inStartElement)
4171 d->writeNamespaceDeclaration(namespaceDeclaration);
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4191 Q_D(QXmlStreamWriter);
4192 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4193 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4194 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4195 namespaceDeclaration.prefix.clear();
4196 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4197 if (d->inStartElement)
4198 d->writeNamespaceDeclaration(namespaceDeclaration);
4203
4204
4205
4206
4207
4208
4209void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4211 Q_D(QXmlStreamWriter);
4212 Q_ASSERT(!contains(data,
"?>"_L1));
4213 if (!d->finishStartElement(
false) && d->autoFormatting)
4214 d->indent(d->tagStack.size());
4217 if (!data.isNull()) {
4222 d->didWriteAnyToken =
true;
4228
4229
4230
4231
4232
4233
4234void QXmlStreamWriter::writeStartDocument()
4236 writeStartDocument(
"1.0"_L1);
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4258 Q_D(QXmlStreamWriter);
4259 d->finishStartElement(
false);
4260 d->write(
"<?xml version=\"");
4263 d->write(
"\" encoding=\"UTF-8");
4265 d->didWriteStartDocument =
true;
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4288 Q_D(QXmlStreamWriter);
4289 d->finishStartElement(
false);
4290 d->write(
"<?xml version=\"");
4293 d->write(
"\" encoding=\"UTF-8");
4295 d->write(
"\" standalone=\"yes\"?>");
4297 d->write(
"\" standalone=\"no\"?>");
4298 d->didWriteStartDocument =
true;
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4314 Q_D(QXmlStreamWriter);
4315 Q_ASSERT(count(qualifiedName,
':') <= 1);
4316 d->writeStartElement({}, qualifiedName);
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4333 Q_D(QXmlStreamWriter);
4334 Q_ASSERT(!contains(name,
':'));
4335 d->writeStartElement(namespaceUri, name);
4338void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4339 StartElementOption option)
4341 if (!finishStartElement(
false) && autoFormatting)
4342 indent(tagStack.size());
4344 Tag &tag = tagStack_push();
4345 tag.name = addToStringStorage(name);
4346 tag.namespaceDeclaration = findNamespace(namespaceUri);
4348 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4349 write(tag.namespaceDeclaration.prefix);
4353 inStartElement = lastWasStartElement =
true;
4355 if (option != StartElementOption::OmitNamespaceDeclarations) {
4356 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4357 writeNamespaceDeclaration(namespaceDeclarations[i]);
4359 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4360 didWriteAnyToken =
true;
4363#if QT_CONFIG(xmlstreamreader)
4365
4366
4367
4368
4369
4370
4371void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4373 Q_D(QXmlStreamWriter);
4374 switch (reader.tokenType()) {
4375 case QXmlStreamReader::NoToken:
4377 case QXmlStreamReader::StartDocument:
4378 writeStartDocument();
4380 case QXmlStreamReader::EndDocument:
4383 case QXmlStreamReader::StartElement: {
4385 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4386 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4387 for (
const auto &namespaceDeclaration : nsDeclarations) {
4388 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4389 namespaceDeclaration.prefix());
4390 extraNamespaces.append(extraNamespace);
4392 d->writeStartElement(
4393 reader.namespaceUri(), reader.name(),
4394 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4396 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4397 d->writeNamespaceDeclaration(extraNamespace);
4398 writeAttributes(reader.attributes());
4400 case QXmlStreamReader::EndElement:
4403 case QXmlStreamReader::Characters:
4404 if (reader.isCDATA())
4405 writeCDATA(reader.text());
4407 writeCharacters(reader.text());
4409 case QXmlStreamReader::Comment:
4410 writeComment(reader.text());
4412 case QXmlStreamReader::DTD:
4413 writeDTD(reader.text());
4415 case QXmlStreamReader::EntityReference:
4416 writeEntityReference(reader.name());
4418 case QXmlStreamReader::ProcessingInstruction:
4419 writeProcessingInstruction(reader.processingInstructionTarget(),
4420 reader.processingInstructionData());
4423 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4424 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4431#if QT_CONFIG(xmlstreamreader)
4432static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4433 QXmlStreamReaderPrivate::XmlContext ctxt)
4436 case QXmlStreamReader::StartDocument:
4437 case QXmlStreamReader::DTD:
4438 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4440 case QXmlStreamReader::StartElement:
4441 case QXmlStreamReader::EndElement:
4442 case QXmlStreamReader::Characters:
4443 case QXmlStreamReader::EntityReference:
4444 case QXmlStreamReader::EndDocument:
4445 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4447 case QXmlStreamReader::Comment:
4448 case QXmlStreamReader::ProcessingInstruction:
4451 case QXmlStreamReader::NoToken:
4452 case QXmlStreamReader::Invalid:
4457#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4458 Q_UNREACHABLE_RETURN(
false);
4465
4466
4467
4468
4469
4470
4471bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4474 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4478 const bool result = isTokenAllowedInContext(type, currentContext);
4479 if (result || currentContext == XmlContext::Body)
4483 currentContext = XmlContext::Body;
4484 return isTokenAllowedInContext(type, currentContext);
4488
4489
4490
4491
4492void QXmlStreamReaderPrivate::checkToken()
4494 Q_Q(QXmlStreamReader);
4497 const XmlContext context = currentContext;
4498 const bool ok = isValidToken(type);
4501 if (error != QXmlStreamReader::Error::NoError)
4505 raiseError(QXmlStreamReader::UnexpectedElementError,
4506 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4507 .arg(q->tokenString(), contextString(context)));
4511 if (type != QXmlStreamReader::DTD)
4516 raiseError(QXmlStreamReader::UnexpectedElementError,
4517 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4538
4539
4540
4541
4542
4543
4544
4545