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()) {
2460 qsizetype nestingLevel = 1;
2462 switch (readNext()) {
2464 case EntityReference:
2465 result.insert(result.size(), d->text);
2470 case ProcessingInstruction:
2474 if (behaviour == SkipChildElements) {
2475 skipCurrentElement();
2477 }
else if (behaviour == IncludeChildElements) {
2483 if (d->error || behaviour == ErrorOnUnexpectedElement) {
2485 d->raiseError(UnexpectedElementError, QXmlStream::tr(
"Expected character data."));
2489 }
while (nestingLevel);
2496
2497
2498
2499void QXmlStreamReader::raiseError(
const QString& message)
2501 Q_D(QXmlStreamReader);
2502 d->raiseError(CustomError, message);
2506
2507
2508
2509
2510QString QXmlStreamReader::errorString()
const
2512 Q_D(
const QXmlStreamReader);
2513 if (d->type == QXmlStreamReader::Invalid)
2514 return d->errorString;
2519
2520
2521
2522QXmlStreamReader::Error QXmlStreamReader::error()
const
2524 Q_D(
const QXmlStreamReader);
2525 if (d->type == QXmlStreamReader::Invalid)
2531
2532
2533QStringView QXmlStreamReader::processingInstructionTarget()
const
2535 Q_D(
const QXmlStreamReader);
2536 return d->processingInstructionTarget;
2540
2541
2542QStringView QXmlStreamReader::processingInstructionData()
const
2544 Q_D(
const QXmlStreamReader);
2545 return d->processingInstructionData;
2551
2552
2553
2554
2555QStringView QXmlStreamReader::name()
const
2557 Q_D(
const QXmlStreamReader);
2562
2563
2564
2565
2566QStringView QXmlStreamReader::namespaceUri()
const
2568 Q_D(
const QXmlStreamReader);
2569 return d->namespaceUri;
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584QStringView QXmlStreamReader::qualifiedName()
const
2586 Q_D(
const QXmlStreamReader);
2587 return d->qualifiedName;
2593
2594
2595
2596
2597
2598
2599QStringView QXmlStreamReader::prefix()
const
2601 Q_D(
const QXmlStreamReader);
2606
2607
2608QXmlStreamAttributes QXmlStreamReader::attributes()
const
2610 Q_D(
const QXmlStreamReader);
2611 return d->attributes;
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2634
2635
2636QXmlStreamAttribute::QXmlStreamAttribute()
2638 m_isDefault =
false;
2642
2643
2644
2645
2646QXmlStreamAttribute::QXmlStreamAttribute(
const QString &namespaceUri,
const QString &name,
const QString &value)
2647 : m_isDefault(
false)
2649 m_namespaceUri = namespaceUri;
2650 m_name = m_qualifiedName = name;
2655
2656
2657
2658
2659QXmlStreamAttribute::QXmlStreamAttribute(
const QString &qualifiedName,
const QString &value)
2660 : m_isDefault(
false)
2662 qsizetype colon = qualifiedName.indexOf(u':');
2663 m_name = qualifiedName.mid(colon + 1);
2664 m_qualifiedName = qualifiedName;
2669
2670
2671
2672
2674
2675
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2688
2689
2690
2691
2692
2693
2694
2697
2698
2701
2702
2703
2704
2705
2707
2708
2709
2710
2712
2713
2714
2715
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2740
2741
2742
2743
2746
2747
2748
2749
2750
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2768
2769
2770QXmlStreamNotationDeclaration::QXmlStreamNotationDeclaration()
2775
2776
2777
2779
2780
2781
2783
2784
2785
2788
2789
2790
2791
2793
2794
2795
2796
2799
2800
2801
2802
2803
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2819
2820
2821
2822
2824
2825
2826
2827
2830
2831
2832QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration()
2837
2838
2839
2840
2841QXmlStreamNamespaceDeclaration::QXmlStreamNamespaceDeclaration(
const QString &prefix,
const QString &namespaceUri)
2844 m_namespaceUri = namespaceUri;
2848
2849
2850
2852
2853
2854
2860
2861
2862
2863
2864
2867
2868
2869
2870
2871
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2888
2889
2890QXmlStreamEntityDeclaration::QXmlStreamEntityDeclaration()
2895
2896
2897
2899
2900
2901
2903
2904
2905
2907
2908
2909
2911
2912
2913
2916
2917
2918
2919
2921
2922
2923
2924
2927
2928
2929
2930
2931
2932
2933QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name)
const noexcept
2935 for (
const QXmlStreamAttribute &attribute : *
this) {
2936 if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
2937 return attribute.value();
2939 return QStringView();
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName)
const noexcept
2960 for (
const QXmlStreamAttribute &attribute : *
this) {
2961 if (attribute.qualifiedName() == qualifiedName)
2962 return attribute.value();
2964 return QStringView();
2968
2969
2970
2971void QXmlStreamAttributes::append(
const QString &namespaceUri,
const QString &name,
const QString &value)
2973 append(QXmlStreamAttribute(namespaceUri, name, value));
2977
2978
2979
2980void QXmlStreamAttributes::append(
const QString &qualifiedName,
const QString &value)
2982 append(QXmlStreamAttribute(qualifiedName, value));
2985#if QT_CONFIG(xmlstreamreader)
2988
2989
2991
2992
2994
2995
2997
2998
3000
3001
3002
3003
3005
3006
3008
3009
3011
3012
3014
3015
3018
3019
3020
3021
3022bool QXmlStreamReader::isWhitespace()
const
3024 Q_D(
const QXmlStreamReader);
3025 return d->type == QXmlStreamReader::Characters && d->isWhitespace;
3029
3030
3031
3032
3033bool QXmlStreamReader::isCDATA()
const
3035 Q_D(
const QXmlStreamReader);
3036 return d->type == QXmlStreamReader::Characters && d->isCDATA;
3042
3043
3044
3045
3046
3047
3048
3049bool QXmlStreamReader::isStandaloneDocument()
const
3051 Q_D(
const QXmlStreamReader);
3052 return d->standalone;
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065bool QXmlStreamReader::hasStandaloneDeclaration()
const
3067 Q_D(
const QXmlStreamReader);
3068 return d->hasStandalone;
3072
3073
3074
3075
3076
3077
3078QStringView QXmlStreamReader::documentVersion()
const
3080 Q_D(
const QXmlStreamReader);
3081 if (d->type == QXmlStreamReader::StartDocument)
3082 return d->documentVersion;
3083 return QStringView();
3087
3088
3089
3090
3091
3092
3093QStringView QXmlStreamReader::documentEncoding()
const
3095 Q_D(
const QXmlStreamReader);
3096 if (d->type == QXmlStreamReader::StartDocument)
3097 return d->documentEncoding;
3098 return QStringView();
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
3192
3193
3194
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3219#if QT_CONFIG(xmlstreamwriter)
3221class QXmlStreamWriterPrivate :
public QXmlStreamPrivateTagStack
3223 QXmlStreamWriter *q_ptr;
3224 Q_DECLARE_PUBLIC(QXmlStreamWriter)
3226 enum class StartElementOption {
3228 OmitNamespaceDeclarations = 1,
3231 QXmlStreamWriterPrivate(QXmlStreamWriter *q);
3232 ~QXmlStreamWriterPrivate() {
3237 void raiseError(QXmlStreamWriter::Error error);
3238 void raiseError(QXmlStreamWriter::Error error, QAnyStringView message);
3239 void write(QAnyStringView s);
3240 void writeEscaped(QAnyStringView,
bool escapeWhitespace =
false);
3241 bool finishStartElement(
bool contents =
true);
3242 void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
3243 StartElementOption option = StartElementOption::KeepEverything);
3244 QIODevice *device =
nullptr;
3245 QString *stringDevice =
nullptr;
3246 uint deleteDevice :1;
3247 uint inStartElement :1;
3248 uint inEmptyElement :1;
3249 uint lastWasStartElement :1;
3250 uint wroteSomething :1;
3251 uint autoFormatting :1;
3252 uint didWriteStartDocument :1;
3253 uint didWriteAnyToken :1;
3254 uint stopWritingOnError :1;
3255 std::string autoFormattingIndent = std::string(4,
' ');
3256 NamespaceDeclaration emptyNamespace;
3257 qsizetype lastNamespaceDeclaration = 1;
3258 QXmlStreamWriter::Error error = QXmlStreamWriter::Error::None;
3259 QString errorString;
3261 NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
3262 NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration =
false,
bool noDefault =
false);
3263 void writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration);
3265 int namespacePrefixCount = 0;
3267 void indent(
int level);
3269 void doWriteToDevice(QStringView s);
3270 void doWriteToDevice(QUtf8StringView s);
3271 void doWriteToDevice(QLatin1StringView s);
3275QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q)
3276 : q_ptr(q), deleteDevice(
false), inStartElement(
false),
3277 inEmptyElement(
false), lastWasStartElement(
false),
3278 wroteSomething(
false), autoFormatting(
false),
3279 didWriteStartDocument(
false), didWriteAnyToken(
false),
3280 stopWritingOnError(
false)
3284void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode)
3288 case QXmlStreamWriter::Error::IO:
3289 errorString = QXmlStream::tr(
"An I/O error occurred while writing");
3291 case QXmlStreamWriter::Error::Encoding:
3292 errorString = QXmlStream::tr(
"An encoding error occurred while writing");
3294 case QXmlStreamWriter::Error::InvalidCharacter:
3295 errorString = QXmlStream::tr(
"Encountered an invalid XML 1.0 character while writing");
3297 case QXmlStreamWriter::Error::Custom:
3298 errorString = QXmlStream::tr(
"An error occurred while writing");
3300 case QXmlStreamWriter::Error::None:
3301 errorString.clear();
3306void QXmlStreamWriterPrivate::raiseError(QXmlStreamWriter::Error errorCode, QAnyStringView message)
3309 errorString = message.toString();
3312void QXmlStreamWriterPrivate::write(QAnyStringView s)
3314 if (stopWritingOnError && (error != QXmlStreamWriter::Error::None))
3317 if (error == QXmlStreamWriter::Error::IO)
3320 s.visit([&] (
auto s) { doWriteToDevice(s); });
3321 }
else if (stringDevice) {
3322 s.visit([&] (
auto s) { stringDevice->append(s); });
3324 qWarning(
"QXmlStreamWriter: No device");
3328void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s,
bool escapeWhitespace)
3335 NextResult operator()(
const char *&it,
const char *)
const
3336 {
return {uchar(*it++),
false}; }
3339 NextResult operator()(
const char *&it,
const char *end)
const
3343 constexpr char32_t invalidValue = 0xFFFFFFFF;
3344 static_assert(invalidValue > QChar::LastValidCodePoint);
3345 auto i =
reinterpret_cast<
const qchar8_t *>(it);
3346 const auto old_i = i;
3347 const auto e =
reinterpret_cast<
const qchar8_t *>(end);
3348 const char32_t result = QUtf8Functions::nextUcs4FromUtf8(i, e, invalidValue);
3350 return result == invalidValue ? NextResult{U'\0',
true}
3351 : NextResult{result,
false};
3355 NextResult operator()(
const QChar *&it,
const QChar *end)
const
3357 QStringIterator decoder(it, end);
3360 constexpr char32_t invalidValue = 0xFFFFFFFF;
3361 static_assert(invalidValue > QChar::LastValidCodePoint);
3362 char32_t result = decoder.next(invalidValue);
3363 it = decoder.position();
3364 return result == invalidValue ? NextResult{U'\0',
true}
3365 : NextResult{result,
false};
3370 escaped.reserve(s.size());
3371 s.visit([&] (
auto s) {
3372 using View =
decltype(s);
3373 using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
3374 std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
3376 auto it = s.begin();
3377 const auto end = s.end();
3381 QLatin1StringView replacement;
3386 const auto decoded = decoder(next_it, end);
3387 switch (decoded.value) {
3389 replacement =
"<"_L1;
3392 replacement =
">"_L1;
3395 replacement =
"&"_L1;
3398 replacement =
"""_L1;
3401 if (escapeWhitespace)
3402 replacement =
"	"_L1;
3405 if (escapeWhitespace)
3406 replacement =
" "_L1;
3409 if (escapeWhitespace)
3410 replacement =
" "_L1;
3414 raiseError(QXmlStreamWriter::Error::InvalidCharacter);
3415 if (stopWritingOnError)
3417 replacement =
""_L1;
3418 Q_ASSERT(!replacement.isNull());
3421 if (decoded.value > 0x1F)
3427 raiseError(decoded.encodingError
3428 ? QXmlStreamWriter::Error::Encoding
3429 : QXmlStreamWriter::Error::InvalidCharacter);
3430 if (stopWritingOnError)
3432 replacement =
""_L1;
3433 Q_ASSERT(!replacement.isNull());
3436 if (!replacement.isNull())
3441 escaped.append(View{mark, it});
3442 escaped.append(replacement);
3451void QXmlStreamWriterPrivate::writeNamespaceDeclaration(
const NamespaceDeclaration &namespaceDeclaration) {
3452 if (namespaceDeclaration.prefix.isEmpty()) {
3454 write(namespaceDeclaration.namespaceUri);
3458 write(namespaceDeclaration.prefix);
3460 write(namespaceDeclaration.namespaceUri);
3463 didWriteAnyToken =
true;
3466bool QXmlStreamWriterPrivate::finishStartElement(
bool contents)
3468 bool hadSomethingWritten = wroteSomething;
3469 wroteSomething = contents;
3470 if (!inStartElement)
3471 return hadSomethingWritten;
3473 if (inEmptyElement) {
3475 QXmlStreamWriterPrivate::Tag tag = tagStack_pop();
3476 lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
3477 lastWasStartElement =
false;
3481 inStartElement = inEmptyElement =
false;
3482 lastNamespaceDeclaration = namespaceDeclarations.size();
3483 didWriteAnyToken =
true;
3484 return hadSomethingWritten;
3487QXmlStreamPrivateTagStack::NamespaceDeclaration &
3488QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
3490 const bool prefixIsXml = prefix ==
"xml"_L1;
3491 const bool namespaceUriIsXml = namespaceUri ==
"http://www.w3.org/XML/1998/namespace"_L1;
3492 if (prefixIsXml && !namespaceUriIsXml) {
3493 qWarning(
"Reserved prefix 'xml' must not be bound to a different namespace name "
3494 "than 'http://www.w3.org/XML/1998/namespace'");
3495 }
else if (!prefixIsXml && namespaceUriIsXml) {
3496 const QString prefixString = prefix.toString();
3497 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3498 "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
3499 qUtf16Printable(prefixString));
3501 if (namespaceUri ==
"http://www.w3.org/2000/xmlns/"_L1) {
3502 const QString prefixString = prefix.toString();
3503 qWarning(
"The prefix '%ls' must not be bound to namespace name "
3504 "'http://www.w3.org/2000/xmlns/'",
3505 qUtf16Printable(prefixString));
3507 auto &namespaceDeclaration = namespaceDeclarations.push();
3508 namespaceDeclaration.prefix = addToStringStorage(prefix);
3509 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3510 return namespaceDeclaration;
3513QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri,
bool writeDeclaration,
bool noDefault)
3515 for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
3516 if (namespaceDeclaration.namespaceUri == namespaceUri) {
3517 if (!noDefault || !namespaceDeclaration.prefix.isEmpty())
3518 return namespaceDeclaration;
3521 if (namespaceUri.isEmpty())
3522 return emptyNamespace;
3523 NamespaceDeclaration &namespaceDeclaration = namespaceDeclarations.push();
3524 if (namespaceUri.isEmpty()) {
3525 namespaceDeclaration.prefix.clear();
3528 int n = ++namespacePrefixCount;
3530 s = u'n' + QString::number(n++);
3531 qsizetype j = namespaceDeclarations.size() - 2;
3532 while (j >= 0 && namespaceDeclarations.at(j).prefix != s)
3537 namespaceDeclaration.prefix = addToStringStorage(s);
3539 namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
3540 if (writeDeclaration)
3541 writeNamespaceDeclaration(namespaceDeclaration);
3542 return namespaceDeclaration;
3547void QXmlStreamWriterPrivate::indent(
int level)
3549 if (didWriteStartDocument || didWriteAnyToken)
3551 for (
int i = 0; i < level; ++i)
3552 write(autoFormattingIndent);
3555void QXmlStreamWriterPrivate::doWriteToDevice(QStringView s)
3557 constexpr qsizetype MaxChunkSize = 512;
3558 char buffer [3 * MaxChunkSize];
3559 QStringEncoder::State state;
3560 while (!s.isEmpty()) {
3561 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3562 char *end = QUtf8::convertFromUnicode(buffer, s.first(chunkSize), &state);
3563 doWriteToDevice(QUtf8StringView{buffer, end});
3564 s = s.sliced(chunkSize);
3566 if (state.remainingChars > 0)
3567 raiseError(QXmlStreamWriter::Error::Encoding);
3570void QXmlStreamWriterPrivate::doWriteToDevice(QUtf8StringView s)
3572 QByteArrayView bytes = s;
3573 if (device->write(bytes.data(), bytes.size()) != bytes.size())
3574 raiseError(QXmlStreamWriter::Error::IO);
3577void QXmlStreamWriterPrivate::doWriteToDevice(QLatin1StringView s)
3579 constexpr qsizetype MaxChunkSize = 512;
3580 char buffer [2 * MaxChunkSize];
3581 while (!s.isEmpty()) {
3582 const qsizetype chunkSize = std::min(s.size(), MaxChunkSize);
3583 char *end = QUtf8::convertFromLatin1(buffer, s.first(chunkSize));
3584 doWriteToDevice(QUtf8StringView{buffer, end});
3585 s = s.sliced(chunkSize);
3590
3591
3592
3593
3594QXmlStreamWriter::QXmlStreamWriter()
3595 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3600
3601
3602QXmlStreamWriter::QXmlStreamWriter(QIODevice *device)
3603 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3605 Q_D(QXmlStreamWriter);
3610
3611
3612
3613QXmlStreamWriter::QXmlStreamWriter(QByteArray *array)
3614 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3616 Q_D(QXmlStreamWriter);
3617 d->device =
new QBuffer(array);
3618 d->device->open(QIODevice::WriteOnly);
3619 d->deleteDevice =
true;
3624
3625QXmlStreamWriter::QXmlStreamWriter(QString *string)
3626 : d_ptr(
new QXmlStreamWriterPrivate(
this))
3628 Q_D(QXmlStreamWriter);
3629 d->stringDevice = string;
3633
3634
3635QXmlStreamWriter::~QXmlStreamWriter()
3641
3642
3643
3644
3645
3646void QXmlStreamWriter::setDevice(QIODevice *device)
3648 Q_D(QXmlStreamWriter);
3649 if (device == d->device)
3651 d->stringDevice =
nullptr;
3652 if (d->deleteDevice) {
3654 d->deleteDevice =
false;
3660
3661
3662
3663
3664
3665QIODevice *QXmlStreamWriter::device()
const
3667 Q_D(
const QXmlStreamWriter);
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3688
3689
3690
3691
3692
3693
3694
3695void QXmlStreamWriter::setAutoFormatting(
bool enable)
3697 Q_D(QXmlStreamWriter);
3698 d->autoFormatting = enable;
3702
3703
3704
3705
3706bool QXmlStreamWriter::autoFormatting()
const
3708 Q_D(
const QXmlStreamWriter);
3709 return d->autoFormatting;
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3726void QXmlStreamWriter::setAutoFormattingIndent(
int spacesOrTabs)
3728 Q_D(QXmlStreamWriter);
3729 d->autoFormattingIndent.assign(size_t(qAbs(spacesOrTabs)), spacesOrTabs >= 0 ?
' ' :
'\t');
3732int QXmlStreamWriter::autoFormattingIndent()
const
3734 Q_D(
const QXmlStreamWriter);
3735 const QLatin1StringView indent(d->autoFormattingIndent);
3736 return indent.count(u' ') - indent.count(u'\t');
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756bool QXmlStreamWriter::stopWritingOnError()
const
3758 Q_D(
const QXmlStreamWriter);
3759 return d->stopWritingOnError;
3762void QXmlStreamWriter::setStopWritingOnError(
bool stop)
3764 Q_D(QXmlStreamWriter);
3765 d->stopWritingOnError = stop;
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780bool QXmlStreamWriter::hasError()
const
3782 return error() != QXmlStreamWriter::Error::None;
3786
3787
3788
3789
3790
3791
3792
3793
3794QXmlStreamWriter::Error QXmlStreamWriter::error()
const
3796 Q_D(
const QXmlStreamWriter);
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810QString QXmlStreamWriter::errorString()
const
3812 Q_D(
const QXmlStreamWriter);
3813 return d->errorString;
3817
3818
3819
3820
3821
3822
3823
3824
3825void QXmlStreamWriter::raiseError(QAnyStringView message)
3827 Q_D(QXmlStreamWriter);
3828 d->raiseError(QXmlStreamWriter::Error::Custom, message);
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringView value)
3844 Q_D(QXmlStreamWriter);
3845 Q_ASSERT(d->inStartElement);
3846 Q_ASSERT(count(qualifiedName,
':') <= 1);
3848 d->write(qualifiedName);
3850 d->writeEscaped(value,
true);
3852 d->didWriteAnyToken =
true;
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView value)
3868 Q_D(QXmlStreamWriter);
3869 Q_ASSERT(d->inStartElement);
3870 Q_ASSERT(!contains(name,
':'));
3871 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->findNamespace(namespaceUri,
true,
true);
3873 if (!namespaceDeclaration.prefix.isEmpty()) {
3874 d->write(namespaceDeclaration.prefix);
3879 d->writeEscaped(value,
true);
3881 d->didWriteAnyToken =
true;
3885
3886
3887
3888
3889
3890
3891
3892void QXmlStreamWriter::writeAttribute(
const QXmlStreamAttribute& attribute)
3894 if (attribute.namespaceUri().isEmpty())
3895 writeAttribute(attribute.qualifiedName(), attribute.value());
3897 writeAttribute(attribute.namespaceUri(), attribute.name(), attribute.value());
3902
3903
3904
3905
3906
3907
3908
3909
3910void QXmlStreamWriter::writeAttributes(
const QXmlStreamAttributes& attributes)
3912 Q_D(QXmlStreamWriter);
3913 Q_ASSERT(d->inStartElement);
3915 for (
const auto &attr : attributes)
3916 writeAttribute(attr);
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931void QXmlStreamWriter::writeCDATA(QAnyStringView text)
3933 Q_D(QXmlStreamWriter);
3934 d->finishStartElement();
3935 d->write(
"<![CDATA[");
3936 while (!text.isEmpty()) {
3937 const auto idx = indexOf(text,
"]]>"_L1);
3940 d->write(text.first(idx));
3944 text = text.sliced(idx + 3);
3952
3953
3954
3955
3956
3957
3958
3959
3960void QXmlStreamWriter::writeCharacters(QAnyStringView text)
3962 Q_D(QXmlStreamWriter);
3963 d->finishStartElement();
3964 d->writeEscaped(text);
3969
3970
3971
3972
3973
3974
3975void QXmlStreamWriter::writeComment(QAnyStringView text)
3977 Q_D(QXmlStreamWriter);
3978 Q_ASSERT(!contains(text,
"--"_L1) && !endsWith(text,
'-'));
3979 if (!d->finishStartElement(
false) && d->autoFormatting)
3980 d->indent(d->tagStack.size());
3984 d->inStartElement = d->lastWasStartElement =
false;
3989
3990
3991
3992
3993
3994void QXmlStreamWriter::writeDTD(QAnyStringView dtd)
3996 Q_D(QXmlStreamWriter);
3997 d->finishStartElement();
3998 if (d->autoFormatting)
4001 if (d->autoFormatting)
4008
4009
4010
4011
4012
4013
4014void QXmlStreamWriter::writeEmptyElement(QAnyStringView qualifiedName)
4016 Q_D(QXmlStreamWriter);
4017 Q_ASSERT(count(qualifiedName,
':') <= 1);
4018 d->writeStartElement({}, qualifiedName);
4019 d->inEmptyElement =
true;
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033void QXmlStreamWriter::writeEmptyElement(QAnyStringView namespaceUri, QAnyStringView name)
4035 Q_D(QXmlStreamWriter);
4036 Q_ASSERT(!contains(name,
':'));
4037 d->writeStartElement(namespaceUri, name);
4038 d->inEmptyElement =
true;
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052void QXmlStreamWriter::writeTextElement(QAnyStringView qualifiedName, QAnyStringView text)
4054 writeStartElement(qualifiedName);
4055 writeCharacters(text);
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071void QXmlStreamWriter::writeTextElement(QAnyStringView namespaceUri, QAnyStringView name, QAnyStringView text)
4073 writeStartElement(namespaceUri, name);
4074 writeCharacters(text);
4080
4081
4082
4083
4084void QXmlStreamWriter::writeEndDocument()
4086 Q_D(QXmlStreamWriter);
4087 while (d->tagStack.size())
4089 if (d->didWriteStartDocument || d->didWriteAnyToken)
4094
4095
4096
4097
4098void QXmlStreamWriter::writeEndElement()
4100 Q_D(QXmlStreamWriter);
4101 Q_ASSERT(d->didWriteAnyToken);
4102 if (d->tagStack.isEmpty())
4106 if (d->inStartElement && !d->inEmptyElement) {
4108 d->lastWasStartElement = d->inStartElement =
false;
4109 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4110 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4114 if (!d->finishStartElement(
false) && !d->lastWasStartElement && d->autoFormatting)
4115 d->indent(d->tagStack.size()-1);
4116 if (d->tagStack.isEmpty())
4118 d->lastWasStartElement =
false;
4119 QXmlStreamWriterPrivate::Tag tag = d->tagStack_pop();
4120 d->lastNamespaceDeclaration = tag.namespaceDeclarationsSize;
4122 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4123 d->write(tag.namespaceDeclaration.prefix);
4133
4134
4135
4136
4137
4138void QXmlStreamWriter::writeEntityReference(QAnyStringView name)
4140 Q_D(QXmlStreamWriter);
4141 d->finishStartElement();
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
4167 Q_D(QXmlStreamWriter);
4168 Q_ASSERT(prefix !=
"xmlns"_L1);
4169 if (prefix.isEmpty()) {
4170 d->findNamespace(namespaceUri, d->inStartElement);
4172 auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
4173 if (d->inStartElement)
4174 d->writeNamespaceDeclaration(namespaceDeclaration);
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192void QXmlStreamWriter::writeDefaultNamespace(QAnyStringView namespaceUri)
4194 Q_D(QXmlStreamWriter);
4195 Q_ASSERT(namespaceUri !=
"http://www.w3.org/XML/1998/namespace"_L1);
4196 Q_ASSERT(namespaceUri !=
"http://www.w3.org/2000/xmlns/"_L1);
4197 QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
4198 namespaceDeclaration.prefix.clear();
4199 namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
4200 if (d->inStartElement)
4201 d->writeNamespaceDeclaration(namespaceDeclaration);
4206
4207
4208
4209
4210
4211
4212void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStringView data)
4214 Q_D(QXmlStreamWriter);
4215 Q_ASSERT(!contains(data,
"?>"_L1));
4216 if (!d->finishStartElement(
false) && d->autoFormatting)
4217 d->indent(d->tagStack.size());
4220 if (!data.isNull()) {
4225 d->didWriteAnyToken =
true;
4231
4232
4233
4234
4235
4236
4237void QXmlStreamWriter::writeStartDocument()
4239 writeStartDocument(
"1.0"_L1);
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259void QXmlStreamWriter::writeStartDocument(QAnyStringView version)
4261 Q_D(QXmlStreamWriter);
4262 d->finishStartElement(
false);
4263 d->write(
"<?xml version=\"");
4266 d->write(
"\" encoding=\"UTF-8");
4268 d->didWriteStartDocument =
true;
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289void QXmlStreamWriter::writeStartDocument(QAnyStringView version,
bool standalone)
4291 Q_D(QXmlStreamWriter);
4292 d->finishStartElement(
false);
4293 d->write(
"<?xml version=\"");
4296 d->write(
"\" encoding=\"UTF-8");
4298 d->write(
"\" standalone=\"yes\"?>");
4300 d->write(
"\" standalone=\"no\"?>");
4301 d->didWriteStartDocument =
true;
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315void QXmlStreamWriter::writeStartElement(QAnyStringView qualifiedName)
4317 Q_D(QXmlStreamWriter);
4318 Q_ASSERT(count(qualifiedName,
':') <= 1);
4319 d->writeStartElement({}, qualifiedName);
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
4336 Q_D(QXmlStreamWriter);
4337 Q_ASSERT(!contains(name,
':'));
4338 d->writeStartElement(namespaceUri, name);
4341void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
4342 StartElementOption option)
4344 if (!finishStartElement(
false) && autoFormatting)
4345 indent(tagStack.size());
4347 Tag &tag = tagStack_push();
4348 tag.name = addToStringStorage(name);
4349 tag.namespaceDeclaration = findNamespace(namespaceUri);
4351 if (!tag.namespaceDeclaration.prefix.isEmpty()) {
4352 write(tag.namespaceDeclaration.prefix);
4356 inStartElement = lastWasStartElement =
true;
4358 if (option != StartElementOption::OmitNamespaceDeclarations) {
4359 for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
4360 writeNamespaceDeclaration(namespaceDeclarations[i]);
4362 tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
4363 didWriteAnyToken =
true;
4366#if QT_CONFIG(xmlstreamreader)
4368
4369
4370
4371
4372
4373
4374void QXmlStreamWriter::writeCurrentToken(
const QXmlStreamReader &reader)
4376 Q_D(QXmlStreamWriter);
4377 switch (reader.tokenType()) {
4378 case QXmlStreamReader::NoToken:
4380 case QXmlStreamReader::StartDocument:
4381 writeStartDocument();
4383 case QXmlStreamReader::EndDocument:
4386 case QXmlStreamReader::StartElement: {
4388 QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
4389 const QXmlStreamNamespaceDeclarations nsDeclarations = reader.namespaceDeclarations();
4390 for (
const auto &namespaceDeclaration : nsDeclarations) {
4391 auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
4392 namespaceDeclaration.prefix());
4393 extraNamespaces.append(extraNamespace);
4395 d->writeStartElement(
4396 reader.namespaceUri(), reader.name(),
4397 QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
4399 for (
const auto &extraNamespace : std::as_const(extraNamespaces))
4400 d->writeNamespaceDeclaration(extraNamespace);
4401 writeAttributes(reader.attributes());
4403 case QXmlStreamReader::EndElement:
4406 case QXmlStreamReader::Characters:
4407 if (reader.isCDATA())
4408 writeCDATA(reader.text());
4410 writeCharacters(reader.text());
4412 case QXmlStreamReader::Comment:
4413 writeComment(reader.text());
4415 case QXmlStreamReader::DTD:
4416 writeDTD(reader.text());
4418 case QXmlStreamReader::EntityReference:
4419 writeEntityReference(reader.name());
4421 case QXmlStreamReader::ProcessingInstruction:
4422 writeProcessingInstruction(reader.processingInstructionTarget(),
4423 reader.processingInstructionData());
4426 Q_ASSERT(reader.tokenType() != QXmlStreamReader::Invalid);
4427 qWarning(
"QXmlStreamWriter: writeCurrentToken() with invalid state.");
4434#if QT_CONFIG(xmlstreamreader)
4435static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
4436 QXmlStreamReaderPrivate::XmlContext ctxt)
4439 case QXmlStreamReader::StartDocument:
4440 case QXmlStreamReader::DTD:
4441 return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
4443 case QXmlStreamReader::StartElement:
4444 case QXmlStreamReader::EndElement:
4445 case QXmlStreamReader::Characters:
4446 case QXmlStreamReader::EntityReference:
4447 case QXmlStreamReader::EndDocument:
4448 return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
4450 case QXmlStreamReader::Comment:
4451 case QXmlStreamReader::ProcessingInstruction:
4454 case QXmlStreamReader::NoToken:
4455 case QXmlStreamReader::Invalid:
4460#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900
)
4461 Q_UNREACHABLE_RETURN(
false);
4468
4469
4470
4471
4472
4473
4474bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
4477 if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
4481 const bool result = isTokenAllowedInContext(type, currentContext);
4482 if (result || currentContext == XmlContext::Body)
4486 currentContext = XmlContext::Body;
4487 return isTokenAllowedInContext(type, currentContext);
4491
4492
4493
4494
4495void QXmlStreamReaderPrivate::checkToken()
4497 Q_Q(QXmlStreamReader);
4500 const XmlContext context = currentContext;
4501 const bool ok = isValidToken(type);
4504 if (error != QXmlStreamReader::Error::NoError)
4508 raiseError(QXmlStreamReader::UnexpectedElementError,
4509 QXmlStream::tr(
"Unexpected token type %1 in %2.")
4510 .arg(q->tokenString(), contextString(context)));
4514 if (type != QXmlStreamReader::DTD)
4519 raiseError(QXmlStreamReader::UnexpectedElementError,
4520 QXmlStream::tr(
"Found second DTD token in %1.").arg(contextString(context)));
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4541
4542
4543
4544
4545
4546
4547
4548